aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--HOWTO/BENCHMARKS.md4
-rw-r--r--HOWTO/DTRACE.md3
-rw-r--r--Makefile.in222
-rw-r--r--aclocal.m435
-rw-r--r--bootstrap/bin/start.bootbin5248 -> 5242 bytes
-rw-r--r--bootstrap/bin/start_clean.bootbin5248 -> 5242 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_a.beambin0 -> 2236 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_asm.beambin11576 -> 11576 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_block.beambin14388 -> 14340 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_bool.beambin16156 -> 16256 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_bsm.beambin13724 -> 12488 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_clean.beambin11468 -> 9476 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_dead.beambin10180 -> 10176 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_dict.beambin5364 -> 5740 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_disasm.beambin25032 -> 25028 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_except.beambin3484 -> 3344 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_flatten.beambin3448 -> 2900 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_jump.beambin9516 -> 8408 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_opcodes.beambin6812 -> 6812 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_peep.beambin2456 -> 2428 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_receive.beambin5832 -> 6568 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_split.beambin2048 -> 2048 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_trim.beambin8568 -> 7452 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_type.beambin14032 -> 14032 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_utils.beambin14604 -> 13108 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_validator.beambin34536 -> 34356 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_z.beambin0 -> 2080 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/cerl.beambin30264 -> 30084 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/cerl_inline.beambin37572 -> 37496 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/cerl_trees.beambin18952 -> 18952 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/compile.beambin37460 -> 35644 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/compiler.app5
-rw-r--r--bootstrap/lib/compiler/ebin/core_lib.beambin5468 -> 5344 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/core_lint.beambin11632 -> 11636 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/core_parse.beambin37696 -> 37688 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/core_pp.beambin12124 -> 10896 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/core_scan.beambin6628 -> 6628 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/erl_bifs.beambin2156 -> 2088 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/rec_env.beambin4780 -> 4772 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_core_dsetel.beambin6996 -> 6992 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_core_fold.beambin46776 -> 46668 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_core_inline.beambin4208 -> 4168 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_expand_pmod.beambin8424 -> 0 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_pre_attributes.beambin3356 -> 3348 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_pre_expand.beambin16292 -> 13420 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_codegen.beambin51696 -> 51816 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_core.beambin51076 -> 50652 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_kernel.beambin42764 -> 43392 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_kernel_pp.beambin11828 -> 10596 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_life.beambin19924 -> 19880 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/application.beambin3772 -> 3860 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/application_controller.beambin30996 -> 30848 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/application_master.beambin6352 -> 6336 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/application_starter.beambin1264 -> 1256 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/auth.beambin6480 -> 6472 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/code.beambin6960 -> 6916 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/code_server.beambin26256 -> 26148 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/disk_log.beambin37260 -> 37096 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/disk_log_1.beambin24928 -> 24908 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/disk_log_server.beambin6408 -> 6404 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/dist_ac.beambin26708 -> 26580 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/dist_util.beambin10508 -> 10512 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/erl_boot_server.beambin5696 -> 5684 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/erl_ddll.beambin2868 -> 2868 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/erl_distribution.beambin1836 -> 1832 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/erl_epmd.beambin7064 -> 7064 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/error_handler.beambin1952 -> 1660 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/erts_debug.beambin3916 -> 3916 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/file.beambin14416 -> 14608 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/file_io_server.beambin14248 -> 14548 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/file_server.beambin5328 -> 5312 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/gen_sctp.beambin3528 -> 3524 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/gen_tcp.beambin2432 -> 2416 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/gen_udp.beambin1644 -> 1632 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/global.beambin32236 -> 32136 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/global_group.beambin17728 -> 17688 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/global_search.beambin3088 -> 3084 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/group.beambin11784 -> 11720 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/heart.beambin3912 -> 3952 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/hipe_unified_loader.beambin12732 -> 12716 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet.beambin20172 -> 21148 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet6_tcp.beambin2684 -> 2680 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet6_tcp_dist.beambin6256 -> 6208 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet6_udp.beambin1732 -> 1728 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_db.beambin26424 -> 25956 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_dns.beambin19728 -> 19716 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_gethost_native.beambin10484 -> 10468 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_parse.beambin12832 -> 12776 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_res.beambin14816 -> 14808 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_tcp.beambin2492 -> 2488 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_tcp_dist.beambin6540 -> 6496 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_udp.beambin1920 -> 1916 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/kernel.app1
-rw-r--r--bootstrap/lib/kernel/ebin/kernel.beambin3792 -> 3792 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/kernel_config.beambin2720 -> 2708 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/net_adm.beambin3064 -> 3060 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/net_kernel.beambin22800 -> 22712 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/os.beambin5276 -> 5276 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/packages.beambin2244 -> 0 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/pg2.beambin7696 -> 7692 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/ram_file.beambin6800 -> 7016 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/rpc.beambin8748 -> 8752 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/seq_trace.beambin1336 -> 1336 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/standard_error.beambin3636 -> 3620 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/user.beambin12332 -> 12384 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/wrap_log_reader.beambin3384 -> 3380 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/array.beambin12036 -> 12032 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/base64.beambin4532 -> 4528 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/beam_lib.beambin18060 -> 18044 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/binary.beambin3660 -> 3644 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/c.beambin13932 -> 13904 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dets.beambin53456 -> 53412 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dets_server.beambin7020 -> 7016 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dets_utils.beambin28864 -> 28736 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dets_v8.beambin27516 -> 27496 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dets_v9.beambin50072 -> 50008 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dict.beambin9140 -> 9132 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/digraph.beambin8320 -> 8308 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/digraph_utils.beambin6808 -> 6348 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/edlin.beambin7912 -> 7912 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/epp.beambin24276 -> 27204 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_bits.beambin2568 -> 2552 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_compile.beambin4896 -> 4876 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_eval.beambin23752 -> 23116 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_expand_records.beambin21900 -> 21652 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_internal.beambin5016 -> 5016 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_lint.beambin85172 -> 82112 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_parse.beambin71552 -> 69912 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_pp.beambin23344 -> 23800 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_scan.beambin31784 -> 31120 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_tar.beambin15352 -> 15228 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/escript.beambin17056 -> 17264 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/ets.beambin21724 -> 21660 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/eval_bits.beambin6748 -> 6736 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/file_sorter.beambin30592 -> 30552 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/filelib.beambin7308 -> 7816 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/filename.beambin12412 -> 12436 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gb_sets.beambin8256 -> 8252 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gb_trees.beambin4992 -> 4992 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen.beambin4112 -> 4080 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen_event.beambin17604 -> 17520 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen_fsm.beambin15348 -> 15136 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen_server.beambin17260 -> 16896 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/io.beambin6608 -> 6784 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/io_lib.beambin8896 -> 9200 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/io_lib_format.beambin11960 -> 12100 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/io_lib_fread.beambin7404 -> 7404 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/io_lib_pretty.beambin12364 -> 13212 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/lib.beambin9068 -> 9624 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/lists.beambin29556 -> 29524 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/log_mf_h.beambin2644 -> 2640 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/ms_transform.beambin20180 -> 20068 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/otp_internal.beambin7156 -> 7860 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/pg.beambin2064 -> 2064 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/pool.beambin3848 -> 3816 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/proc_lib.beambin9200 -> 9776 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/qlc.beambin69376 -> 69144 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/qlc_pt.beambin71588 -> 70944 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/queue.beambin5900 -> 5900 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/re.beambin12544 -> 12752 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/sets.beambin7020 -> 7016 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/shell.beambin30628 -> 30320 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/slave.beambin4424 -> 4424 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/sofs.beambin41100 -> 40500 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/supervisor.beambin22940 -> 23004 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/sys.beambin7328 -> 7292 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/unicode.beambin11620 -> 10928 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/win32reg.beambin5652 -> 5652 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/zip.beambin26800 -> 25212 bytes
-rw-r--r--configure.in17
-rw-r--r--erts/Makefile.in15
-rw-r--r--erts/aclocal.m435
-rw-r--r--erts/configure.in70
-rw-r--r--erts/doc/src/Makefile1
-rw-r--r--erts/doc/src/communication.xml89
-rw-r--r--erts/doc/src/driver_entry.xml41
-rw-r--r--erts/doc/src/erl.xml136
-rw-r--r--erts/doc/src/erl_driver.xml242
-rw-r--r--erts/doc/src/erl_nif.xml97
-rw-r--r--erts/doc/src/erlang.xml386
-rw-r--r--erts/doc/src/erts_alloc.xml6
-rw-r--r--erts/doc/src/notes.xml380
-rw-r--r--erts/doc/src/part.xml1
-rw-r--r--erts/emulator/Makefile.in104
-rw-r--r--erts/emulator/beam/atom.names10
-rw-r--r--erts/emulator/beam/beam_bif_load.c47
-rw-r--r--erts/emulator/beam/beam_bp.c44
-rw-r--r--erts/emulator/beam/beam_emu.c28
-rw-r--r--erts/emulator/beam/beam_load.c2
-rw-r--r--erts/emulator/beam/bif.c674
-rw-r--r--erts/emulator/beam/bif.h21
-rw-r--r--erts/emulator/beam/bif.tab300
-rw-r--r--erts/emulator/beam/binary.c6
-rw-r--r--erts/emulator/beam/break.c90
-rw-r--r--erts/emulator/beam/code_ix.c46
-rw-r--r--erts/emulator/beam/code_ix.h6
-rw-r--r--erts/emulator/beam/copy.c2
-rw-r--r--erts/emulator/beam/dist.c307
-rw-r--r--erts/emulator/beam/dist.h14
-rw-r--r--erts/emulator/beam/erl_afit_alloc.c11
-rw-r--r--erts/emulator/beam/erl_afit_alloc.h5
-rw-r--r--erts/emulator/beam/erl_alloc.c31
-rw-r--r--erts/emulator/beam/erl_alloc.h2
-rw-r--r--erts/emulator/beam/erl_alloc.types20
-rw-r--r--erts/emulator/beam/erl_alloc_util.c920
-rw-r--r--erts/emulator/beam/erl_alloc_util.h55
-rw-r--r--erts/emulator/beam/erl_ao_firstfit_alloc.c16
-rw-r--r--erts/emulator/beam/erl_async.c13
-rw-r--r--erts/emulator/beam/erl_bestfit_alloc.c45
-rw-r--r--erts/emulator/beam/erl_bif_ddll.c194
-rwxr-xr-xerts/emulator/beam/erl_bif_info.c402
-rw-r--r--erts/emulator/beam/erl_bif_op.c5
-rw-r--r--erts/emulator/beam/erl_bif_port.c867
-rw-r--r--erts/emulator/beam/erl_bif_re.c16
-rw-r--r--erts/emulator/beam/erl_bif_timer.c18
-rw-r--r--erts/emulator/beam/erl_bif_trace.c214
-rw-r--r--erts/emulator/beam/erl_bits.c18
-rw-r--r--erts/emulator/beam/erl_db.c93
-rw-r--r--erts/emulator/beam/erl_db_util.c53
-rw-r--r--erts/emulator/beam/erl_db_util.h4
-rw-r--r--erts/emulator/beam/erl_debug.c28
-rw-r--r--erts/emulator/beam/erl_driver.h44
-rw-r--r--erts/emulator/beam/erl_gc.c69
-rw-r--r--erts/emulator/beam/erl_goodfit_alloc.c13
-rw-r--r--erts/emulator/beam/erl_init.c143
-rw-r--r--erts/emulator/beam/erl_lock_check.c25
-rw-r--r--erts/emulator/beam/erl_lock_check.h5
-rw-r--r--erts/emulator/beam/erl_message.c13
-rw-r--r--erts/emulator/beam/erl_message.h23
-rw-r--r--erts/emulator/beam/erl_monitors.c13
-rw-r--r--erts/emulator/beam/erl_monitors.h2
-rw-r--r--erts/emulator/beam/erl_nif.c54
-rw-r--r--erts/emulator/beam/erl_nif_api_funcs.h4
-rw-r--r--erts/emulator/beam/erl_node_container_utils.h102
-rw-r--r--erts/emulator/beam/erl_node_tables.c65
-rw-r--r--erts/emulator/beam/erl_node_tables.h9
-rw-r--r--erts/emulator/beam/erl_port.h944
-rw-r--r--erts/emulator/beam/erl_port_task.c2084
-rw-r--r--erts/emulator/beam/erl_port_task.h160
-rw-r--r--erts/emulator/beam/erl_posix_str.c1
-rw-r--r--erts/emulator/beam/erl_process.c2246
-rw-r--r--erts/emulator/beam/erl_process.h284
-rw-r--r--erts/emulator/beam/erl_process_dict.c6
-rw-r--r--erts/emulator/beam/erl_process_dump.c18
-rw-r--r--erts/emulator/beam/erl_process_lock.c145
-rw-r--r--erts/emulator/beam/erl_process_lock.h56
-rw-r--r--erts/emulator/beam/erl_ptab.c1566
-rw-r--r--erts/emulator/beam/erl_ptab.h472
-rw-r--r--erts/emulator/beam/erl_resolv_dns.c23
-rw-r--r--erts/emulator/beam/erl_resolv_nodns.c23
-rw-r--r--erts/emulator/beam/erl_smp.h28
-rw-r--r--erts/emulator/beam/erl_sys_driver.h1
-rw-r--r--erts/emulator/beam/erl_term.c4
-rw-r--r--erts/emulator/beam/erl_term.h36
-rw-r--r--erts/emulator/beam/erl_thr_progress.c288
-rw-r--r--erts/emulator/beam/erl_thr_progress.h63
-rw-r--r--erts/emulator/beam/erl_threads.h298
-rw-r--r--erts/emulator/beam/erl_trace.c382
-rw-r--r--erts/emulator/beam/erl_trace.h141
-rw-r--r--erts/emulator/beam/erl_utils.h215
-rwxr-xr-xerts/emulator/beam/global.h925
-rw-r--r--erts/emulator/beam/index.c5
-rw-r--r--erts/emulator/beam/io.c4469
-rw-r--r--erts/emulator/beam/module.c2
-rw-r--r--erts/emulator/beam/register.c53
-rw-r--r--erts/emulator/beam/register.h19
-rw-r--r--erts/emulator/beam/sys.h46
-rw-r--r--erts/emulator/beam/utils.c18
-rw-r--r--erts/emulator/drivers/common/efile_drv.c54
-rw-r--r--erts/emulator/drivers/common/erl_efile.h1
-rw-r--r--erts/emulator/drivers/common/inet_drv.c233
-rw-r--r--erts/emulator/drivers/common/ram_file_drv.c8
-rw-r--r--erts/emulator/drivers/unix/ttsl_drv.c12
-rw-r--r--erts/emulator/drivers/unix/unix_efile.c112
-rw-r--r--erts/emulator/drivers/win32/win_efile.c10
-rw-r--r--erts/emulator/hipe/hipe_amd64_bifs.m46
-rw-r--r--erts/emulator/hipe/hipe_bif_list.m45
-rw-r--r--erts/emulator/hipe/hipe_debug.c11
-rw-r--r--erts/emulator/hipe/hipe_mkliterals.c97
-rw-r--r--erts/emulator/hipe/hipe_x86.c2
-rw-r--r--erts/emulator/hipe/hipe_x86_bifs.m412
-rw-r--r--erts/emulator/pcre/pcre.mk8
-rw-r--r--erts/emulator/sys/common/erl_check_io.c53
-rw-r--r--erts/emulator/sys/common/erl_mseg.c1134
-rw-r--r--erts/emulator/sys/common/erl_mseg.h31
-rw-r--r--erts/emulator/sys/unix/erl_unix_sys_ddll.c4
-rw-r--r--erts/emulator/sys/unix/sys.c161
-rw-r--r--erts/emulator/sys/win32/erl_win32_sys_ddll.c4
-rw-r--r--erts/emulator/sys/win32/erl_win_dyn_driver.h8
-rwxr-xr-xerts/emulator/sys/win32/sys.c177
-rw-r--r--erts/emulator/test/alloc_SUITE_data/allocator_test.h8
-rw-r--r--erts/emulator/test/alloc_SUITE_data/basic.c2
-rw-r--r--erts/emulator/test/alloc_SUITE_data/bucket_mask.c73
-rw-r--r--erts/emulator/test/alloc_SUITE_data/coalesce.c6
-rw-r--r--erts/emulator/test/alloc_SUITE_data/mseg_clear_cache.c4
-rw-r--r--erts/emulator/test/beam_SUITE.erl77
-rw-r--r--erts/emulator/test/binary_SUITE.erl26
-rw-r--r--erts/emulator/test/bs_bit_binaries_SUITE.erl45
-rw-r--r--erts/emulator/test/bs_construct_SUITE.erl91
-rw-r--r--erts/emulator/test/busy_port_SUITE.erl30
-rw-r--r--erts/emulator/test/ddll_SUITE.erl2
-rw-r--r--erts/emulator/test/driver_SUITE.erl67
-rw-r--r--erts/emulator/test/driver_SUITE_data/Makefile.src3
-rw-r--r--erts/emulator/test/driver_SUITE_data/thr_msg_blast_drv.c178
-rw-r--r--erts/emulator/test/fun_SUITE.erl4
-rw-r--r--erts/emulator/test/match_spec_SUITE.erl16
-rw-r--r--erts/emulator/test/port_SUITE.erl88
-rw-r--r--erts/emulator/test/process_SUITE.erl2067
-rw-r--r--erts/emulator/test/save_calls_SUITE.erl27
-rw-r--r--erts/emulator/test/smoke_test_SUITE.erl37
-rw-r--r--erts/emulator/test/trace_local_SUITE.erl2
-rw-r--r--erts/emulator/test/tuple_SUITE.erl305
-rwxr-xr-xerts/emulator/utils/beam_makeops21
-rw-r--r--erts/emulator/valgrind/suppress.halfword56
-rw-r--r--erts/emulator/valgrind/suppress.patched.3.6.020
-rw-r--r--erts/emulator/valgrind/suppress.standard12
-rw-r--r--erts/emulator/zlib/zlib.mk6
-rw-r--r--erts/epmd/src/Makefile.in6
-rw-r--r--erts/etc/common/Makefile.in101
-rw-r--r--erts/etc/common/erlexec.c9
-rw-r--r--erts/etc/common/escript.c2
-rw-r--r--erts/etc/common/heart.c214
-rw-r--r--erts/etc/unix/cerl.src30
-rw-r--r--erts/etc/unix/etp-commands260
-rw-r--r--erts/etc/win32/nsis/Makefile12
-rwxr-xr-xerts/etc/win32/nsis/dll_version_helper.sh16
-rw-r--r--erts/etc/win32/nsis/erlang20.nsi13
-rw-r--r--erts/include/internal/ethread.h2
-rw-r--r--erts/lib_src/Makefile.in109
-rw-r--r--erts/lib_src/common/erl_misc_utils.c10
-rw-r--r--erts/preloaded/ebin/erl_prim_loader.beambin54148 -> 54136 bytes
-rw-r--r--erts/preloaded/ebin/erlang.beambin88548 -> 92756 bytes
-rw-r--r--erts/preloaded/ebin/erts_internal.beambin0 -> 3616 bytes
-rw-r--r--erts/preloaded/ebin/init.beambin48580 -> 48556 bytes
-rw-r--r--erts/preloaded/ebin/otp_ring0.beambin1448 -> 1448 bytes
-rw-r--r--erts/preloaded/ebin/prim_file.beambin40816 -> 41176 bytes
-rw-r--r--erts/preloaded/ebin/prim_inet.beambin69764 -> 70016 bytes
-rw-r--r--erts/preloaded/ebin/prim_zip.beambin23460 -> 23408 bytes
-rw-r--r--erts/preloaded/ebin/zlib.beambin12796 -> 12784 bytes
-rw-r--r--erts/preloaded/src/Makefile3
-rw-r--r--erts/preloaded/src/erlang.erl336
-rw-r--r--erts/preloaded/src/erts_internal.erl155
-rw-r--r--erts/preloaded/src/prim_file.erl8
-rw-r--r--erts/preloaded/src/prim_inet.erl9
-rw-r--r--erts/start_scripts/Makefile52
-rw-r--r--erts/test/otp_SUITE.erl25
-rw-r--r--lib/appmon/src/Makefile8
-rw-r--r--lib/appmon/src/appmon.app.src4
-rw-r--r--lib/asn1/c_src/Makefile4
-rw-r--r--lib/asn1/doc/src/asn1_ug.xml397
-rw-r--r--lib/asn1/doc/src/asn1ct.xml73
-rw-r--r--lib/asn1/doc/src/asn1rt.xml39
-rw-r--r--lib/asn1/doc/src/notes.xml2
-rw-r--r--lib/asn1/src/Makefile45
-rw-r--r--lib/asn1/src/asn1.app.src1
-rw-r--r--lib/asn1/src/asn1ct.erl129
-rw-r--r--lib/asn1/src/asn1ct_check.erl111
-rw-r--r--lib/asn1/src/asn1ct_constructed_ber.erl1596
-rw-r--r--lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl25
-rw-r--r--lib/asn1/src/asn1ct_constructed_per.erl1005
-rw-r--r--lib/asn1/src/asn1ct_gen.erl346
-rw-r--r--lib/asn1/src/asn1ct_gen_ber.erl1749
-rw-r--r--lib/asn1/src/asn1ct_gen_ber_bin_v2.erl64
-rw-r--r--lib/asn1/src/asn1ct_gen_per.erl371
-rw-r--r--lib/asn1/src/asn1ct_gen_per_rt2ct.erl400
-rw-r--r--lib/asn1/src/asn1ct_imm.erl626
-rw-r--r--lib/asn1/src/asn1ct_parser2.erl31
-rw-r--r--lib/asn1/src/asn1ct_value.erl24
-rw-r--r--lib/asn1/src/asn1rt_ber_bin.erl1974
-rw-r--r--lib/asn1/src/asn1rt_ber_bin_v2.erl53
-rw-r--r--lib/asn1/src/asn1rt_per_bin.erl2285
-rw-r--r--lib/asn1/src/asn1rt_per_bin_rt2ct.erl331
-rw-r--r--lib/asn1/src/asn1rt_uper_bin.erl299
-rw-r--r--lib/asn1/test/Makefile1
-rw-r--r--lib/asn1/test/asn1_SUITE.erl280
-rw-r--r--lib/asn1/test/asn1_SUITE_data/ConstraintEquivalence.asn142
-rw-r--r--lib/asn1/test/asn1_SUITE_data/Extension-Addition-Group.asn21
-rw-r--r--lib/asn1/test/asn1_SUITE_data/MultipleLevels.asn19
-rw-r--r--lib/asn1/test/asn1_SUITE_data/PartialDecSeq.asn1config2
-rw-r--r--lib/asn1/test/asn1_SUITE_data/PrimStrings.asn126
-rw-r--r--lib/asn1/test/asn1_SUITE_data/SeqExtension.asn128
-rw-r--r--lib/asn1/test/asn1_SUITE_data/extensionAdditionGroup.erl23
-rw-r--r--lib/asn1/test/asn1_SUITE_data/testobj.erl53
-rw-r--r--lib/asn1/test/asn1_app_test.erl3
-rw-r--r--lib/asn1/test/asn1_test_lib.erl10
-rw-r--r--lib/asn1/test/asn1_wrapper.erl35
-rw-r--r--lib/asn1/test/h323test.erl1
-rw-r--r--lib/asn1/test/testChoExtension.erl41
-rw-r--r--lib/asn1/test/testChoExternal.erl75
-rw-r--r--lib/asn1/test/testChoRecursive.erl51
-rw-r--r--lib/asn1/test/testChoiceIndefinite.erl5
-rw-r--r--lib/asn1/test/testCompactBitString.erl302
-rw-r--r--lib/asn1/test/testConstraints.erl191
-rw-r--r--lib/asn1/test/testDeepTConstr.erl26
-rw-r--r--lib/asn1/test/testEnumExt.erl63
-rw-r--r--lib/asn1/test/testINSTANCE_OF.erl17
-rw-r--r--lib/asn1/test/testInfObjectClass.erl15
-rw-r--r--lib/asn1/test/testMergeCompile.erl14
-rw-r--r--lib/asn1/test/testMultipleLevels.erl (renamed from lib/compiler/test/compilation_SUITE_data/bad_functional_value.erl)25
-rw-r--r--lib/asn1/test/testParameterizedInfObj.erl4
-rw-r--r--lib/asn1/test/testPrimStrings.erl353
-rw-r--r--lib/asn1/test/testSSLspecs.erl14
-rw-r--r--lib/asn1/test/testSeqExtension.erl135
-rw-r--r--lib/asn1/test/testSeqIndefinite.erl6
-rw-r--r--lib/asn1/test/testSeqOf.erl11
-rw-r--r--lib/asn1/test/testSetIndefinite.erl5
-rw-r--r--lib/asn1/test/testSetOptional.erl212
-rw-r--r--lib/asn1/test/testTCAP.erl4
-rw-r--r--lib/asn1/test/testTimer.erl53
-rw-r--r--lib/asn1/test/testTypeValueNotation.erl31
-rw-r--r--lib/asn1/test/testX420.erl2
-rw-r--r--lib/asn1/test/test_compile_options.erl3
-rw-r--r--lib/asn1/test/test_inline.erl16
-rw-r--r--lib/asn1/test/test_partial_incomplete_decode.erl2
-rw-r--r--lib/asn1/test/test_selective_decode.erl2
-rw-r--r--lib/asn1/test/test_special_decode_performance.erl8
-rw-r--r--lib/common_test/doc/src/common_test_app.xml11
-rw-r--r--lib/common_test/doc/src/cover_chapter.xml112
-rw-r--r--lib/common_test/doc/src/ct_hooks_chapter.xml43
-rw-r--r--lib/common_test/doc/src/ct_run.xml4
-rw-r--r--lib/common_test/doc/src/notes.xml260
-rw-r--r--lib/common_test/doc/src/run_test_chapter.xml207
-rw-r--r--lib/common_test/doc/src/write_test_chapter.xml52
-rw-r--r--lib/common_test/priv/Makefile.in6
-rw-r--r--lib/common_test/src/Makefile7
-rw-r--r--lib/common_test/src/ct.erl8
-rw-r--r--lib/common_test/src/ct_config.erl5
-rw-r--r--lib/common_test/src/ct_conn_log_h.erl6
-rw-r--r--lib/common_test/src/ct_cover.erl32
-rw-r--r--lib/common_test/src/ct_framework.erl368
-rw-r--r--lib/common_test/src/ct_groups.erl599
-rw-r--r--lib/common_test/src/ct_master.erl2
-rw-r--r--lib/common_test/src/ct_master_logs.erl2
-rw-r--r--lib/common_test/src/ct_netconfc.erl41
-rw-r--r--lib/common_test/src/ct_run.erl196
-rw-r--r--lib/common_test/src/ct_slave.erl67
-rw-r--r--lib/common_test/src/ct_testspec.erl28
-rw-r--r--lib/common_test/src/ct_util.hrl1
-rw-r--r--lib/common_test/src/cth_conn_log.erl2
-rw-r--r--lib/common_test/src/cth_log_redirect.erl2
-rw-r--r--lib/common_test/src/cth_surefire.erl183
-rw-r--r--lib/common_test/test/Makefile8
-rw-r--r--lib/common_test/test/common_test.cover10
-rw-r--r--lib/common_test/test/ct_config_SUITE.erl6
-rw-r--r--lib/common_test/test/ct_config_SUITE_data/config/test/config_static_SUITE.erl10
-rw-r--r--lib/common_test/test/ct_config_info_SUITE.erl14
-rw-r--r--lib/common_test/test/ct_cover_SUITE.erl312
-rw-r--r--lib/common_test/test/ct_cover_SUITE_data/cover_SUITE.erl156
-rw-r--r--lib/common_test/test/ct_cover_SUITE_data/cover_SUITE_data/.gitignore0
-rw-r--r--lib/common_test/test/ct_cover_SUITE_data/cover_test_mod.erl4
-rw-r--r--lib/common_test/test/ct_error_SUITE.erl446
-rw-r--r--lib/common_test/test/ct_error_SUITE_data/error/test/misc_error_1_SUITE.erl12
-rw-r--r--lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_8_SUITE.erl258
-rw-r--r--lib/common_test/test/ct_group_leader_SUITE.erl181
-rw-r--r--lib/common_test/test/ct_group_leader_SUITE_data/group_leader_SUITE.erl252
-rw-r--r--lib/common_test/test/ct_groups_search_SUITE.erl1245
-rw-r--r--lib/common_test/test/ct_groups_search_SUITE_data/groups_search_dummy_1_SUITE.erl83
-rw-r--r--lib/common_test/test/ct_groups_search_SUITE_data/groups_search_dummy_2_SUITE.erl102
-rw-r--r--lib/common_test/test/ct_master_SUITE.erl57
-rw-r--r--lib/common_test/test/ct_master_SUITE_data/master/master_SUITE.erl9
-rw-r--r--lib/common_test/test/ct_netconfc_SUITE.erl9
-rw-r--r--lib/common_test/test/ct_surefire_SUITE.erl351
-rw-r--r--lib/common_test/test/ct_surefire_SUITE_data/surefire_SUITE.erl92
-rw-r--r--lib/common_test/test/ct_system_error_SUITE.erl2
-rw-r--r--lib/common_test/test/ct_test_support.erl94
-rw-r--r--lib/common_test/vsn.mk2
-rw-r--r--lib/compiler/doc/src/compile.xml26
-rw-r--r--lib/compiler/src/Makefile13
-rw-r--r--lib/compiler/src/beam_a.erl97
-rw-r--r--lib/compiler/src/beam_block.erl77
-rw-r--r--lib/compiler/src/beam_bool.erl41
-rw-r--r--lib/compiler/src/beam_bsm.erl157
-rw-r--r--lib/compiler/src/beam_clean.erl45
-rw-r--r--lib/compiler/src/beam_dead.erl16
-rw-r--r--lib/compiler/src/beam_dict.erl18
-rw-r--r--lib/compiler/src/beam_except.erl4
-rw-r--r--lib/compiler/src/beam_flatten.erl53
-rw-r--r--lib/compiler/src/beam_jump.erl127
-rw-r--r--lib/compiler/src/beam_peep.erl8
-rw-r--r--lib/compiler/src/beam_receive.erl54
-rw-r--r--lib/compiler/src/beam_trim.erl68
-rw-r--r--lib/compiler/src/beam_utils.erl284
-rw-r--r--lib/compiler/src/beam_z.erl79
-rw-r--r--lib/compiler/src/compile.erl73
-rw-r--r--lib/compiler/src/compiler.app.src3
-rw-r--r--lib/compiler/src/core_lint.erl3
-rw-r--r--lib/compiler/src/core_scan.erl27
-rw-r--r--lib/compiler/src/sys_core_fold.erl112
-rw-r--r--lib/compiler/src/sys_expand_pmod.erl433
-rw-r--r--lib/compiler/src/sys_pre_expand.erl147
-rw-r--r--lib/compiler/src/v3_codegen.erl101
-rw-r--r--lib/compiler/src/v3_kernel.erl84
-rw-r--r--lib/compiler/test/Makefile5
-rw-r--r--lib/compiler/test/andor_SUITE.erl7
-rw-r--r--lib/compiler/test/beam_except_SUITE.erl (renamed from lib/compiler/test/beam_expect_SUITE.erl)2
-rw-r--r--lib/compiler/test/beam_validator_SUITE.erl19
-rw-r--r--lib/compiler/test/bs_bit_binaries_SUITE.erl12
-rw-r--r--lib/compiler/test/bs_construct_SUITE.erl34
-rw-r--r--lib/compiler/test/bs_match_SUITE.erl98
-rw-r--r--lib/compiler/test/compilation_SUITE.erl42
-rw-r--r--lib/compiler/test/compile_SUITE.erl30
-rw-r--r--lib/compiler/test/core_SUITE.erl8
-rw-r--r--lib/compiler/test/core_fold_SUITE.erl8
-rw-r--r--lib/compiler/test/error_SUITE.erl43
-rw-r--r--lib/compiler/test/guard_SUITE.erl19
-rw-r--r--lib/compiler/test/inline_SUITE.erl74
-rw-r--r--lib/compiler/test/match_SUITE.erl8
-rw-r--r--lib/compiler/test/misc_SUITE.erl22
-rw-r--r--lib/compiler/test/pmod_SUITE.erl121
-rw-r--r--lib/compiler/test/pmod_SUITE_data/pmod_basic.erl83
-rw-r--r--lib/compiler/test/receive_SUITE.erl6
-rw-r--r--lib/compiler/test/receive_SUITE_data/ref_opt/no_4.erl12
-rw-r--r--lib/compiler/test/receive_SUITE_data/ref_opt/yes_10.erl13
-rw-r--r--lib/compiler/test/receive_SUITE_data/ref_opt/yes_11.erl21
-rw-r--r--lib/compiler/test/receive_SUITE_data/ref_opt/yes_12.erl12
-rw-r--r--lib/compiler/test/receive_SUITE_data/ref_opt/yes_13.erl12
-rw-r--r--lib/compiler/test/record_SUITE.erl10
-rw-r--r--lib/compiler/test/test_lib.erl15
-rw-r--r--lib/compiler/test/trycatch_SUITE.erl12
-rw-r--r--lib/compiler/test/warnings_SUITE.erl14
-rw-r--r--lib/cosEvent/src/Makefile16
-rw-r--r--lib/cosEventDomain/src/Makefile10
-rw-r--r--lib/cosFileTransfer/src/Makefile10
-rw-r--r--lib/cosNotification/src/Makefile24
-rw-r--r--lib/cosProperty/src/Makefile10
-rw-r--r--lib/cosTime/src/Makefile18
-rw-r--r--lib/cosTransactions/src/Makefile10
-rw-r--r--lib/crypto/c_src/Makefile.in55
-rw-r--r--lib/crypto/c_src/crypto.c326
-rw-r--r--lib/crypto/c_src/crypto_callback.c165
-rw-r--r--lib/crypto/c_src/crypto_callback.h46
-rwxr-xr-x[-rw-r--r--]lib/crypto/doc/src/crypto.xml37
-rw-r--r--lib/crypto/doc/src/crypto_app.xml2
-rw-r--r--lib/crypto/doc/src/notes.xml2
-rw-r--r--lib/crypto/src/Makefile4
-rw-r--r--lib/crypto/src/crypto.erl134
-rw-r--r--lib/crypto/test/crypto_SUITE.erl354
-rw-r--r--lib/debugger/src/Makefile4
-rw-r--r--lib/debugger/src/dbg_debugged.erl5
-rw-r--r--lib/debugger/src/dbg_ieval.erl6
-rw-r--r--lib/debugger/src/dbg_ui_trace.erl12
-rw-r--r--lib/debugger/src/dbg_ui_trace_win.erl4
-rw-r--r--lib/debugger/src/dbg_wx_code.erl33
-rw-r--r--lib/debugger/src/dbg_wx_filedialog_win.erl9
-rw-r--r--lib/debugger/src/dbg_wx_settings.erl48
-rw-r--r--lib/debugger/src/dbg_wx_trace.erl14
-rw-r--r--lib/debugger/src/dbg_wx_trace_win.erl19
-rw-r--r--lib/debugger/src/dbg_wx_win.erl10
-rw-r--r--lib/debugger/src/int.erl25
-rw-r--r--lib/dialyzer/doc/src/dialyzer.xml8
-rw-r--r--lib/dialyzer/doc/src/dialyzer_chapter.xml6
-rw-r--r--lib/dialyzer/doc/src/notes.xml18
-rw-r--r--lib/dialyzer/src/Makefile12
-rw-r--r--lib/dialyzer/src/dialyzer.erl19
-rw-r--r--lib/dialyzer/src/dialyzer_analysis_callgraph.erl9
-rw-r--r--lib/dialyzer/src/dialyzer_behaviours.erl106
-rw-r--r--lib/dialyzer/src/dialyzer_dataflow.erl53
-rw-r--r--lib/dialyzer/src/dialyzer_races.erl5
-rw-r--r--lib/dialyzer/test/options1_SUITE_data/src/compiler/core_scan.erl25
-rw-r--r--lib/dialyzer/test/options1_SUITE_data/src/compiler/sys_pre_expand.erl56
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/results/mnesia3
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_check.erl2
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen.erl4
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1rt_ber_bin.erl2
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1rt_ber_bin_v2.erl2
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1rt_per_bin_rt2ct.erl2
-rw-r--r--lib/dialyzer/test/race_SUITE_data/results/ets_insert_args102
-rw-r--r--lib/dialyzer/test/race_SUITE_data/src/ets_insert_args10.erl19
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes2
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/port_info_test4
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/record_creation_diffs3
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/comm_layer/comm_connection.erl5
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/comm_layer/comm_port.erl5
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/record_creation_diffs.erl11
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/remote_tuple_set.erl8
-rw-r--r--lib/dialyzer/vsn.mk2
-rw-r--r--lib/diameter/.gitignore57
-rw-r--r--lib/diameter/Makefile32
-rw-r--r--lib/diameter/Makefile.in88
-rw-r--r--lib/diameter/aclocal.m465
-rwxr-xr-xlib/diameter/autoconf/config.guess1519
-rwxr-xr-xlib/diameter/autoconf/config.sub1630
-rwxr-xr-xlib/diameter/autoconf/install-sh519
-rw-r--r--lib/diameter/configure.in137
-rw-r--r--lib/diameter/doc/.gitignore4
-rw-r--r--lib/diameter/doc/src/.gitignore1
-rw-r--r--lib/diameter/doc/src/Makefile21
-rw-r--r--lib/diameter/doc/src/diameter.xml871
-rw-r--r--lib/diameter/doc/src/diameter_app.xml445
-rw-r--r--lib/diameter/doc/src/diameter_codec.xml389
-rw-r--r--lib/diameter/doc/src/diameter_compile.xml62
-rw-r--r--lib/diameter/doc/src/diameter_dict.xml190
-rw-r--r--lib/diameter/doc/src/diameter_intro.xml11
-rw-r--r--lib/diameter/doc/src/diameter_make.xml144
-rw-r--r--lib/diameter/doc/src/diameter_sctp.xml53
-rw-r--r--lib/diameter/doc/src/diameter_soc.xml30
-rw-r--r--lib/diameter/doc/src/diameter_tcp.xml69
-rw-r--r--lib/diameter/doc/src/diameter_transport.xml140
-rw-r--r--lib/diameter/doc/src/files.mk4
-rw-r--r--lib/diameter/doc/src/notes.xml214
-rw-r--r--lib/diameter/doc/src/ref_man.xml3
-rw-r--r--lib/diameter/doc/src/seealso.ent132
-rw-r--r--lib/diameter/doc/src/seehere.sed35
-rw-r--r--lib/diameter/doc/standard/draft-ietf-dime-capablities-update-07.txt392
-rw-r--r--lib/diameter/doc/standard/rfc6733.txt (renamed from lib/diameter/doc/standard/draft-ietf-dime-rfc3588bis-26.txt)6264
-rw-r--r--lib/diameter/doc/standard/rfc6737.txt339
-rw-r--r--lib/diameter/make/release_targets.mk92
-rw-r--r--lib/diameter/make/rules.mk.in193
-rw-r--r--lib/diameter/make/subdir.mk53
-rw-r--r--lib/diameter/make/target.mk33
-rw-r--r--lib/diameter/src/Makefile19
-rw-r--r--lib/diameter/src/base/diameter.appup.src39
-rw-r--r--lib/diameter/src/base/diameter.erl18
-rw-r--r--lib/diameter/src/base/diameter_capx.erl8
-rw-r--r--lib/diameter/src/base/diameter_codec.erl11
-rw-r--r--lib/diameter/src/base/diameter_config.erl83
-rw-r--r--lib/diameter/src/base/diameter_peer.erl2
-rw-r--r--lib/diameter/src/base/diameter_peer_fsm.erl364
-rw-r--r--lib/diameter/src/base/diameter_reg.erl255
-rw-r--r--lib/diameter/src/base/diameter_service.erl846
-rw-r--r--lib/diameter/src/base/diameter_session.erl14
-rw-r--r--lib/diameter/src/base/diameter_watchdog.erl170
-rw-r--r--lib/diameter/test/Makefile9
-rw-r--r--lib/diameter/test/diameter_compiler_SUITE.erl12
-rw-r--r--lib/diameter/test/diameter_dpr_SUITE.erl196
-rw-r--r--lib/diameter/test/diameter_event_SUITE.erl182
-rw-r--r--lib/diameter/test/diameter_failover_SUITE.erl141
-rw-r--r--lib/diameter/test/diameter_traffic_SUITE.erl372
-rw-r--r--lib/diameter/test/diameter_util.erl18
-rw-r--r--lib/diameter/test/diameter_watchdog_SUITE.erl711
-rw-r--r--lib/diameter/test/modules.mk6
-rw-r--r--lib/diameter/vsn.mk4
-rw-r--r--lib/edoc/doc/src/notes.xml2
-rw-r--r--lib/edoc/priv/Makefile7
-rw-r--r--lib/edoc/priv/edoc.dtd4
-rw-r--r--lib/edoc/src/Makefile6
-rw-r--r--lib/edoc/src/edoc.erl9
-rw-r--r--lib/edoc/src/edoc.hrl6
-rw-r--r--lib/edoc/src/edoc_data.erl3
-rw-r--r--lib/edoc/src/edoc_doclet.erl28
-rw-r--r--lib/edoc/src/edoc_extract.erl16
-rw-r--r--lib/edoc/src/edoc_layout.erl15
-rw-r--r--lib/edoc/src/edoc_lib.erl67
-rw-r--r--lib/edoc/src/edoc_macros.erl4
-rw-r--r--lib/edoc/src/edoc_parser.yrl8
-rw-r--r--lib/edoc/src/edoc_refs.erl19
-rw-r--r--lib/edoc/src/edoc_wiki.erl3
-rw-r--r--lib/eldap/src/Makefile6
-rw-r--r--lib/eldap/src/eldap.erl24
-rw-r--r--lib/eldap/vsn.mk2
-rw-r--r--lib/erl_docgen/doc/src/doc-build.xml5
-rw-r--r--lib/erl_docgen/doc/src/notes.xml18
-rwxr-xr-xlib/erl_docgen/priv/bin/xml_from_edoc.escript8
-rw-r--r--lib/erl_docgen/priv/dtd/common.refs.dtd7
-rw-r--r--lib/erl_docgen/priv/dtd/erlref.dtd3
-rw-r--r--lib/erl_docgen/priv/fop.xconf45
-rw-r--r--lib/erl_docgen/priv/xsl/Makefile3
-rw-r--r--lib/erl_docgen/priv/xsl/db_html.xsl36
-rw-r--r--lib/erl_docgen/priv/xsl/db_pdf.xsl14
-rw-r--r--lib/erl_docgen/priv/xsl/db_pdf_params.xsl38
-rw-r--r--lib/erl_docgen/src/Makefile4
-rw-r--r--lib/erl_docgen/src/docgen_edoc_xml_cb.erl37
-rw-r--r--lib/erl_docgen/src/docgen_xmerl_xml_cb.erl28
-rw-r--r--lib/erl_docgen/vsn.mk3
-rw-r--r--lib/erl_interface/aclocal.m435
-rw-r--r--lib/erl_interface/configure.in14
-rw-r--r--lib/erl_interface/doc/src/notes.xml18
-rw-r--r--lib/erl_interface/src/Makefile5
-rw-r--r--lib/erl_interface/src/Makefile.in145
-rw-r--r--lib/erl_interface/src/connect/ei_resolve.c8
-rw-r--r--lib/erl_interface/test/ei_decode_SUITE.erl9
-rw-r--r--lib/erl_interface/test/ei_encode_SUITE.erl13
-rw-r--r--lib/erl_interface/test/ei_print_SUITE.erl4
-rw-r--r--lib/erl_interface/vsn.mk2
-rw-r--r--lib/et/src/Makefile4
-rw-r--r--lib/et/src/et.erl4
-rw-r--r--lib/eunit/doc/src/notes.xml2
-rw-r--r--lib/eunit/include/eunit.hrl157
-rw-r--r--lib/eunit/src/Makefile4
-rw-r--r--lib/eunit/src/eunit.erl5
-rw-r--r--lib/eunit/src/eunit_autoexport.erl7
-rw-r--r--lib/eunit/src/eunit_lib.erl5
-rw-r--r--lib/eunit/src/eunit_surefire.erl5
-rw-r--r--lib/gs/contribs/bonk/Makefile8
-rw-r--r--lib/gs/contribs/cols/Makefile12
-rw-r--r--lib/gs/contribs/mandel/Makefile12
-rw-r--r--lib/gs/contribs/mandel/mandel.erl3
-rw-r--r--lib/gs/contribs/othello/Makefile8
-rw-r--r--lib/gs/src/Makefile6
-rw-r--r--lib/gs/src/gstk_editor.erl6
-rw-r--r--lib/hipe/Makefile10
-rw-r--r--lib/hipe/amd64/hipe_amd64_encode.erl10
-rw-r--r--lib/hipe/cerl/erl_bif_types.erl49
-rw-r--r--lib/hipe/cerl/erl_types.erl10
-rw-r--r--lib/hipe/doc/src/notes.xml16
-rw-r--r--lib/hipe/flow/hipe_dominators.erl6
-rw-r--r--lib/hipe/icode/hipe_icode_mulret.erl14
-rw-r--r--lib/hipe/main/Makefile8
-rw-r--r--lib/hipe/regalloc/hipe_coalescing_regalloc.erl8
-rw-r--r--lib/hipe/regalloc/hipe_optimistic_regalloc.erl12
-rw-r--r--lib/hipe/regalloc/hipe_reg_worklists.erl6
-rw-r--r--lib/hipe/rtl/Makefile4
-rw-r--r--lib/hipe/rtl/hipe_rtl_arith.inc6
-rw-r--r--lib/hipe/rtl/hipe_rtl_mk_switch.erl6
-rw-r--r--lib/hipe/rtl/hipe_rtl_primops.erl6
-rw-r--r--lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl6
-rw-r--r--lib/hipe/rtl/hipe_rtl_ssapre.erl10
-rw-r--r--lib/hipe/ssa/hipe_ssa.inc6
-rw-r--r--lib/hipe/vsn.mk2
-rw-r--r--lib/hipe/x86/hipe_x86_assemble.erl4
-rw-r--r--lib/hipe/x86/hipe_x86_postpass.erl8
-rw-r--r--lib/hipe/x86/hipe_x86_ra_postconditions.erl4
-rw-r--r--lib/ic/c_src/Makefile.in10
-rw-r--r--lib/ic/examples/pre_post_condition/Makefile4
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/Makefile5
-rw-r--r--lib/ic/src/Makefile4
-rw-r--r--lib/ic/test/java_client_erl_server_SUITE.erl11
-rw-r--r--lib/ic/test/java_client_erl_server_SUITE_data/Makefile.src14
-rw-r--r--lib/inets/doc/src/http_uri.xml5
-rw-r--r--lib/inets/doc/src/httpd.xml10
-rw-r--r--lib/inets/doc/src/notes.xml22
-rw-r--r--lib/inets/src/http_server/httpd_conf.erl15
-rw-r--r--lib/inets/src/http_server/httpd_request_handler.erl62
-rw-r--r--lib/inets/src/inets_app/Makefile4
-rw-r--r--lib/inets/src/inets_app/inets.appup.src14
-rw-r--r--lib/inets/test/erl_make_certs.erl4
-rw-r--r--lib/inets/test/ftp_suite_lib.erl1
-rw-r--r--lib/inets/test/httpc_SUITE.erl2
-rw-r--r--lib/inets/test/httpc_cookie_SUITE.erl3
-rw-r--r--lib/inets/test/httpd_SUITE.erl18
-rw-r--r--lib/inets/test/httpd_basic_SUITE.erl16
-rw-r--r--lib/inets/test/inets_SUITE.erl7
-rw-r--r--lib/inets/test/inets_app_test.erl18
-rw-r--r--lib/inets/test/inets_sup_SUITE.erl6
-rw-r--r--lib/inets/vsn.mk2
-rw-r--r--lib/jinterface/java_src/Makefile2
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile19
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/OtpEpmd.java2
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/OtpInputStream.java12
-rw-r--r--lib/jinterface/test/jitu.erl2
-rw-r--r--lib/jinterface/test/nc_SUITE.erl25
-rw-r--r--lib/kernel/doc/src/Makefile1
-rw-r--r--lib/kernel/doc/src/application.xml9
-rw-r--r--lib/kernel/doc/src/error_handler.xml38
-rw-r--r--lib/kernel/doc/src/file.xml40
-rw-r--r--lib/kernel/doc/src/heart.xml35
-rw-r--r--lib/kernel/doc/src/inet.xml195
-rw-r--r--lib/kernel/doc/src/notes.xml38
-rw-r--r--lib/kernel/doc/src/packages.xml208
-rw-r--r--lib/kernel/doc/src/ref_man.xml1
-rw-r--r--lib/kernel/src/Makefile11
-rw-r--r--lib/kernel/src/application.erl16
-rw-r--r--lib/kernel/src/application_controller.erl2
-rw-r--r--lib/kernel/src/code.erl6
-rw-r--r--lib/kernel/src/code_server.erl9
-rw-r--r--lib/kernel/src/disk_log.erl2
-rw-r--r--lib/kernel/src/dist_util.erl3
-rw-r--r--lib/kernel/src/erl_ddll.erl4
-rw-r--r--lib/kernel/src/error_handler.erl53
-rw-r--r--lib/kernel/src/file.erl21
-rw-r--r--lib/kernel/src/file_io_server.erl22
-rw-r--r--lib/kernel/src/gen_sctp.erl2
-rw-r--r--lib/kernel/src/gen_tcp.erl10
-rw-r--r--lib/kernel/src/gen_udp.erl6
-rw-r--r--lib/kernel/src/group.erl8
-rw-r--r--lib/kernel/src/heart.erl5
-rw-r--r--lib/kernel/src/inet.erl64
-rw-r--r--lib/kernel/src/inet_int.hrl5
-rw-r--r--lib/kernel/src/inet_parse.erl13
-rw-r--r--lib/kernel/src/kernel.app.src1
-rw-r--r--lib/kernel/src/packages.erl158
-rw-r--r--lib/kernel/src/pg2.erl4
-rw-r--r--lib/kernel/src/ram_file.erl7
-rw-r--r--lib/kernel/src/rpc.erl2
-rw-r--r--lib/kernel/src/user.erl190
-rw-r--r--lib/kernel/src/wrap_log_reader.erl4
-rw-r--r--lib/kernel/test/Makefile2
-rw-r--r--lib/kernel/test/application_SUITE.erl13
-rw-r--r--lib/kernel/test/code_SUITE.erl4
-rw-r--r--lib/kernel/test/error_handler_SUITE.erl68
-rw-r--r--lib/kernel/test/error_logger_warn_SUITE.erl4
-rw-r--r--lib/kernel/test/file_SUITE.erl72
-rw-r--r--lib/kernel/test/file_name_SUITE.erl165
-rw-r--r--lib/kernel/test/gen_sctp_SUITE.erl50
-rw-r--r--lib/kernel/test/gen_udp_SUITE.erl5
-rw-r--r--lib/kernel/test/global_SUITE.erl158
-rw-r--r--lib/kernel/test/heart_SUITE.erl430
-rw-r--r--lib/kernel/test/ignore_cores.erl158
-rw-r--r--lib/kernel/test/inet_SUITE.erl21
-rw-r--r--lib/kernel/test/inet_sockopt_SUITE.erl155
-rw-r--r--lib/kernel/test/interactive_shell_SUITE.erl215
-rw-r--r--lib/kernel/test/kernel.cover2
-rw-r--r--lib/kernel/test/prim_file_SUITE.erl74
-rw-r--r--lib/kernel/test/ram_file_SUITE.erl17
-rw-r--r--lib/kernel/test/wrap_log_reader_SUITE.erl4
-rw-r--r--lib/megaco/aclocal.m41905
-rw-r--r--lib/megaco/configure.in5
-rw-r--r--lib/megaco/doc/src/megaco_encode.xml23
-rw-r--r--lib/megaco/examples/meas/Makefile.in8
-rw-r--r--lib/megaco/examples/meas/megaco_codec_meas.erl14
-rw-r--r--lib/megaco/examples/meas/megaco_codec_mstone_lib.erl38
-rw-r--r--lib/megaco/examples/meas/megaco_codec_transform.erl4
-rw-r--r--lib/megaco/src/app/Makefile4
-rw-r--r--lib/megaco/src/app/megaco.app.src26
-rw-r--r--lib/megaco/src/binary/Makefile39
-rw-r--r--lib/megaco/src/binary/depend.mk329
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3a.asn1config43
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3a.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3b.asn1config43
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3b.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3c.asn1config43
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3c.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v1.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v2.asn1config43
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v2.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v3.asn1config43
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v3.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_encoder.erl716
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3a.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3b.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3c.asn1config43
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3c.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v1.asn1config44
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v1.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v2.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v3.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3a.asn1config (renamed from lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v2.asn1config)4
-rw-r--r--lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3b.asn1config (renamed from lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v3.asn1config)4
-rw-r--r--lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3c.asn1config (renamed from lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3a.asn1config)4
-rw-r--r--lib/megaco/src/binary/megaco_ber_media_gateway_control_v1.asn1config (renamed from lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v1.asn1config)6
-rw-r--r--lib/megaco/src/binary/megaco_ber_media_gateway_control_v3.asn1config (renamed from lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3b.asn1config)4
-rw-r--r--lib/megaco/src/binary/megaco_binary_encoder.erl285
-rw-r--r--lib/megaco/src/binary/megaco_binary_encoder_lib.erl15
-rw-r--r--lib/megaco/src/binary/megaco_binary_name_resolver_prev3a.erl6
-rw-r--r--lib/megaco/src/binary/megaco_binary_name_resolver_prev3b.erl6
-rw-r--r--lib/megaco/src/binary/megaco_binary_name_resolver_prev3c.erl6
-rw-r--r--lib/megaco/src/binary/megaco_binary_name_resolver_v3.erl6
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3a.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3b.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3c.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v1.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v2.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v3.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_encoder.erl447
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3a.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3b.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3c.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v1.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v2.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v3.set.asn1
-rw-r--r--lib/megaco/src/binary/modules.mk50
-rw-r--r--lib/megaco/src/flex/Makefile.in46
-rw-r--r--lib/megaco/test/megaco_actions_test.erl36
-rw-r--r--lib/megaco/test/megaco_call_flow_test.erl22
-rw-r--r--lib/megaco/test/megaco_codec_prev3a_test.erl35
-rw-r--r--lib/megaco/test/megaco_codec_prev3b_test.erl34
-rw-r--r--lib/megaco/test/megaco_codec_prev3c_test.erl43
-rw-r--r--lib/megaco/test/megaco_codec_v1_test.erl36
-rw-r--r--lib/megaco/test/megaco_codec_v2_test.erl35
-rw-r--r--lib/megaco/test/megaco_codec_v3_test.erl43
-rw-r--r--lib/megaco/test/megaco_mess_test.erl4
-rw-r--r--lib/megaco/test/megaco_mib_test.erl6
-rw-r--r--lib/megaco/test/megaco_test_mg.erl2
-rw-r--r--lib/megaco/test/megaco_test_mgc.erl2
-rw-r--r--lib/mnesia/src/Makefile4
-rw-r--r--lib/mnesia/src/mnesia_controller.erl15
-rw-r--r--lib/mnesia/src/mnesia_event.erl2
-rw-r--r--lib/mnesia/src/mnesia_locker.erl6
-rw-r--r--lib/mnesia/src/mnesia_recover.erl66
-rw-r--r--lib/mnesia/src/mnesia_tm.erl3
-rw-r--r--lib/observer/doc/src/notes.xml2
-rw-r--r--lib/observer/src/Makefile4
-rw-r--r--lib/observer/src/observer_app_wx.erl7
-rw-r--r--lib/observer/src/observer_perf_wx.erl14
-rw-r--r--lib/observer/src/observer_pro_wx.erl2
-rw-r--r--lib/observer/src/observer_tv_table.erl2
-rw-r--r--lib/observer/src/observer_wx.erl100
-rw-r--r--lib/observer/test/crashdump_viewer_SUITE.erl66
-rw-r--r--lib/odbc/aclocal.m435
-rw-r--r--lib/odbc/c_src/Makefile.in6
-rw-r--r--lib/odbc/c_src/odbcserver.c128
-rw-r--r--lib/odbc/c_src/odbcserver.h4
-rw-r--r--lib/odbc/configure.in5
-rw-r--r--lib/odbc/doc/src/notes.xml2
-rw-r--r--lib/odbc/doc/src/odbc.xml37
-rw-r--r--lib/odbc/src/Makefile4
-rw-r--r--lib/odbc/src/odbc.erl5
-rw-r--r--lib/odbc/test/odbc_connect_SUITE.erl32
-rw-r--r--lib/odbc/test/odbc_data_type_SUITE.erl7
-rw-r--r--lib/odbc/vsn.mk2
-rw-r--r--lib/orber/COSS/CosNaming/Makefile8
-rw-r--r--lib/orber/c_src/Makefile.in6
-rw-r--r--lib/orber/doc/src/ch_idl_to_erlang_mapping.xml5
-rw-r--r--lib/orber/examples/Stack/Makefile4
-rw-r--r--lib/orber/src/Makefile19
-rw-r--r--lib/orber/src/orber_iiop_net.erl24
-rw-r--r--lib/os_mon/c_src/Makefile.in16
-rw-r--r--lib/os_mon/mibs/Makefile8
-rw-r--r--lib/os_mon/src/Makefile4
-rw-r--r--lib/os_mon/src/os_mon.erl4
-rw-r--r--lib/otp_mibs/mibs/Makefile2
-rw-r--r--lib/otp_mibs/src/Makefile4
-rw-r--r--lib/parsetools/include/yeccpre.hrl6
-rw-r--r--lib/parsetools/src/Makefile4
-rw-r--r--lib/parsetools/src/esyntax.yrl360
-rw-r--r--lib/parsetools/src/leex.erl99
-rw-r--r--lib/parsetools/src/yecc.erl120
-rw-r--r--lib/parsetools/src/yeccscan.erl6
-rw-r--r--lib/parsetools/test/leex_SUITE.erl115
-rw-r--r--lib/parsetools/test/yecc_SUITE.erl154
-rw-r--r--lib/percept/doc/src/notes.xml15
-rw-r--r--lib/percept/src/Makefile4
-rw-r--r--lib/percept/src/percept.app.src2
-rw-r--r--lib/percept/vsn.mk2
-rw-r--r--lib/pman/src/Makefile4
-rw-r--r--lib/public_key/asn1/AuthenticationFramework.asn1367
-rw-r--r--lib/public_key/asn1/InformationFramework.asn1682
-rw-r--r--lib/public_key/asn1/Makefile18
-rw-r--r--lib/public_key/asn1/OTP-PUB-KEY.asn1config3
-rw-r--r--lib/public_key/asn1/OTP-PUB-KEY.set.asn2
-rw-r--r--lib/public_key/asn1/PKCS-10.asn170
-rw-r--r--lib/public_key/asn1/PKCS-7.asn1387
-rw-r--r--lib/public_key/asn1/PKIX1Explicit88.asn15
-rw-r--r--lib/public_key/asn1/SelectedAttributeTypes.asn11575
-rw-r--r--lib/public_key/asn1/UsefulDefinitions.asn1234
-rw-r--r--lib/public_key/doc/src/cert_records.xml76
-rw-r--r--lib/public_key/doc/src/introduction.xml25
-rw-r--r--lib/public_key/doc/src/notes.xml35
-rw-r--r--lib/public_key/doc/src/part.xml8
-rw-r--r--lib/public_key/doc/src/public_key.xml171
-rw-r--r--lib/public_key/doc/src/public_key_records.xml12
-rw-r--r--lib/public_key/doc/src/using_public_key.xml8
-rw-r--r--lib/public_key/include/public_key.hrl21
-rw-r--r--lib/public_key/src/Makefile7
-rw-r--r--lib/public_key/src/pubkey_cert.erl228
-rw-r--r--lib/public_key/src/pubkey_cert_records.erl6
-rw-r--r--lib/public_key/src/pubkey_crl.erl701
-rw-r--r--lib/public_key/src/pubkey_pem.erl27
-rw-r--r--lib/public_key/src/public_key.app.src1
-rw-r--r--lib/public_key/src/public_key.erl188
-rw-r--r--lib/public_key/test/erl_make_certs.erl11
-rw-r--r--lib/public_key/test/pbe_SUITE.erl105
-rw-r--r--lib/public_key/test/pkits_SUITE.erl1351
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/BadCRLIssuerNameCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/BadCRLSignatureCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/BadSignedCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/BadnotAfterDateCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/BadnotBeforeDateCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/BasicSelfIssuedCRLSigningKeyCACRL.pem13
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/BasicSelfIssuedCRLSigningKeyCRLCertCRL.pem15
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/BasicSelfIssuedNewKeyCACRL.pem13
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/BasicSelfIssuedOldKeyCACRL.pem13
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/BasicSelfIssuedOldKeySelfIssuedCertCRL.pem15
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/DSACACRL.pem7
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/DSAParametersInheritedCACRL.pem8
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/GeneralizedTimeCRLnextUpdateCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/GoodCACRL.pem13
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/GoodsubCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/GoodsubCAPanyPolicyMapping1to2CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/LongSerialNumberCACRL.pem13
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/Mapping1to2CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/MappingFromanyPolicyCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/MappingToanyPolicyCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/MissingbasicConstraintsCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/NameOrderCACRL.pem14
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/NegativeSerialNumberCACRL.pem13
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/NoPoliciesCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/NoissuingDistributionPointCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/OldCRLnextUpdateCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/P12Mapping1to3CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/P12Mapping1to3subCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/P12Mapping1to3subsubCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/P1Mapping1to234CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/P1Mapping1to234subCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/P1anyPolicyMapping1to2CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/PanyPolicyMapping1to2CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP1234CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP1234subCAP123CRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP1234subsubCAP123P12CRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP123CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP123subCAP12CRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP123subsubCAP12P1CRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP123subsubCAP2P2CRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP123subsubsubCAP12P2P1CRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP12CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP12subCAP1CRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP12subsubCAP1P2CRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP2subCA2CRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP2subCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP3CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/RFC3280MandatoryAttributeTypesCACRL.pem14
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/RFC3280OptionalAttributeTypesCACRL.pem14
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/RevokedsubCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/RolloverfromPrintableStringtoUTF8StringCACRL.pem13
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/SeparateCertificateandCRLKeysCA2CRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/SeparateCertificateandCRLKeysCRL.pem13
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/TrustAnchorRootCRL.pem13
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/TwoCRLsCABadCRL.pem13
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/TwoCRLsCAGoodCRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/UIDCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/UTF8StringCaseInsensitiveMatchCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/UTF8StringEncodedNamesCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/UnknownCRLEntryExtensionCACRL.pem13
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/UnknownCRLExtensionCACRL.pem13
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/WrongCRLCACRL.pem13
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/anyPolicyCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/basicConstraintsCriticalcAFalseCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/basicConstraintsNotCriticalCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/basicConstraintsNotCriticalcAFalseCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/deltaCRLCA1CRL.pem16
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/deltaCRLCA1deltaCRL.pem15
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/deltaCRLCA2CRL.pem15
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/deltaCRLCA2deltaCRL.pem13
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/deltaCRLCA3CRL.pem14
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/deltaCRLCA3deltaCRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/deltaCRLIndicatorNoBaseCACRL.pem13
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/distributionPoint1CACRL.pem16
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/distributionPoint2CACRL.pem14
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/indirectCRLCA1CRL.pem13
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/indirectCRLCA3CRL.pem14
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/indirectCRLCA3cRLIssuerCRL.pem15
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/indirectCRLCA4cRLIssuerCRL.pem15
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/indirectCRLCA5CRL.pem35
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy0CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy1CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy1subCA1CRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy1subCA2CRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy1subCAIAP5CRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy1subsubCA2CRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy5CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy5subCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy5subsubCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping0CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping0subCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P12CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P12subCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P12subCAIPM5CRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P12subsubCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P12subsubCAIPM5CRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P1CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P1subCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P1subsubCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping5CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping5subCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping5subsubCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping5subsubsubCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/keyUsageCriticalcRLSignFalseCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/keyUsageCriticalkeyCertSignFalseCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/keyUsageNotCriticalCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/keyUsageNotCriticalcRLSignFalseCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/keyUsageNotCriticalkeyCertSignFalseCACRL.pem13
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN1CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN1subCA1CRL.pem13
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN1subCA2CRL.pem13
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN1subCA3CRL.pem13
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN2CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN3CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN3subCA1CRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN3subCA2CRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN4CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN5CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDNS1CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDNS2CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsRFC822CA1CRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsRFC822CA2CRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsRFC822CA3CRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsURI1CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsURI2CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/onlyContainsAttributeCertsCACRL.pem13
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/onlyContainsCACertsCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/onlyContainsUserCertsCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA1compromiseCRL.pem13
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA1otherreasonsCRL.pem13
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA2CRL1.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA2CRL2.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA3compromiseCRL.pem15
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA3otherreasonsCRL.pem15
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA4compromiseCRL.pem15
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA4otherreasonsCRL.pem15
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint0CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint0subCA2CRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint0subCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint1CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint1subCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subCA0CRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subCA1CRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subCA4CRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subsubCA00CRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subsubCA11CRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subsubCA41CRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subsubsubCA11XCRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subsubsubCA41XCRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/pre2000CRLnextUpdateCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy0CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy0subCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy0subsubCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy0subsubsubCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy10CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy10subCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy10subsubCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy10subsubsubCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy2CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy2subCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy4CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy4subCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy4subsubCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy4subsubsubCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy5CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy5subCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy5subsubCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy5subsubsubCACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy7CACRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy7subCARE2CRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy7subsubCARE2RE4CRL.pem12
-rw-r--r--lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy7subsubsubCARE2RE4CRL.pem12
-rw-r--r--lib/public_key/test/public_key_SUITE.erl306
-rw-r--r--lib/public_key/test/public_key_SUITE_data/pkcs7_cert.pem23
-rw-r--r--lib/public_key/vsn.mk2
-rw-r--r--lib/reltool/doc/src/reltool.xml5
-rw-r--r--lib/reltool/src/Makefile4
-rw-r--r--lib/reltool/src/reltool_sys_win.erl104
-rw-r--r--lib/reltool/src/reltool_target.erl31
-rw-r--r--lib/runtime_tools/c_src/Makefile.in26
-rw-r--r--lib/runtime_tools/doc/src/dbg.xml5
-rw-r--r--lib/runtime_tools/src/Makefile5
-rw-r--r--lib/runtime_tools/src/appmon_info.erl (renamed from lib/appmon/src/appmon_info.erl)0
-rw-r--r--lib/runtime_tools/src/dyntrace.erl4
-rw-r--r--lib/runtime_tools/src/observer_backend.erl2
-rw-r--r--lib/runtime_tools/src/runtime_tools.app.src2
-rw-r--r--lib/runtime_tools/src/runtime_tools_sup.erl3
-rw-r--r--lib/runtime_tools/test/dbg_SUITE.erl4
-rw-r--r--lib/sasl/src/Makefile4
-rw-r--r--lib/sasl/src/overload.erl5
-rw-r--r--lib/sasl/src/release_handler.erl8
-rw-r--r--lib/sasl/src/systools_make.erl43
-rw-r--r--lib/sasl/src/systools_relup.erl5
-rw-r--r--lib/sasl/test/release_handler_SUITE.erl12
-rw-r--r--lib/snmp/doc/src/Makefile2
-rw-r--r--lib/snmp/doc/src/notes.xml82
-rw-r--r--lib/snmp/doc/src/snmpm.xml3
-rw-r--r--lib/snmp/mibs/Makefile.in8
-rw-r--r--lib/snmp/src/agent/snmp_view_based_acm_mib.erl2
-rw-r--r--lib/snmp/src/agent/snmpa_agent.erl6
-rw-r--r--lib/snmp/src/app/Makefile4
-rw-r--r--lib/snmp/src/app/snmp.appup.src574
-rw-r--r--lib/snmp/src/compile/depend.mk4
-rw-r--r--lib/snmp/src/manager/snmpm.erl622
-rw-r--r--lib/snmp/src/manager/snmpm_conf.erl5
-rw-r--r--lib/snmp/src/manager/snmpm_mpd.erl4
-rw-r--r--lib/snmp/src/manager/snmpm_server.erl37
-rw-r--r--lib/snmp/src/manager/snmpm_user_default.erl6
-rw-r--r--lib/snmp/test/snmp_agent_test.erl5
-rw-r--r--lib/snmp/test/snmp_log_test.erl12
-rw-r--r--lib/snmp/test/snmp_manager_test.erl217
-rw-r--r--lib/snmp/test/snmp_manager_user.erl318
-rw-r--r--lib/snmp/test/snmp_manager_user_old.erl126
-rw-r--r--lib/snmp/test/snmp_manager_user_test.erl2
-rw-r--r--lib/snmp/test/snmp_test_lib.erl2
-rw-r--r--lib/snmp/test/snmp_test_manager.erl8
-rw-r--r--lib/snmp/vsn.mk2
-rw-r--r--lib/ssh/doc/html/SSH_protocols.pngbin0 -> 15381 bytes
-rw-r--r--lib/ssh/doc/man6/.gitignore0
-rw-r--r--lib/ssh/doc/src/Makefile35
-rw-r--r--lib/ssh/doc/src/SSH_protocols.pngbin0 -> 15381 bytes
-rw-r--r--lib/ssh/doc/src/book.xml7
-rw-r--r--lib/ssh/doc/src/fascicules.xml5
-rw-r--r--lib/ssh/doc/src/introduction.xml54
-rw-r--r--lib/ssh/doc/src/notes.xml52
-rw-r--r--lib/ssh/doc/src/ref_man.xml15
-rw-r--r--lib/ssh/doc/src/ssh.xml212
-rw-r--r--lib/ssh/doc/src/ssh_app.xml100
-rw-r--r--lib/ssh/doc/src/ssh_channel.xml349
-rw-r--r--lib/ssh/doc/src/ssh_client_key_api.xml124
-rw-r--r--lib/ssh/doc/src/ssh_connection.xml260
-rw-r--r--lib/ssh/doc/src/ssh_protocol.xml149
-rw-r--r--lib/ssh/doc/src/ssh_server_key_api.xml90
-rw-r--r--lib/ssh/doc/src/ssh_sftp.xml65
-rw-r--r--lib/ssh/doc/src/ssh_sftpd.xml51
-rw-r--r--lib/ssh/doc/src/user_guide.gifbin1581 -> 0 bytes
-rw-r--r--lib/ssh/doc/src/usersguide.xml37
-rw-r--r--lib/ssh/doc/src/using_ssh.xml298
-rw-r--r--lib/ssh/src/Makefile8
-rw-r--r--lib/ssh/src/ssh.app.src6
-rw-r--r--lib/ssh/src/ssh.appup.src18
-rw-r--r--lib/ssh/src/ssh.erl137
-rw-r--r--lib/ssh/src/ssh_auth.erl87
-rw-r--r--lib/ssh/src/ssh_auth.hrl4
-rw-r--r--lib/ssh/src/ssh_channel.erl37
-rw-r--r--lib/ssh/src/ssh_cli.erl3
-rw-r--r--lib/ssh/src/ssh_client_key.erl34
-rw-r--r--lib/ssh/src/ssh_client_key_api.erl35
-rw-r--r--lib/ssh/src/ssh_connection.erl59
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl64
-rw-r--r--lib/ssh/src/ssh_connection_manager.erl174
-rw-r--r--lib/ssh/src/ssh_file.erl29
-rw-r--r--lib/ssh/src/ssh_io.erl63
-rw-r--r--lib/ssh/src/ssh_key_api.erl45
-rw-r--r--lib/ssh/src/ssh_server_key.erl (renamed from lib/stdlib/test/erl_eval_helper.erl)25
-rw-r--r--lib/ssh/src/ssh_server_key_api.erl (renamed from lib/test_server/test/test_server_line_SUITE_data/parse_transform_test.erl)55
-rw-r--r--lib/ssh/src/ssh_sftpd.erl89
-rw-r--r--lib/ssh/src/ssh_subsystem.erl47
-rw-r--r--lib/ssh/src/ssh_transport.erl6
-rw-r--r--lib/ssh/src/ssh_xfer.erl5
-rw-r--r--lib/ssh/src/ssh_xfer.hrl12
-rw-r--r--lib/ssh/test/Makefile4
-rw-r--r--lib/ssh/test/ssh_basic_SUITE.erl311
-rw-r--r--lib/ssh/test/ssh_connection_SUITE.erl313
-rw-r--r--lib/ssh/test/ssh_connection_SUITE_data/ssh_host_rsa_key15
-rw-r--r--lib/ssh/test/ssh_echo_server.erl71
-rw-r--r--lib/ssh/test/ssh_sftp_SUITE.erl288
-rw-r--r--lib/ssh/test/ssh_sftpd_SUITE.erl294
-rw-r--r--lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl165
-rw-r--r--lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_sftpd_file_alt.erl2
-rw-r--r--lib/ssh/test/ssh_test_lib.erl19
-rw-r--r--lib/ssh/test/ssh_to_openssh_SUITE.erl176
-rw-r--r--lib/ssh/vsn.mk2
-rw-r--r--lib/ssl/doc/src/notes.xml49
-rw-r--r--lib/ssl/doc/src/ssl.xml4
-rw-r--r--lib/ssl/doc/src/ssl_app.xml14
-rw-r--r--lib/ssl/doc/src/ssl_protocol.xml7
-rw-r--r--lib/ssl/src/Makefile24
-rw-r--r--lib/ssl/src/ssl.appup.src19
-rw-r--r--lib/ssl/src/ssl.erl112
-rw-r--r--lib/ssl/src/ssl_connection.erl514
-rw-r--r--lib/ssl/src/ssl_handshake.erl189
-rw-r--r--lib/ssl/src/ssl_handshake.hrl9
-rw-r--r--lib/ssl/src/ssl_internal.hrl2
-rw-r--r--lib/ssl/src/ssl_manager.erl45
-rw-r--r--lib/ssl/src/ssl_record.erl5
-rw-r--r--lib/ssl/src/ssl_session.erl18
-rw-r--r--lib/ssl/test/Makefile11
-rw-r--r--lib/ssl/test/erl_make_certs.erl4
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl2963
-rw-r--r--lib/ssl/test/ssl_certificate_verify_SUITE.erl982
-rw-r--r--lib/ssl/test/ssl_cipher_SUITE.erl122
-rw-r--r--lib/ssl/test/ssl_dist_SUITE.erl32
-rw-r--r--lib/ssl/test/ssl_handshake_SUITE.erl8
-rw-r--r--lib/ssl/test/ssl_npn_handshake_SUITE.erl30
-rw-r--r--lib/ssl/test/ssl_npn_hello_SUITE.erl92
-rw-r--r--lib/ssl/test/ssl_packet_SUITE.erl1417
-rw-r--r--lib/ssl/test/ssl_payload_SUITE.erl276
-rw-r--r--lib/ssl/test/ssl_session_cache_SUITE.erl132
-rw-r--r--lib/ssl/test/ssl_test_lib.erl190
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl679
-rw-r--r--lib/ssl/vsn.mk2
-rw-r--r--lib/stdlib/doc/src/Makefile11
-rw-r--r--lib/stdlib/doc/src/epp.xml59
-rw-r--r--lib/stdlib/doc/src/erl_pp.xml8
-rw-r--r--lib/stdlib/doc/src/io.xml233
-rw-r--r--lib/stdlib/doc/src/io_lib.xml69
-rw-r--r--lib/stdlib/doc/src/io_protocol.xml476
-rw-r--r--lib/stdlib/doc/src/notes.xml15
-rw-r--r--lib/stdlib/doc/src/proplists.xml22
-rw-r--r--lib/stdlib/doc/src/re.xml6
-rw-r--r--lib/stdlib/doc/src/supervisor.xml8
-rw-r--r--lib/stdlib/doc/src/unicode.xml71
-rw-r--r--lib/stdlib/doc/src/unicode_usage.xml196
-rw-r--r--lib/stdlib/doc/src/ushell1.gifbin13870 -> 0 bytes
-rw-r--r--lib/stdlib/doc/src/ushell1.ps1196
-rw-r--r--lib/stdlib/doc/src/ushell2.gifbin4384 -> 0 bytes
-rw-r--r--lib/stdlib/doc/src/ushell2.ps404
-rw-r--r--lib/stdlib/doc/src/ushell3.gifbin8239 -> 0 bytes
-rw-r--r--lib/stdlib/doc/src/ushell3.ps662
-rw-r--r--lib/stdlib/doc/src/zip.xml4
-rw-r--r--lib/stdlib/src/Makefile14
-rw-r--r--lib/stdlib/src/binary.erl2
-rw-r--r--lib/stdlib/src/c.erl2
-rw-r--r--lib/stdlib/src/dets.erl3
-rw-r--r--lib/stdlib/src/dict.erl5
-rw-r--r--lib/stdlib/src/edlin.erl7
-rw-r--r--lib/stdlib/src/epp.erl211
-rw-r--r--lib/stdlib/src/erl_eval.erl45
-rw-r--r--lib/stdlib/src/erl_expand_records.erl10
-rw-r--r--lib/stdlib/src/erl_lint.erl297
-rw-r--r--lib/stdlib/src/erl_parse.yrl192
-rw-r--r--lib/stdlib/src/erl_pp.erl759
-rw-r--r--lib/stdlib/src/erl_scan.erl287
-rw-r--r--lib/stdlib/src/escript.erl29
-rw-r--r--lib/stdlib/src/ets.erl2
-rw-r--r--lib/stdlib/src/filename.erl22
-rw-r--r--lib/stdlib/src/gb_sets.erl7
-rw-r--r--lib/stdlib/src/gb_trees.erl7
-rw-r--r--lib/stdlib/src/io.erl194
-rw-r--r--lib/stdlib/src/io_lib.erl140
-rw-r--r--lib/stdlib/src/io_lib_format.erl37
-rw-r--r--lib/stdlib/src/io_lib_fread.erl2
-rw-r--r--lib/stdlib/src/io_lib_pretty.erl226
-rw-r--r--lib/stdlib/src/lib.erl173
-rw-r--r--lib/stdlib/src/log_mf_h.erl4
-rw-r--r--lib/stdlib/src/otp_internal.erl127
-rw-r--r--lib/stdlib/src/proc_lib.erl38
-rw-r--r--lib/stdlib/src/proplists.erl72
-rw-r--r--lib/stdlib/src/qlc.erl4
-rw-r--r--lib/stdlib/src/qlc_pt.erl10
-rw-r--r--lib/stdlib/src/sets.erl5
-rw-r--r--lib/stdlib/src/shell.erl193
-rw-r--r--lib/stdlib/src/string.erl3
-rw-r--r--lib/stdlib/src/supervisor.erl25
-rw-r--r--lib/stdlib/src/sys.erl99
-rw-r--r--lib/stdlib/src/win32reg.erl4
-rw-r--r--lib/stdlib/test/Makefile1
-rw-r--r--lib/stdlib/test/base64_SUITE.erl14
-rw-r--r--lib/stdlib/test/binary_module_SUITE.erl9
-rw-r--r--lib/stdlib/test/dict_SUITE.erl20
-rw-r--r--lib/stdlib/test/dict_test_lib.erl55
-rw-r--r--lib/stdlib/test/digraph_SUITE.erl4
-rw-r--r--lib/stdlib/test/epp_SUITE.erl91
-rw-r--r--lib/stdlib/test/erl_eval_SUITE.erl18
-rw-r--r--lib/stdlib/test/erl_expand_records_SUITE.erl47
-rw-r--r--lib/stdlib/test/erl_lint_SUITE.erl26
-rw-r--r--lib/stdlib/test/erl_pp_SUITE.erl111
-rw-r--r--lib/stdlib/test/erl_scan_SUITE.erl214
-rw-r--r--lib/stdlib/test/escript_SUITE.erl38
-rw-r--r--lib/stdlib/test/escript_SUITE_data/emulator_flags_no_shebang10
-rwxr-xr-xlib/stdlib/test/escript_SUITE_data/unicode114
-rwxr-xr-xlib/stdlib/test/escript_SUITE_data/unicode214
-rwxr-xr-xlib/stdlib/test/escript_SUITE_data/unicode313
-rw-r--r--lib/stdlib/test/ets_SUITE.erl54
-rw-r--r--lib/stdlib/test/gen_server_SUITE.erl3
-rw-r--r--lib/stdlib/test/id_transform_SUITE.erl4
-rw-r--r--lib/stdlib/test/io_SUITE.erl63
-rw-r--r--lib/stdlib/test/io_proto_SUITE.erl165
-rw-r--r--lib/stdlib/test/proc_lib_SUITE.erl31
-rw-r--r--lib/stdlib/test/qlc_SUITE.erl15
-rw-r--r--lib/stdlib/test/re_SUITE.erl21
-rw-r--r--lib/stdlib/test/re_testoutput1_replacement_test.erl55
-rw-r--r--lib/stdlib/test/re_testoutput1_split_test.erl81
-rw-r--r--lib/stdlib/test/sets_SUITE.erl342
-rw-r--r--lib/stdlib/test/sets_test_lib.erl82
-rw-r--r--lib/stdlib/test/shell_SUITE.erl226
-rw-r--r--lib/stdlib/test/stdlib.cover15
-rw-r--r--lib/stdlib/test/string_SUITE.erl7
-rw-r--r--lib/stdlib/test/supervisor_SUITE.erl39
-rw-r--r--lib/stdlib/test/supervisor_SUITE_data/Makefile.src15
-rw-r--r--lib/stdlib/test/supervisor_SUITE_data/app_faulty/ebin/app_faulty.app10
-rw-r--r--lib/stdlib/test/supervisor_SUITE_data/app_faulty/src/app_faulty.erl17
-rw-r--r--lib/stdlib/test/supervisor_SUITE_data/app_faulty/src/app_faulty_server.erl32
-rw-r--r--lib/stdlib/test/supervisor_SUITE_data/app_faulty/src/app_faulty_sup.erl17
-rw-r--r--lib/syntax_tools/src/Makefile6
-rw-r--r--lib/syntax_tools/src/epp_dodger.erl4
-rw-r--r--lib/syntax_tools/src/erl_comment_scan.erl12
-rw-r--r--lib/syntax_tools/src/erl_prettypr.erl38
-rw-r--r--lib/syntax_tools/src/erl_syntax.erl164
-rw-r--r--lib/syntax_tools/src/erl_syntax_lib.erl5
-rw-r--r--lib/syntax_tools/src/erl_tidy.erl11
-rw-r--r--lib/syntax_tools/src/igor.erl55
-rw-r--r--lib/test_server/doc/src/notes.xml41
-rw-r--r--lib/test_server/doc/src/test_server.xml14
-rw-r--r--lib/test_server/doc/src/test_server_ctrl.xml93
-rw-r--r--lib/test_server/doc/src/ts.xml4
-rw-r--r--lib/test_server/src/Makefile9
-rw-r--r--lib/test_server/src/erl2html2.erl274
-rw-r--r--lib/test_server/src/test_server.app.src1
-rw-r--r--lib/test_server/src/test_server.erl1329
-rw-r--r--lib/test_server/src/test_server_ctrl.erl1352
-rw-r--r--lib/test_server/src/test_server_gl.erl293
-rw-r--r--lib/test_server/src/test_server_h.erl5
-rw-r--r--lib/test_server/src/test_server_internal.hrl4
-rw-r--r--lib/test_server/src/test_server_io.erl319
-rw-r--r--lib/test_server/src/test_server_node.erl262
-rw-r--r--lib/test_server/src/test_server_sup.erl67
-rw-r--r--lib/test_server/src/ts.erl80
-rw-r--r--lib/test_server/src/ts_run.erl10
-rw-r--r--lib/test_server/test/Makefile5
-rw-r--r--lib/test_server/test/erl2html2_SUITE.erl254
-rw-r--r--lib/test_server/test/erl2html2_SUITE_data/Makefile.src2
-rw-r--r--lib/test_server/test/erl2html2_SUITE_data/header1.hrl4
-rw-r--r--lib/test_server/test/erl2html2_SUITE_data/include/header2.hrl0
-rw-r--r--lib/test_server/test/erl2html2_SUITE_data/m1.erl46
-rw-r--r--lib/test_server/test/test_server.cover20
-rw-r--r--lib/test_server/test/test_server_SUITE.erl141
-rw-r--r--lib/test_server/test/test_server_SUITE_data/Makefile.src5
-rw-r--r--lib/test_server/test/test_server_SUITE_data/test_server_SUITE.erl62
-rw-r--r--lib/test_server/test/test_server_SUITE_data/test_server_break_SUITE.erl148
-rw-r--r--lib/test_server/test/test_server_SUITE_data/test_server_cover_SUITE.erl58
-rw-r--r--lib/test_server/test/test_server_SUITE_data/test_server_cover_SUITE_data/cover_helper.erl4
-rw-r--r--lib/test_server/test/test_server_line_SUITE.erl131
-rw-r--r--lib/test_server/test/test_server_line_SUITE_data/Makefile.src6
-rw-r--r--lib/test_server/test/test_server_test_lib.erl32
-rw-r--r--lib/test_server/vsn.mk2
-rw-r--r--lib/toolbar/src/Makefile4
-rw-r--r--lib/tools/c_src/Makefile.in10
-rw-r--r--lib/tools/doc/src/cover.xml20
-rw-r--r--lib/tools/doc/src/xref.xml2
-rw-r--r--lib/tools/emacs/erlang-pkg.el3
-rw-r--r--lib/tools/emacs/erlang.el65
-rw-r--r--lib/tools/emacs/vsn.mk3
-rw-r--r--lib/tools/src/Makefile4
-rw-r--r--lib/tools/src/cover.erl262
-rw-r--r--lib/tools/src/lcnt.erl3
-rw-r--r--lib/tools/src/tools.app.src2
-rw-r--r--lib/tools/test/cover_SUITE.erl233
-rw-r--r--lib/tools/test/cover_SUITE_data/f.erl11
-rw-r--r--lib/tools/test/cprof_SUITE.erl16
-rw-r--r--lib/tools/test/xref_SUITE.erl65
-rw-r--r--lib/tv/src/Makefile4
-rw-r--r--lib/typer/src/Makefile6
-rw-r--r--lib/webtool/src/Makefile4
-rw-r--r--lib/wx/.gitignore5
-rw-r--r--lib/wx/aclocal.m435
-rw-r--r--lib/wx/api_gen/gen_util.erl12
-rw-r--r--lib/wx/api_gen/gl_gen.erl25
-rw-r--r--lib/wx/api_gen/gl_gen_erl.erl22
-rw-r--r--lib/wx/api_gen/gl_scan_doc.erl14
-rw-r--r--lib/wx/api_gen/wx_extra/wxPrintout.erl5
-rw-r--r--lib/wx/api_gen/wx_gen.erl114
-rw-r--r--lib/wx/api_gen/wx_gen.hrl5
-rw-r--r--lib/wx/api_gen/wx_gen_cpp.erl55
-rw-r--r--lib/wx/api_gen/wx_gen_erl.erl128
-rw-r--r--lib/wx/api_gen/wxapi.conf144
-rw-r--r--lib/wx/c_src/Makefile.in5
-rw-r--r--lib/wx/c_src/gen/wxe_derived_dest.h12
-rw-r--r--lib/wx/c_src/gen/wxe_events.cpp425
-rw-r--r--lib/wx/c_src/gen/wxe_funcs.cpp2197
-rw-r--r--lib/wx/c_src/gen/wxe_macros.h299
-rw-r--r--lib/wx/c_src/wxe_impl.cpp36
-rw-r--r--lib/wx/c_src/wxe_ps_init.c5
-rwxr-xr-xlib/wx/configure.in68
-rw-r--r--lib/wx/examples/demo/demo.erl53
-rw-r--r--lib/wx/examples/demo/ex_aui.erl22
-rw-r--r--lib/wx/examples/demo/ex_button.erl10
-rw-r--r--lib/wx/examples/demo/ex_canvas.erl5
-rw-r--r--lib/wx/examples/demo/ex_canvas_paint.erl25
-rw-r--r--lib/wx/examples/demo/ex_choices.erl6
-rw-r--r--lib/wx/examples/demo/ex_cursor.erl4
-rw-r--r--lib/wx/examples/demo/ex_dialogs.erl4
-rw-r--r--lib/wx/examples/demo/ex_frame_utils.erl4
-rw-r--r--lib/wx/examples/demo/ex_gauge.erl4
-rw-r--r--lib/wx/examples/demo/ex_gl.erl61
-rw-r--r--lib/wx/examples/demo/ex_graphicsContext.erl42
-rw-r--r--lib/wx/examples/demo/ex_grid.erl4
-rw-r--r--lib/wx/examples/demo/ex_htmlWindow.erl4
-rw-r--r--lib/wx/examples/demo/ex_listCtrl.erl8
-rw-r--r--lib/wx/examples/demo/ex_notebook.erl4
-rw-r--r--lib/wx/examples/demo/ex_pickers.erl4
-rw-r--r--lib/wx/examples/demo/ex_popupMenu.erl4
-rw-r--r--lib/wx/examples/demo/ex_radioBox.erl4
-rw-r--r--lib/wx/examples/demo/ex_sashWindow.erl4
-rw-r--r--lib/wx/examples/demo/ex_sizers.erl4
-rw-r--r--lib/wx/examples/demo/ex_slider.erl4
-rw-r--r--lib/wx/examples/demo/ex_splitterWindow.erl4
-rw-r--r--lib/wx/examples/demo/ex_static.erl4
-rw-r--r--lib/wx/examples/demo/ex_textCtrl.erl24
-rw-r--r--lib/wx/examples/demo/ex_treeCtrl.erl4
-rw-r--r--lib/wx/examples/simple/menu.erl4
-rw-r--r--lib/wx/examples/simple/minimal.erl6
-rw-r--r--lib/wx/examples/sudoku/sudoku_board.erl46
-rw-r--r--lib/wx/examples/sudoku/sudoku_gui.erl25
-rw-r--r--lib/wx/include/wx.hrl215
-rw-r--r--lib/wx/src/Makefile12
-rw-r--r--lib/wx/src/gen/gl.erl285
-rw-r--r--lib/wx/src/gen/glu.erl82
-rw-r--r--lib/wx/src/gen/wxCalendarCtrl.erl2
-rw-r--r--lib/wx/src/gen/wxClientDC.erl2
-rw-r--r--lib/wx/src/gen/wxClipboard.erl3
-rw-r--r--lib/wx/src/gen/wxCursor.erl2
-rw-r--r--lib/wx/src/gen/wxDC.erl17
-rw-r--r--lib/wx/src/gen/wxGraphicsContext.erl11
-rw-r--r--lib/wx/src/gen/wxGraphicsPath.erl8
-rw-r--r--lib/wx/src/gen/wxGraphicsRenderer.erl2
-rw-r--r--lib/wx/src/gen/wxGridCellEditor.erl2
-rw-r--r--lib/wx/src/gen/wxIdleEvent.erl2
-rw-r--r--lib/wx/src/gen/wxImage.erl9
-rw-r--r--lib/wx/src/gen/wxMDIClientWindow.erl2
-rw-r--r--lib/wx/src/gen/wxMouseEvent.erl2
-rw-r--r--lib/wx/src/gen/wxPageSetupDialogData.erl9
-rw-r--r--lib/wx/src/gen/wxPaintDC.erl2
-rw-r--r--lib/wx/src/gen/wxPaintEvent.erl2
-rw-r--r--lib/wx/src/gen/wxPen.erl6
-rw-r--r--lib/wx/src/gen/wxPostScriptDC.erl2
-rw-r--r--lib/wx/src/gen/wxPrintData.erl6
-rw-r--r--lib/wx/src/gen/wxPrintout.erl5
-rw-r--r--lib/wx/src/gen/wxStyledTextCtrl.erl47
-rw-r--r--lib/wx/src/gen/wxSystemSettings.erl2
-rw-r--r--lib/wx/src/gen/wxWindowDC.erl2
-rw-r--r--lib/wx/src/gen/wxe_debug.hrl299
-rw-r--r--lib/wx/src/gen/wxe_funcs.hrl299
-rw-r--r--lib/wx/src/wx.erl36
-rw-r--r--lib/wx/src/wxe_master.erl28
-rw-r--r--lib/wx/src/wxe_server.erl14
-rw-r--r--lib/wx/src/wxe_util.erl26
-rw-r--r--lib/wx/test/wx_basic_SUITE.erl32
-rw-r--r--lib/wx/test/wx_class_SUITE.erl17
-rw-r--r--lib/wx/test/wx_event_SUITE.erl79
-rw-r--r--lib/wx/test/wx_opengl_SUITE.erl40
-rw-r--r--lib/wx/test/wx_xtra_SUITE.erl32
-rw-r--r--lib/wx/wxwin-2.8.m4 (renamed from lib/wx/wxwin.m4)0
-rw-r--r--lib/wx/wxwin-2.9.m41060
-rw-r--r--lib/xmerl/doc/src/motorcycles_dtd.txt3
-rw-r--r--lib/xmerl/src/Makefile20
-rw-r--r--lib/xmerl/src/xmerl_scan.erl5
-rw-r--r--lib/xmerl/src/xmerl_xsd.erl3
-rw-r--r--lib/xmerl/test/xmerl_SUITE.erl7
-rw-r--r--make/otp.mk.in53
-rw-r--r--make/otp_ded.mk.in2
-rw-r--r--make/otp_release_targets.mk37
-rw-r--r--make/output.mk.in112
-rw-r--r--make/run_make.mk7
-rwxr-xr-xotp_build2
-rw-r--r--system/doc/efficiency_guide/advanced.xml24
-rw-r--r--system/doc/efficiency_guide/drivers.xml14
-rw-r--r--system/doc/embedded/part.xml1
-rw-r--r--system/doc/reference_manual/introduction.xml13
-rw-r--r--system/doc/reference_manual/ports.xml13
-rw-r--r--system/doc/top/Makefile29
-rw-r--r--system/doc/tutorial/port_driver.c28
-rw-r--r--xcomp/erl-xcomp-powerpc-dso-linux-gnu.conf16
1509 files changed, 68449 insertions, 59151 deletions
diff --git a/.gitignore b/.gitignore
index 3b0e21bde3..e5e74f9a3d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -129,6 +129,7 @@ JAVADOC-GENERATED
/release
+/make/output.mk
/make/emd2exml
# Created by "out_build update_primary"
@@ -242,6 +243,8 @@ JAVADOC-GENERATED
# hipe
+/lib/hipe/boot_ebin/hipe.app
+/lib/hipe/boot_ebin/hipe.appup
/lib/hipe/main/hipe.hrl
/lib/hipe/rtl/hipe_literals.hrl
diff --git a/HOWTO/BENCHMARKS.md b/HOWTO/BENCHMARKS.md
index b3df4638ea..28a590dfd2 100644
--- a/HOWTO/BENCHMARKS.md
+++ b/HOWTO/BENCHMARKS.md
@@ -18,13 +18,13 @@ benchmarks you have to [install the tests][]. To get a listing of all
benchmarks you have available call `ts:benchmarks()`.
To run all benchmarks call `ts:bench()`. This will run all benchmarks using
-the emulator which is in you `$PATH` (Note that this does not have to be the
+the emulator which is in your `$PATH` (Note that this does not have to be the
same as from which the benchmarks were built from). All the results of the
benchmarks are put in a folder in `$TESTROOT/test_server/` called
`YYYY_MO_DDTHH_MI_SS`.
Each benchmark is run multiple times and the data for all runs is collected in
-the files within the benchmark folder. All benchmarks are written so that a
+the files within the benchmark folder. All benchmarks are written so that
higher values are better.
Writing benchmarks
diff --git a/HOWTO/DTRACE.md b/HOWTO/DTRACE.md
index b719c68c59..8fa2fd9d50 100644
--- a/HOWTO/DTRACE.md
+++ b/HOWTO/DTRACE.md
@@ -69,7 +69,8 @@ following may be executed in a different Pthread:
Example output from `lib/runtime_tools/examples/efile_drv.d` while executing
`file:rename("old-name", "new-name")`:
- efile_drv enter tag={3,84} user tag some-user-tag | RENAME (12) | args: old-name new-name , 0 0 (port #Port<0.59>)
+ efile_drv enter tag={3,84} user tag some-user-tag | RENAME (12) | args: old-name new-name ,\
+ 0 0 (port #Port<0.59>)
async I/O worker tag={3,83} | RENAME (12) | efile_drv-int_entry
async I/O worker tag={3,83} | RENAME (12) | efile_drv-int_return
efile_drv return tag={3,83} user tag | RENAME (12) | errno 2
diff --git a/Makefile.in b/Makefile.in
index 544233f097..e5909aa7f0 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -35,6 +35,9 @@ OTP = OTP-@OTP_REL@
# erts (Erlang RunTime System) version
ERTS = erts-@ERTS_VSN@
+# Include verbose output variables
+include $(ERL_TOP)/make/output.mk
+
# ----------------------------------------------------------------------
#
@@ -426,57 +429,58 @@ BOOTSTRAP_COMPILER = $(BOOTSTRAP_TOP)/primary_compiler
.PHONY: emulator libs kernel stdlib compiler hipe typer syntax_tools preloaded
emulator:
- cd erts && ERL_TOP=$(ERL_TOP) $(MAKE) NO_START_SCRIPTS=true $(TYPE) FLAVOR=$(FLAVOR)
+ $(make_verbose)cd erts && ERL_TOP=$(ERL_TOP) $(MAKE) NO_START_SCRIPTS=true $(TYPE) FLAVOR=$(FLAVOR)
libs:
ifeq ($(OTP_SMALL_BUILD),true)
- cd lib && \
+ $(make_verbose)cd lib && \
ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \
$(MAKE) opt
else
- cd lib && \
+ $(make_verbose)cd lib && \
ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \
$(MAKE) opt BUILD_ALL=true
endif
kernel:
- cd lib/kernel && \
+ $(make_verbose)cd lib/kernel && \
ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \
$(MAKE) opt BUILD_ALL=true
stdlib:
- cd lib/stdlib && \
+ $(make_verbose)cd lib/stdlib && \
ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \
$(MAKE) opt BUILD_ALL=true
compiler:
- cd lib/compiler && \
+ $(make_verbose)cd lib/compiler && \
ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \
$(MAKE) opt BUILD_ALL=true
hipe:
- cd lib/hipe && \
+ $(make_verbose)cd lib/hipe && \
ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \
$(MAKE) opt BUILD_ALL=true
typer:
- cd lib/typer && \
+ $(make_verbose)cd lib/typer && \
ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \
$(MAKE) opt BUILD_ALL=true
syntax_tools:
- cd lib/syntax_tools && \
+ $(make_verbose)cd lib/syntax_tools && \
ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \
$(MAKE) opt BUILD_ALL=true
preloaded:
- cd erts/preloaded/src && \
+ $(make_verbose)cd erts/preloaded/src && \
ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \
$(MAKE) opt BUILD_ALL=true
dep depend:
- test X"$$ERTS_SKIP_DEPEND" = X"true" || (cd erts/emulator && ERL_TOP=$(ERL_TOP) $(MAKE) generate)
- test X"$$ERTS_SKIP_DEPEND" = X"true" || (cd erts/emulator && ERL_TOP=$(ERL_TOP) $(MAKE) depend)
- test X"$$ERTS_SKIP_DEPEND" = X"true" || (cd erts/lib_src && ERL_TOP=$(ERL_TOP) $(MAKE) depend)
+ $(make_verbose)
+ $(V_at)test X"$$ERTS_SKIP_DEPEND" = X"true" || (cd erts/emulator && ERL_TOP=$(ERL_TOP) $(MAKE) generate)
+ $(V_at)test X"$$ERTS_SKIP_DEPEND" = X"true" || (cd erts/emulator && ERL_TOP=$(ERL_TOP) $(MAKE) depend)
+ $(V_at)test X"$$ERTS_SKIP_DEPEND" = X"true" || (cd erts/lib_src && ERL_TOP=$(ERL_TOP) $(MAKE) depend)
# Creates "erl" and "erlc" in bootstrap/bin which uses the precompiled
# libraries in the bootstrap directory
@@ -530,14 +534,15 @@ bootstrap_setup_target:
echo $(TARGET) > $(BOOTSTRAP_ROOT)/bootstrap/target
secondary_bootstrap_build:
- cd lib && \
+ $(make_verbose)cd lib && \
ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \
$(MAKE) opt SECONDARY_BOOTSTRAP=true
secondary_bootstrap_copy:
- if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/hipe ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/hipe ; fi
- if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/hipe/ebin ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/hipe/ebin ; fi
- for x in lib/hipe/$(HIPE_BOOTSTRAP_EBIN)/*.beam; do \
+ $(make_verbose)
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/hipe ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/hipe ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/hipe/ebin ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/hipe/ebin ; fi
+ $(V_at)for x in lib/hipe/$(HIPE_BOOTSTRAP_EBIN)/*.beam; do \
BN=`basename $$x`; \
TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/hipe/ebin/$$BN; \
test -f $$TF && \
@@ -547,12 +552,12 @@ secondary_bootstrap_copy:
cp $$x $$TF; \
true; \
done
- if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools ; fi
- if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools/ebin ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools/ebin ; fi
- if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools/include ; fi
- if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/orber ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/orber ; fi
- if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/orber/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/orber/include ; fi
- for x in lib/parsetools/ebin/*.beam; do \
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools/ebin ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools/ebin ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools/include ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/orber ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/orber ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/orber/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/orber/include ; fi
+ $(V_at)for x in lib/parsetools/ebin/*.beam; do \
BN=`basename $$x`; \
TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools/ebin/$$BN; \
test -f $$TF && \
@@ -562,8 +567,8 @@ secondary_bootstrap_copy:
cp $$x $$TF; \
true; \
done
-# cp lib/parsetools/ebin/*.beam $(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools/ebin
- for x in lib/parsetools/include/*.hrl; do \
+# $(V_at)cp lib/parsetools/ebin/*.beam $(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools/ebin
+ $(V_at)for x in lib/parsetools/include/*.hrl; do \
BN=`basename $$x`; \
TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools/include/$$BN; \
test -f $$TF && \
@@ -573,11 +578,11 @@ secondary_bootstrap_copy:
cp $$x $$TF; \
true; \
done
-# cp -f lib/parsetools/include/*.hrl $(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools/include
- if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/asn1 ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/asn1 ; fi
- if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/asn1/ebin ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/asn1/ebin ; fi
- if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/asn1/src ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/asn1/src ; fi
- for x in lib/asn1/ebin/*.beam; do \
+# $(V_at)cp -f lib/parsetools/include/*.hrl $(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools/include
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/asn1 ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/asn1 ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/asn1/ebin ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/asn1/ebin ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/asn1/src ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/asn1/src ; fi
+ $(V_at)for x in lib/asn1/ebin/*.beam; do \
BN=`basename $$x`; \
TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/asn1/ebin/$$BN; \
test -f $$TF && \
@@ -587,8 +592,8 @@ secondary_bootstrap_copy:
cp $$x $$TF; \
true; \
done
-# cp lib/asn1/ebin/*.beam $(BOOTSTRAP_ROOT)/bootstrap/lib/asn1/ebin
- for x in lib/asn1/src/*.[eh]rl; do \
+# $(V_at)cp lib/asn1/ebin/*.beam $(BOOTSTRAP_ROOT)/bootstrap/lib/asn1/ebin
+ $(V_at)for x in lib/asn1/src/*.[eh]rl; do \
BN=`basename $$x`; \
TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/asn1/src/$$BN; \
test -f $$TF && \
@@ -598,8 +603,8 @@ secondary_bootstrap_copy:
cp $$x $$TF; \
true; \
done
-# cp -f lib/asn1/src/*.erl lib/asn1/src/*.hrl $(BOOTSTRAP_ROOT)/bootstrap/lib/asn1/src
- for x in lib/orber/include/*.hrl; do \
+# $(V_at)cp -f lib/asn1/src/*.erl lib/asn1/src/*.hrl $(BOOTSTRAP_ROOT)/bootstrap/lib/asn1/src
+ $(V_at)for x in lib/orber/include/*.hrl; do \
BN=`basename $$x`; \
TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/orber/include/$$BN; \
test -f $$TF && \
@@ -609,9 +614,9 @@ secondary_bootstrap_copy:
cp $$x $$TF; \
true; \
done
- if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/xmerl ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/xmerl ; fi
- if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/xmerl/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/xmerl/include ; fi
- for x in lib/xmerl/include/*.hrl; do \
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/xmerl ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/xmerl ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/xmerl/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/xmerl/include ; fi
+ $(V_at)for x in lib/xmerl/include/*.hrl; do \
BN=`basename $$x`; \
TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/xmerl/include/$$BN; \
test -f $$TF && \
@@ -623,15 +628,16 @@ secondary_bootstrap_copy:
done
tertiary_bootstrap_build:
- cd lib && \
+ $(make_verbose)cd lib && \
ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \
$(MAKE) opt TERTIARY_BOOTSTRAP=true
tertiary_bootstrap_copy:
- if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/snmp ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/snmp ; fi
- if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/snmp/ebin ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/snmp/ebin ; fi
- if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/snmp/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/snmp/include ; fi
- for x in lib/snmp/ebin/*.beam; do \
+ $(make_verbose)
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/snmp ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/snmp ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/snmp/ebin ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/snmp/ebin ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/snmp/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/snmp/include ; fi
+ $(V_at)for x in lib/snmp/ebin/*.beam; do \
BN=`basename $$x`; \
TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/snmp/ebin/$$BN; \
test -f $$TF && \
@@ -641,21 +647,21 @@ tertiary_bootstrap_copy:
cp $$x $$TF; \
true; \
done
-# cp lib/snmp/ebin/*.beam $(BOOTSTRAP_ROOT)/bootstrap/lib/snmp/ebin
- if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/sasl ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/sasl ; fi
- if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/sasl/ebin ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/sasl/ebin ; fi
- if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/sasl/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/sasl/include ; fi
- if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/ic ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/ic ; fi
- if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/ic/ebin ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/ic/ebin ; fi
- if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/ic/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/ic/include ; fi
- if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/wx ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/wx ; fi
- if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/wx/ebin ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/wx/ebin ; fi
- if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/wx/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/wx/include ; fi
- if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/test_server ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/test_server ; fi
- if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/test_server/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/test_server/include ; fi
- if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/common_test ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/common_test ; fi
- if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/common_test/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/common_test/include ; fi
- for x in lib/ic/ebin/*.beam; do \
+# $(V_at)cp lib/snmp/ebin/*.beam $(BOOTSTRAP_ROOT)/bootstrap/lib/snmp/ebin
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/sasl ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/sasl ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/sasl/ebin ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/sasl/ebin ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/sasl/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/sasl/include ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/ic ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/ic ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/ic/ebin ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/ic/ebin ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/ic/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/ic/include ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/wx ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/wx ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/wx/ebin ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/wx/ebin ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/wx/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/wx/include ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/test_server ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/test_server ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/test_server/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/test_server/include ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/common_test ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/common_test ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/common_test/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/common_test/include ; fi
+ $(V_at)for x in lib/ic/ebin/*.beam; do \
BN=`basename $$x`; \
TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/ic/ebin/$$BN; \
test -f $$TF && \
@@ -665,8 +671,8 @@ tertiary_bootstrap_copy:
cp $$x $$TF; \
true; \
done
-# cp lib/ic/ebin/*.beam $(BOOTSTRAP_ROOT)/bootstrap/lib/ic/ebin
- for x in lib/ic/include/*.idl; do \
+# $(V_at)cp lib/ic/ebin/*.beam $(BOOTSTRAP_ROOT)/bootstrap/lib/ic/ebin
+ $(V_at)for x in lib/ic/include/*.idl; do \
BN=`basename $$x`; \
TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/ic/include/$$BN; \
test -f $$TF && \
@@ -676,7 +682,7 @@ tertiary_bootstrap_copy:
cp $$x $$TF; \
true; \
done
- for x in lib/ic/include/*.h; do \
+ $(V_at)for x in lib/ic/include/*.h; do \
BN=`basename $$x`; \
TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/ic/include/$$BN; \
test -f $$TF && \
@@ -686,8 +692,8 @@ tertiary_bootstrap_copy:
cp $$x $$TF; \
true; \
done
-# cp -f lib/ic/include/*.idl lib/ic/include/*.h $(BOOTSTRAP_ROOT)/bootstrap/lib/ic/include
- for x in lib/sasl/ebin/*.beam; do \
+# $(V_at)cp -f lib/ic/include/*.idl lib/ic/include/*.h $(BOOTSTRAP_ROOT)/bootstrap/lib/ic/include
+ $(V_at)for x in lib/sasl/ebin/*.beam; do \
BN=`basename $$x`; \
TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/sasl/ebin/$$BN; \
test -f $$TF && \
@@ -697,10 +703,10 @@ tertiary_bootstrap_copy:
cp $$x $$TF; \
true; \
done
-# cp lib/sasl/ebin/*.beam $(BOOTSTRAP_ROOT)/bootstrap/lib/sasl/ebin
- if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/syntax_tools ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/syntax_tools ; fi
- if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/syntax_tools/ebin ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/syntax_tools/ebin ; fi
- for x in lib/syntax_tools/ebin/*.beam; do \
+# $(V_at)cp lib/sasl/ebin/*.beam $(BOOTSTRAP_ROOT)/bootstrap/lib/sasl/ebin
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/syntax_tools ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/syntax_tools ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/syntax_tools/ebin ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/syntax_tools/ebin ; fi
+ $(V_at)for x in lib/syntax_tools/ebin/*.beam; do \
BN=`basename $$x`; \
TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/syntax_tools/ebin/$$BN; \
test -f $$TF && \
@@ -710,7 +716,7 @@ tertiary_bootstrap_copy:
cp $$x $$TF; \
true; \
done
- for x in lib/wx/include/*.hrl; do \
+ $(V_at)for x in lib/wx/include/*.hrl; do \
BN=`basename $$x`; \
TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/wx/include/$$BN; \
test -f $$TF && \
@@ -721,7 +727,7 @@ tertiary_bootstrap_copy:
true; \
done
# copy wx_object to remove undef behaviour warnings
- for x in lib/wx/ebin/wx_object.beam; do \
+ $(V_at)for x in lib/wx/ebin/wx_object.beam; do \
BN=`basename $$x`; \
TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/wx/ebin/$$BN; \
test -f $$TF && \
@@ -733,7 +739,7 @@ tertiary_bootstrap_copy:
done
# copy test includes to be able to compile tests with bootstrap compiler
- for x in lib/test_server/include/*.hrl; do \
+ $(V_at)for x in lib/test_server/include/*.hrl; do \
BN=`basename $$x`; \
TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/test_server/include/$$BN; \
test -f $$TF && \
@@ -744,7 +750,7 @@ tertiary_bootstrap_copy:
true; \
done
- for x in lib/common_test/include/*.hrl; do \
+ $(V_at)for x in lib/common_test/include/*.hrl; do \
BN=`basename $$x`; \
TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/common_test/include/$$BN; \
test -f $$TF && \
@@ -754,7 +760,7 @@ tertiary_bootstrap_copy:
cp $$x $$TF; \
true; \
done
-# cp lib/syntax_tools/ebin/*.beam $(BOOTSTRAP_ROOT)/bootstrap/lib/syntax_tools/ebin
+# $(V_at)cp lib/syntax_tools/ebin/*.beam $(BOOTSTRAP_ROOT)/bootstrap/lib/syntax_tools/ebin
.PHONY: check_recreate_primary_bootstrap recreate_primary_bootstrap
@@ -783,7 +789,7 @@ check_recreate_primary_bootstrap:
# directories of all applications part of the primary bootstrap.
#
recreate_primary_bootstrap:
- $(ERL_TOP)/otp_build save_bootstrap
+ $(V_at)$(ERL_TOP)/otp_build save_bootstrap
# The first bootstrap build is rarely (never) used in open source, it's
# used to build the shipped bootstrap directory. The Open source bootstrap
@@ -802,21 +808,21 @@ recreate_primary_bootstrap:
primary_bootstrap:
@echo "=== Building a bootstrap compiler in $(BOOTSTRAP_ROOT)/bootstrap"
- $(MAKE) BOOTSTRAP_ROOT=$(BOOTSTRAP_ROOT) \
+ $(V_at)$(MAKE) BOOTSTRAP_ROOT=$(BOOTSTRAP_ROOT) \
ERL_TOP=$(ERL_TOP) \
bootstrap_clean
- cd $(ERL_TOP) && \
+ $(V_at)cd $(ERL_TOP) && \
$(MAKE) TESTROOT=$(BOOTSTRAP_TOP) \
BOOTSTRAP_TOP=$(BOOTSTRAP_TOP) \
primary_bootstrap_build
- cd $(ERL_TOP) && \
+ $(V_at)cd $(ERL_TOP) && \
$(MAKE) TESTROOT=$(BOOTSTRAP_TOP) \
BOOTSTRAP_TOP=$(BOOTSTRAP_TOP) \
primary_bootstrap_copy
- cd $(ERL_TOP)/erts/start_scripts && \
+ $(V_at)cd $(ERL_TOP)/erts/start_scripts && \
$(MAKE) TESTROOT=$(BOOTSTRAP_TOP) \
BOOTSTRAP_TOP=$(BOOTSTRAP_TOP) bootstrap_scripts
- test $(BOOTSTRAP_ROOT) = $(ERL_TOP) \
+ $(V_at)test $(BOOTSTRAP_ROOT) = $(ERL_TOP) \
|| $(ERL_TOP)/otp_build \
copy_primary_bootstrap \
$(BOOTSTRAP_TOP) \
@@ -824,50 +830,52 @@ primary_bootstrap:
primary_bootstrap_build: primary_bootstrap_mkdirs primary_bootstrap_compiler \
primary_bootstrap_stdlib
- cd lib && $(MAKE) ERLC_FLAGS='-pa $(BOOTSTRAP_COMPILER)/ebin' \
+ $(make_verbose)cd lib && $(MAKE) ERLC_FLAGS='-pa $(BOOTSTRAP_COMPILER)/ebin' \
BOOTSTRAP_TOP=$(BOOTSTRAP_TOP) \
BOOTSTRAP=1 opt
primary_bootstrap_compiler:
- cd lib/compiler && $(MAKE) \
+ $(make_verbose)cd lib/compiler && $(MAKE) \
BOOTSTRAP_TOP=$(BOOTSTRAP_TOP) \
BOOTSTRAP_COMPILER=$(BOOTSTRAP_COMPILER) \
BOOTSTRAP=1 \
opt
primary_bootstrap_stdlib:
- cd lib/stdlib/src && $(MAKE) \
+ $(make_verbose)cd lib/stdlib/src && $(MAKE) \
BOOTSTRAP_COMPILER=$(BOOTSTRAP_COMPILER) \
primary_bootstrap_compiler
primary_bootstrap_mkdirs:
- test -d $(BOOTSTRAP_COMPILER)/egen \
+ $(make_verbose)
+ $(V_at)test -d $(BOOTSTRAP_COMPILER)/egen \
|| mkdir -p $(BOOTSTRAP_COMPILER)/egen
- test -d $(BOOTSTRAP_COMPILER)/ebin \
+ $(V_at)test -d $(BOOTSTRAP_COMPILER)/ebin \
|| mkdir -p $(BOOTSTRAP_COMPILER)/ebin
- test -d $(BOOTSTRAP_TOP)/lib/kernel/egen \
+ $(V_at)test -d $(BOOTSTRAP_TOP)/lib/kernel/egen \
|| mkdir -p $(BOOTSTRAP_TOP)/lib/kernel/egen
- test -d $(BOOTSTRAP_TOP)/lib/kernel/ebin \
+ $(V_at)test -d $(BOOTSTRAP_TOP)/lib/kernel/ebin \
|| mkdir -p $(BOOTSTRAP_TOP)/lib/kernel/ebin
- test -d $(BOOTSTRAP_TOP)/lib/kernel/include \
+ $(V_at)test -d $(BOOTSTRAP_TOP)/lib/kernel/include \
|| mkdir -p $(BOOTSTRAP_TOP)/lib/kernel/include
- test -d $(BOOTSTRAP_TOP)/lib/stdlib/egen \
+ $(V_at)test -d $(BOOTSTRAP_TOP)/lib/stdlib/egen \
|| mkdir -p $(BOOTSTRAP_TOP)/lib/stdlib/egen
- test -d $(BOOTSTRAP_TOP)/lib/stdlib/ebin \
+ $(V_at)test -d $(BOOTSTRAP_TOP)/lib/stdlib/ebin \
|| mkdir -p $(BOOTSTRAP_TOP)/lib/stdlib/ebin
- test -d $(BOOTSTRAP_TOP)/lib/stdlib/include \
+ $(V_at)test -d $(BOOTSTRAP_TOP)/lib/stdlib/include \
|| mkdir -p $(BOOTSTRAP_TOP)/lib/stdlib/include
- test -d $(BOOTSTRAP_TOP)/lib/compiler/egen \
+ $(V_at)test -d $(BOOTSTRAP_TOP)/lib/compiler/egen \
|| mkdir -p $(BOOTSTRAP_TOP)/lib/compiler/egen
- test -d $(BOOTSTRAP_TOP)/lib/compiler/ebin \
+ $(V_at)test -d $(BOOTSTRAP_TOP)/lib/compiler/ebin \
|| mkdir -p $(BOOTSTRAP_TOP)/lib/compiler/ebin
- test -d $(BOOTSTRAP_TOP)/lib/orber/include \
+ $(V_at)test -d $(BOOTSTRAP_TOP)/lib/orber/include \
|| mkdir -p $(BOOTSTRAP_TOP)/lib/orber/include
primary_bootstrap_copy:
- cp -f lib/kernel/include/*.hrl $(BOOTSTRAP_TOP)/lib/kernel/include
- cp -f lib/stdlib/include/*.hrl $(BOOTSTRAP_TOP)/lib/stdlib/include
- cp -f lib/orber/include/* $(BOOTSTRAP_TOP)/lib/orber/include
+ $(make_verbose)
+ $(V_at)cp -f lib/kernel/include/*.hrl $(BOOTSTRAP_TOP)/lib/kernel/include
+ $(V_at)cp -f lib/stdlib/include/*.hrl $(BOOTSTRAP_TOP)/lib/stdlib/include
+ $(V_at)cp -f lib/orber/include/* $(BOOTSTRAP_TOP)/lib/orber/include
# To remove modules left by the bootstrap building, but leave (restore)
# the modules in kernel which are needed for an emulator build
@@ -1000,9 +1008,10 @@ eclean:
#
bootstrap_root_clean:
- rm -f $(BOOTSTRAP_ROOT)/bootstrap/lib/*/ebin/*.beam
- rm -f $(BOOTSTRAP_ROOT)/bootstrap/lib/*/include/*.hrl
- rm -f $(BOOTSTRAP_ROOT)/bootstrap/bin/*.*
+ $(make_verbose)
+ $(V_at)rm -f $(BOOTSTRAP_ROOT)/bootstrap/lib/*/ebin/*.beam
+ $(V_at)rm -f $(BOOTSTRAP_ROOT)/bootstrap/lib/*/include/*.hrl
+ $(V_at)rm -f $(BOOTSTRAP_ROOT)/bootstrap/bin/*.*
# $(ERL_TOP)/bootstrap *should* equal $(BOOTSTRAP_TOP)
#
@@ -1010,15 +1019,16 @@ bootstrap_root_clean:
# extra safety precaution (we would really make a mess if
# $(BOOTSTRAP_TOP) for some reason should be empty).
bootstrap_clean:
- rm -f $(ERL_TOP)/bootstrap/lib/*/ebin/*.beam
- rm -f $(ERL_TOP)/bootstrap/lib/*/ebin/*.app
- rm -f $(ERL_TOP)/bootstrap/lib/*/egen/*
- rm -f $(ERL_TOP)/bootstrap/lib/*/include/*.hrl
- rm -f $(ERL_TOP)/bootstrap/primary_compiler/ebin/*
- rm -f $(ERL_TOP)/bootstrap/primary_compiler/egen/*
- rm -f $(ERL_TOP)/bootstrap/bin/*.*
- rm -f $(KERNEL_PRELOAD:%=$(ERL_TOP)/lib/kernel/ebin/%.beam)
- test $(BOOTSTRAP_ROOT) = $(ERL_TOP) \
+ $(make_verbose)
+ $(V_at)rm -f $(ERL_TOP)/bootstrap/lib/*/ebin/*.beam
+ $(V_at)rm -f $(ERL_TOP)/bootstrap/lib/*/ebin/*.app
+ $(V_at)rm -f $(ERL_TOP)/bootstrap/lib/*/egen/*
+ $(V_at)rm -f $(ERL_TOP)/bootstrap/lib/*/include/*.hrl
+ $(V_at)rm -f $(ERL_TOP)/bootstrap/primary_compiler/ebin/*
+ $(V_at)rm -f $(ERL_TOP)/bootstrap/primary_compiler/egen/*
+ $(V_at)rm -f $(ERL_TOP)/bootstrap/bin/*.*
+ $(V_at)rm -f $(KERNEL_PRELOAD:%=$(ERL_TOP)/lib/kernel/ebin/%.beam)
+ $(V_at)test $(BOOTSTRAP_ROOT) = $(ERL_TOP) \
|| $(MAKE) BOOTSTRAP_ROOT=$(BOOTSTRAP_ROOT) bootstrap_root_clean
# ----------------------------------------------------------------------
diff --git a/aclocal.m4 b/aclocal.m4
index b1cf1fe404..918e30a886 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -740,11 +740,16 @@ dnl Try to find POSIX threads
dnl The usual pthread lib...
AC_CHECK_LIB(pthread, pthread_create, THR_LIBS="-lpthread")
-dnl FreeBSD has pthreads in special c library, c_r...
+dnl Very old versions of FreeBSD have pthreads in special c library, c_r...
if test "x$THR_LIBS" = "x"; then
AC_CHECK_LIB(c_r, pthread_create, THR_LIBS="-lc_r")
fi
+dnl QNX has pthreads in standard C library
+ if test "x$THR_LIBS" = "x"; then
+ AC_CHECK_FUNC(pthread_create, THR_LIBS="none_needed")
+ fi
+
dnl On ofs1 the '-pthread' switch should be used
if test "x$THR_LIBS" = "x"; then
AC_MSG_CHECKING([if the '-pthread' switch can be used])
@@ -765,6 +770,9 @@ dnl On ofs1 the '-pthread' switch should be used
if test "x$THR_LIBS" != "x"; then
THR_DEFS="$THR_DEFS -D_THREAD_SAFE -D_REENTRANT -DPOSIX_THREADS"
THR_LIB_NAME=pthread
+ if test "x$THR_LIBS" = "xnone_needed"; then
+ THR_LIBS=
+ fi
case $host_os in
solaris*)
THR_DEFS="$THR_DEFS -D_POSIX_PTHREAD_SEMANTICS" ;;
@@ -1841,6 +1849,31 @@ case $erl_gethrvtime in
esac
])dnl
+dnl ----------------------------------------------------------------------
+dnl
+dnl LM_TRY_ENABLE_CFLAG
+dnl
+dnl
+dnl Tries a CFLAG and sees if it can be enabled without compiler errors
+dnl $1: textual cflag to add
+dnl $2: variable to store the modified CFLAG in
+dnl Usage example LM_TRY_ENABLE_CFLAG([-Werror=return-type], [CFLAGS])
+dnl
+dnl
+AC_DEFUN([LM_TRY_ENABLE_CFLAG], [
+ AC_MSG_CHECKING([if we can add $1 to $2 (via CFLAGS)])
+ saved_CFLAGS=$CFLAGS;
+ CFLAGS="$1 $$2";
+ AC_TRY_COMPILE([],[return 0;],can_enable_flag=true,can_enable_flag=false)
+ CFLAGS=$saved_CFLAGS;
+ if test "X$can_enable_flag" = "Xtrue"; then
+ AC_MSG_RESULT([yes])
+ AS_VAR_SET($2, "$1 $$2")
+ else
+ AC_MSG_RESULT([no])
+ fi
+])
+
dnl ERL_TRY_LINK_JAVA(CLASSES, FUNCTION-BODY
dnl [ACTION_IF_FOUND [, ACTION-IF-NOT-FOUND]])
dnl Freely inspired by AC_TRY_LINK. (Maybe better to create a
diff --git a/bootstrap/bin/start.boot b/bootstrap/bin/start.boot
index c6ebc852a2..a98b0eda7d 100644
--- a/bootstrap/bin/start.boot
+++ b/bootstrap/bin/start.boot
Binary files differ
diff --git a/bootstrap/bin/start_clean.boot b/bootstrap/bin/start_clean.boot
index c6ebc852a2..a98b0eda7d 100644
--- a/bootstrap/bin/start_clean.boot
+++ b/bootstrap/bin/start_clean.boot
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_a.beam b/bootstrap/lib/compiler/ebin/beam_a.beam
new file mode 100644
index 0000000000..fd53a2e0f9
--- /dev/null
+++ b/bootstrap/lib/compiler/ebin/beam_a.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_asm.beam b/bootstrap/lib/compiler/ebin/beam_asm.beam
index 7b1ee38ef8..fd36250580 100644
--- a/bootstrap/lib/compiler/ebin/beam_asm.beam
+++ b/bootstrap/lib/compiler/ebin/beam_asm.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_block.beam b/bootstrap/lib/compiler/ebin/beam_block.beam
index a7bb91adbb..7c287dc773 100644
--- a/bootstrap/lib/compiler/ebin/beam_block.beam
+++ b/bootstrap/lib/compiler/ebin/beam_block.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_bool.beam b/bootstrap/lib/compiler/ebin/beam_bool.beam
index 252257b71d..0324c7743f 100644
--- a/bootstrap/lib/compiler/ebin/beam_bool.beam
+++ b/bootstrap/lib/compiler/ebin/beam_bool.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_bsm.beam b/bootstrap/lib/compiler/ebin/beam_bsm.beam
index 0c998c8e8c..e0d595bea0 100644
--- a/bootstrap/lib/compiler/ebin/beam_bsm.beam
+++ b/bootstrap/lib/compiler/ebin/beam_bsm.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_clean.beam b/bootstrap/lib/compiler/ebin/beam_clean.beam
index 70523ca134..3fe3225c14 100644
--- a/bootstrap/lib/compiler/ebin/beam_clean.beam
+++ b/bootstrap/lib/compiler/ebin/beam_clean.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_dead.beam b/bootstrap/lib/compiler/ebin/beam_dead.beam
index 17cced3c1a..e80f8913a4 100644
--- a/bootstrap/lib/compiler/ebin/beam_dead.beam
+++ b/bootstrap/lib/compiler/ebin/beam_dead.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_dict.beam b/bootstrap/lib/compiler/ebin/beam_dict.beam
index 81e62b0a7d..30777e45b8 100644
--- a/bootstrap/lib/compiler/ebin/beam_dict.beam
+++ b/bootstrap/lib/compiler/ebin/beam_dict.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_disasm.beam b/bootstrap/lib/compiler/ebin/beam_disasm.beam
index ec48b89de7..2ecba86d56 100644
--- a/bootstrap/lib/compiler/ebin/beam_disasm.beam
+++ b/bootstrap/lib/compiler/ebin/beam_disasm.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_except.beam b/bootstrap/lib/compiler/ebin/beam_except.beam
index 5bd28a35d9..e86cdce99e 100644
--- a/bootstrap/lib/compiler/ebin/beam_except.beam
+++ b/bootstrap/lib/compiler/ebin/beam_except.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_flatten.beam b/bootstrap/lib/compiler/ebin/beam_flatten.beam
index 0ac0dc7b92..8f06d7270c 100644
--- a/bootstrap/lib/compiler/ebin/beam_flatten.beam
+++ b/bootstrap/lib/compiler/ebin/beam_flatten.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_jump.beam b/bootstrap/lib/compiler/ebin/beam_jump.beam
index 4811360890..d15e27f507 100644
--- a/bootstrap/lib/compiler/ebin/beam_jump.beam
+++ b/bootstrap/lib/compiler/ebin/beam_jump.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_opcodes.beam b/bootstrap/lib/compiler/ebin/beam_opcodes.beam
index 2c414f1c7d..8425c2b2b5 100644
--- a/bootstrap/lib/compiler/ebin/beam_opcodes.beam
+++ b/bootstrap/lib/compiler/ebin/beam_opcodes.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_peep.beam b/bootstrap/lib/compiler/ebin/beam_peep.beam
index aaba79046c..a21cc7e1e1 100644
--- a/bootstrap/lib/compiler/ebin/beam_peep.beam
+++ b/bootstrap/lib/compiler/ebin/beam_peep.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_receive.beam b/bootstrap/lib/compiler/ebin/beam_receive.beam
index 43f41f6535..95145224bf 100644
--- a/bootstrap/lib/compiler/ebin/beam_receive.beam
+++ b/bootstrap/lib/compiler/ebin/beam_receive.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_split.beam b/bootstrap/lib/compiler/ebin/beam_split.beam
index 296e6c4671..2271c15ee4 100644
--- a/bootstrap/lib/compiler/ebin/beam_split.beam
+++ b/bootstrap/lib/compiler/ebin/beam_split.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_trim.beam b/bootstrap/lib/compiler/ebin/beam_trim.beam
index 86f5d027f4..a497efa4cf 100644
--- a/bootstrap/lib/compiler/ebin/beam_trim.beam
+++ b/bootstrap/lib/compiler/ebin/beam_trim.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_type.beam b/bootstrap/lib/compiler/ebin/beam_type.beam
index 3cb5f06859..7b005ba802 100644
--- a/bootstrap/lib/compiler/ebin/beam_type.beam
+++ b/bootstrap/lib/compiler/ebin/beam_type.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_utils.beam b/bootstrap/lib/compiler/ebin/beam_utils.beam
index 523a6f03fb..abd69e31fe 100644
--- a/bootstrap/lib/compiler/ebin/beam_utils.beam
+++ b/bootstrap/lib/compiler/ebin/beam_utils.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_validator.beam b/bootstrap/lib/compiler/ebin/beam_validator.beam
index 41523ed185..d13cbe1944 100644
--- a/bootstrap/lib/compiler/ebin/beam_validator.beam
+++ b/bootstrap/lib/compiler/ebin/beam_validator.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_z.beam b/bootstrap/lib/compiler/ebin/beam_z.beam
new file mode 100644
index 0000000000..4d28344035
--- /dev/null
+++ b/bootstrap/lib/compiler/ebin/beam_z.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/cerl.beam b/bootstrap/lib/compiler/ebin/cerl.beam
index dcebe13bc8..a10f017869 100644
--- a/bootstrap/lib/compiler/ebin/cerl.beam
+++ b/bootstrap/lib/compiler/ebin/cerl.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/cerl_inline.beam b/bootstrap/lib/compiler/ebin/cerl_inline.beam
index eed98ecd2c..b195422469 100644
--- a/bootstrap/lib/compiler/ebin/cerl_inline.beam
+++ b/bootstrap/lib/compiler/ebin/cerl_inline.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/cerl_trees.beam b/bootstrap/lib/compiler/ebin/cerl_trees.beam
index df3f351c8d..49528c1635 100644
--- a/bootstrap/lib/compiler/ebin/cerl_trees.beam
+++ b/bootstrap/lib/compiler/ebin/cerl_trees.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/compile.beam b/bootstrap/lib/compiler/ebin/compile.beam
index c685035e23..9767c2b2cf 100644
--- a/bootstrap/lib/compiler/ebin/compile.beam
+++ b/bootstrap/lib/compiler/ebin/compile.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/compiler.app b/bootstrap/lib/compiler/ebin/compiler.app
index 5170231c59..733120aa9e 100644
--- a/bootstrap/lib/compiler/ebin/compiler.app
+++ b/bootstrap/lib/compiler/ebin/compiler.app
@@ -18,8 +18,9 @@
{application, compiler,
[{description, "ERTS CXC 138 10"},
- {vsn, "4.8.1"},
+ {vsn, "4.8.2"},
{modules, [
+ beam_a,
beam_asm,
beam_block,
beam_bool,
@@ -40,6 +41,7 @@
beam_type,
beam_utils,
beam_validator,
+ beam_z,
cerl,
cerl_clauses,
cerl_inline,
@@ -55,7 +57,6 @@
sys_core_dsetel,
sys_core_fold,
sys_core_inline,
- sys_expand_pmod,
sys_pre_attributes,
sys_pre_expand,
v3_codegen,
diff --git a/bootstrap/lib/compiler/ebin/core_lib.beam b/bootstrap/lib/compiler/ebin/core_lib.beam
index 1a60454b42..bbf9d34115 100644
--- a/bootstrap/lib/compiler/ebin/core_lib.beam
+++ b/bootstrap/lib/compiler/ebin/core_lib.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/core_lint.beam b/bootstrap/lib/compiler/ebin/core_lint.beam
index 08fef1eb71..bc18af0f7c 100644
--- a/bootstrap/lib/compiler/ebin/core_lint.beam
+++ b/bootstrap/lib/compiler/ebin/core_lint.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/core_parse.beam b/bootstrap/lib/compiler/ebin/core_parse.beam
index 4f555d8036..ac2a161ced 100644
--- a/bootstrap/lib/compiler/ebin/core_parse.beam
+++ b/bootstrap/lib/compiler/ebin/core_parse.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/core_pp.beam b/bootstrap/lib/compiler/ebin/core_pp.beam
index ef3504058a..934d718214 100644
--- a/bootstrap/lib/compiler/ebin/core_pp.beam
+++ b/bootstrap/lib/compiler/ebin/core_pp.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/core_scan.beam b/bootstrap/lib/compiler/ebin/core_scan.beam
index 245e59483d..f14eda5a33 100644
--- a/bootstrap/lib/compiler/ebin/core_scan.beam
+++ b/bootstrap/lib/compiler/ebin/core_scan.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/erl_bifs.beam b/bootstrap/lib/compiler/ebin/erl_bifs.beam
index 9234a54428..815258e0ac 100644
--- a/bootstrap/lib/compiler/ebin/erl_bifs.beam
+++ b/bootstrap/lib/compiler/ebin/erl_bifs.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/rec_env.beam b/bootstrap/lib/compiler/ebin/rec_env.beam
index 91a86d9855..edabfdf444 100644
--- a/bootstrap/lib/compiler/ebin/rec_env.beam
+++ b/bootstrap/lib/compiler/ebin/rec_env.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/sys_core_dsetel.beam b/bootstrap/lib/compiler/ebin/sys_core_dsetel.beam
index 0764734cb1..11c194a5cc 100644
--- a/bootstrap/lib/compiler/ebin/sys_core_dsetel.beam
+++ b/bootstrap/lib/compiler/ebin/sys_core_dsetel.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/sys_core_fold.beam b/bootstrap/lib/compiler/ebin/sys_core_fold.beam
index c878868598..2d812b9922 100644
--- a/bootstrap/lib/compiler/ebin/sys_core_fold.beam
+++ b/bootstrap/lib/compiler/ebin/sys_core_fold.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/sys_core_inline.beam b/bootstrap/lib/compiler/ebin/sys_core_inline.beam
index 907c9d53a5..fa5ed774cd 100644
--- a/bootstrap/lib/compiler/ebin/sys_core_inline.beam
+++ b/bootstrap/lib/compiler/ebin/sys_core_inline.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/sys_expand_pmod.beam b/bootstrap/lib/compiler/ebin/sys_expand_pmod.beam
deleted file mode 100644
index 1649b9f2ff..0000000000
--- a/bootstrap/lib/compiler/ebin/sys_expand_pmod.beam
+++ /dev/null
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/sys_pre_attributes.beam b/bootstrap/lib/compiler/ebin/sys_pre_attributes.beam
index a7ca15a033..d3b213e75a 100644
--- a/bootstrap/lib/compiler/ebin/sys_pre_attributes.beam
+++ b/bootstrap/lib/compiler/ebin/sys_pre_attributes.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/sys_pre_expand.beam b/bootstrap/lib/compiler/ebin/sys_pre_expand.beam
index 1a176b2e3f..60933730c3 100644
--- a/bootstrap/lib/compiler/ebin/sys_pre_expand.beam
+++ b/bootstrap/lib/compiler/ebin/sys_pre_expand.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/v3_codegen.beam b/bootstrap/lib/compiler/ebin/v3_codegen.beam
index 12026564d9..8071b9b616 100644
--- a/bootstrap/lib/compiler/ebin/v3_codegen.beam
+++ b/bootstrap/lib/compiler/ebin/v3_codegen.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/v3_core.beam b/bootstrap/lib/compiler/ebin/v3_core.beam
index 84c005edc9..5e29ac196e 100644
--- a/bootstrap/lib/compiler/ebin/v3_core.beam
+++ b/bootstrap/lib/compiler/ebin/v3_core.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/v3_kernel.beam b/bootstrap/lib/compiler/ebin/v3_kernel.beam
index cd4bf48540..ce71dd37bb 100644
--- a/bootstrap/lib/compiler/ebin/v3_kernel.beam
+++ b/bootstrap/lib/compiler/ebin/v3_kernel.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/v3_kernel_pp.beam b/bootstrap/lib/compiler/ebin/v3_kernel_pp.beam
index 485aa63dcb..d263343393 100644
--- a/bootstrap/lib/compiler/ebin/v3_kernel_pp.beam
+++ b/bootstrap/lib/compiler/ebin/v3_kernel_pp.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/v3_life.beam b/bootstrap/lib/compiler/ebin/v3_life.beam
index aa8b6b227b..f4a45b2a22 100644
--- a/bootstrap/lib/compiler/ebin/v3_life.beam
+++ b/bootstrap/lib/compiler/ebin/v3_life.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/application.beam b/bootstrap/lib/kernel/ebin/application.beam
index 4485b9e1e8..3287c3f132 100644
--- a/bootstrap/lib/kernel/ebin/application.beam
+++ b/bootstrap/lib/kernel/ebin/application.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/application_controller.beam b/bootstrap/lib/kernel/ebin/application_controller.beam
index 9c94dbd5c7..28512de9f1 100644
--- a/bootstrap/lib/kernel/ebin/application_controller.beam
+++ b/bootstrap/lib/kernel/ebin/application_controller.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/application_master.beam b/bootstrap/lib/kernel/ebin/application_master.beam
index 4d1098bcec..e73de8b687 100644
--- a/bootstrap/lib/kernel/ebin/application_master.beam
+++ b/bootstrap/lib/kernel/ebin/application_master.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/application_starter.beam b/bootstrap/lib/kernel/ebin/application_starter.beam
index 14ff4dc088..06d8098af9 100644
--- a/bootstrap/lib/kernel/ebin/application_starter.beam
+++ b/bootstrap/lib/kernel/ebin/application_starter.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/auth.beam b/bootstrap/lib/kernel/ebin/auth.beam
index 33f1ab875b..0f0eb3437e 100644
--- a/bootstrap/lib/kernel/ebin/auth.beam
+++ b/bootstrap/lib/kernel/ebin/auth.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/code.beam b/bootstrap/lib/kernel/ebin/code.beam
index f1fd519f50..04150eee56 100644
--- a/bootstrap/lib/kernel/ebin/code.beam
+++ b/bootstrap/lib/kernel/ebin/code.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/code_server.beam b/bootstrap/lib/kernel/ebin/code_server.beam
index dc10d111d2..f142832816 100644
--- a/bootstrap/lib/kernel/ebin/code_server.beam
+++ b/bootstrap/lib/kernel/ebin/code_server.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/disk_log.beam b/bootstrap/lib/kernel/ebin/disk_log.beam
index fa221e7c9d..6573609386 100644
--- a/bootstrap/lib/kernel/ebin/disk_log.beam
+++ b/bootstrap/lib/kernel/ebin/disk_log.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/disk_log_1.beam b/bootstrap/lib/kernel/ebin/disk_log_1.beam
index 1deb5ad05e..d851460d38 100644
--- a/bootstrap/lib/kernel/ebin/disk_log_1.beam
+++ b/bootstrap/lib/kernel/ebin/disk_log_1.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/disk_log_server.beam b/bootstrap/lib/kernel/ebin/disk_log_server.beam
index d985f64937..81b76167a5 100644
--- a/bootstrap/lib/kernel/ebin/disk_log_server.beam
+++ b/bootstrap/lib/kernel/ebin/disk_log_server.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/dist_ac.beam b/bootstrap/lib/kernel/ebin/dist_ac.beam
index 3eae6b82a7..b8c133313b 100644
--- a/bootstrap/lib/kernel/ebin/dist_ac.beam
+++ b/bootstrap/lib/kernel/ebin/dist_ac.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/dist_util.beam b/bootstrap/lib/kernel/ebin/dist_util.beam
index 7fc3325da4..8e07296a49 100644
--- a/bootstrap/lib/kernel/ebin/dist_util.beam
+++ b/bootstrap/lib/kernel/ebin/dist_util.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/erl_boot_server.beam b/bootstrap/lib/kernel/ebin/erl_boot_server.beam
index 19f6ceeda2..47563a5d81 100644
--- a/bootstrap/lib/kernel/ebin/erl_boot_server.beam
+++ b/bootstrap/lib/kernel/ebin/erl_boot_server.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/erl_ddll.beam b/bootstrap/lib/kernel/ebin/erl_ddll.beam
index 4fdec24b11..776c36e739 100644
--- a/bootstrap/lib/kernel/ebin/erl_ddll.beam
+++ b/bootstrap/lib/kernel/ebin/erl_ddll.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/erl_distribution.beam b/bootstrap/lib/kernel/ebin/erl_distribution.beam
index b084e63a0d..9a6acc0585 100644
--- a/bootstrap/lib/kernel/ebin/erl_distribution.beam
+++ b/bootstrap/lib/kernel/ebin/erl_distribution.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/erl_epmd.beam b/bootstrap/lib/kernel/ebin/erl_epmd.beam
index 8ae4bbaf14..0eaecd949a 100644
--- a/bootstrap/lib/kernel/ebin/erl_epmd.beam
+++ b/bootstrap/lib/kernel/ebin/erl_epmd.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/error_handler.beam b/bootstrap/lib/kernel/ebin/error_handler.beam
index 6d56c98c67..740ba28f72 100644
--- a/bootstrap/lib/kernel/ebin/error_handler.beam
+++ b/bootstrap/lib/kernel/ebin/error_handler.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/erts_debug.beam b/bootstrap/lib/kernel/ebin/erts_debug.beam
index 5c6483e368..4dda8d492c 100644
--- a/bootstrap/lib/kernel/ebin/erts_debug.beam
+++ b/bootstrap/lib/kernel/ebin/erts_debug.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/file.beam b/bootstrap/lib/kernel/ebin/file.beam
index 243be75c43..b66197b778 100644
--- a/bootstrap/lib/kernel/ebin/file.beam
+++ b/bootstrap/lib/kernel/ebin/file.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/file_io_server.beam b/bootstrap/lib/kernel/ebin/file_io_server.beam
index b8e2df2a2d..2c617ae7e4 100644
--- a/bootstrap/lib/kernel/ebin/file_io_server.beam
+++ b/bootstrap/lib/kernel/ebin/file_io_server.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/file_server.beam b/bootstrap/lib/kernel/ebin/file_server.beam
index fd9a9924bb..32c6a94a25 100644
--- a/bootstrap/lib/kernel/ebin/file_server.beam
+++ b/bootstrap/lib/kernel/ebin/file_server.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/gen_sctp.beam b/bootstrap/lib/kernel/ebin/gen_sctp.beam
index 3092353498..1f33d85cb2 100644
--- a/bootstrap/lib/kernel/ebin/gen_sctp.beam
+++ b/bootstrap/lib/kernel/ebin/gen_sctp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/gen_tcp.beam b/bootstrap/lib/kernel/ebin/gen_tcp.beam
index 02103cc215..0182e11345 100644
--- a/bootstrap/lib/kernel/ebin/gen_tcp.beam
+++ b/bootstrap/lib/kernel/ebin/gen_tcp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/gen_udp.beam b/bootstrap/lib/kernel/ebin/gen_udp.beam
index 3b9ca85608..e49561399d 100644
--- a/bootstrap/lib/kernel/ebin/gen_udp.beam
+++ b/bootstrap/lib/kernel/ebin/gen_udp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/global.beam b/bootstrap/lib/kernel/ebin/global.beam
index 96d7365006..4a90e37aac 100644
--- a/bootstrap/lib/kernel/ebin/global.beam
+++ b/bootstrap/lib/kernel/ebin/global.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/global_group.beam b/bootstrap/lib/kernel/ebin/global_group.beam
index dd7d0e429e..e989448fae 100644
--- a/bootstrap/lib/kernel/ebin/global_group.beam
+++ b/bootstrap/lib/kernel/ebin/global_group.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/global_search.beam b/bootstrap/lib/kernel/ebin/global_search.beam
index aa70042058..0d6f105e5f 100644
--- a/bootstrap/lib/kernel/ebin/global_search.beam
+++ b/bootstrap/lib/kernel/ebin/global_search.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/group.beam b/bootstrap/lib/kernel/ebin/group.beam
index 8e813f6964..2a7e46faf5 100644
--- a/bootstrap/lib/kernel/ebin/group.beam
+++ b/bootstrap/lib/kernel/ebin/group.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/heart.beam b/bootstrap/lib/kernel/ebin/heart.beam
index b20f872241..7e81d1610a 100644
--- a/bootstrap/lib/kernel/ebin/heart.beam
+++ b/bootstrap/lib/kernel/ebin/heart.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam
index 1574686ba6..5b41832dec 100644
--- a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam
+++ b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet.beam b/bootstrap/lib/kernel/ebin/inet.beam
index fe2d597723..88a97e0ec2 100644
--- a/bootstrap/lib/kernel/ebin/inet.beam
+++ b/bootstrap/lib/kernel/ebin/inet.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet6_tcp.beam b/bootstrap/lib/kernel/ebin/inet6_tcp.beam
index 4c80d1d71e..dc592e336c 100644
--- a/bootstrap/lib/kernel/ebin/inet6_tcp.beam
+++ b/bootstrap/lib/kernel/ebin/inet6_tcp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet6_tcp_dist.beam b/bootstrap/lib/kernel/ebin/inet6_tcp_dist.beam
index 1bc785fa37..148a74fe49 100644
--- a/bootstrap/lib/kernel/ebin/inet6_tcp_dist.beam
+++ b/bootstrap/lib/kernel/ebin/inet6_tcp_dist.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet6_udp.beam b/bootstrap/lib/kernel/ebin/inet6_udp.beam
index 736c0157e5..2c94263b99 100644
--- a/bootstrap/lib/kernel/ebin/inet6_udp.beam
+++ b/bootstrap/lib/kernel/ebin/inet6_udp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_db.beam b/bootstrap/lib/kernel/ebin/inet_db.beam
index 555c8c307e..a3081261a2 100644
--- a/bootstrap/lib/kernel/ebin/inet_db.beam
+++ b/bootstrap/lib/kernel/ebin/inet_db.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_dns.beam b/bootstrap/lib/kernel/ebin/inet_dns.beam
index 7f262cf20d..07b4356f7b 100644
--- a/bootstrap/lib/kernel/ebin/inet_dns.beam
+++ b/bootstrap/lib/kernel/ebin/inet_dns.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_gethost_native.beam b/bootstrap/lib/kernel/ebin/inet_gethost_native.beam
index 4e6ce0fc5e..47aa6e05f0 100644
--- a/bootstrap/lib/kernel/ebin/inet_gethost_native.beam
+++ b/bootstrap/lib/kernel/ebin/inet_gethost_native.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_parse.beam b/bootstrap/lib/kernel/ebin/inet_parse.beam
index b74c0ee730..c5a2398824 100644
--- a/bootstrap/lib/kernel/ebin/inet_parse.beam
+++ b/bootstrap/lib/kernel/ebin/inet_parse.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_res.beam b/bootstrap/lib/kernel/ebin/inet_res.beam
index 9e8e9fa4de..bef3efd11b 100644
--- a/bootstrap/lib/kernel/ebin/inet_res.beam
+++ b/bootstrap/lib/kernel/ebin/inet_res.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_tcp.beam b/bootstrap/lib/kernel/ebin/inet_tcp.beam
index d16795f44d..00a8175665 100644
--- a/bootstrap/lib/kernel/ebin/inet_tcp.beam
+++ b/bootstrap/lib/kernel/ebin/inet_tcp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam b/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam
index 22f2db4182..e794a5e94c 100644
--- a/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam
+++ b/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_udp.beam b/bootstrap/lib/kernel/ebin/inet_udp.beam
index 917e3da3a7..6fb98bd777 100644
--- a/bootstrap/lib/kernel/ebin/inet_udp.beam
+++ b/bootstrap/lib/kernel/ebin/inet_udp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/kernel.app b/bootstrap/lib/kernel/ebin/kernel.app
index 48f6250828..ca2dc4f7c5 100644
--- a/bootstrap/lib/kernel/ebin/kernel.app
+++ b/bootstrap/lib/kernel/ebin/kernel.app
@@ -28,7 +28,6 @@
application_starter,
auth,
code,
- packages,
code_server,
dist_util,
erl_boot_server,
diff --git a/bootstrap/lib/kernel/ebin/kernel.beam b/bootstrap/lib/kernel/ebin/kernel.beam
index 8321a999c1..7f6d8fcb30 100644
--- a/bootstrap/lib/kernel/ebin/kernel.beam
+++ b/bootstrap/lib/kernel/ebin/kernel.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/kernel_config.beam b/bootstrap/lib/kernel/ebin/kernel_config.beam
index c5a63b6217..848401eacf 100644
--- a/bootstrap/lib/kernel/ebin/kernel_config.beam
+++ b/bootstrap/lib/kernel/ebin/kernel_config.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/net_adm.beam b/bootstrap/lib/kernel/ebin/net_adm.beam
index 182c2cd0fc..dc7e091cf2 100644
--- a/bootstrap/lib/kernel/ebin/net_adm.beam
+++ b/bootstrap/lib/kernel/ebin/net_adm.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/net_kernel.beam b/bootstrap/lib/kernel/ebin/net_kernel.beam
index 9eebd72403..f27b82d841 100644
--- a/bootstrap/lib/kernel/ebin/net_kernel.beam
+++ b/bootstrap/lib/kernel/ebin/net_kernel.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/os.beam b/bootstrap/lib/kernel/ebin/os.beam
index ea33408b31..8e13b88768 100644
--- a/bootstrap/lib/kernel/ebin/os.beam
+++ b/bootstrap/lib/kernel/ebin/os.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/packages.beam b/bootstrap/lib/kernel/ebin/packages.beam
deleted file mode 100644
index 511c6a6e74..0000000000
--- a/bootstrap/lib/kernel/ebin/packages.beam
+++ /dev/null
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/pg2.beam b/bootstrap/lib/kernel/ebin/pg2.beam
index 439bbc24f2..02b9264e22 100644
--- a/bootstrap/lib/kernel/ebin/pg2.beam
+++ b/bootstrap/lib/kernel/ebin/pg2.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/ram_file.beam b/bootstrap/lib/kernel/ebin/ram_file.beam
index 02baece827..74fcc898c3 100644
--- a/bootstrap/lib/kernel/ebin/ram_file.beam
+++ b/bootstrap/lib/kernel/ebin/ram_file.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/rpc.beam b/bootstrap/lib/kernel/ebin/rpc.beam
index bfb80cf827..305779539a 100644
--- a/bootstrap/lib/kernel/ebin/rpc.beam
+++ b/bootstrap/lib/kernel/ebin/rpc.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/seq_trace.beam b/bootstrap/lib/kernel/ebin/seq_trace.beam
index ceb4e14324..13489135a2 100644
--- a/bootstrap/lib/kernel/ebin/seq_trace.beam
+++ b/bootstrap/lib/kernel/ebin/seq_trace.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/standard_error.beam b/bootstrap/lib/kernel/ebin/standard_error.beam
index f34c1a9bd1..b5b22bb71a 100644
--- a/bootstrap/lib/kernel/ebin/standard_error.beam
+++ b/bootstrap/lib/kernel/ebin/standard_error.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/user.beam b/bootstrap/lib/kernel/ebin/user.beam
index f3aae4a980..7b761283a0 100644
--- a/bootstrap/lib/kernel/ebin/user.beam
+++ b/bootstrap/lib/kernel/ebin/user.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/wrap_log_reader.beam b/bootstrap/lib/kernel/ebin/wrap_log_reader.beam
index 1af9de5e72..7a328be682 100644
--- a/bootstrap/lib/kernel/ebin/wrap_log_reader.beam
+++ b/bootstrap/lib/kernel/ebin/wrap_log_reader.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/array.beam b/bootstrap/lib/stdlib/ebin/array.beam
index 8741e4d5df..28d04dea2c 100644
--- a/bootstrap/lib/stdlib/ebin/array.beam
+++ b/bootstrap/lib/stdlib/ebin/array.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/base64.beam b/bootstrap/lib/stdlib/ebin/base64.beam
index 07877625dd..2ca9a4d0b8 100644
--- a/bootstrap/lib/stdlib/ebin/base64.beam
+++ b/bootstrap/lib/stdlib/ebin/base64.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/beam_lib.beam b/bootstrap/lib/stdlib/ebin/beam_lib.beam
index afe3bcc466..c7ebc3b440 100644
--- a/bootstrap/lib/stdlib/ebin/beam_lib.beam
+++ b/bootstrap/lib/stdlib/ebin/beam_lib.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/binary.beam b/bootstrap/lib/stdlib/ebin/binary.beam
index 255c50aa01..6077d965ed 100644
--- a/bootstrap/lib/stdlib/ebin/binary.beam
+++ b/bootstrap/lib/stdlib/ebin/binary.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/c.beam b/bootstrap/lib/stdlib/ebin/c.beam
index 8c69197cbc..d919fa0a2d 100644
--- a/bootstrap/lib/stdlib/ebin/c.beam
+++ b/bootstrap/lib/stdlib/ebin/c.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/dets.beam b/bootstrap/lib/stdlib/ebin/dets.beam
index 4a33312cc0..19f589980f 100644
--- a/bootstrap/lib/stdlib/ebin/dets.beam
+++ b/bootstrap/lib/stdlib/ebin/dets.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/dets_server.beam b/bootstrap/lib/stdlib/ebin/dets_server.beam
index 26de164bd9..871104a73d 100644
--- a/bootstrap/lib/stdlib/ebin/dets_server.beam
+++ b/bootstrap/lib/stdlib/ebin/dets_server.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/dets_utils.beam b/bootstrap/lib/stdlib/ebin/dets_utils.beam
index e4cd1e8b2e..f9b99f574c 100644
--- a/bootstrap/lib/stdlib/ebin/dets_utils.beam
+++ b/bootstrap/lib/stdlib/ebin/dets_utils.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/dets_v8.beam b/bootstrap/lib/stdlib/ebin/dets_v8.beam
index c8e1549256..e580e2f1ea 100644
--- a/bootstrap/lib/stdlib/ebin/dets_v8.beam
+++ b/bootstrap/lib/stdlib/ebin/dets_v8.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/dets_v9.beam b/bootstrap/lib/stdlib/ebin/dets_v9.beam
index 8cfcb9f8f1..4d383902cd 100644
--- a/bootstrap/lib/stdlib/ebin/dets_v9.beam
+++ b/bootstrap/lib/stdlib/ebin/dets_v9.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/dict.beam b/bootstrap/lib/stdlib/ebin/dict.beam
index 35e67d6c59..83d30876cc 100644
--- a/bootstrap/lib/stdlib/ebin/dict.beam
+++ b/bootstrap/lib/stdlib/ebin/dict.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/digraph.beam b/bootstrap/lib/stdlib/ebin/digraph.beam
index 2c1788668d..82735d07cc 100644
--- a/bootstrap/lib/stdlib/ebin/digraph.beam
+++ b/bootstrap/lib/stdlib/ebin/digraph.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/digraph_utils.beam b/bootstrap/lib/stdlib/ebin/digraph_utils.beam
index 39cb9d90da..a5957fc9ce 100644
--- a/bootstrap/lib/stdlib/ebin/digraph_utils.beam
+++ b/bootstrap/lib/stdlib/ebin/digraph_utils.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/edlin.beam b/bootstrap/lib/stdlib/ebin/edlin.beam
index 874bc4e107..3eac2b2000 100644
--- a/bootstrap/lib/stdlib/ebin/edlin.beam
+++ b/bootstrap/lib/stdlib/ebin/edlin.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/epp.beam b/bootstrap/lib/stdlib/ebin/epp.beam
index 2e2b3ef4ed..a3a86afce9 100644
--- a/bootstrap/lib/stdlib/ebin/epp.beam
+++ b/bootstrap/lib/stdlib/ebin/epp.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_bits.beam b/bootstrap/lib/stdlib/ebin/erl_bits.beam
index 595be6a76a..7149491121 100644
--- a/bootstrap/lib/stdlib/ebin/erl_bits.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_bits.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_compile.beam b/bootstrap/lib/stdlib/ebin/erl_compile.beam
index e449884f0b..c2757faf82 100644
--- a/bootstrap/lib/stdlib/ebin/erl_compile.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_compile.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_eval.beam b/bootstrap/lib/stdlib/ebin/erl_eval.beam
index 6198c4f43a..1445449c6e 100644
--- a/bootstrap/lib/stdlib/ebin/erl_eval.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_eval.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_expand_records.beam b/bootstrap/lib/stdlib/ebin/erl_expand_records.beam
index 5c9663cd54..764f624cab 100644
--- a/bootstrap/lib/stdlib/ebin/erl_expand_records.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_expand_records.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_internal.beam b/bootstrap/lib/stdlib/ebin/erl_internal.beam
index 94a0a75c29..d557c6c5d7 100644
--- a/bootstrap/lib/stdlib/ebin/erl_internal.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_internal.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_lint.beam b/bootstrap/lib/stdlib/ebin/erl_lint.beam
index 875ccf94c2..20b6d9cd44 100644
--- a/bootstrap/lib/stdlib/ebin/erl_lint.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_lint.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_parse.beam b/bootstrap/lib/stdlib/ebin/erl_parse.beam
index 85fa455908..0b274c9630 100644
--- a/bootstrap/lib/stdlib/ebin/erl_parse.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_parse.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_pp.beam b/bootstrap/lib/stdlib/ebin/erl_pp.beam
index 2c32b68322..9c5c72af30 100644
--- a/bootstrap/lib/stdlib/ebin/erl_pp.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_pp.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_scan.beam b/bootstrap/lib/stdlib/ebin/erl_scan.beam
index 9e70ed846e..ef47d3a06c 100644
--- a/bootstrap/lib/stdlib/ebin/erl_scan.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_scan.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_tar.beam b/bootstrap/lib/stdlib/ebin/erl_tar.beam
index 7eacf3272c..4cb833bb30 100644
--- a/bootstrap/lib/stdlib/ebin/erl_tar.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_tar.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/escript.beam b/bootstrap/lib/stdlib/ebin/escript.beam
index e832f973d7..f8f3145066 100644
--- a/bootstrap/lib/stdlib/ebin/escript.beam
+++ b/bootstrap/lib/stdlib/ebin/escript.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/ets.beam b/bootstrap/lib/stdlib/ebin/ets.beam
index cc6521891b..e255819b70 100644
--- a/bootstrap/lib/stdlib/ebin/ets.beam
+++ b/bootstrap/lib/stdlib/ebin/ets.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/eval_bits.beam b/bootstrap/lib/stdlib/ebin/eval_bits.beam
index 73e20d9a8d..379fc3655f 100644
--- a/bootstrap/lib/stdlib/ebin/eval_bits.beam
+++ b/bootstrap/lib/stdlib/ebin/eval_bits.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/file_sorter.beam b/bootstrap/lib/stdlib/ebin/file_sorter.beam
index 633d8acd10..180054c091 100644
--- a/bootstrap/lib/stdlib/ebin/file_sorter.beam
+++ b/bootstrap/lib/stdlib/ebin/file_sorter.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/filelib.beam b/bootstrap/lib/stdlib/ebin/filelib.beam
index 20f48fe18e..65f45632ac 100644
--- a/bootstrap/lib/stdlib/ebin/filelib.beam
+++ b/bootstrap/lib/stdlib/ebin/filelib.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/filename.beam b/bootstrap/lib/stdlib/ebin/filename.beam
index e371f3f478..de676f2bed 100644
--- a/bootstrap/lib/stdlib/ebin/filename.beam
+++ b/bootstrap/lib/stdlib/ebin/filename.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gb_sets.beam b/bootstrap/lib/stdlib/ebin/gb_sets.beam
index dc4c752654..10b584677d 100644
--- a/bootstrap/lib/stdlib/ebin/gb_sets.beam
+++ b/bootstrap/lib/stdlib/ebin/gb_sets.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gb_trees.beam b/bootstrap/lib/stdlib/ebin/gb_trees.beam
index edf1805440..24aab57544 100644
--- a/bootstrap/lib/stdlib/ebin/gb_trees.beam
+++ b/bootstrap/lib/stdlib/ebin/gb_trees.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gen.beam b/bootstrap/lib/stdlib/ebin/gen.beam
index 0a39dc1c7e..77d0bf806a 100644
--- a/bootstrap/lib/stdlib/ebin/gen.beam
+++ b/bootstrap/lib/stdlib/ebin/gen.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gen_event.beam b/bootstrap/lib/stdlib/ebin/gen_event.beam
index 23c4f53c30..be35e0124e 100644
--- a/bootstrap/lib/stdlib/ebin/gen_event.beam
+++ b/bootstrap/lib/stdlib/ebin/gen_event.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gen_fsm.beam b/bootstrap/lib/stdlib/ebin/gen_fsm.beam
index c2713544ff..06782fbf91 100644
--- a/bootstrap/lib/stdlib/ebin/gen_fsm.beam
+++ b/bootstrap/lib/stdlib/ebin/gen_fsm.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gen_server.beam b/bootstrap/lib/stdlib/ebin/gen_server.beam
index 5d68dda4cf..0ccd003b0b 100644
--- a/bootstrap/lib/stdlib/ebin/gen_server.beam
+++ b/bootstrap/lib/stdlib/ebin/gen_server.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/io.beam b/bootstrap/lib/stdlib/ebin/io.beam
index 0a2ae3490c..ddfcca41e8 100644
--- a/bootstrap/lib/stdlib/ebin/io.beam
+++ b/bootstrap/lib/stdlib/ebin/io.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/io_lib.beam b/bootstrap/lib/stdlib/ebin/io_lib.beam
index b240aa157d..9420ea0f53 100644
--- a/bootstrap/lib/stdlib/ebin/io_lib.beam
+++ b/bootstrap/lib/stdlib/ebin/io_lib.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/io_lib_format.beam b/bootstrap/lib/stdlib/ebin/io_lib_format.beam
index 5fb023c5e1..1a7c3393f8 100644
--- a/bootstrap/lib/stdlib/ebin/io_lib_format.beam
+++ b/bootstrap/lib/stdlib/ebin/io_lib_format.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/io_lib_fread.beam b/bootstrap/lib/stdlib/ebin/io_lib_fread.beam
index 5ecd664026..f3f059df26 100644
--- a/bootstrap/lib/stdlib/ebin/io_lib_fread.beam
+++ b/bootstrap/lib/stdlib/ebin/io_lib_fread.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam b/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam
index be283307f3..b14eb23e7c 100644
--- a/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam
+++ b/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/lib.beam b/bootstrap/lib/stdlib/ebin/lib.beam
index 3865cfb227..668ea7eb29 100644
--- a/bootstrap/lib/stdlib/ebin/lib.beam
+++ b/bootstrap/lib/stdlib/ebin/lib.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/lists.beam b/bootstrap/lib/stdlib/ebin/lists.beam
index dfd689aa5a..68b6d0da56 100644
--- a/bootstrap/lib/stdlib/ebin/lists.beam
+++ b/bootstrap/lib/stdlib/ebin/lists.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/log_mf_h.beam b/bootstrap/lib/stdlib/ebin/log_mf_h.beam
index fdb417b71e..7d5ef0e093 100644
--- a/bootstrap/lib/stdlib/ebin/log_mf_h.beam
+++ b/bootstrap/lib/stdlib/ebin/log_mf_h.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/ms_transform.beam b/bootstrap/lib/stdlib/ebin/ms_transform.beam
index bc16416161..6031052e4c 100644
--- a/bootstrap/lib/stdlib/ebin/ms_transform.beam
+++ b/bootstrap/lib/stdlib/ebin/ms_transform.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/otp_internal.beam b/bootstrap/lib/stdlib/ebin/otp_internal.beam
index 270d35ef33..84feea2c66 100644
--- a/bootstrap/lib/stdlib/ebin/otp_internal.beam
+++ b/bootstrap/lib/stdlib/ebin/otp_internal.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/pg.beam b/bootstrap/lib/stdlib/ebin/pg.beam
index 0b08fb57ca..65195defbf 100644
--- a/bootstrap/lib/stdlib/ebin/pg.beam
+++ b/bootstrap/lib/stdlib/ebin/pg.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/pool.beam b/bootstrap/lib/stdlib/ebin/pool.beam
index 3b1dbc3524..9a9bfa4e2f 100644
--- a/bootstrap/lib/stdlib/ebin/pool.beam
+++ b/bootstrap/lib/stdlib/ebin/pool.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/proc_lib.beam b/bootstrap/lib/stdlib/ebin/proc_lib.beam
index 6b5c081480..e22b3ad758 100644
--- a/bootstrap/lib/stdlib/ebin/proc_lib.beam
+++ b/bootstrap/lib/stdlib/ebin/proc_lib.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/qlc.beam b/bootstrap/lib/stdlib/ebin/qlc.beam
index 716f28b661..302dda040f 100644
--- a/bootstrap/lib/stdlib/ebin/qlc.beam
+++ b/bootstrap/lib/stdlib/ebin/qlc.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/qlc_pt.beam b/bootstrap/lib/stdlib/ebin/qlc_pt.beam
index 8a25d95384..eb098b31ae 100644
--- a/bootstrap/lib/stdlib/ebin/qlc_pt.beam
+++ b/bootstrap/lib/stdlib/ebin/qlc_pt.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/queue.beam b/bootstrap/lib/stdlib/ebin/queue.beam
index 5ebb0f9cc6..688c411798 100644
--- a/bootstrap/lib/stdlib/ebin/queue.beam
+++ b/bootstrap/lib/stdlib/ebin/queue.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/re.beam b/bootstrap/lib/stdlib/ebin/re.beam
index e20546d45d..8001c49672 100644
--- a/bootstrap/lib/stdlib/ebin/re.beam
+++ b/bootstrap/lib/stdlib/ebin/re.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/sets.beam b/bootstrap/lib/stdlib/ebin/sets.beam
index 5ac7691a8f..614f807ae1 100644
--- a/bootstrap/lib/stdlib/ebin/sets.beam
+++ b/bootstrap/lib/stdlib/ebin/sets.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/shell.beam b/bootstrap/lib/stdlib/ebin/shell.beam
index 20b9938d06..5614d31ac8 100644
--- a/bootstrap/lib/stdlib/ebin/shell.beam
+++ b/bootstrap/lib/stdlib/ebin/shell.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/slave.beam b/bootstrap/lib/stdlib/ebin/slave.beam
index dfc8cad9d6..4f3dfa3716 100644
--- a/bootstrap/lib/stdlib/ebin/slave.beam
+++ b/bootstrap/lib/stdlib/ebin/slave.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/sofs.beam b/bootstrap/lib/stdlib/ebin/sofs.beam
index a0c8c58c03..5a7ddd5f56 100644
--- a/bootstrap/lib/stdlib/ebin/sofs.beam
+++ b/bootstrap/lib/stdlib/ebin/sofs.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/supervisor.beam b/bootstrap/lib/stdlib/ebin/supervisor.beam
index 837027e93a..aae89985c8 100644
--- a/bootstrap/lib/stdlib/ebin/supervisor.beam
+++ b/bootstrap/lib/stdlib/ebin/supervisor.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/sys.beam b/bootstrap/lib/stdlib/ebin/sys.beam
index 724dfed4e6..e06badfec4 100644
--- a/bootstrap/lib/stdlib/ebin/sys.beam
+++ b/bootstrap/lib/stdlib/ebin/sys.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/unicode.beam b/bootstrap/lib/stdlib/ebin/unicode.beam
index 074fe0534d..9869d4862b 100644
--- a/bootstrap/lib/stdlib/ebin/unicode.beam
+++ b/bootstrap/lib/stdlib/ebin/unicode.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/win32reg.beam b/bootstrap/lib/stdlib/ebin/win32reg.beam
index 9c7893f7ff..6df20f8db7 100644
--- a/bootstrap/lib/stdlib/ebin/win32reg.beam
+++ b/bootstrap/lib/stdlib/ebin/win32reg.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/zip.beam b/bootstrap/lib/stdlib/ebin/zip.beam
index 2907ee286b..41386df3f0 100644
--- a/bootstrap/lib/stdlib/ebin/zip.beam
+++ b/bootstrap/lib/stdlib/ebin/zip.beam
Binary files differ
diff --git a/configure.in b/configure.in
index e906c17ecc..c0994245e8 100644
--- a/configure.in
+++ b/configure.in
@@ -354,6 +354,21 @@ elif test X"$TMPSYS" '=' X"Darwin-i386"; then
export LDFLAGS
fi
+AC_ARG_ENABLE([silent-rules], [dnl
+AS_HELP_STRING(
+ [--enable-silent-rules],
+ [less verbose build output (undo: "make V=1")])
+AS_HELP_STRING(
+ [--disable-silent-rules],
+ [verbose build output (undo: "make V=0")])dnl
+])
+
+DEFAULT_VERBOSITY=1
+if test X${enable_silent_rules} = Xyes; then
+ DEFAULT_VERBOSITY=0
+fi
+AC_SUBST(DEFAULT_VERBOSITY)
+
if test X${enable_m64_build} = Xyes; then
enable_hipe=no
CFLAGS="-m64 $CFLAGS"
@@ -378,7 +393,7 @@ AC_SUBST(NATIVE_LIBS_ENABLED)
export ERL_TOP
AC_CONFIG_SUBDIRS(lib erts)
-AC_CONFIG_FILES([Makefile])
+AC_CONFIG_FILES([Makefile make/output.mk])
AC_CONFIG_FILES([make/emd2exml], [chmod +x make/emd2exml])
AC_OUTPUT
diff --git a/erts/Makefile.in b/erts/Makefile.in
index 5df6d71ef3..0bcb784972 100644
--- a/erts/Makefile.in
+++ b/erts/Makefile.in
@@ -19,6 +19,7 @@
.NOTPARALLEL:
+include $(ERL_TOP)/make/output.mk
include $(ERL_TOP)/make/target.mk
include vsn.mk
@@ -38,11 +39,11 @@ all: smp opt
.PHONY: docs
docs:
- ( cd doc/src && $(MAKE) $@ )
+ $(V_at)( cd doc/src && $(MAKE) $@ )
.PHONY: debug opt clean
debug opt clean:
- for d in emulator $(ERTSDIRS); do \
+ $(V_at)for d in emulator $(ERTSDIRS); do \
if test -d $$d; then \
( cd $$d && $(MAKE) $@ FLAVOR=$(FLAVOR) ) || exit $$? ; \
fi ; \
@@ -55,7 +56,7 @@ debug opt clean:
.PHONY: $(EXTRA_FLAVORS)
$(EXTRA_FLAVORS):
- ( cd emulator && $(MAKE) opt FLAVOR=$@ )
+ $(V_at)( cd emulator && $(MAKE) opt FLAVOR=$@ )
# Make erl script and erlc in $(ERL_TOP)/bin which runs the compiled version
# Note that erlc is not a script and requires extra handling on cygwin.
@@ -67,7 +68,7 @@ $(EXTRA_FLAVORS):
.PHONY: local_setup
local_setup:
@cd start_scripts && $(MAKE)
- @echo `ls $(ERL_TOP)/bin/`
+ $(V_colon)@echo `ls $(ERL_TOP)/bin/`
@rm -f $(ERL_TOP)/bin/erl $(ERL_TOP)/bin/erlc $(ERL_TOP)/bin/cerl \
$(ERL_TOP)/bin/erl.exe $(ERL_TOP)/bin/erlc.exe \
$(ERL_TOP)/bin/escript $(ERL_TOP)/bin/escript.exe \
@@ -128,10 +129,10 @@ makefiles:
.PHONY: release
release:
- for f in plain $(EXTRA_FLAVORS) ; do \
+ $(V_at)for f in plain $(EXTRA_FLAVORS) ; do \
( cd emulator && $(MAKE) release FLAVOR=$$f ) \
done
- for d in $(ERTSDIRS) $(XINSTDIRS); do \
+ $(V_at)for d in $(ERTSDIRS) $(XINSTDIRS); do \
if test -d $$d; then \
( cd $$d && $(MAKE) $@ ) || exit $$? ; \
fi ; \
@@ -139,4 +140,4 @@ release:
.PHONY: release_docs
release_docs:
- ( cd doc/src && $(MAKE) $@ )
+ $(V_at)( cd doc/src && $(MAKE) $@ )
diff --git a/erts/aclocal.m4 b/erts/aclocal.m4
index b1cf1fe404..918e30a886 100644
--- a/erts/aclocal.m4
+++ b/erts/aclocal.m4
@@ -740,11 +740,16 @@ dnl Try to find POSIX threads
dnl The usual pthread lib...
AC_CHECK_LIB(pthread, pthread_create, THR_LIBS="-lpthread")
-dnl FreeBSD has pthreads in special c library, c_r...
+dnl Very old versions of FreeBSD have pthreads in special c library, c_r...
if test "x$THR_LIBS" = "x"; then
AC_CHECK_LIB(c_r, pthread_create, THR_LIBS="-lc_r")
fi
+dnl QNX has pthreads in standard C library
+ if test "x$THR_LIBS" = "x"; then
+ AC_CHECK_FUNC(pthread_create, THR_LIBS="none_needed")
+ fi
+
dnl On ofs1 the '-pthread' switch should be used
if test "x$THR_LIBS" = "x"; then
AC_MSG_CHECKING([if the '-pthread' switch can be used])
@@ -765,6 +770,9 @@ dnl On ofs1 the '-pthread' switch should be used
if test "x$THR_LIBS" != "x"; then
THR_DEFS="$THR_DEFS -D_THREAD_SAFE -D_REENTRANT -DPOSIX_THREADS"
THR_LIB_NAME=pthread
+ if test "x$THR_LIBS" = "xnone_needed"; then
+ THR_LIBS=
+ fi
case $host_os in
solaris*)
THR_DEFS="$THR_DEFS -D_POSIX_PTHREAD_SEMANTICS" ;;
@@ -1841,6 +1849,31 @@ case $erl_gethrvtime in
esac
])dnl
+dnl ----------------------------------------------------------------------
+dnl
+dnl LM_TRY_ENABLE_CFLAG
+dnl
+dnl
+dnl Tries a CFLAG and sees if it can be enabled without compiler errors
+dnl $1: textual cflag to add
+dnl $2: variable to store the modified CFLAG in
+dnl Usage example LM_TRY_ENABLE_CFLAG([-Werror=return-type], [CFLAGS])
+dnl
+dnl
+AC_DEFUN([LM_TRY_ENABLE_CFLAG], [
+ AC_MSG_CHECKING([if we can add $1 to $2 (via CFLAGS)])
+ saved_CFLAGS=$CFLAGS;
+ CFLAGS="$1 $$2";
+ AC_TRY_COMPILE([],[return 0;],can_enable_flag=true,can_enable_flag=false)
+ CFLAGS=$saved_CFLAGS;
+ if test "X$can_enable_flag" = "Xtrue"; then
+ AC_MSG_RESULT([yes])
+ AS_VAR_SET($2, "$1 $$2")
+ else
+ AC_MSG_RESULT([no])
+ fi
+])
+
dnl ERL_TRY_LINK_JAVA(CLASSES, FUNCTION-BODY
dnl [ACTION_IF_FOUND [, ACTION-IF-NOT-FOUND]])
dnl Freely inspired by AC_TRY_LINK. (Maybe better to create a
diff --git a/erts/configure.in b/erts/configure.in
index 6ad1951a4e..a0c5cab181 100644
--- a/erts/configure.in
+++ b/erts/configure.in
@@ -537,6 +537,9 @@ else
fi
if test "x$GCC" = xyes; then
+ # Treat certain GCC warnings as errors
+ LM_TRY_ENABLE_CFLAG([-Werror=return-type], [WERRORFLAGS])
+
# until the emulator can handle this, I suggest we turn it off!
#WFLAGS="-Wall -Wshadow -Wcast-qual -Wmissing-declarations"
WFLAGS="-Wall -Wstrict-prototypes"
@@ -559,11 +562,13 @@ if test "x$GCC" = xyes; then
CFLAGS=$saved_CFLAGS
else
WFLAGS=""
+ WERRORFLAGS=""
fi
dnl DEBUG_FLAGS is obsolete (I hope)
AC_SUBST(DEBUG_FLAGS)
AC_SUBST(DEBUG_CFLAGS)
AC_SUBST(WFLAGS)
+AC_SUBST(WERRORFLAGS)
AC_SUBST(CFLAG_RUNTIME_LIBRARY_PATH)
AC_CHECK_SIZEOF(void *) # Needed for ARCH and smp checks below
@@ -735,12 +740,8 @@ esac
AC_MSG_CHECKING(if VM has to be linked with Carbon framework)
case $ARCH-$OPSYS in
- amd64-darwin*)
- LIBCARBON=
- AC_MSG_RESULT([no])
- ;;
*-darwin*)
- LIBCARBON="-framework Carbon "
+ LIBCARBON="-framework Carbon -framework Cocoa"
AC_MSG_RESULT([yes])
;;
*)
@@ -826,6 +827,12 @@ if test -z "$FOP"; then
AC_MSG_WARN([No 'fop' command found: going to generate placeholder PDF files])
fi
+AC_CHECK_PROGS(XMLLINT, xmllint)
+if test -z "$XMLLINT"; then
+ echo "xmllint" >> doc/CONF_INFO
+ AC_MSG_WARN([No 'xmllint' command found: can't run the xmllint target for the documentation])
+fi
+
dnl
dnl We can live with Solaris /usr/ucb/install
dnl
@@ -1075,8 +1082,45 @@ fi
AC_SUBST(ERTS_BUILD_SMP_EMU)
-AC_CHECK_FUNCS([posix_fadvise])
+AC_CHECK_FUNCS([posix_fadvise, fallocate])
+AC_CHECK_HEADERS([linux/falloc.h])
+dnl * Old glibcs have broken posix_fallocate(). Make sure not to use it.
+dnl * It may also be broken in AIX.
+AC_CACHE_CHECK([whether posix_fallocate() works],i_cv_posix_fallocate_works,[
+ AC_TRY_RUN([
+ #if !defined(__sun) && !defined(__sun__)
+ #define _XOPEN_SOURCE 600
+ #endif
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <fcntl.h>
+ #include <unistd.h>
+ #if defined(__GLIBC__) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 7))
+ possibly broken posix_fallocate
+ #endif
+ int main() {
+ int fd = creat("conftest.temp", 0600);
+ int ret;
+ if (-1 == fd) {
+ perror("creat()");
+ return 2;
+ }
+ ret = posix_fallocate(fd, 1024, 1024) < 0 ? 1 : 0;
+ unlink("conftest.temp");
+ return ret;
+ }
+ ], [
+ i_cv_posix_fallocate_works=yes
+ ], [
+ i_cv_posix_fallocate_works=no
+ ], [
+ i_cv_posix_fallocate_works=no
+ ])
+])
+if test $i_cv_posix_fallocate_works = yes; then
+ AC_DEFINE(HAVE_POSIX_FALLOCATE,, Define if you have a working posix_fallocate())
+fi
#
# Figure out if the emulator should use threads. The default is set above
@@ -2000,8 +2044,12 @@ case "$erts_cv_have_in6addr_loopback" in
[Define to 1 if you have the variable in6addr_loopback declared.])
esac
-AC_CHECK_DECLS([IN6ADDR_ANY_INIT, IN6ADDR_LOOPBACK_INIT], [], [],
- [#include <netinet/in.h>])
+AC_CHECK_DECLS([IN6ADDR_ANY_INIT, IN6ADDR_LOOPBACK_INIT, IPV6_V6ONLY], [], [],
+ [
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ ])
dnl ----------------------------------------------------------------------
dnl Checks for features/quirks in the system that affects Erlang.
@@ -4457,7 +4505,7 @@ dnl needs to be rebuilt.
dnl
AC_DEFINE_UNQUOTED(ERTS_EMU_CMDLINE_FLAGS,
-"$STATIC_CFLAGS $CFLAGS $DEBUG_CFLAGS $EMU_THR_DEFS $DEFS $WFLAGS",
+"$STATIC_CFLAGS $CFLAGS $DEBUG_CFLAGS $EMU_THR_DEFS $DEFS $WERRORFLAGS $WFLAGS",
[The only reason ERTS_EMU_CMDLINE_FLAGS exists is to force modification of config.h when the emulator command line flags are modified by configure])
dnl ----------------------------------------------------------------------
@@ -4520,6 +4568,10 @@ AH_BOTTOM([
#endif
])
+if test "x$GCC" = xyes; then
+ CFLAGS="$WERRORFLAGS $CFLAGS"
+fi
+
dnl ----------------------------------------------------------------------
dnl Output the result.
dnl ----------------------------------------------------------------------
diff --git a/erts/doc/src/Makefile b/erts/doc/src/Makefile
index 91e823fdb1..89d7c85a86 100644
--- a/erts/doc/src/Makefile
+++ b/erts/doc/src/Makefile
@@ -77,6 +77,7 @@ XML_CHAPTER_FILES = \
inet_cfg.xml \
erl_ext_dist.xml \
erl_dist_protocol.xml \
+ communication.xml \
notes.xml \
notes_history.xml
diff --git a/erts/doc/src/communication.xml b/erts/doc/src/communication.xml
new file mode 100644
index 0000000000..6049123f6a
--- /dev/null
+++ b/erts/doc/src/communication.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2012</year><year>2012</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Communication in Erlang</title>
+ <prepared>Rickard Green</prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date>2012-12-03</date>
+ <rev>PA1</rev>
+ <file>communication.xml</file>
+ </header>
+ <p>Communication in Erlang is conceptually performed using
+ asynchronous signaling. All different executing entities
+ such as processes, and ports communicate via asynchronous
+ signals. The most commonly used signal is a message. Other
+ common signals are exit, link, unlink, monitor, demonitor
+ signals.</p>
+ <section>
+ <title>Passing of Signals</title>
+ <p>The amount of time that passes between a signal being sent
+ and the arrival of the signal at the destination is unspecified
+ but positive. If the receiver has terminated, the signal will
+ not arrive, but it is possible that it triggers another signal.
+ For example, a link signal sent to a non-existing process will
+ trigger an exit signal which will be sent back to where the link
+ signal originated from. When communicating over the distribution,
+ signals may be lost if the distribution channel goes down.</p>
+ <p>The only signal ordering guarantee given is the following. If
+ an entity sends multiple signals to the same destination entity,
+ the order will be preserved. That is, if <c>A</c> send
+ a signal <c>S1</c> to <c>B</c>, and later sends
+ the signal <c>S2</c> to <c>B</c>, <c>S1</c> is guaranteed not to
+ arrive after <c>S2</c>.</p>
+ </section>
+ <section>
+ <title>Synchronous Communication</title>
+ <p>Some communication is synchronous. If broken down into pieces,
+ a synchronous communication operation, consists of two asynchronous
+ signals. One request signal and one reply signal. An example of
+ such a synchronous communication is a call to <c>process_info/2</c>
+ when the first argument is not <c>self()</c>. The caller will send
+ an asynchronous signal requesting information, and will then
+ wait for the reply signal containing the requested information. When
+ the request signal reaches its destination the destination process
+ replies with the requested information.</p>
+ </section>
+ <section>
+ <title>Implementation</title>
+ <p>The implementation of different asynchronous signals in the
+ VM may vary over time, but the behavior will always respect this
+ concept of asynchronous signals being passed between entities
+ as described above.</p>
+ <p>By inspecting the implementation you might notice that some
+ specific signal actually gives a stricter guarantee than described
+ above. It is of vital importance that such knowledge about the
+ implementation is <em>not</em> used by Erlang code, since the
+ implementation might change at any time without prior notice.</p>
+ <p>Some example of major implementation changes:</p>
+ <list type="bulleted">
+ <item>As of ERTS version 5.5.2 exit signals to processes are truly
+ asynchronously delivered.</item>
+ <item>As of ERTS version 5.10 all signals from processes to ports
+ are truly asynchronously delivered.</item>
+ </list>
+ </section>
+</chapter>
+
diff --git a/erts/doc/src/driver_entry.xml b/erts/doc/src/driver_entry.xml
index a2efdf3ebc..c37138e7b1 100644
--- a/erts/doc/src/driver_entry.xml
+++ b/erts/doc/src/driver_entry.xml
@@ -4,7 +4,7 @@
<cref>
<header>
<copyright>
- <year>2001</year><year>2011</year>
+ <year>2001</year><year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -34,6 +34,29 @@
<lib>driver_entry</lib>
<libsummary>The driver-entry structure used by erlang drivers.</libsummary>
<description>
+ <marker id="WARNING"/>
+ <warning><p><em>Use this functionality with extreme care!</em></p>
+ <p>A driver callback is executed as a direct extension of the
+ native code of the VM. Execution is not made in a safe environment.
+ The VM can <em>not</em> provide the same services as provided when
+ executing Erlang code, such as preemptive scheduling or memory
+ protection. If the driver callback function doesn't behave well,
+ the whole VM will misbehave.</p>
+ <list>
+ <item><p>A driver callback that crash will crash the whole VM.</p></item>
+ <item><p>An erroneously implemented driver callback might cause
+ a VM internal state inconsistency which may cause a crash of the VM,
+ or miscellaneous misbehaviors of the VM at any point after the call
+ to the driver callback.</p></item>
+ <item><p>A driver callback that do
+ <seealso marker="erl_driver#lengthy_work">lengthy work</seealso>
+ before returning will degrade responsiveness of the VM,
+ and may cause miscellaneous strange behaviors. Such strange behaviors
+ include, but are not limited to, extreme memory usage, and bad load
+ balancing between schedulers. Strange behaviors that might occur due
+ to lengthy work may also vary between OTP releases.</p></item>
+ </list>
+ </warning>
<p>
As of erts version 5.9 (OTP release R15B) the driver interface
has been changed with larger types for the callbacks
@@ -377,11 +400,11 @@ typedef struct erl_drv_entry {
<tag><marker id="driver_flags"/>int driver_flags</tag>
<item>
- <p>This field is used to pass driver capability information to the
- runtime system. If the <c>extended_marker</c> field equals
- <c>ERL_DRV_EXTENDED_MARKER</c>, it should contain <c>0</c> or
- driver flags (<c>ERL_DRV_FLAG_*</c>) ored bitwise. Currently
- the following driver flags exist:
+ <p>This field is used to pass driver capability and other
+ information to the runtime system. If the
+ <c>extended_marker</c> field equals <c>ERL_DRV_EXTENDED_MARKER</c>,
+ it should contain <c>0</c> or driver flags (<c>ERL_DRV_FLAG_*</c>)
+ ored bitwise. Currently the following driver flags exist:
</p>
<taglist>
<tag><c>ERL_DRV_FLAG_USE_PORT_LOCKING</c></tag>
@@ -404,6 +427,12 @@ typedef struct erl_drv_entry {
by the Erlang distribution (the behaviour has always been
required by drivers used by the distribution).
</item>
+ <tag><c>ERL_DRV_FLAG_NO_BUSY_MSGQ</c></tag>
+ <item>Disable busy port message queue functionality. For
+ more information, see the documentation of the
+ <seealso marker="erl_driver#erl_drv_busy_msgq_limits">erl_drv_busy_msgq_limits()</seealso>
+ function.
+ </item>
</taglist>
</item>
<tag>void *handle2</tag>
diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml
index 93d1289e8d..99f2466d79 100644
--- a/erts/doc/src/erl.xml
+++ b/erts/doc/src/erl.xml
@@ -582,13 +582,71 @@
<seealso marker="erts_alloc">erts_alloc(3)</seealso> for
further information.</p>
</item>
+ <tag><c><![CDATA[+n Behavior]]></c></tag>
+ <item>
+ <p>Control behavior of signals to ports.</p>
+ <p>As of OTP-R16 signals to ports are truly asynchronously
+ delivered. Note that signals always have been documented as
+ asynchronous. The underlying implementation has, however,
+ previously delivered these signals synchronously. Correctly
+ written Erlang programs should be able to handle this without
+ any issues. Bugs in existing Erlang programs that make false
+ assumptions about signals to ports may, however, be tricky to
+ find. This switch has been introduced in order to at least
+ make it easier to compare behaviors during a transition period.
+ Note that <em>this flag is deprecated</em> as of its
+ introduction, and is scheduled for removal in OTP-R17.
+ <c>Behavior</c> should be one of the following characters:</p>
+ <taglist>
+ <tag><c>d</c></tag>
+ <item>The default. Asynchronous signals. A process that sends
+ a signal to a port may continue execution before the signal
+ has been delivered to the port.</item>
+ <tag><c>s</c></tag>
+ <item>Synchronous signals. A processes that sends a signal
+ to a port will not continue execution until the signal has
+ been delivered. Should <em>only</em> be used for testing and
+ debugging.</item>
+ <tag><c>a</c></tag>
+ <item>Asynchronous signals. As the default, but a processes
+ that sends a signal will even more frequently continue
+ execution before the signal has been delivered to the
+ port. Should <em>only</em> be used for testing and
+ debugging.</item>
+ </taglist>
+ </item>
<tag><marker id="max_processes"><c><![CDATA[+P Number]]></c></marker></tag>
<item>
- <p>Sets the maximum number of concurrent processes for this
- system. <c><![CDATA[Number]]></c> must be in the range 16..134217727.
- Default is 32768.</p>
- <p><em>NOTE</em>: It is possible to choose any value in the range
- but powers of 2 perform best.</p>
+ <p>Sets the maximum number of simultaneously existing processes for this
+ system. Valid range for <c>Number</c> is <c>[1024-134217727]</c></p>
+ <p><em>NOTE</em>: The actual maximum chosen may be much larger than
+ the <c>Number</c> passed. Currently the runtime system often,
+ but not always, chooses a value that is a power of 2. This might,
+ however, be changed in the future. The actual value chosen can be
+ checked by calling
+ <seealso marker="erlang#system_info_process_limit">erlang:system_info(process_limit)</seealso>.</p>
+ <p>The default value is <c>262144</c></p>
+ </item>
+ <tag><marker id="max_ports"><c><![CDATA[+Q Number]]></c></marker></tag>
+ <item>
+ <p>Sets the maximum number of simultaneously existing ports for this
+ system. Valid range for <c>Number</c> is <c>[1024-134217727]</c></p>
+ <p><em>NOTE</em>: The actual maximum chosen may be much larger than
+ the actual <c>Number</c> passed. Currently the runtime system often,
+ but not always, chooses a value that is a power of 2. This might,
+ however, be changed in the future. The actual value chosen can be
+ checked by calling
+ <seealso marker="erlang#system_info_port_limit">erlang:system_info(port_limit)</seealso>.</p>
+ <p>The default value used is normally <c>65536</c>. However, if
+ the runtime system is able to determine maximum amount of file
+ descriptors that it is allowed to open and this value is larger
+ than <c>65536</c>, the chosen value will increased to a value
+ larger or equal to the maximum amount of file descriptors that
+ can be opened.</p>
+ <p>Previously the environment variable <c>ERL_MAX_PORTS</c> was used
+ for setting the maximum number of simultaneously existing ports. This
+ environment variable is deprecated, and scheduled for removal in
+ OTP-R17, but can still be used.</p>
</item>
<tag><marker id="compat_rel"><c><![CDATA[+R ReleaseNumber]]></c></marker></tag>
<item>
@@ -597,21 +655,14 @@
default. This flags sets the emulator in compatibility mode
with an earlier Erlang/OTP release <c><![CDATA[ReleaseNumber]]></c>.
The release number must be in the range
- <c><![CDATA[7..<current release>]]></c>. This limits the emulator,
- making it possible for it to communicate with Erlang nodes
- (as well as C- and Java nodes) running that earlier release.</p>
- <p>For example, an R10 node is not automatically compatible
- with an R9 node, but R10 nodes started with the <c><![CDATA[+R 9]]></c>
- flag can co-exist with R9 nodes in the same distributed
- Erlang system, they are R9-compatible.</p>
+ <c><![CDATA[<current release>-2..<current release>]]></c>. This
+ limits the emulator, making it possible for it to communicate
+ with Erlang nodes (as well as C- and Java nodes) running that
+ earlier release.</p>
<p>Note: Make sure all nodes (Erlang-, C-, and Java nodes) of
a distributed Erlang system is of the same Erlang/OTP release,
or from two different Erlang/OTP releases X and Y, where
<em>all</em> Y nodes have compatibility mode X.</p>
- <p>For example: A distributed Erlang system can consist of
- R10 nodes, or of R9 nodes and R9-compatible R10 nodes, but
- not of R9 nodes, R9-compatible R10 nodes and "regular" R10
- nodes, as R9 and "regular" R10 nodes are not compatible.</p>
</item>
<tag><c><![CDATA[+r]]></c></tag>
<item>
@@ -934,6 +985,22 @@
without prior notice.
</p>
</item>
+ <tag><marker id="+spp"><c>+spp Bool</c></marker></tag>
+ <item>
+ <p>Set default scheduler hint for port parallelism. If set to
+ <c>true</c>, the VM will schedule port tasks when it by this can
+ improve the parallelism in the system. If set to <c>false</c>,
+ the VM will try to perform port tasks immediately and by this
+ improve latency at the expense of parallelism. If this
+ flag has not been passed, the default scheduler hint for port
+ parallelism is currently <c>false</c>. The default used can be
+ inspected in runtime by calling
+ <seealso marker="erlang#system_info_port_parallelism">erlang:system_info(port_parallelism)</seealso>.
+ The default can be overriden on port creation by passing the
+ <seealso marker="erlang#open_port_parallelism">parallelism</seealso>
+ option to
+ <seealso marker="erlang#open_port/2">open_port/2</seealso></p>.
+ </item>
<tag><marker id="sched_thread_stack_size"><c><![CDATA[+sss size]]></c></marker></tag>
<item>
<p>Suggested stack size, in kilowords, for scheduler threads.
@@ -1042,8 +1109,39 @@
the emulator will be allowed to spend writing a crash dump. When
the given number of seconds have elapsed, the emulator will be
terminated by a SIGALRM signal.</p>
- </item>
- <tag><c><![CDATA[ERL_AFLAGS]]></c></tag>
+
+ <p> If the environment variable is <em>not</em> set or it is set to zero seconds, <c><![CDATA[ERL_CRASH_DUMP_SECONDS=0]]></c>,
+ the runtime system will not even attempt to write the crash dump file. It will just terminate.
+ </p>
+ <p> If the environment variable is set to negative valie, e.g. <c><![CDATA[ERL_CRASH_DUMP_SECONDS=-1]]></c>,
+ the runtime system will wait indefinitely for the crash dump file to be written.
+ </p>
+ <p> This environment variable is used in conjuction with
+ <seealso marker="kernel:heart"><c>heart</c></seealso> if <c>heart</c> is running:
+ </p>
+ <taglist>
+ <tag><c><![CDATA[ERL_CRASH_DUMP_SECONDS=0]]></c></tag>
+ <item><p>
+ Suppresses the writing a crash dump file entirely,
+ thus rebooting the runtime system immediately.
+ This is the same as not setting the environment variable.
+ </p>
+ </item>
+ <tag><c><![CDATA[ERL_CRASH_DUMP_SECONDS=-1]]></c></tag>
+ <item><p>Setting the environment variable to a negative value will cause the
+ termination of the runtime system to wait until the crash dump file
+ has been completly written.
+ </p>
+ </item>
+ <tag><c><![CDATA[ERL_CRASH_DUMP_SECONDS=S]]></c></tag>
+ <item><p>
+ Will wait for <c>S</c> seconds to complete the crash dump file and
+ then terminate the runtime system.
+ </p>
+ </item>
+ </taglist>
+ </item>
+ <tag><marker id="ERL_AFLAGS"><c><![CDATA[ERL_AFLAGS]]></c></marker></tag>
<item>
<p>The content of this environment variable will be added to the
beginning of the command line for <c><![CDATA[erl]]></c>.</p>
@@ -1053,7 +1151,7 @@
the <c><![CDATA[-extra]]></c> section, i.e. the end of the command line
following after an <c><![CDATA[-extra]]></c> flag.</p>
</item>
- <tag><c><![CDATA[ERL_ZFLAGS]]></c> and <c><![CDATA[ERL_FLAGS]]></c></tag>
+ <tag><marker id="ERL_ZFLAGS"><c><![CDATA[ERL_ZFLAGS]]></c></marker> and <marker id="ERL_FLAGS"><c><![CDATA[ERL_FLAGS]]></c></marker></tag>
<item>
<p>The content of these environment variables will be added to the
end of the command line for <c><![CDATA[erl]]></c>.</p>
diff --git a/erts/doc/src/erl_driver.xml b/erts/doc/src/erl_driver.xml
index 187c263b60..13f42a74a7 100644
--- a/erts/doc/src/erl_driver.xml
+++ b/erts/doc/src/erl_driver.xml
@@ -34,6 +34,32 @@
<lib>erl_driver</lib>
<libsummary>API functions for an Erlang driver</libsummary>
<description>
+ <p>An Erlang driver is a library containing a set of native driver
+ callback functions that the Erlang VM calls when certain
+ events occur. There may be multiple instances of a driver, each
+ instance is associated with an Erlang port.</p>
+ <marker id="WARNING"/>
+ <warning><p><em>Use this functionality with extreme care!</em></p>
+ <p>A driver callback is executed as a direct extension of the
+ native code of the VM. Execution is not made in a safe environment.
+ The VM can <em>not</em> provide the same services as provided when
+ executing Erlang code, such as preemptive scheduling or memory
+ protection. If the driver callback function doesn't behave well,
+ the whole VM will misbehave.</p>
+ <list>
+ <item><p>A driver callback that crash will crash the whole VM.</p></item>
+ <item><p>An erroneously implemented driver callback might cause
+ a VM internal state inconsistency which may cause a crash of the VM,
+ or miscellaneous misbehaviors of the VM at any point after the call
+ to the driver callback.</p></item>
+ <item><p>A driver callback that do <seealso marker="#lengthy_work">lengthy
+ work</seealso> before returning will degrade responsiveness of the VM,
+ and may cause miscellaneous strange behaviors. Such strange behaviors
+ include, but are not limited to, extreme memory usage, and bad load
+ balancing between schedulers. Strange behaviors that might occur due
+ to lengthy work may also vary between OTP releases.</p></item>
+ </list>
+ </warning>
<p>As of erts version 5.5.3 the driver interface has been extended
(see <seealso marker="driver_entry#extended_marker">extended marker</seealso>).
The extended interface introduce
@@ -53,16 +79,12 @@
<p>The driver calls back to the emulator, using the API
functions declared in <c>erl_driver.h</c>. They are used for
outputting data from the driver, using timers, etc.</p>
- <p>A driver is a library with a set of function that the emulator
- calls, in response to Erlang functions and message
- sending. There may be multiple instances of a driver, each
- instance is connected to an Erlang port. Every port has a port
- owner process. Communication with the port is normally done
- through the port owner process.</p>
- <p>Most of the functions take the <c>port</c> handle as an
- argument. This identifies the driver instance. Note that this
- port handle must be stored by the driver, it is not given when
- the driver is called from the emulator (see
+ <p>Each driver instance is associated with a port. Every port
+ has a port owner process. Communication with the port is normally
+ done through the port owner process. Most of the functions take
+ the <c>port</c> handle as an argument. This identifies the driver
+ instance. Note that this port handle must be stored by the driver,
+ it is not given when the driver is called from the emulator (see
<seealso marker="driver_entry#emulator">driver_entry</seealso>).</p>
<p>Some of the functions take a parameter of type
<c>ErlDrvBinary</c>, a driver binary. It should be both
@@ -123,12 +145,35 @@
different threads. This, however, is not a problem for any
function in this API, since the emulator has control over
these threads.</p>
- <note>
- <p>Functions not explicitly documented as thread-safe are
- <em>not</em> thread-safe. Also note that some functions
+ <warning>
+ <p>Functions not explicitly documented as thread safe are
+ <em>not</em> thread safe. Also note that some functions
are <em>only</em> thread safe when used in a runtime
system with SMP support.</p>
- </note>
+ <p>A function not explicitly documented as thread safe may at
+ some point in time have a thread safe implementation in the
+ runtime system. Such an implementation may however change to
+ a thread <em>unsafe</em> implementation at any time <em>without
+ any notice</em> at all.
+ </p>
+ <p><em>Only use functions explicitly documented as thread safe
+ from arbitrary threads.</em></p>
+ </warning>
+ <p><marker id="lengthy_work"/>
+ As mentioned in the <seealso marker="#WARNING">warning</seealso> text at
+ the beginning of this document it is of vital importance that a driver callback
+ does return relatively fast. It is hard to give an exact maximum amount
+ of time that a driver callback is allowed to work, but as a rule of thumb
+ a well behaving driver callback should return before a millisecond has
+ passed. This can be achieved using different approaches.
+ If you have full control over the code that are to execute in the driver
+ callback, the best approach is to divide the work into multiple chunks of
+ work and trigger multiple calls to the
+ <seealso marker="driver_entry#timeout">timeout callback</seealso> using
+ zero timeouts. This might, however, not always be possible, e.g. when
+ calling third party libraries. In this case you typically want to dispatch
+ the work to another thread. Information about thread primitives can be
+ found below.</p>
</description>
<section>
@@ -1492,16 +1537,81 @@ typedef struct ErlIOVec {
</desc>
</func>
<func>
+ <name><ret>void</ret><nametext>erl_drv_busy_msgq_limits(ErlDrvPort port, ErlDrvSizeT *low, ErlDrvSizeT *high)</nametext></name>
+ <fsummary>Set and get limits for busy port message queue</fsummary>
+ <desc>
+ <marker id="erl_drv_busy_msgq_limits"></marker>
+ <p>Sets and gets limits that will be used for controling the
+ busy state of the port message queue.</p>
+ <p>The port message queue will be set into a busy
+ state when the amount of command data queued on the
+ message queue reaches the <c>high</c> limit. The port
+ message queue will be set into a not busy state when the
+ amount of command data queued on the message queue falls
+ below the <c>low</c> limit. Command data is in this
+ context data passed to the port using either
+ <c>Port ! {Owner, {command, Data}}</c>, or
+ <c>port_command/[2,3]</c>. Note that these limits
+ only concerns command data that have not yet reached the
+ port. The <seealso marker="#set_busy_port">busy port</seealso>
+ feature can be used for data that has reached the port.</p>
+
+ <p>Valid limits are values in the range
+ <c>[ERL_DRV_BUSY_MSGQ_LIM_MIN, ERL_DRV_BUSY_MSGQ_LIM_MAX]</c>.
+ Limits will be automatically adjusted to be sane. That is,
+ the system will adjust values so that the low limit used is
+ lower or equal to the high limit used. By default the high
+ limit will be 8 kB and the low limit will be 4 kB.</p>
+
+ <p>By passing a pointer to an integer variable containing
+ the value <c>ERL_DRV_BUSY_MSGQ_READ_ONLY</c>, currently used
+ limit will be read and written back to the integer variable.
+ A new limit can be set by passing a pointer to an integer
+ variable containing a valid limit. The passed value will be
+ written to the internal limit. The internal limit will then
+ be adjusted. After this the adjusted limit will be written
+ back to the integer variable from which the new value was
+ read. Values are in bytes.</p>
+
+ <p>The busy message queue feature can be disabled either
+ by setting the <c>ERL_DRV_FLAG_NO_BUSY_MSGQ</c>
+ <seealso marker="driver_entry#driver_flags">driver flag</seealso>
+ in the <seealso marker="driver_entry">driver_entry</seealso>
+ used by the driver, or by calling this function with
+ <c>ERL_DRV_BUSY_MSGQ_DISABLED</c> as a limit (either low or
+ high). When this feature has been disabled it cannot be
+ enabled again. When reading the limits both of them
+ will be <c>ERL_DRV_BUSY_MSGQ_DISABLED</c>, if this
+ feature has been disabled.</p>
+
+ <p>Processes sending command data to the port will be suspended
+ if either the port is busy or if the port message queue is
+ busy. Suspended processes will be resumed when neither the
+ port is busy, nor the port message queue is busy.</p>
+
+ <p>For information about busy port functionality
+ see the documentation of the
+ <seealso marker="#set_busy_port">set_busy_port()</seealso>
+ function.</p>
+ </desc>
+ </func>
+ <func>
<name><ret>void</ret><nametext>set_busy_port(ErlDrvPort port, int on)</nametext></name>
<fsummary>Signal or unsignal port as busy</fsummary>
<desc>
<marker id="set_busy_port"></marker>
- <p>This function set and resets the busy status of the port. If
- <c>on</c> is 1, the port is set to busy, if it's 0 the port
- is set to not busy.</p>
- <p>When the port is busy, sending to it with <c>Port ! Data</c>
- or <c>port_command/2</c>, will block the port owner process,
- until the port is signaled as not busy.</p>
+ <p>This function set and unset the busy state of the port. If
+ <c>on</c> is non-zero, the port is set to busy, if it's zero the port
+ is set to not busy. You typically want to combine
+ this feature with the <seealso marker="#erl_drv_busy_msgq_limits">busy
+ port message queue</seealso> functionality.</p>
+ <p>Processes sending command data to the port will be suspended
+ if either the port is busy or if the port message queue
+ is busy. Suspended processes will be resumed when neither the
+ port is busy, nor the port message queue is busy. Command data
+ is in this context data passed to the port using either
+ <c>Port ! {Owner, {command, Data}}</c>, or
+ <c>port_command/[2,3]</c>.</p>
<p>If the
<seealso marker="driver_entry#driver_flags"><![CDATA[ERL_DRV_FLAG_SOFT_BUSY]]></seealso>
has been set in the
@@ -1510,6 +1620,10 @@ typedef struct ErlIOVec {
<seealso marker="erlang#port_command/3">port_command(Port, Data, [force])</seealso>
even though the driver has signaled that it is busy.
</p>
+ <p>For information about busy port message queue functionality
+ see the documentation of the
+ <seealso marker="#erl_drv_busy_msgq_limits">erl_drv_busy_msgq_limits()</seealso>
+ function.</p>
</desc>
</func>
<func>
@@ -1570,6 +1684,8 @@ typedef struct ErlIOVec {
<desc>
<marker id="driver_connected"></marker>
<p>This function returns the port owner process.</p>
+ <p>Note that this function is <em>not</em> thread-safe, not
+ even when the emulator with SMP support is used.</p>
</desc>
</func>
<func>
@@ -1597,22 +1713,32 @@ typedef struct ErlIOVec {
<tag><seealso marker="driver_entry#call">call</seealso></tag>
<item>Called from <c>erlang:port_call/3</c></item>
</taglist>
+ <p>Note that this function is <em>not</em> thread-safe, not
+ even when the emulator with SMP support is used.</p>
</desc>
</func>
<func>
- <name><ret>int</ret><nametext>driver_output_term(ErlDrvPort port, ErlDrvTermData* term, int n)</nametext></name>
+ <name><ret>int</ret><nametext>erl_drv_output_term(ErlDrvTermData port, ErlDrvTermData* term, int n)</nametext></name>
<fsummary>Send term data from driver to port owner</fsummary>
<desc>
- <marker id="driver_output_term"></marker>
+ <marker id="erl_drv_output_term"></marker>
<p>This functions sends data in the special driver term
- format. This is a fast way to deliver term data from a
- driver. It also needs no binary conversion, so the port
- owner process receives data as normal Erlang terms.</p>
+ format to the port owner process. This is a fast way to
+ deliver term data from a driver. It also needs no binary
+ conversion, so the port owner process receives data as
+ normal Erlang terms. The
+ <seealso marker="#erl_drv_send_term">erl_drv_send_term()</seealso>
+ functions can be used for sending to any arbitrary process
+ on the local node.</p>
+ <note><p>Note that the <c>port</c> parameter is <em>not</em>
+ an ordinary port handle, but a port handle converted using
+ <c>driver_mk_port()</c>.</p></note>
<p>The <c>term</c> parameter points to an array of
<c>ErlDrvTermData</c>, with <c>n</c> elements. This array
contains terms described in the driver term format. Every
term consists of one to four elements in the array. The
- term first has a term type, and then arguments.</p>
+ term first has a term type, and then arguments. The
+ <c>port</c> parameter specifies the sending port.</p>
<p>Tuple and lists (with the exception of strings, see below),
are built in reverse polish notation, so that to build a
tuple, the elements are given first, and then the tuple
@@ -1664,17 +1790,17 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len
ErlDrvPort port = ...
ErlDrvTermData spec[] = {
ERL_DRV_ATOM, driver_mk_atom("tcp"),
- ERL_DRV_PORT, driver_mk_port(port),
+ ERL_DRV_PORT, driver_mk_port(drvport),
ERL_DRV_INT, 100,
ERL_DRV_BINARY, bin, 50, 0,
ERL_DRV_LIST, 2,
ERL_DRV_TUPLE, 3,
};
- driver_output_term(port, spec, sizeof(spec) / sizeof(spec[0]));
+ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0]));
]]>
</code>
<p>Where <c>bin</c> is a driver binary of length at least 50
- and <c>port</c> is a port handle. Note that the <c>ERL_DRV_LIST</c>
+ and <c>drvport</c> is a port handle. Note that the <c>ERL_DRV_LIST</c>
comes after the elements of the list, likewise the
<c>ERL_DRV_TUPLE</c>.</p>
<p>The term <c>ERL_DRV_STRING_CONS</c> is a way to construct
@@ -1695,7 +1821,7 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len
ERL_DRV_NIL,
ERL_DRV_LIST, 4
};
- driver_output_term(port, spec, sizeof(spec) / sizeof(spec[0]));
+ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0]));
]]></code>
<p></p>
<code type="none"><![CDATA[
@@ -1705,7 +1831,7 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len
ERL_DRV_STRING_CONS, (ErlDrvTermData)"123", 3,
ERL_DRV_STRING_CONS, (ErlDrvTermData)"abc", 3,
};
- driver_output_term(port, spec, sizeof(spec) / sizeof(spec[0]));
+ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0]));
]]></code>
<p>The <c>ERL_DRV_EXT2TERM</c> term type is used for passing a
term encoded with the
@@ -1725,7 +1851,7 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len
ERL_DRV_EXT2TERM, (ErlDrvTermData) binp->orig_bytes, binp->orig_size
ERL_DRV_TUPLE, 2,
};
- driver_output_term(port, spec, sizeof(spec) / sizeof(spec[0]));
+ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0]));
]]></code>
<p>If you want to pass a binary and don't already have the content
of the binary in an <c>ErlDrvBinary</c>, you can benefit from using
@@ -1741,6 +1867,22 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len
<c>ERL_DRV_EXT2TERM</c> term types were introduced in the 5.6
version of erts.
</p>
+ <p>This function is only thread-safe when the emulator with SMP
+ support is used.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>driver_output_term(ErlDrvPort port, ErlDrvTermData* term, int n)</nametext></name>
+ <fsummary>Send term data from driver to port owner</fsummary>
+ <desc>
+ <marker id="driver_output_term"></marker>
+ <warning><p><c>driver_output_term()</c> is deferred and will
+ be removed in the OTP-R17 release. Use
+ <seealso marker="#erl_drv_send_term">erl_drv_output_term()</seealso>
+ instead.</p>
+ </warning>
+ <p>The parameters <c>term</c> and <c>n</c> do the same thing
+ as in <seealso marker="#erl_drv_output_term">erl_drv_output_term()</seealso>.</p>
<p>Note that this function is <em>not</em> thread-safe, not
even when the emulator with SMP support is used.</p>
</desc>
@@ -1754,6 +1896,8 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len
<c>string</c>. The atom is created and won't change, so the
return value may be saved and reused, which is faster than
looking up the atom several times.</p>
+ <p>Note that this function is <em>not</em> thread-safe, not
+ even when the emulator with SMP support is used.</p>
</desc>
</func>
<func>
@@ -1762,20 +1906,46 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len
<desc>
<marker id="driver_mk_port"></marker>
<p>This function converts a port handle to the erlang term
- format, usable in the <c>driver_output_send</c> function.</p>
+ format, usable in the <seealso marker="#erl_drv_output_term">erl_drv_output_term()</seealso>, and <seealso marker="#erl_drv_send_term">erl_drv_send_term()</seealso> functions.</p>
+ <p>Note that this function is <em>not</em> thread-safe, not
+ even when the emulator with SMP support is used.</p>
</desc>
</func>
<func>
- <name><ret>int</ret><nametext>driver_send_term(ErlDrvPort port, ErlDrvTermData receiver, ErlDrvTermData* term, int n)</nametext></name>
+ <name><ret>int</ret><nametext>erl_drv_send_term(ErlDrvTermData port, ErlDrvTermData receiver, ErlDrvTermData* term, int n)</nametext></name>
<fsummary>Send term data to other process than port owner process</fsummary>
<desc>
- <marker id="driver_send_term"></marker>
+ <marker id="erl_drv_send_term"></marker>
<p>This function is the only way for a driver to send data to
<em>other</em> processes than the port owner process. The
<c>receiver</c> parameter specifies the process to receive
the data.</p>
+ <note><p>Note that the <c>port</c> parameter is <em>not</em>
+ an ordinary port handle, but a port handle converted using
+ <c>driver_mk_port()</c>.</p></note>
+ <p>The parameters <c>port</c>, <c>term</c> and <c>n</c> do the same thing
+ as in <seealso marker="#erl_drv_output_term">erl_drv_output_term()</seealso>.</p>
+ <p>This function is only thread-safe when the emulator with SMP
+ support is used.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>driver_send_term(ErlDrvPort port, ErlDrvTermData receiver, ErlDrvTermData* term, int n)</nametext></name>
+ <fsummary>Send term data to other process than port owner process</fsummary>
+ <desc>
+ <marker id="driver_send_term"></marker>
+ <warning><p><c>driver_send_term()</c> is deferred and will
+ be removed in the OTP-R17 release. Use
+ <seealso marker="#erl_drv_send_term">erl_drv_send_term()</seealso>
+ instead.</p>
+ <p>Also note that parameters of <c>driver_send_term()</c>
+ cannot be properly checked by the runtime system when
+ executed by arbitrary threads. This may cause the
+ <c>driver_send_term()</c> function not to fail when
+ it should.</p>
+ </warning>
<p>The parameters <c>term</c> and <c>n</c> do the same thing
- as in <seealso marker="#driver_output_term">driver_output_term</seealso>.</p>
+ as in <seealso marker="#erl_drv_output_term">erl_drv_output_term()</seealso>.</p>
<p>This function is only thread-safe when the emulator with SMP
support is used.</p>
</desc>
diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml
index f484e9eaf7..f00f7b9f46 100644
--- a/erts/doc/src/erl_nif.xml
+++ b/erts/doc/src/erl_nif.xml
@@ -34,30 +34,6 @@
<lib>erl_nif</lib>
<libsummary>API functions for an Erlang NIF library</libsummary>
<description>
- <note><p>The NIF concept is officially supported from R14B. NIF source code
- written for earlier experimental versions might need adaption to run on R14B.</p>
- <p>No incompatible changes between <em>R14B</em> and R14A.</p>
- <p>Incompatible changes between <em>R14A</em> and R13B04:</p>
- <list>
- <item>Environment argument removed for <c>enif_alloc</c>,
- <c>enif_realloc</c>, <c>enif_free</c>, <c>enif_alloc_binary</c>,
- <c>enif_realloc_binary</c>, <c>enif_release_binary</c>,
- <c>enif_alloc_resource</c>, <c>enif_release_resource</c>,
- <c>enif_is_identical</c> and <c>enif_compare</c>.</item>
- <item>Character encoding argument added to <c>enif_get_atom</c>
- and <c>enif_make_existing_atom</c>.</item>
- <item>Module argument added to <c>enif_open_resource_type</c>
- while changing name spaces of resource types from global to module local.</item>
- </list>
- <p>Incompatible changes between <em>R13B04</em> and R13B03:</p>
- <list>
- <item>The function prototypes of the NIFs have changed to expect <c>argc</c> and <c>argv</c>
- arguments. The arity of a NIF is by that no longer limited to 3.</item>
- <item><c>enif_get_data</c> renamed as <c>enif_priv_data</c>.</item>
- <item><c>enif_make_string</c> got a third argument for character encoding.</item>
- </list>
- </note>
-
<p>A NIF library contains native implementation of some functions
of an Erlang module. The native implemented functions (NIFs) are
called like any other functions without any difference to the
@@ -67,6 +43,57 @@
is to throw an exception. But it can also be used as a fallback
implementation if the NIF library is not implemented for some
architecture.</p>
+ <marker id="WARNING"/>
+ <warning><p><em>Use this functionality with extreme care!</em></p>
+ <p>A native function is executed as a direct extension of the
+ native code of the VM. Execution is not made in a safe environment.
+ The VM can <em>not</em> provide the same services as provided when
+ executing Erlang code, such as preemptive scheduling or memory
+ protection. If the native function doesn't behave well, the whole
+ VM will misbehave.</p>
+ <list>
+ <item><p>A native function that crash will crash the whole VM.</p></item>
+ <item><p>An erroneously implemented native function might cause
+ a VM internal state inconsistency which may cause a crash of the VM,
+ or miscellaneous misbehaviors of the VM at any point after the call
+ to the native function.</p></item>
+ <item><p>A native function that do <seealso marker="#lengthy_work">lengthy
+ work</seealso> before returning will degrade responsiveness of the VM,
+ and may cause miscellaneous strange behaviors. Such strange behaviors
+ include, but are not limited to, extreme memory usage, and bad load
+ balancing between schedulers. Strange behaviors that might occur due
+ to lengthy work may also vary between OTP releases.</p></item>
+ </list>
+ </warning>
+
+ <p>The NIF concept is officially supported from R14B. NIF source code
+ written for earlier experimental versions might need adaption to run on R14B
+ or later versions:</p>
+ <list>
+ <item>No incompatible changes between <em>R14B</em> and R14A.</item>
+ <item>Incompatible changes between <em>R14A</em> and R13B04:
+ <list>
+ <item>Environment argument removed for <c>enif_alloc</c>,
+ <c>enif_realloc</c>, <c>enif_free</c>, <c>enif_alloc_binary</c>,
+ <c>enif_realloc_binary</c>, <c>enif_release_binary</c>,
+ <c>enif_alloc_resource</c>, <c>enif_release_resource</c>,
+ <c>enif_is_identical</c> and <c>enif_compare</c>.</item>
+ <item>Character encoding argument added to <c>enif_get_atom</c>
+ and <c>enif_make_existing_atom</c>.</item>
+ <item>Module argument added to <c>enif_open_resource_type</c>
+ while changing name spaces of resource types from global to module local.</item>
+ </list>
+ </item>
+ <item>Incompatible changes between <em>R13B04</em> and R13B03:
+ <list>
+ <item>The function prototypes of the NIFs have changed to expect <c>argc</c> and <c>argv</c>
+ arguments. The arity of a NIF is by that no longer limited to 3.</item>
+ <item><c>enif_get_data</c> renamed as <c>enif_priv_data</c>.</item>
+ <item><c>enif_make_string</c> got a third argument for character encoding.</item>
+ </list>
+ </item>
+ </list>
+
<p>A minimal example of a NIF library can look like this:</p>
<p/>
<code type="none">
@@ -136,7 +163,23 @@ ok
then retrieved by calling <seealso marker="#enif_priv_data">enif_priv_data</seealso>.</p>
<p>There is no way to explicitly unload a NIF library. A library will be
automatically unloaded when the module code that it belongs to is purged
- by the code server.</p>
+ by the code server.</p>
+
+ <p><marker id="lengthy_work"/>
+ As mentioned in the <seealso marker="#WARNING">warning</seealso> text at
+ the beginning of this document it is of vital importance that a native function
+ does return relatively fast. It is hard to give an exact maximum amount
+ of time that a native function is allowed to work, but as a rule of thumb
+ a well behaving native function should return to its caller before a
+ millisecond has passed. This can be achieved using different approaches.
+ If you have full control over the code that are to execute in the native
+ function, the best approach is to divide the work into multiple chunks of
+ work and call the native function multiple times. This might, however,
+ not always be possible, e.g. when calling third party libraries. In this
+ case you typically want to dispatch the work to another thread, return
+ from the native function, and wait for the result. The thread can send
+ the result back to the calling thread using message passing. Information
+ about thread primitives can be found below.</p>
</description>
<section>
<title>FUNCTIONALITY</title>
@@ -266,10 +309,6 @@ ok
mutable.</p>
<p>The library initialization callbacks <c>load</c>, <c>reload</c> and
<c>upgrade</c> are all thread-safe even for shared state data.</p>
- <p>Avoid doing lengthy work in NIF calls as that may degrade the
- responsiveness of the VM. NIFs are called directly by the same scheduler
- thread that executed the calling Erlang code. The calling scheduler will thus
- be blocked from doing any other work until the NIF returns.</p>
</item>
</taglist>
</section>
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index ef0e6fea84..1d67be2e52 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -626,6 +626,22 @@ false</pre>
{more,6}</pre>
</desc>
</func>
+
+ <func>
+ <name name="delete_element" arity="2"/>
+ <fsummary>Delete element at index in a tuple</fsummary>
+ <type_desc variable="Index">1..tuple_size(<anno>Tuple1</anno>)</type_desc>
+ <desc>
+ <p>
+ Returns a new tuple with element at <c><anno>Index</anno></c> removed from
+ tuple <c><anno>Tuple1</anno></c>.
+ </p>
+ <pre>
+> <input>erlang:delete_element(2, {one, two, three}).</input>
+{one,three}</pre>
+ </desc>
+ </func>
+
<func>
<name name="delete_module" arity="1"/>
<fsummary>Make the current code for a module old</fsummary>
@@ -854,10 +870,10 @@ b</pre>
</func>
<func>
<name name="exit" arity="2"/>
- <fsummary>Send an exit signal to a process</fsummary>
+ <fsummary>Send an exit signal to a process or a port</fsummary>
<desc>
<p>Sends an exit signal with exit reason <c><anno>Reason</anno></c> to
- the process <c><anno>Pid</anno></c>.</p>
+ the process or port identified by <c><anno>Pid</anno></c>.</p>
<p>The following behavior apply if <c><anno>Reason</anno></c> is any term
except <c>normal</c> or <c>kill</c>:</p>
<p>If <c><anno>Pid</anno></c> is not trapping exits, <c><anno>Pid</anno></c> itself will
@@ -1361,6 +1377,24 @@ os_prompt% </pre>
when the process wakes up.</p>
</desc>
</func>
+
+ <func>
+ <name name="insert_element" arity="3"/>
+ <fsummary>Insert an element at index in a tuple</fsummary>
+ <type_desc variable="Index">1..tuple_size(<anno>Tuple1</anno>) + 1</type_desc>
+ <desc>
+ <p>
+ Returns a new tuple with element <c><anno>Term</anno></c> insert at position
+ <c><anno>Index</anno></c> in tuple <c><anno>Tuple1</anno></c>.
+ All elements from position <c><anno>Index</anno></c> and upwards are subsequently
+ pushed one step higher in the new tuple <c><anno>Tuple2</anno></c>.
+ </p>
+ <pre>
+> <input>erlang:insert_element(2, {one, two, three}, new).</input>
+{one,new,two,three}</pre>
+ </desc>
+ </func>
+
<func>
<name name="integer_to_list" arity="1"/>
<fsummary>Text representation of an integer</fsummary>
@@ -1497,13 +1531,6 @@ os_prompt% </pre>
applied with <c><anno>Arity</anno></c> number of arguments; otherwise
returns <c>false</c>.</p>
<p>Allowed in guard tests.</p>
- <warning>
- <p>Currently, <c>is_function/2</c> will also return
- <c>true</c> if the first argument is a tuple fun (a tuple
- containing two atoms). In a future release, tuple funs will
- no longer be supported and <c>is_function/2</c> will return
- <c>false</c> if given a tuple fun.</p>
- </warning>
</desc>
</func>
<func>
@@ -2767,6 +2794,18 @@ os_prompt% </pre>
console window when spawning the port program.
(This option has no effect on other platforms.)</p>
</item>
+ <tag><marker id="open_port_parallelism"><c>{parallelism, Boolean}</c></marker></tag>
+ <item>
+ <p>Set scheduler hint for port parallelism. If set to <c>true</c>,
+ the VM will schedule port tasks when it by this can improve the
+ parallelism in the system. If set to <c>false</c>, the VM will
+ try to perform port tasks immediately and by this improving the
+ latency at the expense of parallelism. The default can be set on
+ system startup by passing the
+ <seealso marker="erl#+spp">+spp</seealso> command line argument
+ to <seealso marker="erl">erl(1)</seealso>.
+ </p>
+ </item>
</taglist>
<p>The default is <c>stream</c> for all types of port and
<c>use_stdio</c> for spawned ports.</p>
@@ -2819,10 +2858,11 @@ os_prompt% </pre>
the owning process using signals of the form
<c>{'EXIT', Port, PosixCode}</c>. See <c>file(3)</c> for
possible values of <c>PosixCode</c>.</p>
- <p><marker id="ERL_MAX_PORTS"></marker>
- The maximum number of ports that can be open at the same
- time is 1024 by default, but can be configured by
- the environment variable <c>ERL_MAX_PORTS</c>.</p>
+ <p>The maximum number of ports that can be open at the same
+ time can be configured by passing the
+ <seealso marker="erl#max_ports"><c>+Q</c></seealso>
+ command line flag to
+ <seealso marker="erl"><c>erl(1)</c></seealso>.</p>
</desc>
</func>
<func>
@@ -2880,10 +2920,10 @@ os_prompt% </pre>
<desc>
<p>Closes an open port. Roughly the same as
<c><anno>Port</anno> ! {self(), close}</c> except for the error behaviour
- (see below), and that the port does <em>not</em> reply with
- <c>{Port, closed}</c>. Any process may close a port with
- <c>port_close/1</c>, not only the port owner (the connected
- process).</p>
+ (see below), being synchronous, and that the port does
+ <em>not</em> reply with <c>{Port, closed}</c>. Any process may
+ close a port with <c>port_close/1</c>, not only the port owner
+ (the connected process).</p>
<p>For comparison: <c><anno>Port</anno> ! {self(), close}</c> fails with
<c>badarg</c> if <c><anno>Port</anno></c> cannot be sent to (i.e.,
<c><anno>Port</anno></c> refers neither to a port nor to a process). If
@@ -2895,8 +2935,12 @@ os_prompt% </pre>
<p>Note that any process can close a port using
<c><anno>Port</anno> ! {PortOwner, close}</c> just as if it itself was
the port owner, but the reply always goes to the port owner.</p>
- <p>In short: <c>port_close(Port)</c> has a cleaner and more
- logical behaviour than <c><anno>Port</anno> ! {self(), close}</c>.</p>
+ <p>As of OTP-R16 <c><anno>Port</anno> ! {PortOwner, close}</c> is truly
+ asynchronous. Note that this operation has always been
+ documented as an asynchronous operation, while the underlying
+ implementation has been synchronous. <c>port_close/1</c> is
+ however still fully synchronous. This due to its error
+ behavior.</p>
<p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not an open port or
the registered name of an open port.</p>
</desc>
@@ -2906,11 +2950,11 @@ os_prompt% </pre>
<fsummary>Send data to a port</fsummary>
<desc>
<p>Sends data to a port. Same as
- <c><anno>Port</anno> ! {self(), {command, Data}}</c> except for the error
- behaviour (see below). Any process may send data to a port
- with <c>port_command/2</c>, not only the port owner
- (the connected process).</p>
- <p>For comparison: <c><anno>Port</anno> ! {self(), {command, Data}}</c>
+ <c><anno>Port</anno> ! {PortOwner, {command, Data}}</c> except for the error
+ behaviour and being synchronous (see below). Any process may
+ send data to a port with <c>port_command/2</c>, not only the
+ port owner (the connected process).</p>
+ <p>For comparison: <c><anno>Port</anno> ! {PortOwner, {command, Data}}</c>
fails with <c>badarg</c> if <c><anno>Port</anno></c> cannot be sent to
(i.e., <c><anno>Port</anno></c> refers neither to a port nor to a process).
If <c><anno>Port</anno></c> is a closed port the data message disappears
@@ -2921,11 +2965,14 @@ os_prompt% </pre>
<p>Note that any process can send to a port using
<c><anno>Port</anno> ! {PortOwner, {command, <anno>Data</anno>}}</c> just as if it
itself was the port owner.</p>
- <p>In short: <c>port_command(<anno>Port</anno>, <anno>Data</anno>)</c> has a cleaner and
- more logical behaviour than
- <c><anno>Port</anno> ! {self(), {command, Data}}</c>.</p>
<p>If the port is busy, the calling process will be suspended
until the port is not busy anymore.</p>
+ <p>As of OTP-R16 <c><anno>Port</anno> ! {PortOwner, {command, Data}}</c> is
+ truly asynchronous. Note that this operation has always been
+ documented as an asynchronous operation, while the underlying
+ implementation has been synchronous. <c>port_command/2</c> is
+ however still fully synchronous. This due to its error
+ behavior.</p>
<p>Failures:</p>
<taglist>
<tag><c>badarg</c></tag>
@@ -2999,7 +3046,7 @@ os_prompt% </pre>
<fsummary>Set the owner of a port</fsummary>
<desc>
<p>Sets the port owner (the connected port) to <c><anno>Pid</anno></c>.
- Roughly the same as <c><anno>Port</anno> ! {self(), {connect, <anno>Pid</anno>}}</c>
+ Roughly the same as <c><anno>Port</anno> ! {Owner, {connect, <anno>Pid</anno>}}</c>
except for the following:</p>
<list type="bulleted">
<item>
@@ -3010,6 +3057,9 @@ os_prompt% </pre>
<c>{Port,connected}</c>.</p>
</item>
<item>
+ <p><c>port_connect/1</c> is synchronous, see below.</p>
+ </item>
+ <item>
<p>The new port owner gets linked to the port.</p>
</item>
</list>
@@ -3033,11 +3083,14 @@ os_prompt% </pre>
<c><anno>Port</anno> ! {PortOwner, {connect, <anno>Pid</anno>}}</c> just as if it
itself was the port owner, but the reply always goes to
the port owner.</p>
- <p>In short: <c>port_connect(<anno>Port</anno>, <anno>Pid</anno>)</c> has a cleaner and
- more logical behaviour than
- <c><anno>Port</anno> ! {self(),{connect,<anno>Pid</anno>}}</c>.</p>
+ <p>As of OTP-R16 <c><anno>Port</anno> ! {PortOwner, {connect, <anno>Pid</anno>}}</c> is
+ truly asynchronous. Note that this operation has always been
+ documented as an asynchronous operation, while the underlying
+ implementation has been synchronous. <c>port_connect/2</c> is
+ however still fully synchronous. This due to its error
+ behavior.</p>
<p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not an open port
- or the registered name of an open port, or if <c><anno>Pid</anno></c> is
+ or the registered name of an open port, or if <c>Pid</c> is
not an existing local pid.</p>
</desc>
</func>
@@ -3084,71 +3137,187 @@ os_prompt% </pre>
</func>
<func>
<name name="port_info" arity="1"/>
- <type name="port_info_result_item"/>
<fsummary>Information about a port</fsummary>
<desc>
<p>Returns a list containing tuples with information about
the <c><anno>Port</anno></c>, or <c>undefined</c> if the port is not open.
The order of the tuples is not defined, nor are all the
tuples mandatory.</p>
- <taglist>
- <tag><c>{registered_name, <anno>RegName</anno>}</c></tag>
- <item>
- <p><c><anno>RegName</anno></c> (an atom) is the registered name of
- the port. If the port has no registered name, this tuple
- is not present in the list.</p>
- </item>
- <tag><c>{id, <anno>Index</anno>}</c></tag>
- <item>
- <p><c><anno>Index</anno></c> (an integer) is the internal index of the
- port. This index may be used to separate ports.</p>
- </item>
- <tag><c>{connected, <anno>Pid</anno>}</c></tag>
- <item>
- <p><c><anno>Pid</anno></c> is the process connected to the port.</p>
- </item>
- <tag><c>{links, <anno>Pids</anno>}</c></tag>
- <item>
- <p><c><anno>Pids</anno></c> is a list of pids to which processes the
- port is linked.</p>
- </item>
- <tag><c>{name, <anno>String</anno>}</c></tag>
- <item>
- <p><c><anno>String</anno></c> is the command name set by
- <c>open_port</c>.</p>
- </item>
- <tag><c>{input, <anno>Bytes</anno>}</c></tag>
- <item>
- <p><c><anno>Bytes</anno></c> is the total number of bytes read from
- the port.</p>
- </item>
- <tag><c>{output, <anno>Bytes</anno>}</c></tag>
- <item>
- <p><c><anno>Bytes</anno></c> is the total number of bytes written to
- the port.</p>
- </item>
- <tag><c>{os_pid, <anno>OsPid</anno> | undefined}</c></tag>
- <item>
- <p><c> <anno>OsPid</anno></c> is the process identifier (or equivalent) of an OS process created with <c>open_port({spawn | spawn_executable, Command}, Options)</c>. If the port is not the result of spawning an OS process, the value is <c>undefined</c>.</p>
- </item>
- </taglist>
- <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local port.</p>
+ <p>Currently the result will containt information about the
+ following <c>Item</c>s: <c>registered_name</c> (if the port has
+ a registered name), <c>id</c>, <c>connected</c>, <c>links</c>,
+ <c>name</c>, <c>input</c>, and <c>output</c>. For more information
+ about the different <c>Item</c>s, see
+ <seealso marker="#port_info/2">port_info/2</seealso>.</p>
+ <p>Failure: <c>badarg</c> if <c>Port</c> is not a local port
+ identifier, or an atom.</p>
</desc>
</func>
<func>
- <name name="port_info" arity="2"/>
- <type name="port_info_item"/>
- <type name="port_info_result_item"/>
- <fsummary>Information about a port</fsummary>
+ <name name="port_info" arity="2" clause_i="1"/>
+ <fsummary>Information about the connected process of a port</fsummary>
<desc>
- <p>Returns information about <c><anno>Port</anno></c> as specified
- by <c><anno>Item</anno></c>, or <c>undefined</c> if the port is not open.
- Also, if <c>Item =:= registered_name</c> and the port has no
- registered name, <c>[]</c> is returned.</p>
- <p>For valid values of <c><anno>Item</anno></c>, and corresponding
- values of <c><anno>Result</anno></c>, see
- <seealso marker="#port_info/1">erlang:port_info/1</seealso>.</p>
- <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local port.</p>
+ <p><c><anno>Pid</anno></c> is the process identifier of the process
+ connected to the port.</p>
+ <p>If the port identified by <c><anno>Port</anno></c> is not open,
+ <c>undefined</c> is returned.</p>
+ <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local
+ port identifier, or an atom.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="port_info" arity="2" clause_i="2"/>
+ <fsummary>Information about the internal index of a port</fsummary>
+ <desc>
+ <p><c><anno>Index</anno></c> is the internal index of the port. This
+ index may be used to separate ports.</p>
+ <p>If the port identified by <c><anno>Port</anno></c> is not open,
+ <c>undefined</c> is returned.</p>
+ <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local
+ port identifier, or an atom.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="port_info" arity="2" clause_i="3"/>
+ <fsummary>Information about the input of a port</fsummary>
+ <desc>
+ <p><c><anno>Bytes</anno></c> is the total number of bytes
+ read from the port.</p>
+ <p>If the port identified by <c><anno>Port</anno></c> is not open,
+ <c>undefined</c> is returned.</p>
+ <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local
+ port identifier, or an atom.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="port_info" arity="2" clause_i="4"/>
+ <fsummary>Information about the links of a port</fsummary>
+ <desc>
+ <p><c><anno>Pids</anno></c> is a list of the process identifiers
+ of the processes that the port is linked to.</p>
+ <p>If the port identified by <c><anno>Port</anno></c> is not open,
+ <c>undefined</c> is returned.</p>
+ <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local
+ port identifier, or an atom.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="port_info" arity="2" clause_i="5"/>
+ <fsummary>Information about the locking of a port</fsummary>
+ <desc>
+ <p><c><anno>Locking</anno></c> is currently either <c>false</c>
+ (emulator without SMP support), <c>port_level</c> (port specific
+ locking), or <c>driver_level</c> (driver specific locking). Note
+ that these results are highly implementation specific and might
+ change in the future.</p>
+ <p>If the port identified by <c><anno>Port</anno></c> is not open,
+ <c>undefined</c> is returned.</p>
+ <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local
+ port identifier, or an atom.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="port_info" arity="2" clause_i="6"/>
+ <fsummary>Information about the memory size of a port</fsummary>
+ <desc>
+ <p><c><anno>Bytes</anno></c> is the total amount of memory,
+ in bytes, allocated for this port by the runtime system. Note
+ that the port itself might have allocated memory which is not
+ included in <c><anno>Bytes</anno></c>.</p>
+ <p>If the port identified by <c><anno>Port</anno></c> is not open,
+ <c>undefined</c> is returned.</p>
+ <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local
+ port identifier, or an atom.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="port_info" arity="2" clause_i="7"/>
+ <fsummary>Information about the monitors of a port</fsummary>
+ <desc>
+ <p><c><anno>Monitors</anno></c> represent processes that this port
+ is monitoring.</p>
+ <p>If the port identified by <c><anno>Port</anno></c> is not open,
+ <c>undefined</c> is returned.</p>
+ <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local
+ port identifier, or an atom.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="port_info" arity="2" clause_i="8"/>
+ <fsummary>Information about the name of a port</fsummary>
+ <desc>
+ <p><c><anno>Name</anno></c> is the command name set by
+ <seealso marker="#open_port/2">open_port/2</seealso>.</p>
+ <p>If the port identified by <c><anno>Port</anno></c> is not open,
+ <c>undefined</c> is returned.</p>
+ <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local
+ port identifier, or an atom.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="port_info" arity="2" clause_i="9"/>
+ <fsummary>Information about the OS pid of a port</fsummary>
+ <desc>
+ <p><c><anno>OsPid</anno></c> is the process identifier (or equivalent)
+ of an OS process created with
+ <seealso marker="#open_port/2">open_port({spawn | spawn_executable,
+ Command}, Options)</seealso>. If the port is not the result of spawning
+ an OS process, the value is <c>undefined</c>.</p>
+ <p>If the port identified by <c><anno>Port</anno></c> is not open,
+ <c>undefined</c> is returned.</p>
+ <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local
+ port identifier, or an atom.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="port_info" arity="2" clause_i="10"/>
+ <fsummary>Information about the output of a port</fsummary>
+ <desc>
+ <p><c><anno>Bytes</anno></c> is the total number of bytes written
+ to the port from Erlang processes using either
+ <seealso marker="#port_command/2">port_command/2</seealso>,
+ <seealso marker="#port_command/3">port_command/3</seealso>,
+ or <c><anno>Port</anno> ! {Owner, {command, Data}</c>.
+ </p>
+ <p>If the port identified by <c><anno>Port</anno></c> is not open,
+ <c>undefined</c> is returned.</p>
+ <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local
+ port identifier, or an atom.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="port_info" arity="2" clause_i="11"/>
+ <fsummary>Information about the parallelism hint of a port</fsummary>
+ <desc>
+ <p><c><anno>Boolean</anno></c> corresponds to the port parallelism
+ hint being used by this port. For more information see
+ the <seealso marker="#open_port_parallelism">parallelism</seealso>
+ option of <seealso marker="#open_port/2">open_port/2</seealso>.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="port_info" arity="2" clause_i="12"/>
+ <fsummary>Information about the queue size of a port</fsummary>
+ <desc>
+ <p><c><anno>Bytes</anno></c> is the total amount of data,
+ in bytes, queued by the port using the ERTS driver queue
+ implementation.</p>
+ <p>If the port identified by <c><anno>Port</anno></c> is not open,
+ <c>undefined</c> is returned.</p>
+ <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local
+ port identifier, or an atom.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="port_info" arity="2" clause_i="13"/>
+ <fsummary>Information about the registered name of a port</fsummary>
+ <desc>
+ <p><c><anno>RegisteredName</anno></c> is the registered name of
+ the port. If the port has no registered name, <c>[]</c> is returned.</p>
+ <p>If the port identified by <c><anno>Port</anno></c> is not open,
+ <c>undefined</c> is returned.</p>
+ <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local
+ port identifier, or an atom.</p>
</desc>
</func>
<func>
@@ -3168,7 +3337,10 @@ os_prompt% </pre>
<name name="ports" arity="0"/>
<fsummary>All open ports</fsummary>
<desc>
- <p>Returns a list of all ports on the local node.</p>
+ <p>Returns a list of port identifiers corresponding to all the
+ ports currently existing on the local node.</p>
+
+ <p>Note that a port that is exiting, exists but is not open.</p>
</desc>
</func>
<func>
@@ -3534,10 +3706,11 @@ os_prompt% </pre>
the initial function call with which the process was
spawned.</p>
</item>
- <tag><c>{links, <anno>Pids</anno>}</c></tag>
+ <tag><c>{links, <anno>PidsAndPorts</anno>}</c></tag>
<item>
- <p><c><anno>Pids</anno></c> is a list of pids, with processes to
- which the process has a link.</p>
+ <p><c><anno>PidsAndPorts</anno></c> is a list of pids and
+ port identifiers, with processes or ports to which the process
+ has a link.</p>
</item>
<tag><c>{last_calls, false|Calls}</c></tag>
<item>
@@ -5501,19 +5674,40 @@ ok
<item>
<p>Returns a string containing the OTP release number.</p>
</item>
+ <tag><marker id="system_info_port_parallelism"><c>port_parallelism</c></marker></tag>
+ <item><p>Returns the default port parallelism scheduling hint used.
+ For more information see the
+ <seealso marker="erl#+spp">+spp</seealso> command line argument
+ of <seealso marker="erl">erl(1)</seealso>.</p></item>
+ <tag><c>process_count</c></tag>
+ <item>
+ <p>Returns the number of ports currently existing at
+ the local node as an integer. The same value as
+ <c>length(erlang:ports())</c> returns.</p>
+ </item>
+ <tag><marker id="system_info_port_limit"><c>port_limit</c></marker></tag>
+ <item>
+ <p>Returns the maximum number of simultaneously existing
+ ports at the local node as an integer. This limit
+ can be configured at startup by using the
+ <seealso marker="erl#max_ports"><c>+Q</c></seealso>
+ command line flag of
+ <seealso marker="erl"><c>erl(1)</c></seealso>.</p>
+ </item>
<tag><c>process_count</c></tag>
<item>
<p>Returns the number of processes currently existing at
the local node as an integer. The same value as
<c>length(processes())</c> returns.</p>
</item>
- <tag><c>process_limit</c></tag>
+ <tag><marker id="system_info_process_limit"><c>process_limit</c></marker></tag>
<item>
- <p>Returns the maximum number of concurrently existing
+ <p>Returns the maximum number of simultaneously existing
processes at the local node as an integer. This limit
- can be configured at startup by using the command line
- flag <c>+P</c>, see
- <seealso marker="erts:erl#max_processes">erl(1)</seealso>.</p>
+ can be configured at startup by using the
+ <seealso marker="erl#max_processes"><c>+P</c></seealso>
+ command line flag of
+ <seealso marker="erl"><c>erl(1)</c></seealso>.</p>
</item>
<tag><c>procs</c></tag>
<item>
diff --git a/erts/doc/src/erts_alloc.xml b/erts/doc/src/erts_alloc.xml
index ec5e7d9b74..87d6682328 100644
--- a/erts/doc/src/erts_alloc.xml
+++ b/erts/doc/src/erts_alloc.xml
@@ -341,7 +341,8 @@
Largest (<c>mseg_alloc</c>) multiblock carrier size (in
kilobytes). See <seealso marker="#mseg_mbc_sizes">the description
on how sizes for mseg_alloc multiblock carriers are decided</seealso>
- in "the <c>alloc_util</c> framework" section.</item>
+ in "the <c>alloc_util</c> framework" section. On 32-bit Unix style OS
+ this limit can not be set higher than 128 megabyte.</item>
<tag><marker id="M_mbcgs"><c><![CDATA[+M<S>mbcgs <ratio>]]></c></marker></tag>
<item>
(<c>mseg_alloc</c>) multiblock carrier growth stages. See
@@ -413,7 +414,8 @@
Singleblock carrier threshold. Blocks larger than this
threshold will be placed in singleblock carriers. Blocks
smaller than this threshold will be placed in multiblock
- carriers.</item>
+ carriers. On 32-bit Unix style OS this threshold can not be set higher
+ than 8 megabytes.</item>
<tag><marker id="M_sbmbcs"><c><![CDATA[+M<S>sbmbcs <size>]]></c></marker></tag>
<item>
Small block multiblock carrier size (in bytes). Memory blocks smaller
diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml
index cdb72b2b98..de6696671b 100644
--- a/erts/doc/src/notes.xml
+++ b/erts/doc/src/notes.xml
@@ -30,6 +30,386 @@
</header>
<p>This document describes the changes made to the ERTS application.</p>
+<section><title>Erts 5.10</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Set new peeled off SCTP socket to nonblocking socket
+ (Thanks to Jonas Falkevik)</p>
+ <p>
+ Own Id: OTP-10491</p>
+ </item>
+ <item>
+ <p>
+ Fix various typos (thanks to Tuncer Ayaz)</p>
+ <p>
+ Own Id: OTP-10611</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ A boolean socket option 'ipv6_v6only' for IPv6 sockets
+ has been added. The default value of the option is OS
+ dependent, so applications aiming to be portable should
+ consider using <c>{ipv6_v6only,true}</c> when creating an
+ <c>inet6</c> listening/destination socket, and if
+ neccesary also create an <c>inet</c> socket on the same
+ port for IPv4 traffic. See the documentation.</p>
+ <p>
+ Own Id: OTP-8928 Aux Id: kunagi-193 [104] </p>
+ </item>
+ <item>
+ <p>It is now allowed to define stubs for BIFs, to allow
+ type specs to be written for BIFs. For example, if there
+ is BIF called <c>lists:member/2</c>, a dummy definition
+ of <c>lists:member/2</c> is now allowed.</p>
+ <p>
+ Own Id: OTP-9861</p>
+ </item>
+ <item>
+ <p>
+ Code loading and upgrade are now done without blocking
+ the emulator in single threaded mode. This will improve
+ realtime characteristics when code is loaded/upgraded on
+ a running SMP system.</p>
+ <p>
+ Own Id: OTP-9974</p>
+ </item>
+ <item>
+ <p>In the SMP emulator, turning on and off tracing will
+ no longer take down the system to single-scheduling. </p>
+ <p>
+ Own Id: OTP-10122</p>
+ </item>
+ <item>
+ <p>
+ Tuple funs (deprecated in R15B) are no longer supported.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-10170</p>
+ </item>
+ <item>
+ <p>Major port improvements. The most notable:</p> <list>
+ <item>New internal port table implementation allowing for
+ both parallel reads as well as writes. Especially read
+ operations have become really cheap.</item> <item>Dynamic
+ allocation of port structures. This allow for a much
+ larger maximum amount of ports allowed as a default. The
+ previous default of 1024 has been raised to 65536.
+ Maximum amount of ports can be set using the <seealso
+ marker="erts:erl#+Q">+Q</seealso> command line flag of
+ <seealso marker="erts:erl">erl(1)</seealso>. The
+ previously used environment variable <c>ERL_MAX_PORTS</c>
+ has been deprecated and scheduled for removal in
+ OTP-R17.</item> <item>Major rewrite of scheduling of port
+ tasks. Major benefits of the rewrite are reduced
+ contention on run queue locks, and reduced amount of
+ memory allocation operations needed. The rewrite was also
+ necessary in order to make it possible to schedule
+ signals from processes to ports.</item> <item>Improved
+ internal thread progress functionality for easy
+ management of unmanaged threads. This improvement was
+ necessary for the rewrite of the port task
+ scheduling.</item> <item>Rewrite of all process to port
+ signal implementations in order to make it possible to
+ schedule those operations. All port operations can now be
+ scheduled which allows for reduced lock contention on the
+ port lock as well as truly asynchronous communication
+ with ports.</item> <item>Optimized lookup of port handles
+ from drivers.</item> <item>Optimized driver lookup when
+ creating ports.</item> <item>Preemptable <seealso
+ marker="erts:erlang#ports-0">erlang:ports/0</seealso>
+ BIF.</item> </list>
+ <p>These changes imply changes of the characteristics of
+ the system. The most notable:</p> <taglist> <tag>Order of
+ signal delivery.</tag> <item>The previous implementation
+ of the VM has delivered signals from processes to ports
+ in a synchronous stricter fashion than required by the
+ language. As of ERTS version 5.10, signals are truly
+ asynchronously delivered. The order of signal delivery
+ still adheres to the requirements of the language, but
+ only to the requirements. That is, some signal sequences
+ that previously always were delivered in one specific
+ order may now from time to time be delivered in different
+ orders. This may cause Erlang programs that have made
+ <em>false assumptions</em> about signal delivery order to
+ fail even though they previously succeeded. For more
+ information about signal ordering guarantees, see the
+ chapter on <seealso
+ marker="erts:communication">communication</seealso> in
+ the ERTS user's guide. The <seealso
+ marker="erts:erl#+n">+n</seealso> command line flag of
+ <seealso marker="erts:erl">erl(1)</seealso> can be
+ helpful when trying to find signaling order bugs in
+ Erlang code that have been exposed by these
+ changes.</item> <tag>Latency of signals sent from
+ processes to ports.</tag> <item>Signals from processes to
+ ports where previously always delivered immediately. This
+ kept latency for such communication to a minimum, but it
+ could cause lock contention which was very expensive for
+ the system as a whole. In order to keep this latency low
+ also in the future, most signals from processes to ports
+ are by default still delivered immediately as long as no
+ conflicts occur. Such conflicts include not being able to
+ acquire the port lock, but also include other conflicts.
+ When a conflict occur, the signal will be scheduled for
+ delivery at a later time. A scheduled signal delivery may
+ cause a higher latency for this specific communication,
+ but improves the overall performance of the system since
+ it reduce lock contention between schedulers. The default
+ behavior of only scheduling delivery of these signals on
+ conflict can be changed by passing the <seealso
+ marker="erts:erl#+spp">+spp</seealso> command line flag
+ to <seealso marker="erts:erl">erl(1)</seealso>. The
+ behavior can also be changed on port basis using the
+ <seealso
+ marker="erts:erlang#open_port_parallelism">parallelism</seealso>
+ option of the <seealso
+ marker="erts:erlang#open_port-2">open_port/2</seealso>
+ BIF.</item> <tag>Execution time of the
+ <c>erlang:ports/0</c> BIF.</tag> <item>Since <seealso
+ marker="erts:erlang#ports-0">erlang:ports/0</seealso> now
+ can be preempted, the responsiveness of the system as a
+ whole has been improved. A call to <c>erlang:ports/0</c>
+ may, however, take a much longer time to complete than
+ before. How much longer time heavily depends on the
+ system load.</item> </taglist>
+ <p><em>Potential incompatibilities</em>:</p> <list>
+ <item><c>driver_send_term()</c> has been deprecated and
+ has been scheduled for removal in OTP-R17. Replace usage
+ of <c>driver_send_term()</c> with usage of <seealso
+ marker="erts:erl_driver#erl_drv_send_term">erl_drv_send_term()</seealso>.</item>
+ <item><c>driver_output_term()</c> has been deprecated and
+ has been scheduled for removal in OTP-R17. Replace usage
+ of <c>driver_output_term()</c> with usage of <seealso
+ marker="erts:erl_driver#erl_drv_output_term">erl_drv_output_term()</seealso>.</item>
+ <item>The new function <seealso
+ marker="erts:erl_driver#erl_drv_busy_msgq_limits">erl_drv_busy_msgq_limits()</seealso>
+ has been added in order to able to control management of
+ port queues.</item> </list>
+ <p>The <seealso
+ marker="erts:erl_driver#version_management">driver API
+ version</seealso> has been bumped to 2.1 from 2.0 due to
+ the above changes in the driver API.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-10336 Aux Id: kunagi-138
+ [b5b97f67-fe34-46dc-93e6-a2931576db12] </p>
+ </item>
+ <item>
+ <p>
+ Erlang specification 4.7.3 defines max tuple size to
+ 65535 elements It is now enforced to no more than
+ 16777215 elements (arity 24 bits)</p>
+ <p>
+ Previous edge cases (28 bits) were not validated and
+ could cause undefined behaviour.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-10633</p>
+ </item>
+ <item>
+ <p>
+ The previous default of a maximum of 32768 simultaneous
+ processes has been raised to 262144. This value can be
+ changed using the the <seealso
+ marker="erl#+P">+P</seealso> command line flag of
+ <seealso marker="erl">erl(1)</seealso>. Note that the
+ value passed now is considered as a hint, and that actual
+ value chosen in most cases will be a power of two.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-10647 Aux Id: OTP-10336 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 5.9.3.1</title>
+
+ <section><title>Known Bugs and Problems</title>
+ <list>
+ <item>
+ <p>
+ Create an erl_crash.dump if no heart exists and no
+ ERL_CRASH_DUMP_SECONDS is set (behaviour changed).</p>
+ <p>
+ Don't create an erl_crash.dump if heart do exists and no
+ ERL_CRASH_DUMP_SECONDS is set (behaviour not changed).</p>
+ <p>
+ This changes the behaviour back to the R15B02 default
+ considering if a beam was running with no heart.</p>
+ <p>
+ Own Id: OTP-10602</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 5.9.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix linking in OpenBSD. (Thanks to Matthew Dempsky)</p>
+ <p>
+ Own Id: OTP-10395</p>
+ </item>
+ <item>
+ <p>
+ Fix bug causing fallback atomics to be used even though
+ healthy gcc atomics or libatomic_ops was detected.</p>
+ <p>
+ Own Id: OTP-10418</p>
+ </item>
+ <item>
+ <p>
+ Ensure 'erl_crash.dump' when asked for it. This will
+ change erl_crash.dump behaviour.</p>
+ <p>
+ * Not setting ERL_CRASH_DUMP_SECONDS will now terminate
+ beam immediately on a crash without writing a crash dump
+ file.</p>
+ <p>
+ * Setting ERL_CRASH_DUMP_SECONDS to 0 will also terminate
+ beam immediately on a crash without writing a crash dump
+ file, i.e. same as not setting ERL_CRASH_DUMP_SECONDS
+ environment variable.</p>
+ <p>
+ * Setting ERL_CRASH_DUMP_SECONDS to a negative value will
+ let the beam wait indefinitely on the crash dump file
+ being written.</p>
+ <p>
+ * Setting ERL_CRASH_DUMP_SECONDS to a positive value will
+ let the beam wait that many seconds on the crash dump
+ file being written.</p>
+ <p>
+ A positive value will set an alarm/timeout for restart
+ both in beam and in heart if heart is running.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-10422 Aux Id: kunagi-250 [161] </p>
+ </item>
+ <item>
+ <p>
+ Fix bug where MSVRT100.dll was not included in the
+ windows installer.</p>
+ <p>
+ Own Id: OTP-10481</p>
+ </item>
+ <item>
+ <p>In the expression
+ <c>&lt;&lt;Bin/binary,...&gt;&gt;</c>, if <c>Bin</c> was
+ a bitstring with a size not a multiple of 8, either no
+ exception was generated or an incorrect exception was
+ generated. (Thanks to Adam Rutkowski for reporting this
+ bug.)</p>
+ <p>
+ Own Id: OTP-10524</p>
+ </item>
+ <item>
+ <p>
+ The runtime system could crash while scheduling a port
+ task. The port task was scheduled either due to an
+ external I/O event being triggered, a driver timeout
+ being triggered, or data being sent over a distribution
+ channel.</p>
+ <p>
+ Own Id: OTP-10556</p>
+ </item>
+ <item>
+ <p>
+ <c>erlang:memory(ets)</c> erroneously included the size
+ of each ETS-table main structure twice.</p>
+ <p>
+ Own Id: OTP-10558</p>
+ </item>
+ <item>
+ <p>
+ Fix compile error in generated file hipe_amd64_bifs.S for
+ Solaris.</p>
+ <p>
+ Own Id: OTP-10577</p>
+ </item>
+ <item>
+ <p>
+ A faulty spec for process_info/2 could cause false
+ dialyzer warnings. The spec is corrected.</p>
+ <p>
+ Own Id: OTP-10584</p>
+ </item>
+ <item>
+ <p>
+ In very rare cases, the VM could crash if a garbage
+ collector was called while executing an appending bit
+ syntax instruction. The symptom was a core when
+ reallocating memory in the function erts_bs_append. The
+ garbage collector bug is now corrected.</p>
+ <p>
+ Own Id: OTP-10590</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Improve support for building and testing in embedded ppc
+ environments.</p>
+ <p>
+ Own Id: OTP-10265 Aux Id: kunagi-159
+ [daf97f67-5724-4812-a5b6-7e86990133d2-1] </p>
+ </item>
+ <item>
+ <p>
+ Due to a race condition on Windows, sometimes when
+ printing to standard output and then immediately
+ terminating erlang all data would not be printed. The
+ emulator now waits for all data to be printed before
+ exiting.</p>
+ <p>
+ Own Id: OTP-10325 Aux Id: kunagi-166
+ [dd72d0e2-3e76-4a51-8b56-7564e24eecae] </p>
+ </item>
+ <item>
+ <p>
+ The frequency with which sleeping schedulers are woken
+ due to outstanding memory deallocation jobs has been
+ reduced.</p>
+ <p>
+ Own Id: OTP-10476 Aux Id: OTP-10162 </p>
+ </item>
+ <item>
+ <p>
+ Clearer warnings about the dangers of misuse of <seealso
+ marker="erl_nif#WARNING">native functions</seealso> and
+ <seealso marker="erl_driver#WARNING">drivers</seealso>
+ have been added to the documentation.</p>
+ <p>
+ Own Id: OTP-10557</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erts 5.9.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/erts/doc/src/part.xml b/erts/doc/src/part.xml
index e27b722721..2c178556d4 100644
--- a/erts/doc/src/part.xml
+++ b/erts/doc/src/part.xml
@@ -31,6 +31,7 @@
<description>
<p>The Erlang Runtime System Application <em>ERTS</em>.</p>
</description>
+ <xi:include href="communication.xml"/>
<xi:include href="match_spec.xml"/>
<xi:include href="crash_dump.xml"/>
<xi:include href="alt_dist.xml"/>
diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in
index 7e966c81bb..3e44bbb8db 100644
--- a/erts/emulator/Makefile.in
+++ b/erts/emulator/Makefile.in
@@ -61,7 +61,7 @@ else
ifeq ($(TYPE),purify)
PURIFY = purify $(PURIFY_BUILD_OPTIONS)
TYPEMARKER = .purify
-TYPE_FLAGS = $(DEBUG_CFLAGS) -DPURIFY -DNO_JUMP_TABLE -DERTS_MSEG_FAKE_SEGMENTS
+TYPE_FLAGS = $(DEBUG_CFLAGS) -DPURIFY -DNO_JUMP_TABLE
ENABLE_ALLOC_TYPE_VARS += purify
else
@@ -92,7 +92,7 @@ else
ifeq ($(TYPE),valgrind)
PURIFY =
TYPEMARKER = .valgrind
-TYPE_FLAGS = $(DEBUG_CFLAGS) -DVALGRIND -DNO_JUMP_TABLE -DERTS_MSEG_FAKE_SEGMENTS
+TYPE_FLAGS = $(DEBUG_CFLAGS) -DVALGRIND -DNO_JUMP_TABLE
ENABLE_ALLOC_TYPE_VARS += valgrind
else
@@ -399,7 +399,7 @@ include zlib/zlib.mk
include pcre/pcre.mk
$(ERTS_LIB):
- cd $(ERTS_LIB_DIR) && $(MAKE) $(TYPE)
+ $(V_at)cd $(ERTS_LIB_DIR) && $(MAKE) $(TYPE)
.PHONY: clean
clean:
@@ -491,7 +491,7 @@ $(TTF_DIR)/beam_pred_funcs.h \
$(TTF_DIR)/beam_tr_funcs.h \
: $(TTF_DIR)/OPCODES-GENERATED
$(TTF_DIR)/OPCODES-GENERATED: $(OPCODE_TABLES) utils/beam_makeops
- LANG=C $(PERL) utils/beam_makeops \
+ $(gen_verbose)LANG=C $(PERL) utils/beam_makeops \
-wordsize @EXTERNAL_WORD_SIZE@ \
-outdir $(TTF_DIR) \
-DUSE_VM_PROBES=$(if $(USE_VM_PROBES),1,0) \
@@ -525,22 +525,22 @@ $(TARGET)/erl_atom_table.h \
$(TARGET)/erl_pbifs.c \
: $(TARGET)/TABLES-GENERATED
$(TARGET)/TABLES-GENERATED: $(ATOMS) $(BIFS) utils/make_tables
- LANG=C $(PERL) utils/make_tables -src $(TARGET) -include $(TARGET)\
+ $(gen_verbose)LANG=C $(PERL) utils/make_tables -src $(TARGET) -include $(TARGET)\
$(ATOMS) $(BIFS) && echo $? >$(TARGET)/TABLES-GENERATED
GENERATE += $(TARGET)/TABLES-GENERATED
$(TTF_DIR)/erl_alloc_types.h: beam/erl_alloc.types utils/make_alloc_types
- LANG=C $(PERL) utils/make_alloc_types -src $< -dst $@ $(ENABLE_ALLOC_TYPE_VARS)
+ $(gen_verbose)LANG=C $(PERL) utils/make_alloc_types -src $< -dst $@ $(ENABLE_ALLOC_TYPE_VARS)
GENERATE += $(TTF_DIR)/erl_alloc_types.h
# version include file
$(TARGET)/erl_version.h: ../vsn.mk
- LANG=C $(PERL) utils/make_version -o $@ $(SYSTEM_VSN) $(VSN)$(SERIALNO) $(TARGET)
+ $(gen_verbose)LANG=C $(PERL) utils/make_version -o $@ $(SYSTEM_VSN) $(VSN)$(SERIALNO) $(TARGET)
GENERATE += $(TARGET)/erl_version.h
# driver table
$(TTF_DIR)/driver_tab.c: Makefile.in
- LANG=C $(PERL) utils/make_driver_tab -o $@ $(DRV_OBJS)
+ $(gen_verbose)LANG=C $(PERL) utils/make_driver_tab -o $@ $(DRV_OBJS)
GENERATE += $(TTF_DIR)/driver_tab.c
@@ -560,8 +560,9 @@ $(PRELOAD_SRC): $(ERL_TOP)/erts/preloaded/ebin/otp_ring0.beam \
$(ERL_TOP)/erts/preloaded/ebin/zlib.beam \
$(ERL_TOP)/erts/preloaded/ebin/prim_zip.beam \
$(ERL_TOP)/erts/preloaded/ebin/erl_prim_loader.beam \
- $(ERL_TOP)/erts/preloaded/ebin/erlang.beam
- LANG=C $(PERL) utils/make_preload $(MAKE_PRELOAD_EXTRA) -rc $^ > $@
+ $(ERL_TOP)/erts/preloaded/ebin/erlang.beam \
+ $(ERL_TOP)/erts/preloaded/ebin/erts_internal.beam
+ $(gen_verbose)LANG=C $(PERL) utils/make_preload $(MAKE_PRELOAD_EXTRA) -rc $^ > $@
else
PRELOAD_OBJ = $(OBJDIR)/preload.o
PRELOAD_SRC = $(TARGET)/preload.c
@@ -572,8 +573,9 @@ $(PRELOAD_SRC): $(ERL_TOP)/erts/preloaded/ebin/otp_ring0.beam \
$(ERL_TOP)/erts/preloaded/ebin/zlib.beam \
$(ERL_TOP)/erts/preloaded/ebin/prim_zip.beam \
$(ERL_TOP)/erts/preloaded/ebin/erl_prim_loader.beam \
- $(ERL_TOP)/erts/preloaded/ebin/erlang.beam
- LANG=C $(PERL) utils/make_preload -old $^ > $@
+ $(ERL_TOP)/erts/preloaded/ebin/erlang.beam \
+ $(ERL_TOP)/erts/preloaded/ebin/erts_internal.beam
+ $(gen_verbose)LANG=C $(PERL) utils/make_preload -old $^ > $@
endif
.PHONY : generate
@@ -584,13 +586,13 @@ else
generate: $(TTF_DIR)/GENERATED $(PRELOAD_SRC)
$(TTF_DIR)/GENERATED: $(GENERATE)
- echo $? >$(TTF_DIR)/GENERATED
+ $(gen_verbose)echo $? >$(TTF_DIR)/GENERATED
endif
$(TARGET)/erlang_dtrace.h: beam/erlang_dtrace.d
- dtrace -h -C -Ibeam -s $< -o ./erlang_dtrace.tmp
- sed -e '/^#define[ ]*ERLANG_[A-Z0-9_]*(.*)/y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' ./erlang_dtrace.tmp > $@
- rm ./erlang_dtrace.tmp
+ $(dtrace_verbose)dtrace -h -C -Ibeam -s $< -o ./erlang_dtrace.tmp
+ $(V_at)sed -e '/^#define[ ]*ERLANG_[A-Z0-9_]*(.*)/y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' ./erlang_dtrace.tmp > $@
+ $(V_at)rm ./erlang_dtrace.tmp
# ----------------------------------------------------------------------
# Pattern rules
@@ -611,45 +613,45 @@ endif
ifeq ($(TARGET),win32)
$(OBJDIR)/dll_sys.o: sys/$(ERLANG_OSTYPE)/sys.c
- $(CC) $(CFLAGS) -DERL_RUN_SHARED_LIB=1 $(INCLUDES) -c $< -o $@
+ $(V_CC) $(CFLAGS) -DERL_RUN_SHARED_LIB=1 $(INCLUDES) -c $< -o $@
$(OBJDIR)/beams.$(RES_EXT): $(TARGET)/beams.rc
- $(RC) -o $@ -I$(ERL_TOP)/erts/etc/win32 $(TARGET)/beams.rc
+ $(V_RC) -o $@ -I$(ERL_TOP)/erts/etc/win32 $(TARGET)/beams.rc
endif
ifneq ($(filter tile-%,$(TARGET)),)
$(OBJDIR)/beam_emu.o: beam/beam_emu.c
- $(CC) $(subst -O2, $(GEN_OPT_FLGS), $(CFLAGS)) \
+ $(V_CC) $(subst -O2, $(GEN_OPT_FLGS), $(CFLAGS)) \
-OPT:Olimit=0 -WOPT:lpre=off:spre=off:epre=off \
$(INCLUDES) -c $< -o $@
else
# Usually the same as the default rule, but certain platforms (e.g. win32) mix
# different compilers
$(OBJDIR)/beam_emu.o: beam/beam_emu.c
- $(EMU_CC) $(subst -O2, $(GEN_OPT_FLGS), $(CFLAGS)) $(INCLUDES) -c $< -o $@
+ $(V_EMU_CC) $(subst -O2, $(GEN_OPT_FLGS), $(CFLAGS)) $(INCLUDES) -c $< -o $@
endif
$(OBJDIR)/%.o: beam/%.c
- $(CC) $(subst -O2, $(GEN_OPT_FLGS), $(CFLAGS)) $(INCLUDES) -c $< -o $@
+ $(V_CC) $(subst -O2, $(GEN_OPT_FLGS), $(CFLAGS)) $(INCLUDES) -c $< -o $@
$(OBJDIR)/%.o: $(TARGET)/%.c
- $(CC) $(CFLAGS) $(INCLUDES) -Idrivers/common -c $< -o $@
+ $(V_CC) $(CFLAGS) $(INCLUDES) -Idrivers/common -c $< -o $@
$(OBJDIR)/%.o: $(TTF_DIR)/%.c
- $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
+ $(V_CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
$(OBJDIR)/%.o: sys/$(ERLANG_OSTYPE)/%.c
- $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
+ $(V_CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
$(OBJDIR)/%.o: sys/common/%.c
- $(CC) $(subst -O2, $(GEN_OPT_FLGS), $(CFLAGS)) $(INCLUDES) -c $< -o $@
+ $(V_CC) $(subst -O2, $(GEN_OPT_FLGS), $(CFLAGS)) $(INCLUDES) -c $< -o $@
$(OBJDIR)/%.o: drivers/common/%.c
- $(CC) $(CFLAGS) -DLIBSCTP=$(LIBSCTP) $(INCLUDES) -Idrivers/common -Idrivers/$(ERLANG_OSTYPE) -c $< -o $@
+ $(V_CC) $(CFLAGS) -DLIBSCTP=$(LIBSCTP) $(INCLUDES) -Idrivers/common -Idrivers/$(ERLANG_OSTYPE) -c $< -o $@
$(OBJDIR)/%.o: drivers/$(ERLANG_OSTYPE)/%.c
- $(CC) $(CFLAGS) $(INCLUDES) -Idrivers/common -Idrivers/$(ERLANG_OSTYPE) -I../etc/$(ERLANG_OSTYPE) -c $< -o $@
+ $(V_CC) $(CFLAGS) $(INCLUDES) -Idrivers/common -Idrivers/$(ERLANG_OSTYPE) -I../etc/$(ERLANG_OSTYPE) -c $< -o $@
# ----------------------------------------------------------------------
# Specials
@@ -657,19 +659,19 @@ $(OBJDIR)/%.o: drivers/$(ERLANG_OSTYPE)/%.c
CS_SRC = sys/$(ERLANG_OSTYPE)/erl_child_setup.c
$(BINDIR)/$(CS_EXECUTABLE): $(TTF_DIR)/GENERATED $(PRELOAD_SRC) $(CS_SRC) $(ERTS_LIB)
- $(CS_PURIFY) $(CC) $(CS_LDFLAGS) -o $(BINDIR)/$(CS_EXECUTABLE) \
+ $(ld_verbose)$(CS_PURIFY) $(CC) $(CS_LDFLAGS) -o $(BINDIR)/$(CS_EXECUTABLE) \
$(CS_CFLAGS) $(COMMON_INCLUDES) $(CS_SRC) $(CS_LIBS)
$(OBJDIR)/%.kp.o: sys/common/%.c
- $(CC) -DERTS_KERNEL_POLL_VERSION $(subst -O2, $(GEN_OPT_FLGS), $(CFLAGS)) $(INCLUDES) -c $< -o $@
+ $(V_CC) -DERTS_KERNEL_POLL_VERSION $(subst -O2, $(GEN_OPT_FLGS), $(CFLAGS)) $(INCLUDES) -c $< -o $@
$(OBJDIR)/%.nkp.o: sys/common/%.c
- $(CC) -DERTS_NO_KERNEL_POLL_VERSION $(subst -O2, $(GEN_OPT_FLGS), $(CFLAGS)) $(INCLUDES) -c $< -o $@
+ $(V_CC) -DERTS_NO_KERNEL_POLL_VERSION $(subst -O2, $(GEN_OPT_FLGS), $(CFLAGS)) $(INCLUDES) -c $< -o $@
ifeq ($(GCC),yes)
$(OBJDIR)/erl_goodfit_alloc.o: beam/erl_goodfit_alloc.c
- $(CC) $(subst -O2, $(GEN_OPT_FLGS) $(UNROLL_FLG), $(CFLAGS)) $(INCLUDES) -c $< -o $@
+ $(V_CC) $(subst -O2, $(GEN_OPT_FLGS) $(UNROLL_FLG), $(CFLAGS)) $(INCLUDES) -c $< -o $@
endif
# ----------------------------------------------------------------------
@@ -735,7 +737,8 @@ RUN_OBJS = \
$(OBJDIR)/packet_parser.o $(OBJDIR)/safe_hash.o \
$(OBJDIR)/erl_zlib.o $(OBJDIR)/erl_nif.o \
$(OBJDIR)/erl_bif_binary.o $(OBJDIR)/erl_ao_firstfit_alloc.o \
- $(OBJDIR)/erl_thr_queue.o $(OBJDIR)/erl_sched_spec_pre_alloc.o
+ $(OBJDIR)/erl_thr_queue.o $(OBJDIR)/erl_sched_spec_pre_alloc.o \
+ $(OBJDIR)/erl_ptab.o
ifeq ($(TARGET),win32)
DRV_OBJS = \
@@ -841,28 +844,28 @@ $(OBJS): $(TTF_DIR)/GENERATED
M4FLAGS += -DTARGET=$(TARGET) -DOPSYS=$(OPSYS) -DARCH=$(ARCH)
$(TTF_DIR)/%.S: hipe/%.m4
- m4 $(M4FLAGS) $< > $@
+ $(m4_verbose)m4 $(M4FLAGS) $< > $@
$(TTF_DIR)/%.h: hipe/%.m4
- m4 $(M4FLAGS) $< > $@
+ $(m4_verbose)m4 $(M4FLAGS) $< > $@
$(OBJDIR)/%.o: $(TTF_DIR)/%.S
- $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
+ $(V_CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
$(OBJDIR)/%.o: hipe/%.S
- $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
+ $(V_CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
$(OBJDIR)/%.o: hipe/%.c
- $(CC) $(subst O2,O3, $(CFLAGS)) $(INCLUDES) -c $< -o $@
+ $(V_CC) $(subst O2,O3, $(CFLAGS)) $(INCLUDES) -c $< -o $@
$(BINDIR)/hipe_mkliterals$(TF_MARKER): $(OBJDIR)/hipe_mkliterals.o
- $(CC) $(CFLAGS) $(INCLUDES) -o $@ $<
+ $(ld_verbose)$(CC) $(CFLAGS) $(INCLUDES) -o $@ $<
$(OBJDIR)/hipe_mkliterals.o: $(HIPE_ASM) $(TTF_DIR)/erl_alloc_types.h \
$(TTF_DIR)/OPCODES-GENERATED $(TARGET)/TABLES-GENERATED
$(TTF_DIR)/hipe_literals.h: $(BINDIR)/hipe_mkliterals$(TF_MARKER)
- $(BINDIR)/hipe_mkliterals$(TF_MARKER) -c > $@
+ $(gen_verbose)$(BINDIR)/hipe_mkliterals$(TF_MARKER) -c > $@
$(OBJDIR)/hipe_x86_glue.o: hipe/hipe_x86_glue.S \
$(TTF_DIR)/hipe_x86_asm.h $(TTF_DIR)/hipe_literals.h \
@@ -905,7 +908,7 @@ $(OBJDIR)/hipe_arm_bifs.o: $(TTF_DIR)/hipe_arm_bifs.S \
# Use -fomit-frame-pointer to work around gcc (v4.5.2) bug causing
# "error: r7 cannot be used in asm here" for DEBUG build.
$(OBJDIR)/hipe_arm.o: hipe/hipe_arm.c
- $(CC) $(subst O2,O3, $(CFLAGS)) -fomit-frame-pointer $(INCLUDES) -c $< -o $@
+ $(V_CC) $(subst O2,O3, $(CFLAGS)) -fomit-frame-pointer $(INCLUDES) -c $< -o $@
# end of HiPE section
########################################
@@ -916,13 +919,13 @@ $(OBJDIR)/hipe_arm.o: hipe/hipe_arm.c
ifeq ($(TARGET), win32)
# Only the basic erlang to begin with eh?
$(BINDIR)/$(EMULATOR_EXECUTABLE): $(INIT_OBJS) $(OBJS) $(DEPLIBS)
- $(PURIFY) $(LD) -dll -def:sys/$(ERLANG_OSTYPE)/erl.def -implib:$(BINDIR)/erl_dll.lib -o $(BINDIR)/$(EMULATOR_EXECUTABLE) \
+ $(ld_verbose)$(PURIFY) $(LD) -dll -def:sys/$(ERLANG_OSTYPE)/erl.def -implib:$(BINDIR)/erl_dll.lib -o $(BINDIR)/$(EMULATOR_EXECUTABLE) \
$(LDFLAGS) $(DEXPORT) $(INIT_OBJS) $(OBJS) $(LIBS)
else
$(BINDIR)/$(EMULATOR_EXECUTABLE): $(INIT_OBJS) $(OBJS) $(DEPLIBS)
- $(PURIFY) $(LD) -o $(BINDIR)/$(EMULATOR_EXECUTABLE) \
+ $(ld_verbose)$(PURIFY) $(LD) -o $(BINDIR)/$(EMULATOR_EXECUTABLE) \
$(HIPEBEAMLDFLAGS) $(LDFLAGS) $(DEXPORT) $(INIT_OBJS) $(OBJS) $(LIBS)
endif
@@ -1010,23 +1013,24 @@ depend:
else
depend: $(TTF_DIR)/depend.mk
$(TTF_DIR)/depend.mk: $(TTF_DIR)/GENERATED $(PRELOAD_SRC)
- $(DEP_CC) $(DEP_FLAGS) $(BEAM_SRC) \
+ $(gen_verbose)
+ $(V_at)$(DEP_CC) $(DEP_FLAGS) $(BEAM_SRC) \
| $(SED_DEPEND) > $(TTF_DIR)/depend.mk
- $(DEP_CC) $(DEP_FLAGS) -DLIBSCTP=$(LIBSCTP) $(DRV_COMMON_SRC) \
+ $(V_at)$(DEP_CC) $(DEP_FLAGS) -DLIBSCTP=$(LIBSCTP) $(DRV_COMMON_SRC) \
| $(SED_DEPEND) >> $(TTF_DIR)/depend.mk
- $(DEP_CC) $(DEP_FLAGS) -I../etc/$(ERLANG_OSTYPE) $(DRV_OSTYPE_SRC) \
+ $(V_at)$(DEP_CC) $(DEP_FLAGS) -I../etc/$(ERLANG_OSTYPE) $(DRV_OSTYPE_SRC) \
| $(SED_DEPEND) >> $(TTF_DIR)/depend.mk
- $(DEP_CC) $(DEP_FLAGS) $(SYS_SRC) \
+ $(V_at)$(DEP_CC) $(DEP_FLAGS) $(SYS_SRC) \
| $(SED_DEPEND) >> $(TTF_DIR)/depend.mk
- $(DEP_CC) $(DEP_FLAGS) $(TARGET_SRC) \
+ $(V_at)$(DEP_CC) $(DEP_FLAGS) $(TARGET_SRC) \
| $(SED_DEPEND) >> $(TTF_DIR)/depend.mk
- $(DEP_CC) $(DEP_FLAGS) $(ZLIB_SRC) \
+ $(V_at)$(DEP_CC) $(DEP_FLAGS) $(ZLIB_SRC) \
| $(SED_DEPEND_ZLIB) >> $(TTF_DIR)/depend.mk
ifdef HIPE_ENABLED
- $(DEP_CC) $(DEP_FLAGS) $(HIPE_SRC) \
+ $(V_at)$(DEP_CC) $(DEP_FLAGS) $(HIPE_SRC) \
| $(SED_DEPEND) >> $(TTF_DIR)/depend.mk
endif
- cd $(ERTS_LIB_DIR) && $(MAKE) depend
+ $(V_at)cd $(ERTS_LIB_DIR) && $(MAKE) depend
endif
ifneq ($(MAKECMDGOALS),clean)
diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names
index 106fad030b..c47a608215 100644
--- a/erts/emulator/beam/atom.names
+++ b/erts/emulator/beam/atom.names
@@ -94,6 +94,7 @@ atom asynchronous
atom atom
atom atom_used
atom attributes
+atom await_port_send_result
atom await_proc_exit
atom await_sched_wall_time_modifications
atom awaiting_load
@@ -152,6 +153,7 @@ atom connection_closed
atom cons
atom const
atom context_switches
+atom control
atom copy
atom cpu
atom cpu_timestamp
@@ -204,6 +206,7 @@ atom erlang
atom ERROR='ERROR'
atom error_handler
atom error_logger
+atom erts_internal
atom ets
atom ETS_TRANSFER='ETS-TRANSFER'
atom event
@@ -237,6 +240,7 @@ atom gc_end
atom gc_start
atom Ge='>='
atom generational
+atom get_data
atom get_seq_token
atom get_tcw
atom getenv
@@ -252,6 +256,7 @@ atom heap_block_size
atom heap_size
atom heap_sizes
atom heap_type
+atom heart_port
atom heir
atom hidden
atom hide
@@ -407,6 +412,7 @@ atom overlapped_io
atom owner
atom packet
atom packet_size
+atom parallelism
atom Plus='+'
atom pause
atom pending
@@ -418,12 +424,12 @@ atom pid
atom port
atom ports
atom port_count
+atom port_limit
atom print
atom priority
atom private
atom process
atom processes
-atom processes_trap
atom processes_used
atom process_count
atom process_display
@@ -433,6 +439,7 @@ atom procs
atom profile
atom protected
atom protection
+atom ptab_list_continue
atom public
atom purify
atom quantify
@@ -480,6 +487,7 @@ atom sequential_trace_token
atom serial
atom set
atom set_cpu_topology
+atom set_data
atom set_on_first_link
atom set_on_first_spawn
atom set_on_link
diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c
index e8f8a04344..e0a4f86d2d 100644
--- a/erts/emulator/beam/beam_bif_load.c
+++ b/erts/emulator/beam/beam_bif_load.c
@@ -148,6 +148,15 @@ struct m {
};
static Eterm staging_epilogue(Process* c_p, int, Eterm res, int, struct m*, int);
+#ifdef ERTS_SMP
+static void smp_code_ix_commiter(void*);
+
+static struct /* Protected by code_write_permission */
+{
+ Process* stager;
+ ErtsThrPrgrLaterOp lop;
+}commiter_state;
+#endif
static Eterm
exception_list(Process* p, Eterm tag, struct m* mp, Sint exceptions)
@@ -347,7 +356,6 @@ staging_epilogue(Process* c_p, int commit, Eterm res, int is_blocking,
}
#ifdef ERTS_SMP
else {
- ErtsThrPrgrVal later;
ASSERT(is_value(res));
if (loaded) {
@@ -356,17 +364,17 @@ staging_epilogue(Process* c_p, int commit, Eterm res, int is_blocking,
erts_end_staging_code_ix();
/*
* Now we must wait for all schedulers to do a memory barrier before
- * we can activate and let them access the new staged code. This allows
+ * we can commit and let them access the new staged code. This allows
* schedulers to read active code_ix in a safe way while executing
* without any memory barriers at all.
*/
-
- later = erts_thr_progress_later(c_p->scheduler_data);
- erts_thr_progress_wakeup(c_p->scheduler_data, later);
- erts_notify_code_ix_activation(c_p, later);
+ ASSERT(commiter_state.stager == NULL);
+ commiter_state.stager = c_p;
+ erts_schedule_thr_prgr_later_op(smp_code_ix_commiter, NULL, &commiter_state.lop);
+ erts_smp_proc_inc_refc(c_p);
erts_suspend(c_p, ERTS_PROC_LOCK_MAIN, NULL);
/*
- * handle_code_ix_activation() will do the rest "later"
+ * smp_code_ix_commiter() will do the rest "later"
* and resume this process to return 'res'.
*/
ERTS_BIF_YIELD_RETURN(c_p, res);
@@ -374,6 +382,28 @@ staging_epilogue(Process* c_p, int commit, Eterm res, int is_blocking,
#endif
}
+
+#ifdef ERTS_SMP
+static void smp_code_ix_commiter(void* null)
+{
+ Process* p = commiter_state.stager;
+
+ erts_commit_staging_code_ix();
+ erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS);
+ if (!ERTS_PROC_IS_EXITING(p)) {
+ erts_resume(p, ERTS_PROC_LOCK_STATUS);
+ }
+ erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS);
+ erts_smp_proc_dec_refc(p);
+#ifdef DEBUG
+ commiter_state.stager = NULL;
+#endif
+ erts_release_code_write_permission();
+}
+#endif /* ERTS_SMP */
+
+
+
BIF_RETTYPE
check_old_code_1(BIF_ALIST_1)
{
@@ -408,8 +438,7 @@ check_process_code_2(BIF_ALIST_2)
if (is_internal_pid(BIF_ARG_1)) {
Eterm res;
ErtsCodeIndex code_ix;
- if (internal_pid_index(BIF_ARG_1) >= erts_max_processes)
- goto error;
+
code_ix = erts_active_code_ix();
modp = erts_get_module(BIF_ARG_2, code_ix);
if (modp == NULL) { /* Doesn't exist. */
diff --git a/erts/emulator/beam/beam_bp.c b/erts/emulator/beam/beam_bp.c
index 50d18b0347..c1e11f6448 100644
--- a/erts/emulator/beam/beam_bp.c
+++ b/erts/emulator/beam/beam_bp.c
@@ -65,10 +65,10 @@
#define ERTS_BPF_ALL 0xFF
-extern Eterm beam_return_to_trace[1]; /* OpCode(i_return_to_trace) */
-extern Eterm beam_return_trace[1]; /* OpCode(i_return_trace) */
-extern Eterm beam_exception_trace[1]; /* OpCode(i_exception_trace) */
-extern Eterm beam_return_time_trace[1]; /* OpCode(i_return_time_trace) */
+extern BeamInstr beam_return_to_trace[1]; /* OpCode(i_return_to_trace) */
+extern BeamInstr beam_return_trace[1]; /* OpCode(i_return_trace) */
+extern BeamInstr beam_exception_trace[1]; /* OpCode(i_exception_trace) */
+extern BeamInstr beam_return_time_trace[1]; /* OpCode(i_return_time_trace) */
erts_smp_atomic32_t erts_active_bp_index;
erts_smp_atomic32_t erts_staging_bp_index;
@@ -161,7 +161,7 @@ erts_bp_match_functions(BpFunctions* f, Eterm mfa[3], int specified)
for (current = 0; current < num_modules; current++) {
BeamInstr** code_base = (BeamInstr **) module[current]->curr.code;
BeamInstr* code;
- Uint num_functions = (Uint) code_base[MI_NUM_FUNCTIONS];
+ Uint num_functions = (Uint)(UWord) code_base[MI_NUM_FUNCTIONS];
Uint fi;
if (specified > 0) {
@@ -172,7 +172,7 @@ erts_bp_match_functions(BpFunctions* f, Eterm mfa[3], int specified)
}
for (fi = 0; fi < num_functions; fi++) {
- Eterm* pc;
+ BeamInstr* pc;
int wi;
code = code_base[MI_FUNCTIONS+fi];
@@ -254,7 +254,7 @@ erts_consolidate_bp_data(BpFunctions* f, int local)
Uint i;
Uint n = f->matched;
- ERTS_SMP_LC_ASSERT(erts_is_code_ix_locked());
+ ERTS_SMP_LC_ASSERT(erts_has_code_write_permission());
for (i = 0; i < n; i++) {
consolidate_bp_data(fs[i].mod, fs[i].pc, local);
@@ -266,7 +266,7 @@ erts_consolidate_bif_bp_data(void)
{
int i;
- ERTS_SMP_LC_ASSERT(erts_is_code_ix_locked());
+ ERTS_SMP_LC_ASSERT(erts_has_code_write_permission());
for (i = 0; i < BIF_SIZE; i++) {
Export *ep = bif_export[i];
consolidate_bp_data(0, ep->code+3, 0);
@@ -555,7 +555,7 @@ erts_clear_module_break(Module *modp) {
if (code_base == NULL) {
return 0;
}
- n = (Uint) code_base[MI_NUM_FUNCTIONS];
+ n = (Uint)(UWord) code_base[MI_NUM_FUNCTIONS];
for (i = 0; i < n; ++i) {
BeamInstr* pc;
@@ -692,7 +692,7 @@ erts_bif_trace(int bif_index, Process* p, Eterm* args, BeamInstr* I)
* export entry */
BeamInstr *cp = p->cp;
GenericBp* g;
- GenericBpData* bp;
+ GenericBpData* bp = NULL;
Uint bp_flags = 0;
ERTS_SMP_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p);
@@ -714,7 +714,7 @@ erts_bif_trace(int bif_index, Process* p, Eterm* args, BeamInstr* I)
IS_TRACED_FL(p, F_TRACE_CALLS)) {
int local = !!(bp_flags & ERTS_BPF_LOCAL_TRACE);
flags = erts_call_trace(p, ep->code, bp->local_ms, args,
- local, &p->tracer_proc);
+ local, &ERTS_TRACER_PROC(p));
}
if (bp_flags & ERTS_BPF_META_TRACE) {
Eterm tpid1, tpid2;
@@ -800,7 +800,7 @@ erts_bif_trace(int bif_index, Process* p, Eterm* args, BeamInstr* I)
}
if (flags & MATCH_SET_EXCEPTION_TRACE) {
erts_trace_exception(p, ep->code, class, value,
- &p->tracer_proc);
+ &ERTS_TRACER_PROC(p));
}
if ((flags & MATCH_SET_RETURN_TO_TRACE) && p->catches > 0) {
/* can only happen if(local)*/
@@ -825,7 +825,7 @@ erts_bif_trace(int bif_index, Process* p, Eterm* args, BeamInstr* I)
UnUseTmpHeapNoproc(3);
if ((flags_meta|flags) & MATCH_SET_EXCEPTION_TRACE) {
erts_smp_proc_lock(p, ERTS_PROC_LOCKS_ALL_MINOR);
- p->trace_flags |= F_EXCEPTION_TRACE;
+ ERTS_TRACE_FLAGS(p) |= F_EXCEPTION_TRACE;
erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL_MINOR);
}
}
@@ -835,7 +835,7 @@ erts_bif_trace(int bif_index, Process* p, Eterm* args, BeamInstr* I)
}
/* MATCH_SET_RETURN_TO_TRACE cannot occur if(meta) */
if (flags & MATCH_SET_RX_TRACE) {
- erts_trace_return(p, ep->code, result, &p->tracer_proc);
+ erts_trace_return(p, ep->code, result, &ERTS_TRACER_PROC(p));
}
if (flags & MATCH_SET_RETURN_TO_TRACE) {
/* can only happen if(local)*/
@@ -919,7 +919,7 @@ do_call_trace(Process* c_p, BeamInstr* I, Eterm* reg,
E -= 1;
ASSERT(c_p->htop <= E && E <= c_p->hend);
E[0] = make_cp(c_p->cp);
- c_p->cp = (BeamInstr *) beam_return_to_trace;
+ c_p->cp = beam_return_to_trace;
}
if (flags & MATCH_SET_RX_TRACE) {
E -= 3;
@@ -935,7 +935,7 @@ do_call_trace(Process* c_p, BeamInstr* I, Eterm* reg,
c_p->cp = (flags & MATCH_SET_EXCEPTION_TRACE) ?
beam_exception_trace : beam_return_trace;
erts_smp_proc_lock(c_p, ERTS_PROC_LOCKS_ALL_MINOR);
- c_p->trace_flags |= F_EXCEPTION_TRACE;
+ ERTS_TRACE_FLAGS(c_p) |= F_EXCEPTION_TRACE;
erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_ALL_MINOR);
}
c_p->stop = E;
@@ -974,7 +974,7 @@ erts_trace_time_call(Process* c_p, BeamInstr* I, BpDataTime* bdt)
ASSERT(pbt->pc);
/* add time to previous code */
bp_time_diff(&sitem, pbt, ms, s, us);
- sitem.pid = c_p->id;
+ sitem.pid = c_p->common.id;
sitem.count = 0;
/* previous breakpoint */
@@ -997,7 +997,7 @@ erts_trace_time_call(Process* c_p, BeamInstr* I, BpDataTime* bdt)
}
/* Add count to this code */
- sitem.pid = c_p->id;
+ sitem.pid = c_p->common.id;
sitem.count = 1;
sitem.s_time = 0;
sitem.us_time = 0;
@@ -1055,7 +1055,7 @@ erts_trace_time_return(Process *p, BeamInstr *pc)
ASSERT(pbt->pc);
bp_time_diff(&sitem, pbt, ms, s, us);
- sitem.pid = p->id;
+ sitem.pid = p->common.id;
sitem.count = 0;
/* previous breakpoint */
@@ -1386,7 +1386,7 @@ void erts_schedule_time_break(Process *p, Uint schedule) {
if (pbdt) {
get_sys_now(&ms,&s,&us);
bp_time_diff(&sitem, pbt, ms, s, us);
- sitem.pid = p->id;
+ sitem.pid = p->common.id;
sitem.count = 0;
h = &(pbdt->hash[bp_sched2ix_proc(p)]);
@@ -1449,7 +1449,7 @@ set_function_break(BeamInstr *pc, Binary *match_spec, Uint break_flags,
Uint common;
ErtsBpIndex ix = erts_staging_bp_ix();
- ERTS_SMP_LC_ASSERT(erts_is_code_ix_locked());
+ ERTS_SMP_LC_ASSERT(erts_has_code_write_permission());
g = (GenericBp *) pc[-4];
if (g == 0) {
int i;
@@ -1565,7 +1565,7 @@ clear_function_break(BeamInstr *pc, Uint break_flags)
Uint common;
ErtsBpIndex ix = erts_staging_bp_ix();
- ERTS_SMP_LC_ASSERT(erts_is_code_ix_locked());
+ ERTS_SMP_LC_ASSERT(erts_has_code_write_permission());
if ((g = (GenericBp *) pc[-4]) == 0) {
return 1;
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index 7b1ae624ce..0e9d140908 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -516,7 +516,7 @@ extern int count_instructions;
# define Dispatchfun() DispatchMacroFun()
#endif
-#define Self(R) R = c_p->id
+#define Self(R) R = c_p->common.id
#define Node(R) R = erts_this_node->sysname
#define Arg(N) I[(N)+1]
@@ -1074,11 +1074,11 @@ init_emulator(void)
void
dtrace_drvport_str(ErlDrvPort drvport, char *port_buf)
{
- Port *port = erts_drvport2port(drvport);
+ Port *port = erts_drvport2port(drvport, NULL);
erts_snprintf(port_buf, DTRACE_TERM_BUF_SIZE, "#Port<%lu.%lu>",
- port_channel_no(port->id),
- port_number(port->id));
+ port_channel_no(port->common.id),
+ port_number(port->common.id));
}
#endif
/*
@@ -1195,7 +1195,7 @@ void process_main(void)
c_p = schedule(c_p, reds_used);
ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p);
#ifdef DEBUG
- pid = c_p->id; /* Save for debugging purpouses */
+ pid = c_p->common.id; /* Save for debugging purpouses */
#endif
ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
PROCESS_MAIN_CHK_LOCKS(c_p);
@@ -1227,7 +1227,7 @@ void process_main(void)
reds = c_p->fcalls;
if (ERTS_PROC_GET_SAVED_CALLS_BUF(c_p)
- && (c_p->trace_flags & F_SENSITIVE) == 0) {
+ && (ERTS_TRACE_FLAGS(c_p) & F_SENSITIVE) == 0) {
neg_o_reds = -reds;
FCALLS = REDS_IN(c_p) = 0;
} else {
@@ -1591,6 +1591,7 @@ void process_main(void)
reg[0] = r(0);
result = erl_send(c_p, r(0), x(1));
PreFetch(0, next);
+ ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p);
ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
PROCESS_MAIN_CHK_LOCKS(c_p);
if (c_p->mbuf || MSO(c_p).overhead >= BIN_VHEAP_SZ(c_p)) {
@@ -1866,14 +1867,14 @@ void process_main(void)
erts_fprintf(stderr,
"Dtrace -> (%T) stop spreading "
"tag %T with message %T\r\n",
- c_p->id,DT_UTAG(c_p),ERL_MESSAGE_TERM(msgp));
+ c_p->common.id,DT_UTAG(c_p),ERL_MESSAGE_TERM(msgp));
#endif
} else {
#ifdef DTRACE_TAG_HARDDEBUG
erts_fprintf(stderr,
"Dtrace -> (%T) kill tag %T with "
"message %T\r\n",
- c_p->id,DT_UTAG(c_p),ERL_MESSAGE_TERM(msgp));
+ c_p->common.id,DT_UTAG(c_p),ERL_MESSAGE_TERM(msgp));
#endif
DT_UTAG(c_p) = NIL;
SEQ_TRACE_TOKEN(c_p) = NIL;
@@ -1898,7 +1899,7 @@ void process_main(void)
erts_fprintf(stderr,
"Dtrace -> (%T) receive tag (%T) "
"with message %T\r\n",
- c_p->id, DT_UTAG(c_p), ERL_MESSAGE_TERM(msgp));
+ c_p->common.id, DT_UTAG(c_p), ERL_MESSAGE_TERM(msgp));
#endif
} else {
#endif
@@ -1914,7 +1915,7 @@ void process_main(void)
}
msg = ERL_MESSAGE_TERM(msgp);
seq_trace_output(SEQ_TRACE_TOKEN(c_p), msg, SEQ_TRACE_RECEIVE,
- c_p->id, c_p);
+ c_p->common.id, c_p);
#ifdef USE_VM_PROBES
}
#endif
@@ -2567,6 +2568,7 @@ void process_main(void)
reg[0] = r(0);
result = (*bf)(c_p, reg, I);
ASSERT(!ERTS_PROC_IS_EXITING(c_p) || is_non_value(result));
+ ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p);
ERTS_HOLE_CHECK(c_p);
ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
PROCESS_MAIN_CHK_LOCKS(c_p);
@@ -3301,7 +3303,6 @@ void process_main(void)
PROCESS_MAIN_CHK_LOCKS(c_p);
bif_nif_arity = I[-1];
ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p);
- ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p);
ASSERT(!ERTS_PROC_IS_EXITING(c_p));
{
@@ -3346,7 +3347,6 @@ void process_main(void)
bif_nif_arity = I[-1];
ASSERT(bif_nif_arity <= 3);
ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p);
- ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p);
reg[0] = r(0);
{
Eterm (*bf)(Process*, Eterm*, BeamInstr*) = vbf;
@@ -5257,7 +5257,7 @@ terminate_proc(Process* c_p, Eterm Value)
/* EXF_LOG is a primary exception flag */
if (c_p->freason & EXF_LOG) {
erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
- erts_dsprintf(dsbufp, "Error in process %T ", c_p->id);
+ erts_dsprintf(dsbufp, "Error in process %T ", c_p->common.id);
if (erts_is_alive)
erts_dsprintf(dsbufp, "on node %T ", erts_this_node->sysname);
erts_dsprintf(dsbufp,"with exit value: %0.*T\n", display_items, Value);
@@ -6186,7 +6186,7 @@ new_fun(Process* p, Eterm* reg, ErlFunEntry* fe, int num_free)
MSO(p).first = (struct erl_off_heap_header*) funp;
funp->fe = fe;
funp->num_free = num_free;
- funp->creator = p->id;
+ funp->creator = p->common.id;
#ifdef HIPE
funp->native_address = fe->native_address;
#endif
diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c
index 25ae480dc7..b51f076a5d 100644
--- a/erts/emulator/beam/beam_load.c
+++ b/erts/emulator/beam/beam_load.c
@@ -756,7 +756,7 @@ erts_finish_loading(Binary* magic, Process* c_p,
* table which is not protected by any locks.
*/
- ERTS_SMP_LC_ASSERT(erts_initialized == 0 || erts_is_code_ix_locked() ||
+ ERTS_SMP_LC_ASSERT(erts_initialized == 0 || erts_has_code_write_permission() ||
erts_smp_thr_progress_is_blocking());
/*
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index 1cdce49eef..97c8114437 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -37,10 +37,13 @@
#include "erl_db_util.h"
#include "register.h"
#include "erl_thr_progress.h"
+#define ERTS_PTAB_WANT_BIF_IMPL__
+#include "erl_ptab.h"
static Export* flush_monitor_message_trap = NULL;
static Export* set_cpu_topology_trap = NULL;
static Export* await_proc_exit_trap = NULL;
+static Export* await_port_send_result_trap = NULL;
Export* erts_format_cpu_topology_trap = NULL;
static Export *await_sched_wall_time_mod_trap;
@@ -83,8 +86,10 @@ static int insert_internal_link(Process* p, Eterm rpid)
ASSERT(is_internal_pid(rpid));
#ifdef ERTS_SMP
- if (IS_TRACED(p) && (p->trace_flags & (F_TRACE_SOL|F_TRACE_SOL1)))
+ if (IS_TRACED(p)
+ && (ERTS_TRACE_FLAGS(p) & (F_TRACE_SOL|F_TRACE_SOL1))) {
rp_locks = ERTS_PROC_LOCKS_ALL;
+ }
erts_smp_proc_lock(p, ERTS_PROC_LOCK_LINK);
#endif
@@ -100,27 +105,27 @@ static int insert_internal_link(Process* p, Eterm rpid)
}
if (p != rp) {
- erts_add_link(&(p->nlinks), LINK_PID, rp->id);
- erts_add_link(&(rp->nlinks), LINK_PID, p->id);
+ erts_add_link(&ERTS_P_LINKS(p), LINK_PID, rp->common.id);
+ erts_add_link(&ERTS_P_LINKS(rp), LINK_PID, p->common.id);
- ASSERT(is_nil(p->tracer_proc)
- || is_internal_pid(p->tracer_proc)
- || is_internal_port(p->tracer_proc));
+ ASSERT(is_nil(ERTS_TRACER_PROC(p))
+ || is_internal_pid(ERTS_TRACER_PROC(p))
+ || is_internal_port(ERTS_TRACER_PROC(p)));
if (IS_TRACED(p)) {
- if (p->trace_flags & (F_TRACE_SOL|F_TRACE_SOL1)) {
- rp->trace_flags |= (p->trace_flags & TRACEE_FLAGS);
- rp->tracer_proc = p->tracer_proc; /* maybe steal */
+ if (ERTS_TRACE_FLAGS(p) & (F_TRACE_SOL|F_TRACE_SOL1)) {
+ ERTS_TRACE_FLAGS(rp) |= (ERTS_TRACE_FLAGS(p) & TRACEE_FLAGS);
+ ERTS_TRACER_PROC(rp) = ERTS_TRACER_PROC(p); /* maybe steal */
- if (p->trace_flags & F_TRACE_SOL1) { /* maybe override */
- rp->trace_flags &= ~(F_TRACE_SOL1 | F_TRACE_SOL);
- p->trace_flags &= ~(F_TRACE_SOL1 | F_TRACE_SOL);
+ if (ERTS_TRACE_FLAGS(p) & F_TRACE_SOL1) { /* maybe override */
+ ERTS_TRACE_FLAGS(rp) &= ~(F_TRACE_SOL1 | F_TRACE_SOL);
+ ERTS_TRACE_FLAGS(p) &= ~(F_TRACE_SOL1 | F_TRACE_SOL);
}
}
}
}
if (IS_TRACED_FL(rp, F_TRACE_PROCS))
- trace_proc(p, rp, am_getting_linked, p->id);
+ trace_proc(p, rp, am_getting_linked, p->common.id);
if (p == rp)
erts_smp_proc_unlock(p, rp_locks & ~ERTS_PROC_LOCK_MAIN);
@@ -144,10 +149,6 @@ BIF_RETTYPE link_1(BIF_ALIST_1)
/* check that the pid or port which is our argument is OK */
if (is_internal_pid(BIF_ARG_1)) {
- if (internal_pid_index(BIF_ARG_1) >= erts_max_processes) {
- BIF_ERROR(BIF_P, BADARG);
- }
-
if (insert_internal_link(BIF_P, BIF_ARG_1)) {
BIF_RET(am_true);
}
@@ -157,19 +158,37 @@ BIF_RETTYPE link_1(BIF_ALIST_1)
}
if (is_internal_port(BIF_ARG_1)) {
- Port *pt = erts_id2port(BIF_ARG_1, BIF_P, ERTS_PROC_LOCK_MAIN);
- if (!pt) {
+ int send_link_signal = 0;
+ Port *prt = erts_port_lookup(BIF_ARG_1, ERTS_PORT_SFLGS_INVALID_LOOKUP);
+ if (!prt) {
goto res_no_proc;
}
erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_LINK);
- if (erts_add_link(&(BIF_P->nlinks), LINK_PID, BIF_ARG_1) >= 0)
- erts_add_link(&(pt->nlinks), LINK_PID, BIF_P->id);
+ if (erts_add_link(&ERTS_P_LINKS(BIF_P), LINK_PID, BIF_ARG_1) >= 0)
+ send_link_signal = 1;
/* else: already linked */
erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_LINK);
- erts_smp_port_unlock(pt);
+
+ if (send_link_signal) {
+ Eterm ref;
+ Eterm *refp = erts_port_synchronous_ops ? &ref : NULL;
+
+ switch (erts_port_link(BIF_P, prt, BIF_P->common.id, refp)) {
+ case ERTS_PORT_OP_DROPPED:
+ case ERTS_PORT_OP_BADARG:
+ goto res_no_proc;
+ case ERTS_PORT_OP_SCHEDULED:
+ if (refp) {
+ ASSERT(is_internal_ref(ref));
+ BIF_TRAP3(await_port_send_result_trap, BIF_P, ref, am_true, am_true);
+ }
+ default:
+ break;
+ }
+ }
BIF_RET(am_true);
}
else if (is_external_port(BIF_ARG_1)
@@ -182,7 +201,7 @@ BIF_RETTYPE link_1(BIF_ALIST_1)
erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_LINK);
/* We may earn time by checking first that we're not linked already */
- if (erts_lookup_link(BIF_P->nlinks, BIF_ARG_1) != NULL) {
+ if (erts_lookup_link(ERTS_P_LINKS(BIF_P), BIF_ARG_1) != NULL) {
erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_LINK);
BIF_RET(am_true);
}
@@ -209,10 +228,10 @@ BIF_RETTYPE link_1(BIF_ALIST_1)
erts_smp_de_links_lock(dep);
- erts_add_link(&(BIF_P->nlinks), LINK_PID, BIF_ARG_1);
+ erts_add_link(&ERTS_P_LINKS(BIF_P), LINK_PID, BIF_ARG_1);
lnk = erts_add_or_lookup_link(&(dep->nlinks),
LINK_PID,
- BIF_P->id);
+ BIF_P->common.id);
ASSERT(lnk != NULL);
erts_add_link(&ERTS_LINK_ROOT(lnk), LINK_PID, BIF_ARG_1);
@@ -220,7 +239,7 @@ BIF_RETTYPE link_1(BIF_ALIST_1)
erts_smp_de_runlock(dep);
erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_LINK);
- code = erts_dsig_send_link(&dsd, BIF_P->id, BIF_ARG_1);
+ code = erts_dsig_send_link(&dsd, BIF_P->common.id, BIF_ARG_1);
if (code == ERTS_DSIG_SEND_YIELD)
ERTS_BIF_YIELD_RETURN(BIF_P, am_true);
BIF_RET(am_true);
@@ -289,7 +308,7 @@ remote_demonitor(Process *c_p, DistEntry *dep, Eterm ref, Eterm to)
if (dmon)
erts_destroy_monitor(dmon);
}
- mon = erts_remove_monitor(&c_p->monitors, ref);
+ mon = erts_remove_monitor(&ERTS_P_MONITORS(c_p), ref);
erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_LINK);
res = ERTS_DEMONITOR_TRUE;
@@ -298,7 +317,7 @@ remote_demonitor(Process *c_p, DistEntry *dep, Eterm ref, Eterm to)
case ERTS_DSIG_PREP_CONNECTED:
erts_smp_de_links_lock(dep);
- mon = erts_remove_monitor(&c_p->monitors, ref);
+ mon = erts_remove_monitor(&ERTS_P_MONITORS(c_p), ref);
dmon = erts_remove_monitor(&dep->monitors, ref);
erts_smp_de_links_unlock(dep);
erts_smp_de_runlock(dep);
@@ -325,7 +344,7 @@ remote_demonitor(Process *c_p, DistEntry *dep, Eterm ref, Eterm to)
* the atom is stored there. Yield if necessary.
*/
code = erts_dsig_send_demonitor(&dsd,
- c_p->id,
+ c_p->common.id,
(mon->name != NIL
? mon->name
: mon->pid),
@@ -387,7 +406,7 @@ static int demonitor(Process *c_p, Eterm ref)
goto done; /* Cannot be this monitor's ref */
}
- mon = erts_lookup_monitor(c_p->monitors, ref);
+ mon = erts_lookup_monitor(ERTS_P_MONITORS(c_p), ref);
if (!mon) {
res = ERTS_DEMONITOR_FALSE;
goto done;
@@ -426,7 +445,7 @@ static int demonitor(Process *c_p, Eterm ref)
to,
ERTS_PROC_LOCK_LINK,
ERTS_P2P_FLG_ALLOW_OTHER_X);
- mon = erts_remove_monitor(&c_p->monitors, ref);
+ mon = erts_remove_monitor(&ERTS_P_MONITORS(c_p), ref);
#ifndef ERTS_SMP
ASSERT(mon);
#else
@@ -440,7 +459,7 @@ static int demonitor(Process *c_p, Eterm ref)
}
if (rp) {
ErtsMonitor *rmon;
- rmon = erts_remove_monitor(&(rp->monitors), ref);
+ rmon = erts_remove_monitor(&ERTS_P_MONITORS(rp), ref);
if (rp != c_p)
erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_LINK);
if (rmon != NULL)
@@ -582,7 +601,7 @@ local_pid_monitor(Process *p, Eterm target)
mon_ref = erts_make_ref(p);
ERTS_BIF_PREP_RET(ret, mon_ref);
- if (target == p->id) {
+ if (target == p->common.id) {
return ret;
}
@@ -599,8 +618,8 @@ local_pid_monitor(Process *p, Eterm target)
else {
ASSERT(rp != p);
- erts_add_monitor(&(p->monitors), MON_ORIGIN, mon_ref, target, NIL);
- erts_add_monitor(&(rp->monitors), MON_TARGET, mon_ref, p->id, NIL);
+ erts_add_monitor(&ERTS_P_MONITORS(p), MON_ORIGIN, mon_ref, target, NIL);
+ erts_add_monitor(&ERTS_P_MONITORS(rp), MON_TARGET, mon_ref, p->common.id, NIL);
erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_LINK);
}
@@ -635,9 +654,9 @@ local_name_monitor(Process *p, Eterm target_name)
UnUseTmpHeap(3,p);
}
else if (rp != p) {
- erts_add_monitor(&(p->monitors), MON_ORIGIN, mon_ref, rp->id,
+ erts_add_monitor(&ERTS_P_MONITORS(p), MON_ORIGIN, mon_ref, rp->common.id,
target_name);
- erts_add_monitor(&(rp->monitors), MON_TARGET, mon_ref, p->id,
+ erts_add_monitor(&ERTS_P_MONITORS(rp), MON_TARGET, mon_ref, p->common.id,
target_name);
erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_LINK);
}
@@ -689,16 +708,16 @@ remote_monitor(Process *p, Eterm bifarg1, Eterm bifarg2,
erts_smp_de_links_lock(dep);
- erts_add_monitor(&(p->monitors), MON_ORIGIN, mon_ref, p_trgt,
+ erts_add_monitor(&ERTS_P_MONITORS(p), MON_ORIGIN, mon_ref, p_trgt,
p_name);
- erts_add_monitor(&(dep->monitors), MON_TARGET, mon_ref, p->id,
+ erts_add_monitor(&(dep->monitors), MON_TARGET, mon_ref, p->common.id,
d_name);
erts_smp_de_links_unlock(dep);
erts_smp_de_runlock(dep);
erts_smp_proc_unlock(p, ERTS_PROC_LOCK_LINK);
- code = erts_dsig_send_monitor(&dsd, p->id, target, mon_ref);
+ code = erts_dsig_send_monitor(&dsd, p->common.id, target, mon_ref);
if (code == ERTS_DSIG_SEND_YIELD)
ERTS_BIF_PREP_YIELD_RETURN(ret, p, mon_ref);
else
@@ -941,36 +960,39 @@ BIF_RETTYPE unlink_1(BIF_ALIST_1)
}
if (is_internal_port(BIF_ARG_1)) {
- Port *pt = erts_id2port_sflgs(BIF_ARG_1,
- BIF_P,
- ERTS_PROC_LOCK_MAIN,
- ERTS_PORT_SFLGS_DEAD);
-
erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_LINK|ERTS_PROC_LOCK_STATUS);
#ifdef ERTS_SMP
- if (ERTS_PROC_PENDING_EXIT(BIF_P)) {
- if (pt)
- erts_smp_port_unlock(pt);
+ if (ERTS_PROC_PENDING_EXIT(BIF_P))
goto handle_pending_exit;
- }
#endif
- l = erts_remove_link(&BIF_P->nlinks, BIF_ARG_1);
-
- ASSERT(pt || !l);
-
- if (pt) {
- rl = erts_remove_link(&pt->nlinks, BIF_P->id);
- erts_smp_port_unlock(pt);
- if (rl)
- erts_destroy_link(rl);
- }
+ l = erts_remove_link(&ERTS_P_LINKS(BIF_P), BIF_ARG_1);
erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_LINK|ERTS_PROC_LOCK_STATUS);
- if (l)
+ if (l) {
+ Port *prt;
+
erts_destroy_link(l);
+ /* Send unlink signal */
+ prt = erts_port_lookup(BIF_ARG_1, ERTS_PORT_SFLGS_DEAD);
+ if (prt) {
+ ErtsPortOpResult res;
+ Eterm ref;
+ Eterm *refp = erts_port_synchronous_ops ? &ref : NULL;
+#ifdef DEBUG
+ ref = NIL;
+#endif
+ res = erts_port_unlink(BIF_P, prt, BIF_P->common.id, refp);
+
+ if (refp && res == ERTS_PORT_OP_SCHEDULED) {
+ ASSERT(is_internal_ref(ref));
+ BIF_TRAP3(await_port_send_result_trap, BIF_P, ref, am_true, am_true);
+ }
+ }
+ }
+
BIF_RET(am_true);
}
else if (is_external_port(BIF_ARG_1)
@@ -993,7 +1015,7 @@ BIF_RETTYPE unlink_1(BIF_ALIST_1)
if (ERTS_PROC_PENDING_EXIT(BIF_P))
goto handle_pending_exit;
#endif
- l = erts_remove_link(&BIF_P->nlinks,BIF_ARG_1);
+ l = erts_remove_link(&ERTS_P_LINKS(BIF_P), BIF_ARG_1);
erts_smp_proc_unlock(BIF_P,
ERTS_PROC_LOCK_LINK|ERTS_PROC_LOCK_STATUS);
@@ -1022,8 +1044,8 @@ BIF_RETTYPE unlink_1(BIF_ALIST_1)
#endif
case ERTS_DSIG_PREP_CONNECTED:
- erts_remove_dist_link(&dld, BIF_P->id, BIF_ARG_1, dep);
- code = erts_dsig_send_unlink(&dsd, BIF_P->id, BIF_ARG_1);
+ erts_remove_dist_link(&dld, BIF_P->common.id, BIF_ARG_1, dep);
+ code = erts_dsig_send_unlink(&dsd, BIF_P->common.id, BIF_ARG_1);
erts_destroy_dist_link(&dld);
if (code == ERTS_DSIG_SEND_YIELD)
ERTS_BIF_YIELD_RETURN(BIF_P, am_true);
@@ -1037,10 +1059,6 @@ BIF_RETTYPE unlink_1(BIF_ALIST_1)
/* Internal pid... */
- /* process ok ? */
- if (internal_pid_index(BIF_ARG_1) >= erts_max_processes)
- BIF_ERROR(BIF_P, BADARG);
-
erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_LINK|ERTS_PROC_LOCK_STATUS);
/* get process struct */
@@ -1059,7 +1077,7 @@ BIF_RETTYPE unlink_1(BIF_ALIST_1)
#endif
/* unlink and ignore errors */
- l = erts_remove_link(&BIF_P->nlinks,BIF_ARG_1);
+ l = erts_remove_link(&ERTS_P_LINKS(BIF_P), BIF_ARG_1);
if (l != NULL)
erts_destroy_link(l);
@@ -1067,12 +1085,12 @@ BIF_RETTYPE unlink_1(BIF_ALIST_1)
ERTS_SMP_ASSERT_IS_NOT_EXITING(BIF_P);
}
else {
- rl = erts_remove_link(&(rp->nlinks),BIF_P->id);
+ rl = erts_remove_link(&ERTS_P_LINKS(rp), BIF_P->common.id);
if (rl != NULL)
erts_destroy_link(rl);
if (IS_TRACED_FL(rp, F_TRACE_PROCS) && rl != NULL) {
- trace_proc(BIF_P, rp, am_getting_unlinked, BIF_P->id);
+ trace_proc(BIF_P, rp, am_getting_unlinked, BIF_P->common.id);
}
if (rp != BIF_P)
@@ -1345,15 +1363,28 @@ BIF_RETTYPE exit_2(BIF_ALIST_2)
*/
if (is_internal_port(BIF_ARG_1)) {
- Port *prt;
- erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
- prt = erts_id2port(BIF_ARG_1, NULL, 0);
+ Port *prt = erts_port_lookup(BIF_ARG_1, ERTS_PORT_SFLGS_INVALID_LOOKUP);
+
if (prt) {
- erts_do_exit_port(prt, BIF_P->id, BIF_ARG_2);
- erts_port_release(prt);
+ Eterm ref;
+ Eterm *refp = erts_port_synchronous_ops ? &ref : NULL;
+ ErtsPortOpResult res;
+
+#ifdef DEBUG
+ ref = NIL;
+#endif
+
+ res = erts_port_exit(BIF_P, 0, prt, BIF_P->common.id, BIF_ARG_2, refp);
+
+ ERTS_BIF_CHK_EXITED(BIF_P);
+
+ if (refp && res == ERTS_PORT_OP_SCHEDULED) {
+ ASSERT(is_internal_ref(ref));
+ BIF_TRAP3(await_port_send_result_trap, BIF_P, ref, am_true, am_true);
+ }
+
}
- erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
- ERTS_BIF_CHK_EXITED(BIF_P);
+
BIF_RET(am_true);
}
else if(is_external_port(BIF_ARG_1)
@@ -1379,7 +1410,7 @@ BIF_RETTYPE exit_2(BIF_ALIST_2)
case ERTS_DSIG_PREP_NOT_CONNECTED:
BIF_TRAP2(dexit_trap, BIF_P, BIF_ARG_1, BIF_ARG_2);
case ERTS_DSIG_PREP_CONNECTED:
- code = erts_dsig_send_exit2(&dsd, BIF_P->id, BIF_ARG_1, BIF_ARG_2);
+ code = erts_dsig_send_exit2(&dsd, BIF_P->common.id, BIF_ARG_1, BIF_ARG_2);
if (code == ERTS_DSIG_SEND_YIELD)
ERTS_BIF_YIELD_RETURN(BIF_P, am_true);
BIF_RET(am_true);
@@ -1397,9 +1428,7 @@ BIF_RETTYPE exit_2(BIF_ALIST_2)
*/
ErtsProcLocks rp_locks;
- if (internal_pid_index(BIF_ARG_1) >= erts_max_processes)
- BIF_ERROR(BIF_P, BADARG);
- if (BIF_ARG_1 == BIF_P->id) {
+ if (BIF_ARG_1 == BIF_P->common.id) {
rp_locks = ERTS_PROC_LOCKS_ALL;
rp = BIF_P;
erts_smp_proc_lock(rp, ERTS_PROC_LOCKS_ALL_MINOR);
@@ -1417,7 +1446,7 @@ BIF_RETTYPE exit_2(BIF_ALIST_2)
* Send an exit signal.
*/
erts_send_exit_signal(BIF_P,
- BIF_P->id,
+ BIF_P->common.id,
rp,
&rp_locks,
BIF_ARG_2,
@@ -1519,22 +1548,24 @@ BIF_RETTYPE process_flag_2(BIF_ALIST_2)
}
/*
* NOTE: It is important that we check for pending exit signals
- * and handle them before flag trap_exit is set to true.
- * For more info, see implementation of erts_send_exit_signal().
+ * and handle them before returning if trap_exit is set to
+ * true. For more info, see implementation of
+ * erts_send_exit_signal().
*/
- erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_STATUS);
- ERTS_SMP_LC_ASSERT((ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS)
- & erts_proc_lc_my_proc_locks(BIF_P));
- ERTS_SMP_BIF_CHK_PENDING_EXIT(BIF_P,
- ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS);
if (trap_exit)
- state = erts_smp_atomic32_read_bor_nob(&BIF_P->state,
- ERTS_PSFLG_TRAP_EXIT);
+ state = erts_smp_atomic32_read_bor_mb(&BIF_P->state,
+ ERTS_PSFLG_TRAP_EXIT);
else
- state = erts_smp_atomic32_read_band_nob(&BIF_P->state,
- ~ERTS_PSFLG_TRAP_EXIT);
+ state = erts_smp_atomic32_read_band_mb(&BIF_P->state,
+ ~ERTS_PSFLG_TRAP_EXIT);
+#ifdef ERTS_SMP
+ if (ERTS_PROC_PENDING_EXIT(BIF_P)) {
+ erts_handle_pending_exit(BIF_P, ERTS_PROC_LOCK_MAIN);
+ ERTS_BIF_EXITED(BIF_P);
+ }
+#endif
+
old_value = (state & ERTS_PSFLG_TRAP_EXIT) ? am_true : am_false;
- erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_STATUS);
BIF_RET(old_value);
}
else if (BIF_ARG_1 == am_scheduler) {
@@ -1617,11 +1648,13 @@ BIF_RETTYPE process_flag_2(BIF_ALIST_2)
goto error;
}
erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCKS_ALL_MINOR);
- old_value = BIF_P->trace_flags & F_SENSITIVE ? am_true : am_false;
+ old_value = (ERTS_TRACE_FLAGS(BIF_P) & F_SENSITIVE
+ ? am_true
+ : am_false);
if (is_sensitive) {
- BIF_P->trace_flags |= F_SENSITIVE;
+ ERTS_TRACE_FLAGS(BIF_P) |= F_SENSITIVE;
} else {
- BIF_P->trace_flags &= ~F_SENSITIVE;
+ ERTS_TRACE_FLAGS(BIF_P) &= ~F_SENSITIVE;
}
erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCKS_ALL_MINOR);
BIF_RET(old_value);
@@ -1747,8 +1780,9 @@ ebif_bang_2(BIF_ALIST_2)
#define SEND_BADARG (-4)
#define SEND_USER_ERROR (-5)
#define SEND_INTERNAL_ERROR (-6)
+#define SEND_AWAIT_RESULT (-7)
-Sint do_send(Process *p, Eterm to, Eterm msg, int suspend);
+Sint do_send(Process *p, Eterm to, Eterm msg, int suspend, Eterm *refp);
static Sint remote_send(Process *p, DistEntry *dep,
Eterm to, Eterm full_to, Eterm msg, int suspend)
@@ -1802,7 +1836,7 @@ static Sint remote_send(Process *p, DistEntry *dep,
}
Sint
-do_send(Process *p, Eterm to, Eterm msg, int suspend) {
+do_send(Process *p, Eterm to, Eterm msg, int suspend, Eterm *refp) {
Eterm portid;
Port *pt;
Process* rp;
@@ -1814,16 +1848,10 @@ do_send(Process *p, Eterm to, Eterm msg, int suspend) {
trace_send(p, to, msg);
if (ERTS_PROC_GET_SAVED_CALLS_BUF(p))
save_calls(p, &exp_send);
-
- if (internal_pid_index(to) >= erts_max_processes)
- return SEND_BADARG;
- rp = erts_proc_lookup_raw(to);
-
- if (!rp) {
- ERTS_SMP_ASSERT_IS_NOT_EXITING(p);
+ rp = erts_proc_lookup_raw(to);
+ if (!rp)
return 0;
- }
} else if (is_external_pid(to)) {
dep = external_pid_dist_entry(to);
if(dep == erts_this_dist_entry) {
@@ -1832,7 +1860,7 @@ do_send(Process *p, Eterm to, Eterm msg, int suspend) {
"Discarding message %T from %T to %T in an old "
"incarnation (%d) of this node (%d)\n",
msg,
- p->id,
+ p->common.id,
to,
external_pid_creation(to),
erts_this_node->creation);
@@ -1841,45 +1869,24 @@ do_send(Process *p, Eterm to, Eterm msg, int suspend) {
}
return remote_send(p, dep, to, to, msg, suspend);
} else if (is_atom(to)) {
-
- /* Need to virtual schedule out sending process
- * because of lock wait. This is only necessary
- * for internal port calling but the lock is bundled
- * with name lookup.
- */
-
- if (IS_TRACED_FL(p, F_TRACE_SCHED_PROCS)) {
- trace_virtual_sched(p, am_out);
- }
- if (erts_system_profile_flags.runnable_procs && erts_system_profile_flags.exclusive) {
- profile_runnable_proc(p, am_inactive);
- }
- erts_whereis_name(p, ERTS_PROC_LOCK_MAIN,
- to,
- &rp, 0, 0,
- &pt);
+ Eterm id = erts_whereis_name_to_id(p, to);
+ rp = erts_proc_lookup(id);
+ if (rp)
+ goto send_message;
+
+ pt = erts_port_lookup(id, ERTS_PORT_SFLGS_INVALID_LOOKUP);
if (pt) {
- portid = pt->id;
+ portid = id;
goto port_common;
}
-
- /* Not a port virtually schedule the process back in */
- if (IS_TRACED_FL(p, F_TRACE_SCHED_PROCS)) {
- trace_virtual_sched(p, am_in);
- }
- if (erts_system_profile_flags.runnable_procs && erts_system_profile_flags.exclusive) {
- profile_runnable_proc(p, am_active);
- }
if (IS_TRACED(p))
trace_send(p, to, msg);
if (ERTS_PROC_GET_SAVED_CALLS_BUF(p))
save_calls(p, &exp_send);
- if (!rp) {
- return SEND_BADARG;
- }
+ return SEND_BADARG;
} else if (is_external_port(to)
&& (external_port_dist_entry(to)
== erts_this_dist_entry)) {
@@ -1888,50 +1895,56 @@ do_send(Process *p, Eterm to, Eterm msg, int suspend) {
"Discarding message %T from %T to %T in an old "
"incarnation (%d) of this node (%d)\n",
msg,
- p->id,
+ p->common.id,
to,
external_port_creation(to),
erts_this_node->creation);
erts_send_error_to_logger(p->group_leader, dsbufp);
return 0;
} else if (is_internal_port(to)) {
+ int ret_val;
portid = to;
- /* schedule out calling process, waiting for lock*/
- if (IS_TRACED_FL(p, F_TRACE_SCHED_PROCS)) {
- trace_virtual_sched(p, am_out);
- }
- if (erts_system_profile_flags.runnable_procs && erts_system_profile_flags.exclusive) {
- profile_runnable_proc(p, am_inactive);
- }
- pt = erts_id2port(to, p, ERTS_PROC_LOCK_MAIN);
+
+ pt = erts_port_lookup(portid, ERTS_PORT_SFLGS_INVALID_LOOKUP);
+
port_common:
- ERTS_SMP_LC_ASSERT(!pt || erts_lc_is_port_locked(pt));
+ ret_val = 0;
- /* We have waited for locks, trace schedule ports */
- if (pt && IS_TRACED_FL(pt, F_TRACE_SCHED_PORTS)) {
- trace_sched_ports_where(pt, am_in, am_command);
- }
- if (pt && erts_system_profile_flags.runnable_ports && !erts_port_is_scheduled(pt)) {
- profile_runnable_port(pt, am_active);
- }
-
- /* XXX let port_command handle the busy stuff !!! */
- if (pt && (pt->status & ERTS_PORT_SFLG_PORT_BUSY)) {
- if (suspend) {
- erts_suspend(p, ERTS_PROC_LOCK_MAIN, pt);
- if (erts_system_monitor_flags.busy_port) {
- monitor_generic(p, am_busy_port, portid);
+ if (pt) {
+ int ps_flags = suspend ? 0 : ERTS_PORT_SIG_FLG_NOSUSPEND;
+ *refp = NIL;
+
+ switch (erts_port_command(p, ps_flags, pt, msg, refp)) {
+ case ERTS_PORT_OP_CALLER_EXIT:
+ /* We are exiting... */
+ return SEND_USER_ERROR;
+ case ERTS_PORT_OP_BUSY:
+ /* Nothing has been sent */
+ if (suspend)
+ erts_suspend(p, ERTS_PROC_LOCK_MAIN, pt);
+ return SEND_YIELD;
+ case ERTS_PORT_OP_BUSY_SCHEDULED:
+ /* Message was sent */
+ if (suspend) {
+ erts_suspend(p, ERTS_PROC_LOCK_MAIN, pt);
+ ret_val = SEND_YIELD_RETURN;
+ break;
}
+ /* Fall through */
+ case ERTS_PORT_OP_SCHEDULED:
+ if (is_not_nil(*refp)) {
+ ASSERT(is_internal_ref(*refp));
+ ret_val = SEND_AWAIT_RESULT;
+ }
+ break;
+ case ERTS_PORT_OP_DROPPED:
+ case ERTS_PORT_OP_BADARG:
+ case ERTS_PORT_OP_DONE:
+ break;
+ default:
+ ERTS_INTERNAL_ERROR("Unexpected erts_port_command() result");
+ break;
}
- /* Virtually schedule out the port before releasing */
- if (IS_TRACED_FL(pt, F_TRACE_SCHED_PORTS)) {
- trace_sched_ports_where(pt, am_out, am_command);
- }
- if (erts_system_profile_flags.runnable_ports && !erts_port_is_scheduled(pt)) {
- profile_runnable_port(pt, am_inactive);
- }
- erts_port_release(pt);
- return SEND_YIELD;
}
if (IS_TRACED(p)) /* trace once only !! */
@@ -1949,30 +1962,11 @@ do_send(Process *p, Eterm to, Eterm msg, int suspend) {
SEQ_TRACE_SEND, portid, p);
}
- /* XXX NO GC in port command */
- erts_port_command(p, p->id, pt, msg);
- if (pt) {
- /* Virtually schedule out the port before releasing */
- if (IS_TRACED_FL(pt, F_TRACE_SCHED_PORTS)) {
- trace_sched_ports_where(pt, am_out, am_command);
- }
- if (erts_system_profile_flags.runnable_ports && !erts_port_is_scheduled(pt)) {
- profile_runnable_port(pt, am_inactive);
- }
- erts_port_release(pt);
- }
- /* Virtually schedule in process */
- if (IS_TRACED_FL(p, F_TRACE_SCHED_PROCS)) {
- trace_virtual_sched(p, am_in);
- }
- if (erts_system_profile_flags.runnable_procs && erts_system_profile_flags.exclusive) {
- profile_runnable_proc(p, am_active);
- }
if (ERTS_PROC_IS_EXITING(p)) {
KILL_CATCHES(p); /* Must exit */
return SEND_USER_ERROR;
}
- return 0;
+ return ret_val;
} else if (is_tuple(to)) { /* Remote send */
int ret;
tp = tuple_val(to);
@@ -1988,47 +1982,24 @@ do_send(Process *p, Eterm to, Eterm msg, int suspend) {
dep = erts_sysname_to_connected_dist_entry(tp[2]);
if (dep == erts_this_dist_entry) {
+ Eterm id;
erts_deref_dist_entry(dep);
if (IS_TRACED(p))
trace_send(p, to, msg);
if (ERTS_PROC_GET_SAVED_CALLS_BUF(p))
save_calls(p, &exp_send);
-
- /* Need to virtual schedule out sending process
- * because of lock wait. This is only necessary
- * for internal port calling but the lock is bundled.
- */
-
- if (IS_TRACED_FL(p, F_TRACE_SCHED_PROCS)) {
- trace_virtual_sched(p, am_out);
- }
- if (erts_system_profile_flags.runnable_procs && erts_system_profile_flags.exclusive) {
- profile_runnable_proc(p, am_inactive);
- }
- erts_whereis_name(p, ERTS_PROC_LOCK_MAIN,
- tp[1],
- &rp, 0, 0,
- &pt);
+ id = erts_whereis_name_to_id(p, tp[1]);
+
+ rp = erts_proc_lookup_raw(id);
+ if (rp)
+ goto send_message;
+ pt = erts_port_lookup(id, ERTS_PORT_SFLGS_INVALID_LOOKUP);
if (pt) {
- portid = pt->id;
+ portid = id;
goto port_common;
}
- /* Port lookup failed, virtually schedule the process
- * back in.
- */
-
- if (IS_TRACED_FL(p, F_TRACE_SCHED_PROCS)) {
- trace_virtual_sched(p, am_in);
- }
- if (erts_system_profile_flags.runnable_procs && erts_system_profile_flags.exclusive) {
- profile_runnable_proc(p, am_active);
- }
-
- if (!rp) {
- return 0;
- }
- goto send_message;
+ return 0;
}
ret = remote_send(p, dep, tp[1], to, msg, suspend);
@@ -2067,6 +2038,7 @@ do_send(Process *p, Eterm to, Eterm msg, int suspend) {
BIF_RETTYPE send_3(BIF_ALIST_3)
{
+ Eterm ref;
Process *p = BIF_P;
Eterm to = BIF_ARG_1;
Eterm msg = BIF_ARG_2;
@@ -2090,12 +2062,18 @@ BIF_RETTYPE send_3(BIF_ALIST_3)
if(!is_nil(l)) {
BIF_ERROR(p, BADARG);
}
-
- result = do_send(p, to, msg, suspend);
+
+#ifdef DEBUG
+ ref = NIL;
+#endif
+
+ result = do_send(p, to, msg, suspend, &ref);
if (result > 0) {
ERTS_VBUMP_REDS(p, result);
BIF_RET(am_ok);
- } else switch (result) {
+ }
+
+ switch (result) {
case 0:
BIF_RET(am_ok);
break;
@@ -2118,6 +2096,9 @@ BIF_RETTYPE send_3(BIF_ALIST_3)
ERTS_BIF_YIELD_RETURN(p, am_ok);
else
BIF_RET(am_nosuspend);
+ case SEND_AWAIT_RESULT:
+ ASSERT(is_internal_ref(ref));
+ BIF_TRAP3(await_port_send_result_trap, p, ref, am_nosuspend, am_ok);
case SEND_BADARG:
BIF_ERROR(p, BADARG);
break;
@@ -2142,12 +2123,21 @@ BIF_RETTYPE send_2(BIF_ALIST_2)
Eterm erl_send(Process *p, Eterm to, Eterm msg)
{
- Sint result = do_send(p, to, msg, !0);
+ Eterm ref;
+ Sint result;
+
+#ifdef DEBUG
+ ref = NIL;
+#endif
+
+ result = do_send(p, to, msg, !0, &ref);
if (result > 0) {
ERTS_VBUMP_REDS(p, result);
BIF_RET(msg);
- } else switch (result) {
+ }
+
+ switch (result) {
case 0:
BIF_RET(msg);
break;
@@ -2159,6 +2149,9 @@ Eterm erl_send(Process *p, Eterm to, Eterm msg)
break;
case SEND_YIELD_RETURN:
ERTS_BIF_YIELD_RETURN(p, msg);
+ case SEND_AWAIT_RESULT:
+ ASSERT(is_internal_ref(ref));
+ BIF_TRAP3(await_port_send_result_trap, p, ref, msg, msg);
case SEND_BADARG:
BIF_ERROR(p, BADARG);
break;
@@ -2428,9 +2421,7 @@ BIF_RETTYPE setelement_3(BIF_ALIST_3)
/* copy the tuple */
resp = hp;
- while (size--) { /* XXX use memcpy? */
- *hp++ = *ptr++;
- }
+ sys_memcpy(hp, ptr, sizeof(Eterm)*size);
resp[ix] = BIF_ARG_3;
BIF_RET(make_tuple(resp));
}
@@ -2443,7 +2434,7 @@ BIF_RETTYPE make_tuple_2(BIF_ALIST_2)
Eterm* hp;
Eterm res;
- if (is_not_small(BIF_ARG_1) || (n = signed_val(BIF_ARG_1)) < 0) {
+ if (is_not_small(BIF_ARG_1) || (n = signed_val(BIF_ARG_1)) < 0 || n > ERTS_MAX_TUPLE_SIZE) {
BIF_ERROR(BIF_P, BADARG);
}
hp = HAlloc(BIF_P, n+1);
@@ -2464,7 +2455,7 @@ BIF_RETTYPE make_tuple_3(BIF_ALIST_3)
Eterm list = BIF_ARG_3;
Eterm* tup;
- if (is_not_small(BIF_ARG_1) || (n = signed_val(BIF_ARG_1)) < 0) {
+ if (is_not_small(BIF_ARG_1) || (n = signed_val(BIF_ARG_1)) < 0 || n > ERTS_MAX_TUPLE_SIZE) {
error:
BIF_ERROR(BIF_P, BADARG);
}
@@ -2516,11 +2507,16 @@ BIF_RETTYPE append_element_2(BIF_ALIST_2)
Eterm res;
if (is_not_tuple(BIF_ARG_1)) {
+ error:
BIF_ERROR(BIF_P, BADARG);
}
- ptr = tuple_val(BIF_ARG_1);
+ ptr = tuple_val(BIF_ARG_1);
arity = arityval(*ptr);
- hp = HAlloc(BIF_P, arity + 2);
+
+ if (arity + 1 > ERTS_MAX_TUPLE_SIZE)
+ goto error;
+
+ hp = HAlloc(BIF_P, arity + 2);
res = make_tuple(hp);
*hp = make_arityval(arity+1);
while (arity--) {
@@ -2530,6 +2526,78 @@ BIF_RETTYPE append_element_2(BIF_ALIST_2)
BIF_RET(res);
}
+BIF_RETTYPE insert_element_3(BIF_ALIST_3)
+{
+ Eterm* ptr;
+ Eterm* hp;
+ Uint arity;
+ Eterm res;
+ Sint ix;
+
+ if (is_not_tuple(BIF_ARG_2) || is_not_small(BIF_ARG_1)) {
+ BIF_ERROR(BIF_P, BADARG);
+ }
+
+ ptr = tuple_val(BIF_ARG_2);
+ arity = arityval(*ptr);
+ ix = signed_val(BIF_ARG_1);
+
+ if ((ix < 1) || (ix > (arity + 1))) {
+ BIF_ERROR(BIF_P, BADARG);
+ }
+
+ hp = HAlloc(BIF_P, arity + 1 + 1);
+ res = make_tuple(hp);
+ *hp = make_arityval(arity + 1);
+
+ ix--;
+ arity -= ix;
+
+ while (ix--) { *++hp = *++ptr; }
+
+ *++hp = BIF_ARG_3;
+
+ while(arity--) { *++hp = *++ptr; }
+
+ BIF_RET(res);
+}
+
+BIF_RETTYPE delete_element_2(BIF_ALIST_3)
+{
+ Eterm* ptr;
+ Eterm* hp;
+ Uint arity;
+ Eterm res;
+ Sint ix;
+
+ if (is_not_tuple(BIF_ARG_2) || is_not_small(BIF_ARG_1)) {
+ BIF_ERROR(BIF_P, BADARG);
+ }
+
+ ptr = tuple_val(BIF_ARG_2);
+ arity = arityval(*ptr);
+ ix = signed_val(BIF_ARG_1);
+
+ if ((ix < 1) || (ix > arity) || (arity == 0)) {
+ BIF_ERROR(BIF_P, BADARG);
+ }
+
+ hp = HAlloc(BIF_P, arity + 1 - 1);
+ res = make_tuple(hp);
+ *hp = make_arityval(arity - 1);
+
+ ix--;
+ arity -= ix;
+
+ while (ix--) { *++hp = *++ptr; }
+
+ ++ptr;
+
+ while(arity--) { *++hp = *++ptr; }
+
+ BIF_RET(res);
+}
+
/**********************************************************************/
/* convert an atom to a list of ascii integer */
@@ -3104,7 +3172,7 @@ BIF_RETTYPE list_to_tuple_1(BIF_ALIST_1)
Eterm* hp;
int len;
- if ((len = list_length(list)) < 0) {
+ if ((len = list_length(list)) < 0 || len > ERTS_MAX_TUPLE_SIZE) {
BIF_ERROR(BIF_P, BADARG);
}
@@ -3126,7 +3194,7 @@ BIF_RETTYPE list_to_tuple_1(BIF_ALIST_1)
BIF_RETTYPE self_0(BIF_ALIST_0)
{
- BIF_RET(BIF_P->id);
+ BIF_RET(BIF_P->common.id);
}
/**********************************************************************/
@@ -3163,11 +3231,9 @@ static erts_smp_spinlock_t make_ref_lock;
static erts_smp_mtx_t ports_snapshot_mtx;
erts_smp_atomic_t erts_dead_ports_ptr; /* To store dying ports during snapshot */
-Eterm erts_make_ref_in_buffer(Eterm buffer[REF_THING_SIZE])
+void
+erts_make_ref_in_array(Uint32 ref[ERTS_MAX_REF_NUMBERS])
{
- Eterm* hp = buffer;
- Uint32 ref0, ref1, ref2;
-
erts_smp_spin_lock(&make_ref_lock);
reference0++;
@@ -3179,24 +3245,36 @@ Eterm erts_make_ref_in_buffer(Eterm buffer[REF_THING_SIZE])
}
}
- ref0 = reference0;
- ref1 = reference1;
- ref2 = reference2;
+ ref[0] = reference0;
+ ref[1] = reference1;
+ ref[2] = reference2;
erts_smp_spin_unlock(&make_ref_lock);
+}
- write_ref_thing(hp, ref0, ref1, ref2);
+Eterm erts_make_ref_in_buffer(Eterm buffer[REF_THING_SIZE])
+{
+ Eterm* hp = buffer;
+ Uint32 ref[ERTS_MAX_REF_NUMBERS];
+
+ erts_make_ref_in_array(ref);
+ write_ref_thing(hp, ref[0], ref[1], ref[2]);
return make_internal_ref(hp);
}
Eterm erts_make_ref(Process *p)
{
Eterm* hp;
+ Uint32 ref[ERTS_MAX_REF_NUMBERS];
ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_MAIN & erts_proc_lc_my_proc_locks(p));
hp = HAlloc(p, REF_THING_SIZE);
- return erts_make_ref_in_buffer(hp);
+
+ erts_make_ref_in_array(ref);
+ write_ref_thing(hp, ref[0], ref[1], ref[2]);
+
+ return make_internal_ref(hp);
}
BIF_RETTYPE make_ref_0(BIF_ALIST_0)
@@ -3460,7 +3538,7 @@ BIF_RETTYPE garbage_collect_1(BIF_ALIST_1)
BIF_ERROR(BIF_P, BADARG);
}
- if (BIF_P->id == BIF_ARG_1)
+ if (BIF_P->common.id == BIF_ARG_1)
rp = BIF_P;
else {
#ifdef ERTS_SMP
@@ -3500,71 +3578,23 @@ BIF_RETTYPE garbage_collect_0(BIF_ALIST_0)
}
/**********************************************************************/
-/* Return a list of active ports */
+/*
+ * The erlang:processes/0 BIF.
+ */
-BIF_RETTYPE ports_0(BIF_ALIST_0)
+BIF_RETTYPE processes_0(BIF_ALIST_0)
{
- Eterm res = NIL;
- Eterm* port_buf = erts_alloc(ERTS_ALC_T_TMP,
- sizeof(Eterm)*erts_max_ports);
- Eterm* pp = port_buf;
- Eterm* dead_ports;
- int alive, dead;
- Uint32 next_ss;
- int i;
-
- /* To get a consistent snapshot...
- * We add alive ports from start of the buffer
- * while dying ports are added from the other end by the killing threads.
- */
-
- erts_smp_mtx_lock(&ports_snapshot_mtx); /* One snapshot at a time */
-
- erts_smp_atomic_set_nob(&erts_dead_ports_ptr,
- (erts_aint_t) (port_buf + erts_max_ports));
-
- next_ss = erts_smp_atomic32_inc_read_relb(&erts_ports_snapshot);
-
- for (i = erts_max_ports-1; i >= 0; i--) {
- Port* prt = &erts_port[i];
- erts_smp_port_state_lock(prt);
- if (!(prt->status & ERTS_PORT_SFLGS_DEAD)
- && prt->snapshot != next_ss) {
- ASSERT(prt->snapshot == next_ss - 1);
- *pp++ = prt->id;
- prt->snapshot = next_ss; /* Consumed by this snapshot */
- }
- erts_smp_port_state_unlock(prt);
- }
-
- dead_ports = (Eterm*)erts_smp_atomic_xchg_nob(&erts_dead_ports_ptr,
- (erts_aint_t) NULL);
- erts_smp_mtx_unlock(&ports_snapshot_mtx);
-
- ASSERT(pp <= dead_ports);
-
- alive = pp - port_buf;
- dead = port_buf + erts_max_ports - dead_ports;
-
- ASSERT((alive+dead) <= erts_max_ports);
-
- if (alive+dead > 0) {
- erts_aint_t i;
- Eterm *hp = HAlloc(BIF_P, (alive+dead)*2);
-
- for (i = 0; i < alive; i++) {
- res = CONS(hp, port_buf[i], res);
- hp += 2;
- }
- for (i = 0; i < dead; i++) {
- res = CONS(hp, dead_ports[i], res);
- hp += 2;
- }
- }
+ return erts_ptab_list(BIF_P, &erts_proc);
+}
- erts_free(ERTS_ALC_T_TMP, port_buf);
+/**********************************************************************/
+/*
+ * The erlang:ports/0 BIF.
+ */
- BIF_RET(res);
+BIF_RETTYPE ports_0(BIF_ALIST_0)
+{
+ return erts_ptab_list(BIF_P, &erts_port);
}
/**********************************************************************/
@@ -4194,12 +4224,13 @@ BIF_RETTYPE system_flag_2(BIF_ALIST_2)
BIF_RET(old_value);
}
} else if (BIF_ARG_1 == make_small(1)) {
- Uint i;
+ int i, max;
ErlMessage* mp;
erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
erts_smp_thr_progress_block();
- for (i = 0; i < erts_max_processes; i++) {
+ max = erts_ptab_max(&erts_proc);
+ for (i = 0; i < max; i++) {
Process *p = erts_pix2proc(i);
if (p) {
#ifdef USE_VM_PROBES
@@ -4546,6 +4577,8 @@ void erts_init_bif(void)
am_format_cpu_topology,
1);
await_proc_exit_trap = erts_export_put(am_erlang,am_await_proc_exit,3);
+ await_port_send_result_trap
+ = erts_export_put(am_erts_internal, am_await_port_send_result, 3);
await_sched_wall_time_mod_trap
= erts_export_put(am_erlang, am_await_sched_wall_time_modifications, 2);
erts_smp_atomic32_init_nob(&sched_wall_time, 0);
@@ -4561,19 +4594,18 @@ bif erlang:send_to_logger/2
BIF_RETTYPE send_to_logger_2(BIF_ALIST_2)
{
byte *buf;
- int len;
+ ErlDrvSizeT len;
if (!is_atom(BIF_ARG_1) || !(is_list(BIF_ARG_2) ||
is_nil(BIF_ARG_1))) {
BIF_ERROR(BIF_P,BADARG);
}
- len = io_list_len(BIF_ARG_2);
- if (len < 0)
+ if (erts_iolist_size(BIF_ARG_2, &len) != 0)
BIF_ERROR(BIF_P,BADARG);
else if (len == 0)
buf = "";
else {
#ifdef DEBUG
- int len2;
+ ErlDrvSizeT len2;
#endif
buf = (byte *) erts_alloc(ERTS_ALC_T_TMP, len+1);
#ifdef DEBUG
@@ -4581,7 +4613,7 @@ BIF_RETTYPE send_to_logger_2(BIF_ALIST_2)
#else
(void)
#endif
- io_list_to_buf(BIF_ARG_2, buf, len);
+ erts_iolist_to_buf(BIF_ARG_2, buf, len);
ASSERT(len2 == len);
buf[len] = '\0';
switch (BIF_ARG_1) {
@@ -4675,7 +4707,6 @@ BIF_RETTYPE dt_prepend_vm_tag_data_1(BIF_ALIST_1)
#ifdef USE_VM_PROBES
Eterm b;
Eterm *hp;
- hp = HAlloc(BIF_P,2);
if (is_binary((DT_UTAG(BIF_P)))) {
Uint sz = binary_size(DT_UTAG(BIF_P));
int i;
@@ -4692,6 +4723,7 @@ BIF_RETTYPE dt_prepend_vm_tag_data_1(BIF_ALIST_1)
} else {
b = new_binary(BIF_P,(byte *)"\0",1);
}
+ hp = HAlloc(BIF_P,2);
BIF_RET(CONS(hp,b,BIF_ARG_1));
#else
BIF_RET(BIF_ARG_1);
@@ -4702,7 +4734,6 @@ BIF_RETTYPE dt_append_vm_tag_data_1(BIF_ALIST_1)
#ifdef USE_VM_PROBES
Eterm b;
Eterm *hp;
- hp = HAlloc(BIF_P,2);
if (is_binary((DT_UTAG(BIF_P)))) {
Uint sz = binary_size(DT_UTAG(BIF_P));
int i;
@@ -4719,6 +4750,7 @@ BIF_RETTYPE dt_append_vm_tag_data_1(BIF_ALIST_1)
} else {
b = new_binary(BIF_P,(byte *)"\0",1);
}
+ hp = HAlloc(BIF_P,2);
BIF_RET(CONS(hp,BIF_ARG_1,b));
#else
BIF_RET(BIF_ARG_1);
@@ -4742,14 +4774,14 @@ BIF_RETTYPE dt_spread_tag_1(BIF_ALIST_1)
#ifdef DTRACE_TAG_HARDDEBUG
erts_fprintf(stderr,
"Dtrace -> (%T) start spreading tag %T\r\n",
- BIF_P->id,DT_UTAG(BIF_P));
+ BIF_P->common.id,DT_UTAG(BIF_P));
#endif
} else {
DT_UTAG_FLAGS(BIF_P) &= ~DT_UTAG_SPREADING;
#ifdef DTRACE_TAG_HARDDEBUG
erts_fprintf(stderr,
"Dtrace -> (%T) stop spreading tag %T\r\n",
- BIF_P->id,DT_UTAG(BIF_P));
+ BIF_P->common.id,DT_UTAG(BIF_P));
#endif
}
}
@@ -4775,7 +4807,7 @@ BIF_RETTYPE dt_restore_tag_1(BIF_ALIST_1)
#ifdef DTRACE_TAG_HARDDEBUG
erts_fprintf(stderr,
"Dtrace -> (%T) restore Killing tag!\r\n",
- BIF_P->id);
+ BIF_P->common.id);
#endif
}
DT_UTAG(BIF_P) = NIL;
@@ -4792,12 +4824,12 @@ BIF_RETTYPE dt_restore_tag_1(BIF_ALIST_1)
erts_fprintf(stderr,
"Dtrace -> (%T) restore stop spreading "
"tag %T\r\n",
- BIF_P->id, tpl[2]);
+ BIF_P->common.id, tpl[2]);
} else if ((x & DT_UTAG_SPREADING) &&
!(DT_UTAG_FLAGS(BIF_P) & DT_UTAG_SPREADING)) {
erts_fprintf(stderr,
"Dtrace -> (%T) restore start spreading "
- "tag %T\r\n",BIF_P->id,tpl[2]);
+ "tag %T\r\n",BIF_P->common.id,tpl[2]);
}
#endif
DT_UTAG_FLAGS(BIF_P) = x;
diff --git a/erts/emulator/beam/bif.h b/erts/emulator/beam/bif.h
index 7cb2c78815..71f232035d 100644
--- a/erts/emulator/beam/bif.h
+++ b/erts/emulator/beam/bif.h
@@ -322,27 +322,6 @@ do { \
ERTS_BIF_EXITED((PROC)); \
} while (0)
-#ifdef ERTS_SMP
-#define ERTS_SMP_BIF_CHK_PENDING_EXIT(P, L) \
-do { \
- ERTS_SMP_LC_ASSERT((L) == erts_proc_lc_my_proc_locks((P))); \
- ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_MAIN & (L)); \
- if (!((L) & ERTS_PROC_LOCK_STATUS)) \
- erts_smp_proc_lock((P), ERTS_PROC_LOCK_STATUS); \
- if (ERTS_PROC_PENDING_EXIT((P))) { \
- erts_handle_pending_exit((P), (L)|ERTS_PROC_LOCK_STATUS); \
- erts_smp_proc_unlock((P), \
- (((L)|ERTS_PROC_LOCK_STATUS) \
- & ~ERTS_PROC_LOCK_MAIN)); \
- ERTS_BIF_EXITED((P)); \
- } \
- if (!((L) & ERTS_PROC_LOCK_STATUS)) \
- erts_smp_proc_unlock((P), ERTS_PROC_LOCK_STATUS); \
-} while (0)
-#else
-#define ERTS_SMP_BIF_CHK_PENDING_EXIT(P, L)
-#endif
-
/*
* The ERTS_BIF_*_AWAIT_X_*_TRAP makros either exits the caller, or
* sets up a trap to erlang:await_proc_exit/3.
diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab
index f7dad2767f..59a91cd40c 100644
--- a/erts/emulator/beam/bif.tab
+++ b/erts/emulator/beam/bif.tab
@@ -31,432 +31,233 @@
#
# Important: Use "ubif" for guard BIFs and operators; use "bif" for ordinary BIFs.
#
-# Add new BIFs to the end of the file. Do not bother adding a "packaged BIF name"
-# (such as 'erl.lang.number'); if/when packages will be supported we will add
-# all those names.
+# Add new BIFs to the end of the file.
#
# Note: Guards BIFs require special support in the compiler (to be able to actually
# call them from within a guard).
#
ubif erlang:abs/1
-ubif 'erl.lang.number':abs/1 ebif_abs_1
bif erlang:adler32/1
-bif 'erl.util.crypt.adler32':sum/1 ebif_adler32_1
bif erlang:adler32/2
-bif 'erl.util.crypt.adler32':sum/2 ebif_adler32_2
bif erlang:adler32_combine/3
-bif 'erl.util.crypt.adler32':combine/3 ebif_adler32_combine_3
bif erlang:apply/3
-bif 'erl.lang':apply/3 ebif_apply_3
bif erlang:atom_to_list/1
-bif 'erl.lang.atom':to_string/1 ebif_atom_to_string_1 atom_to_list_1
bif erlang:binary_to_list/1
-bif 'erl.lang.binary':to_list/1 ebif_binary_to_list_1
bif erlang:binary_to_list/3
-bif 'erl.lang.binary':to_list/3 ebif_binary_to_list_3
bif erlang:binary_to_term/1
-bif 'erl.lang.binary':to_term/1 ebif_binary_to_term_1
bif erlang:check_process_code/2
-bif 'erl.system.code':check_process/2 ebif_check_process_code_2
bif erlang:crc32/1
-bif 'erl.util.crypt.crc32':sum/1 ebif_crc32_1
bif erlang:crc32/2
-bif 'erl.util.crypt.crc32':sum/2 ebif_crc32_2
bif erlang:crc32_combine/3
-bif 'erl.util.crypt.crc32':combine/3 ebif_crc32_combine_3
bif erlang:date/0
-bif 'erl.util.date':today/0 ebif_date_0
bif erlang:delete_module/1
-bif 'erl.system.code':delete/1 ebif_delete_module_1
bif erlang:display/1
-bif 'erl.system.debug':display/1 ebif_display_1
bif erlang:display_string/1
-bif 'erl.system.debug':display_string/1 ebif_display_string_1
bif erlang:display_nl/0
-bif 'erl.system.debug':display_nl/0 ebif_display_nl_0
ubif erlang:element/2
-ubif 'erl.lang.tuple':element/2 ebif_element_2
bif erlang:erase/0
-bif 'erl.lang.proc.pdict':erase/0 ebif_erase_0
bif erlang:erase/1
-bif 'erl.lang.proc.pdict':erase/1 ebif_erase_1
bif erlang:exit/1
-bif 'erl.lang':exit/1 ebif_exit_1
bif erlang:exit/2
-bif 'erl.lang.proc':signal/2 ebif_signal_2 exit_2
bif erlang:external_size/1
-bif 'erl.lang.term':external_size/1 ebif_external_size_1
bif erlang:external_size/2
-bif 'erl.lang.term':external_size/2 ebif_external_size_2
ubif erlang:float/1
-ubif 'erl.lang.number':to_float/1 ebif_to_float_1 float_1
bif erlang:float_to_list/1
-bif 'erl.lang.float':to_string/1 ebif_float_to_string_1 float_to_list_1
bif erlang:fun_info/2
-bif 'erl.lang.function':info/2 ebif_fun_info_2
bif erlang:garbage_collect/0
-bif 'erl.system':garbage_collect/0 ebif_garbage_collect_0
bif erlang:garbage_collect/1
-bif 'erl.system':garbage_collect/1 ebif_garbage_collect_1
bif erlang:get/0
-bif 'erl.lang.proc.pdict':get/0 ebif_get_0
bif erlang:get/1
-bif 'erl.lang.proc.pdict':get/1 ebif_get_1
bif erlang:get_keys/1
-bif 'erl.lang.proc.pdict':get_keys/1 ebif_get_keys_1
bif erlang:group_leader/0
-bif 'erl.lang.proc':group_leader/0 ebif_group_leader_0
bif erlang:group_leader/2
-bif 'erl.lang.proc':set_group_leader/2 ebif_group_leader_2
bif erlang:halt/0
-bif 'erl.lang.system':halt/0 ebif_halt_0
bif erlang:halt/1
-bif 'erl.lang.system':halt/1 ebif_halt_1
bif erlang:halt/2
-bif 'erl.lang.system':halt/2 ebif_halt_2
bif erlang:phash/2
bif erlang:phash2/1
bif erlang:phash2/2
-bif 'erl.lang.term':hash/1 ebif_phash2_1
-bif 'erl.lang.term':hash/2 ebif_phash2_2
ubif erlang:hd/1
-ubif 'erl.lang.list':hd/1 ebif_hd_1
bif erlang:integer_to_list/1
-bif 'erl.lang.integer':to_string/1 ebif_integer_to_string_1 integer_to_list_1
bif erlang:is_alive/0
-bif 'erl.lang.node':is_alive/0 ebif_is_alive_0
ubif erlang:length/1
-ubif 'erl.lang.list':length/1 ebif_length_1
bif erlang:link/1
-bif 'erl.lang.proc':link/1 ebif_link_1
bif erlang:list_to_atom/1
-bif 'erl.lang.atom':from_string/1 ebif_string_to_atom_1 list_to_atom_1
bif erlang:list_to_binary/1
-bif 'erl.lang.binary':from_list/1 ebif_list_to_binary_1
bif erlang:list_to_float/1
-bif 'erl.lang.float':from_string/1 ebif_string_to_float_1 list_to_float_1
bif erlang:list_to_integer/1
-bif 'erl.lang.integer':from_string/1 ebif_string_to_integer_1 list_to_integer_1
bif erlang:list_to_pid/1
-bif 'erl.lang.proc':string_to_pid/1 ebif_string_to_pid_1 list_to_pid_1
bif erlang:list_to_tuple/1
-bif 'erl.lang.tuple':from_list/1 ebif_list_to_tuple_1
bif erlang:loaded/0
-bif 'erl.system.code':loaded/0 ebif_loaded_0
bif erlang:localtime/0
-bif 'erl.util.date':local/0 ebif_localtime_0
bif erlang:localtime_to_universaltime/2
-bif 'erl.util.date':local_to_utc/2 ebif_localtime_to_universaltime_2
bif erlang:make_ref/0
-bif 'erl.lang.ref':new/0 ebif_make_ref_0
bif erlang:md5/1
-bif 'erl.util.crypt.md5':digest/1 ebif_md5_1
bif erlang:md5_init/0
-bif 'erl.util.crypt.md5':init/0 ebif_md5_init_0
bif erlang:md5_update/2
-bif 'erl.util.crypt.md5':update/2 ebif_md5_update_2
bif erlang:md5_final/1
-bif 'erl.util.crypt.md5':final/1 ebif_md5_final_1
bif erlang:module_loaded/1
-bif 'erl.system.code':is_loaded/1 ebif_is_loaded_1 module_loaded_1
bif erlang:function_exported/3
-bif 'erl.system.code':is_loaded/3 ebif_is_loaded_3 function_exported_3
bif erlang:monitor_node/2
-bif 'erl.lang.node':monitor/2 ebif_monitor_node_2
bif erlang:monitor_node/3
-bif 'erl.lang.node':monitor/3 ebif_monitor_node_3
ubif erlang:node/1
-ubif 'erl.lang.node':node/1 ebif_node_1
ubif erlang:node/0
-ubif 'erl.lang.node':node/0 ebif_node_0
bif erlang:nodes/1
-bif 'erl.lang.node':nodes/1 ebif_nodes_1
bif erlang:now/0
-bif 'erl.system':now/0 ebif_now_0
bif erlang:open_port/2
-bif 'erl.lang.port':open/2 ebif_open_port_2 open_port_2
bif erlang:pid_to_list/1
-bif 'erl.lang.proc':pid_to_string/1 ebif_pid_to_string_1 pid_to_list_1
-bif erlang:port_info/1
-bif 'erl.lang.port':info/1 ebif_port_info_1
-bif erlang:port_info/2
-bif 'erl.lang.port':info/2 ebif_port_info_2
bif erlang:ports/0
-bif 'erl.lang.node':ports/0 ebif_ports_0
bif erlang:pre_loaded/0
-bif 'erl.system.code':preloaded/0 ebif_pre_loaded_0
bif erlang:process_flag/2
-bif 'erl.lang.proc':set_flag/2 ebif_process_flag_2
bif erlang:process_flag/3
-bif 'erl.lang.proc':set_flag/3 ebif_process_flag_3
bif erlang:process_info/1
-bif 'erl.lang.proc':info/1 ebif_process_info_1
bif erlang:process_info/2
-bif 'erl.lang.proc':info/2 ebif_process_info_2
bif erlang:processes/0
-bif 'erl.lang.node':processes/0 ebif_processes_0
bif erlang:purge_module/1
-bif 'erl.system.code':purge/1 ebif_purge_module_1
bif erlang:put/2
-bif 'erl.lang.proc.pdict':put/2 ebif_put_2
bif erlang:register/2
-bif 'erl.lang.node':register/2 ebif_register_2
bif erlang:registered/0
-bif 'erl.lang.node':registered/0 ebif_registered_0
ubif erlang:round/1
-ubif 'erl.lang.number':round/1 ebif_round_1
ubif erlang:self/0
-ubif 'erl.lang.proc':self/0 ebif_self_0
bif erlang:setelement/3
-bif 'erl.lang.tuple':setelement/3 ebif_setelement_3
ubif erlang:size/1
-ubif 'erl.lang.term':size/1 ebif_size_1
bif erlang:spawn/3
-bif 'erl.lang.proc':spawn/3 ebif_spawn_3
bif erlang:spawn_link/3
-bif 'erl.lang.proc':spawn_link/3 ebif_spawn_link_3
bif erlang:split_binary/2
-bif 'erl.lang.binary':split/2 ebif_split_binary_2
bif erlang:statistics/1
-bif 'erl.system':statistics/1 ebif_statistics_1
bif erlang:term_to_binary/1
-bif 'erl.lang.binary':from_term/1 ebif_term_to_binary_1
bif erlang:term_to_binary/2
-bif 'erl.lang.binary':from_term/2 ebif_term_to_binary_2
bif erlang:throw/1
-bif 'erl.lang':throw/1 ebif_throw_1
bif erlang:time/0
-bif 'erl.util.date':time_of_day/0 ebif_time_0
ubif erlang:tl/1
-ubif 'erl.lang.list':tl/1 ebif_tl_1
ubif erlang:trunc/1
-ubif 'erl.lang.number':trunc/1 ebif_trunc_1
bif erlang:tuple_to_list/1
-bif 'erl.lang.tuple':to_list/1 ebif_tuple_to_list_1
bif erlang:universaltime/0
-bif 'erl.util.date':utc/0 ebif_universaltime_0
bif erlang:universaltime_to_localtime/1
-bif 'erl.util.date':utc_to_local/1 ebif_universaltime_to_localtime_1
bif erlang:unlink/1
-bif 'erl.lang.proc':unlink/1 ebif_unlink_1
bif erlang:unregister/1
-bif 'erl.lang.node':unregister/1 ebif_unregister_1
bif erlang:whereis/1
-bif 'erl.lang.node':whereis/1 ebif_whereis_1
bif erlang:spawn_opt/1
-bif 'erl.lang.proc':spawn_opt/1 ebif_spawn_opt_1
bif erlang:setnode/2
bif erlang:setnode/3
bif erlang:dist_exit/3
-bif erlang:port_call/2
-bif 'erl.lang.port':call/2 ebif_port_call_2
-bif erlang:port_call/3
-bif 'erl.lang.port':call/3 ebif_port_call_3
-bif erlang:port_command/2
-bif 'erl.lang.port':command/2 ebif_port_command_2
-bif erlang:port_command/3
-bif 'erl.lang.port':command/3 ebif_port_command_3
-bif erlang:port_control/3
-bif 'erl.lang.port':control/3 ebif_port_control_3
-bif erlang:port_close/1
-bif 'erl.lang.port':close/1 ebif_port_close_1
-bif erlang:port_connect/2
-bif 'erl.lang.port':connect/2 ebif_port_connect_2
-bif erlang:port_set_data/2
-bif 'erl.lang.port':set_data/2 ebif_port_set_data_2
-bif erlang:port_get_data/1
-bif 'erl.lang.port':get_data/1 ebif_port_get_data_1
+# Static native functions in erts_internal
+bif erts_internal:port_info/1
+bif erts_internal:port_info/2
+bif erts_internal:port_call/3
+bif erts_internal:port_command/3
+bif erts_internal:port_control/3
+bif erts_internal:port_close/1
+bif erts_internal:port_connect/2
+bif erts_internal:port_set_data/2
+bif erts_internal:port_get_data/1
# Tracing & debugging.
bif erlang:trace_pattern/2
-bif 'erl.system.debug':trace_pattern/2 ebif_trace_pattern_2
bif erlang:trace_pattern/3
-bif 'erl.system.debug':trace_pattern/3 ebif_trace_pattern_3
bif erlang:trace/3
-bif 'erl.system.debug':trace/3 ebif_trace_3
bif erlang:trace_info/2
-bif 'erl.system.debug':trace_info/2 ebif_trace_info_2
bif erlang:trace_delivered/1
-bif 'erl.system.debug':trace_delivered/1 ebif_trace_delivered_1
bif erlang:seq_trace/2
-bif 'erl.system.debug':seq_trace/2 ebif_seq_trace_2
bif erlang:seq_trace_info/1
-bif 'erl.system.debug':seq_trace_info/1 ebif_seq_trace_info_1
bif erlang:seq_trace_print/1
-bif 'erl.system.debug':seq_trace_print/1 ebif_seq_trace_print_1
bif erlang:seq_trace_print/2
-bif 'erl.system.debug':seq_trace_print/2 ebif_seq_trace_print_2
bif erlang:suspend_process/2
-bif 'erl.system.debug':suspend_process/2 ebif_suspend_process_2
bif erlang:resume_process/1
-bif 'erl.system.debug':resume_process/1 ebif_resume_process_1
bif erlang:process_display/2
-bif 'erl.system.debug':process_display/2 ebif_process_display_2
bif erlang:bump_reductions/1
-bif 'erl.lang.proc':bump_reductions/1 ebif_bump_reductions_1
bif math:cos/1
-bif 'erl.lang.math':cos/1 ebif_math_cos_1
bif math:cosh/1
-bif 'erl.lang.math':cosh/1 ebif_math_cosh_1
bif math:sin/1
-bif 'erl.lang.math':sin/1 ebif_math_sin_1
bif math:sinh/1
-bif 'erl.lang.math':sinh/1 ebif_math_sinh_1
bif math:tan/1
-bif 'erl.lang.math':tan/1 ebif_math_tan_1
bif math:tanh/1
-bif 'erl.lang.math':tanh/1 ebif_math_tanh_1
bif math:acos/1
-bif 'erl.lang.math':acos/1 ebif_math_acos_1
bif math:acosh/1
-bif 'erl.lang.math':acosh/1 ebif_math_acosh_1
bif math:asin/1
-bif 'erl.lang.math':asin/1 ebif_math_asin_1
bif math:asinh/1
-bif 'erl.lang.math':asinh/1 ebif_math_asinh_1
bif math:atan/1
-bif 'erl.lang.math':atan/1 ebif_math_atan_1
bif math:atanh/1
-bif 'erl.lang.math':atanh/1 ebif_math_atanh_1
bif math:erf/1
-bif 'erl.lang.math':erf/1 ebif_math_erf_1
bif math:erfc/1
-bif 'erl.lang.math':erfc/1 ebif_math_erfc_1
bif math:exp/1
-bif 'erl.lang.math':exp/1 ebif_math_exp_1
bif math:log/1
-bif 'erl.lang.math':log/1 ebif_math_log_1
bif math:log10/1
-bif 'erl.lang.math':log10/1 ebif_math_log10_1
bif math:sqrt/1
-bif 'erl.lang.math':sqrt/1 ebif_math_sqrt_1
bif math:atan2/2
-bif 'erl.lang.math':atan2/2 ebif_math_atan2_2
bif math:pow/2
-bif 'erl.lang.math':pow/2 ebif_math_pow_2
bif erlang:start_timer/3
-bif 'erl.lang.timer':start/3 ebif_start_timer_3
bif erlang:send_after/3
-bif 'erl.lang.timer':send_after/3 ebif_send_after_3
bif erlang:cancel_timer/1
-bif 'erl.lang.timer':cancel/1 ebif_cancel_timer_1
bif erlang:read_timer/1
-bif 'erl.lang.timer':read/1 ebif_read_timer_1
bif erlang:make_tuple/2
-bif 'erl.lang.tuple':make/2 ebif_make_tuple_2
bif erlang:append_element/2
-bif 'erl.lang.tuple':append_element/2 ebif_append_element_2
bif erlang:make_tuple/3
bif erlang:system_flag/2
-bif 'erl.system':set_flag/2 ebif_system_flag_2
bif erlang:system_info/1
-bif 'erl.system':info/1 ebif_system_info_1
# New in R9C
bif erlang:system_monitor/0
-bif 'erl.system':monitor/0 ebif_system_monitor_0
bif erlang:system_monitor/1
-bif 'erl.system':monitor/1 ebif_system_monitor_1
bif erlang:system_monitor/2
-bif 'erl.system':monitor/2 ebif_system_monitor_2
# Added 2006-11-07
bif erlang:system_profile/2
-bif 'erl.system':profile/2 ebif_system_profile_2
# End Added 2006-11-07
# Added 2007-01-17
bif erlang:system_profile/0
-bif 'erl.system':profile/0 ebif_system_profile_0
# End Added 2007-01-17
bif erlang:ref_to_list/1
-bif 'erl.lang.ref':to_string/1 ebif_ref_to_string_1 ref_to_list_1
bif erlang:port_to_list/1
-bif 'erl.lang.port':to_string/1 ebif_port_to_string_1 port_to_list_1
bif erlang:fun_to_list/1
-bif 'erl.lang.function':to_string/1 ebif_fun_to_string_1 fun_to_list_1
bif erlang:monitor/2
-bif 'erl.lang.proc':monitor/2 ebif_monitor_2
bif erlang:demonitor/1
-bif 'erl.lang.proc':demonitor/1 ebif_demonitor_1
bif erlang:demonitor/2
-bif 'erl.lang.proc':demonitor/2 ebif_demonitor_2
bif erlang:is_process_alive/1
-bif 'erl.lang.proc':is_alive/1 ebif_proc_is_alive_1 is_process_alive_1
bif erlang:error/1 error_1
-bif 'erl.lang':error/1 ebif_error_1 error_1
bif erlang:error/2 error_2
-bif 'erl.lang':error/2 ebif_error_2 error_2
bif erlang:raise/3 raise_3
-bif 'erl.lang':raise/3 ebif_raise_3 raise_3
bif erlang:get_stacktrace/0
-bif 'erl.lang.proc':get_stacktrace/0 ebif_get_stacktrace_0
bif erlang:is_builtin/3
-bif 'erl.system.code':is_builtin/3 ebif_is_builtin_3
ubif erlang:'and'/2
-ubif 'erl.lang.bool':'and'/2 ebif_and_2
ubif erlang:'or'/2
-ubif 'erl.lang.bool':'or'/2 ebif_or_2
ubif erlang:'xor'/2
-ubif 'erl.lang.bool':'xor'/2 ebif_xor_2
ubif erlang:'not'/1
-ubif 'erl.lang.bool':'not'/1 ebif_not_1
ubif erlang:'>'/2 sgt_2
-ubif 'erl.lang.term':greater/2 ebif_gt_2 sgt_2
ubif erlang:'>='/2 sge_2
-ubif 'erl.lang.term':greater_or_equal/2 ebif_ge_2 sge_2
ubif erlang:'<'/2 slt_2
-ubif 'erl.lang.term':less/2 ebif_lt_2 slt_2
ubif erlang:'=<'/2 sle_2
-ubif 'erl.lang.term':less_or_equal/2 ebif_le_2 sle_2
ubif erlang:'=:='/2 seq_2
-ubif 'erl.lang.term':equal/2 ebif_eq_2 seq_2
ubif erlang:'=='/2 seqeq_2
-ubif 'erl.lang.term':arith_equal/2 ebif_areq_2 seqeq_2
ubif erlang:'=/='/2 sneq_2
-ubif 'erl.lang.term':not_equal/2 ebif_neq_2 sneq_2
ubif erlang:'/='/2 sneqeq_2
-ubif 'erl.lang.term':not_arith_equal/2 ebif_nareq_2 sneqeq_2
ubif erlang:'+'/2 splus_2
-ubif 'erl.lang.number':plus/2 ebif_plus_2 splus_2
ubif erlang:'-'/2 sminus_2
-ubif 'erl.lang.number':minus/2 ebif_minus_2 sminus_2
ubif erlang:'*'/2 stimes_2
-ubif 'erl.lang.number':multiply/2 ebif_multiply_2 stimes_2
ubif erlang:'/'/2 div_2
-ubif 'erl.lang.number':divide/2 ebif_divide_2 div_2
ubif erlang:'div'/2 intdiv_2
-ubif 'erl.lang.integer':'div'/2 ebif_intdiv_2
ubif erlang:'rem'/2
-ubif 'erl.lang.integer':'rem'/2 ebif_rem_2
ubif erlang:'bor'/2
-ubif 'erl.lang.integer':'bor'/2 ebif_bor_2
ubif erlang:'band'/2
-ubif 'erl.lang.integer':'band'/2 ebif_band_2
ubif erlang:'bxor'/2
-ubif 'erl.lang.integer':'bxor'/2 ebif_bxor_2
ubif erlang:'bsl'/2
-ubif 'erl.lang.integer':'bsl'/2 ebif_bsl_2
ubif erlang:'bsr'/2
-ubif 'erl.lang.integer':'bsr'/2 ebif_bsr_2
ubif erlang:'bnot'/1
-ubif 'erl.lang.integer':'bnot'/1 ebif_bnot_1
ubif erlang:'-'/1 sminus_1
-ubif 'erl.lang.number':minus/1 ebif_minus_1 sminus_1
ubif erlang:'+'/1 splus_1
-ubif 'erl.lang.number':plus/1 ebif_plus_1 splus_1
# New operators in R8. These were the only operators missing.
# erlang:send/2, erlang:append/2 and erlang:subtract/2 are now also
@@ -464,45 +265,27 @@ ubif 'erl.lang.number':plus/1 ebif_plus_1 splus_1
# internal references have been updated to the new ebif_... entries.
bif erlang:'!'/2 ebif_bang_2
-bif 'erl.lang.proc':send/2 ebif_send_2 send_2
bif erlang:send/2
-bif 'erl.lang':send/3 ebif_send_3 send_3
bif erlang:send/3
bif erlang:'++'/2 ebif_plusplus_2
-bif 'erl.lang.list':append/2 ebif_append_2 ebif_plusplus_2
bif erlang:append/2
bif erlang:'--'/2 ebif_minusminus_2
-bif 'erl.lang.list':subtract/2 ebif_list_subtract_2 ebif_minusminus_2
bif erlang:subtract/2
ubif erlang:is_atom/1
-ubif 'erl.lang.term':is_atom/1 ebif_is_atom_1
ubif erlang:is_list/1
-ubif 'erl.lang.term':is_list/1 ebif_is_list_1
ubif erlang:is_tuple/1
-ubif 'erl.lang.term':is_tuple/1 ebif_is_tuple_1
ubif erlang:is_float/1
-ubif 'erl.lang.term':is_float/1 ebif_is_float_1
ubif erlang:is_integer/1
-ubif 'erl.lang.term':is_integer/1 ebif_is_integer_1
ubif erlang:is_number/1
-ubif 'erl.lang.term':is_number/1 ebif_is_number_1
ubif erlang:is_pid/1
-ubif 'erl.lang.term':is_pid/1 ebif_is_pid_1
ubif erlang:is_port/1
-ubif 'erl.lang.term':is_port/1 ebif_is_port_1
ubif erlang:is_reference/1
-ubif 'erl.lang.term':is_reference/1 ebif_is_reference_1
ubif erlang:is_binary/1
-ubif 'erl.lang.term':is_binary/1 ebif_is_binary_1
ubif erlang:is_function/1
-ubif 'erl.lang.term':is_function/1 ebif_is_function_1
ubif erlang:is_function/2
-ubif 'erl.lang.term':is_function/2 ebif_is_function_2
ubif erlang:is_record/2
-ubif 'erl.lang.term':is_record/2 ebif_is_record_2
ubif erlang:is_record/3
-ubif 'erl.lang.term':is_record/3 ebif_is_record_3
bif erlang:match_spec_test/3
@@ -511,96 +294,53 @@ bif erlang:match_spec_test/3
#
bif ets:all/0
-bif 'erl.lang.ets':all/0 ebif_ets_all_0
bif ets:new/2
-bif 'erl.lang.ets':new/2 ebif_ets_new_2
bif ets:delete/1
-bif 'erl.lang.ets':delete/1 ebif_ets_delete_1
bif ets:delete/2
-bif 'erl.lang.ets':delete/2 ebif_ets_delete_2
bif ets:delete_all_objects/1
-bif 'erl.lang.ets':delete_all_objects/1 ebif_ets_delete_all_objects_1
bif ets:delete_object/2
-bif 'erl.lang.ets':delete_object/2 ebif_ets_delete_object_2
bif ets:first/1
-bif 'erl.lang.ets':first/1 ebif_ets_first_1
bif ets:is_compiled_ms/1
-bif 'erl.lang.ets':is_compiled_ms/1 ebif_ets_is_compiled_ms_1
bif ets:lookup/2
-bif 'erl.lang.ets':lookup/2 ebif_ets_lookup_2
bif ets:lookup_element/3
-bif 'erl.lang.ets':lookup_element/3 ebif_ets_lookup_element_3
bif ets:info/1
-bif 'erl.lang.ets':info/1 ebif_ets_info_1
bif ets:info/2
-bif 'erl.lang.ets':info/2 ebif_ets_info_2
bif ets:last/1
-bif 'erl.lang.ets':last/1 ebif_ets_last_1
bif ets:match/1
-bif 'erl.lang.ets':match/1 ebif_ets_match_1
bif ets:match/2
-bif 'erl.lang.ets':match/2 ebif_ets_match_2
bif ets:match/3
-bif 'erl.lang.ets':match/3 ebif_ets_match_3
bif ets:match_object/1
-bif 'erl.lang.ets':match_object/1 ebif_ets_match_object_1
bif ets:match_object/2
-bif 'erl.lang.ets':match_object/2 ebif_ets_match_object_2
bif ets:match_object/3
-bif 'erl.lang.ets':match_object/3 ebif_ets_match_object_3
bif ets:member/2
-bif 'erl.lang.ets':is_key/2 ebif_ets_member_2
bif ets:next/2
-bif 'erl.lang.ets':next/2 ebif_ets_next_2
bif ets:prev/2
-bif 'erl.lang.ets':prev/2 ebif_ets_prev_2
bif ets:insert/2
-bif 'erl.lang.ets':insert/2 ebif_ets_insert_2
bif ets:insert_new/2
-bif 'erl.lang.ets':insert_new/2 ebif_ets_insert_new_2
bif ets:rename/2
-bif 'erl.lang.ets':rename/2 ebif_ets_rename_2
bif ets:safe_fixtable/2
-bif 'erl.lang.ets':fixtable/2 ebif_ets_safe_fixtable_2
bif ets:slot/2
-bif 'erl.lang.ets':slot/2 ebif_ets_slot_2
bif ets:update_counter/3
-bif 'erl.lang.ets':update_counter/3 ebif_ets_update_counter_3
bif ets:select/1
-bif 'erl.lang.ets':select/1 ebif_ets_select_1
bif ets:select/2
-bif 'erl.lang.ets':select/2 ebif_ets_select_2
bif ets:select/3
-bif 'erl.lang.ets':select/3 ebif_ets_select_3
bif ets:select_count/2
-bif 'erl.lang.ets':select/2 ebif_ets_select_count_2
bif ets:select_reverse/1
-bif 'erl.lang.ets':select_reverse/1 ebif_ets_select_reverse_1
bif ets:select_reverse/2
-bif 'erl.lang.ets':select_reverse/2 ebif_ets_select_reverse_2
bif ets:select_reverse/3
-bif 'erl.lang.ets':select_reverse/3 ebif_ets_select_reverse_3
bif ets:select_delete/2
-bif 'erl.lang.ets':select_delete/2 ebif_ets_select_delete_2
bif ets:match_spec_compile/1
-bif 'erl.lang.ets':match_spec_compile/1 ebif_ets_match_spec_compile_1
bif ets:match_spec_run_r/3
-bif 'erl.lang.ets':match_spec_run_r/3 ebif_ets_match_spec_run_r_3
#
# Bifs in os module.
#
bif os:putenv/2
-bif 'erl.system.os':setenv/2 ebif_os_setenv_2 os_putenv_2
bif os:getenv/0
-bif 'erl.system.os':getenv/0 ebif_os_getenv_0
bif os:getenv/1
-bif 'erl.system.os':getenv/1 ebif_os_getenv_1
bif os:getpid/0
-bif 'erl.system.os':pid/0 ebif_os_pid_0 os_getpid_0
bif os:timestamp/0
-bif 'erl.system.os':timestamp/0 ebif_os_timestamp_0 os_timestamp_0
#
# Bifs in the erl_ddll module (the module actually does not exist)
@@ -627,13 +367,9 @@ bif re:run/3
#
bif lists:member/2
-bif 'erl.lang.list':is_element/2 ebif_list_is_element_2 lists_member_2
bif lists:reverse/2
-bif 'erl.lang.list':reverse/2 ebif_list_reverse_2 lists_reverse_2
bif lists:keymember/3
-bif 'erl.lang.list.keylist':is_element/3 ebif_keylist_is_element_3 lists_keymember_3
bif lists:keysearch/3
-bif 'erl.lang.list.keylist':search/3 ebif_keylist_search_3 lists_keysearch_3
bif lists:keyfind/3
#
@@ -641,21 +377,13 @@ bif lists:keyfind/3
#
bif erts_debug:disassemble/1
-bif 'erl.system.debug':disassemble/1 ebif_erts_debug_disassemble_1
bif erts_debug:breakpoint/2
-bif 'erl.system.debug':breakpoint/2 ebif_erts_debug_breakpoint_2
bif erts_debug:same/2
-bif 'erl.system.debug':same/2 ebif_erts_debug_same_2
bif erts_debug:flat_size/1
-bif 'erl.system.debug':flat_size/1 ebif_erts_debug_flat_size_1
bif erts_debug:get_internal_state/1
-bif 'erl.system.debug':get_internal_state/1 ebif_erts_debug_get_internal_state_1
bif erts_debug:set_internal_state/2
-bif 'erl.system.debug':set_internal_state/2 ebif_erts_debug_set_internal_state_2
bif erts_debug:display/1
-bif 'erl.system.debug':display/1 ebif_erts_debug_display_1
bif erts_debug:dist_ext_to_term/2
-bif 'erl.system.debug':dist_ext_to_term/2 ebif_erts_debug_dist_ext_to_term_2
bif erts_debug:instructions/0
#
@@ -675,13 +403,9 @@ bif erts_debug:lock_counters/1
#
bif code:get_chunk/2
-bif 'erl.system.code':get_chunk/2 ebif_code_get_chunk_2
bif code:module_md5/1
-bif 'erl.system.code':module_md5/1 ebif_code_module_md5_1
bif code:make_stub_module/3
-bif 'erl.system.code':make_stub_module/3 ebif_code_make_stub_module_3
bif code:is_module_native/1
-bif 'erl.system.code':is_native/1 ebif_code_is_native_1 code_is_module_native_1
#
# New Bifs in R9C.
@@ -833,6 +557,8 @@ bif erlang:dt_append_vm_tag_data/1
#
bif erlang:prepare_loading/2
bif erlang:finish_loading/1
+bif erlang:insert_element/3
+bif erlang:delete_element/2
#
# Obsolete
diff --git a/erts/emulator/beam/binary.c b/erts/emulator/beam/binary.c
index 3d2725e239..4441dab181 100644
--- a/erts/emulator/beam/binary.c
+++ b/erts/emulator/beam/binary.c
@@ -355,10 +355,10 @@ BIF_RETTYPE bitstring_to_list_1(BIF_ALIST_1)
BIF_RETTYPE erts_list_to_binary_bif(Process *p, Eterm arg)
{
Eterm bin;
- Uint size;
+ ErlDrvSizeT size;
byte* bytes;
#ifdef DEBUG
- int offset;
+ ErlDrvSizeT offset;
#endif
if (is_nil(arg)) {
@@ -377,7 +377,7 @@ BIF_RETTYPE erts_list_to_binary_bif(Process *p, Eterm arg)
#ifdef DEBUG
offset =
#endif
- io_list_to_buf(arg, (char*) bytes, size);
+ erts_iolist_to_buf(arg, (char*) bytes, size);
ASSERT(offset == 0);
BIF_RET(bin);
diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c
index 376201c309..9aa1e5f30d 100644
--- a/erts/emulator/beam/break.c
+++ b/erts/emulator/beam/break.c
@@ -61,16 +61,19 @@ extern char* erts_system_version[];
static void
port_info(int to, void *to_arg)
{
- int i;
- for (i = 0; i < erts_max_ports; i++)
- print_port_info(to, to_arg, i);
+ int i, max = erts_ptab_max(&erts_port);
+ for (i = 0; i < max; i++) {
+ Port *p = erts_pix2port(i);
+ if (p)
+ print_port_info(p, to, to_arg);
+ }
}
void
process_info(int to, void *to_arg)
{
- int i;
- for (i = 0; i < erts_max_processes; i++) {
+ int i, max = erts_ptab_max(&erts_proc);
+ for (i = 0; i < max; i++) {
Process *p = erts_pix2proc(i);
if (p && p->i != ENULL) {
if (!ERTS_PROC_IS_EXITING(p))
@@ -84,12 +87,12 @@ process_info(int to, void *to_arg)
static void
process_killer(void)
{
- int i, j;
+ int i, j, max = erts_ptab_max(&erts_proc);
Process* rp;
erts_printf("\n\nProcess Information\n\n");
erts_printf("--------------------------------------------------\n");
- for (i = erts_max_processes-1; i >= 0; i--) {
+ for (i = max-1; i >= 0; i--) {
rp = erts_pix2proc(i);
if (rp && rp->i != ENULL) {
int br;
@@ -196,7 +199,7 @@ print_process_info(int to, void *to_arg, Process *p)
erts_aint32_t state;
/* display the PID */
- erts_print(to, to_arg, "=proc:%T\n", p->id);
+ erts_print(to, to_arg, "=proc:%T\n", p->common.id);
/* Display the state */
erts_print(to, to_arg, "State: ");
@@ -226,8 +229,8 @@ print_process_info(int to, void *to_arg, Process *p)
* If the process is registered as a global process, display the
* registered name
*/
- if (p->reg != NULL)
- erts_print(to, to_arg, "Name: %T\n", p->reg->name);
+ if (p->common.u.alive.reg)
+ erts_print(to, to_arg, "Name: %T\n", p->common.u.alive.reg->name);
/*
* Display the initial function name
@@ -301,11 +304,11 @@ print_process_info(int to, void *to_arg, Process *p)
}
/* display the links only if there are any*/
- if (p->nlinks != NULL || p->monitors != NULL) {
+ if (ERTS_P_LINKS(p) || ERTS_P_MONITORS(p)) {
PrintMonitorContext context = {1,to};
erts_print(to, to_arg,"Link list: [");
- erts_doforall_links(p->nlinks, &doit_print_link, &context);
- erts_doforall_monitors(p->monitors, &doit_print_monitor, &context);
+ erts_doforall_links(ERTS_P_LINKS(p), &doit_print_link, &context);
+ erts_doforall_monitors(ERTS_P_MONITORS(p), &doit_print_monitor, &context);
erts_print(to, to_arg,"]\n");
}
@@ -625,9 +628,9 @@ bin_check(void)
{
Process *rp;
struct erl_off_heap_header* hdr;
- int i, printed = 0;
+ int i, printed = 0, max = erts_ptab_max(&erts_proc);
- for (i=0; i < erts_max_processes; i++) {
+ for (i=0; i < max; i++) {
rp = erts_pix2proc(i);
if (!rp)
continue;
@@ -635,7 +638,7 @@ bin_check(void)
if (hdr->thing_word == HEADER_PROC_BIN) {
ProcBin *bp = (ProcBin*) hdr;
if (!printed) {
- erts_printf("Process %T holding binary data \n", rp->id);
+ erts_printf("Process %T holding binary data \n", rp->common.id);
printed = 1;
}
erts_printf("%p orig_size: %bpd, norefs = %bpd\n",
@@ -663,10 +666,14 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args)
ErtsThrPrgrData tpd_buf; /* in case we aren't a managed thread... */
#endif
int fd;
+ size_t envsz;
time_t now;
+ char env[21]; /* enough to hold any 64-bit integer */
size_t dumpnamebufsize = MAXPATHLEN;
char dumpnamebuf[MAXPATHLEN];
char* dumpname;
+ int secs;
+ int env_erl_crash_dump_seconds_set = 1;
if (ERTS_SOMEONE_IS_CRASH_DUMPING)
return;
@@ -689,9 +696,54 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args)
erts_writing_erl_crash_dump = 1;
#endif
- erts_sys_prepare_crash_dump();
+ envsz = sizeof(env);
+ /* ERL_CRASH_DUMP_SECONDS not set
+ * if we have a heart port, break immediately
+ * otherwise dump crash indefinitely (until crash is complete)
+ * same as ERL_CRASH_DUMP_SECONDS = 0
+ * - do not write dump
+ * - do not set an alarm
+ * - break immediately
+ *
+ * ERL_CRASH_DUMP_SECONDS = 0
+ * - do not write dump
+ * - do not set an alarm
+ * - break immediately
+ *
+ * ERL_CRASH_DUMP_SECONDS < 0
+ * - do not set alarm
+ * - write dump until done
+ *
+ * ERL_CRASH_DUMP_SECONDS = S (and S positive)
+ * - Don't dump file forever
+ * - set alarm (set in sys)
+ * - write dump until alarm or file is written completely
+ */
+
+ if (erts_sys_getenv__("ERL_CRASH_DUMP_SECONDS", env, &envsz) != 0) {
+ env_erl_crash_dump_seconds_set = 0;
+ secs = -1;
+ } else {
+ env_erl_crash_dump_seconds_set = 1;
+ secs = atoi(env);
+ }
+
+ if (secs == 0) {
+ return;
+ }
+
+ /* erts_sys_prepare_crash_dump returns 1 if heart port is found, otherwise 0
+ * If we don't find heart (0) and we don't have ERL_CRASH_DUMP_SECONDS set
+ * we should continue writing a dump
+ *
+ * beware: secs -1 means no alarm
+ */
+
+ if (erts_sys_prepare_crash_dump(secs) && !env_erl_crash_dump_seconds_set ) {
+ return;
+ }
- if (erts_sys_getenv_raw("ERL_CRASH_DUMP",&dumpnamebuf[0],&dumpnamebufsize) != 0)
+ if (erts_sys_getenv__("ERL_CRASH_DUMP",&dumpnamebuf[0],&dumpnamebufsize) != 0)
dumpname = "erl_crash.dump";
else
dumpname = &dumpnamebuf[0];
@@ -717,7 +769,7 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args)
erts_print_nif_taints(fd, NULL);
erts_fdprintf(fd, "Atoms: %d\n", atom_table_size());
info(fd, NULL); /* General system info */
- if (erts_proc.tab)
+ if (erts_ptab_initialized(&erts_proc))
process_info(fd, NULL); /* Info about each process and port */
db_info(fd, NULL, 0);
erts_print_bif_timer_info(fd, NULL);
diff --git a/erts/emulator/beam/code_ix.c b/erts/emulator/beam/code_ix.c
index 8025058ee0..c66d5a2f05 100644
--- a/erts/emulator/beam/code_ix.c
+++ b/erts/emulator/beam/code_ix.c
@@ -36,13 +36,13 @@
erts_smp_atomic32_t the_active_code_index;
erts_smp_atomic32_t the_staging_code_index;
-static int the_code_ix_lock = 0;
-struct code_ix_queue_item {
+static Process* code_writing_process = NULL;
+struct code_write_queue_item {
Process *p;
- struct code_ix_queue_item* next;
+ struct code_write_queue_item* next;
};
-static struct code_ix_queue_item* the_code_ix_queue = NULL;
-static erts_smp_mtx_t the_code_ix_queue_lock;
+static struct code_write_queue_item* code_write_queue = NULL;
+static erts_smp_mtx_t code_write_permission_mtx;
#ifdef ERTS_ENABLE_LOCK_CHECK
static erts_tsd_key_t has_code_write_permission;
@@ -56,7 +56,7 @@ void erts_code_ix_init(void)
*/
erts_smp_atomic32_init_nob(&the_active_code_index, 0);
erts_smp_atomic32_init_nob(&the_staging_code_index, 0);
- erts_smp_mtx_init(&the_code_ix_queue_lock, "code_ix_queue");
+ erts_smp_mtx_init(&code_write_permission_mtx, "code_write_permission");
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_tsd_key_create(&has_code_write_permission);
#endif
@@ -114,53 +114,55 @@ int erts_try_seize_code_write_permission(Process* c_p)
#ifdef ERTS_SMP
ASSERT(!erts_smp_thr_progress_is_blocking()); /* to avoid deadlock */
#endif
+ ASSERT(c_p != NULL);
- erts_smp_mtx_lock(&the_code_ix_queue_lock);
- success = !the_code_ix_lock;
+ erts_smp_mtx_lock(&code_write_permission_mtx);
+ success = (code_writing_process == NULL);
if (success) {
- the_code_ix_lock = 1;
+ code_writing_process = c_p;
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_tsd_set(has_code_write_permission, (void *) 1);
#endif
}
else { /* Already locked */
- struct code_ix_queue_item* qitem;
+ struct code_write_queue_item* qitem;
+ ASSERT(code_writing_process != c_p);
qitem = erts_alloc(ERTS_ALC_T_CODE_IX_LOCK_Q, sizeof(*qitem));
qitem->p = c_p;
erts_smp_proc_inc_refc(c_p);
- qitem->next = the_code_ix_queue;
- the_code_ix_queue = qitem;
+ qitem->next = code_write_queue;
+ code_write_queue = qitem;
erts_suspend(c_p, ERTS_PROC_LOCK_MAIN, NULL);
}
- erts_smp_mtx_unlock(&the_code_ix_queue_lock);
+ erts_smp_mtx_unlock(&code_write_permission_mtx);
return success;
}
void erts_release_code_write_permission(void)
{
- ERTS_SMP_LC_ASSERT(erts_is_code_ix_locked());
- erts_smp_mtx_lock(&the_code_ix_queue_lock);
- while (the_code_ix_queue != NULL) { /* unleash the entire herd */
- struct code_ix_queue_item* qitem = the_code_ix_queue;
+ erts_smp_mtx_lock(&code_write_permission_mtx);
+ ERTS_SMP_LC_ASSERT(erts_has_code_write_permission());
+ while (code_write_queue != NULL) { /* unleash the entire herd */
+ struct code_write_queue_item* qitem = code_write_queue;
erts_smp_proc_lock(qitem->p, ERTS_PROC_LOCK_STATUS);
if (!ERTS_PROC_IS_EXITING(qitem->p)) {
erts_resume(qitem->p, ERTS_PROC_LOCK_STATUS);
}
erts_smp_proc_unlock(qitem->p, ERTS_PROC_LOCK_STATUS);
- the_code_ix_queue = qitem->next;
+ code_write_queue = qitem->next;
erts_smp_proc_dec_refc(qitem->p);
erts_free(ERTS_ALC_T_CODE_IX_LOCK_Q, qitem);
}
- the_code_ix_lock = 0;
+ code_writing_process = NULL;
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_tsd_set(has_code_write_permission, (void *) 0);
#endif
- erts_smp_mtx_unlock(&the_code_ix_queue_lock);
+ erts_smp_mtx_unlock(&code_write_permission_mtx);
}
#ifdef ERTS_ENABLE_LOCK_CHECK
-int erts_is_code_ix_locked(void)
+int erts_has_code_write_permission(void)
{
- return the_code_ix_lock && erts_tsd_get(has_code_write_permission);
+ return (code_writing_process != NULL) && erts_tsd_get(has_code_write_permission);
}
#endif
diff --git a/erts/emulator/beam/code_ix.h b/erts/emulator/beam/code_ix.h
index 6b2680044e..e2bd0da112 100644
--- a/erts/emulator/beam/code_ix.h
+++ b/erts/emulator/beam/code_ix.h
@@ -18,7 +18,7 @@
*/
/* Description:
- * This is the interface that facilitate changing the beam code
+ * This is the interface that facilitates changing the beam code
* (load,upgrade,delete) while allowing executing Erlang processes to
* access the code without any locks or other expensive memory barriers.
*
@@ -35,7 +35,7 @@
* The third code index is not explicitly used. It can be thought of as
* the "previous active" or the "next staging" index. It is needed to make
* sure that we do not reuse a code index for staging until we are sure
- * that no executing BIFs are still referring it.
+ * that no executing BIFs are still referencing it.
* We could get by with only two (0 and 1), but that would require that we
* must wait for all schedulers to re-schedule before each code change
* operation can start staging.
@@ -116,7 +116,7 @@ void erts_commit_staging_code_ix(void);
void erts_abort_staging_code_ix(void);
#ifdef ERTS_ENABLE_LOCK_CHECK
-int erts_is_code_ix_locked(void);
+int erts_has_code_write_permission(void);
#endif
diff --git a/erts/emulator/beam/copy.c b/erts/emulator/beam/copy.c
index 36eda04de2..23c0fca6aa 100644
--- a/erts/emulator/beam/copy.c
+++ b/erts/emulator/beam/copy.c
@@ -47,7 +47,7 @@ copy_object(Eterm obj, Process* to)
if (DTRACE_ENABLED(copy_object)) {
DTRACE_CHARBUF(proc_name, 64);
- erts_snprintf(proc_name, sizeof(proc_name), "%T", to->id);
+ erts_snprintf(proc_name, sizeof(proc_name), "%T", to->common.id);
DTRACE2(copy_object, proc_name, size);
}
#endif
diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c
index 28c4621ff2..64cd93a100 100644
--- a/erts/emulator/beam/dist.c
+++ b/erts/emulator/beam/dist.c
@@ -67,7 +67,7 @@ dist_msg_dbg(ErtsDistExternal *edep, char *what, byte *buf, int sz)
{
byte *extp = edep->extp;
Eterm msg;
- Sint size = erts_decode_dist_ext_size(edep, 0);
+ Sint size = erts_decode_dist_ext_size(edep);
if (size < 0) {
erts_fprintf(stderr,
"DIST MSG DEBUG: erts_decode_dist_ext_size(%s) failed:\n",
@@ -124,6 +124,13 @@ static void send_nodes_mon_msgs(Process *, Eterm, Eterm, Eterm, Eterm);
static void init_nodes_monitors(void);
static erts_smp_atomic_t no_caches;
+static erts_smp_atomic_t no_nodes;
+
+struct {
+ Eterm reason;
+ ErlHeapFragment *bp;
+} nodedown;
+
static void
delete_cache(ErtsAtomCache *cache)
@@ -144,7 +151,7 @@ create_cache(DistEntry *dep)
ERTS_SMP_LC_ASSERT(
is_internal_port(dep->cid)
- && erts_lc_is_port_locked(&erts_port[internal_port_index(dep->cid)]));
+ && erts_lc_is_port_locked(erts_port_lookup_raw(dep->cid)));
ASSERT(!dep->cache);
dep->cache = cp = (ErtsAtomCache*) erts_alloc(ERTS_ALC_T_DCACHE,
@@ -171,11 +178,10 @@ get_suspended_on_de(DistEntry *dep, Uint32 unset_qflgs)
return NULL;
}
else {
- ErtsProcList *plp;
- plp = dep->suspended.first;
- dep->suspended.first = NULL;
- dep->suspended.last = NULL;
- return plp;
+ ErtsProcList *suspended = dep->suspended;
+ dep->suspended = NULL;
+ erts_proclist_fetch(&suspended, NULL);
+ return suspended;
}
}
@@ -252,7 +258,7 @@ static void doit_monitor_net_exits(ErtsMonitor *mon, void *vnecp)
if (mon->type == MON_ORIGIN) {
/* local pid is beeing monitored */
- rmon = erts_remove_monitor(&(rp->monitors),mon->ref);
+ rmon = erts_remove_monitor(&ERTS_P_MONITORS(rp), mon->ref);
/* ASSERT(rmon != NULL); nope, can happen during process exit */
if (rmon != NULL) {
erts_destroy_monitor(rmon);
@@ -262,7 +268,7 @@ static void doit_monitor_net_exits(ErtsMonitor *mon, void *vnecp)
Eterm watched;
UseTmpHeapNoproc(3);
ASSERT(mon->type == MON_TARGET);
- rmon = erts_remove_monitor(&(rp->monitors),mon->ref);
+ rmon = erts_remove_monitor(&ERTS_P_MONITORS(rp), mon->ref);
/* ASSERT(rmon != NULL); can happen during process exit */
if (rmon != NULL) {
ASSERT(is_atom(rmon->name) || is_nil(rmon->name));
@@ -311,7 +317,7 @@ static void doit_link_net_exits_sub(ErtsLink *sublnk, void *vlnecp)
goto done;
}
- rlnk = erts_remove_link(&(rp->nlinks), sublnk->pid);
+ rlnk = erts_remove_link(&ERTS_P_LINKS(rp), sublnk->pid);
xres = erts_send_exit_signal(NULL,
sublnk->pid,
rp,
@@ -370,7 +376,7 @@ static void doit_node_link_net_exits(ErtsLink *lnk, void *vnecp)
if (!rp) {
goto done;
}
- rlnk = erts_remove_link(&(rp->nlinks), name);
+ rlnk = erts_remove_link(&ERTS_P_LINKS(rp), name);
if (rlnk != NULL) {
ASSERT(is_atom(rlnk->pid) && (rlnk->type == LINK_NODE));
erts_destroy_link(rlnk);
@@ -394,6 +400,47 @@ static void doit_node_link_net_exits(ErtsLink *lnk, void *vnecp)
erts_destroy_link(lnk);
}
+static void
+set_node_not_alive(void *unused)
+{
+ ErlHeapFragment *bp;
+ Eterm nodename = erts_this_dist_entry->sysname;
+
+ ASSERT(erts_smp_atomic_read_nob(&no_nodes) == 0);
+
+ erts_smp_thr_progress_block();
+ erts_set_this_node(am_Noname, 0);
+ erts_is_alive = 0;
+ send_nodes_mon_msgs(NULL, am_nodedown, nodename, am_visible, nodedown.reason);
+ nodedown.reason = NIL;
+ bp = nodedown.bp;
+ nodedown.bp = NULL;
+ erts_smp_thr_progress_unblock();
+ if (bp)
+ free_message_buffer(bp);
+}
+
+static ERTS_INLINE void
+dec_no_nodes(void)
+{
+ erts_aint_t no = erts_smp_atomic_dec_read_mb(&no_nodes);
+ ASSERT(no >= 0);
+ ASSERT(erts_get_scheduler_id()); /* Need to be a scheduler */
+ if (no == 0)
+ erts_schedule_misc_aux_work(erts_get_scheduler_id(),
+ set_node_not_alive,
+ NULL);
+}
+
+static ERTS_INLINE void
+inc_no_nodes(void)
+{
+#ifdef DEBUG
+ erts_aint_t no = erts_smp_atomic_read_nob(&no_nodes);
+ ASSERT(erts_is_alive ? no > 0 : no == 0);
+#endif
+ erts_smp_atomic_inc_mb(&no_nodes);
+}
/*
* proc is currently running or exiting process.
@@ -403,47 +450,76 @@ int erts_do_net_exits(DistEntry *dep, Eterm reason)
Eterm nodename;
if (dep == erts_this_dist_entry) { /* Net kernel has died (clean up!!) */
+ DistEntry *tdep;
+ int no_dist_port = 0;
Eterm nd_reason = (reason == am_no_network
? am_no_network
: am_net_kernel_terminated);
erts_smp_rwmtx_rwlock(&erts_dist_table_rwmtx);
+ for (tdep = erts_hidden_dist_entries; tdep; tdep = tdep->next)
+ no_dist_port++;
+ for (tdep = erts_visible_dist_entries; tdep; tdep = tdep->next)
+ no_dist_port++;
+
/* KILL all port controllers */
- while(erts_visible_dist_entries || erts_hidden_dist_entries) {
- DistEntry *tdep;
- Eterm prt_id;
- Port *prt;
- if(erts_hidden_dist_entries)
- tdep = erts_hidden_dist_entries;
- else
- tdep = erts_visible_dist_entries;
- prt_id = tdep->cid;
- ASSERT(is_internal_port(prt_id));
+ if (no_dist_port == 0)
erts_smp_rwmtx_rwunlock(&erts_dist_table_rwmtx);
+ else {
+ Eterm def_buf[128];
+ int i = 0;
+ Eterm *dist_port;
- prt = erts_id2port(prt_id, NULL, 0);
- if (prt) {
- ASSERT(prt->status & ERTS_PORT_SFLG_DISTRIBUTION);
- ASSERT(prt->dist_entry);
- /* will call do_net_exists !!! */
- erts_do_exit_port(prt, prt_id, nd_reason);
- erts_port_release(prt);
+ if (no_dist_port <= sizeof(def_buf)/sizeof(def_buf[0]))
+ dist_port = &def_buf[0];
+ else
+ dist_port = erts_alloc(ERTS_ALC_T_TMP,
+ sizeof(Eterm)*no_dist_port);
+ for (tdep = erts_hidden_dist_entries; tdep; tdep = tdep->next) {
+ ASSERT(is_internal_port(tdep->cid));
+ dist_port[i++] = tdep->cid;
+ }
+ for (tdep = erts_visible_dist_entries; tdep; tdep = tdep->next) {
+ ASSERT(is_internal_port(tdep->cid));
+ dist_port[i++] = tdep->cid;
}
+ erts_smp_rwmtx_rwunlock(&erts_dist_table_rwmtx);
- erts_smp_rwmtx_rwlock(&erts_dist_table_rwmtx);
- }
+ for (i = 0; i < no_dist_port; i++) {
+ Port *prt = erts_port_lookup(dist_port[i],
+ ERTS_PORT_SFLGS_INVALID_LOOKUP);
+ if (!prt)
+ continue;
+ ASSERT(erts_atomic32_read_nob(&prt->state)
+ & ERTS_PORT_SFLG_DISTRIBUTION);
- erts_smp_rwmtx_rwunlock(&erts_dist_table_rwmtx);
+ erts_port_exit(NULL, ERTS_PORT_SIG_FLG_FORCE_SCHED,
+ prt, dist_port[i], nd_reason, NULL);
+ }
- nodename = erts_this_dist_entry->sysname;
- erts_smp_thr_progress_block();
- erts_set_this_node(am_Noname, 0);
- erts_is_alive = 0;
- send_nodes_mon_msgs(NULL, am_nodedown, nodename, am_visible, nd_reason);
- erts_smp_thr_progress_unblock();
+ if (dist_port != &def_buf[0])
+ erts_free(ERTS_ALC_T_TMP, dist_port);
+ }
+ /*
+ * When last dist port exits, node will be taken
+ * from alive to not alive.
+ */
+ ASSERT(is_nil(nodedown.reason) && !nodedown.bp);
+ if (is_immed(nd_reason))
+ nodedown.reason = nd_reason;
+ else {
+ Eterm *hp;
+ Uint sz = size_object(nd_reason);
+ nodedown.bp = new_message_buffer(sz);
+ hp = nodedown.bp->mem;
+ nodedown.reason = copy_struct(nd_reason,
+ sz,
+ &hp,
+ &nodedown.bp->off_heap);
+ }
}
- else { /* recursive call via erts_do_exit_port() will end up here */
+ else { /* Call from distribution port */
NetExitsContext nec = {dep};
ErtsLink *nlinks;
ErtsLink *node_links;
@@ -454,10 +530,10 @@ int erts_do_net_exits(DistEntry *dep, Eterm reason)
erts_smp_de_rwlock(dep);
ERTS_SMP_LC_ASSERT(is_internal_port(dep->cid)
- && erts_lc_is_port_locked(&erts_port[internal_port_index(dep->cid)]));
+ && erts_lc_is_port_locked(erts_port_lookup_raw(dep->cid)));
if (erts_port_task_is_scheduled(&dep->dist_cmd))
- erts_port_task_abort(dep->cid, &dep->dist_cmd);
+ erts_port_task_abort(&dep->dist_cmd);
if (dep->status & ERTS_DE_SFLG_EXITING) {
#ifdef DEBUG
@@ -503,6 +579,9 @@ int erts_do_net_exits(DistEntry *dep, Eterm reason)
clear_dist_entry(dep);
}
+
+ dec_no_nodes();
+
return 1;
}
@@ -516,6 +595,10 @@ void init_dist(void)
{
init_nodes_monitors();
+ nodedown.reason = NIL;
+ nodedown.bp = NULL;
+
+ erts_smp_atomic_init_nob(&no_nodes, 0);
erts_smp_atomic_init_nob(&no_caches, 0);
/* Lookup/Install all references to trap functions */
@@ -769,7 +852,7 @@ erts_dsig_send_msg(ErtsDSigData *dsdp, Eterm remote, Eterm message)
*node_name = *sender_name = *receiver_name = '\0';
if (DTRACE_ENABLED(message_send) || DTRACE_ENABLED(message_send_remote)) {
erts_snprintf(node_name, sizeof(node_name), "%T", dsdp->dep->sysname);
- erts_snprintf(sender_name, sizeof(sender_name), "%T", sender->id);
+ erts_snprintf(sender_name, sizeof(sender_name), "%T", sender->common.id);
erts_snprintf(receiver_name, sizeof(receiver_name), "%T", remote);
msize = size_object(message);
if (token != NIL && token != am_have_dt_utag) {
@@ -826,7 +909,7 @@ erts_dsig_send_reg_msg(ErtsDSigData *dsdp, Eterm remote_name, Eterm message)
*node_name = *sender_name = *receiver_name = '\0';
if (DTRACE_ENABLED(message_send) || DTRACE_ENABLED(message_send_remote)) {
erts_snprintf(node_name, sizeof(node_name), "%T", dsdp->dep->sysname);
- erts_snprintf(sender_name, sizeof(sender_name), "%T", sender->id);
+ erts_snprintf(sender_name, sizeof(sender_name), "%T", sender->common.id);
erts_snprintf(receiver_name, sizeof(receiver_name),
"{%T,%s}", remote_name, node_name);
msize = size_object(message);
@@ -840,10 +923,10 @@ erts_dsig_send_reg_msg(ErtsDSigData *dsdp, Eterm remote_name, Eterm message)
if (token != NIL)
ctl = TUPLE5(&ctl_heap[0], make_small(DOP_REG_SEND_TT),
- sender->id, am_Cookie, remote_name, token);
+ sender->common.id, am_Cookie, remote_name, token);
else
ctl = TUPLE4(&ctl_heap[0], make_small(DOP_REG_SEND),
- sender->id, am_Cookie, remote_name);
+ sender->common.id, am_Cookie, remote_name);
DTRACE6(message_send, sender_name, receiver_name,
msize, tok_label, tok_lastcnt, tok_serial);
DTRACE7(message_send_remote, sender_name, node_name, receiver_name,
@@ -889,7 +972,7 @@ erts_dsig_send_exit_tt(ErtsDSigData *dsdp, Eterm local, Eterm remote,
*node_name = *sender_name = *remote_name = '\0';
if (DTRACE_ENABLED(process_exit_signal_remote)) {
erts_snprintf(node_name, sizeof(node_name), "%T", dsdp->dep->sysname);
- erts_snprintf(sender_name, sizeof(sender_name), "%T", sender->id);
+ erts_snprintf(sender_name, sizeof(sender_name), "%T", sender->common.id);
erts_snprintf(remote_name, sizeof(remote_name),
"{%T,%s}", remote, node_name);
erts_snprintf(reason_str, sizeof(reason), "%T", reason);
@@ -1141,7 +1224,7 @@ int erts_net_message(Port *prt,
}
erts_smp_de_links_lock(dep);
- res = erts_add_link(&(rp->nlinks), LINK_PID, from);
+ res = erts_add_link(&ERTS_P_LINKS(rp), LINK_PID, from);
if (res < 0) {
/* It was already there! Lets skip the rest... */
@@ -1149,7 +1232,7 @@ int erts_net_message(Port *prt,
erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_LINK);
break;
}
- lnk = erts_add_or_lookup_link(&(dep->nlinks), LINK_PID, rp->id);
+ lnk = erts_add_or_lookup_link(&(dep->nlinks), LINK_PID, rp->common.id);
erts_add_link(&(ERTS_LINK_ROOT(lnk)), LINK_PID, from);
erts_smp_de_links_unlock(dep);
@@ -1176,7 +1259,7 @@ int erts_net_message(Port *prt,
if (!rp)
break;
- lnk = erts_remove_link(&(rp->nlinks), from);
+ lnk = erts_remove_link(&ERTS_P_LINKS(rp), from);
if (IS_TRACED_FL(rp, F_TRACE_PROCS) && lnk != NULL) {
trace_proc(NULL, rp, am_getting_unlinked, from);
@@ -1233,10 +1316,10 @@ int erts_net_message(Port *prt,
}
else {
if (is_atom(watched))
- watched = rp->id;
+ watched = rp->common.id;
erts_smp_de_links_lock(dep);
erts_add_monitor(&(dep->monitors), MON_ORIGIN, ref, watched, name);
- erts_add_monitor(&(rp->monitors), MON_TARGET, ref, watcher, name);
+ erts_add_monitor(&ERTS_P_MONITORS(rp), MON_TARGET, ref, watcher, name);
erts_smp_de_links_unlock(dep);
erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_LINK);
}
@@ -1275,7 +1358,7 @@ int erts_net_message(Port *prt,
if (!rp) {
break;
}
- mon = erts_remove_monitor(&(rp->monitors),ref);
+ mon = erts_remove_monitor(&ERTS_P_MONITORS(rp), ref);
erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_LINK);
ASSERT(mon != NULL);
if (mon == NULL) {
@@ -1432,7 +1515,7 @@ int erts_net_message(Port *prt,
erts_destroy_monitor(mon);
- mon = erts_remove_monitor(&(rp->monitors),ref);
+ mon = erts_remove_monitor(&ERTS_P_MONITORS(rp), ref);
if (mon == NULL) {
erts_smp_proc_unlock(rp, rp_locks);
@@ -1483,7 +1566,7 @@ int erts_net_message(Port *prt,
if (!rp)
lnk = NULL;
else {
- lnk = erts_remove_link(&(rp->nlinks), from);
+ lnk = erts_remove_link(&ERTS_P_LINKS(rp), from);
/* If lnk == NULL, we have unlinked on this side, i.e.
* ignore exit.
@@ -1597,7 +1680,7 @@ int erts_net_message(Port *prt,
erts_free(ERTS_ALC_T_DCTRL_BUF, (void *) ctl);
}
UnUseTmpHeapNoproc(DIST_CTL_DEFAULT_SIZE);
- erts_do_exit_port(prt, dep->cid, am_killed);
+ erts_deliver_port_exit(prt, dep->cid, am_killed, 0);
ERTS_SMP_CHK_NO_PROC_LOCKS;
return -1;
}
@@ -1693,7 +1776,6 @@ dsig_send(ErtsDSigData *dsdp, Eterm ctl, Eterm msg, int force_busy)
erts_smp_mtx_unlock(&dep->qlock);
plp = erts_proclist_create(c_p);
- plp->next = NULL;
erts_suspend(c_p, ERTS_PROC_LOCK_MAIN, NULL);
suspended = 1;
erts_smp_mtx_lock(&dep->qlock);
@@ -1726,11 +1808,7 @@ dsig_send(ErtsDSigData *dsdp, Eterm ctl, Eterm msg, int force_busy)
else {
/* Enqueue suspended process on dist entry */
ASSERT(plp);
- if (dep->suspended.last)
- dep->suspended.last->next = plp;
- else
- dep->suspended.first = plp;
- dep->suspended.last = plp;
+ erts_proclist_store_last(&dep->suspended, plp);
}
}
@@ -1779,7 +1857,7 @@ dsig_send(ErtsDSigData *dsdp, Eterm ctl, Eterm msg, int force_busy)
erts_snprintf(port_str, sizeof(port_str), "%T", cid);
erts_snprintf(remote_str, sizeof(remote_str), "%T", dep->sysname);
- erts_snprintf(pid_str, sizeof(pid_str), "%T", c_p->id);
+ erts_snprintf(pid_str, sizeof(pid_str), "%T", c_p->common.id);
DTRACE4(dist_port_busy, erts_this_node_sysname,
port_str, remote_str, pid_str);
}
@@ -1812,7 +1890,7 @@ dist_port_command(Port *prt, ErtsDistOutputBuf *obuf)
DTRACE_CHARBUF(port_str, 64);
DTRACE_CHARBUF(remote_str, 64);
- erts_snprintf(port_str, sizeof(port_str), "%T", prt->id);
+ erts_snprintf(port_str, sizeof(port_str), "%T", prt->common.id);
erts_snprintf(remote_str, sizeof(remote_str),
"%T", prt->dist_entry->sysname);
DTRACE4(dist_output, erts_this_node_sysname, port_str,
@@ -1866,7 +1944,7 @@ dist_port_commandv(Port *prt, ErtsDistOutputBuf *obuf)
DTRACE_CHARBUF(port_str, 64);
DTRACE_CHARBUF(remote_str, 64);
- erts_snprintf(port_str, sizeof(port_str), "%T", prt->id);
+ erts_snprintf(port_str, sizeof(port_str), "%T", prt->common.id);
erts_snprintf(remote_str, sizeof(remote_str),
"%T", prt->dist_entry->sysname);
DTRACE4(dist_outputv, erts_this_node_sysname, port_str,
@@ -1903,13 +1981,13 @@ int
erts_dist_command(Port *prt, int reds_limit)
{
Sint reds = ERTS_PORT_REDS_DIST_CMD_START;
- int prt_busy;
Uint32 status;
Uint32 flags;
Sint obufsize = 0;
ErtsDistOutputQueue oq, foq;
DistEntry *dep = prt->dist_entry;
Uint (*send)(Port *prt, ErtsDistOutputBuf *obuf);
+ erts_aint32_t sched_flags;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
@@ -1925,7 +2003,7 @@ erts_dist_command(Port *prt, int reds_limit)
erts_smp_de_runlock(dep);
if (status & ERTS_DE_SFLG_EXITING) {
- erts_do_exit_port(prt, prt->id, am_killed);
+ erts_deliver_port_exit(prt, prt->common.id, am_killed, 0);
erts_deref_dist_entry(dep);
return reds + ERTS_PORT_REDS_DIST_CMD_EXIT;
}
@@ -1952,12 +2030,12 @@ erts_dist_command(Port *prt, int reds_limit)
dep->finalized_out_queue.first = NULL;
dep->finalized_out_queue.last = NULL;
+ sched_flags = erts_smp_atomic32_read_nob(&prt->sched.flags);
+
if (reds > reds_limit)
goto preempted;
- prt_busy = (int) (prt->status & ERTS_PORT_SFLG_PORT_BUSY);
-
- if (!prt_busy && foq.first) {
+ if (!(sched_flags & ERTS_PTS_FLG_BUSY_PORT) && foq.first) {
int preempt = 0;
do {
Uint size;
@@ -1974,11 +2052,10 @@ erts_dist_command(Port *prt, int reds_limit)
obufsize += size_obuf(fob);
foq.first = foq.first->next;
free_dist_obuf(fob);
- preempt = reds > reds_limit || (prt->status & ERTS_PORT_SFLGS_DEAD);
- if (prt->status & ERTS_PORT_SFLG_PORT_BUSY) {
- prt_busy = 1;
+ sched_flags = erts_smp_atomic32_read_nob(&prt->sched.flags);
+ preempt = reds > reds_limit || (sched_flags & ERTS_PTS_FLG_EXIT);
+ if (sched_flags & ERTS_PTS_FLG_BUSY_PORT)
break;
- }
} while (foq.first && !preempt);
if (!foq.first)
foq.last = NULL;
@@ -1986,7 +2063,7 @@ erts_dist_command(Port *prt, int reds_limit)
goto preempted;
}
- if (prt_busy) {
+ if (sched_flags & ERTS_PTS_FLG_BUSY_PORT) {
if (oq.first) {
ErtsDistOutputBuf *ob;
int preempt;
@@ -2058,12 +2135,10 @@ erts_dist_command(Port *prt, int reds_limit)
obufsize += size_obuf(fob);
oq.first = oq.first->next;
free_dist_obuf(fob);
- preempt = reds > reds_limit || (prt->status & ERTS_PORT_SFLGS_DEAD);
- if (prt->status & ERTS_PORT_SFLG_PORT_BUSY) {
- prt_busy = 1;
- if (oq.first && !preempt)
- goto finalize_only;
- }
+ sched_flags = erts_smp_atomic32_read_nob(&prt->sched.flags);
+ preempt = reds > reds_limit || (sched_flags & ERTS_PTS_FLG_EXIT);
+ if ((sched_flags & ERTS_PTS_FLG_BUSY_PORT) && oq.first && !preempt)
+ goto finalize_only;
}
ASSERT(!oq.first || preempt);
@@ -2091,7 +2166,7 @@ erts_dist_command(Port *prt, int reds_limit)
ASSERT(dep->qsize >= obufsize);
dep->qsize -= obufsize;
obufsize = 0;
- if (!prt_busy
+ if (!(sched_flags & ERTS_PTS_FLG_BUSY_PORT)
&& (dep->qflgs & ERTS_DE_QFLG_BUSY)
&& dep->qsize < erts_dist_buf_busy_limit) {
ErtsProcList *suspendees;
@@ -2137,11 +2212,15 @@ erts_dist_command(Port *prt, int reds_limit)
return reds;
preempted:
+ /*
+ * Here we assume that state has been read
+ * since last call to driver.
+ */
ASSERT(oq.first || !oq.last);
ASSERT(!oq.first || oq.last);
- if (prt->status & ERTS_PORT_SFLGS_DEAD) {
+ if (sched_flags & ERTS_PTS_FLG_EXIT) {
/*
* Port died during port command; clean up 'oq'
* and 'foq'. Things buffered in dist entry after
@@ -2199,7 +2278,7 @@ erts_dist_port_not_busy(Port *prt)
DTRACE_CHARBUF(port_str, 64);
DTRACE_CHARBUF(remote_str, 64);
- erts_snprintf(port_str, sizeof(port_str), "%T", prt->id);
+ erts_snprintf(port_str, sizeof(port_str), "%T", prt->common.id);
erts_snprintf(remote_str, sizeof(remote_str),
"%T", prt->dist_entry->sysname);
DTRACE3(dist_port_not_busy, erts_this_node_sysname,
@@ -2241,7 +2320,7 @@ static void doit_print_monitor_info(ErtsMonitor *mon, void *vptdp)
Process *rp;
ErtsMonitor *rmon;
rp = erts_proc_lookup(mon->pid);
- if (!rp || (rmon = erts_lookup_monitor(rp->monitors, mon->ref)) == NULL) {
+ if (!rp || (rmon = erts_lookup_monitor(ERTS_P_MONITORS(rp), mon->ref)) == NULL) {
erts_print(to, arg, "Warning, stray monitor for: %T\n", mon->pid);
} else if (mon->type == MON_ORIGIN) {
/* Local pid is being monitored */
@@ -2486,6 +2565,7 @@ BIF_RETTYPE setnode_2(BIF_ALIST_2)
erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
erts_smp_thr_progress_block();
+ inc_no_nodes();
erts_set_this_node(BIF_ARG_1, (Uint32) creation);
erts_is_alive = 1;
send_nodes_mon_msgs(NULL, am_nodeup, BIF_ARG_1, am_visible, NIL);
@@ -2554,9 +2634,9 @@ BIF_RETTYPE setnode_3(BIF_ALIST_3)
/* DFLAG_EXTENDED_REFERENCES is compulsory from R9 and forward */
if (!(DFLAG_EXTENDED_REFERENCES & flags)) {
erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
- erts_dsprintf(dsbufp, "%T", BIF_P->id);
- if (BIF_P->reg)
- erts_dsprintf(dsbufp, " (%T)", BIF_P->reg->name);
+ erts_dsprintf(dsbufp, "%T", BIF_P->common.id);
+ if (BIF_P->common.u.alive.reg)
+ erts_dsprintf(dsbufp, " (%T)", BIF_P->common.u.alive.reg->name);
erts_dsprintf(dsbufp,
" attempted to enable connection to node %T "
"which is not able to handle extended references.\n",
@@ -2576,10 +2656,14 @@ BIF_RETTYPE setnode_3(BIF_ALIST_3)
else if (!dep)
goto system_limit; /* Should never happen!!! */
- pp = erts_id2port(BIF_ARG_2, BIF_P, ERTS_PROC_LOCK_MAIN);
+ pp = erts_id2port_sflgs(BIF_ARG_2,
+ BIF_P,
+ ERTS_PROC_LOCK_MAIN,
+ ERTS_PORT_SFLGS_INVALID_LOOKUP);
erts_smp_de_rwlock(dep);
- if (!pp || (pp->status & ERTS_PORT_SFLG_EXITING))
+ if (!pp || (erts_atomic32_read_nob(&pp->state)
+ & ERTS_PORT_SFLG_EXITING))
goto badarg;
if ((pp->drv_ptr->flags & ERL_DRV_FLAG_SOFT_BUSY) == 0)
@@ -2594,11 +2678,7 @@ BIF_RETTYPE setnode_3(BIF_ALIST_3)
plp->next = NULL;
erts_suspend(BIF_P, ERTS_PROC_LOCK_MAIN, NULL);
erts_smp_mtx_lock(&dep->qlock);
- if (dep->suspended.last)
- dep->suspended.last->next = plp;
- else
- dep->suspended.first = plp;
- dep->suspended.last = plp;
+ erts_proclist_store_last(&dep->suspended, plp);
erts_smp_mtx_unlock(&dep->qlock);
goto yield;
}
@@ -2608,7 +2688,16 @@ BIF_RETTYPE setnode_3(BIF_ALIST_3)
if (pp->dist_entry || is_not_nil(dep->cid))
goto badarg;
- erts_port_status_bor_set(pp, ERTS_PORT_SFLG_DISTRIBUTION);
+ erts_atomic32_read_bor_nob(&pp->state, ERTS_PORT_SFLG_DISTRIBUTION);
+
+ /*
+ * Dist-ports do not use the "busy port message queue" functionality, but
+ * instead use "busy dist entry" functionality.
+ */
+ {
+ ErlDrvSizeT disable = ERL_DRV_BUSY_MSGQ_DISABLED;
+ erl_drv_busy_msgq_limits((ErlDrvPort) pp, &disable, NULL);
+ }
pp->dist_entry = dep;
@@ -2640,6 +2729,8 @@ BIF_RETTYPE setnode_3(BIF_ALIST_3)
erts_smp_de_rwunlock(dep);
dep = NULL; /* inc of refc transferred to port (dist_entry field) */
+ inc_no_nodes();
+
send_nodes_mon_msgs(BIF_P,
am_nodeup,
BIF_ARG_1,
@@ -2653,7 +2744,7 @@ BIF_RETTYPE setnode_3(BIF_ALIST_3)
}
if (pp)
- erts_smp_port_unlock(pp);
+ erts_port_release(pp);
return ret;
@@ -2697,7 +2788,7 @@ BIF_RETTYPE dist_exit_3(BIF_ALIST_3)
if (is_internal_pid(local)) {
Process *lp;
ErtsProcLocks lp_locks;
- if (BIF_P->id == local) {
+ if (BIF_P->common.id == local) {
lp_locks = ERTS_PROC_LOCKS_ALL;
lp = BIF_P;
erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCKS_ALL_MINOR);
@@ -2725,11 +2816,17 @@ BIF_RETTYPE dist_exit_3(BIF_ALIST_3)
#endif
erts_smp_proc_unlock(lp, lp_locks);
if (lp == BIF_P) {
+ erts_aint32_t state = erts_smp_atomic32_read_acqb(&BIF_P->state);
/*
* We may have exited current process and may have to take action.
*/
- ERTS_BIF_CHK_EXITED(BIF_P);
- ERTS_SMP_BIF_CHK_PENDING_EXIT(BIF_P, ERTS_PROC_LOCK_MAIN);
+ if (state & (ERTS_PSFLG_EXITING|ERTS_PSFLG_PENDING_EXIT)) {
+#ifdef ERTS_SMP
+ if (state & ERTS_PSFLG_PENDING_EXIT)
+ erts_handle_pending_exit(BIF_P, ERTS_PROC_LOCK_MAIN);
+#endif
+ ERTS_BIF_EXITED(BIF_P);
+ }
}
}
else if (is_external_pid(local)
@@ -2927,23 +3024,23 @@ monitor_node(Process* p, Eterm Node, Eterm Bool, Eterm Options)
if (Bool == am_true) {
ASSERT(dep->cid != NIL);
lnk = erts_add_or_lookup_link(&(dep->node_links), LINK_NODE,
- p->id);
+ p->common.id);
++ERTS_LINK_REFC(lnk);
- lnk = erts_add_or_lookup_link(&(p->nlinks), LINK_NODE, Node);
+ lnk = erts_add_or_lookup_link(&ERTS_P_LINKS(p), LINK_NODE, Node);
++ERTS_LINK_REFC(lnk);
}
else {
- lnk = erts_lookup_link(dep->node_links, p->id);
+ lnk = erts_lookup_link(dep->node_links, p->common.id);
if (lnk != NULL) {
if ((--ERTS_LINK_REFC(lnk)) == 0) {
erts_destroy_link(erts_remove_link(&(dep->node_links),
- p->id));
+ p->common.id));
}
}
- lnk = erts_lookup_link(p->nlinks, Node);
+ lnk = erts_lookup_link(ERTS_P_LINKS(p), Node);
if (lnk != NULL) {
if ((--ERTS_LINK_REFC(lnk)) == 0) {
- erts_destroy_link(erts_remove_link(&(p->nlinks),
+ erts_destroy_link(erts_remove_link(&ERTS_P_LINKS(p),
Node));
}
}
@@ -3505,7 +3602,7 @@ erts_processes_monitoring_nodes(Process *c_p)
olist = erts_bld_cons(hpp, szp, am_nodedown_reason, olist);
res = erts_bld_cons(hpp, szp,
erts_bld_tuple(hpp, szp, 2,
- nmp->proc->id,
+ nmp->proc->common.id,
olist),
res);
}
diff --git a/erts/emulator/beam/dist.h b/erts/emulator/beam/dist.h
index 845151c895..2bc3d9c881 100644
--- a/erts/emulator/beam/dist.h
+++ b/erts/emulator/beam/dist.h
@@ -187,11 +187,12 @@ void erts_schedule_dist_command(Port *prt, DistEntry *dist_entry)
if (prt) {
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
- ASSERT((erts_port_status_get(prt) & ERTS_PORT_SFLGS_DEAD) == 0);
+ ASSERT((erts_atomic32_read_nob(&prt->state)
+ & ERTS_PORT_SFLGS_DEAD) == 0);
ASSERT(prt->dist_entry);
dep = prt->dist_entry;
- id = prt->id;
+ id = prt->common.id;
}
else {
ASSERT(dist_entry);
@@ -203,13 +204,8 @@ void erts_schedule_dist_command(Port *prt, DistEntry *dist_entry)
id = dep->cid;
}
- if (!erts_smp_atomic_xchg_mb(&dep->dist_cmd_scheduled, 1)) {
- (void) erts_port_task_schedule(id,
- &dep->dist_cmd,
- ERTS_PORT_TASK_DIST_CMD,
- (ErlDrvEvent) -1,
- NULL);
- }
+ if (!erts_smp_atomic_xchg_mb(&dep->dist_cmd_scheduled, 1))
+ erts_port_task_schedule(id, &dep->dist_cmd, ERTS_PORT_TASK_DIST_CMD);
}
#endif
diff --git a/erts/emulator/beam/erl_afit_alloc.c b/erts/emulator/beam/erl_afit_alloc.c
index 570cc59be2..306b32691c 100644
--- a/erts/emulator/beam/erl_afit_alloc.c
+++ b/erts/emulator/beam/erl_afit_alloc.c
@@ -37,6 +37,12 @@
#define GET_ERL_AF_ALLOC_IMPL
#include "erl_afit_alloc.h"
+struct AFFreeBlock_t_ {
+ Block_t block_head;
+ AFFreeBlock_t *prev;
+ AFFreeBlock_t *next;
+};
+#define AF_BLK_SZ(B) MBC_FBLK_SZ(&(B)->block_head)
#define MIN_MBC_SZ (16*1024)
#define MIN_MBC_FIRST_FREE_SZ (4*1024)
@@ -80,7 +86,6 @@ erts_afalc_start(AFAllctr_t *afallctr,
init->sbmbct = 0; /* Small mbc not supported by afit */
- allctr->mbc_header_size = sizeof(Carrier_t);
allctr->min_mbc_size = MIN_MBC_SZ;
allctr->min_mbc_first_free_size = MIN_MBC_FIRST_FREE_SZ;
allctr->min_block_size = sizeof(AFFreeBlock_t);
@@ -118,7 +123,7 @@ get_free_block(Allctr_t *allctr, Uint size, Block_t *cand_blk, Uint cand_size,
ASSERT(!cand_blk || cand_size >= size);
- if (afallctr->free_list && BLK_SZ(afallctr->free_list) >= size) {
+ if (afallctr->free_list && AF_BLK_SZ(afallctr->free_list) >= size) {
AFFreeBlock_t *res = afallctr->free_list;
afallctr->free_list = res->next;
if (res->next)
@@ -135,7 +140,7 @@ link_free_block(Allctr_t *allctr, Block_t *block, Uint32 flags)
AFFreeBlock_t *blk = (AFFreeBlock_t *) block;
AFAllctr_t *afallctr = (AFAllctr_t *) allctr;
- if (afallctr->free_list && BLK_SZ(afallctr->free_list) > BLK_SZ(blk)) {
+ if (afallctr->free_list && AF_BLK_SZ(afallctr->free_list) > AF_BLK_SZ(blk)) {
blk->next = afallctr->free_list->next;
blk->prev = afallctr->free_list;
afallctr->free_list->next = blk;
diff --git a/erts/emulator/beam/erl_afit_alloc.h b/erts/emulator/beam/erl_afit_alloc.h
index ea408a7194..87caccac20 100644
--- a/erts/emulator/beam/erl_afit_alloc.h
+++ b/erts/emulator/beam/erl_afit_alloc.h
@@ -49,11 +49,6 @@ Allctr_t *erts_afalc_start(AFAllctr_t *, AFAllctrInit_t *, AllctrInit_t *);
#include "erl_alloc_util.h"
typedef struct AFFreeBlock_t_ AFFreeBlock_t;
-struct AFFreeBlock_t_ {
- Block_t block_head;
- AFFreeBlock_t *prev;
- AFFreeBlock_t *next;
-};
struct AFAllctr_t_ {
Allctr_t allctr; /* Has to be first! */
diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c
index 3eee53eba3..5da8c69c03 100644
--- a/erts/emulator/beam/erl_alloc.c
+++ b/erts/emulator/beam/erl_alloc.c
@@ -310,9 +310,9 @@ set_default_ll_alloc_opts(struct au_init *ip)
ip->init.util.name_prefix = "ll_";
ip->init.util.alloc_no = ERTS_ALC_A_LONG_LIVED;
#ifndef SMALL_MEMORY
- ip->init.util.mmbcs = 2*1024*1024; /* Main carrier size */
+ ip->init.util.mmbcs = 2*1024*1024 - 40; /* Main carrier size */
#else
- ip->init.util.mmbcs = 1*1024*1024; /* Main carrier size */
+ ip->init.util.mmbcs = 1*1024*1024 - 40; /* Main carrier size */
#endif
ip->init.util.ts = ERTS_ALC_MTA_LONG_LIVED;
ip->init.util.asbcst = 0;
@@ -1173,6 +1173,11 @@ handle_au_arg(struct au_init *auip,
break;
case 'e':
auip->enable = get_bool_value(sub_param+1, argv, ip);
+#if !HAVE_ERTS_SBMBC
+ if (auip->init.util.alloc_no == ERTS_ALC_A_SBMBC) {
+ auip->enable = 0;
+ }
+#endif
break;
case 'l':
if (has_prefix("lmbcs", sub_param)) {
@@ -1233,10 +1238,16 @@ handle_au_arg(struct au_init *auip,
auip->init.util.sbct = get_kb_value(sub_param + 4, argv, ip);
}
else if (has_prefix("sbmbcs", sub_param)) {
- auip->init.util.sbmbcs = get_byte_value(sub_param + 6, argv, ip);
+#if HAVE_ERTS_SBMBC
+ auip->init.util.sbmbcs =
+#endif
+ get_byte_value(sub_param + 6, argv, ip);
}
else if (has_prefix("sbmbct", sub_param)) {
- auip->init.util.sbmbct = get_byte_value(sub_param + 6, argv, ip);
+#if HAVE_ERTS_SBMBC
+ auip->init.util.sbmbct =
+#endif
+ get_byte_value(sub_param + 6, argv, ip);
}
else if (has_prefix("smbcs", sub_param)) {
auip->default_.smbcs = 0;
@@ -1403,6 +1414,9 @@ handle_args(int *argc, char **argv, erts_alc_hndl_args_init_t *init)
else if (strcmp("max", arg) == 0) {
for (a = 0; a < aui_sz; a++)
aui[a]->enable = 1;
+#if !HAVE_ERTS_SBMBC
+ init->sbmbc_alloc.enable = 0;
+#endif
}
else if (strcmp("config", arg) == 0) {
init->erts_alloc_config = 1;
@@ -2128,6 +2142,7 @@ erts_memory(int *print_to_p, void *print_to_arg, void *proc, Eterm earg)
if (want_tot_or_sys || want.processes || want.processes_used) {
+ int max_processes = erts_ptab_max(&erts_proc);
UWord tmp;
if (ERTS_MEM_NEED_ALL_ALCU)
@@ -2137,7 +2152,7 @@ erts_memory(int *print_to_p, void *print_to_arg, void *proc, Eterm earg)
fi, ERTS_ALC_NO_FIXED_SIZES);
tmp = alcu_size(ERTS_ALC_A_EHEAP, NULL, 0);
}
- tmp += erts_max_processes*sizeof(Process*);
+ tmp += max_processes*sizeof(erts_smp_atomic_t);
tmp += erts_bif_timer_memory_size();
tmp += erts_tot_link_lh_size();
@@ -2268,6 +2283,8 @@ erts_allocated_areas(int *print_to_p, void *print_to_arg, void *proc)
Eterm res = THE_NON_VALUE;
int i, length;
Uint reserved_atom_space, atom_space;
+ int max_processes = erts_ptab_max(&erts_proc);
+ int max_ports = erts_ptab_max(&erts_port);
if (proc) {
ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_MAIN
@@ -2299,7 +2316,7 @@ erts_allocated_areas(int *print_to_p, void *print_to_arg, void *proc)
values[i].arity = 2;
values[i].name = "static";
values[i].ui[0] =
- erts_max_ports*sizeof(Port) /* Port table */
+ max_ports*sizeof(erts_smp_atomic_t) /* Port table */
+ erts_timer_wheel_memory_size(); /* Timer wheel */
i++;
@@ -2378,7 +2395,7 @@ erts_allocated_areas(int *print_to_p, void *print_to_arg, void *proc)
values[i].arity = 2;
values[i].name = "process_table";
- values[i].ui[0] = erts_max_processes*sizeof(Process*);
+ values[i].ui[0] = max_processes*sizeof(Process*);
i++;
values[i].arity = 2;
diff --git a/erts/emulator/beam/erl_alloc.h b/erts/emulator/beam/erl_alloc.h
index e475f9d8a2..ba5ec9c367 100644
--- a/erts/emulator/beam/erl_alloc.h
+++ b/erts/emulator/beam/erl_alloc.h
@@ -267,6 +267,8 @@ typedef void (*erts_alloc_verify_func_t)(Allctr_t *);
erts_alloc_verify_func_t
erts_alloc_get_verify_unused_temp_alloc(Allctr_t **allctr);
+#define ERTS_ALC_DATA_ALIGN_SIZE(SZ) \
+ (((((SZ) - 1) / 8) + 1) * 8)
#define ERTS_ALC_CACHE_LINE_ALIGN_SIZE(SZ) \
(((((SZ) - 1) / ERTS_CACHE_LINE_SIZE) + 1) * ERTS_CACHE_LINE_SIZE)
diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types
index 0a4407f009..d4de0d076a 100644
--- a/erts/emulator/beam/erl_alloc.types
+++ b/erts/emulator/beam/erl_alloc.types
@@ -146,6 +146,7 @@ class SYSTEM system_data
type SBMBC SBMBC SYSTEM small_block_mbc
type PROC FIXED_SIZE PROCESSES proc
+type PORT DRIVER SYSTEM port
type ATOM LONG_LIVED ATOM atom_entry
type MODULE LONG_LIVED CODE module_entry
type REG_PROC STANDARD PROCESSES reg_proc
@@ -189,7 +190,10 @@ type PORT_TABLE LONG_LIVED SYSTEM port_tab
type TIMER_WHEEL LONG_LIVED SYSTEM timer_wheel
type DRV DRIVER SYSTEM drv_internal
type DRV_BINARY BINARY BINARIES drv_binary
-type DRIVER STANDARD SYSTEM driver
+type DRIVER DRIVER SYSTEM driver
+type DRV_CMD_DATA DRIVER SYSTEM driver_command_data
+type DRV_CTRL_DATA DRIVER SYSTEM driver_control_data
+type DRV_CALL_DATA DRIVER SYSTEM driver_call_data
type NIF DRIVER SYSTEM nif_internal
type BINARY BINARY BINARIES binary
type NBIF_TABLE SYSTEM SYSTEM nbif_tab
@@ -197,14 +201,12 @@ type ARG_REG STANDARD PROCESSES arg_reg
type PROC_DICT STANDARD PROCESSES proc_dict
type CALLS_BUF STANDARD PROCESSES calls_buf
type BPD STANDARD SYSTEM bpd
-type PORT_NAME STANDARD SYSTEM port_name
type LINEBUF STANDARD SYSTEM line_buf
type IOQ STANDARD SYSTEM io_queue
type BITS_BUF STANDARD SYSTEM bits_buf
type TMP_DIST_BUF TEMPORARY SYSTEM tmp_dist_buf
type ASYNC_DATA LONG_LIVED SYSTEM internal_async_data
type ESTACK TEMPORARY SYSTEM estack
-type PORT_CALL_BUF TEMPORARY SYSTEM port_call_buf
type DB_TABLE ETS ETS db_tab
type DB_FIXATION SHORT_LIVED ETS db_fixation
type DB_FIX_DEL SHORT_LIVED ETS fixed_del
@@ -234,14 +236,14 @@ type DDLL_HANDLE STANDARD SYSTEM ddll_handle
type DDLL_ERRCODES LONG_LIVED SYSTEM ddll_errcodes
type DDLL_TMP_BUF TEMPORARY SYSTEM ddll_tmp_buf
type PORT_TASK SHORT_LIVED SYSTEM port_task
-type PORT_TASKQ SHORT_LIVED SYSTEM port_task_queue
+type PT_HNDL_LIST SHORT_LIVED SYSTEM port_task_handle_list
type MISC_OP_LIST SHORT_LIVED SYSTEM misc_op_list
type PORT_NAMES SHORT_LIVED SYSTEM port_names
-type PORT_DATA_LOCK STANDARD SYSTEM port_data_lock
+type PORT_DATA_LOCK DRIVER SYSTEM port_data_lock
type NODES_MON STANDARD PROCESSES nodes_monitor
-type PROCS_TPROC_EL SHORT_LIVED PROCESSES processes_term_proc_el
-type PROCS_CNKINF SHORT_LIVED PROCESSES processes_chunk_info
-type PROCS_PIDS SHORT_LIVED PROCESSES processes_pids
+type PTAB_LIST_DEL SHORT_LIVED PROCESSES ptab_list_deleted_el
+type PTAB_LIST_CNKI SHORT_LIVED PROCESSES ptab_list_chunk_info
+type PTAB_LIST_PIDS SHORT_LIVED PROCESSES ptab_list_pids
type RE_TMP_BUF TEMPORARY SYSTEM re_tmp_buf
type RE_SUBJECT SHORT_LIVED SYSTEM re_subject
type RE_HEAP STANDARD SYSTEM re_heap
@@ -266,6 +268,8 @@ type AUX_WORK_TMO LONG_LIVED SYSTEM aux_work_timeouts
type MISC_AUX_WORK_Q LONG_LIVED SYSTEM misc_aux_work_q
type CODE_IX_LOCK_Q SHORT_LIVED SYSTEM code_ix_lock_q
type PROC_INTERVAL LONG_LIVED SYSTEM process_interval
+type BUSY_CALLER_TAB SHORT_LIVED SYSTEM busy_caller_table
+type BUSY_CALLER SHORT_LIVED SYSTEM busy_caller
+if threads_no_smp
# Need thread safe allocs, but std_alloc and fix_alloc are not;
diff --git a/erts/emulator/beam/erl_alloc_util.c b/erts/emulator/beam/erl_alloc_util.c
index 97ba306a79..3d6761339b 100644
--- a/erts/emulator/beam/erl_alloc_util.c
+++ b/erts/emulator/beam/erl_alloc_util.c
@@ -78,10 +78,12 @@ int erts_have_sbmbc_alloc;
#if HAVE_ERTS_MSEG
-#define INV_MSEG_UNIT_MASK ((UWord) (mseg_unit_size - 1))
-#define MSEG_UNIT_MASK (~INV_MSEG_UNIT_MASK)
+#define MSEG_UNIT_SHIFT MSEG_ALIGN_BITS
+#define MSEG_UNIT_SZ (1 << MSEG_UNIT_SHIFT)
+#define MSEG_UNIT_MASK ((~(UWord)0) << MSEG_UNIT_SHIFT)
+
#define MSEG_UNIT_FLOOR(X) ((X) & MSEG_UNIT_MASK)
-#define MSEG_UNIT_CEILING(X) MSEG_UNIT_FLOOR((X) + INV_MSEG_UNIT_MASK)
+#define MSEG_UNIT_CEILING(X) MSEG_UNIT_FLOOR((X) + ~MSEG_UNIT_MASK)
#endif
@@ -104,7 +106,6 @@ int erts_have_sbmbc_alloc;
static Uint sys_alloc_carrier_size;
#if HAVE_ERTS_MSEG
static Uint max_mseg_carriers;
-static Uint mseg_unit_size;
#endif
#define ONE_GIGA (1000000000)
@@ -117,16 +118,47 @@ static Uint mseg_unit_size;
? ((CC).giga_no--, (CC).no = ONE_GIGA - 1) \
: (CC).no--)
-/* ... */
+/* Multi block carrier (MBC) memory layout in R16:
+
+Empty MBC:
+[Carrier_t|pad|Block_t L0T|fhdr| free... ]
+
+MBC after allocating first block:
+[Carrier_t|pad|Block_t 000| udata |pad|Block_t L0T|fhdr| free... ]
+
+MBC after allocating second block:
+[Carrier_t|pad|Block_t 000| udata |pad|Block_t 000| udata |pad|Block_t L0T|fhdr| free... ]
+
+MBC after deallocating first block:
+[Carrier_t|pad|Block_t 00T|fhdr| free |FreeBlkFtr_t|Block_t 0P0| udata |pad|Block_t L0T|fhdr| free... ]
+
+
+ udata = Allocated user data
+ pad = Padding to ensure correct alignment for user data
+ fhdr = Allocator specific header to keep track of free block
+ free = Unused free memory
+ T = This block is free (THIS_FREE_BLK_HDR_FLG)
+ P = Previous block is free (PREV_FREE_BLK_HDR_FLG)
+ L = Last block in carrier (LAST_BLK_HDR_FLG)
+*/
+
+/* Single block carrier (SBC):
+[Carrier_t|pad|Block_t 111| udata... ]
+*/
+
/* Blocks ... */
-#define SBC_BLK_FTR_FLG (((UWord) 1) << 0)
+#define UNUSED0_BLK_FTR_FLG (((UWord) 1) << 0)
#define UNUSED1_BLK_FTR_FLG (((UWord) 1) << 1)
#define UNUSED2_BLK_FTR_FLG (((UWord) 1) << 2)
-#define ABLK_HDR_SZ (sizeof(Block_t))
-#define FBLK_FTR_SZ (sizeof(UWord))
+#if MBC_ABLK_OFFSET_BITS
+# define ABLK_HDR_SZ (offsetof(Block_t,u))
+#else
+# define ABLK_HDR_SZ (sizeof(Block_t))
+#endif
+#define FBLK_FTR_SZ (sizeof(FreeBlkFtr_t))
#define UMEMSZ2BLKSZ(AP, SZ) \
(ABLK_HDR_SZ + (SZ) <= (AP)->min_block_size \
@@ -136,88 +168,181 @@ static Uint mseg_unit_size;
#define UMEM2BLK(P) ((Block_t *) (((char *) (P)) - ABLK_HDR_SZ))
#define BLK2UMEM(P) ((void *) (((char *) (P)) + ABLK_HDR_SZ))
-#define PREV_BLK_SZ(B) \
- ((UWord) (*(((UWord *) (B)) - 1) & SZ_MASK))
+#define PREV_BLK_SZ(B) ((UWord) (((FreeBlkFtr_t *)(B))[-1]))
#define SET_BLK_SZ_FTR(B, SZ) \
- (*((UWord *) (((char *) (B)) + (SZ) - sizeof(UWord))) = (SZ))
+ (((FreeBlkFtr_t *) (((char *) (B)) + (SZ)))[-1] = (SZ))
#define THIS_FREE_BLK_HDR_FLG (((UWord) 1) << 0)
#define PREV_FREE_BLK_HDR_FLG (((UWord) 1) << 1)
#define LAST_BLK_HDR_FLG (((UWord) 1) << 2)
-#define SET_BLK_SZ(B, SZ) \
+/* Special flag combo for (allocated) SBC blocks
+*/
+#define SBC_BLK_HDR_FLG (THIS_FREE_BLK_HDR_FLG | PREV_FREE_BLK_HDR_FLG | LAST_BLK_HDR_FLG)
+
+#define SET_MBC_ABLK_SZ(B, SZ) \
(ASSERT(((SZ) & FLG_MASK) == 0), \
- (*((Block_t *) (B)) = ((*((Block_t *) (B)) & FLG_MASK) | (SZ))))
-#define SET_BLK_FREE(B) \
- (*((Block_t *) (B)) |= THIS_FREE_BLK_HDR_FLG)
-#define SET_BLK_ALLOCED(B) \
- (*((Block_t *) (B)) &= ~THIS_FREE_BLK_HDR_FLG)
-#define SET_PREV_BLK_FREE(B) \
- (*((Block_t *) (B)) |= PREV_FREE_BLK_HDR_FLG)
+ (B)->bhdr = (((B)->bhdr) & ~MBC_ABLK_SZ_MASK) | (SZ))
+#define SET_MBC_FBLK_SZ(B, SZ) \
+ (ASSERT(((SZ) & FLG_MASK) == 0), \
+ (B)->bhdr = (((B)->bhdr) & ~MBC_FBLK_SZ_MASK) | (SZ))
+#define SET_SBC_BLK_SZ(B, SZ) \
+ (ASSERT(((SZ) & FLG_MASK) == 0), \
+ (B)->bhdr = (((B)->bhdr) & ~SBC_BLK_SZ_MASK) | (SZ))
+#define SET_PREV_BLK_FREE(AP,B) \
+ (ASSERT(!IS_MBC_FIRST_BLK(AP,B)), \
+ ASSERT(!IS_FREE_BLK(B)), \
+ (B)->bhdr |= PREV_FREE_BLK_HDR_FLG)
#define SET_PREV_BLK_ALLOCED(B) \
- (*((Block_t *) (B)) &= ~PREV_FREE_BLK_HDR_FLG)
+ ((B)->bhdr &= ~PREV_FREE_BLK_HDR_FLG)
#define SET_LAST_BLK(B) \
- (*((Block_t *) (B)) |= LAST_BLK_HDR_FLG)
+ ((B)->bhdr |= LAST_BLK_HDR_FLG)
#define SET_NOT_LAST_BLK(B) \
- (*((Block_t *) (B)) &= ~LAST_BLK_HDR_FLG)
+ ((B)->bhdr &= ~LAST_BLK_HDR_FLG)
#define SBH_THIS_FREE THIS_FREE_BLK_HDR_FLG
-#define SBH_THIS_ALLOCED ((UWord) 0)
#define SBH_PREV_FREE PREV_FREE_BLK_HDR_FLG
-#define SBH_PREV_ALLOCED ((UWord) 0)
#define SBH_LAST_BLK LAST_BLK_HDR_FLG
-#define SBH_NOT_LAST_BLK ((UWord) 0)
-#define SET_BLK_HDR(B, Sz, F) \
- (ASSERT(((Sz) & FLG_MASK) == 0), *((Block_t *) (B)) = ((Sz) | (F)))
+
+#if MBC_ABLK_OFFSET_BITS
+
+# define MBC_SZ_MAX_LIMIT ((((UWord)1 << MBC_ABLK_OFFSET_BITS) - 1) << MSEG_ALIGN_BITS)
+
+# define BLK_CARRIER_OFFSET(B, C) (((char*)(B) - (char*)(C)) >> MSEG_UNIT_SHIFT)
+
+# define SET_MBC_ABLK_HDR(B, Sz, F, C) \
+ (ASSERT(((Sz) & ~MBC_ABLK_SZ_MASK) == 0), \
+ ASSERT(!((UWord)(F) & (~FLG_MASK|THIS_FREE_BLK_HDR_FLG))), \
+ (B)->bhdr = ((Sz) | (F) | (BLK_CARRIER_OFFSET(B,C) << MBC_ABLK_OFFSET_SHIFT)))
+
+# define SET_MBC_FBLK_HDR(B, Sz, F, C) \
+ (ASSERT(((Sz) & ~MBC_FBLK_SZ_MASK) == 0), \
+ ASSERT(((UWord)(F) & (~FLG_MASK|THIS_FREE_BLK_HDR_FLG|PREV_FREE_BLK_HDR_FLG)) == THIS_FREE_BLK_HDR_FLG), \
+ (B)->bhdr = ((Sz) | (F)), \
+ (B)->u.carrier = (C))
+
+# define ABLK_TO_MBC(B) \
+ (ASSERT(IS_MBC_BLK(B) && IS_ALLOCED_BLK(B)), \
+ (Carrier_t*)((MSEG_UNIT_FLOOR((UWord)(B)) - \
+ (((B)->bhdr >> MBC_ABLK_OFFSET_SHIFT) << MSEG_UNIT_SHIFT))))
+
+# define FBLK_TO_MBC(B) \
+ (ASSERT(IS_MBC_BLK(B) && IS_FREE_BLK(B)), \
+ (B)->u.carrier)
+
+# define BLK_TO_MBC(B) (IS_FREE_BLK(B) ? FBLK_TO_MBC(B) : ABLK_TO_MBC(B))
+
+# define IS_MBC_FIRST_ABLK(AP,B) \
+ ((((UWord)(B) & ~MSEG_UNIT_MASK) == MBC_HEADER_SIZE(AP)) \
+ && ((B)->bhdr & MBC_ABLK_OFFSET_MASK) == 0)
+
+# define IS_MBC_FIRST_FBLK(AP,B) \
+ ((char*)(B) == (char*)((B)->u.carrier) + MBC_HEADER_SIZE(AP))
+
+# define IS_MBC_FIRST_BLK(AP,B) \
+ (IS_FREE_BLK(B) ? IS_MBC_FIRST_FBLK(AP,B) : IS_MBC_FIRST_ABLK(AP,B))
+
+# define SET_BLK_FREE(B) \
+ (ASSERT(!IS_PREV_BLK_FREE(B)), \
+ (B)->u.carrier = ABLK_TO_MBC(B), \
+ (B)->bhdr |= THIS_FREE_BLK_HDR_FLG, \
+ (B)->bhdr &= (MBC_ABLK_SZ_MASK|FLG_MASK))
+
+# define SET_BLK_ALLOCED(B) \
+ (ASSERT(((B)->bhdr & (MBC_ABLK_OFFSET_MASK|THIS_FREE_BLK_HDR_FLG)) == THIS_FREE_BLK_HDR_FLG), \
+ (B)->bhdr &= ~THIS_FREE_BLK_HDR_FLG, \
+ (B)->bhdr |= (BLK_CARRIER_OFFSET(B,(B)->u.carrier) << MBC_ABLK_OFFSET_SHIFT))
+
+#else /* !MBC_ABLK_OFFSET_BITS */
+
+# define MBC_SZ_MAX_LIMIT ((UWord)~0)
+
+# define SET_MBC_ABLK_HDR(B, Sz, F, C) \
+ (ASSERT(((Sz) & FLG_MASK) == 0), \
+ ASSERT(!((UWord)(F) & (~FLG_MASK|THIS_FREE_BLK_HDR_FLG))), \
+ ASSERT((UWord)(F) < SBC_BLK_HDR_FLG), \
+ (B)->bhdr = ((Sz) | (F)), \
+ (B)->carrier = (C))
+
+# define SET_MBC_FBLK_HDR(B, Sz, F, C) \
+ (ASSERT(((Sz) & FLG_MASK) == 0), \
+ ASSERT(((UWord)(F) & (~FLG_MASK|THIS_FREE_BLK_HDR_FLG|PREV_FREE_BLK_HDR_FLG)) == THIS_FREE_BLK_HDR_FLG), \
+ (B)->bhdr = ((Sz) | (F)), \
+ (B)->carrier = (C))
+
+# define BLK_TO_MBC(B) ((B)->carrier)
+# define ABLK_TO_MBC(B) BLK_TO_MBC(B)
+# define FBLK_TO_MBC(B) BLK_TO_MBC(B)
+
+# define IS_MBC_FIRST_BLK(AP,B) \
+ ((char*)(B) == (char*)((B)->carrier) + MBC_HEADER_SIZE(AP))
+# define IS_MBC_FIRST_ABLK(AP,B) IS_MBC_FIRST_BLK(AP,B)
+# define IS_MBC_FIRST_FBLK(AP,B) IS_MBC_FIRST_BLK(AP,B)
+
+# define SET_BLK_FREE(B) \
+ (ASSERT(!IS_PREV_BLK_FREE(B)), \
+ (B)->bhdr |= THIS_FREE_BLK_HDR_FLG)
+
+# define SET_BLK_ALLOCED(B) \
+ ((B)->bhdr &= ~THIS_FREE_BLK_HDR_FLG)
+
+#endif /* !MBC_ABLK_OFFSET_BITS */
+
+#define SET_SBC_BLK_HDR(B, Sz) \
+ (ASSERT(((Sz) & FLG_MASK) == 0), (B)->bhdr = ((Sz) | (SBC_BLK_HDR_FLG)))
+
#define BLK_UMEM_SZ(B) \
(BLK_SZ(B) - (ABLK_HDR_SZ))
#define IS_PREV_BLK_FREE(B) \
- (*((Block_t *) (B)) & PREV_FREE_BLK_HDR_FLG)
+ ((B)->bhdr & PREV_FREE_BLK_HDR_FLG)
#define IS_PREV_BLK_ALLOCED(B) \
(!IS_PREV_BLK_FREE((B)))
#define IS_FREE_BLK(B) \
- (*((Block_t *) (B)) & THIS_FREE_BLK_HDR_FLG)
+ (ASSERT(!IS_SBC_BLK(B)), (B)->bhdr & THIS_FREE_BLK_HDR_FLG)
#define IS_ALLOCED_BLK(B) \
(!IS_FREE_BLK((B)))
#define IS_LAST_BLK(B) \
- (*((Block_t *) (B)) & LAST_BLK_HDR_FLG)
+ ((B)->bhdr & LAST_BLK_HDR_FLG)
#define IS_NOT_LAST_BLK(B) \
(!IS_LAST_BLK((B)))
#define GET_LAST_BLK_HDR_FLG(B) \
- (*((Block_t*) (B)) & LAST_BLK_HDR_FLG)
+ ((B)->bhdr & LAST_BLK_HDR_FLG)
#define GET_THIS_FREE_BLK_HDR_FLG(B) \
- (*((Block_t*) (B)) & THIS_FREE_BLK_HDR_FLG)
+ ((B)->bhdr & THIS_FREE_BLK_HDR_FLG)
#define GET_PREV_FREE_BLK_HDR_FLG(B) \
- (*((Block_t*) (B)) & PREV_FREE_BLK_HDR_FLG)
+ ((B)->bhdr & PREV_FREE_BLK_HDR_FLG)
#define GET_BLK_HDR_FLGS(B) \
- (*((Block_t*) (B)) & FLG_MASK)
-
-#define IS_FIRST_BLK(B) \
- (IS_PREV_BLK_FREE((B)) && (PREV_BLK_SZ((B)) == 0))
-#define IS_NOT_FIRST_BLK(B) \
- (!IS_FIRST_BLK((B)))
-
-#define SET_SBC_BLK_FTR(FTR) \
- ((FTR) = (0 | SBC_BLK_FTR_FLG))
-#define SET_MBC_BLK_FTR(FTR) \
- ((FTR) = 0)
+ ((B)->bhdr & FLG_MASK)
#define IS_SBC_BLK(B) \
- (IS_PREV_BLK_FREE((B)) && (((UWord *) (B))[-1] & SBC_BLK_FTR_FLG))
+ (((B)->bhdr & FLG_MASK) == SBC_BLK_HDR_FLG)
#define IS_MBC_BLK(B) \
(!IS_SBC_BLK((B)))
+#define MBC_BLK_SZ(B) (IS_FREE_BLK(B) ? MBC_FBLK_SZ(B) : MBC_ABLK_SZ(B))
+
#define NXT_BLK(B) \
- ((Block_t *) (((char *) (B)) + BLK_SZ((B))))
+ (ASSERT(IS_MBC_BLK(B)), \
+ (Block_t *) (((char *) (B)) + MBC_BLK_SZ((B))))
#define PREV_BLK(B) \
((Block_t *) (((char *) (B)) - PREV_BLK_SZ((B))))
+#define BLK_AFTER(B,Sz) \
+ ((Block_t *) (((char *) (B)) + (Sz)))
+
+#define BLK_SZ(B) ((B)->bhdr & (((B)->bhdr & THIS_FREE_BLK_HDR_FLG) ? MBC_FBLK_SZ_MASK : MBC_ABLK_SZ_MASK))
+
/* Carriers ... */
+#define SBC_HEADER_SIZE (UNIT_CEILING(sizeof(Carrier_t) + ABLK_HDR_SZ) \
+ - ABLK_HDR_SZ)
+#define MBC_HEADER_SIZE(AP) SBC_HEADER_SIZE
+
+
#define MSEG_CARRIER_HDR_FLAG (((UWord) 1) << 0)
#define SBC_CARRIER_HDR_FLAG (((UWord) 1) << 1)
@@ -226,20 +351,20 @@ static Uint mseg_unit_size;
#define SCH_MBC 0
#define SCH_SBC SBC_CARRIER_HDR_FLAG
-#define SET_CARRIER_HDR(C, Sz, F) \
- (ASSERT(((Sz) & FLG_MASK) == 0), (C)->chdr = ((Sz) | (F)))
+#define SET_CARRIER_HDR(C, Sz, F, AP) \
+ (ASSERT(((Sz) & FLG_MASK) == 0), (C)->chdr = ((Sz) | (F)), (C)->allctr = (AP))
-#define BLK2SBC(AP, B) \
- ((Carrier_t *) (((char *) (B)) - (AP)->sbc_header_size))
-#define FBLK2MBC(AP, B) \
- ((Carrier_t *) (((char *) (B)) - (AP)->mbc_header_size))
+#define BLK_TO_SBC(B) \
+ ((Carrier_t *) (((char *) (B)) - SBC_HEADER_SIZE))
+#define FIRST_BLK_TO_MBC(AP, B) \
+ ((Carrier_t *) (((char *) (B)) - MBC_HEADER_SIZE(AP)))
-#define MBC2FBLK(AP, P) \
- ((Block_t *) (((char *) (P)) + (AP)->mbc_header_size))
+#define MBC_TO_FIRST_BLK(AP, P) \
+ ((Block_t *) (((char *) (P)) + MBC_HEADER_SIZE(AP)))
#define SBC2BLK(AP, P) \
- ((Block_t *) (((char *) (P)) + (AP)->sbc_header_size))
+ ((Block_t *) (((char *) (P)) + SBC_HEADER_SIZE))
#define SBC2UMEM(AP, P) \
- ((void *) (((char *) (P)) + ((AP)->sbc_header_size + ABLK_HDR_SZ)))
+ ((void *) (((char *) (P)) + (SBC_HEADER_SIZE + ABLK_HDR_SZ)))
#define IS_MSEG_CARRIER(C) \
((C)->chdr & MSEG_CARRIER_HDR_FLAG)
@@ -250,15 +375,6 @@ static Uint mseg_unit_size;
#define IS_MB_CARRIER(C) \
(!IS_SB_CARRIER((C)))
-#define SET_MSEG_CARRIER(C) \
- ((C)->chdr |= MSEG_CARRIER_HDR_FLAG)
-#define SET_SYS_ALLOC_CARRIER(C) \
- ((C)->chdr &= ~MSEG_CARRIER_HDR_FLAG)
-#define SET_SB_CARRIER(C) \
- ((C)->chdr |= SBC_CARRIER_HDR_FLAG)
-#define SET_MB_CARRIER(C) \
- ((C)->chdr &= ~SBC_CARRIER_HDR_FLAG)
-
#define SET_CARRIER_SZ(C, SZ) \
(ASSERT(((SZ) & FLG_MASK) == 0), \
((C)->chdr = ((C)->chdr & FLG_MASK) | (SZ)))
@@ -506,11 +622,11 @@ static void mbc_free(Allctr_t *allctr, void *p);
#if HAVE_ERTS_MSEG
static ERTS_INLINE void *
-alcu_mseg_alloc(Allctr_t *allctr, Uint *size_p)
+alcu_mseg_alloc(Allctr_t *allctr, Uint *size_p, Uint flags)
{
void *res;
- res = erts_mseg_alloc_opt(allctr->alloc_no, size_p, &allctr->mseg_opt);
+ res = erts_mseg_alloc_opt(allctr->alloc_no, size_p, flags, &allctr->mseg_opt);
INC_CC(allctr->calls.mseg_alloc);
return res;
}
@@ -521,7 +637,7 @@ alcu_mseg_realloc(Allctr_t *allctr, void *seg, Uint old_size, Uint *new_size_p)
void *res;
res = erts_mseg_realloc_opt(allctr->alloc_no, seg, old_size, new_size_p,
- &allctr->mseg_opt);
+ ERTS_MSEG_FLG_NONE, &allctr->mseg_opt);
INC_CC(allctr->calls.mseg_realloc);
return res;
}
@@ -765,13 +881,9 @@ erts_alcu_fix_alloc_shrink(Allctr_t *allctr, erts_aint32_t flgs)
#define ERTS_ALCU_DD_FIX_TYPE_OFFS \
((sizeof(ErtsAllctrDDBlock_t)-1)/sizeof(UWord) + 1)
-#define ERTS_AU_PREF_ALLOC_IX_MASK \
- ((((UWord) 1) << ERTS_AU_PREF_ALLOC_BITS) - 1)
-#define ERTS_AU_PREF_ALLOC_SIZE_MASK \
- ((((UWord) 1) << (sizeof(UWord)*8 - ERTS_AU_PREF_ALLOC_BITS)) - 1)
-static ERTS_INLINE int
-get_pref_allctr(void *extra, Allctr_t **allctr)
+static ERTS_INLINE Allctr_t*
+get_pref_allctr(void *extra)
{
ErtsAllocatorThrSpec_t *tspec = (ErtsAllocatorThrSpec_t *) extra;
int pref_ix;
@@ -781,34 +893,33 @@ get_pref_allctr(void *extra, Allctr_t **allctr)
ASSERT(sizeof(UWord) == sizeof(Allctr_t *));
ASSERT(0 <= pref_ix && pref_ix < tspec->size);
- *allctr = tspec->allctr[pref_ix];
- return pref_ix;
+ return tspec->allctr[pref_ix];
}
-static ERTS_INLINE void *
-get_used_allctr(void *extra, void *p, Allctr_t **allctr, UWord *sizep)
+/* SMP note:
+ * get_used_allctr() must be safe WITHOUT locking the allocator while
+ * concurrent threads may be updating adjacent blocks.
+ * We rely on getting a consistent result (without atomic op) when reading
+ * the block header word even if a concurrent thread is updating
+ * the "PREV_FREE" flag bit.
+ */
+static ERTS_INLINE Allctr_t*
+get_used_allctr(void *extra, void *p, UWord *sizep)
{
- ErtsAllocatorThrSpec_t *tspec = (ErtsAllocatorThrSpec_t *) extra;
- void *ptr = (void *) (((char *) p) - sizeof(UWord));
- UWord ainfo = *((UWord *) ptr);
- int aix = (int) (ainfo & ERTS_AU_PREF_ALLOC_IX_MASK);
- *allctr = tspec->allctr[aix];
- if (sizep)
- *sizep = ((ainfo >> ERTS_AU_PREF_ALLOC_BITS)
- & ERTS_AU_PREF_ALLOC_SIZE_MASK);
- return ptr;
-}
+ Block_t* blk = UMEM2BLK(p);
+ Carrier_t* crr;
-static ERTS_INLINE void *
-put_used_allctr(void *p, int ix, UWord size)
-{
- UWord ainfo = (size >= ERTS_AU_PREF_ALLOC_SIZE_MASK
- ? ERTS_AU_PREF_ALLOC_SIZE_MASK
- : size);
- ainfo <<= ERTS_AU_PREF_ALLOC_BITS;
- ainfo |= (UWord) ix;
- *((UWord *) p) = ainfo;
- return (void *) (((char *) p) + sizeof(UWord));
+ if (IS_SBC_BLK(blk)) {
+ crr = BLK_TO_SBC(blk);
+ if (sizep)
+ *sizep = SBC_BLK_SZ(blk) - ABLK_HDR_SZ;
+ }
+ else {
+ crr = ABLK_TO_MBC(blk);
+ if (sizep)
+ *sizep = MBC_ABLK_SZ(blk) - ABLK_HDR_SZ;
+ }
+ return crr->allctr;
}
static void
@@ -1209,10 +1320,8 @@ mbc_alloc_block(Allctr_t *allctr, Uint size, Uint *blk_szp, Uint32 *alcu_flgsp)
if ((*alcu_flgsp) & ERTS_ALCU_FLG_SBMBC)
blk = create_sbmbc(allctr, get_blk_sz);
else {
-#if HALFWORD_HEAP
- blk = create_carrier(allctr, get_blk_sz, CFLG_MBC|CFLG_FORCE_MSEG);
-#else
blk = create_carrier(allctr, get_blk_sz, CFLG_MBC);
+#if !HALFWORD_HEAP && !HAVE_SUPER_ALIGNED_MB_CARRIERS
if (!blk) {
/* Emergency! We couldn't create the carrier as we wanted.
Try to place it in a sys_alloced sbc. */
@@ -1242,6 +1351,7 @@ mbc_alloc_finalize(Allctr_t *allctr,
Block_t *blk,
Uint org_blk_sz,
UWord flags,
+ Carrier_t *crr,
Uint want_blk_sz,
int valid_blk_info,
Uint32 alcu_flgs)
@@ -1262,22 +1372,18 @@ mbc_alloc_finalize(Allctr_t *allctr,
/* Shrink block... */
blk_sz = want_blk_sz;
nxt_blk_sz = org_blk_sz - blk_sz;
- SET_BLK_HDR(blk,
- blk_sz,
- SBH_THIS_ALLOCED|SBH_NOT_LAST_BLK|prev_free_flg);
+ SET_MBC_ABLK_HDR(blk, blk_sz, prev_free_flg, crr);
- nxt_blk = NXT_BLK(blk);
- SET_BLK_HDR(nxt_blk,
- nxt_blk_sz,
- (SBH_THIS_FREE
- | SBH_PREV_ALLOCED
- | (flags & LAST_BLK_HDR_FLG)));
+ nxt_blk = BLK_AFTER(blk, blk_sz);
+ SET_MBC_FBLK_HDR(nxt_blk, nxt_blk_sz,
+ SBH_THIS_FREE|(flags & LAST_BLK_HDR_FLG),
+ crr);
if (!(flags & LAST_BLK_HDR_FLG)) {
SET_BLK_SZ_FTR(nxt_blk, nxt_blk_sz);
if (!valid_blk_info) {
- Block_t *nxt_nxt_blk = NXT_BLK(nxt_blk);
- SET_PREV_BLK_FREE(nxt_nxt_blk);
+ Block_t *nxt_nxt_blk = BLK_AFTER(nxt_blk, nxt_blk_sz);
+ SET_PREV_BLK_FREE(allctr, nxt_nxt_blk);
}
}
(*allctr->link_free_block)(allctr, nxt_blk, alcu_flgs);
@@ -1291,40 +1397,40 @@ mbc_alloc_finalize(Allctr_t *allctr,
|| nxt_blk == PREV_BLK(NXT_BLK(nxt_blk)));
ASSERT((flags & LAST_BLK_HDR_FLG)
|| IS_PREV_BLK_FREE(NXT_BLK(nxt_blk)));
- ASSERT(nxt_blk_sz == BLK_SZ(nxt_blk));
+ ASSERT(nxt_blk_sz == MBC_BLK_SZ(nxt_blk));
ASSERT(nxt_blk_sz % sizeof(Unit_t) == 0);
ASSERT(nxt_blk_sz >= allctr->min_block_size);
+ ASSERT(ABLK_TO_MBC(blk) == crr);
+ ASSERT(FBLK_TO_MBC(nxt_blk) == crr);
}
else {
+ ASSERT(org_blk_sz <= MBC_ABLK_SZ_MASK);
blk_sz = org_blk_sz;
if (flags & LAST_BLK_HDR_FLG) {
if (valid_blk_info)
SET_BLK_ALLOCED(blk);
else
- SET_BLK_HDR(blk,
- blk_sz,
- SBH_THIS_ALLOCED|SBH_LAST_BLK|prev_free_flg);
+ SET_MBC_ABLK_HDR(blk, blk_sz, SBH_LAST_BLK|prev_free_flg, crr);
}
else {
if (valid_blk_info)
SET_BLK_ALLOCED(blk);
else
- SET_BLK_HDR(blk,
- blk_sz,
- SBH_THIS_ALLOCED|SBH_NOT_LAST_BLK|prev_free_flg);
- nxt_blk = NXT_BLK(blk);
+ SET_MBC_ABLK_HDR(blk, blk_sz, prev_free_flg, crr);
+ nxt_blk = BLK_AFTER(blk, blk_sz);
SET_PREV_BLK_ALLOCED(nxt_blk);
}
ASSERT((flags & LAST_BLK_HDR_FLG)
? IS_LAST_BLK(blk)
: IS_NOT_LAST_BLK(blk));
+ ASSERT(ABLK_TO_MBC(blk) == crr);
}
STAT_MBC_BLK_ALLOC(allctr, blk_sz, alcu_flgs);
ASSERT(IS_ALLOCED_BLK(blk));
- ASSERT(blk_sz == BLK_SZ(blk));
+ ASSERT(blk_sz == MBC_BLK_SZ(blk));
ASSERT(blk_sz % sizeof(Unit_t) == 0);
ASSERT(blk_sz >= allctr->min_block_size);
ASSERT(blk_sz >= want_blk_sz);
@@ -1348,8 +1454,9 @@ mbc_alloc(Allctr_t *allctr, Uint size)
if (IS_MBC_BLK(blk))
mbc_alloc_finalize(allctr,
blk,
- BLK_SZ(blk),
+ MBC_FBLK_SZ(blk),
GET_BLK_HDR_FLGS(blk),
+ FBLK_TO_MBC(blk),
blk_sz,
1,
alcu_flgs);
@@ -1370,7 +1477,7 @@ mbc_free(Allctr_t *allctr, void *p)
ASSERT(p);
blk = UMEM2BLK(p);
- blk_sz = BLK_SZ(blk);
+ blk_sz = MBC_ABLK_SZ(blk);
if (blk_sz < allctr->sbmbc_threshold)
alcu_flgs |= ERTS_ALCU_FLG_SBMBC;
@@ -1381,17 +1488,18 @@ mbc_free(Allctr_t *allctr, void *p)
STAT_MBC_BLK_FREE(allctr, blk_sz, alcu_flgs);
- is_first_blk = IS_FIRST_BLK(blk);
+ is_first_blk = IS_MBC_FIRST_ABLK(allctr, blk);
is_last_blk = IS_LAST_BLK(blk);
- if (!is_first_blk && IS_PREV_BLK_FREE(blk)) {
+ if (IS_PREV_BLK_FREE(blk)) {
+ ASSERT(!is_first_blk);
/* Coalesce with previous block... */
blk = PREV_BLK(blk);
(*allctr->unlink_free_block)(allctr, blk, alcu_flgs);
- blk_sz += BLK_SZ(blk);
- is_first_blk = IS_FIRST_BLK(blk);
- SET_BLK_SZ(blk, blk_sz);
+ blk_sz += MBC_FBLK_SZ(blk);
+ is_first_blk = IS_MBC_FIRST_FBLK(allctr, blk);
+ SET_MBC_FBLK_SZ(blk, blk_sz);
}
else {
SET_BLK_FREE(blk);
@@ -1400,12 +1508,12 @@ mbc_free(Allctr_t *allctr, void *p)
if (is_last_blk)
SET_LAST_BLK(blk);
else {
- nxt_blk = NXT_BLK(blk);
+ nxt_blk = BLK_AFTER(blk, blk_sz);
if (IS_FREE_BLK(nxt_blk)) {
/* Coalesce with next block... */
(*allctr->unlink_free_block)(allctr, nxt_blk, alcu_flgs);
- blk_sz += BLK_SZ(nxt_blk);
- SET_BLK_SZ(blk, blk_sz);
+ blk_sz += MBC_FBLK_SZ(nxt_blk);
+ SET_MBC_FBLK_SZ(blk, blk_sz);
is_last_blk = IS_LAST_BLK(nxt_blk);
if (is_last_blk)
@@ -1416,26 +1524,26 @@ mbc_free(Allctr_t *allctr, void *p)
}
}
else {
- SET_PREV_BLK_FREE(nxt_blk);
+ SET_PREV_BLK_FREE(allctr, nxt_blk);
SET_NOT_LAST_BLK(blk);
SET_BLK_SZ_FTR(blk, blk_sz);
}
}
- ASSERT(is_last_blk ? IS_LAST_BLK(blk) : IS_NOT_LAST_BLK(blk));
- ASSERT(is_first_blk ? IS_FIRST_BLK(blk) : IS_NOT_FIRST_BLK(blk));
ASSERT(IS_FREE_BLK(blk));
+ ASSERT(!is_last_blk == !IS_LAST_BLK(blk));
+ ASSERT(!is_first_blk == !IS_MBC_FIRST_FBLK(allctr, blk));
ASSERT(is_first_blk || IS_PREV_BLK_ALLOCED(blk));
ASSERT(is_last_blk || IS_PREV_BLK_FREE(NXT_BLK(blk)));
- ASSERT(blk_sz == BLK_SZ(blk));
+ ASSERT(blk_sz == MBC_BLK_SZ(blk));
ASSERT(is_last_blk || blk == PREV_BLK(NXT_BLK(blk)));
ASSERT(blk_sz % sizeof(Unit_t) == 0);
ASSERT(IS_MBC_BLK(blk));
if (is_first_blk
&& is_last_blk
- && allctr->main_carrier != FBLK2MBC(allctr, blk)) {
+ && allctr->main_carrier != FIRST_BLK_TO_MBC(allctr, blk)) {
if (alcu_flgs & ERTS_ALCU_FLG_SBMBC)
destroy_sbmbc(allctr, blk);
else
@@ -1472,7 +1580,7 @@ mbc_realloc(Allctr_t *allctr, void *p, Uint size, Uint32 alcu_flgs)
ASSERT(size < allctr->sbc_threshold);
blk = (Block_t *) UMEM2BLK(p);
- old_blk_sz = BLK_SZ(blk);
+ old_blk_sz = MBC_ABLK_SZ(blk);
ASSERT(old_blk_sz >= allctr->min_block_size);
@@ -1497,6 +1605,7 @@ mbc_realloc(Allctr_t *allctr, void *p, Uint size, Uint32 alcu_flgs)
return p;
else if (blk_sz < old_blk_sz) {
/* Shrink block... */
+ Carrier_t* crr;
Block_t *nxt_nxt_blk;
Uint diff_sz_val = old_blk_sz - blk_sz;
Uint old_blk_sz_val = old_blk_sz;
@@ -1516,16 +1625,18 @@ mbc_realloc(Allctr_t *allctr, void *p, Uint size, Uint32 alcu_flgs)
return NULL;
cand_blk_sz = old_blk_sz;
- if (!IS_PREV_BLK_FREE(blk) || IS_FIRST_BLK(blk))
+ if (!IS_PREV_BLK_FREE(blk)) {
cand_blk = blk;
+ }
else {
+ ASSERT(!IS_MBC_FIRST_ABLK(allctr, blk));
cand_blk = PREV_BLK(blk);
cand_blk_sz += PREV_BLK_SZ(blk);
}
if (!is_last_blk) {
- nxt_blk = NXT_BLK(blk);
+ nxt_blk = BLK_AFTER(blk, old_blk_sz);
if (IS_FREE_BLK(nxt_blk))
- cand_blk_sz += BLK_SZ(nxt_blk);
+ cand_blk_sz += MBC_FBLK_SZ(nxt_blk);
}
new_blk = (*allctr->get_free_block)(allctr,
@@ -1541,52 +1652,48 @@ mbc_realloc(Allctr_t *allctr, void *p, Uint size, Uint32 alcu_flgs)
nxt_blk_sz = old_blk_sz - blk_sz;
- if ((is_last_blk || IS_ALLOCED_BLK(NXT_BLK(blk)))
+ if ((is_last_blk || IS_ALLOCED_BLK(BLK_AFTER(blk,old_blk_sz)))
&& (nxt_blk_sz < allctr->min_block_size))
return p;
HARD_CHECK_BLK_CARRIER(allctr, blk);
- SET_BLK_SZ(blk, blk_sz);
+ nxt_nxt_blk = BLK_AFTER(blk, old_blk_sz);
+
+ SET_MBC_ABLK_SZ(blk, blk_sz);
SET_NOT_LAST_BLK(blk);
- nxt_blk = NXT_BLK(blk);
- SET_BLK_HDR(nxt_blk,
- nxt_blk_sz,
- SBH_THIS_FREE|SBH_PREV_ALLOCED|SBH_NOT_LAST_BLK);
+ nxt_blk = BLK_AFTER(blk, blk_sz);
STAT_MBC_BLK_FREE(allctr, old_blk_sz, alcu_flgs);
STAT_MBC_BLK_ALLOC(allctr, blk_sz, alcu_flgs);
- ASSERT(BLK_SZ(blk) >= allctr->min_block_size);
+ ASSERT(MBC_BLK_SZ(blk) >= allctr->min_block_size);
- if (is_last_blk)
- SET_LAST_BLK(nxt_blk);
- else {
- nxt_nxt_blk = NXT_BLK(nxt_blk);
+ if (!is_last_blk) {
if (IS_FREE_BLK(nxt_nxt_blk)) {
/* Coalesce with next free block... */
- nxt_blk_sz += BLK_SZ(nxt_nxt_blk);
+ nxt_blk_sz += MBC_FBLK_SZ(nxt_nxt_blk);
(*allctr->unlink_free_block)(allctr, nxt_nxt_blk, alcu_flgs);
- SET_BLK_SZ(nxt_blk, nxt_blk_sz);
- is_last_blk = IS_LAST_BLK(nxt_nxt_blk);
- if (is_last_blk)
- SET_LAST_BLK(nxt_blk);
- else
- SET_BLK_SZ_FTR(nxt_blk, nxt_blk_sz);
+ is_last_blk = GET_LAST_BLK_HDR_FLG(nxt_nxt_blk);
}
else {
- SET_BLK_SZ_FTR(nxt_blk, nxt_blk_sz);
- SET_PREV_BLK_FREE(nxt_nxt_blk);
+ SET_PREV_BLK_FREE(allctr, nxt_nxt_blk);
}
+ SET_BLK_SZ_FTR(nxt_blk, nxt_blk_sz);
}
+ crr = ABLK_TO_MBC(blk);
+ SET_MBC_FBLK_HDR(nxt_blk, nxt_blk_sz,
+ SBH_THIS_FREE | (is_last_blk ? SBH_LAST_BLK : 0),
+ crr);
+
(*allctr->link_free_block)(allctr, nxt_blk, alcu_flgs);
ASSERT(IS_ALLOCED_BLK(blk));
- ASSERT(blk_sz == BLK_SZ(blk));
+ ASSERT(blk_sz == MBC_BLK_SZ(blk));
ASSERT(blk_sz % sizeof(Unit_t) == 0);
ASSERT(blk_sz >= allctr->min_block_size);
ASSERT(blk_sz >= size + ABLK_HDR_SZ);
@@ -1594,14 +1701,15 @@ mbc_realloc(Allctr_t *allctr, void *p, Uint size, Uint32 alcu_flgs)
ASSERT(IS_FREE_BLK(nxt_blk));
ASSERT(IS_PREV_BLK_ALLOCED(nxt_blk));
- ASSERT(nxt_blk_sz == BLK_SZ(nxt_blk));
+ ASSERT(nxt_blk_sz == MBC_BLK_SZ(nxt_blk));
ASSERT(nxt_blk_sz % sizeof(Unit_t) == 0);
ASSERT(nxt_blk_sz >= allctr->min_block_size);
ASSERT(IS_MBC_BLK(nxt_blk));
ASSERT(is_last_blk ? IS_LAST_BLK(nxt_blk) : IS_NOT_LAST_BLK(nxt_blk));
ASSERT(is_last_blk || nxt_blk == PREV_BLK(NXT_BLK(nxt_blk)));
ASSERT(is_last_blk || IS_PREV_BLK_FREE(NXT_BLK(nxt_blk)));
-
+ ASSERT(FBLK_TO_MBC(nxt_blk) == crr);
+
HARD_CHECK_BLK_CARRIER(allctr, blk);
return p;
@@ -1610,8 +1718,8 @@ mbc_realloc(Allctr_t *allctr, void *p, Uint size, Uint32 alcu_flgs)
/* Need larger block... */
if (!is_last_blk) {
- nxt_blk = NXT_BLK(blk);
- nxt_blk_sz = BLK_SZ(nxt_blk);
+ nxt_blk = BLK_AFTER(blk, old_blk_sz);
+ nxt_blk_sz = MBC_BLK_SZ(nxt_blk);
if (IS_FREE_BLK(nxt_blk) && get_blk_sz <= old_blk_sz + nxt_blk_sz) {
/* Grow into next block... */
@@ -1624,7 +1732,7 @@ mbc_realloc(Allctr_t *allctr, void *p, Uint size, Uint32 alcu_flgs)
if (nxt_blk_sz < allctr->min_block_size) {
blk_sz += nxt_blk_sz;
- SET_BLK_SZ(blk, blk_sz);
+ SET_MBC_ABLK_SZ(blk, blk_sz);
if (is_last_blk) {
SET_LAST_BLK(blk);
@@ -1633,21 +1741,20 @@ mbc_realloc(Allctr_t *allctr, void *p, Uint size, Uint32 alcu_flgs)
#endif
}
else {
- nxt_blk = NXT_BLK(blk);
+ nxt_blk = BLK_AFTER(blk, blk_sz);
SET_PREV_BLK_ALLOCED(nxt_blk);
#ifdef DEBUG
is_last_blk = IS_LAST_BLK(nxt_blk);
- nxt_blk_sz = BLK_SZ(nxt_blk);
+ nxt_blk_sz = MBC_BLK_SZ(nxt_blk);
#endif
}
}
else {
- SET_BLK_SZ(blk, blk_sz);
+ Carrier_t* crr = ABLK_TO_MBC(blk);
+ SET_MBC_ABLK_SZ(blk, blk_sz);
- nxt_blk = NXT_BLK(blk);
- SET_BLK_HDR(nxt_blk,
- nxt_blk_sz,
- SBH_THIS_FREE|SBH_PREV_ALLOCED|SBH_NOT_LAST_BLK);
+ nxt_blk = BLK_AFTER(blk, blk_sz);
+ SET_MBC_FBLK_HDR(nxt_blk, nxt_blk_sz, SBH_THIS_FREE, crr);
if (is_last_blk)
SET_LAST_BLK(nxt_blk);
@@ -1657,6 +1764,7 @@ mbc_realloc(Allctr_t *allctr, void *p, Uint size, Uint32 alcu_flgs)
(*allctr->link_free_block)(allctr, nxt_blk, alcu_flgs);
ASSERT(IS_FREE_BLK(nxt_blk));
+ ASSERT(FBLK_TO_MBC(nxt_blk) == crr);
}
STAT_MBC_BLK_FREE(allctr, old_blk_sz, alcu_flgs);
@@ -1664,14 +1772,14 @@ mbc_realloc(Allctr_t *allctr, void *p, Uint size, Uint32 alcu_flgs)
ASSERT(IS_ALLOCED_BLK(blk));
- ASSERT(blk_sz == BLK_SZ(blk));
+ ASSERT(blk_sz == MBC_BLK_SZ(blk));
ASSERT(blk_sz % sizeof(Unit_t) == 0);
ASSERT(blk_sz >= allctr->min_block_size);
ASSERT(blk_sz >= size + ABLK_HDR_SZ);
ASSERT(IS_MBC_BLK(blk));
ASSERT(!nxt_blk || IS_PREV_BLK_ALLOCED(nxt_blk));
- ASSERT(!nxt_blk || nxt_blk_sz == BLK_SZ(nxt_blk));
+ ASSERT(!nxt_blk || nxt_blk_sz == MBC_BLK_SZ(nxt_blk));
ASSERT(!nxt_blk || nxt_blk_sz % sizeof(Unit_t) == 0);
ASSERT(!nxt_blk || nxt_blk_sz >= allctr->min_block_size);
ASSERT(!nxt_blk || IS_MBC_BLK(nxt_blk));
@@ -1696,18 +1804,19 @@ mbc_realloc(Allctr_t *allctr, void *p, Uint size, Uint32 alcu_flgs)
/* Need to grow in another block */
- if (!IS_PREV_BLK_FREE(blk) || IS_FIRST_BLK(blk)) {
+ if (!IS_PREV_BLK_FREE(blk)) {
cand_blk = NULL;
cand_blk_sz = 0;
}
else {
+ ASSERT(!IS_MBC_FIRST_ABLK(allctr, blk));
cand_blk = PREV_BLK(blk);
cand_blk_sz = old_blk_sz + PREV_BLK_SZ(blk);
if (!is_last_blk) {
- nxt_blk = NXT_BLK(blk);
+ nxt_blk = BLK_AFTER(blk, old_blk_sz);
if (IS_FREE_BLK(nxt_blk))
- cand_blk_sz += BLK_SZ(nxt_blk);
+ cand_blk_sz += MBC_FBLK_SZ(nxt_blk);
}
}
@@ -1743,8 +1852,9 @@ mbc_realloc(Allctr_t *allctr, void *p, Uint size, Uint32 alcu_flgs)
if (new_blk) {
mbc_alloc_finalize(allctr,
new_blk,
- BLK_SZ(new_blk),
+ MBC_FBLK_SZ(new_blk),
GET_BLK_HDR_FLGS(new_blk),
+ FBLK_TO_MBC(new_blk),
blk_sz,
1,
alcu_flgs);
@@ -1754,6 +1864,7 @@ mbc_realloc(Allctr_t *allctr, void *p, Uint size, Uint32 alcu_flgs)
return new_p;
}
else {
+ Carrier_t* crr;
Uint new_blk_sz;
UWord new_blk_flgs;
Uint prev_blk_sz;
@@ -1774,10 +1885,10 @@ mbc_realloc(Allctr_t *allctr, void *p, Uint size, Uint32 alcu_flgs)
if (is_last_blk)
new_blk_flgs |= LAST_BLK_HDR_FLG;
else {
- nxt_blk = NXT_BLK(blk);
+ nxt_blk = BLK_AFTER(blk, old_blk_sz);
if (IS_FREE_BLK(nxt_blk)) {
new_blk_flgs |= GET_LAST_BLK_HDR_FLG(nxt_blk);
- new_blk_sz += BLK_SZ(nxt_blk);
+ new_blk_sz += MBC_FBLK_SZ(nxt_blk);
(*allctr->unlink_free_block)(allctr, nxt_blk, alcu_flgs);
}
}
@@ -1790,6 +1901,7 @@ mbc_realloc(Allctr_t *allctr, void *p, Uint size, Uint32 alcu_flgs)
new_p = BLK2UMEM(new_blk);
blk_cpy_sz = MIN(blk_sz, old_blk_sz);
+ crr = FBLK_TO_MBC(new_blk);
if (prev_blk_sz >= blk_cpy_sz)
sys_memcpy(new_p, p, blk_cpy_sz - ABLK_HDR_SZ);
@@ -1800,6 +1912,7 @@ mbc_realloc(Allctr_t *allctr, void *p, Uint size, Uint32 alcu_flgs)
new_blk,
new_blk_sz,
new_blk_flgs,
+ crr,
blk_sz,
0,
alcu_flgs);
@@ -1815,35 +1928,40 @@ mbc_realloc(Allctr_t *allctr, void *p, Uint size, Uint32 alcu_flgs)
#ifdef DEBUG
#if HAVE_ERTS_MSEG
-#define ASSERT_MSEG_UNIT_SIZE_MULTIPLE(CSZ) ASSERT((CSZ) % mseg_unit_size == 0)
+#define ASSERT_MSEG_UNIT_SIZE_MULTIPLE(CSZ) ASSERT((CSZ) % MSEG_UNIT_SZ == 0)
#else
#define ASSERT_MSEG_UNIT_SIZE_MULTIPLE(CSZ)
#endif
-#define CHECK_1BLK_CARRIER(A, SBC, MSEGED, C, CSZ, B, BSZ) \
-do { \
- ASSERT(IS_FIRST_BLK((B))); \
- ASSERT(IS_LAST_BLK((B))); \
- ASSERT((CSZ) == CARRIER_SZ((C))); \
- ASSERT((BSZ) == BLK_SZ((B))); \
- ASSERT((BSZ) % sizeof(Unit_t) == 0); \
- if ((SBC)) { \
- ASSERT(IS_SBC_BLK((B))); \
- ASSERT(IS_SB_CARRIER((C))); \
- } \
- else { \
- ASSERT(IS_MBC_BLK((B))); \
- ASSERT(IS_MB_CARRIER((C))); \
- } \
- if ((MSEGED)) { \
- ASSERT(IS_MSEG_CARRIER((C))); \
- ASSERT_MSEG_UNIT_SIZE_MULTIPLE((CSZ)); \
- } \
- else { \
- ASSERT(IS_SYS_ALLOC_CARRIER((C))); \
- ASSERT((CSZ) % sizeof(Unit_t) == 0); \
- } \
-} while (0)
+static void CHECK_1BLK_CARRIER(Allctr_t* A, int SBC, int MSEGED, Carrier_t* C,
+ UWord CSZ, Block_t* B, UWord BSZ)
+{
+ ASSERT(IS_LAST_BLK((B)));
+ ASSERT((CSZ) == CARRIER_SZ((C)));
+ ASSERT((BSZ) % sizeof(Unit_t) == 0);
+ if ((SBC)) {
+ ASSERT((BSZ) == SBC_BLK_SZ((B)));
+ ASSERT((char*)B == (char*)C + SBC_HEADER_SIZE);
+ ASSERT(IS_SBC_BLK((B)));
+ ASSERT(IS_SB_CARRIER((C)));
+ }
+ else {
+ ASSERT(IS_FREE_BLK(B));
+ ASSERT((BSZ) == MBC_FBLK_SZ((B)));
+ ASSERT(IS_MBC_FIRST_FBLK(A, (B)));
+ ASSERT(IS_MBC_BLK((B)));
+ ASSERT(IS_MB_CARRIER((C)));
+ ASSERT(FBLK_TO_MBC(B) == (C));
+ }
+ if ((MSEGED)) {
+ ASSERT(IS_MSEG_CARRIER((C)));
+ ASSERT_MSEG_UNIT_SIZE_MULTIPLE((CSZ));
+ }
+ else {
+ ASSERT(IS_SYS_ALLOC_CARRIER((C)));
+ ASSERT((CSZ) % sizeof(Unit_t) == 0);
+ }
+}
#else
#define CHECK_1BLK_CARRIER(A, SBC, MSEGED, C, CSZ, B, BSZ)
@@ -1865,37 +1983,18 @@ create_sbmbc(Allctr_t *allctr, Uint umem_sz)
crr = erts_alloc(ERTS_ALC_T_SBMBC, crr_sz);
INC_CC(allctr->calls.sbmbc_alloc);
- SET_CARRIER_HDR(crr, crr_sz, SCH_SYS_ALLOC|SCH_MBC);
-
- blk = MBC2FBLK(allctr, crr);
+ SET_CARRIER_HDR(crr, crr_sz, SCH_SYS_ALLOC|SCH_MBC, allctr);
-#ifdef ERTS_ALLOC_UTIL_HARD_DEBUG
- if (allctr->mbc_header_size % sizeof(Unit_t) == 0)
- crr_sz -= sizeof(UWord);
-#endif
+ blk = MBC_TO_FIRST_BLK(allctr, crr);
- blk_sz = UNIT_FLOOR(crr_sz - allctr->mbc_header_size);
+ blk_sz = UNIT_FLOOR(crr_sz - MBC_HEADER_SIZE(allctr));
- SET_MBC_BLK_FTR(((UWord *) blk)[-1]);
- SET_BLK_HDR(blk, blk_sz, SBH_THIS_FREE|SBH_PREV_FREE|SBH_LAST_BLK);
-
-#ifdef ERTS_ALLOC_UTIL_HARD_DEBUG
- *((Carrier_t **) NXT_BLK(blk)) = crr;
-#endif
+ SET_MBC_FBLK_HDR(blk, blk_sz, SBH_THIS_FREE|SBH_LAST_BLK, crr);
link_carrier(&allctr->sbmbc_list, crr);
-#ifdef ERTS_ALLOC_UTIL_HARD_DEBUG
- if (allctr->mbc_header_size % sizeof(Unit_t) == 0)
- crr_sz += sizeof(UWord);
-#endif
-
STAT_SBMBC_ALLOC(allctr, crr_sz);
CHECK_1BLK_CARRIER(allctr, 0, 0, crr, crr_sz, blk, blk_sz);
-#ifdef ERTS_ALLOC_UTIL_HARD_DEBUG
- if (allctr->mbc_header_size % sizeof(Unit_t) == 0)
- crr_sz -= sizeof(UWord);
-#endif
if (allctr->creating_mbc)
(*allctr->creating_mbc)(allctr, crr, ERTS_ALCU_FLG_SBMBC);
@@ -1909,11 +2008,10 @@ destroy_sbmbc(Allctr_t *allctr, Block_t *blk)
Uint crr_sz;
Carrier_t *crr;
- ASSERT(IS_FIRST_BLK(blk));
-
ASSERT(IS_MBC_BLK(blk));
+ ASSERT(IS_MBC_FIRST_FBLK(allctr, blk));
- crr = FBLK2MBC(allctr, blk);
+ crr = FIRST_BLK_TO_MBC(allctr, blk);
crr_sz = CARRIER_SZ(crr);
#ifdef DEBUG
@@ -1952,14 +2050,25 @@ create_carrier(Allctr_t *allctr, Uint umem_sz, UWord flags)
Uint blk_sz, bcrr_sz, crr_sz;
#if HAVE_ERTS_MSEG
int have_tried_sys_alloc = 0, have_tried_mseg = 0;
+ Uint mseg_flags;
#endif
#ifdef DEBUG
int is_mseg = 0;
#endif
+#if HALFWORD_HEAP
+ flags |= CFLG_FORCE_MSEG;
+#elif HAVE_SUPER_ALIGNED_MB_CARRIERS
+ if (flags & CFLG_MBC) {
+ flags |= CFLG_FORCE_MSEG;
+ }
+#endif
+
ASSERT((flags & CFLG_SBC && !(flags & CFLG_MBC))
|| (flags & CFLG_MBC && !(flags & CFLG_SBC)));
+ ASSERT(!(flags & CFLG_FORCE_MSEG && flags & CFLG_FORCE_SYS_ALLOC));
+
blk_sz = UMEMSZ2BLKSZ(allctr, umem_sz);
#if HAVE_ERTS_MSEG
@@ -1974,29 +2083,27 @@ create_carrier(Allctr_t *allctr, Uint umem_sz, UWord flags)
if (allctr->sbcs.curr.norm.mseg.no >= allctr->max_mseg_sbcs)
goto try_sys_alloc;
}
+#if !HAVE_SUPER_ALIGNED_MB_CARRIERS
else {
if (allctr->mbcs.curr.norm.mseg.no >= allctr->max_mseg_mbcs)
goto try_sys_alloc;
}
+#endif
try_mseg:
if (flags & CFLG_SBC) {
- crr_sz = blk_sz + allctr->sbc_header_size;
+ crr_sz = blk_sz + SBC_HEADER_SIZE;
+ mseg_flags = ERTS_MSEG_FLG_NONE;
}
else {
crr_sz = (*allctr->get_next_mbc_size)(allctr);
- if (crr_sz < allctr->mbc_header_size + blk_sz)
- crr_sz = allctr->mbc_header_size + blk_sz;
-#ifdef ERTS_ALLOC_UTIL_HARD_DEBUG
- if (allctr->mbc_header_size % sizeof(Unit_t) == 0)
- crr_sz += sizeof(UWord);
-#endif
+ if (crr_sz < MBC_HEADER_SIZE(allctr) + blk_sz)
+ crr_sz = MBC_HEADER_SIZE(allctr) + blk_sz;
+ mseg_flags = ERTS_MSEG_FLG_2POW;
}
- crr_sz = MSEG_UNIT_CEILING(crr_sz);
- ASSERT(crr_sz % mseg_unit_size == 0);
- crr = (Carrier_t *) alcu_mseg_alloc(allctr, &crr_sz);
+ crr = (Carrier_t *) alcu_mseg_alloc(allctr, &crr_sz, mseg_flags);
if (!crr) {
have_tried_mseg = 1;
if (!(have_tried_sys_alloc || flags & CFLG_FORCE_MSEG))
@@ -2008,32 +2115,31 @@ create_carrier(Allctr_t *allctr, Uint umem_sz, UWord flags)
is_mseg = 1;
#endif
if (flags & CFLG_SBC) {
- SET_CARRIER_HDR(crr, crr_sz, SCH_MSEG|SCH_SBC);
+ SET_CARRIER_HDR(crr, crr_sz, SCH_MSEG|SCH_SBC, allctr);
STAT_MSEG_SBC_ALLOC(allctr, crr_sz, blk_sz);
goto sbc_final_touch;
}
else {
- SET_CARRIER_HDR(crr, crr_sz, SCH_MSEG|SCH_MBC);
+#ifndef ARCH_64
+ ASSERT(crr_sz <= MBC_SZ_MAX_LIMIT);
+#endif
+ SET_CARRIER_HDR(crr, crr_sz, SCH_MSEG|SCH_MBC, allctr);
STAT_MSEG_MBC_ALLOC(allctr, crr_sz);
goto mbc_final_touch;
}
try_sys_alloc:
+
#endif /* #if HAVE_ERTS_MSEG */
if (flags & CFLG_SBC) {
- bcrr_sz = blk_sz + allctr->sbc_header_size;
+ bcrr_sz = blk_sz + SBC_HEADER_SIZE;
}
else {
- bcrr_sz = allctr->mbc_header_size + blk_sz;
+ bcrr_sz = MBC_HEADER_SIZE(allctr) + blk_sz;
if (!(flags & CFLG_MAIN_CARRIER)
&& bcrr_sz < allctr->smallest_mbc_size)
bcrr_sz = allctr->smallest_mbc_size;
-#ifdef ERTS_ALLOC_UTIL_HARD_DEBUG
- if (allctr->mbc_header_size % sizeof(Unit_t) == 0)
- bcrr_sz += sizeof(UWord);
-#endif
-
}
crr_sz = (flags & CFLG_FORCE_SIZE
@@ -2057,7 +2163,7 @@ create_carrier(Allctr_t *allctr, Uint umem_sz, UWord flags)
}
}
if (flags & CFLG_SBC) {
- SET_CARRIER_HDR(crr, crr_sz, SCH_SYS_ALLOC|SCH_SBC);
+ SET_CARRIER_HDR(crr, crr_sz, SCH_SYS_ALLOC|SCH_SBC, allctr);
STAT_SYS_ALLOC_SBC_ALLOC(allctr, crr_sz, blk_sz);
#if HAVE_ERTS_MSEG
@@ -2066,8 +2172,7 @@ create_carrier(Allctr_t *allctr, Uint umem_sz, UWord flags)
blk = SBC2BLK(allctr, crr);
- SET_SBC_BLK_FTR(((UWord *) blk)[-1]);
- SET_BLK_HDR(blk, blk_sz, SBH_THIS_ALLOCED|SBH_PREV_FREE|SBH_LAST_BLK);
+ SET_SBC_BLK_HDR(blk, blk_sz);
link_carrier(&allctr->sbc_list, crr);
@@ -2075,28 +2180,18 @@ create_carrier(Allctr_t *allctr, Uint umem_sz, UWord flags)
}
else {
- SET_CARRIER_HDR(crr, crr_sz, SCH_SYS_ALLOC|SCH_MBC);
+ SET_CARRIER_HDR(crr, crr_sz, SCH_SYS_ALLOC|SCH_MBC, allctr);
STAT_SYS_ALLOC_MBC_ALLOC(allctr, crr_sz);
#if HAVE_ERTS_MSEG
mbc_final_touch:
#endif
- blk = MBC2FBLK(allctr, crr);
-
-#ifdef ERTS_ALLOC_UTIL_HARD_DEBUG
- if (allctr->mbc_header_size % sizeof(Unit_t) == 0)
- crr_sz -= sizeof(UWord);
-#endif
-
- blk_sz = UNIT_FLOOR(crr_sz - allctr->mbc_header_size);
+ blk = MBC_TO_FIRST_BLK(allctr, crr);
- SET_MBC_BLK_FTR(((UWord *) blk)[-1]);
- SET_BLK_HDR(blk, blk_sz, SBH_THIS_FREE|SBH_PREV_FREE|SBH_LAST_BLK);
+ blk_sz = UNIT_FLOOR(crr_sz - MBC_HEADER_SIZE(allctr));
-#ifdef ERTS_ALLOC_UTIL_HARD_DEBUG
- *((Carrier_t **) NXT_BLK(blk)) = crr;
-#endif
+ SET_MBC_FBLK_HDR(blk, blk_sz, SBH_THIS_FREE|SBH_LAST_BLK, crr);
if (flags & CFLG_MAIN_CARRIER) {
ASSERT(!allctr->main_carrier);
@@ -2105,15 +2200,7 @@ create_carrier(Allctr_t *allctr, Uint umem_sz, UWord flags)
link_carrier(&allctr->mbc_list, crr);
-#ifdef ERTS_ALLOC_UTIL_HARD_DEBUG
- if (allctr->mbc_header_size % sizeof(Unit_t) == 0)
- crr_sz += sizeof(UWord);
-#endif
CHECK_1BLK_CARRIER(allctr, 0, is_mseg, crr, crr_sz, blk, blk_sz);
-#ifdef ERTS_ALLOC_UTIL_HARD_DEBUG
- if (allctr->mbc_header_size % sizeof(Unit_t) == 0)
- crr_sz -= sizeof(UWord);
-#endif
if (allctr->creating_mbc)
(*allctr->creating_mbc)(allctr, crr, 0);
@@ -2142,8 +2229,8 @@ resize_carrier(Allctr_t *allctr, Block_t *old_blk, Uint umem_sz, UWord flags)
HARD_CHECK_BLK_CARRIER(allctr, old_blk);
- old_blk_sz = BLK_SZ(old_blk);
- old_crr = BLK2SBC(allctr, old_blk);
+ old_blk_sz = SBC_BLK_SZ(old_blk);
+ old_crr = BLK_TO_SBC(old_blk);
old_crr_sz = CARRIER_SZ(old_crr);
ASSERT(IS_SB_CARRIER(old_crr));
ASSERT(IS_SBC_BLK(old_blk));
@@ -2157,7 +2244,7 @@ resize_carrier(Allctr_t *allctr, Block_t *old_blk, Uint umem_sz, UWord flags)
if (!(flags & CFLG_FORCE_SYS_ALLOC)) {
- new_crr_sz = new_blk_sz + allctr->sbc_header_size;
+ new_crr_sz = new_blk_sz + SBC_HEADER_SIZE;
new_crr_sz = MSEG_UNIT_CEILING(new_crr_sz);
new_crr = (Carrier_t *) alcu_mseg_realloc(allctr,
old_crr,
@@ -2166,7 +2253,7 @@ resize_carrier(Allctr_t *allctr, Block_t *old_blk, Uint umem_sz, UWord flags)
if (new_crr) {
SET_CARRIER_SZ(new_crr, new_crr_sz);
new_blk = SBC2BLK(allctr, new_crr);
- SET_BLK_SZ(new_blk, new_blk_sz);
+ SET_SBC_BLK_SZ(new_blk, new_blk_sz);
STAT_MSEG_SBC_ALLOC(allctr, new_crr_sz, new_blk_sz);
relink_carrier(&allctr->sbc_list, new_crr);
CHECK_1BLK_CARRIER(allctr, 1, 1, new_crr, new_crr_sz,
@@ -2174,6 +2261,11 @@ resize_carrier(Allctr_t *allctr, Block_t *old_blk, Uint umem_sz, UWord flags)
DEBUG_SAVE_ALIGNMENT(new_crr);
return new_blk;
}
+#if HALFWORD_HEAP
+ /* Old carrier unchanged; restore stat */
+ STAT_MSEG_SBC_ALLOC(allctr, old_crr_sz, old_blk_sz);
+ return NULL;
+#endif
create_flags |= CFLG_FORCE_SYS_ALLOC; /* since mseg_realloc()
failed */
}
@@ -2196,7 +2288,7 @@ resize_carrier(Allctr_t *allctr, Block_t *old_blk, Uint umem_sz, UWord flags)
else {
if (!(flags & CFLG_FORCE_MSEG)) {
#endif /* #if HAVE_ERTS_MSEG */
- new_bcrr_sz = new_blk_sz + allctr->sbc_header_size;
+ new_bcrr_sz = new_blk_sz + SBC_HEADER_SIZE;
new_crr_sz = (flags & CFLG_FORCE_SIZE
? UNIT_CEILING(new_bcrr_sz)
: SYS_ALLOC_CARRIER_CEILING(new_bcrr_sz));
@@ -2208,7 +2300,7 @@ resize_carrier(Allctr_t *allctr, Block_t *old_blk, Uint umem_sz, UWord flags)
sys_realloc_success:
SET_CARRIER_SZ(new_crr, new_crr_sz);
new_blk = SBC2BLK(allctr, new_crr);
- SET_BLK_SZ(new_blk, new_blk_sz);
+ SET_SBC_BLK_SZ(new_blk, new_blk_sz);
STAT_SYS_ALLOC_SBC_FREE(allctr, old_crr_sz, old_blk_sz);
STAT_SYS_ALLOC_SBC_ALLOC(allctr, new_crr_sz, new_blk_sz);
relink_carrier(&allctr->sbc_list, new_crr);
@@ -2218,7 +2310,7 @@ resize_carrier(Allctr_t *allctr, Block_t *old_blk, Uint umem_sz, UWord flags)
return new_blk;
}
else if (new_crr_sz > UNIT_CEILING(new_bcrr_sz)) {
- new_crr_sz = new_blk_sz + allctr->sbc_header_size;
+ new_crr_sz = new_blk_sz + SBC_HEADER_SIZE;
new_crr_sz = UNIT_CEILING(new_crr_sz);
new_crr = (Carrier_t *) alcu_sys_realloc(allctr,
(void *) old_crr,
@@ -2262,11 +2354,9 @@ destroy_carrier(Allctr_t *allctr, Block_t *blk)
Uint is_mseg = 0;
#endif
- ASSERT(IS_FIRST_BLK(blk));
-
if (IS_SBC_BLK(blk)) {
- Uint blk_sz = BLK_SZ(blk);
- crr = BLK2SBC(allctr, blk);
+ Uint blk_sz = SBC_BLK_SZ(blk);
+ crr = BLK_TO_SBC(blk);
crr_sz = CARRIER_SZ(crr);
ASSERT(IS_LAST_BLK(blk));
@@ -2276,7 +2366,7 @@ destroy_carrier(Allctr_t *allctr, Block_t *blk)
#if HAVE_ERTS_MSEG
if (IS_MSEG_CARRIER(crr)) {
is_mseg++;
- ASSERT(crr_sz % mseg_unit_size == 0);
+ ASSERT(crr_sz % MSEG_UNIT_SZ == 0);
STAT_MSEG_SBC_FREE(allctr, crr_sz, blk_sz);
}
else
@@ -2287,7 +2377,8 @@ destroy_carrier(Allctr_t *allctr, Block_t *blk)
}
else {
- crr = FBLK2MBC(allctr, blk);
+ ASSERT(IS_MBC_FIRST_FBLK(allctr, blk));
+ crr = FIRST_BLK_TO_MBC(allctr, blk);
crr_sz = CARRIER_SZ(crr);
#ifdef DEBUG
@@ -2305,7 +2396,7 @@ destroy_carrier(Allctr_t *allctr, Block_t *blk)
#if HAVE_ERTS_MSEG
if (IS_MSEG_CARRIER(crr)) {
is_mseg++;
- ASSERT(crr_sz % mseg_unit_size == 0);
+ ASSERT(crr_sz % MSEG_UNIT_SZ == 0);
STAT_MSEG_MBC_FREE(allctr, crr_sz);
}
else
@@ -3430,12 +3521,7 @@ do_erts_alcu_alloc(ErtsAlcType_t type, void *extra, Uint size)
if (allctr->dd.use)
ERTS_ALCU_HANDLE_DD_IN_OP(allctr, 1);
#endif
-#if HALFWORD_HEAP
- blk = create_carrier(allctr, size,
- CFLG_SBC | CFLG_FORCE_MSEG);
-#else
blk = create_carrier(allctr, size, CFLG_SBC);
-#endif
res = blk ? BLK2UMEM(blk) : NULL;
}
else
@@ -3506,24 +3592,20 @@ erts_alcu_alloc_thr_spec(ErtsAlcType_t type, void *extra, Uint size)
void *
erts_alcu_alloc_thr_pref(ErtsAlcType_t type, void *extra, Uint size)
{
- int pref_ix;
Allctr_t *pref_allctr;
void *res;
- pref_ix = get_pref_allctr(extra, &pref_allctr);
+ pref_allctr = get_pref_allctr(extra);
if (pref_allctr->thread_safe)
erts_mtx_lock(&pref_allctr->mutex);
ERTS_ALCU_DBG_CHK_THR_ACCESS(pref_allctr);
- res = do_erts_alcu_alloc(type, pref_allctr, size + sizeof(UWord));
+ res = do_erts_alcu_alloc(type, pref_allctr, size);
if (pref_allctr->thread_safe)
erts_mtx_unlock(&pref_allctr->mutex);
- if (res)
- res = put_used_allctr(res, pref_ix, size);
-
DEBUG_CHECK_ALIGNMENT(res);
@@ -3644,21 +3726,20 @@ erts_alcu_free_thr_pref(ErtsAlcType_t type, void *extra, void *p)
{
if (p) {
Allctr_t *pref_allctr, *used_allctr;
- void *ptr;
- get_pref_allctr(extra, &pref_allctr);
- ptr = get_used_allctr(extra, p, &used_allctr, NULL);
+ pref_allctr = get_pref_allctr(extra);
+ used_allctr = get_used_allctr(extra, p, NULL);
if (pref_allctr != used_allctr)
enqueue_dealloc_other_instance(type,
used_allctr,
- ptr,
+ p,
(used_allctr->dd.ix
- pref_allctr->dd.ix));
else {
if (used_allctr->thread_safe)
erts_mtx_lock(&used_allctr->mutex);
ERTS_ALCU_DBG_CHK_THR_ACCESS(used_allctr);
- do_erts_alcu_free(type, used_allctr, ptr);
+ do_erts_alcu_free(type, used_allctr, p);
if (used_allctr->thread_safe)
erts_mtx_unlock(&used_allctr->mutex);
}
@@ -3739,13 +3820,13 @@ do_erts_alcu_realloc(ErtsAlcType_t type,
if (IS_MBC_BLK(blk))
res = mbc_realloc(allctr, p, size, alcu_flgs);
else {
- Uint used_sz = allctr->sbc_header_size + ABLK_HDR_SZ + size;
+ Uint used_sz = SBC_HEADER_SIZE + ABLK_HDR_SZ + size;
Uint crr_sz;
Uint diff_sz_val;
Uint crr_sz_val;
#if HAVE_ERTS_MSEG
- if (IS_SYS_ALLOC_CARRIER(BLK2SBC(allctr, blk)))
+ if (IS_SYS_ALLOC_CARRIER(BLK_TO_SBC(blk)))
#endif
crr_sz = SYS_ALLOC_CARRIER_CEILING(used_sz);
#if HAVE_ERTS_MSEG
@@ -3775,7 +3856,7 @@ do_erts_alcu_realloc(ErtsAlcType_t type,
if (res) {
sys_memcpy((void*) res,
(void*) p,
- MIN(BLK_SZ(blk) - ABLK_HDR_SZ, size));
+ MIN(SBC_BLK_SZ(blk) - ABLK_HDR_SZ, size));
destroy_carrier(allctr, blk);
}
}
@@ -3798,16 +3879,12 @@ do_erts_alcu_realloc(ErtsAlcType_t type,
else if (alcu_flgs & ERTS_ALCU_FLG_FAIL_REALLOC_MOVE)
return NULL;
else {
-#if HALFWORD_HEAP
- new_blk = create_carrier(allctr, size, CFLG_SBC | CFLG_FORCE_MSEG);
-#else
new_blk = create_carrier(allctr, size, CFLG_SBC);
-#endif
if (new_blk) {
res = BLK2UMEM(new_blk);
sys_memcpy((void *) res,
(void *) p,
- MIN(BLK_SZ(blk) - ABLK_HDR_SZ, size));
+ MIN(MBC_ABLK_SZ(blk) - ABLK_HDR_SZ, size));
mbc_free(allctr, p);
}
else
@@ -3966,16 +4043,15 @@ static ERTS_INLINE void *
realloc_thr_pref(ErtsAlcType_t type, void *extra, void *p, Uint size,
int force_move)
{
- int pref_ix;
- void *ptr, *res;
+ void *res;
Allctr_t *pref_allctr, *used_allctr;
UWord old_user_size;
if (!p)
return erts_alcu_alloc_thr_pref(type, extra, size);
- pref_ix = get_pref_allctr(extra, &pref_allctr);
- ptr = get_used_allctr(extra, p, &used_allctr, &old_user_size);
+ pref_allctr = get_pref_allctr(extra);
+ used_allctr = get_used_allctr(extra, p, &old_user_size);
ASSERT(used_allctr && pref_allctr);
@@ -3985,56 +4061,33 @@ realloc_thr_pref(ErtsAlcType_t type, void *extra, void *p, Uint size,
ERTS_ALCU_DBG_CHK_THR_ACCESS(used_allctr);
res = do_erts_alcu_realloc(type,
used_allctr,
- ptr,
- size + sizeof(UWord),
+ p,
+ size,
0);
if (used_allctr->thread_safe)
erts_mtx_unlock(&used_allctr->mutex);
- if (res)
- res = put_used_allctr(res, pref_ix, size);
}
else {
if (pref_allctr->thread_safe)
erts_mtx_lock(&pref_allctr->mutex);
- res = do_erts_alcu_alloc(type, pref_allctr, size + sizeof(UWord));
- if (pref_allctr->thread_safe && (!force_move
- || used_allctr != pref_allctr))
+ res = do_erts_alcu_alloc(type, pref_allctr, size);
+ if (pref_allctr->thread_safe && used_allctr != pref_allctr) {
erts_mtx_unlock(&pref_allctr->mutex);
+ }
if (res) {
- Block_t *blk;
- size_t cpy_size;
-
- res = put_used_allctr(res, pref_ix, size);
-
DEBUG_CHECK_ALIGNMENT(res);
- blk = UMEM2BLK(ptr);
- if (old_user_size != ERTS_AU_PREF_ALLOC_SIZE_MASK)
- cpy_size = old_user_size;
- else {
- if (used_allctr->thread_safe && (!force_move
- || used_allctr != pref_allctr))
- erts_mtx_lock(&used_allctr->mutex);
- ERTS_SMP_LC_ASSERT(!used_allctr->thread_safe ||
- erts_lc_mtx_is_locked(&used_allctr->mutex));
- cpy_size = BLK_SZ(blk);
- if (used_allctr->thread_safe && (!force_move
- || used_allctr != pref_allctr))
- erts_mtx_unlock(&used_allctr->mutex);
- cpy_size -= ABLK_HDR_SZ + sizeof(UWord);
- }
- if (cpy_size > size)
- cpy_size = size;
- sys_memcpy(res, p, cpy_size);
+ sys_memcpy(res, p, MIN(size,old_user_size));
- if (!force_move || used_allctr != pref_allctr)
+ if (used_allctr != pref_allctr) {
enqueue_dealloc_other_instance(type,
used_allctr,
- ptr,
+ p,
(used_allctr->dd.ix
- pref_allctr->dd.ix));
+ }
else {
- do_erts_alcu_free(type, used_allctr, ptr);
+ do_erts_alcu_free(type, used_allctr, p);
ASSERT(pref_allctr == used_allctr);
if (pref_allctr->thread_safe)
erts_mtx_unlock(&pref_allctr->mutex);
@@ -4111,7 +4164,7 @@ erts_alcu_start(Allctr_t *allctr, AllctrInit_t *init)
allctr->ramv = init->ramv;
allctr->main_carrier_size = init->mmbcs;
- allctr->sbc_threshold = init->sbct;
+
#if HAVE_ERTS_MSEG
allctr->mseg_opt.abs_shrink_th = init->asbcst;
allctr->mseg_opt.rel_shrink_th = init->rsbcst;
@@ -4120,20 +4173,29 @@ erts_alcu_start(Allctr_t *allctr, AllctrInit_t *init)
allctr->mbc_move_threshold = init->rmbcmt;
#if HAVE_ERTS_MSEG
allctr->max_mseg_sbcs = init->mmsbc;
+# if HAVE_SUPER_ALIGNED_MB_CARRIERS
+ allctr->max_mseg_mbcs = ~(Uint)0;
+# else
allctr->max_mseg_mbcs = init->mmmbc;
+# endif
#endif
allctr->largest_mbc_size = MAX(init->lmbcs, init->smbcs);
+#ifndef ARCH_64
+ if (allctr->largest_mbc_size > MBC_SZ_MAX_LIMIT) {
+ allctr->largest_mbc_size = MBC_SZ_MAX_LIMIT;
+ }
+#endif
allctr->smallest_mbc_size = init->smbcs;
allctr->mbc_growth_stages = MAX(1, init->mbcgs);
if (allctr->min_block_size < ABLK_HDR_SZ)
goto error;
allctr->min_block_size = UNIT_CEILING(allctr->min_block_size
- + sizeof(UWord));
+ + sizeof(FreeBlkFtr_t));
#if ERTS_SMP
if (init->tpref) {
- Uint sz = sizeof(Block_t);
+ Uint sz = ABLK_HDR_SZ;
sz += ERTS_ALCU_DD_FIX_TYPE_OFFS*sizeof(UWord);
if (init->fix)
sz += sizeof(UWord);
@@ -4143,6 +4205,23 @@ erts_alcu_start(Allctr_t *allctr, AllctrInit_t *init)
}
#endif
+ allctr->sbc_threshold = init->sbct;
+#ifndef ARCH_64
+ if (allctr->sbc_threshold > 0) {
+ Uint max_mbc_block_sz = UNIT_CEILING(allctr->sbc_threshold - 1 + ABLK_HDR_SZ);
+ if (max_mbc_block_sz + UNIT_FLOOR(allctr->min_block_size - 1) > MBC_ABLK_SZ_MASK
+ || max_mbc_block_sz < allctr->sbc_threshold) { /* wrap around */
+ /*
+ * By limiting sbc_threshold to (hard limit - min_block_size)
+ * we avoid having to split off free "residue blocks"
+ * smaller than min_block_size.
+ */
+ max_mbc_block_sz = MBC_ABLK_SZ_MASK - UNIT_FLOOR(allctr->min_block_size - 1);
+ allctr->sbc_threshold = max_mbc_block_sz - ABLK_HDR_SZ + 1;
+ }
+ }
+#endif
+
allctr->sbmbc_threshold = init->sbmbct;
@@ -4158,7 +4237,7 @@ erts_alcu_start(Allctr_t *allctr, AllctrInit_t *init)
allctr->sbmbc_size = init->sbmbcs;
min_size = allctr->sbmbc_threshold;
min_size += allctr->min_block_size;
- min_size += allctr->mbc_header_size;
+ min_size += MBC_HEADER_SIZE(allctr);
if (allctr->sbmbc_size < min_size)
allctr->sbmbc_size = min_size;
}
@@ -4203,59 +4282,26 @@ erts_alcu_start(Allctr_t *allctr, AllctrInit_t *init)
if (!allctr->get_next_mbc_size)
allctr->get_next_mbc_size = get_next_mbc_size;
- if (allctr->mbc_header_size < sizeof(Carrier_t))
- goto error;
#ifdef ERTS_SMP
allctr->dd.use = 0;
if (init->tpref) {
- allctr->mbc_header_size = (UNIT_CEILING(allctr->mbc_header_size
- + FBLK_FTR_SZ
- + ABLK_HDR_SZ
- + sizeof(UWord))
- - ABLK_HDR_SZ
- - sizeof(UWord));
- allctr->sbc_header_size = (UNIT_CEILING(sizeof(Carrier_t)
- + FBLK_FTR_SZ
- + ABLK_HDR_SZ
- + sizeof(UWord))
- - ABLK_HDR_SZ
- - sizeof(UWord));
-
allctr->dd.use = 1;
init_dd_queue(&allctr->dd.q);
allctr->dd.ix = init->ix;
}
- else
#endif
- {
- allctr->mbc_header_size = (UNIT_CEILING(allctr->mbc_header_size
- + FBLK_FTR_SZ
- + ABLK_HDR_SZ)
- - ABLK_HDR_SZ);
- allctr->sbc_header_size = (UNIT_CEILING(sizeof(Carrier_t)
- + FBLK_FTR_SZ
- + ABLK_HDR_SZ)
- - ABLK_HDR_SZ);
- }
if (allctr->main_carrier_size) {
Block_t *blk;
-#if HALFWORD_HEAP
- blk = create_carrier(allctr,
- allctr->main_carrier_size,
- CFLG_MBC
- | CFLG_FORCE_SIZE
- | CFLG_FORCE_MSEG
- | CFLG_MAIN_CARRIER);
-#else
blk = create_carrier(allctr,
allctr->main_carrier_size,
CFLG_MBC
| CFLG_FORCE_SIZE
+#if !HALFWORD_HEAP && !HAVE_SUPER_ALIGNED_MB_CARRIERS
| CFLG_FORCE_SYS_ALLOC
- | CFLG_MAIN_CARRIER);
#endif
+ | CFLG_MAIN_CARRIER);
if (!blk)
goto error;
@@ -4303,9 +4349,9 @@ erts_alcu_stop(Allctr_t *allctr)
while (allctr->sbc_list.first)
destroy_carrier(allctr, SBC2BLK(allctr, allctr->sbc_list.first));
while (allctr->mbc_list.first)
- destroy_carrier(allctr, MBC2FBLK(allctr, allctr->mbc_list.first));
+ destroy_carrier(allctr, MBC_TO_FIRST_BLK(allctr, allctr->mbc_list.first));
while (allctr->sbmbc_list.first)
- destroy_sbmbc(allctr, MBC2FBLK(allctr, allctr->sbmbc_list.first));
+ destroy_sbmbc(allctr, MBC_TO_FIRST_BLK(allctr, allctr->sbmbc_list.first));
#ifdef USE_THREADS
if (allctr->thread_safe)
@@ -4319,17 +4365,9 @@ erts_alcu_stop(Allctr_t *allctr)
void
erts_alcu_init(AlcUInit_t *init)
{
-
+ ASSERT(SBC_BLK_SZ_MASK == MBC_FBLK_SZ_MASK); /* see BLK_SZ */
#if HAVE_ERTS_MSEG
- mseg_unit_size = erts_mseg_unit_size();
-
- if (mseg_unit_size % sizeof(Unit_t)) /* A little paranoid... */
- erl_exit(-1,
- "Mseg unit size (%d) not evenly divideble by "
- "internal unit size of alloc_util (%d)\n",
- mseg_unit_size,
- sizeof(Unit_t));
-
+ ASSERT(erts_mseg_unit_size() == MSEG_UNIT_SZ);
max_mseg_carriers = init->mmc;
sys_alloc_carrier_size = MSEG_UNIT_CEILING(init->ycs);
#else /* #if HAVE_ERTS_MSEG */
@@ -4372,11 +4410,10 @@ erts_alcu_test(unsigned long op, unsigned long a1, unsigned long a2)
case 0x00b: return (unsigned long) CARRIER_SZ((Carrier_t *) a1);
case 0x00c: return (unsigned long) SBC2BLK((Allctr_t *) a1,
(Carrier_t *) a2);
- case 0x00d: return (unsigned long) BLK2SBC((Allctr_t *) a1,
- (Block_t *) a2);
- case 0x00e: return (unsigned long) MBC2FBLK((Allctr_t *) a1,
+ case 0x00d: return (unsigned long) BLK_TO_SBC((Block_t *) a2);
+ case 0x00e: return (unsigned long) MBC_TO_FIRST_BLK((Allctr_t *) a1,
(Carrier_t *) a2);
- case 0x00f: return (unsigned long) FBLK2MBC((Allctr_t *) a1,
+ case 0x00f: return (unsigned long) FIRST_BLK_TO_MBC((Allctr_t *) a1,
(Block_t *) a2);
case 0x010: return (unsigned long) ((Allctr_t *) a1)->mbc_list.first;
case 0x011: return (unsigned long) ((Allctr_t *) a1)->mbc_list.last;
@@ -4388,7 +4425,7 @@ erts_alcu_test(unsigned long op, unsigned long a1, unsigned long a2)
case 0x017: return (unsigned long) ((Allctr_t *) a1)->min_block_size;
case 0x018: return (unsigned long) NXT_BLK((Block_t *) a1);
case 0x019: return (unsigned long) PREV_BLK((Block_t *) a1);
- case 0x01a: return (unsigned long) IS_FIRST_BLK((Block_t *) a1);
+ case 0x01a: return (unsigned long) IS_MBC_FIRST_BLK((Allctr_t*)a1, (Block_t *) a2);
case 0x01b: return (unsigned long) sizeof(Unit_t);
default: ASSERT(0); return ~((unsigned long) 0);
}
@@ -4432,6 +4469,13 @@ erts_alcu_verify_unused_ts(Allctr_t *allctr)
#endif
}
+#ifdef DEBUG
+int is_sbc_blk(Block_t* blk)
+{
+ return IS_SBC_BLK(blk);
+}
+#endif
+
#ifdef ERTS_ALLOC_UTIL_HARD_DEBUG
static void
@@ -4441,34 +4485,37 @@ check_blk_carrier(Allctr_t *allctr, Block_t *iblk)
CarrierList_t *cl;
if (IS_SBC_BLK(iblk)) {
- Carrier_t *sbc = BLK2SBC(allctr, iblk);
+ Carrier_t *sbc = BLK_TO_SBC(iblk);
ASSERT(SBC2BLK(allctr, sbc) == iblk);
- ASSERT(IS_ALLOCED_BLK(iblk));
- ASSERT(IS_FIRST_BLK(iblk));
- ASSERT(IS_LAST_BLK(iblk));
- ASSERT(CARRIER_SZ(sbc) - allctr->sbc_header_size >= BLK_SZ(iblk));
+ ASSERT(CARRIER_SZ(sbc) - SBC_HEADER_SIZE >= SBC_BLK_SZ(iblk));
#if HAVE_ERTS_MSEG
if (IS_MSEG_CARRIER(sbc)) {
- ASSERT(CARRIER_SZ(sbc) % mseg_unit_size == 0);
+ ASSERT(CARRIER_SZ(sbc) % MSEG_UNIT_SZ == 0);
}
#endif
crr = sbc;
cl = &allctr->sbc_list;
}
else {
- Carrier_t *mbc = NULL;
Block_t *prev_blk = NULL;
Block_t *blk;
char *carrier_end;
Uint is_free_blk;
Uint tot_blk_sz;
Uint blk_sz;
+ int has_wrapped_around = 0;
blk = iblk;
tot_blk_sz = 0;
+ crr = BLK_TO_MBC(blk);
+ ASSERT(IS_MB_CARRIER(crr));
+ /* Step around the carrier one whole lap starting at 'iblk'
+ */
while (1) {
+ ASSERT(IS_MBC_BLK(blk));
+ ASSERT(BLK_TO_MBC(blk) == crr);
if (prev_blk) {
ASSERT(NXT_BLK(prev_blk) == blk);
@@ -4481,18 +4528,16 @@ check_blk_carrier(Allctr_t *allctr, Block_t *iblk)
}
}
- if (mbc) {
+ if (has_wrapped_around) {
+ ASSERT(((Block_t *) crr) < blk);
if (blk == iblk)
break;
- ASSERT(((Block_t *) mbc) < blk && blk < iblk);
+ ASSERT(blk < iblk);
}
else
ASSERT(blk >= iblk);
-
- ASSERT(IS_MBC_BLK(blk));
-
- blk_sz = BLK_SZ(blk);
+ blk_sz = MBC_BLK_SZ(blk);
ASSERT(blk_sz % sizeof(Unit_t) == 0);
ASSERT(blk_sz >= allctr->min_block_size);
@@ -4500,44 +4545,40 @@ check_blk_carrier(Allctr_t *allctr, Block_t *iblk)
tot_blk_sz += blk_sz;
is_free_blk = (int) IS_FREE_BLK(blk);
- if(is_free_blk) {
- if (IS_NOT_LAST_BLK(blk))
- ASSERT(*((UWord *) (((char *) blk)+blk_sz-sizeof(UWord)))
- == blk_sz);
- }
+ ASSERT(!is_free_blk
+ || IS_LAST_BLK(blk)
+ || PREV_BLK_SZ(((char *) blk)+blk_sz) == blk_sz);
if (allctr->check_block)
(*allctr->check_block)(allctr, blk, (int) is_free_blk);
if (IS_LAST_BLK(blk)) {
carrier_end = ((char *) NXT_BLK(blk));
- mbc = *((Carrier_t **) NXT_BLK(blk));
+ has_wrapped_around = 1;
prev_blk = NULL;
- blk = MBC2FBLK(allctr, mbc);
- ASSERT(IS_FIRST_BLK(blk));
+ blk = MBC_TO_FIRST_BLK(allctr, crr);
+ ASSERT(IS_MBC_FIRST_BLK(allctr,blk));
}
else {
prev_blk = blk;
blk = NXT_BLK(blk);
}
}
-
- ASSERT(IS_MB_CARRIER(mbc));
- ASSERT((((char *) mbc)
- + allctr->mbc_header_size
+
+ ASSERT((((char *) crr)
+ + MBC_HEADER_SIZE(allctr)
+ tot_blk_sz) == carrier_end);
- ASSERT(((char *) mbc) + CARRIER_SZ(mbc) - sizeof(Unit_t) <= carrier_end
- && carrier_end <= ((char *) mbc) + CARRIER_SZ(mbc));
+ ASSERT(((char *) crr) + CARRIER_SZ(crr) - sizeof(Unit_t) <= carrier_end
+ && carrier_end <= ((char *) crr) + CARRIER_SZ(crr));
if (allctr->check_mbc)
- (*allctr->check_mbc)(allctr, mbc);
+ (*allctr->check_mbc)(allctr, crr);
#if HAVE_ERTS_MSEG
- if (IS_MSEG_CARRIER(mbc)) {
- ASSERT(CARRIER_SZ(mbc) % mseg_unit_size == 0);
+ if (IS_MSEG_CARRIER(crr)) {
+ ASSERT(CARRIER_SZ(crr) % MSEG_UNIT_SZ == 0);
}
#endif
- crr = mbc;
cl = &allctr->mbc_list;
}
@@ -4559,4 +4600,5 @@ check_blk_carrier(Allctr_t *allctr, Block_t *iblk)
#endif
}
-#endif
+#endif /* ERTS_ALLOC_UTIL_HARD_DEBUG */
+
diff --git a/erts/emulator/beam/erl_alloc_util.h b/erts/emulator/beam/erl_alloc_util.h
index cedf4ccf85..e0754e7f69 100644
--- a/erts/emulator/beam/erl_alloc_util.h
+++ b/erts/emulator/beam/erl_alloc_util.h
@@ -216,16 +216,40 @@ erts_aint32_t erts_alcu_fix_alloc_shrink(Allctr_t *, erts_aint32_t);
#define UNIT_FLOOR(X) ((X) & UNIT_MASK)
#define UNIT_CEILING(X) UNIT_FLOOR((X) + INV_UNIT_MASK)
+#define FLG_MASK INV_UNIT_MASK
+#define SBC_BLK_SZ_MASK UNIT_MASK
+#define MBC_FBLK_SZ_MASK UNIT_MASK
+#define CARRIER_SZ_MASK UNIT_MASK
-#define SZ_MASK (~((UWord) 0) << 3)
-#define FLG_MASK (~(SZ_MASK))
+#if HAVE_ERTS_MSEG
+# ifdef ARCH_64
+# define MBC_ABLK_OFFSET_BITS 24
+# elif HAVE_SUPER_ALIGNED_MB_CARRIERS
+# define MBC_ABLK_OFFSET_BITS 9
+ /* Affects hard limits for sbct and lmbcs documented in erts_alloc.xml */
+# endif
+#endif
+#ifndef MBC_ABLK_OFFSET_BITS
+# define MBC_ABLK_OFFSET_BITS 0 /* no carrier offset in block header */
+#endif
+
+#if MBC_ABLK_OFFSET_BITS
+# define MBC_ABLK_OFFSET_SHIFT (sizeof(UWord)*8 - MBC_ABLK_OFFSET_BITS)
+# define MBC_ABLK_OFFSET_MASK (~((UWord)0) << MBC_ABLK_OFFSET_SHIFT)
+# define MBC_ABLK_SZ_MASK (~MBC_ABLK_OFFSET_MASK & ~FLG_MASK)
+# define HAVE_ERTS_SBMBC 0
+#else
+# define MBC_ABLK_SZ_MASK (~FLG_MASK)
+# define HAVE_ERTS_SBMBC 1
+#endif
-#define BLK_SZ(B) \
- (*((Block_t *) (B)) & SZ_MASK)
+#define MBC_ABLK_SZ(B) (ASSERT_EXPR(!is_sbc_blk(B)), (B)->bhdr & MBC_ABLK_SZ_MASK)
+#define MBC_FBLK_SZ(B) (ASSERT_EXPR(!is_sbc_blk(B)), (B)->bhdr & MBC_FBLK_SZ_MASK)
+#define SBC_BLK_SZ(B) (ASSERT_EXPR(is_sbc_blk(B)), (B)->bhdr & SBC_BLK_SZ_MASK)
#define CARRIER_SZ(C) \
- ((C)->chdr & SZ_MASK)
+ ((C)->chdr & CARRIER_SZ_MASK)
extern int erts_have_sbmbc_alloc;
@@ -236,6 +260,7 @@ struct Carrier_t_ {
UWord chdr;
Carrier_t *next;
Carrier_t *prev;
+ Allctr_t *allctr;
};
typedef struct {
@@ -243,8 +268,19 @@ typedef struct {
Carrier_t *last;
} CarrierList_t;
-typedef UWord Block_t;
-typedef UWord FreeBlkFtr_t;
+typedef struct {
+ UWord bhdr;
+#if !MBC_ABLK_OFFSET_BITS
+ Carrier_t *carrier;
+#else
+ union {
+ Carrier_t *carrier; /* if free */
+ char udata__[1]; /* if allocated */
+ }u;
+#endif
+} Block_t;
+
+typedef UWord FreeBlkFtr_t; /* Footer of a free block */
typedef struct {
UWord giga_no;
@@ -381,8 +417,6 @@ struct Allctr_t_ {
#endif
/* */
- Uint mbc_header_size;
- Uint sbc_header_size;
Uint min_mbc_size;
Uint min_mbc_first_free_size;
Uint min_block_size;
@@ -469,6 +503,9 @@ void erts_alcu_verify_unused_ts(Allctr_t *allctr);
unsigned long erts_alcu_test(unsigned long, unsigned long, unsigned long);
+#ifdef DEBUG
+int is_sbc_blk(Block_t*);
+#endif
#endif /* #if defined(GET_ERL_ALLOC_UTIL_IMPL)
diff --git a/erts/emulator/beam/erl_ao_firstfit_alloc.c b/erts/emulator/beam/erl_ao_firstfit_alloc.c
index 5bdb752d3a..86b4696d8f 100644
--- a/erts/emulator/beam/erl_ao_firstfit_alloc.c
+++ b/erts/emulator/beam/erl_ao_firstfit_alloc.c
@@ -91,6 +91,7 @@ struct AOFF_RBTree_t_ {
AOFF_RBTree_t *right;
Uint max_sz; /* of all blocks in this sub-tree */
};
+#define AOFF_BLK_SZ(B) MBC_FBLK_SZ(&(B)->hdr)
#ifdef HARD_DEBUG
static AOFF_RBTree_t * check_tree(AOFF_RBTree_t* root, Uint);
@@ -102,7 +103,7 @@ static AOFF_RBTree_t * check_tree(AOFF_RBTree_t* root, Uint);
*/
static ERTS_INLINE Uint node_max_size(AOFF_RBTree_t *x)
{
- Uint sz = BLK_SZ(x);
+ Uint sz = AOFF_BLK_SZ(x);
if (x->left && x->left->max_sz > sz) {
sz = x->left->max_sz;
}
@@ -183,7 +184,6 @@ erts_aoffalc_start(AOFFAllctr_t *alc,
sys_memcpy((void *) alc, (void *) &zero.allctr, sizeof(AOFFAllctr_t));
- allctr->mbc_header_size = sizeof(Carrier_t);
allctr->min_mbc_size = MIN_MBC_SZ;
allctr->min_mbc_first_free_size = MIN_MBC_FIRST_FREE_SZ;
allctr->min_block_size = sizeof(AOFF_RBTree_t);
@@ -587,7 +587,7 @@ aoff_link_free_block(Allctr_t *allctr, Block_t *block, Uint32 flags)
AOFF_RBTree_t *blk = (AOFF_RBTree_t *) block;
AOFF_RBTree_t **root = ((flags & ERTS_ALCU_FLG_SBMBC)
? &alc->sbmbc_root : &alc->mbc_root);
- Uint blk_sz = BLK_SZ(blk);
+ Uint blk_sz = AOFF_BLK_SZ(blk);
#ifdef HARD_DEBUG
check_tree(*root, 0);
@@ -659,7 +659,7 @@ aoff_get_free_block(Allctr_t *allctr, Uint size,
if (x->left && x->left->max_sz >= size) {
x = x->left;
}
- else if (BLK_SZ(x) >= size) {
+ else if (AOFF_BLK_SZ(x) >= size) {
blk = x;
break;
}
@@ -910,12 +910,12 @@ check_tree(AOFF_RBTree_t* root, Uint size)
ASSERT(x->right > x);
ASSERT(x->right->max_sz <= x->max_sz);
}
- ASSERT(x->max_sz >= BLK_SZ(x));
- ASSERT(x->max_sz == BLK_SZ(x)
+ ASSERT(x->max_sz >= AOFF_BLK_SZ(x));
+ ASSERT(x->max_sz == AOFF_BLK_SZ(x)
|| x->max_sz == (x->left ? x->left->max_sz : 0)
|| x->max_sz == (x->right ? x->right->max_sz : 0));
- if (size && BLK_SZ(x) >= size) {
+ if (size && AOFF_BLK_SZ(x) >= size) {
if (!res || x < res) {
res = x;
}
@@ -956,7 +956,7 @@ print_tree_aux(AOFF_RBTree_t *x, int indent)
}
fprintf(stderr, "%s: sz=%lu addr=0x%lx max_size=%lu\r\n",
IS_BLACK(x) ? "BLACK" : "RED",
- BLK_SZ(x), (Uint)x, x->max_sz);
+ AOFF_BLK_SZ(x), (Uint)x, x->max_sz);
print_tree_aux(x->left, indent + INDENT_STEP);
}
}
diff --git a/erts/emulator/beam/erl_async.c b/erts/emulator/beam/erl_async.c
index c5f432bea1..f2ca193ace 100644
--- a/erts/emulator/beam/erl_async.c
+++ b/erts/emulator/beam/erl_async.c
@@ -382,10 +382,15 @@ static ERTS_INLINE ErtsAsync *async_get(ErtsThrQ_t *q,
static ERTS_INLINE void call_async_ready(ErtsAsync *a)
{
+#if ERTS_USE_ASYNC_READY_Q
Port *p = erts_id2port_sflgs(a->port,
NULL,
0,
ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP);
+#else
+ Port *p = erts_thr_id2port_sflgs(a->port,
+ ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP);
+#endif
if (!p) {
if (a->async_free)
a->async_free(a->async_data);
@@ -395,7 +400,11 @@ static ERTS_INLINE void call_async_ready(ErtsAsync *a)
if (a->async_free)
a->async_free(a->async_data);
}
+#if ERTS_USE_ASYNC_READY_Q
erts_port_release(p);
+#else
+ erts_thr_port_release(p);
+#endif
}
if (a->pdl)
driver_pdl_dec_refc(a->pdl);
@@ -603,7 +612,7 @@ long driver_async(ErlDrvPort ix, unsigned int* key,
sched_id = 1;
#endif
- prt = erts_drvport2port(ix);
+ prt = erts_drvport2port(ix, NULL);
if (!prt)
return -1;
@@ -615,7 +624,7 @@ long driver_async(ErlDrvPort ix, unsigned int* key,
a->sched_id = sched_id;
#endif
a->hndl = (DE_Handle*)prt->drv_ptr->handle;
- a->port = prt->id;
+ a->port = prt->common.id;
a->pdl = NULL;
a->async_data = async_data;
a->async_invoke = async_invoke;
diff --git a/erts/emulator/beam/erl_bestfit_alloc.c b/erts/emulator/beam/erl_bestfit_alloc.c
index c50fdeb4e8..743cbd93c9 100644
--- a/erts/emulator/beam/erl_bestfit_alloc.c
+++ b/erts/emulator/beam/erl_bestfit_alloc.c
@@ -73,6 +73,8 @@
#define SET_RED(N) (((RBTree_t *) (N))->flags |= RED_FLG)
#define SET_BLACK(N) (((RBTree_t *) (N))->flags &= ~RED_FLG)
+#define BF_BLK_SZ(B) MBC_FBLK_SZ(&(B)->hdr)
+
#undef ASSERT
#define ASSERT ASSERT_EXPR
@@ -177,7 +179,6 @@ erts_bfalc_start(BFAllctr_t *bfallctr,
bfallctr->address_order = bfinit->ao;
- allctr->mbc_header_size = sizeof(Carrier_t);
allctr->min_mbc_size = MIN_MBC_SZ;
allctr->min_mbc_first_free_size = MIN_MBC_FIRST_FREE_SZ;
allctr->min_block_size = (bfinit->ao
@@ -592,7 +593,7 @@ aobf_link_free_block(Allctr_t *allctr, Block_t *block, Uint32 flags)
? &bfallctr->sbmbc_root
: &bfallctr->mbc_root);
RBTree_t *blk = (RBTree_t *) block;
- Uint blk_sz = BLK_SZ(blk);
+ Uint blk_sz = BF_BLK_SZ(blk);
@@ -610,7 +611,7 @@ aobf_link_free_block(Allctr_t *allctr, Block_t *block, Uint32 flags)
while (1) {
Uint size;
- size = BLK_SZ(x);
+ size = BF_BLK_SZ(x);
if (blk_sz < size || (blk_sz == size && blk < x)) {
if (!x->left) {
@@ -668,7 +669,7 @@ aobf_get_free_block(Allctr_t *allctr, Uint size,
ASSERT(!cand_blk || cand_size >= size);
while (x) {
- blk_sz = BLK_SZ(x);
+ blk_sz = BF_BLK_SZ(x);
if (blk_sz < size) {
x = x->right;
}
@@ -686,7 +687,7 @@ aobf_get_free_block(Allctr_t *allctr, Uint size,
#endif
if (cand_blk) {
- blk_sz = BLK_SZ(blk);
+ blk_sz = BF_BLK_SZ(blk);
if (cand_size < blk_sz)
return NULL; /* cand_blk was better */
if (cand_size == blk_sz && ((void *) cand_blk) < ((void *) blk))
@@ -711,7 +712,7 @@ bf_link_free_block(Allctr_t *allctr, Block_t *block, Uint32 flags)
? &bfallctr->sbmbc_root
: &bfallctr->mbc_root);
RBTree_t *blk = (RBTree_t *) block;
- Uint blk_sz = BLK_SZ(blk);
+ Uint blk_sz = BF_BLK_SZ(blk);
SET_TREE_NODE(blk);
@@ -730,7 +731,7 @@ bf_link_free_block(Allctr_t *allctr, Block_t *block, Uint32 flags)
while (1) {
Uint size;
- size = BLK_SZ(x);
+ size = BF_BLK_SZ(x);
if (blk_sz == size) {
@@ -796,7 +797,7 @@ bf_unlink_free_block(Allctr_t *allctr, Block_t *block, Uint32 flags)
else if (LIST_NEXT(x)) {
/* Replace tree node by next element in list... */
- ASSERT(BLK_SZ(LIST_NEXT(x)) == BLK_SZ(x));
+ ASSERT(BF_BLK_SZ(LIST_NEXT(x)) == BF_BLK_SZ(x));
ASSERT(IS_TREE_NODE(x));
ASSERT(IS_LIST_ELEM(LIST_NEXT(x)));
@@ -834,7 +835,7 @@ bf_get_free_block(Allctr_t *allctr, Uint size,
ASSERT(!cand_blk || cand_size >= size);
while (x) {
- blk_sz = BLK_SZ(x);
+ blk_sz = BF_BLK_SZ(x);
if (blk_sz < size) {
x = x->right;
}
@@ -855,11 +856,11 @@ bf_get_free_block(Allctr_t *allctr, Uint size,
#ifdef HARD_DEBUG
{
RBTree_t *ct_blk = check_tree(root, 0, size);
- ASSERT(BLK_SZ(ct_blk) == BLK_SZ(blk));
+ ASSERT(BF_BLK_SZ(ct_blk) == BF_BLK_SZ(blk));
}
#endif
- if (cand_blk && cand_size <= BLK_SZ(blk))
+ if (cand_blk && cand_size <= BF_BLK_SZ(blk))
return NULL; /* cand_blk was better */
/* Use next block if it exist in order to avoid replacing
@@ -1093,36 +1094,36 @@ check_tree(RBTree_t *root, int ao, Uint size)
if (x->left) {
ASSERT(x->left->parent == x);
if (ao) {
- ASSERT(BLK_SZ(x->left) < BLK_SZ(x)
- || (BLK_SZ(x->left) == BLK_SZ(x) && x->left < x));
+ ASSERT(BF_BLK_SZ(x->left) < BF_BLK_SZ(x)
+ || (BF_BLK_SZ(x->left) == BF_BLK_SZ(x) && x->left < x));
}
else {
ASSERT(IS_TREE_NODE(x->left));
- ASSERT(BLK_SZ(x->left) < BLK_SZ(x));
+ ASSERT(BF_BLK_SZ(x->left) < BF_BLK_SZ(x));
}
}
if (x->right) {
ASSERT(x->right->parent == x);
if (ao) {
- ASSERT(BLK_SZ(x->right) > BLK_SZ(x)
- || (BLK_SZ(x->right) == BLK_SZ(x) && x->right > x));
+ ASSERT(BF_BLK_SZ(x->right) > BF_BLK_SZ(x)
+ || (BF_BLK_SZ(x->right) == BF_BLK_SZ(x) && x->right > x));
}
else {
ASSERT(IS_TREE_NODE(x->right));
- ASSERT(BLK_SZ(x->right) > BLK_SZ(x));
+ ASSERT(BF_BLK_SZ(x->right) > BF_BLK_SZ(x));
}
}
- if (size && BLK_SZ(x) >= size) {
+ if (size && BF_BLK_SZ(x) >= size) {
if (ao) {
if (!res
- || BLK_SZ(x) < BLK_SZ(res)
- || (BLK_SZ(x) == BLK_SZ(res) && x < res))
+ || BF_BLK_SZ(x) < BF_BLK_SZ(res)
+ || (BF_BLK_SZ(x) == BF_BLK_SZ(res) && x < res))
res = x;
}
else {
- if (!res || BLK_SZ(x) < BLK_SZ(res))
+ if (!res || BF_BLK_SZ(x) < BF_BLK_SZ(res))
res = x;
}
}
@@ -1168,7 +1169,7 @@ print_tree_aux(RBTree_t *x, int indent)
}
fprintf(stderr, "%s: sz=%lu addr=0x%lx\r\n",
IS_BLACK(x) ? "BLACK" : "RED",
- BLK_SZ(x),
+ BF_BLK_SZ(x),
(Uint) x);
print_tree_aux(x->left, indent + INDENT_STEP);
}
diff --git a/erts/emulator/beam/erl_bif_ddll.c b/erts/emulator/beam/erl_bif_ddll.c
index 7f7c975e78..7cbea55eac 100644
--- a/erts/emulator/beam/erl_bif_ddll.c
+++ b/erts/emulator/beam/erl_bif_ddll.c
@@ -104,16 +104,49 @@ static void dereference_all_processes(DE_Handle *dh);
static void restore_process_references(DE_Handle *dh);
static void ddll_no_more_references(void *vdh);
-#define lock_drv_list() erts_smp_mtx_lock(&erts_driver_list_lock)
-#define unlock_drv_list() erts_smp_mtx_unlock(&erts_driver_list_lock)
+#define lock_drv_list() erts_smp_rwmtx_rwlock(&erts_driver_list_lock)
+#define unlock_drv_list() erts_smp_rwmtx_rwunlock(&erts_driver_list_lock)
#define assert_drv_list_locked() \
- ERTS_SMP_LC_ASSERT(erts_smp_lc_mtx_is_locked(&erts_driver_list_lock))
+ ERTS_SMP_LC_ASSERT(erts_smp_lc_rwmtx_is_rwlocked(&erts_driver_list_lock) \
+ || erts_smp_lc_rwmtx_is_rlocked(&erts_driver_list_lock))
+#define assert_drv_list_rwlocked() \
+ ERTS_SMP_LC_ASSERT(erts_smp_lc_rwmtx_is_rwlocked(&erts_driver_list_lock))
+#define assert_drv_list_rlocked() \
+ ERTS_SMP_LC_ASSERT(erts_smp_lc_rwmtx_is_rlocked(&erts_driver_list_lock))
#define assert_drv_list_not_locked() \
- ERTS_SMP_LC_ASSERT(!erts_smp_lc_mtx_is_locked(&erts_driver_list_lock))
+ ERTS_SMP_LC_ASSERT(!erts_smp_lc_rwmtx_is_rwlocked(&erts_driver_list_lock) \
+ && !erts_smp_lc_rwmtx_is_rlocked(&erts_driver_list_lock))
#define FREE_PORT_FLAGS (ERTS_PORT_SFLGS_DEAD & (~ERTS_PORT_SFLG_INITIALIZING))
+static void
+kill_ports_driver_unloaded(DE_Handle *dh)
+{
+ int ix, max = erts_ptab_max(&erts_port);
+
+ for (ix = 0; ix < max; ix++) {
+ erts_aint32_t state;
+ Port* prt = erts_pix2port(ix);
+ if (!prt)
+ continue;
+
+ ERTS_SMP_DATA_DEPENDENCY_READ_MEMORY_BARRIER;
+
+ state = erts_atomic32_read_nob(&prt->state);
+ if (state & FREE_PORT_FLAGS)
+ continue;
+
+ erts_smp_port_lock(prt);
+
+ state = erts_atomic32_read_nob(&prt->state);
+ if (!(state & ERTS_PORT_SFLGS_DEAD) && prt->drv_ptr->handle == dh)
+ driver_failure_atom((ErlDrvPort) prt, "driver_unloaded");
+
+ erts_port_release(prt);
+ }
+}
+
/*
* try_load(Path, Name, OptionList) -> {ok,Status} |
* {ok, PendingStatus, Ref} |
@@ -149,7 +182,7 @@ BIF_RETTYPE erl_ddll_try_load_3(BIF_ALIST_3)
Eterm name_term = BIF_ARG_2;
Eterm options = BIF_ARG_3;
char *path = NULL;
- Uint path_len;
+ ErlDrvSizeT path_len;
char *name = NULL;
DE_Handle *dh;
erts_driver_t *drv;
@@ -228,7 +261,7 @@ BIF_RETTYPE erl_ddll_try_load_3(BIF_ALIST_3)
goto error;
}
path = erts_alloc(ERTS_ALC_T_DDLL_TMP_BUF, path_len + 1 /* might need path separator */ + sys_strlen(name) + 1);
- if (io_list_to_buf(path_term, path, path_len) != 0) {
+ if (erts_iolist_to_buf(path_term, path, path_len) != 0) {
goto error;
}
while (path_len > 0 && (path[path_len-1] == '\\' || path[path_len-1] == '/')) {
@@ -356,40 +389,16 @@ BIF_RETTYPE erl_ddll_try_load_3(BIF_ALIST_3)
ok_term = mkatom("loaded");
}
}
- assert_drv_list_locked();
+ assert_drv_list_rwlocked();
if (kill_ports) {
- int j;
- /* Avoid closing the driver by referencing it */
+ /* Avoid closing the driver by referencing it */
erts_ddll_reference_driver(dh);
ASSERT(dh->status == ERL_DE_RELOAD);
dh->status = ERL_DE_FORCE_RELOAD;
#if DDLL_SMP
unlock_drv_list();
#endif
- for (j = 0; j < erts_max_ports; j++) {
- Port* prt = &erts_port[j];
- erts_smp_port_state_lock(prt);
- if (!(prt->status & FREE_PORT_FLAGS) &&
- prt->drv_ptr->handle == dh) {
- erts_smp_atomic_inc_nob(&prt->refc);
-#if DDLL_SMP
- /* Extremely rare spinlock */
- while(prt->status & ERTS_PORT_SFLG_INITIALIZING) {
- erts_smp_port_state_unlock(prt);
- erts_smp_port_state_lock(prt);
- }
- erts_smp_port_state_unlock(prt);
- erts_smp_mtx_lock(prt->lock);
- if (!(prt->status & ERTS_PORT_SFLGS_DEAD)) {
- driver_failure_atom(j, "driver_unloaded");
- }
-#else
- driver_failure_atom(j, "driver_unloaded");
-#endif
- erts_port_release(prt);
- }
- else erts_smp_port_state_unlock(prt);
- }
+ kill_ports_driver_unloaded(dh);
/* Dereference, eventually causing driver destruction */
#if DDLL_SMP
lock_drv_list();
@@ -579,45 +588,21 @@ Eterm erl_ddll_try_unload_2(BIF_ALIST_2)
dh->reload_full_path = dh->reload_driver_name = NULL;
dh->reload_flags = 0;
}
- if (dh->port_count > 0) {
+ if (erts_smp_atomic32_read_nob(&dh->port_count) > 0) {
++kill_ports;
}
dh->status = ERL_DE_UNLOAD;
ok_term = am_pending_driver;
done:
- assert_drv_list_locked();
+ assert_drv_list_rwlocked();
if (kill_ports > 1) {
- int j;
/* Avoid closing the driver by referencing it */
erts_ddll_reference_driver(dh);
dh->status = ERL_DE_FORCE_UNLOAD;
#if DDLL_SMP
unlock_drv_list();
#endif
- for (j = 0; j < erts_max_ports; j++) {
- Port* prt = &erts_port[j];
- erts_smp_port_state_lock(prt);
- if (!(prt->status & FREE_PORT_FLAGS)
- && prt->drv_ptr->handle == dh) {
- erts_smp_atomic_inc_nob(&prt->refc);
-#if DDLL_SMP
- /* Extremely rare spinlock */
- while(prt->status & ERTS_PORT_SFLG_INITIALIZING) {
- erts_smp_port_state_unlock(prt);
- erts_smp_port_state_lock(prt);
- }
- erts_smp_port_state_unlock(prt);
- erts_smp_mtx_lock(prt->lock);
- if (!(prt->status & ERTS_PORT_SFLGS_DEAD)) {
- driver_failure_atom(j, "driver_unloaded");
- }
-#else
- driver_failure_atom(j, "driver_unloaded");
-#endif
- erts_port_release(prt);
- }
- else erts_smp_port_state_unlock(prt);
- }
+ kill_ports_driver_unloaded(dh);
#if DDLL_SMP
lock_drv_list();
#endif
@@ -787,7 +772,7 @@ BIF_RETTYPE erl_ddll_info_2(BIF_ALIST_2)
} else if (drv->handle->status == ERL_DE_PERMANENT) {
res = am_permanent;
} else {
- res = make_small(drv->handle->port_count);
+ res = make_small(erts_smp_atomic32_read_nob(&drv->handle->port_count));
}
goto done;
case am_linked_in_driver:
@@ -1045,38 +1030,16 @@ void erts_ddll_proc_dead(Process *p, ErtsProcLocks plocks)
}
dh->status = ERL_DE_UNLOAD;
}
- if (!left && drv->handle->port_count > 0) {
+ if (!left
+ && erts_smp_atomic32_read_nob(&drv->handle->port_count) > 0) {
if (kill_ports) {
- int j;
DE_Handle *dh = drv->handle;
erts_ddll_reference_driver(dh);
dh->status = ERL_DE_FORCE_UNLOAD;
#if DDLL_SMP
unlock_drv_list();
#endif
- for (j = 0; j < erts_max_ports; j++) {
- Port* prt = &erts_port[j];
- erts_smp_port_state_lock(prt);
- if (!(prt->status & FREE_PORT_FLAGS) &&
- prt->drv_ptr->handle == dh) {
- erts_smp_atomic_inc_nob(&prt->refc);
-#if DDLL_SMP
- while(prt->status & ERTS_PORT_SFLG_INITIALIZING) {
- erts_smp_port_state_unlock(prt);
- erts_smp_port_state_lock(prt);
- }
- erts_smp_port_state_unlock(prt);
- erts_smp_mtx_lock(prt->lock);
- if (!(prt->status & ERTS_PORT_SFLGS_DEAD)) {
- driver_failure_atom(j, "driver_unloaded");
- }
-#else
- driver_failure_atom(j, "driver_unloaded");
-#endif
- erts_port_release(prt);
- }
- else erts_smp_port_state_unlock(prt);
- }
+ kill_ports_driver_unloaded(dh);
#if DDLL_SMP
lock_drv_list(); /* Needed for future list operations */
#endif
@@ -1098,7 +1061,7 @@ void erts_ddll_proc_dead(Process *p, ErtsProcLocks plocks)
void erts_ddll_lock_driver(DE_Handle *dh, char *name)
{
DE_ProcEntry *p,*q;
- assert_drv_list_locked();
+ assert_drv_list_rwlocked();
notify_all(dh, name,
ERL_DE_PROC_AWAIT_LOAD, am_UP, am_permanent);
notify_all(dh, name,
@@ -1121,19 +1084,22 @@ void erts_ddll_lock_driver(DE_Handle *dh, char *name)
void erts_ddll_increment_port_count(DE_Handle *dh)
{
assert_drv_list_locked();
- dh->port_count++;
+ erts_smp_atomic32_inc_nob(&dh->port_count);
}
void erts_ddll_decrement_port_count(DE_Handle *dh)
{
assert_drv_list_locked();
- ASSERT(dh->port_count > 0);
- dh->port_count--;
+#if DEBUG
+ ASSERT(erts_smp_atomic32_dec_read_nob(&dh->port_count) >= 0);
+#else
+ erts_smp_atomic32_dec_nob(&dh->port_count);
+#endif
}
static void first_ddll_reference(DE_Handle *dh)
{
- assert_drv_list_locked();
+ assert_drv_list_rwlocked();
erts_refc_init(&(dh->refc),1);
}
@@ -1161,7 +1127,7 @@ void erts_ddll_dereference_driver(DE_Handle *dh)
static void dereference_all_processes(DE_Handle *dh)
{
DE_ProcEntry *p;
- assert_drv_list_locked();
+ assert_drv_list_rwlocked();
for(p = dh->procs;p != NULL; p = p->next) {
if (p->awaiting_status == ERL_DE_PROC_LOADED) {
ASSERT(!(p->flags & ERL_DE_FL_DEREFERENCED));
@@ -1174,7 +1140,7 @@ static void dereference_all_processes(DE_Handle *dh)
static void restore_process_references(DE_Handle *dh)
{
DE_ProcEntry *p;
- assert_drv_list_locked();
+ assert_drv_list_rwlocked();
ASSERT(erts_refc_read(&(dh->refc),0) == 0);
for(p = dh->procs;p != NULL; p = p->next) {
if (p->awaiting_status == ERL_DE_PROC_LOADED) {
@@ -1402,7 +1368,7 @@ static int is_last_user(DE_Handle *dh, Process *proc) {
DE_ProcEntry *p = dh->procs;
int found = 0;
- assert_drv_list_locked();
+ assert_drv_list_rwlocked();
while (p != NULL) {
if (p->proc == proc && p->awaiting_status == ERL_DE_PROC_LOADED) {
@@ -1423,7 +1389,7 @@ static DE_ProcEntry *find_proc_entry(DE_Handle *dh, Process *proc, Uint status)
{
DE_ProcEntry *p = dh->procs;
- assert_drv_list_locked();
+ assert_drv_list_rwlocked();
while (p != NULL) {
if (p->proc == proc && p->awaiting_status == status) {
@@ -1450,7 +1416,7 @@ static int num_procs(DE_Handle *dh, Uint status) {
DE_ProcEntry *p = dh->procs;
int i = 0;
- assert_drv_list_locked();
+ assert_drv_list_rwlocked();
while (p != NULL) {
if (p->awaiting_status == status) {
@@ -1465,7 +1431,7 @@ static int num_entries(DE_Handle *dh, Process *proc, Uint status) {
DE_ProcEntry *p = dh->procs;
int i = 0;
- assert_drv_list_locked();
+ assert_drv_list_rwlocked();
while (p != NULL) {
if (p->awaiting_status == status && p->proc == proc) {
++i;
@@ -1478,7 +1444,7 @@ static int num_entries(DE_Handle *dh, Process *proc, Uint status) {
static void add_proc_loaded(DE_Handle *dh, Process *proc)
{
DE_ProcEntry *p;
- assert_drv_list_locked();
+ assert_drv_list_rwlocked();
p = erts_alloc(ERTS_ALC_T_DDLL_PROCESS, sizeof(DE_ProcEntry));
p->proc = proc;
p->flags = 0;
@@ -1490,7 +1456,7 @@ static void add_proc_loaded(DE_Handle *dh, Process *proc)
static void add_proc_loaded_deref(DE_Handle *dh, Process *proc)
{
DE_ProcEntry *p;
- assert_drv_list_locked();
+ assert_drv_list_rwlocked();
p = erts_alloc(ERTS_ALC_T_DDLL_PROCESS, sizeof(DE_ProcEntry));
p->proc = proc;
p->awaiting_status = ERL_DE_PROC_LOADED;
@@ -1510,7 +1476,7 @@ static void add_proc_waiting(DE_Handle *dh, Process *proc,
Uint status, Eterm ref)
{
DE_ProcEntry *p;
- assert_drv_list_locked();
+ assert_drv_list_rwlocked();
p = erts_alloc(ERTS_ALC_T_DDLL_PROCESS, sizeof(DE_ProcEntry));
p->proc = proc;
p->flags = 0;
@@ -1524,7 +1490,7 @@ static Eterm add_monitor(Process *p, DE_Handle *dh, Uint status)
{
Eterm r;
- assert_drv_list_locked();
+ assert_drv_list_rwlocked();
r = erts_make_ref(p);
add_proc_waiting(dh, p, status, r);
return r;
@@ -1535,7 +1501,7 @@ static void set_driver_reloading(DE_Handle *dh, Process *proc, char *path, char
{
DE_ProcEntry *p;
- assert_drv_list_locked();
+ assert_drv_list_rwlocked();
p = erts_alloc(ERTS_ALC_T_DDLL_PROCESS, sizeof(DE_ProcEntry));
p->proc = proc;
p->awaiting_status = ERL_DE_OK;
@@ -1556,7 +1522,7 @@ static int do_load_driver_entry(DE_Handle *dh, char *path, char *name)
int res;
ErlDrvEntry *dp;
- assert_drv_list_locked();
+ assert_drv_list_rwlocked();
if ((res = erts_sys_ddll_open(path, &(dh->handle))) != ERL_DE_NO_ERROR) {
return res;
@@ -1594,7 +1560,7 @@ static int do_load_driver_entry(DE_Handle *dh, char *path, char *name)
goto error;
}
erts_smp_atomic_init_nob(&(dh->refc), (erts_aint_t) 0);
- dh->port_count = 0;
+ erts_smp_atomic32_init_nob(&dh->port_count, 0);
dh->full_path = erts_alloc(ERTS_ALC_T_DDLL_HANDLE, sys_strlen(path) + 1);
sys_strcpy(dh->full_path, path);
dh->flags = 0;
@@ -1620,7 +1586,7 @@ static int do_unload_driver_entry(DE_Handle *dh, Eterm *save_name)
{
erts_driver_t *q, *p = driver_list;
- assert_drv_list_locked();
+ assert_drv_list_rwlocked();
while (p != NULL) {
if (p->handle == dh) {
@@ -1660,11 +1626,11 @@ static int load_driver_entry(DE_Handle **dhp, char *path, char *name)
int res;
DE_Handle *dh = erts_alloc(ERTS_ALC_T_DDLL_HANDLE, sizeof(DE_Handle));
- assert_drv_list_locked();
+ assert_drv_list_rwlocked();
dh->handle = NULL;
dh->procs = NULL;
- dh->port_count = 0;
+ erts_smp_atomic32_init_nob(&dh->port_count, 0);
erts_refc_init(&(dh->refc), (erts_aint_t) 0);
dh->status = -1;
dh->reload_full_path = NULL;
@@ -1698,7 +1664,7 @@ static int reload_driver_entry(DE_Handle *dh)
int loadres;
Uint flags = dh->reload_flags;
- assert_drv_list_locked();
+ assert_drv_list_rwlocked();
dh->reload_full_path = NULL;
dh->reload_driver_name = NULL;
@@ -1736,7 +1702,7 @@ static void notify_proc(Process *proc, Eterm ref, Eterm driver_name, Eterm type,
ErtsProcLocks rp_locks = 0;
ERTS_SMP_CHK_NO_PROC_LOCKS;
- assert_drv_list_locked();
+ assert_drv_list_rwlocked();
if (errcode != 0) {
int need = load_error_need(errcode);
Eterm e;
@@ -1769,7 +1735,7 @@ static void notify_all(DE_Handle *dh, char *name, Uint awaiting, Eterm type, Ete
{
DE_ProcEntry **p;
- assert_drv_list_locked();
+ assert_drv_list_rwlocked();
p = &(dh->procs);
while (*p != NULL) {
@@ -1875,7 +1841,7 @@ static Eterm mkatom(char *str)
static char *pick_list_or_atom(Eterm name_term)
{
char *name = NULL;
- Uint name_len;
+ ErlDrvSizeT name_len;
if (is_atom(name_term)) {
Atom *ap = atom_tab(atom_val(name_term));
if (ap->len == 0) {
@@ -1891,7 +1857,7 @@ static char *pick_list_or_atom(Eterm name_term)
goto error;
}
name = erts_alloc(ERTS_ALC_T_DDLL_TMP_BUF, name_len + 1);
- if (io_list_to_buf(name_term, name, name_len) != 0) {
+ if (erts_iolist_to_buf(name_term, name, name_len) != 0) {
goto error;
}
name[name_len] = '\0';
@@ -1912,10 +1878,10 @@ static int build_proc_info(DE_Handle *dh, ProcEntryInfo **out_pei, Uint filter)
int i;
DE_ProcEntry *pe;
- assert_drv_list_locked();
+ assert_drv_list_rwlocked();
for (pe = dh->procs; pe != NULL; pe = pe->next) {
- Eterm id = pe->proc->id;
+ Eterm id = pe->proc->common.id;
Uint stat = pe->awaiting_status;
if (stat == ERL_DE_PROC_AWAIT_UNLOAD_ONLY) {
stat = ERL_DE_PROC_AWAIT_UNLOAD;
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index a3811ccdb0..fabddffc68 100755
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -40,6 +40,8 @@
#include "erl_cpu_topology.h"
#include "erl_async.h"
#include "erl_thr_progress.h"
+#define ERTS_PTAB_WANT_DEBUG_FUNCS__
+#include "erl_ptab.h"
#ifdef HIPE
#include "hipe_arch.h"
#endif
@@ -128,8 +130,6 @@ static char erts_system_version[] = ("Erlang " ERLANG_OTP_RELEASE
static Eterm os_type_tuple;
static Eterm os_version_tuple;
-static BIF_RETTYPE port_info(Process* p, Eterm portid, Eterm item);
-
static Eterm
current_function(Process* p, Process* rp, Eterm** hpp, int full_info);
static Eterm current_stacktrace(Process* p, Process* rp, Eterm** hpp);
@@ -873,8 +873,7 @@ BIF_RETTYPE process_info_1(BIF_ALIST_1)
&& external_pid_dist_entry(BIF_ARG_1) == erts_this_dist_entry)
BIF_RET(am_undefined);
- if (is_not_internal_pid(BIF_ARG_1)
- || internal_pid_index(BIF_ARG_1) >= erts_max_processes) {
+ if (is_not_internal_pid(BIF_ARG_1)) {
BIF_ERROR(BIF_P, BADARG);
}
@@ -909,8 +908,7 @@ BIF_RETTYPE process_info_2(BIF_ALIST_2)
&& external_pid_dist_entry(pid) == erts_this_dist_entry)
BIF_RET(am_undefined);
- if (is_not_internal_pid(pid)
- || internal_pid_index(BIF_ARG_1) >= erts_max_processes) {
+ if (is_not_internal_pid(pid)) {
BIF_ERROR(BIF_P, BADARG);
}
@@ -1002,9 +1000,9 @@ process_info_aux(Process *BIF_P,
switch (item) {
case am_registered_name:
- if (rp->reg != NULL) {
+ if (rp->common.u.alive.reg) {
hp = HAlloc(BIF_P, 3);
- res = rp->reg->name;
+ res = rp->common.u.alive.reg->name;
} else {
if (always_wrap) {
hp = HAlloc(BIF_P, 3);
@@ -1050,7 +1048,7 @@ process_info_aux(Process *BIF_P,
ERTS_SMP_MSGQ_MV_INQ2PRIVQ(rp);
n = rp->msg.len;
- if (n == 0 || rp->trace_flags & F_SENSITIVE) {
+ if (n == 0 || ERTS_TRACE_FLAGS(rp) & F_SENSITIVE) {
hp = HAlloc(BIF_P, 3);
} else {
int remove_bad_messages = 0;
@@ -1209,7 +1207,7 @@ process_info_aux(Process *BIF_P,
INIT_MONITOR_INFOS(mic);
- erts_doforall_links(rp->nlinks,&collect_one_link,&mic);
+ erts_doforall_links(ERTS_P_LINKS(rp),&collect_one_link,&mic);
hp = HAlloc(BIF_P, 3 + mic.sz);
res = NIL;
@@ -1227,7 +1225,7 @@ process_info_aux(Process *BIF_P,
int i;
INIT_MONITOR_INFOS(mic);
- erts_doforall_monitors(rp->monitors,&collect_one_origin_monitor,&mic);
+ erts_doforall_monitors(ERTS_P_MONITORS(rp),&collect_one_origin_monitor,&mic);
hp = HAlloc(BIF_P, 3 + mic.sz);
res = NIL;
for (i = 0; i < mic.mi_i; i++) {
@@ -1264,7 +1262,7 @@ process_info_aux(Process *BIF_P,
Eterm item;
INIT_MONITOR_INFOS(mic);
- erts_doforall_monitors(rp->monitors,&collect_one_target_monitor,&mic);
+ erts_doforall_monitors(ERTS_P_MONITORS(rp),&collect_one_target_monitor,&mic);
hp = HAlloc(BIF_P, 3 + mic.sz);
res = NIL;
@@ -1330,7 +1328,7 @@ process_info_aux(Process *BIF_P,
}
case am_dictionary:
- if (rp->trace_flags & F_SENSITIVE) {
+ if (ERTS_TRACE_FLAGS(rp) & F_SENSITIVE) {
res = NIL;
} else {
res = erts_dictionary_copy(BIF_P, rp->dictionary);
@@ -1426,8 +1424,8 @@ process_info_aux(Process *BIF_P,
ERTS_SMP_MSGQ_MV_INQ2PRIVQ(rp);
- erts_doforall_links(rp->nlinks, &one_link_size, &size);
- erts_doforall_monitors(rp->monitors, &one_mon_size, &size);
+ erts_doforall_links(ERTS_P_LINKS(rp), &one_link_size, &size);
+ erts_doforall_monitors(ERTS_P_MONITORS(rp), &one_mon_size, &size);
size += (rp->heap_sz + rp->mbuf_sz) * sizeof(Eterm);
if (rp->old_hend && rp->old_heap)
size += (rp->old_hend - rp->old_heap) * sizeof(Eterm);
@@ -1500,7 +1498,7 @@ process_info_aux(Process *BIF_P,
case am_trace:
hp = HAlloc(BIF_P, 3);
- res = make_small(rp->trace_flags & TRACEE_FLAGS);
+ res = make_small(ERTS_TRACE_FLAGS(rp) & TRACEE_FLAGS);
break;
case am_binary: {
@@ -1605,7 +1603,7 @@ current_function(Process* BIF_P, Process* rp, Eterm** hpp, int full_info)
}
}
- if (BIF_P->id == rp->id) {
+ if (BIF_P == rp) {
FunctionInfo fi2;
/*
@@ -1837,17 +1835,17 @@ info_1_tuple(Process* BIF_P, /* Pointer to current process. */
# define ERTS_ERROR_CHECKER_PRINTF_XML VALGRIND_PRINTF_XML
# endif
#endif
- Uint buf_size = 8*1024; /* Try with 8KB first */
+ ErlDrvSizeT buf_size = 8*1024; /* Try with 8KB first */
char *buf = erts_alloc(ERTS_ALC_T_TMP, buf_size);
- int r = io_list_to_buf(*tp, (char*) buf, buf_size - 1);
- if (r < 0) {
+ ErlDrvSizeT r = erts_iolist_to_buf(*tp, (char*) buf, buf_size - 1);
+ if (ERTS_IOLIST_TO_BUF_FAILED(r)) {
erts_free(ERTS_ALC_T_TMP, (void *) buf);
if (erts_iolist_size(*tp, &buf_size)) {
goto badarg;
}
buf_size++;
buf = erts_alloc(ERTS_ALC_T_TMP, buf_size);
- r = io_list_to_buf(*tp, (char*) buf, buf_size - 1);
+ r = erts_iolist_to_buf(*tp, (char*) buf, buf_size - 1);
ASSERT(r == buf_size - 1);
}
buf[buf_size - 1 - r] = '\0';
@@ -2159,9 +2157,13 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1)
res = TUPLE2(hp, am_min_bin_vheap_size,make_small(BIN_VH_MIN_SIZE));
BIF_RET(res);
} else if (BIF_ARG_1 == am_process_count) {
- BIF_RET(make_small(erts_process_count()));
+ BIF_RET(make_small(erts_ptab_count(&erts_proc)));
} else if (BIF_ARG_1 == am_process_limit) {
- BIF_RET(make_small(erts_max_processes));
+ BIF_RET(make_small(erts_ptab_max(&erts_proc)));
+ } else if (BIF_ARG_1 == am_port_count) {
+ BIF_RET(make_small(erts_ptab_count(&erts_port)));
+ } else if (BIF_ARG_1 == am_port_limit) {
+ BIF_RET(make_small(erts_ptab_max(&erts_port)));
} else if (BIF_ARG_1 == am_info
|| BIF_ARG_1 == am_procs
|| BIF_ARG_1 == am_loaded
@@ -2534,6 +2536,9 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1)
} else if (ERTS_IS_ATOM_STR("run_queues", BIF_ARG_1)) {
res = make_small(erts_no_run_queues);
BIF_RET(res);
+ } else if (ERTS_IS_ATOM_STR("port_parallelism", BIF_ARG_1)) {
+ res = erts_port_parallelism ? am_true : am_false;
+ BIF_RET(res);
} else if (ERTS_IS_ATOM_STR("c_compiler_used", BIF_ARG_1)) {
Eterm *hp = NULL;
Uint sz = 0;
@@ -2701,66 +2706,6 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1)
BIF_ERROR(BIF_P, BADARG);
}
-BIF_RETTYPE
-port_info_1(BIF_ALIST_1)
-{
- Process* p = BIF_P;
- Eterm pid = BIF_ARG_1;
- static Eterm keys[] = {
- am_name,
- am_links,
- am_id,
- am_connected,
- am_input,
- am_output,
- am_os_pid
- };
- Eterm items[ASIZE(keys)];
- Eterm result = NIL;
- Eterm reg_name;
- Eterm* hp;
- Uint need;
- int i;
-
- /*
- * Collect all information about the port.
- */
-
- for (i = 0; i < ASIZE(keys); i++) {
- Eterm item;
-
- item = port_info(p, pid, keys[i]);
- if (is_non_value(item)) {
- return THE_NON_VALUE;
- }
- if (item == am_undefined) {
- return am_undefined;
- }
- items[i] = item;
- }
- reg_name = port_info(p, pid, am_registered_name);
-
- /*
- * Build the resulting list.
- */
-
- need = 2*ASIZE(keys);
- if (is_tuple(reg_name)) {
- need += 2;
- }
- hp = HAlloc(p, need);
- for (i = ASIZE(keys) - 1; i >= 0; i--) {
- result = CONS(hp, items[i], result);
- hp += 2;
- }
- if (is_tuple(reg_name)) {
- result = CONS(hp, reg_name, result);
- }
-
- return result;
-}
-
-
/**********************************************************************/
/* Return information on ports */
/* Info:
@@ -2773,38 +2718,20 @@ port_info_1(BIF_ALIST_1)
** os_pid The child's process ID
*/
-BIF_RETTYPE port_info_2(BIF_ALIST_2)
-{
- return port_info(BIF_P, BIF_ARG_1, BIF_ARG_2);
-}
-
-static BIF_RETTYPE port_info(Process* p, Eterm portid, Eterm item)
+Eterm
+erts_bld_port_info(Eterm **hpp, ErlOffHeap *ohp, Uint *szp, Port *prt, Eterm item)
{
- BIF_RETTYPE ret;
- Port *prt;
- Eterm res;
- Eterm* hp;
- int count;
-
- if (is_internal_port(portid))
- prt = erts_id2port(portid, p, ERTS_PROC_LOCK_MAIN);
- else if (is_atom(portid))
- erts_whereis_name(p, ERTS_PROC_LOCK_MAIN,
- portid, NULL, 0, 0, &prt);
- else if (is_external_port(portid)
- && external_port_dist_entry(portid) == erts_this_dist_entry)
- BIF_RET(am_undefined);
- else {
- BIF_ERROR(p, BADARG);
- }
+ Eterm res = THE_NON_VALUE;
- if (!prt) {
- BIF_RET(am_undefined);
- }
+ ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
if (item == am_id) {
- hp = HAlloc(p, 3);
- res = make_small(internal_port_number(portid));
+ if (hpp)
+ res = make_small(internal_port_index(prt->common.id));
+ if (szp) {
+ res = am_true;
+ goto done;
+ }
}
else if (item == am_links) {
MonitorInfoCollection mic;
@@ -2813,17 +2740,26 @@ static BIF_RETTYPE port_info(Process* p, Eterm portid, Eterm item)
INIT_MONITOR_INFOS(mic);
- erts_doforall_links(prt->nlinks, &collect_one_link, &mic);
+ erts_doforall_links(ERTS_P_LINKS(prt), &collect_one_link, &mic);
- hp = HAlloc(p, 3 + mic.sz);
- res = NIL;
- for (i = 0; i < mic.mi_i; i++) {
- item = STORE_NC(&hp, &MSO(p), mic.mi[i].entity);
- res = CONS(hp, item, res);
- hp += 2;
+ if (szp)
+ *szp += mic.sz;
+
+ if (hpp) {
+ res = NIL;
+ for (i = 0; i < mic.mi_i; i++) {
+ item = STORE_NC(hpp, ohp, mic.mi[i].entity);
+ res = CONS(*hpp, item, res);
+ *hpp += 2;
+ }
}
+
DESTROY_MONITOR_INFOS(mic);
+ if (szp) {
+ res = am_true;
+ goto done;
+ }
}
else if (item == am_monitors) {
MonitorInfoCollection mic;
@@ -2832,79 +2768,96 @@ static BIF_RETTYPE port_info(Process* p, Eterm portid, Eterm item)
INIT_MONITOR_INFOS(mic);
- erts_doforall_monitors(prt->monitors, &collect_one_origin_monitor, &mic);
+ erts_doforall_monitors(ERTS_P_MONITORS(prt), &collect_one_origin_monitor, &mic);
- hp = HAlloc(p, 3 + mic.sz);
- res = NIL;
- for (i = 0; i < mic.mi_i; i++) {
- Eterm t;
- item = STORE_NC(&hp, &MSO(p), mic.mi[i].entity);
- t = TUPLE2(hp, am_process, item);
- hp += 3;
- res = CONS(hp, t, res);
- hp += 2;
+ if (szp)
+ *szp += mic.sz;
+
+ if (hpp) {
+ res = NIL;
+ for (i = 0; i < mic.mi_i; i++) {
+ Eterm t;
+ item = STORE_NC(hpp, ohp, mic.mi[i].entity);
+ t = TUPLE2(*hpp, am_process, item);
+ *hpp += 3;
+ res = CONS(*hpp, t, res);
+ *hpp += 2;
+ }
}
+
DESTROY_MONITOR_INFOS(mic);
+ if (szp) {
+ res = am_true;
+ goto done;
+ }
}
else if (item == am_name) {
- count = sys_strlen(prt->name);
+ int count = sys_strlen(prt->name);
+
+ if (hpp)
+ res = buf_to_intlist(hpp, prt->name, count, NIL);
- hp = HAlloc(p, 3 + 2*count);
- res = buf_to_intlist(&hp, prt->name, count, NIL);
+ if (szp) {
+ *szp += 2*count;
+ res = am_true;
+ goto done;
+ }
}
else if (item == am_connected) {
- hp = HAlloc(p, 3);
- res = prt->connected; /* internal pid */
+ if (hpp)
+ res = ERTS_PORT_GET_CONNECTED(prt); /* internal pid */
+ if (szp) {
+ res = am_true;
+ goto done;
+ }
}
else if (item == am_input) {
- Uint hsz = 3;
- Uint n = prt->bytes_in;
- (void) erts_bld_uint(NULL, &hsz, n);
- hp = HAlloc(p, hsz);
- res = erts_bld_uint(&hp, NULL, n);
+ res = erts_bld_uint(hpp, szp, prt->bytes_in);
+ if (szp) {
+ res = am_true;
+ goto done;
+ }
}
else if (item == am_output) {
- Uint hsz = 3;
- Uint n = prt->bytes_out;
- (void) erts_bld_uint(NULL, &hsz, n);
- hp = HAlloc(p, hsz);
- res = erts_bld_uint(&hp, NULL, n);
+ res = erts_bld_uint(hpp, szp, prt->bytes_out);
+ if (szp) {
+ res = am_true;
+ goto done;
+ }
}
else if (item == am_os_pid) {
- if (prt->os_pid >= 0) {
- Uint hsz = 3;
- UWord n = prt->os_pid;
- (void) erts_bld_uword(NULL, &hsz, n);
- hp = HAlloc(p, hsz);
- res = erts_bld_uword(&hp, NULL, n);
- } else {
- hp = HAlloc(p, 3);
- res = am_undefined;
- }
+ res = (prt->os_pid < 0
+ ? am_undefined
+ : erts_bld_uword(hpp, szp, (UWord) prt->os_pid));
+ if (szp) {
+ res = am_true;
+ goto done;
+ }
}
else if (item == am_registered_name) {
- RegProc *reg;
- reg = prt->reg;
- if (reg == NULL) {
- ERTS_BIF_PREP_RET(ret, NIL);
- goto done;
- } else {
- hp = HAlloc(p, 3);
+ RegProc *reg = prt->common.u.alive.reg;
+ if (reg) {
res = reg->name;
+ if (szp) {
+ res = am_true;
+ goto done;
+ }
+ }
+ else {
+ if (szp)
+ return am_undefined;
+ return NIL;
}
}
else if (item == am_memory) {
/* All memory consumed in bytes (the Port struct should not be
included though).
*/
- Uint hsz = 3;
Uint size = 0;
ErlHeapFragment* bp;
- hp = HAlloc(p, 3);
-
- erts_doforall_links(prt->nlinks, &one_link_size, &size);
+ erts_doforall_links(ERTS_P_LINKS(prt), &one_link_size, &size);
for (bp = prt->bp; bp; bp = bp->next)
size += sizeof(ErlHeapFragment) + (bp->alloc_size - 1)*sizeof(Eterm);
@@ -2918,51 +2871,72 @@ static BIF_RETTYPE port_info(Process* p, Eterm portid, Eterm item)
/* All memory allocated by the driver should be included, but it is
hard to retrieve... */
- (void) erts_bld_uint(NULL, &hsz, size);
- hp = HAlloc(p, hsz);
- res = erts_bld_uint(&hp, NULL, size);
+ res = erts_bld_uint(hpp, szp, size);
+ if (szp) {
+ res = am_true;
+ goto done;
+ }
}
else if (item == am_queue_size) {
Uint ioq_size = erts_port_ioq_size(prt);
- Uint hsz = 3;
- (void) erts_bld_uint(NULL, &hsz, ioq_size);
- hp = HAlloc(p, hsz);
- res = erts_bld_uint(&hp, NULL, ioq_size);
+ res = erts_bld_uint(hpp, szp, ioq_size);
+ if (szp) {
+ res = am_true;
+ goto done;
+ }
}
else if (ERTS_IS_ATOM_STR("locking", item)) {
- hp = HAlloc(p, 3);
+ if (hpp) {
#ifndef ERTS_SMP
- res = am_false;
+ res = am_false;
#else
- if (prt->status & ERTS_PORT_SFLG_PORT_SPECIFIC_LOCK) {
- DECL_AM(port_level);
- ASSERT(prt->drv_ptr->flags
- & ERL_DRV_FLAG_USE_PORT_LOCKING);
- res = AM_port_level;
+ if (erts_atomic32_read_nob(&prt->state)
+ & ERTS_PORT_SFLG_PORT_SPECIFIC_LOCK) {
+ DECL_AM(port_level);
+ ASSERT(prt->drv_ptr->flags
+ & ERL_DRV_FLAG_USE_PORT_LOCKING);
+ res = AM_port_level;
+ }
+ else {
+ DECL_AM(driver_level);
+ ASSERT(!(prt->drv_ptr->flags
+ & ERL_DRV_FLAG_USE_PORT_LOCKING));
+ res = AM_driver_level;
+ }
+#endif
}
- else {
- DECL_AM(driver_level);
- ASSERT(!(prt->drv_ptr->flags
- & ERL_DRV_FLAG_USE_PORT_LOCKING));
- res = AM_driver_level;
+ if (szp) {
+ res = am_true;
+ goto done;
}
-#endif
+ }
+ else if (item == am_parallelism) {
+ if (szp) {
+ res = am_true;
+ goto done;
+ }
+ res = ((ERTS_PTS_FLG_PARALLELISM &
+ erts_smp_atomic32_read_nob(&prt->sched.flags))
+ ? am_true
+ : am_false);
}
else {
- ERTS_BIF_PREP_ERROR(ret, p, BADARG);
- goto done;
+ if (szp)
+ return am_false;
+ return THE_NON_VALUE;
}
- ERTS_BIF_PREP_RET(ret, TUPLE2(hp, item, res));
-
- done:
-
- erts_smp_port_unlock(prt);
+done:
+ if (szp)
+ *szp += 3;
+ if (hpp) {
+ res = TUPLE2(*hpp, item, res);
+ *hpp += 3;
+ }
- return ret;
+ return res;
}
-
BIF_RETTYPE
fun_info_2(BIF_ALIST_2)
{
@@ -3094,12 +3068,9 @@ BIF_RETTYPE is_process_alive_1(BIF_ALIST_1)
if(is_internal_pid(BIF_ARG_1)) {
Process *rp;
- if (BIF_ARG_1 == BIF_P->id)
+ if (BIF_ARG_1 == BIF_P->common.id)
BIF_RET(am_true);
- if(internal_pid_index(BIF_ARG_1) >= erts_max_processes)
- BIF_ERROR(BIF_P, BADARG);
-
rp = erts_proc_lookup(BIF_ARG_1);
if (!rp) {
BIF_RET(am_false);
@@ -3317,10 +3288,9 @@ BIF_RETTYPE erts_debug_get_internal_state_1(BIF_ALIST_1)
/* Used by node_container_SUITE (emulator) */
Eterm res;
if (ERTS_IS_ATOM_STR("next_pid", BIF_ARG_1))
- res = erts_test_next_pid(0, 0);
- else {
- res = erts_test_next_port(0, 0);
- }
+ res = erts_ptab_test_next_id(&erts_proc, 0, 0);
+ else
+ res = erts_ptab_test_next_id(&erts_port, 0, 0);
if (res < 0)
BIF_RET(am_false);
BIF_RET(erts_make_integer(res, BIF_P));
@@ -3356,11 +3326,11 @@ BIF_RETTYPE erts_debug_get_internal_state_1(BIF_ALIST_1)
}
else if (ERTS_IS_ATOM_STR("processes", BIF_ARG_1)) {
/* Used by process_SUITE (emulator) */
- BIF_RET(erts_debug_processes(BIF_P));
+ BIF_RET(erts_debug_ptab_list(BIF_P, &erts_proc));
}
else if (ERTS_IS_ATOM_STR("processes_bif_info", BIF_ARG_1)) {
/* Used by process_SUITE (emulator) */
- BIF_RET(erts_debug_processes_bif_info(BIF_P));
+ BIF_RET(erts_debug_ptab_list_bif_info(BIF_P, &erts_proc));
}
else if (ERTS_IS_ATOM_STR("max_atom_out_cache_index", BIF_ARG_1)) {
/* Used by distribution_SUITE (emulator) */
@@ -3421,17 +3391,20 @@ BIF_RETTYPE erts_debug_get_internal_state_1(BIF_ALIST_1)
ERTS_SMP_ASSERT_IS_NOT_EXITING(BIF_P);
BIF_RET(am_undefined);
}
- res = make_link_list(BIF_P, p->nlinks, NIL);
+ res = make_link_list(BIF_P, ERTS_P_LINKS(p), NIL);
erts_smp_proc_unlock(p, ERTS_PROC_LOCK_LINK);
BIF_RET(res);
}
else if(is_internal_port(tp[2])) {
Eterm res;
- Port *p = erts_id2port(tp[2], BIF_P, ERTS_PROC_LOCK_MAIN);
+ Port *p = erts_id2port_sflgs(tp[2],
+ BIF_P,
+ ERTS_PROC_LOCK_MAIN,
+ ERTS_PORT_SFLGS_INVALID_LOOKUP);
if(!p)
BIF_RET(am_undefined);
- res = make_link_list(BIF_P, p->nlinks, NIL);
- erts_smp_port_unlock(p);
+ res = make_link_list(BIF_P, ERTS_P_LINKS(p), NIL);
+ erts_port_release(p);
BIF_RET(res);
}
else if(is_node_name_atom(tp[2])) {
@@ -3463,7 +3436,7 @@ BIF_RETTYPE erts_debug_get_internal_state_1(BIF_ALIST_1)
ERTS_SMP_ASSERT_IS_NOT_EXITING(BIF_P);
BIF_RET(am_undefined);
}
- res = make_monitor_list(BIF_P, p->monitors);
+ res = make_monitor_list(BIF_P, ERTS_P_MONITORS(p));
erts_smp_proc_unlock(p, ERTS_PROC_LOCK_LINK);
BIF_RET(res);
} else if(is_node_name_atom(tp[2])) {
@@ -3606,7 +3579,7 @@ BIF_RETTYPE erts_debug_set_internal_state_2(BIF_ALIST_2)
erts_aint_t prev_on = erts_smp_atomic_xchg_nob(&available_internal_state, on);
if (on) {
erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
- erts_dsprintf(dsbufp, "Process %T ", BIF_P->id);
+ erts_dsprintf(dsbufp, "Process %T ", BIF_P->common.id);
if (erts_is_alive)
erts_dsprintf(dsbufp, "on node %T ", erts_this_node->sysname);
erts_dsprintf(dsbufp,
@@ -3674,10 +3647,9 @@ BIF_RETTYPE erts_debug_set_internal_state_2(BIF_ALIST_2)
Eterm res;
if (ERTS_IS_ATOM_STR("next_pid", BIF_ARG_1))
- res = erts_test_next_pid(1, next);
- else {
- res = erts_test_next_port(1, next);
- }
+ res = erts_ptab_test_next_id(&erts_proc, 1, next);
+ else
+ res = erts_ptab_test_next_id(&erts_port, 1, next);
if (res < 0)
BIF_RET(am_false);
BIF_RET(erts_make_integer(res, BIF_P));
@@ -3948,8 +3920,8 @@ static Eterm lcnt_build_lock_term(Eterm **hpp, Uint *szp, erts_lcnt_lock_t *lock
} else if (lock->flag & ERTS_LCNT_LT_PROCLOCK) {
/* use registered names as id's for process locks if available */
proc = erts_proc_lookup(lock->id);
- if (proc && proc->reg) {
- id = proc->reg->name;
+ if (proc && proc->common.u.alive.reg) {
+ id = proc->common.u.alive.reg->name;
} else {
/* otherwise use process id */
id = lock->id;
diff --git a/erts/emulator/beam/erl_bif_op.c b/erts/emulator/beam/erl_bif_op.c
index 13f8b1f63c..d4cd9c89b3 100644
--- a/erts/emulator/beam/erl_bif_op.c
+++ b/erts/emulator/beam/erl_bif_op.c
@@ -261,11 +261,6 @@ Eterm erl_is_function(Process* p, Eterm arg1, Eterm arg2)
if (exp->code[2] == (Uint) arity) {
BIF_RET(am_true);
}
- } else if (is_tuple(arg1)) {
- Eterm* tp = tuple_val(arg1);
- if (tp[0] == make_arityval(2) && is_atom(tp[1]) && is_atom(tp[2])) {
- BIF_RET(am_true);
- }
}
BIF_RET(am_false);
}
diff --git a/erts/emulator/beam/erl_bif_port.c b/erts/emulator/beam/erl_bif_port.c
index f9009166c0..81146e38d7 100644
--- a/erts/emulator/beam/erl_bif_port.c
+++ b/erts/emulator/beam/erl_bif_port.c
@@ -42,28 +42,26 @@
#include "erl_bits.h"
#include "dtrace-wrapper.h"
-static int open_port(Process* p, Eterm name, Eterm settings, int *err_nump);
+static Port *open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump);
static byte* convert_environment(Process* p, Eterm env);
static char **convert_args(Eterm);
static void free_args(char **);
char *erts_default_arg0 = "default";
-static BIF_RETTYPE
-port_call(Process* p, Eterm arg1, Eterm arg2, Eterm arg3);
-
BIF_RETTYPE open_port_2(BIF_ALIST_2)
{
- int port_num;
- Eterm port_val;
+ Port *port;
+ Eterm port_id;
char *str;
- int err_num;
+ int err_type, err_num;
- if ((port_num = open_port(BIF_P, BIF_ARG_1, BIF_ARG_2, &err_num)) < 0) {
- if (port_num == -3) {
+ port = open_port(BIF_P, BIF_ARG_1, BIF_ARG_2, &err_type, &err_num);
+ if (!port) {
+ if (err_type == -3) {
ASSERT(err_num == BADARG || err_num == SYSTEM_LIMIT);
BIF_ERROR(BIF_P, err_num);
- } else if (port_num == -2) {
+ } else if (err_type == -2) {
str = erl_errno_id(err_num);
} else {
str = "einval";
@@ -74,546 +72,408 @@ BIF_RETTYPE open_port_2(BIF_ALIST_2)
erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_LINK);
- port_val = erts_port[port_num].id;
- erts_add_link(&(erts_port[port_num].nlinks), LINK_PID, BIF_P->id);
- erts_add_link(&(BIF_P->nlinks), LINK_PID, port_val);
+ port_id = port->common.id;
+ erts_add_link(&ERTS_P_LINKS(port), LINK_PID, BIF_P->common.id);
+ erts_add_link(&ERTS_P_LINKS(BIF_P), LINK_PID, port_id);
erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_LINK);
- erts_port_release(&erts_port[port_num]);
+ erts_port_release(port);
- BIF_RET(port_val);
+ BIF_RET(port_id);
}
-/****************************************************************************
-
- PORT BIFS:
-
- port_command/2 -- replace Port ! {..., {command, Data}}
- port_command(Port, Data) -> true
- when port(Port), io-list(Data)
-
- port_control/3 -- new port_control(Port, Ctl, Data) -> Reply
- port_control(Port, Ctl, Data) -> Reply
- where integer(Ctl), io-list(Data), io-list(Reply)
-
- port_close/1 -- replace Port ! {..., close}
- port_close(Port) -> true
- when port(Port)
-
- port_connect/2 -- replace Port ! {..., {connect, Pid}}
- port_connect(Port, Pid)
- when port(Port), pid(Pid)
-
- ***************************************************************************/
-
-static Port*
-id_or_name2port(Process *c_p, Eterm id)
+static ERTS_INLINE Port *
+lookup_port(Process *c_p, Eterm id_or_name)
{
- Port *port;
- if (is_not_atom(id))
- port = erts_id2port(id, c_p, ERTS_PROC_LOCK_MAIN);
+ /* TODO: Implement nicer lookup in register... */
+ Eterm id;
+ if (is_atom(id_or_name))
+ id = erts_whereis_name_to_id(c_p, id_or_name);
else
- erts_whereis_name(c_p, ERTS_PROC_LOCK_MAIN, id, NULL, 0, 0, &port);
- return port;
+ id = id_or_name;
+ return erts_port_lookup(id, ERTS_PORT_SFLGS_INVALID_LOOKUP);
}
-#define ERTS_PORT_COMMAND_FLAG_FORCE (((Uint32) 1) << 0)
-#define ERTS_PORT_COMMAND_FLAG_NOSUSPEND (((Uint32) 1) << 1)
+/*
+ * erts_internal:port_command/3 is used by the
+ * erlang:port_command/2 and erlang:port_command/3
+ * BIFs.
+ */
-static BIF_RETTYPE
-do_port_command(Process *BIF_P, Eterm arg1, Eterm arg2, Eterm arg3,
- Uint32 flags)
+BIF_RETTYPE erts_internal_port_command_3(BIF_ALIST_3)
{
BIF_RETTYPE res;
- Port *p;
-
- /* Trace sched out before lock check wait */
- if (IS_TRACED_FL(BIF_P, F_TRACE_SCHED_PROCS)) {
- trace_virtual_sched(BIF_P, am_out);
- }
-
- if (erts_system_profile_flags.runnable_procs && erts_system_profile_flags.exclusive) {
- profile_runnable_proc(BIF_P, am_inactive);
- }
-
- p = id_or_name2port(BIF_P, arg1);
- if (!p) {
- if (IS_TRACED_FL(BIF_P, F_TRACE_SCHED_PROCS)) {
- trace_virtual_sched(BIF_P, am_in);
+ Port *prt;
+ int flags = 0;
+ Eterm ref;
+
+ if (is_not_nil(BIF_ARG_3)) {
+ Eterm l = BIF_ARG_3;
+ while (is_list(l)) {
+ Eterm* cons = list_val(l);
+ Eterm car = CAR(cons);
+ if (car == am_force)
+ flags |= ERTS_PORT_SIG_FLG_FORCE;
+ else if (car == am_nosuspend)
+ flags |= ERTS_PORT_SIG_FLG_NOSUSPEND;
+ else
+ BIF_RET(am_badarg);
+ l = CDR(cons);
}
- if (erts_system_profile_flags.runnable_procs && erts_system_profile_flags.exclusive) {
- profile_runnable_proc(BIF_P, am_active);
- }
- BIF_ERROR(BIF_P, BADARG);
+ if (!is_nil(l))
+ BIF_RET(am_badarg);
}
-
- /* Trace port in, id_or_name2port causes wait */
- if (IS_TRACED_FL(p, F_TRACE_SCHED_PORTS)) {
- trace_sched_ports_where(p, am_in, am_command);
- }
- if (erts_system_profile_flags.runnable_ports && !erts_port_is_scheduled(p)) {
- profile_runnable_port(p, am_active);
+ prt = lookup_port(BIF_P, BIF_ARG_1);
+ if (!prt)
+ BIF_RET(am_badarg);
+
+ if (flags & ERTS_PORT_SIG_FLG_FORCE) {
+ if (!(prt->drv_ptr->flags & ERL_DRV_FLAG_SOFT_BUSY))
+ BIF_RET(am_notsup);
}
- ERTS_BIF_PREP_RET(res, am_true);
+#ifdef DEBUG
+ ref = NIL;
+#endif
- if ((flags & ERTS_PORT_COMMAND_FLAG_FORCE)
- && !(p->drv_ptr->flags & ERL_DRV_FLAG_SOFT_BUSY)) {
- ERTS_BIF_PREP_ERROR(res, BIF_P, EXC_NOTSUP);
- }
- else if (!(flags & ERTS_PORT_COMMAND_FLAG_FORCE)
- && p->status & ERTS_PORT_SFLG_PORT_BUSY) {
- if (flags & ERTS_PORT_COMMAND_FLAG_NOSUSPEND) {
+ switch (erts_port_output(BIF_P, flags, prt, prt->common.id, BIF_ARG_2, &ref)) {
+ case ERTS_PORT_OP_CALLER_EXIT:
+ case ERTS_PORT_OP_BADARG:
+ case ERTS_PORT_OP_DROPPED:
+ ERTS_BIF_PREP_RET(res, am_badarg);
+ break;
+ case ERTS_PORT_OP_BUSY:
+ ASSERT(!(flags & ERTS_PORT_SIG_FLG_FORCE));
+ if (flags & ERTS_PORT_SIG_FLG_NOSUSPEND)
ERTS_BIF_PREP_RET(res, am_false);
- }
else {
- erts_suspend(BIF_P, ERTS_PROC_LOCK_MAIN, p);
- if (erts_system_monitor_flags.busy_port) {
- monitor_generic(BIF_P, am_busy_port, p->id);
- }
- ERTS_BIF_PREP_YIELD3(res, bif_export[BIF_port_command_3], BIF_P,
- arg1, arg2, arg3);
- }
- } else {
- int wres;
- erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
- ERTS_SMP_CHK_NO_PROC_LOCKS;
- wres = erts_write_to_port(BIF_P->id, p, arg2);
- erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
- if (wres != 0) {
- ERTS_BIF_PREP_ERROR(res, BIF_P, BADARG);
+ erts_suspend(BIF_P, ERTS_PROC_LOCK_MAIN, prt);
+ ERTS_BIF_PREP_YIELD3(res, bif_export[BIF_erts_internal_port_command_3],
+ BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3);
}
- }
-
- if (IS_TRACED_FL(p, F_TRACE_SCHED_PORTS)) {
- trace_sched_ports_where(p, am_out, am_command);
- }
- if (erts_system_profile_flags.runnable_ports && !erts_port_is_scheduled(p)) {
- profile_runnable_port(p, am_inactive);
+ break;
+ case ERTS_PORT_OP_BUSY_SCHEDULED:
+ ASSERT(!(flags & ERTS_PORT_SIG_FLG_FORCE));
+ /* Fall through... */
+ case ERTS_PORT_OP_SCHEDULED:
+ ASSERT(is_internal_ref(ref));
+ ERTS_BIF_PREP_RET(res, ref);
+ break;
+ case ERTS_PORT_OP_DONE:
+ ERTS_BIF_PREP_RET(res, am_true);
+ break;
+ default:
+ ERTS_INTERNAL_ERROR("Unexpected erts_port_output() result");
+ break;
}
- erts_port_release(p);
- /* Trace sched in after port release */
- if (IS_TRACED_FL(BIF_P, F_TRACE_SCHED_PROCS)) {
- trace_virtual_sched(BIF_P, am_in);
- }
- if (erts_system_profile_flags.runnable_procs && erts_system_profile_flags.exclusive) {
- profile_runnable_proc(BIF_P, am_active);
- }
-
if (ERTS_PROC_IS_EXITING(BIF_P)) {
KILL_CATCHES(BIF_P); /* Must exit */
ERTS_BIF_PREP_ERROR(res, BIF_P, EXC_ERROR);
}
- return res;
-}
-BIF_RETTYPE port_command_2(BIF_ALIST_2)
-{
- return do_port_command(BIF_P, BIF_ARG_1, BIF_ARG_2, NIL, 0);
+ return res;
}
-BIF_RETTYPE port_command_3(BIF_ALIST_3)
+BIF_RETTYPE erts_internal_port_call_3(BIF_ALIST_3)
{
- Eterm l = BIF_ARG_3;
- Uint32 flags = 0;
- while (is_list(l)) {
- Eterm* cons = list_val(l);
- Eterm car = CAR(cons);
- if (car == am_force) {
- flags |= ERTS_PORT_COMMAND_FLAG_FORCE;
- } else if (car == am_nosuspend) {
- flags |= ERTS_PORT_COMMAND_FLAG_NOSUSPEND;
- } else {
- BIF_ERROR(BIF_P, BADARG);
- }
- l = CDR(cons);
- }
- if(!is_nil(l)) {
- BIF_ERROR(BIF_P, BADARG);
+ Port* prt;
+ Eterm retval;
+ Uint uint_op;
+ unsigned int op;
+ erts_aint32_t state;
+
+ prt = lookup_port(BIF_P, BIF_ARG_1);
+ if (!prt)
+ BIF_RET(am_badarg);
+
+ if (!term_to_Uint(BIF_ARG_2, &uint_op))
+ BIF_RET(am_badarg);
+
+ if (uint_op > (Uint) UINT_MAX)
+ BIF_RET(am_badarg);
+
+ op = (unsigned int) uint_op;
+
+ switch (erts_port_call(BIF_P, prt, op, BIF_ARG_3, &retval)) {
+ case ERTS_PORT_OP_CALLER_EXIT:
+ case ERTS_PORT_OP_DROPPED:
+ case ERTS_PORT_OP_BADARG:
+ retval = am_badarg;
+ break;
+ case ERTS_PORT_OP_SCHEDULED:
+ ASSERT(is_internal_ref(retval));
+ break;
+ case ERTS_PORT_OP_DONE:
+ ASSERT(is_not_internal_ref(retval));
+ break;
+ default:
+ ERTS_INTERNAL_ERROR("Unexpected erts_port_call() result");
+ retval = am_internal_error;
+ break;
}
- return do_port_command(BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3, flags);
-}
-BIF_RETTYPE port_call_2(BIF_ALIST_2)
-{
- return port_call(BIF_P,BIF_ARG_1, make_small(0), BIF_ARG_2);
-}
+ state = erts_smp_atomic32_read_acqb(&BIF_P->state);
+ if (state & (ERTS_PSFLG_EXITING|ERTS_PSFLG_PENDING_EXIT)) {
+#ifdef ERTS_SMP
+ if (state & ERTS_PSFLG_PENDING_EXIT)
+ erts_handle_pending_exit(BIF_P, ERTS_PROC_LOCK_MAIN);
+#endif
+ ERTS_BIF_EXITED(BIF_P);
+ }
-BIF_RETTYPE port_call_3(BIF_ALIST_3)
-{
- return port_call(BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3);
+ BIF_RET(retval);
}
-static BIF_RETTYPE
-port_call(Process* c_p, Eterm arg1, Eterm arg2, Eterm arg3)
+BIF_RETTYPE erts_internal_port_control_3(BIF_ALIST_3)
{
- Uint op;
- Port *p;
- Uint size;
- byte *bytes;
- byte *endp;
- ErlDrvSizeT real_size;
- erts_driver_t *drv;
- byte port_input[256]; /* Default input buffer to encode in */
- byte port_result[256]; /* Buffer for result from port. */
- byte* port_resp; /* Pointer to result buffer. */
- char *prc;
- ErlDrvSSizeT ret;
- Eterm res;
- Sint result_size;
- Eterm *hp;
- Eterm *hp_end;
- unsigned ret_flags = 0U;
- int fpe_was_unmasked;
-
- bytes = &port_input[0];
- port_resp = port_result;
- /* trace of port scheduling with virtual process descheduling
- * lock wait
- */
- if (IS_TRACED_FL(c_p, F_TRACE_SCHED_PROCS)) {
- trace_virtual_sched(c_p, am_out);
- }
-
- if (erts_system_profile_flags.runnable_procs && erts_system_profile_flags.exclusive) {
- profile_runnable_proc(c_p, am_inactive);
+ Port* prt;
+ Eterm retval;
+ Uint uint_op;
+ unsigned int op;
+ erts_aint32_t state;
+
+ prt = lookup_port(BIF_P, BIF_ARG_1);
+ if (!prt)
+ BIF_RET(am_badarg);
+
+ if (!term_to_Uint(BIF_ARG_2, &uint_op))
+ BIF_RET(am_badarg);
+
+ if (uint_op > (Uint) UINT_MAX)
+ BIF_RET(am_badarg);
+
+ op = (unsigned int) uint_op;
+
+ switch (erts_port_control(BIF_P, prt, op, BIF_ARG_3, &retval)) {
+ case ERTS_PORT_OP_CALLER_EXIT:
+ case ERTS_PORT_OP_BADARG:
+ case ERTS_PORT_OP_DROPPED:
+ retval = am_badarg;
+ break;
+ case ERTS_PORT_OP_SCHEDULED:
+ ASSERT(is_internal_ref(retval));
+ break;
+ case ERTS_PORT_OP_DONE:
+ ASSERT(is_not_internal_ref(retval));
+ break;
+ default:
+ ERTS_INTERNAL_ERROR("Unexpected erts_port_control() result");
+ retval = am_internal_error;
+ break;
}
- p = id_or_name2port(c_p, arg1);
- if (!p) {
- error:
- if (port_resp != port_result &&
- !(ret_flags & DRIVER_CALL_KEEP_BUFFER)) {
- driver_free(port_resp);
- }
- if (bytes != &port_input[0])
- erts_free(ERTS_ALC_T_PORT_CALL_BUF, bytes);
- /* Need to virtual schedule in the process if there
- * was an error.
- */
- if (IS_TRACED_FL(c_p, F_TRACE_SCHED_PROCS)) {
- trace_virtual_sched(c_p, am_in);
- }
-
- if (erts_system_profile_flags.runnable_procs && erts_system_profile_flags.exclusive) {
- profile_runnable_proc(c_p, am_active);
- }
-
- if (p)
- erts_port_release(p);
+ state = erts_smp_atomic32_read_acqb(&BIF_P->state);
+ if (state & (ERTS_PSFLG_EXITING|ERTS_PSFLG_PENDING_EXIT)) {
#ifdef ERTS_SMP
- ERTS_SMP_BIF_CHK_PENDING_EXIT(c_p, ERTS_PROC_LOCK_MAIN);
-#else
- ERTS_BIF_CHK_EXITED(c_p);
+ if (state & ERTS_PSFLG_PENDING_EXIT)
+ erts_handle_pending_exit(BIF_P, ERTS_PROC_LOCK_MAIN);
#endif
- BIF_ERROR(c_p, BADARG);
- }
-
- if ((drv = p->drv_ptr) == NULL) {
- goto error;
- }
- if (drv->call == NULL) {
- goto error;
- }
- if (!term_to_Uint(arg2, &op)) {
- goto error;
- }
- p->caller = c_p->id;
-
- /* Lock taken, virtual schedule of port */
- if (IS_TRACED_FL(p, F_TRACE_SCHED_PORTS)) {
- trace_sched_ports_where(p, am_in, am_call);
- }
-
- if (erts_system_profile_flags.runnable_ports && !erts_port_is_scheduled(p)) {
- profile_runnable_port(p, am_active);
+ ERTS_BIF_EXITED(BIF_P);
}
- size = erts_encode_ext_size(arg3);
- if (size > sizeof(port_input))
- bytes = erts_alloc(ERTS_ALC_T_PORT_CALL_BUF, size);
- endp = bytes;
- erts_encode_ext(arg3, &endp);
+ BIF_RET(retval);
+}
- real_size = endp - bytes;
- if (real_size > size) {
- erl_exit(1, "%s, line %d: buffer overflow: %d word(s)\n",
- __FILE__, __LINE__, endp - (bytes + size));
- }
- erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN);
-#ifdef USE_VM_PROBES
- if (DTRACE_ENABLED(driver_call)) {
- DTRACE_CHARBUF(process_str, DTRACE_TERM_BUF_SIZE);
- DTRACE_CHARBUF(port_str, DTRACE_TERM_BUF_SIZE);
+/*
+ * erts_internal:port_close/1 is used by the
+ * erlang:port_close/1 BIF.
+ */
+BIF_RETTYPE erts_internal_port_close_1(BIF_ALIST_1)
+{
+ Eterm ref;
+ Port *prt;
- dtrace_pid_str(p->connected, process_str);
- dtrace_port_str(p, port_str);
- DTRACE5(driver_call, process_str, port_str, p->name, op, real_size);
- }
-#endif
- prc = (char *) port_resp;
- fpe_was_unmasked = erts_block_fpe();
- ret = drv->call((ErlDrvData)p->drv_data,
- (unsigned) op,
- (char *) bytes,
- (int) real_size,
- &prc,
- (int) sizeof(port_result),
- &ret_flags);
- erts_unblock_fpe(fpe_was_unmasked);
- if (IS_TRACED_FL(p, F_TRACE_SCHED_PORTS)) {
- trace_sched_ports_where(p, am_out, am_call);
- }
-
- if (erts_system_profile_flags.runnable_ports && !erts_port_is_scheduled(p)) {
- profile_runnable_port(p, am_inactive);
- }
-
- port_resp = (byte *) prc;
- p->caller = NIL;
- erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN);
-#ifdef HARDDEBUG
- {
- ErlDrvSizeT z;
- printf("real_size = %ld,%d, ret = %ld,%d\r\n", (unsigned long) real_size,
- (int) real_size, (unsigned long)ret, (int) ret);
- printf("[");
- for(z = 0; z < real_size; ++z) {
- printf("%d, ",(int) bytes[z]);
- }
- printf("]\r\n");
- printf("[");
- for(z = 0; z < ret; ++z) {
- printf("%d, ",(int) port_resp[z]);
- }
- printf("]\r\n");
- }
-#endif
- if (ret <= 0 || port_resp[0] != VERSION_MAGIC) {
- /* Error or a binary without magic/ with wrong magic */
- goto error;
- }
- result_size = erts_decode_ext_size(port_resp, ret);
- if (result_size < 0) {
- goto error;
- }
- hp = HAlloc(c_p, result_size);
- hp_end = hp + result_size;
- endp = port_resp;
- res = erts_decode_ext(&hp, &MSO(c_p), &endp);
- if (res == THE_NON_VALUE) {
- goto error;
- }
- HRelease(c_p, hp_end, hp);
- if (port_resp != port_result && !(ret_flags & DRIVER_CALL_KEEP_BUFFER)) {
- driver_free(port_resp);
- }
- if (bytes != &port_input[0])
- erts_free(ERTS_ALC_T_PORT_CALL_BUF, bytes);
- if (p)
- erts_port_release(p);
-#ifdef ERTS_SMP
- ERTS_SMP_BIF_CHK_PENDING_EXIT(c_p, ERTS_PROC_LOCK_MAIN);
-#else
- ERTS_BIF_CHK_EXITED(c_p);
+#ifdef DEBUG
+ ref = NIL;
#endif
- if (IS_TRACED_FL(c_p, F_TRACE_SCHED_PROCS)) {
- trace_virtual_sched(c_p, am_in);
- }
- if (erts_system_profile_flags.runnable_procs && erts_system_profile_flags.exclusive) {
- profile_runnable_proc(c_p, am_active);
+ prt = lookup_port(BIF_P, BIF_ARG_1);
+ if (!prt)
+ BIF_RET(am_badarg);
+
+
+ switch (erts_port_exit(BIF_P, 0, prt, prt->common.id, am_normal, &ref)) {
+ case ERTS_PORT_OP_CALLER_EXIT:
+ case ERTS_PORT_OP_BADARG:
+ case ERTS_PORT_OP_DROPPED:
+ BIF_RET(am_badarg);
+ case ERTS_PORT_OP_SCHEDULED:
+ ASSERT(is_internal_ref(ref));
+ BIF_RET(ref);
+ case ERTS_PORT_OP_DONE:
+ BIF_RET(am_true);
+ default:
+ ERTS_INTERNAL_ERROR("Unexpected erts_port_exit() result");
+ BIF_RET(am_internal_error);
}
-
- return res;
}
-
-BIF_RETTYPE port_control_3(BIF_ALIST_3)
-{
- Port* p;
- Uint op;
- Eterm res = THE_NON_VALUE;
-
- /* Virtual schedule out calling process before lock wait */
- if (IS_TRACED_FL(BIF_P, F_TRACE_SCHED_PROCS)) {
- trace_virtual_sched(BIF_P, am_out);
- }
- if (erts_system_profile_flags.runnable_procs && erts_system_profile_flags.exclusive) {
- profile_runnable_proc(BIF_P, am_inactive);
- }
+/*
+ * erts_internal:port_connect/2 is used by the
+ * erlang:port_connect/2 BIF.
+ */
+BIF_RETTYPE erts_internal_port_connect_2(BIF_ALIST_2)
+{
+ Eterm ref;
+ Port* prt;
- p = id_or_name2port(BIF_P, BIF_ARG_1);
- if (!p) {
- /* Schedule the process before exiting */
- if (IS_TRACED_FL(BIF_P, F_TRACE_SCHED_PROCS)) {
- trace_virtual_sched(BIF_P, am_in);
- }
-
- if (erts_system_profile_flags.runnable_procs && erts_system_profile_flags.exclusive) {
- profile_runnable_proc(BIF_P, am_active);
- }
-
- BIF_ERROR(BIF_P, BADARG);
- }
+ prt = lookup_port(BIF_P, BIF_ARG_1);
+ if (!prt)
+ BIF_RET(am_badarg);
- /* Trace the port for scheduling in */
- if (IS_TRACED_FL(p, F_TRACE_SCHED_PORTS)) {
- trace_sched_ports_where(p, am_in, am_control);
- }
-
- if (erts_system_profile_flags.runnable_ports && !erts_port_is_scheduled(p)) {
- profile_runnable_port(p, am_active);
- }
+#ifdef DEBUG
+ ref = NIL;
+#endif
- if (term_to_Uint(BIF_ARG_2, &op))
- res = erts_port_control(BIF_P, p, op, BIF_ARG_3);
-
- /* Trace the port for scheduling out */
- if (IS_TRACED_FL(p, F_TRACE_SCHED_PORTS)) {
- trace_sched_ports_where(p, am_out, am_control);
+ switch (erts_port_connect(BIF_P, 0, prt, prt->common.id, BIF_ARG_2, &ref)) {
+ case ERTS_PORT_OP_CALLER_EXIT:
+ case ERTS_PORT_OP_BADARG:
+ case ERTS_PORT_OP_DROPPED:
+ BIF_RET(am_badarg);
+ case ERTS_PORT_OP_SCHEDULED:
+ ASSERT(is_internal_ref(ref));
+ BIF_RET(ref);
+ break;
+ case ERTS_PORT_OP_DONE:
+ BIF_RET(am_true);
+ break;
+ default:
+ ERTS_INTERNAL_ERROR("Unexpected erts_port_connect() result");
+ BIF_RET(am_internal_error);
}
+}
- if (erts_system_profile_flags.runnable_ports && !erts_port_is_scheduled(p)) {
- profile_runnable_port(p, am_inactive);
- }
+BIF_RETTYPE erts_internal_port_info_1(BIF_ALIST_1)
+{
+ Eterm retval;
+ Port* prt;
- erts_port_release(p);
-#ifdef ERTS_SMP
- ERTS_SMP_BIF_CHK_PENDING_EXIT(BIF_P, ERTS_PROC_LOCK_MAIN);
-#else
- ERTS_BIF_CHK_EXITED(BIF_P);
-#endif
-
- if (IS_TRACED_FL(BIF_P, F_TRACE_SCHED_PROCS)) {
- trace_virtual_sched(BIF_P, am_in);
+ if (is_internal_port(BIF_ARG_1) || is_atom(BIF_ARG_1)) {
+ prt = lookup_port(BIF_P, BIF_ARG_1);
+ if (!prt)
+ BIF_RET(am_undefined);
}
-
- if (erts_system_profile_flags.runnable_procs && erts_system_profile_flags.exclusive) {
- profile_runnable_proc(BIF_P, am_active);
+ else if (is_external_port(BIF_ARG_1)) {
+ if (external_port_dist_entry(BIF_ARG_1) == erts_this_dist_entry)
+ BIF_RET(am_undefined);
+ else
+ BIF_RET(am_badarg);
}
-
- if (is_non_value(res)) {
- BIF_ERROR(BIF_P, BADARG);
+ else {
+ BIF_RET(am_badarg);
+ }
+
+ switch (erts_port_info(BIF_P, prt, THE_NON_VALUE, &retval)) {
+ case ERTS_PORT_OP_CALLER_EXIT:
+ case ERTS_PORT_OP_BADARG:
+ BIF_RET(am_badarg);
+ case ERTS_PORT_OP_DROPPED:
+ BIF_RET(am_undefined);
+ case ERTS_PORT_OP_SCHEDULED:
+ ASSERT(is_internal_ref(retval));
+ BIF_RET(retval);
+ case ERTS_PORT_OP_DONE:
+ ASSERT(is_not_internal_ref(retval));
+ BIF_RET(retval);
+ default:
+ ERTS_INTERNAL_ERROR("Unexpected erts_port_info() result");
+ BIF_RET(am_internal_error);
}
- BIF_RET(res);
}
-BIF_RETTYPE port_close_1(BIF_ALIST_1)
-{
- Port* p;
- erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
- p = id_or_name2port(NULL, BIF_ARG_1);
- if (!p) {
- erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
- BIF_ERROR(BIF_P, BADARG);
- }
- erts_do_exit_port(p, p->connected, am_normal);
- /* if !ERTS_SMP: since we terminate port with reason normal
- we SHOULD never get an exit signal ourselves
- */
- erts_port_release(p);
- erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
- BIF_RET(am_true);
-}
-BIF_RETTYPE port_connect_2(BIF_ALIST_2)
+BIF_RETTYPE erts_internal_port_info_2(BIF_ALIST_2)
{
+ Eterm retval;
Port* prt;
- Process* rp;
- Eterm pid = BIF_ARG_2;
- if (is_not_internal_pid(pid)) {
- error:
- BIF_ERROR(BIF_P, BADARG);
+ if (is_internal_port(BIF_ARG_1) || is_atom(BIF_ARG_1)) {
+ prt = lookup_port(BIF_P, BIF_ARG_1);
+ if (!prt)
+ BIF_RET(am_undefined);
}
- prt = id_or_name2port(BIF_P, BIF_ARG_1);
- if (!prt) {
- goto error;
+ else if (is_external_port(BIF_ARG_1)) {
+ if (external_port_dist_entry(BIF_ARG_1) == erts_this_dist_entry)
+ BIF_RET(am_undefined);
+ else
+ BIF_RET(am_badarg);
}
-
- rp = erts_pid2proc(BIF_P, ERTS_PROC_LOCK_MAIN,
- pid, ERTS_PROC_LOCK_LINK);
- if (!rp) {
- erts_smp_port_unlock(prt);
- ERTS_SMP_ASSERT_IS_NOT_EXITING(BIF_P);
- goto error;
- }
-
- erts_add_link(&(rp->nlinks), LINK_PID, prt->id);
- erts_add_link(&(prt->nlinks), LINK_PID, pid);
-
- erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_LINK);
-
- prt->connected = pid; /* internal pid */
- erts_smp_port_unlock(prt);
-#ifdef USE_VM_PROBES
- if (DTRACE_ENABLED(port_connect)) {
- DTRACE_CHARBUF(process_str, DTRACE_TERM_BUF_SIZE);
- DTRACE_CHARBUF(port_str, DTRACE_TERM_BUF_SIZE);
- DTRACE_CHARBUF(newprocess_str, DTRACE_TERM_BUF_SIZE);
-
- dtrace_pid_str(prt->connected, process_str);
- erts_snprintf(port_str, sizeof(port_str), "%T", prt->id);
- dtrace_proc_str(rp, newprocess_str);
- DTRACE4(port_connect, process_str, port_str, prt->name, newprocess_str);
+ else {
+ BIF_RET(am_badarg);
+ }
+
+ switch (erts_port_info(BIF_P, prt, BIF_ARG_2, &retval)) {
+ case ERTS_PORT_OP_CALLER_EXIT:
+ case ERTS_PORT_OP_BADARG:
+ BIF_RET(am_badarg);
+ case ERTS_PORT_OP_DROPPED:
+ BIF_RET(am_undefined);
+ case ERTS_PORT_OP_SCHEDULED:
+ ASSERT(is_internal_ref(retval));
+ BIF_RET(retval);
+ case ERTS_PORT_OP_DONE:
+ ASSERT(is_not_internal_ref(retval));
+ BIF_RET(retval);
+ default:
+ ERTS_INTERNAL_ERROR("Unexpected erts_port_info() result");
+ BIF_RET(am_internal_error);
}
-#endif
- BIF_RET(am_true);
}
-BIF_RETTYPE port_set_data_2(BIF_ALIST_2)
+
+BIF_RETTYPE erts_internal_port_set_data_2(BIF_ALIST_2)
{
+ Eterm ref;
Port* prt;
- Eterm portid = BIF_ARG_1;
- Eterm data = BIF_ARG_2;
- prt = id_or_name2port(BIF_P, portid);
- if (!prt) {
- BIF_ERROR(BIF_P, BADARG);
- }
- if (prt->bp != NULL) {
- free_message_buffer(prt->bp);
- prt->bp = NULL;
- }
- if (IS_CONST(data)) {
- prt->data = data;
- } else {
- Uint size;
- ErlHeapFragment* bp;
- Eterm* hp;
-
- size = size_object(data);
- prt->bp = bp = new_message_buffer(size);
- hp = bp->mem;
- prt->data = copy_struct(data, size, &hp, &bp->off_heap);
+ prt = lookup_port(BIF_P, BIF_ARG_1);
+ if (!prt)
+ BIF_RET(am_badarg);
+
+ switch (erts_port_set_data(BIF_P, prt, BIF_ARG_2, &ref)) {
+ case ERTS_PORT_OP_CALLER_EXIT:
+ case ERTS_PORT_OP_BADARG:
+ case ERTS_PORT_OP_DROPPED:
+ BIF_RET(am_badarg);
+ case ERTS_PORT_OP_SCHEDULED:
+ ASSERT(is_internal_ref(ref));
+ BIF_RET(ref);
+ case ERTS_PORT_OP_DONE:
+ BIF_RET(am_true);
+ default:
+ ERTS_INTERNAL_ERROR("Unexpected erts_port_set_data() result");
+ BIF_RET(am_internal_error);
}
- erts_smp_port_unlock(prt);
- BIF_RET(am_true);
}
-BIF_RETTYPE port_get_data_1(BIF_ALIST_1)
+BIF_RETTYPE erts_internal_port_get_data_1(BIF_ALIST_1)
{
- BIF_RETTYPE res;
+ Eterm retval;
Port* prt;
- Eterm portid = BIF_ARG_1;
- prt = id_or_name2port(BIF_P, portid);
- if (!prt) {
- BIF_ERROR(BIF_P, BADARG);
- }
- if (prt->bp == NULL) { /* MUST be CONST! */
- res = prt->data;
- } else {
- Eterm* hp = HAlloc(BIF_P, prt->bp->used_size);
- res = copy_struct(prt->data, prt->bp->used_size, &hp, &MSO(BIF_P));
+ prt = lookup_port(BIF_P, BIF_ARG_1);
+ if (!prt)
+ BIF_RET(am_badarg);
+
+ switch (erts_port_get_data(BIF_P, prt, &retval)) {
+ case ERTS_PORT_OP_CALLER_EXIT:
+ case ERTS_PORT_OP_BADARG:
+ case ERTS_PORT_OP_DROPPED:
+ BIF_RET(am_badarg);
+ case ERTS_PORT_OP_SCHEDULED:
+ ASSERT(is_internal_ref(retval));
+ BIF_RET(retval);
+ case ERTS_PORT_OP_DONE:
+ ASSERT(is_not_internal_ref(retval));
+ BIF_RET(retval);
+ default:
+ ERTS_INTERNAL_ERROR("Unexpected erts_port_get_data() result");
+ BIF_RET(am_internal_error);
}
- erts_smp_port_unlock(prt);
- BIF_RET(res);
}
/*
@@ -625,11 +485,10 @@ BIF_RETTYPE port_get_data_1(BIF_ALIST_1)
* either BADARG or SYSTEM_LIMIT).
*/
-static int
-open_port(Process* p, Eterm name, Eterm settings, int *err_nump)
+static Port *
+open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump)
{
-#define OPEN_PORT_ERROR(VAL) do { port_num = (VAL); goto do_return; } while (0)
- int i, port_num;
+ int i;
Eterm option;
Uint arity;
Eterm* tp;
@@ -637,11 +496,11 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_nump)
erts_driver_t* driver;
char* name_buf = NULL;
SysDriverOpts opts;
- int binary_io;
- int soft_eof;
Sint linebuf;
Eterm edir = NIL;
byte dir[MAXPATHLEN];
+ erts_aint32_t sflgs = 0;
+ Port *port;
/* These are the defaults */
opts.packet_bytes = 0;
@@ -655,8 +514,7 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_nump)
opts.overlapped_io = 0;
opts.spawn_type = ERTS_SPAWN_ANY;
opts.argv = NULL;
- binary_io = 0;
- soft_eof = 0;
+ opts.parallelism = erts_port_parallelism;
linebuf = 0;
*err_nump = 0;
@@ -734,6 +592,13 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_nump)
}
} else if (option == am_cd) {
edir = *tp;
+ } else if (option == am_parallelism) {
+ if (*tp == am_true)
+ opts.parallelism = 1;
+ else if (*tp == am_false)
+ opts.parallelism = 0;
+ else
+ goto badarg;
} else {
goto badarg;
}
@@ -748,13 +613,13 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_nump)
} else if (*nargs == am_nouse_stdio) {
opts.use_stdio = 0;
} else if (*nargs == am_binary) {
- binary_io = 1;
+ sflgs |= ERTS_PORT_SFLG_BINARY_IO;
} else if (*nargs == am_in) {
opts.read_write |= DO_READ;
} else if (*nargs == am_out) {
opts.read_write |= DO_WRITE;
} else if (*nargs == am_eof) {
- soft_eof = 1;
+ sflgs |= ERTS_PORT_SFLG_SOFT_EOF;
} else if (*nargs == am_hide) {
opts.hide_window = 1;
} else if (*nargs == am_exit_status) {
@@ -902,9 +767,9 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_nump)
heap[2] = make_small(0);
heap[3] = NIL;
iolist = make_list(heap);
- r = io_list_to_buf(iolist, (char*) dir, MAXPATHLEN);
+ r = erts_iolist_to_buf(iolist, (char*) dir, MAXPATHLEN);
UnUseTmpHeap(4,p);
- if (r < 0) {
+ if (ERTS_IOLIST_TO_BUF_FAILED(r)) {
goto badarg;
}
opts.wd = (char *) dir;
@@ -926,44 +791,40 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_nump)
erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN);
- port_num = erts_open_driver(driver, p->id, name_buf, &opts, err_nump);
+ port = erts_open_driver(driver, p->common.id, name_buf, &opts, err_typep, err_nump);
#ifdef USE_VM_PROBES
- if (port_num >= 0 && DTRACE_ENABLED(port_open)) {
+ if (port && DTRACE_ENABLED(port_open)) {
DTRACE_CHARBUF(process_str, DTRACE_TERM_BUF_SIZE);
DTRACE_CHARBUF(port_str, DTRACE_TERM_BUF_SIZE);
dtrace_proc_str(p, process_str);
- erts_snprintf(port_str, sizeof(port_str), "%T", erts_port[port_num].id);
+ erts_snprintf(port_str, sizeof(port_str), "%T", port->common.id);
DTRACE3(port_open, process_str, name_buf, port_str);
}
#endif
erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN);
- if (port_num < 0) {
- DEBUGF(("open_driver returned %d(%d)\n", port_num, *err_nump));
+ if (!port) {
+ DEBUGF(("open_driver returned (%d:%d)\n",
+ err_typep ? *err_typep : 4711,
+ err_nump ? *err_nump : 4711));
if (IS_TRACED_FL(p, F_TRACE_SCHED_PROCS)) {
trace_virtual_sched(p, am_in);
}
- OPEN_PORT_ERROR(port_num);
+ goto do_return;
}
if (IS_TRACED_FL(p, F_TRACE_SCHED_PROCS)) {
trace_virtual_sched(p, am_in);
}
- if (binary_io) {
- erts_port_status_bor_set(&erts_port[port_num],
- ERTS_PORT_SFLG_BINARY_IO);
- }
- if (soft_eof) {
- erts_port_status_bor_set(&erts_port[port_num],
- ERTS_PORT_SFLG_SOFT_EOF);
- }
- if (linebuf && erts_port[port_num].linebuf == NULL){
- erts_port[port_num].linebuf = allocate_linebuf(linebuf);
- erts_port_status_bor_set(&erts_port[port_num],
- ERTS_PORT_SFLG_LINEBUF_IO);
+ if (linebuf && port->linebuf == NULL){
+ port->linebuf = allocate_linebuf(linebuf);
+ sflgs |= ERTS_PORT_SFLG_LINEBUF_IO;
}
+
+ if (sflgs)
+ erts_atomic32_read_bor_relb(&port->state, sflgs);
do_return:
if (name_buf)
@@ -974,13 +835,15 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_nump)
if (opts.wd && opts.wd != ((char *)dir)) {
erts_free(ERTS_ALC_T_TMP, (void *) opts.wd);
}
- return port_num;
+ return port;
badarg:
- *err_nump = BADARG;
- OPEN_PORT_ERROR(-3);
+ if (err_typep)
+ *err_typep = -3;
+ if (err_nump)
+ *err_nump = BADARG;
+ port = NULL;
goto do_return;
-#undef OPEN_PORT_ERROR
}
/* Arguments can be given i unicode and as raw binaries, convert filename is used to convert */
diff --git a/erts/emulator/beam/erl_bif_re.c b/erts/emulator/beam/erl_bif_re.c
index b036c5ef5c..88f980d19f 100644
--- a/erts/emulator/beam/erl_bif_re.c
+++ b/erts/emulator/beam/erl_bif_re.c
@@ -413,7 +413,7 @@ build_compile_result(Process *p, Eterm error_tag, pcre *result, int errcode, con
static BIF_RETTYPE
re_compile(Process* p, Eterm arg1, Eterm arg2)
{
- Uint slen;
+ ErlDrvSizeT slen;
char *expr;
pcre *result;
int errcode = 0;
@@ -444,7 +444,7 @@ re_compile(Process* p, Eterm arg1, Eterm arg2)
BIF_ERROR(p,BADARG);
}
expr = erts_alloc(ERTS_ALC_T_RE_TMP_BUF, slen + 1);
- if (io_list_to_buf(arg1, expr, slen) != 0) {
+ if (erts_iolist_to_buf(arg1, expr, slen) != 0) {
erts_free(ERTS_ALC_T_RE_TMP_BUF, expr);
BIF_ERROR(p,BADARG);
}
@@ -797,7 +797,7 @@ build_capture(Eterm capture_spec[CAPSPEC_SIZE], const pcre *code)
memcpy(tmpb,ap->name,ap->len);
tmpb[ap->len] = '\0';
} else {
- Uint slen;
+ ErlDrvSizeT slen;
if (erts_iolist_size(val, &slen)) {
goto error;
}
@@ -809,7 +809,7 @@ build_capture(Eterm capture_spec[CAPSPEC_SIZE], const pcre *code)
(tmpbsiz = slen + 1));
}
}
- if (io_list_to_buf(val, tmpb, slen) != 0) {
+ if (erts_iolist_to_buf(val, tmpb, slen) != 0) {
goto error;
}
tmpb[slen] = '\0';
@@ -853,7 +853,7 @@ re_run(Process *p, Eterm arg1, Eterm arg2, Eterm arg3)
const pcre *code_tmp;
RestartContext restart;
byte *temp_alloc = NULL;
- Uint slength;
+ ErlDrvSizeT slength;
int startoffset = 0;
int options = 0, comp_options = 0;
int ovsize;
@@ -877,7 +877,7 @@ re_run(Process *p, Eterm arg1, Eterm arg2, Eterm arg3)
if (is_not_tuple(arg2) || (arityval(*tuple_val(arg2)) != 4)) {
if (is_binary(arg2) || is_list(arg2) || is_nil(arg2)) {
/* Compile from textual RE */
- Uint slen;
+ ErlDrvSizeT slen;
char *expr;
pcre *result;
int errcode = 0;
@@ -896,7 +896,7 @@ re_run(Process *p, Eterm arg1, Eterm arg2, Eterm arg3)
}
expr = erts_alloc(ERTS_ALC_T_RE_TMP_BUF, slen + 1);
- if (io_list_to_buf(arg2, expr, slen) != 0) {
+ if (erts_iolist_to_buf(arg2, expr, slen) != 0) {
erts_free(ERTS_ALC_T_RE_TMP_BUF, expr);
BIF_ERROR(p,BADARG);
}
@@ -1039,7 +1039,7 @@ handle_iolist:
}
restart.subject = erts_alloc(ERTS_ALC_T_RE_SUBJECT, slength);
- if (io_list_to_buf(arg1, restart.subject, slength) != 0) {
+ if (erts_iolist_to_buf(arg1, restart.subject, slength) != 0) {
erts_free(ERTS_ALC_T_RE_SUBJECT, restart.ovector);
erts_free(ERTS_ALC_T_RE_SUBJECT, restart.code);
erts_free(ERTS_ALC_T_RE_SUBJECT, restart.subject);
diff --git a/erts/emulator/beam/erl_bif_timer.c b/erts/emulator/beam/erl_bif_timer.c
index 525b11f61c..d67695e533 100644
--- a/erts/emulator/beam/erl_bif_timer.c
+++ b/erts/emulator/beam/erl_bif_timer.c
@@ -265,10 +265,10 @@ link_proc(Process *p, ErtsBifTimer* btm)
{
btm->receiver.proc.ess = p;
btm->receiver.proc.prev = NULL;
- btm->receiver.proc.next = p->bif_timers;
- if (p->bif_timers)
- p->bif_timers->receiver.proc.prev = btm;
- p->bif_timers = btm;
+ btm->receiver.proc.next = p->u.bif_timers;
+ if (p->u.bif_timers)
+ p->u.bif_timers->receiver.proc.prev = btm;
+ p->u.bif_timers = btm;
}
static ERTS_INLINE void
@@ -277,7 +277,7 @@ unlink_proc(ErtsBifTimer* btm)
if (btm->receiver.proc.prev)
btm->receiver.proc.prev->receiver.proc.next = btm->receiver.proc.next;
else
- btm->receiver.proc.ess->bif_timers = btm->receiver.proc.next;
+ btm->receiver.proc.ess->u.bif_timers = btm->receiver.proc.next;
if (btm->receiver.proc.next)
btm->receiver.proc.next->receiver.proc.prev = btm->receiver.proc.prev;
}
@@ -613,7 +613,7 @@ erts_print_bif_timer_info(int to, void *to_arg)
for (btm = bif_timer_tab[i]; btm; btm = btm->tab.next) {
Eterm receiver = (btm->flags & BTM_FLG_BYNAME
? btm->receiver.name
- : btm->receiver.proc.ess->id);
+ : btm->receiver.proc.ess->common.id);
erts_print(to, to_arg, "=timer:%T\n", receiver);
erts_print(to, to_arg, "Message: %T\n", btm->message);
erts_print(to, to_arg, "Time left: %u ms\n",
@@ -637,7 +637,7 @@ erts_cancel_bif_timers(Process *p, ErtsProcLocks plocks)
erts_smp_proc_lock(p, plocks);
}
- btm = p->bif_timers;
+ btm = p->u.bif_timers;
while (btm) {
ErtsBifTimer *tmp_btm;
ASSERT(!(btm->flags & BTM_FLG_CANCELED));
@@ -647,7 +647,7 @@ erts_cancel_bif_timers(Process *p, ErtsProcLocks plocks)
erts_cancel_timer(&tmp_btm->tm);
}
- p->bif_timers = NULL;
+ p->u.bif_timers = NULL;
erts_smp_btm_rwunlock();
}
@@ -696,7 +696,7 @@ erts_bif_timer_foreach(void (*func)(Eterm, Eterm, ErlHeapFragment *, void *),
for (btm = bif_timer_tab[i]; btm; btm = btm->tab.next) {
(*func)((btm->flags & BTM_FLG_BYNAME
? btm->receiver.name
- : btm->receiver.proc.ess->id),
+ : btm->receiver.proc.ess->common.id),
btm->message,
btm->bp,
arg);
diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c
index 06cec1795d..99a4394666 100644
--- a/erts/emulator/beam/erl_bif_trace.c
+++ b/erts/emulator/beam/erl_bif_trace.c
@@ -58,10 +58,17 @@ static struct { /* Protected by code write permission */
int local;
BpFunctions f; /* Local functions */
BpFunctions e; /* Export entries */
+#ifdef ERTS_SMP
+ Process* stager;
+ ErtsThrPrgrLaterOp lop;
+#endif
} finish_bp;
static Eterm
trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist);
+#ifdef ERTS_SMP
+static void smp_bp_finisher(void* arg);
+#endif
static BIF_RETTYPE
system_monitor(Process *p, Eterm monitor_pid, Eterm list);
@@ -117,7 +124,7 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist)
struct trace_pattern_flags flags = erts_trace_pattern_flags_off;
int is_global;
Process *meta_tracer_proc = p;
- Eterm meta_tracer_pid = p->id;
+ Eterm meta_tracer_pid = p->common.id;
if (!erts_try_seize_code_write_permission(p)) {
ERTS_BIF_YIELD3(bif_export[BIF_trace_pattern_3], p, MFA, Pattern, flaglist);
@@ -164,14 +171,12 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist)
}
} else if (is_internal_port(meta_tracer_pid)) {
Port *meta_tracer_port;
- meta_tracer_proc = NULL;
- if (internal_port_index(meta_tracer_pid) >= erts_max_ports)
- goto error;
- meta_tracer_port =
- &erts_port[internal_port_index(meta_tracer_pid)];
- if (INVALID_TRACER_PORT(meta_tracer_port, meta_tracer_pid)) {
+ meta_tracer_proc = NULL;
+ meta_tracer_port = (erts_port_lookup(
+ meta_tracer_pid,
+ ERTS_PORT_SFLGS_INVALID_TRACER_LOOKUP));
+ if (!meta_tracer_port)
goto error;
- }
} else {
goto error;
}
@@ -247,7 +252,7 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist)
MatchSetRef(erts_default_meta_match_spec);
erts_default_meta_tracer_pid = meta_tracer_pid;
if (meta_tracer_proc) {
- meta_tracer_proc->trace_flags |= F_TRACER;
+ ERTS_TRACE_FLAGS(meta_tracer_proc) |= F_TRACER;
}
} else if (! flags.breakpoint) {
MatchSetUnref(erts_default_meta_match_spec);
@@ -335,7 +340,7 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist)
}
if (meta_tracer_proc) {
- meta_tracer_proc->trace_flags |= F_TRACER;
+ ERTS_TRACE_FLAGS(meta_tracer_proc) |= F_TRACER;
}
matches = erts_set_trace_pattern(p, mfa, specified,
@@ -350,7 +355,10 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist)
#ifdef ERTS_SMP
if (finish_bp.current >= 0) {
ASSERT(matches >= 0);
- erts_notify_finish_breakpointing(p);
+ ASSERT(finish_bp.stager == NULL);
+ finish_bp.stager = p;
+ erts_schedule_thr_prgr_later_op(smp_bp_finisher, NULL, &finish_bp.lop);
+ erts_smp_proc_inc_refc(p);
erts_suspend(p, ERTS_PROC_LOCK_MAIN, NULL);
ERTS_BIF_YIELD_RETURN(p, make_small(matches));
}
@@ -366,6 +374,29 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist)
}
}
+#ifdef ERTS_SMP
+static void smp_bp_finisher(void* null)
+{
+ if (erts_finish_breakpointing()) { /* Not done */
+ /* Arrange for being called again */
+ erts_schedule_thr_prgr_later_op(smp_bp_finisher, NULL, &finish_bp.lop);
+ }
+ else { /* Done */
+ Process* p = finish_bp.stager;
+#ifdef DEBUG
+ finish_bp.stager = NULL;
+#endif
+ erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS);
+ if (!ERTS_PROC_IS_EXITING(p)) {
+ erts_resume(p, ERTS_PROC_LOCK_STATUS);
+ }
+ erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS);
+ erts_smp_proc_dec_refc(p);
+ erts_release_code_write_permission();
+ }
+}
+#endif /* ERTS_SMP */
+
void
erts_get_default_trace_pattern(int *trace_pattern_is_on,
Binary **match_spec,
@@ -373,7 +404,7 @@ erts_get_default_trace_pattern(int *trace_pattern_is_on,
struct trace_pattern_flags *trace_pattern_flags,
Eterm *meta_tracer_pid)
{
- ERTS_SMP_LC_ASSERT(erts_is_code_ix_locked() ||
+ ERTS_SMP_LC_ASSERT(erts_has_code_write_permission() ||
erts_smp_thr_progress_is_blocking());
if (trace_pattern_is_on)
*trace_pattern_is_on = erts_default_trace_pattern_is_on;
@@ -389,7 +420,7 @@ erts_get_default_trace_pattern(int *trace_pattern_is_on,
int erts_is_default_trace_enabled(void)
{
- ERTS_SMP_LC_ASSERT(erts_is_code_ix_locked() ||
+ ERTS_SMP_LC_ASSERT(erts_has_code_write_permission() ||
erts_smp_thr_progress_is_blocking());
return erts_default_trace_pattern_is_on;
}
@@ -493,24 +524,24 @@ Eterm trace_3(BIF_ALIST_3)
if (is_nil(tracer) || is_internal_pid(tracer)) {
Process *tracer_proc = erts_pid2proc(p,
ERTS_PROC_LOCK_MAIN,
- is_nil(tracer) ? p->id : tracer,
+ is_nil(tracer) ? p->common.id : tracer,
ERTS_PROC_LOCKS_ALL);
if (!tracer_proc)
goto error;
- tracer_proc->trace_flags |= F_TRACER;
+ ERTS_TRACE_FLAGS(tracer_proc) |= F_TRACER;
erts_smp_proc_unlock(tracer_proc,
(tracer_proc == p
? ERTS_PROC_LOCKS_ALL_MINOR
: ERTS_PROC_LOCKS_ALL));
} else if (is_internal_port(tracer)) {
- Port *tracer_port = erts_id2port(tracer, p, ERTS_PROC_LOCK_MAIN);
- if (!erts_is_valid_tracer_port(tracer)) {
- if (tracer_port)
- erts_smp_port_unlock(tracer_port);
+ Port *tracer_port = erts_id2port_sflgs(tracer,
+ p,
+ ERTS_PROC_LOCK_MAIN,
+ ERTS_PORT_SFLGS_INVALID_TRACER_LOOKUP);
+ if (!tracer_port)
goto error;
- }
- tracer_port->trace_flags |= F_TRACER;
- erts_smp_port_unlock(tracer_port);
+ ERTS_TRACE_FLAGS(tracer_port) |= F_TRACER;
+ erts_port_release(tracer_port);
} else
goto error;
@@ -521,7 +552,7 @@ Eterm trace_3(BIF_ALIST_3)
case am_true:
on = 1;
if (is_nil(tracer))
- tracer = p->id;
+ tracer = p->common.id;
break;
default:
goto error;
@@ -543,26 +574,29 @@ Eterm trace_3(BIF_ALIST_3)
if (pid_spec == tracer)
goto error;
- tracee_port = erts_id2port(pid_spec, p, ERTS_PROC_LOCK_MAIN);
+ tracee_port = erts_id2port_sflgs(pid_spec,
+ p,
+ ERTS_PROC_LOCK_MAIN,
+ ERTS_PORT_SFLGS_INVALID_LOOKUP);
if (!tracee_port)
goto error;
if (tracer != NIL && port_already_traced(p, tracee_port, tracer)) {
- erts_smp_port_unlock(tracee_port);
+ erts_port_release(tracee_port);
goto already_traced;
}
if (on)
- tracee_port->trace_flags |= mask;
+ ERTS_TRACE_FLAGS(tracee_port) |= mask;
else
- tracee_port->trace_flags &= ~mask;
+ ERTS_TRACE_FLAGS(tracee_port) &= ~mask;
- if (!tracee_port->trace_flags)
- tracee_port->tracer_proc = NIL;
+ if (!ERTS_TRACE_FLAGS(tracee_port))
+ ERTS_TRACER_PROC(tracee_port) = NIL;
else if (tracer != NIL)
- tracee_port->tracer_proc = tracer;
+ ERTS_TRACER_PROC(tracee_port) = tracer;
- erts_smp_port_unlock(tracee_port);
+ erts_port_release(tracee_port);
matches = 1;
} else if (is_pid(pid_spec)) {
@@ -594,14 +628,14 @@ Eterm trace_3(BIF_ALIST_3)
}
if (on)
- tracee_p->trace_flags |= mask;
+ ERTS_TRACE_FLAGS(tracee_p) |= mask;
else
- tracee_p->trace_flags &= ~mask;
+ ERTS_TRACE_FLAGS(tracee_p) &= ~mask;
- if ((tracee_p->trace_flags & TRACEE_FLAGS) == 0)
- tracee_p->tracer_proc = NIL;
+ if ((ERTS_TRACE_FLAGS(tracee_p) & TRACEE_FLAGS) == 0)
+ ERTS_TRACER_PROC(tracee_p) = NIL;
else if (tracer != NIL)
- tracee_p->tracer_proc = tracer;
+ ERTS_TRACER_PROC(tracee_p) = tracer;
erts_smp_proc_unlock(tracee_p,
(tracee_p == p
@@ -675,47 +709,56 @@ Eterm trace_3(BIF_ALIST_3)
ok = 1;
if (procs || mods) {
+ int max = erts_ptab_max(&erts_proc);
/* tracing of processes */
- for (i = 0; i < erts_max_processes; i++) {
+ for (i = 0; i < max; i++) {
Process* tracee_p = erts_pix2proc(i);
if (! tracee_p)
continue;
if (tracer != NIL) {
- if (tracee_p->id == tracer)
+ if (tracee_p->common.id == tracer)
continue;
if (already_traced(NULL, tracee_p, tracer))
continue;
}
if (on) {
- tracee_p->trace_flags |= mask;
+ ERTS_TRACE_FLAGS(tracee_p) |= mask;
} else {
- tracee_p->trace_flags &= ~mask;
+ ERTS_TRACE_FLAGS(tracee_p) &= ~mask;
}
- if(!(tracee_p->trace_flags & TRACEE_FLAGS)) {
- tracee_p->tracer_proc = NIL;
+ if(!(ERTS_TRACE_FLAGS(tracee_p) & TRACEE_FLAGS)) {
+ ERTS_TRACER_PROC(tracee_p) = NIL;
} else if (tracer != NIL) {
- tracee_p->tracer_proc = tracer;
+ ERTS_TRACER_PROC(tracee_p) = tracer;
}
matches++;
}
}
if (ports || mods) {
+ int max = erts_ptab_max(&erts_port);
/* tracing of ports */
- for (i = 0; i < erts_max_ports; i++) {
- Port *tracee_port = &erts_port[i];
- if (tracee_port->status & ERTS_PORT_SFLGS_DEAD) continue;
+ for (i = 0; i < max; i++) {
+ erts_aint32_t state;
+ Port *tracee_port = erts_pix2port(i);
+ if (!tracee_port)
+ continue;
+ state = erts_atomic32_read_nob(&tracee_port->state);
+ if (state & ERTS_PORT_SFLGS_DEAD)
+ continue;
if (tracer != NIL) {
- if (tracee_port->id == tracer) continue;
- if (port_already_traced(NULL, tracee_port, tracer)) continue;
+ if (tracee_port->common.id == tracer)
+ continue;
+ if (port_already_traced(NULL, tracee_port, tracer))
+ continue;
}
- if (on) tracee_port->trace_flags |= mask;
- else tracee_port->trace_flags &= ~mask;
+ if (on) ERTS_TRACE_FLAGS(tracee_port) |= mask;
+ else ERTS_TRACE_FLAGS(tracee_port) &= ~mask;
- if (!(tracee_port->trace_flags & TRACEE_FLAGS)) {
- tracee_port->tracer_proc = NIL;
+ if (!(ERTS_TRACE_FLAGS(tracee_port) & TRACEE_FLAGS)) {
+ ERTS_TRACER_PROC(tracee_port) = NIL;
} else if (tracer != NIL) {
- tracee_port->tracer_proc = tracer;
+ ERTS_TRACER_PROC(tracee_port) = tracer;
}
/* matches are not counted for ports since it would violate compatibility */
/* This could be a reason to modify this function or make a new one. */
@@ -784,20 +827,20 @@ static int port_already_traced(Process *c_p, Port *tracee_port, Eterm tracer)
* * main lock is held on c_p
* * all locks are held on port tracee_p
*/
- if ((tracee_port->trace_flags & TRACEE_FLAGS)
- && tracee_port->tracer_proc != tracer) {
+ if ((ERTS_TRACE_FLAGS(tracee_port) & TRACEE_FLAGS)
+ && ERTS_TRACER_PROC(tracee_port) != tracer) {
/* This tracee is already being traced, and not by the
* tracer to be */
- if (is_internal_port(tracee_port->tracer_proc)) {
- if (!erts_is_valid_tracer_port(tracee_port->tracer_proc)) {
+ if (is_internal_port(ERTS_TRACER_PROC(tracee_port))) {
+ if (!erts_is_valid_tracer_port(ERTS_TRACER_PROC(tracee_port))) {
/* Current trace port now invalid
* - discard it and approve the new. */
goto remove_tracer;
} else
return 1;
}
- else if(is_internal_pid(tracee_port->tracer_proc)) {
- Process *tracer_p = erts_proc_lookup(tracee_port->tracer_proc);
+ else if(is_internal_pid(ERTS_TRACER_PROC(tracee_port))) {
+ Process *tracer_p = erts_proc_lookup(ERTS_TRACER_PROC(tracee_port));
if (!tracer_p) {
/* Current trace process now invalid
* - discard it and approve the new. */
@@ -807,8 +850,8 @@ static int port_already_traced(Process *c_p, Port *tracee_port, Eterm tracer)
}
else {
remove_tracer:
- tracee_port->trace_flags &= ~TRACEE_FLAGS;
- tracee_port->tracer_proc = NIL;
+ ERTS_TRACE_FLAGS(tracee_port) &= ~TRACEE_FLAGS;
+ ERTS_TRACER_PROC(tracee_port) = NIL;
}
}
return 0;
@@ -824,20 +867,22 @@ static int already_traced(Process *c_p, Process *tracee_p, Eterm tracer)
* * main lock is held on c_p
* * all locks multiple are held on tracee_p
*/
- if ((tracee_p->trace_flags & TRACEE_FLAGS)
- && tracee_p->tracer_proc != tracer) {
+ if ((ERTS_TRACE_FLAGS(tracee_p) & TRACEE_FLAGS)
+ && ERTS_TRACER_PROC(tracee_p) != tracer) {
/* This tracee is already being traced, and not by the
* tracer to be */
- if (is_internal_port(tracee_p->tracer_proc)) {
- if (!erts_is_valid_tracer_port(tracee_p->tracer_proc)) {
+ if (is_internal_port(ERTS_TRACER_PROC(tracee_p))) {
+ if (!erts_is_valid_tracer_port(ERTS_TRACER_PROC(tracee_p))) {
/* Current trace port now invalid
* - discard it and approve the new. */
goto remove_tracer;
} else
return 1;
}
- else if(is_internal_pid(tracee_p->tracer_proc)) {
- Process *tracer_p = erts_proc_lookup(tracee_p->tracer_proc);
+ else if(is_internal_pid(ERTS_TRACER_PROC(tracee_p))) {
+ Process *tracer_p;
+
+ tracer_p = erts_proc_lookup(ERTS_TRACER_PROC(tracee_p));
if (!tracer_p) {
/* Current trace process now invalid
* - discard it and approve the new. */
@@ -847,8 +892,8 @@ static int already_traced(Process *c_p, Process *tracee_p, Eterm tracer)
}
else {
remove_tracer:
- tracee_p->trace_flags &= ~TRACEE_FLAGS;
- tracee_p->tracer_proc = NIL;
+ ERTS_TRACE_FLAGS(tracee_p) &= ~TRACEE_FLAGS;
+ ERTS_TRACER_PROC(tracee_p) = NIL;
}
}
return 0;
@@ -892,8 +937,7 @@ trace_info_pid(Process* p, Eterm pid_spec, Eterm key)
if (pid_spec == am_new) {
erts_get_default_tracing(&trace_flags, &tracer);
- } else if (is_internal_pid(pid_spec)
- && internal_pid_index(pid_spec) < erts_max_processes) {
+ } else if (is_internal_pid(pid_spec)) {
Process *tracee;
tracee = erts_pid2proc(p, ERTS_PROC_LOCK_MAIN,
pid_spec, ERTS_PROC_LOCKS_ALL);
@@ -901,16 +945,16 @@ trace_info_pid(Process* p, Eterm pid_spec, Eterm key)
if (!tracee) {
return am_undefined;
} else {
- tracer = tracee->tracer_proc;
- trace_flags = tracee->trace_flags;
+ tracer = ERTS_TRACER_PROC(tracee);
+ trace_flags = ERTS_TRACE_FLAGS(tracee);
}
if (is_internal_pid(tracer)) {
if (!erts_proc_lookup(tracer)) {
reset_tracer:
- tracee->trace_flags &= ~TRACEE_FLAGS;
- trace_flags = tracee->trace_flags;
- tracer = tracee->tracer_proc = NIL;
+ ERTS_TRACE_FLAGS(tracee) &= ~TRACEE_FLAGS;
+ trace_flags = ERTS_TRACE_FLAGS(tracee);
+ tracer = ERTS_TRACER_PROC(tracee) = NIL;
}
}
else if (is_internal_port(tracer)) {
@@ -1530,7 +1574,7 @@ erts_set_trace_pattern(Process*p, Eterm* mfa, int specified,
int
erts_finish_breakpointing(void)
{
- ERTS_SMP_LC_ASSERT(erts_is_code_ix_locked());
+ ERTS_SMP_LC_ASSERT(erts_has_code_write_permission());
/*
* Memory barriers will be issued for all processes *before*
@@ -1538,7 +1582,6 @@ erts_finish_breakpointing(void)
* are blocked, in which case memory barriers will be issued
* when they are awaken.)
*/
-
switch (finish_bp.current++) {
case 0:
/*
@@ -1845,7 +1888,7 @@ new_seq_trace_token(Process* p)
SEQ_TRACE_TOKEN(p) = TUPLE5(hp, make_small(0), /* Flags */
make_small(0), /* Label */
make_small(0), /* Serial */
- p->id, /* Internal pid */ /* From */
+ p->common.id, /* Internal pid */ /* From */
make_small(p->seq_trace_lastcnt));
}
}
@@ -2215,9 +2258,11 @@ BIF_RETTYPE system_profile_2(BIF_ALIST_2)
if (!profiler_p)
goto error;
} else if (is_internal_port(profiler)) {
- if (internal_port_index(profiler) >= erts_max_ports) goto error;
- profiler_port = &erts_port[internal_port_index(profiler)];
- if (INVALID_TRACER_PORT(profiler_port, profiler)) goto error;
+ profiler_port = (erts_port_lookup(
+ profiler,
+ ERTS_PORT_SFLGS_INVALID_TRACER_LOOKUP));
+ if (!profiler_port)
+ goto error;
} else {
goto error;
}
@@ -2281,8 +2326,7 @@ trace_delivered_1(BIF_ALIST_1)
p = NULL;
} else if (! (p = erts_pid2proc(BIF_P, ERTS_PROC_LOCK_MAIN,
BIF_ARG_1, ERTS_PROC_LOCKS_ALL))) {
- if (is_not_internal_pid(BIF_ARG_1)
- || internal_pid_index(BIF_ARG_1) >= erts_max_processes) {
+ if (is_not_internal_pid(BIF_ARG_1)) {
BIF_ERROR(BIF_P, BADARG);
}
}
@@ -2301,7 +2345,7 @@ trace_delivered_1(BIF_ALIST_1)
msg = TUPLE3(hp, AM_trace_delivered, BIF_ARG_1, msg_ref);
#ifdef ERTS_SMP
- erts_send_sys_msg_proc(BIF_P->id, BIF_P->id, msg, bp);
+ erts_send_sys_msg_proc(BIF_P->common.id, BIF_P->common.id, msg, bp);
if (p)
erts_smp_proc_unlock(p,
(BIF_P == p
diff --git a/erts/emulator/beam/erl_bits.c b/erts/emulator/beam/erl_bits.c
index 6bc227eeda..3753b618e1 100644
--- a/erts/emulator/beam/erl_bits.c
+++ b/erts/emulator/beam/erl_bits.c
@@ -1247,6 +1247,12 @@ erts_bs_append(Process* c_p, Eterm* reg, Uint live, Eterm build_size_term,
*/
erts_bin_offset = 8*sb->size + sb->bitsize;
+ if (unit > 1) {
+ if ((unit == 8 && (erts_bin_offset & 7) != 0) ||
+ (erts_bin_offset % unit) != 0) {
+ goto badarg;
+ }
+ }
used_size_in_bits = erts_bin_offset + build_size_in_bits;
sb->is_writable = 0; /* Make sure that no one else can write. */
pb->size = NBYTES(used_size_in_bits);
@@ -1316,6 +1322,12 @@ erts_bs_append(Process* c_p, Eterm* reg, Uint live, Eterm build_size_term,
*/
ERTS_GET_BINARY_BYTES(bin, src_bytes, bitoffs, bitsize);
erts_bin_offset = 8*binary_size(bin) + bitsize;
+ if (unit > 1) {
+ if ((unit == 8 && (erts_bin_offset & 7) != 0) ||
+ (erts_bin_offset % unit) != 0) {
+ goto badarg;
+ }
+ }
used_size_in_bits = erts_bin_offset + build_size_in_bits;
used_size_in_bytes = NBYTES(used_size_in_bits);
bin_size = 2*used_size_in_bytes;
@@ -1363,12 +1375,6 @@ erts_bs_append(Process* c_p, Eterm* reg, Uint live, Eterm build_size_term,
/*
* Now copy the data into the binary.
*/
- if (unit > 1) {
- if ((unit == 8 && (erts_bin_offset & 7) != 0) ||
- (erts_bin_offset % unit) != 0) {
- return THE_NON_VALUE;
- }
- }
copy_binary_to_buffer(erts_current_bin, 0, src_bytes, bitoffs, erts_bin_offset);
return make_binary(sb);
diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c
index 4c30905495..48a95cdf32 100644
--- a/erts/emulator/beam/erl_db.c
+++ b/erts/emulator/beam/erl_db.c
@@ -251,7 +251,6 @@ free_dbtable(void *vtb)
#endif
ASSERT(is_immed(tb->common.heir_data));
erts_db_free(ERTS_ALC_T_DB_TABLE, tb, (void *) tb, sizeof(DbTable));
- ERTS_ETS_MISC_MEM_ADD(-sizeof(DbTable));
}
static void schedule_free_dbtable(DbTable* tb)
@@ -426,7 +425,8 @@ DbTable* db_get_table_aux(Process *p,
if (tb) {
db_lock(tb, kind);
if (tb->common.id != id
- || ((tb->common.status & what) == 0 && p->id != tb->common.owner)) {
+ || ((tb->common.status & what) == 0
+ && p->common.id != tb->common.owner)) {
db_unlock(tb, kind);
tb = NULL;
}
@@ -616,7 +616,7 @@ BIF_RETTYPE ets_safe_fixtable_2(BIF_ALIST_2)
#ifdef HARDDEBUG
erts_fprintf(stderr,
"ets:safe_fixtable(%T,%T); Process: %T, initial: %T:%T/%bpu\n",
- BIF_ARG_1, BIF_ARG_2, BIF_P->id,
+ BIF_ARG_1, BIF_ARG_2, BIF_P->common.id,
BIF_P->initial[0], BIF_P->initial[1], BIF_P->initial[2]);
#endif
kind = (BIF_ARG_2 == am_true) ? LCK_READ : LCK_WRITE_REC;
@@ -1195,7 +1195,7 @@ BIF_RETTYPE ets_rename_2(BIF_ALIST_2)
#ifdef HARDDEBUG
erts_fprintf(stderr,
"ets:rename(%T,%T); Process: %T, initial: %T:%T/%bpu\n",
- BIF_ARG_1, BIF_ARG_2, BIF_P->id,
+ BIF_ARG_1, BIF_ARG_2, BIF_P->common.id,
BIF_P->initial[0], BIF_P->initial[1], BIF_P->initial[2]);
#endif
@@ -1423,7 +1423,6 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2)
erts_smp_atomic_init_nob(&init_tb.common.memory_size, 0);
tb = (DbTable*) erts_db_alloc(ERTS_ALC_T_DB_TABLE,
&init_tb, sizeof(DbTable));
- ERTS_ETS_MISC_MEM_ADD(sizeof(DbTable));
erts_smp_atomic_init_nob(&tb->common.memory_size,
erts_smp_atomic_read_nob(&init_tb.common.memory_size));
}
@@ -1439,7 +1438,7 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2)
db_init_lock(tb, status & (DB_FINE_LOCKED|DB_FREQ_READ),
"db_tab", "db_tab_fix");
tb->common.keypos = keypos;
- tb->common.owner = BIF_P->id;
+ tb->common.owner = BIF_P->common.id;
set_heir(BIF_P, tb, heir, heir_data);
erts_smp_atomic_init_nob(&tb->common.nitems, 0);
@@ -1508,7 +1507,7 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2)
#ifdef HARDDEBUG
erts_fprintf(stderr,
"ets:new(%T,%T)=%T; Process: %T, initial: %T:%T/%bpu\n",
- BIF_ARG_1, BIF_ARG_2, ret, BIF_P->id,
+ BIF_ARG_1, BIF_ARG_2, ret, BIF_P->common.id,
BIF_P->initial[0], BIF_P->initial[1], BIF_P->initial[2]);
erts_fprintf(stderr, "ets: new: meta_pid_to_tab common.memory_size = %ld\n",
erts_smp_atomic_read_nob(&meta_pid_to_tab->common.memory_size));
@@ -1520,7 +1519,9 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2)
db_meta_lock(meta_pid_to_tab, LCK_WRITE_REC);
if (db_put_hash(meta_pid_to_tab,
- TUPLE2(meta_tuple, BIF_P->id, make_small(slot)),
+ TUPLE2(meta_tuple,
+ BIF_P->common.id,
+ make_small(slot)),
0) != DB_ERROR_NONE) {
erl_exit(1,"Could not update ets metadata.");
}
@@ -1639,7 +1640,7 @@ BIF_RETTYPE ets_delete_1(BIF_ALIST_1)
#ifdef HARDDEBUG
erts_fprintf(stderr,
"ets:delete(%T); Process: %T, initial: %T:%T/%bpu\n",
- BIF_ARG_1, BIF_P->id,
+ BIF_ARG_1, BIF_P->common.id,
BIF_P->initial[0], BIF_P->initial[1], BIF_P->initial[2]);
#endif
@@ -1656,7 +1657,7 @@ BIF_RETTYPE ets_delete_1(BIF_ALIST_1)
tb->common.status &= ~(DB_PROTECTED|DB_PUBLIC|DB_PRIVATE);
tb->common.status |= DB_DELETE;
- if (tb->common.owner != BIF_P->id) {
+ if (tb->common.owner != BIF_P->common.id) {
DeclareTmpHeap(meta_tuple,3,BIF_P);
/*
@@ -1671,10 +1672,12 @@ BIF_RETTYPE ets_delete_1(BIF_ALIST_1)
make_small(tb->common.slot));
BIF_P->flags |= F_USING_DB;
- tb->common.owner = BIF_P->id;
+ tb->common.owner = BIF_P->common.id;
db_put_hash(meta_pid_to_tab,
- TUPLE2(meta_tuple,BIF_P->id,make_small(tb->common.slot)),
+ TUPLE2(meta_tuple,
+ BIF_P->common.id,
+ make_small(tb->common.slot)),
0);
db_meta_unlock(meta_pid_to_tab, LCK_WRITE_REC);
UnUseTmpHeap(3,BIF_P);
@@ -1750,7 +1753,7 @@ BIF_RETTYPE ets_give_away_3(BIF_ALIST_3)
}
if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_WRITE, LCK_WRITE)) == NULL
- || tb->common.owner != BIF_P->id) {
+ || tb->common.owner != BIF_P->common.id) {
goto badarg;
}
from_pid = tb->common.owner;
@@ -1773,7 +1776,10 @@ BIF_RETTYPE ets_give_away_3(BIF_ALIST_3)
db_unlock(tb,LCK_WRITE);
erts_send_message(BIF_P, to_proc, &to_locks,
- TUPLE4(buf, am_ETS_TRANSFER, tb->common.id, from_pid, BIF_ARG_3),
+ TUPLE4(buf, am_ETS_TRANSFER,
+ tb->common.id,
+ from_pid,
+ BIF_ARG_3),
0);
erts_smp_proc_unlock(to_proc, to_locks);
UnUseTmpHeap(5,BIF_P);
@@ -1835,7 +1841,7 @@ BIF_RETTYPE ets_setopts_2(BIF_ALIST_2)
if (tail != NIL
|| (tb = db_get_table(BIF_P, BIF_ARG_1, DB_WRITE, LCK_WRITE)) == NULL
- || tb->common.owner != BIF_P->id) {
+ || tb->common.owner != BIF_P->common.id) {
goto badarg;
}
@@ -2649,7 +2655,7 @@ BIF_RETTYPE ets_info_1(BIF_ALIST_1)
*/
/* If/when we implement lockless private tables:
- if ((tb->common.status & DB_PRIVATE) && owner != BIF_P->id) {
+ if ((tb->common.status & DB_PRIVATE) && owner != BIF_P->common.id) {
db_unlock(tb, LCK_READ);
rp = erts_pid2proc_not_running(BIF_P, ERTS_PROC_LOCK_MAIN,
owner, ERTS_PROC_LOCK_MAIN);
@@ -2867,7 +2873,6 @@ void init_db(void)
meta_pid_to_tab = (DbTable*) erts_db_alloc(ERTS_ALC_T_DB_TABLE,
&init_tb,
sizeof(DbTable));
- ERTS_ETS_MISC_MEM_ADD(sizeof(DbTable));
erts_smp_atomic_init_nob(&meta_pid_to_tab->common.memory_size,
erts_smp_atomic_read_nob(&init_tb.common.memory_size));
@@ -2899,7 +2904,6 @@ void init_db(void)
meta_pid_to_fixed_tab = (DbTable*) erts_db_alloc(ERTS_ALC_T_DB_TABLE,
&init_tb,
sizeof(DbTable));
- ERTS_ETS_MISC_MEM_ADD(sizeof(DbTable));
erts_smp_atomic_init_nob(&meta_pid_to_fixed_tab->common.memory_size,
erts_smp_atomic_read_nob(&init_tb.common.memory_size));
@@ -3043,9 +3047,9 @@ static int give_away_to_heir(Process* p, DbTable* tb)
Eterm to_pid;
UWord heir_data;
- ASSERT(tb->common.owner == p->id);
+ ASSERT(tb->common.owner == p->common.id);
ASSERT(is_internal_pid(tb->common.heir));
- ASSERT(tb->common.heir != p->id);
+ ASSERT(tb->common.heir != p->common.id);
retry:
to_pid = tb->common.heir;
to_proc = erts_pid2proc_opt(p, ERTS_PROC_LOCK_MAIN,
@@ -3058,7 +3062,7 @@ retry:
db_lock(tb,LCK_WRITE);
ASSERT(tb != NULL);
- if (tb->common.owner != p->id) {
+ if (tb->common.owner != p->common.id) {
if (to_proc != NULL ) {
erts_smp_proc_unlock(to_proc, to_locks);
}
@@ -3069,7 +3073,7 @@ retry:
if (to_proc != NULL ) {
erts_smp_proc_unlock(to_proc, to_locks);
}
- if (to_pid == p->id || to_pid == am_none) {
+ if (to_pid == p->common.id || to_pid == am_none) {
return 0; /* no real heir, table still mine */
}
goto retry;
@@ -3078,7 +3082,8 @@ retry:
if (to_proc == NULL) {
return 0; /* heir not alive, table still mine */
}
- if (to_proc->started_interval != tb->common.heir_started_interval) {
+ if (to_proc->common.u.alive.started_interval
+ != tb->common.heir_started_interval) {
erts_smp_proc_unlock(to_proc, to_locks);
return 0; /* heir dead and pid reused, table still mine */
}
@@ -3103,7 +3108,11 @@ retry:
heir_data = tpv[1];
}
erts_send_message(p, to_proc, &to_locks,
- TUPLE4(buf, am_ETS_TRANSFER, tb->common.id, p->id, heir_data),
+ TUPLE4(buf,
+ am_ETS_TRANSFER,
+ tb->common.id,
+ p->common.id,
+ heir_data),
0);
erts_smp_proc_unlock(to_proc, to_locks);
return !0;
@@ -3112,7 +3121,7 @@ retry:
/*
* erts_db_process_exiting() is called when a process terminates.
* It returns 0 when completely done, and !0 when it wants to
- * yield. c_p->u.exit_data can hold a pointer to a state while
+ * yield. c_p->u.terminate can hold a pointer to a state while
* yielding.
*/
#define ERTS_DB_INTERNAL_ERROR(LSTR) \
@@ -3122,8 +3131,8 @@ retry:
int
erts_db_process_exiting(Process *c_p, ErtsProcLocks c_p_locks)
{
- ErtsDbProcCleanupState *state = (ErtsDbProcCleanupState *) c_p->u.exit_data;
- Eterm pid = c_p->id;
+ ErtsDbProcCleanupState *state = (ErtsDbProcCleanupState *) c_p->u.terminate;
+ Eterm pid = c_p->common.id;
ErtsDbProcCleanupState default_state;
int ret;
@@ -3304,7 +3313,7 @@ erts_db_process_exiting(Process *c_p, ErtsProcLocks c_p_locks)
if (state != &default_state)
erts_free(ERTS_ALC_T_DB_PROC_CLEANUP, state);
- c_p->u.exit_data = NULL;
+ c_p->u.terminate = NULL;
return 0;
default:
@@ -3325,13 +3334,13 @@ erts_db_process_exiting(Process *c_p, ErtsProcLocks c_p_locks)
break;
}
- ASSERT(c_p->u.exit_data == (void *) state
+ ASSERT(c_p->u.terminate == (void *) state
|| state == &default_state);
if (state == &default_state) {
- c_p->u.exit_data = erts_alloc(ERTS_ALC_T_DB_PROC_CLEANUP,
+ c_p->u.terminate = erts_alloc(ERTS_ALC_T_DB_PROC_CLEANUP,
sizeof(ErtsDbProcCleanupState));
- sys_memcpy(c_p->u.exit_data,
+ sys_memcpy(c_p->u.terminate,
(void*) state,
sizeof(ErtsDbProcCleanupState));
}
@@ -3357,7 +3366,7 @@ static void fix_table_locked(Process* p, DbTable* tb)
}
else {
for (; fix != NULL; fix = fix->next) {
- if (fix->pid == p->id) {
+ if (fix->pid == p->common.id) {
++(fix->counter);
#ifdef ERTS_SMP
erts_smp_mtx_unlock(&tb->common.fixlock);
@@ -3369,7 +3378,7 @@ static void fix_table_locked(Process* p, DbTable* tb)
fix = (DbFixation *) erts_db_alloc(ERTS_ALC_T_DB_FIXATION,
tb, sizeof(DbFixation));
ERTS_ETS_MISC_MEM_ADD(sizeof(DbFixation));
- fix->pid = p->id;
+ fix->pid = p->common.id;
fix->counter = 1;
fix->next = tb->common.fixations;
tb->common.fixations = fix;
@@ -3380,7 +3389,9 @@ static void fix_table_locked(Process* p, DbTable* tb)
UseTmpHeap(3,p);
db_meta_lock(meta_pid_to_fixed_tab, LCK_WRITE_REC);
if (db_put_hash(meta_pid_to_fixed_tab,
- TUPLE2(meta_tuple, p->id, make_small(tb->common.slot)),
+ TUPLE2(meta_tuple,
+ p->common.id,
+ make_small(tb->common.slot)),
0) != DB_ERROR_NONE) {
UnUseTmpHeap(3,p);
erl_exit(1,"Could not insert ets metadata in safe_fixtable.");
@@ -3400,7 +3411,7 @@ static void unfix_table_locked(Process* p, DbTable* tb,
erts_smp_mtx_lock(&tb->common.fixlock);
#endif
for (pp = &tb->common.fixations; *pp != NULL; pp = &(*pp)->next) {
- if ((*pp)->pid == p->id) {
+ if ((*pp)->pid == p->common.id) {
DbFixation* fix = *pp;
erts_refc_dec(&tb->common.ref,0);
--(fix->counter);
@@ -3414,7 +3425,7 @@ static void unfix_table_locked(Process* p, DbTable* tb,
#endif
db_meta_lock(meta_pid_to_fixed_tab, LCK_WRITE_REC);
db_erase_bag_exact2(meta_pid_to_fixed_tab,
- p->id, make_small(tb->common.slot));
+ p->common.id, make_small(tb->common.slot));
db_meta_unlock(meta_pid_to_fixed_tab, LCK_WRITE_REC);
erts_db_free(ERTS_ALC_T_DB_FIXATION,
tb, (void *) fix, sizeof(DbFixation));
@@ -3473,15 +3484,15 @@ static void set_heir(Process* me, DbTable* tb, Eterm heir, UWord heir_data)
if (heir == am_none) {
return;
}
- if (heir == me->id) {
- erts_ensure_later_proc_interval(me->started_interval);
- tb->common.heir_started_interval = me->started_interval;
+ if (heir == me->common.id) {
+ erts_ensure_later_proc_interval(me->common.u.alive.started_interval);
+ tb->common.heir_started_interval = me->common.u.alive.started_interval;
}
else {
Process* heir_proc= erts_proc_lookup(heir);
if (heir_proc != NULL) {
- erts_ensure_later_proc_interval(heir_proc->started_interval);
- tb->common.heir_started_interval = heir_proc->started_interval;
+ erts_ensure_later_proc_interval(heir_proc->common.u.alive.started_interval);
+ tb->common.heir_started_interval = heir_proc->common.u.alive.started_interval;
} else {
tb->common.heir = am_none;
}
diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c
index 0c9ca83ce4..bb08762b26 100644
--- a/erts/emulator/beam/erl_db_util.c
+++ b/erts/emulator/beam/erl_db_util.c
@@ -138,21 +138,23 @@ set_tracee_flags(Process *tracee_p, Eterm tracer, Uint d_flags, Uint e_flags) {
Uint flags;
if (tracer == NIL) {
- flags = tracee_p->trace_flags & ~TRACEE_FLAGS;
+ flags = ERTS_TRACE_FLAGS(tracee_p) & ~TRACEE_FLAGS;
} else {
- flags = ((tracee_p->trace_flags & ~d_flags) | e_flags);
+ flags = ((ERTS_TRACE_FLAGS(tracee_p) & ~d_flags) | e_flags);
if (! flags) tracer = NIL;
}
- ret = tracee_p->tracer_proc != tracer || tracee_p->trace_flags != flags
- ? am_true : am_false;
- tracee_p->tracer_proc = tracer;
- tracee_p->trace_flags = flags;
+ ret = ((ERTS_TRACER_PROC(tracee_p) != tracer
+ || ERTS_TRACE_FLAGS(tracee_p) != flags)
+ ? am_true
+ : am_false);
+ ERTS_TRACER_PROC(tracee_p) = tracer;
+ ERTS_TRACE_FLAGS(tracee_p) = flags;
return ret;
}
/*
** Assuming all locks on tracee_p on entry
**
-** Changes tracee_p->trace_flags and tracee_p->tracer_proc
+** Changes ERTS_TRACE_FLAGS(tracee_p) and ERTS_TRACER_PROC(tracee_p)
** according to input disable/enable flags and tracer.
**
** Returns am_true|am_false on success, am_true if value changed,
@@ -173,17 +175,20 @@ set_match_trace(Process *tracee_p, Eterm fail_term, Eterm tracer,
tracer, ERTS_PROC_LOCKS_ALL))) {
if (tracee_p != tracer_p) {
ret = set_tracee_flags(tracee_p, tracer, d_flags, e_flags);
- tracer_p->trace_flags |= tracee_p->trace_flags ? F_TRACER : 0;
+ ERTS_TRACE_FLAGS(tracer_p) |= (ERTS_TRACE_FLAGS(tracee_p)
+ ? F_TRACER
+ : 0);
erts_smp_proc_unlock(tracer_p, ERTS_PROC_LOCKS_ALL);
}
} else if (is_internal_port(tracer)) {
Port *tracer_port =
- erts_id2port(tracer, tracee_p, ERTS_PROC_LOCKS_ALL);
+ erts_id2port_sflgs(tracer,
+ tracee_p,
+ ERTS_PROC_LOCKS_ALL,
+ ERTS_PORT_SFLGS_INVALID_TRACER_LOOKUP);
if (tracer_port) {
- if (! INVALID_TRACER_PORT(tracer_port, tracer)) {
- ret = set_tracee_flags(tracee_p, tracer, d_flags, e_flags);
- }
- erts_smp_port_unlock(tracer_port);
+ ret = set_tracee_flags(tracee_p, tracer, d_flags, e_flags);
+ erts_port_release(tracer_port);
}
} else {
ASSERT(is_nil(tracer));
@@ -2174,7 +2179,7 @@ restart:
pc += n;
break;
case matchSelf:
- *esp++ = c_p->id;
+ *esp++ = c_p->common.id;
break;
case matchWaste:
--esp;
@@ -2261,7 +2266,7 @@ restart:
case matchEnableTrace:
if ( (n = erts_trace_flag2bit(esp[-1]))) {
BEGIN_ATOMIC_TRACE(c_p);
- set_tracee_flags(c_p, c_p->tracer_proc, 0, n);
+ set_tracee_flags(c_p, ERTS_TRACER_PROC(c_p), 0, n);
esp[-1] = am_true;
} else {
esp[-1] = FAIL_TERM;
@@ -2274,7 +2279,7 @@ restart:
BEGIN_ATOMIC_TRACE(c_p);
if ( (tmpp = get_proc(c_p, 0, esp[0], 0))) {
/* Always take over the tracer of the current process */
- set_tracee_flags(tmpp, c_p->tracer_proc, 0, n);
+ set_tracee_flags(tmpp, ERTS_TRACER_PROC(c_p), 0, n);
esp[-1] = am_true;
}
}
@@ -2282,7 +2287,7 @@ restart:
case matchDisableTrace:
if ( (n = erts_trace_flag2bit(esp[-1]))) {
BEGIN_ATOMIC_TRACE(c_p);
- set_tracee_flags(c_p, c_p->tracer_proc, n, 0);
+ set_tracee_flags(c_p, ERTS_TRACER_PROC(c_p), n, 0);
esp[-1] = am_true;
} else {
esp[-1] = FAIL_TERM;
@@ -2295,7 +2300,7 @@ restart:
BEGIN_ATOMIC_TRACE(c_p);
if ( (tmpp = get_proc(c_p, 0, esp[0], 0))) {
/* Always take over the tracer of the current process */
- set_tracee_flags(tmpp, c_p->tracer_proc, n, 0);
+ set_tracee_flags(tmpp, ERTS_TRACER_PROC(c_p), n, 0);
esp[-1] = am_true;
}
}
@@ -2316,12 +2321,12 @@ restart:
--esp;
if (*esp == am_true) {
erts_smp_proc_lock(c_p, ERTS_PROC_LOCKS_ALL_MINOR);
- c_p->trace_flags |= F_TRACE_SILENT;
+ ERTS_TRACE_FLAGS(c_p) |= F_TRACE_SILENT;
erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_ALL_MINOR);
}
else if (*esp == am_false) {
erts_smp_proc_lock(c_p, ERTS_PROC_LOCKS_ALL_MINOR);
- c_p->trace_flags &= ~F_TRACE_SILENT;
+ ERTS_TRACE_FLAGS(c_p) &= ~F_TRACE_SILENT;
erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_ALL_MINOR);
}
break;
@@ -2329,11 +2334,11 @@ restart:
{
/* disable enable */
Uint d_flags = 0, e_flags = 0; /* process trace flags */
- Eterm tracer = c_p->tracer_proc;
+ Eterm tracer = ERTS_TRACER_PROC(c_p);
/* XXX Atomicity note: Not fully atomic. Default tracer
* is sampled from current process but applied to
* tracee and tracer later after releasing main
- * locks on current process, so c_p->tracer_proc
+ * locks on current process, so ERTS_TRACER_PROC(c_p)
* may actually have changed when tracee and tracer
* gets updated. I do not think nobody will notice.
* It is just the default value that is not fully atomic.
@@ -2358,7 +2363,7 @@ restart:
{
/* disable enable */
Uint d_flags = 0, e_flags = 0; /* process trace flags */
- Eterm tracer = c_p->tracer_proc;
+ Eterm tracer = ERTS_TRACER_PROC(c_p);
/* XXX Atomicity note. Not fully atomic. See above.
* Above it could possibly be solved, but not here.
*/
@@ -5004,7 +5009,7 @@ static Eterm match_spec_test(Process *p, Eterm against, Eterm spec, int trace)
static Eterm seq_trace_fake(Process *p, Eterm arg1)
{
Eterm result = erl_seq_trace_info(p, arg1);
- if (is_tuple(result) && *tuple_val(result) == 2) {
+ if (!is_non_value(result) && is_tuple(result) && *tuple_val(result) == 2) {
return (tuple_val(result))[2];
}
return result;
diff --git a/erts/emulator/beam/erl_db_util.h b/erts/emulator/beam/erl_db_util.h
index dcecc4251a..d8f6e40d2e 100644
--- a/erts/emulator/beam/erl_db_util.h
+++ b/erts/emulator/beam/erl_db_util.h
@@ -320,10 +320,10 @@ ERTS_GLB_INLINE int db_eq(DbTableCommon* tb, Eterm a, DbTerm* b)
#define DB_INFO (DB_PROTECTED|DB_PUBLIC|DB_PRIVATE)
#define ONLY_WRITER(P,T) (((T)->common.status & (DB_PRIVATE|DB_PROTECTED)) \
- && (T)->common.owner == (P)->id)
+ && (T)->common.owner == (P)->common.id)
#define ONLY_READER(P,T) (((T)->common.status & DB_PRIVATE) && \
-(T)->common.owner == (P)->id)
+(T)->common.owner == (P)->common.id)
/* Function prototypes */
BIF_RETTYPE db_get_trace_control_word(Process* p);
diff --git a/erts/emulator/beam/erl_debug.c b/erts/emulator/beam/erl_debug.c
index 22e873afc6..b90d00f236 100644
--- a/erts/emulator/beam/erl_debug.c
+++ b/erts/emulator/beam/erl_debug.c
@@ -252,16 +252,16 @@ void erts_check_stack(Process *p)
if (p->stop > stack_start)
erl_exit(1,
"<%lu.%lu.%lu>: Stack underflow\n",
- internal_pid_channel_no(p->id),
- internal_pid_number(p->id),
- internal_pid_serial(p->id));
+ internal_pid_channel_no(p->common.id),
+ internal_pid_number(p->common.id),
+ internal_pid_serial(p->common.id));
if (p->stop < stack_end)
erl_exit(1,
"<%lu.%lu.%lu>: Stack overflow\n",
- internal_pid_channel_no(p->id),
- internal_pid_number(p->id),
- internal_pid_serial(p->id));
+ internal_pid_channel_no(p->common.id),
+ internal_pid_number(p->common.id),
+ internal_pid_serial(p->common.id));
for (elemp = p->stop; elemp < stack_start; elemp++) {
int in_mbuf = 0;
@@ -284,9 +284,9 @@ void erts_check_stack(Process *p)
erl_exit(1,
"<%lu.%lu.%lu>: Wild stack pointer\n",
- internal_pid_channel_no(p->id),
- internal_pid_number(p->id),
- internal_pid_serial(p->id));
+ internal_pid_channel_no(p->common.id),
+ internal_pid_number(p->common.id),
+ internal_pid_serial(p->common.id));
}
}
@@ -387,16 +387,16 @@ void verify_process(Process *p)
#define VERIFY_AREA(name,ptr,sz) { \
int n = (sz); \
while (n--) if(!verify_eterm(p,*(ptr+n))) \
- erl_exit(1,"Wild pointer found in " name " of %T!\n",p->id); }
+ erl_exit(1,"Wild pointer found in " name " of %T!\n",p->common.id); }
#define VERIFY_ETERM(name,eterm) { \
if(!verify_eterm(p,eterm)) \
- erl_exit(1,"Wild pointer found in " name " of %T!\n",p->id); }
+ erl_exit(1,"Wild pointer found in " name " of %T!\n",p->common.id); }
ErlMessage* mp = p->msg.first;
- VERBOSE(DEBUG_MEMORY,("Verify process: %T...\n",p->id));
+ VERBOSE(DEBUG_MEMORY,("Verify process: %T...\n",p->common.id));
while (mp != NULL) {
VERIFY_ETERM("message term",ERL_MESSAGE_TERM(mp));
@@ -516,7 +516,7 @@ static void print_process_memory(Process *p)
ErlHeapFragment* bp = MBUF(p);
erts_printf("==============================\n");
- erts_printf("|| Memory info for %T ||\n",p->id);
+ erts_printf("|| Memory info for %T ||\n",p->common.id);
erts_printf("==============================\n");
erts_printf("-- %-*s ---%s-%s-%s-%s--\n",
@@ -601,7 +601,7 @@ void print_memory_info(Process *p)
{
if (p != NULL) {
erts_printf("======================================\n");
- erts_printf("|| Memory info for %-12T ||\n",p->id);
+ erts_printf("|| Memory info for %-12T ||\n",p->common.id);
erts_printf("======================================\n");
erts_printf("+- local heap ----%s-%s-%s-%s-+\n",
dashes,dashes,dashes,dashes);
diff --git a/erts/emulator/beam/erl_driver.h b/erts/emulator/beam/erl_driver.h
index 771ee46d2b..d50ba364d0 100644
--- a/erts/emulator/beam/erl_driver.h
+++ b/erts/emulator/beam/erl_driver.h
@@ -85,7 +85,7 @@
#include "erl_drv_nif.h"
#include <stdlib.h>
-#include <string.h> /* ssize_t on Mac OS X */
+#include <sys/types.h> /* ssize_t */
#if defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_)
#ifndef STATIC_ERLANG_DRIVER
@@ -133,7 +133,7 @@ typedef struct {
#define ERL_DRV_EXTENDED_MARKER (0xfeeeeeed)
#define ERL_DRV_EXTENDED_MAJOR_VERSION 2
-#define ERL_DRV_EXTENDED_MINOR_VERSION 0
+#define ERL_DRV_EXTENDED_MINOR_VERSION 1
/*
* The emulator will refuse to load a driver with different major
@@ -154,6 +154,7 @@ typedef struct {
#define ERL_DRV_FLAG_USE_PORT_LOCKING (1 << 0)
#define ERL_DRV_FLAG_SOFT_BUSY (1 << 1)
+#define ERL_DRV_FLAG_NO_BUSY_MSGQ (1 << 2)
/*
* Integer types
@@ -207,8 +208,8 @@ typedef struct erl_drv_binary {
typedef struct _erl_drv_data* ErlDrvData; /* Data to be used by the driver itself. */
#ifndef ERL_SYS_DRV
typedef struct _erl_drv_event* ErlDrvEvent; /* An event to be selected on. */
-typedef struct _erl_drv_port* ErlDrvPort; /* A port descriptor. */
#endif
+typedef struct _erl_drv_port* ErlDrvPort; /* A port descriptor. */
typedef struct _erl_drv_port* ErlDrvThreadData; /* Thread data. */
#if !defined(__WIN32__) && !defined(_WIN32) && !defined(_WIN32_) && !defined(USE_SELECT)
@@ -377,9 +378,18 @@ typedef struct erl_drv_entry {
ErlDrvEntry* driver_init(void)
#endif
+#define ERL_DRV_BUSY_MSGQ_DISABLED (~((ErlDrvSizeT) 0))
+#define ERL_DRV_BUSY_MSGQ_READ_ONLY ((ErlDrvSizeT) 0)
+#define ERL_DRV_BUSY_MSGQ_LIM_MAX (ERL_DRV_BUSY_MSGQ_DISABLED - 1)
+#define ERL_DRV_BUSY_MSGQ_LIM_MIN ((ErlDrvSizeT) 1)
+
/*
* These are the functions available for driver writers.
*/
+EXTERN void erl_drv_busy_msgq_limits(ErlDrvPort port,
+ ErlDrvSizeT *low,
+ ErlDrvSizeT *high);
+
EXTERN int driver_select(ErlDrvPort port, ErlDrvEvent event, int mode, int on);
EXTERN int driver_event(ErlDrvPort port, ErlDrvEvent event,
ErlDrvEventData event_data);
@@ -594,11 +604,33 @@ EXTERN ErlDrvPort driver_create_port(ErlDrvPort creator_port,
ErlDrvData drv_data);
+/*
+ * driver_output_term() is deprecated, and scheduled for removal in
+ * OTP-R17. Use erl_drv_output_term() instead. For more information
+ * see the erl_driver(3) documentation.
+ */
+EXTERN int driver_output_term(ErlDrvPort ix,
+ ErlDrvTermData* data,
+ int len) ERL_DRV_DEPRECATED_FUNC;
+/*
+ * driver_send_term() is deprecated, and scheduled for removal in
+ * OTP-R17. Use erl_drv_send_term() instead. For more information
+ * see the erl_driver(3) documentation.
+ */
+EXTERN int driver_send_term(ErlDrvPort ix,
+ ErlDrvTermData to,
+ ErlDrvTermData* data,
+ int len) ERL_DRV_DEPRECATED_FUNC;
+
/* output term data to the port owner */
-EXTERN int driver_output_term(ErlDrvPort ix, ErlDrvTermData* data, int len);
+EXTERN int erl_drv_output_term(ErlDrvTermData port,
+ ErlDrvTermData* data,
+ int len);
/* output term data to a specific process */
-EXTERN int driver_send_term(ErlDrvPort ix, ErlDrvTermData to,
- ErlDrvTermData* data, int len);
+EXTERN int erl_drv_send_term(ErlDrvTermData port,
+ ErlDrvTermData to,
+ ErlDrvTermData* data,
+ int len);
/* Async IO functions */
EXTERN long driver_async(ErlDrvPort ix,
diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c
index 6075a527c3..a33085315a 100644
--- a/erts/emulator/beam/erl_gc.c
+++ b/erts/emulator/beam/erl_gc.c
@@ -59,7 +59,7 @@ static Uint reclaimed; /* no of words reclaimed in GCs */
erts_fprintf(stderr, "htop=%p\n", (p)->htop); \
erts_fprintf(stderr, "heap=%p\n", (p)->heap); \
erl_exit(ERTS_ABORT_EXIT, "%s, line %d: %T: Overrun stack and heap\n", \
- __FILE__,__LINE__,(P)->id); \
+ __FILE__,__LINE__,(P)->common.id); \
}
#ifdef DEBUG
@@ -129,7 +129,7 @@ static void disallow_heap_frag_ref(Process* p, Eterm* n_htop, Eterm* objv, int n
#if defined(ARCH_64) && !HALFWORD_HEAP
# define MAX_HEAP_SIZES 154
#else
-# define MAX_HEAP_SIZES 55
+# define MAX_HEAP_SIZES 59
#endif
static Sint heap_sizes[MAX_HEAP_SIZES]; /* Suitable heap sizes. */
@@ -144,6 +144,7 @@ void
erts_init_gc(void)
{
int i = 0;
+ Sint max_heap_size = 0;
ASSERT(offsetof(ProcBin,thing_word) == offsetof(struct erl_off_heap_header,thing_word));
ASSERT(offsetof(ProcBin,thing_word) == offsetof(ErlFunThing,thing_word));
@@ -168,16 +169,30 @@ erts_init_gc(void)
* we really don't want that growth when the heaps are that big.
*/
- heap_sizes[0] = 34;
- heap_sizes[1] = 55;
- for (i = 2; i < 23; i++) {
- heap_sizes[i] = heap_sizes[i-1] + heap_sizes[i-2];
+ /* Growth stage 1 - Fibonacci + 1*/
+ /* 12,38 will hit size 233, the old default */
+
+ heap_sizes[0] = 12;
+ heap_sizes[1] = 38;
+
+ for(i = 2; i < 23; i++) {
+ /* one extra word for block header */
+ heap_sizes[i] = heap_sizes[i-1] + heap_sizes[i-2] + 1;
}
+
+ /* for 32 bit we want max_heap_size to be MAX(32bit) / 4 [words] (and halfword)
+ * for 64 bit we want max_heap_size to be MAX(52bit) / 8 [words]
+ */
+
+ max_heap_size = sizeof(Eterm) < 8 ? (Sint)((~(Uint)0)/(sizeof(Eterm))) :
+ (Sint)(((Uint64)1 << 53)/sizeof(Eterm));
+
+ /* Growth stage 2 - 20% growth */
/* At 1.3 mega words heap, we start to slow down. */
for (i = 23; i < ALENGTH(heap_sizes); i++) {
- heap_sizes[i] = 5*(heap_sizes[i-1]/4);
- if (heap_sizes[i] < 0) {
+ heap_sizes[i] = heap_sizes[i-1] + heap_sizes[i-1]/5;
+ if ((heap_sizes[i] < 0) || heap_sizes[i] > max_heap_size) {
/* Size turned negative. Discard this last size. */
i--;
break;
@@ -336,6 +351,19 @@ erts_gc_after_bif_call(Process* p, Eterm result, Eterm* regs, Uint arity)
return result;
}
+static ERTS_INLINE void reset_active_writer(Process *p)
+{
+ struct erl_off_heap_header* ptr;
+ ptr = MSO(p).first;
+ while (ptr) {
+ if (ptr->thing_word == HEADER_PROC_BIN) {
+ ProcBin *pbp = (ProcBin*) ptr;
+ pbp->flags &= ~PB_ACTIVE_WRITER;
+ }
+ ptr = ptr->next;
+ }
+}
+
/*
* Garbage collect a process.
*
@@ -391,6 +419,7 @@ erts_garbage_collect(Process* p, int need, Eterm* objv, int nobj)
DTRACE2(gc_minor_end, pidbuf, reclaimed_now);
}
}
+ reset_active_writer(p);
/*
* Finish.
@@ -854,14 +883,12 @@ minor_collection(Process* p, int need, Eterm* objv, int nobj, Uint *recl)
}
}
- if (wanted < MIN_HEAP_SIZE(p)) {
- wanted = MIN_HEAP_SIZE(p);
- } else {
- wanted = next_heap_size(p, wanted, 0);
- }
+ wanted = wanted < MIN_HEAP_SIZE(p) ? MIN_HEAP_SIZE(p)
+ : next_heap_size(p, wanted, 0);
if (wanted < HEAP_SIZE(p)) {
shrink_new_heap(p, wanted, objv, nobj);
}
+
ASSERT(HEAP_SIZE(p) == next_heap_size(p, HEAP_SIZE(p), 0));
return 1; /* We are done. */
}
@@ -1420,11 +1447,10 @@ adjust_after_fullsweep(Process *p, Uint size_before, int need, Eterm *objv, int
I think this is better as fullsweep is used mainly on
small memory systems, but I could be wrong... */
wanted = 2 * need_after;
- if (wanted < p->min_heap_size) {
- sz = p->min_heap_size;
- } else {
- sz = next_heap_size(p, wanted, 0);
- }
+
+ sz = wanted < p->min_heap_size ? p->min_heap_size
+ : next_heap_size(p, wanted, 0);
+
if (sz < HEAP_SIZE(p)) {
shrink_new_heap(p, sz, objv, nobj);
}
@@ -1932,9 +1958,9 @@ setup_rootset(Process *p, Eterm *objv, int nobj, Rootset *rootset)
n++;
}
#endif
- ASSERT(is_nil(p->tracer_proc) ||
- is_internal_pid(p->tracer_proc) ||
- is_internal_port(p->tracer_proc));
+ ASSERT(is_nil(ERTS_TRACER_PROC(p)) ||
+ is_internal_pid(ERTS_TRACER_PROC(p)) ||
+ is_internal_port(ERTS_TRACER_PROC(p)));
ASSERT(is_pid(follow_moved(p->group_leader)));
if (is_not_immed(p->group_leader)) {
@@ -2166,7 +2192,6 @@ link_live_proc_bin(struct shrink_cand_data *shrink,
if (pbp->flags & PB_ACTIVE_WRITER) {
- pbp->flags &= ~PB_ACTIVE_WRITER;
shrink->no_of_active++;
}
else { /* inactive */
diff --git a/erts/emulator/beam/erl_goodfit_alloc.c b/erts/emulator/beam/erl_goodfit_alloc.c
index e7d4ac2b67..f98d377fd6 100644
--- a/erts/emulator/beam/erl_goodfit_alloc.c
+++ b/erts/emulator/beam/erl_goodfit_alloc.c
@@ -205,7 +205,6 @@ erts_gfalc_start(GFAllctr_t *gfallctr,
init->sbmbct = 0; /* Small mbc not yet supported by goodfit */
- allctr->mbc_header_size = sizeof(Carrier_t);
allctr->min_mbc_size = MIN_MBC_SZ;
allctr->min_mbc_first_free_size = MIN_MBC_FIRST_FREE_SZ;
allctr->min_block_size = sizeof(GFFreeBlock_t);
@@ -363,7 +362,7 @@ search_bucket(Allctr_t *allctr, int ix, Uint size)
blk && i < max_blk_search;
blk = blk->next, i++) {
- blk_sz = BLK_SZ(blk);
+ blk_sz = MBC_FBLK_SZ(&blk->block_head);
blk_on_lambc = (((char *) blk) < gfallctr->last_aux_mbc_end
&& gfallctr->last_aux_mbc_start <= ((char *) blk));
@@ -402,7 +401,7 @@ get_free_block(Allctr_t *allctr, Uint size,
if (min_bi == unsafe_bi) {
blk = search_bucket(allctr, min_bi, size);
if (blk) {
- if (cand_blk && cand_size <= BLK_SZ(blk))
+ if (cand_blk && cand_size <= MBC_FBLK_SZ(blk))
return NULL; /* cand_blk was better */
unlink_free_block(allctr, blk, flags);
return blk;
@@ -422,7 +421,7 @@ get_free_block(Allctr_t *allctr, Uint size,
/* We are guaranteed to find a block that fits in this bucket */
blk = search_bucket(allctr, min_bi, size);
ASSERT(blk);
- if (cand_blk && cand_size <= BLK_SZ(blk))
+ if (cand_blk && cand_size <= MBC_FBLK_SZ(blk))
return NULL; /* cand_blk was better */
unlink_free_block(allctr, blk, flags);
return blk;
@@ -435,7 +434,7 @@ link_free_block(Allctr_t *allctr, Block_t *block, Uint32 flags)
{
GFAllctr_t *gfallctr = (GFAllctr_t *) allctr;
GFFreeBlock_t *blk = (GFFreeBlock_t *) block;
- Uint sz = BLK_SZ(blk);
+ Uint sz = MBC_FBLK_SZ(&blk->block_head);
int i = BKT_IX(gfallctr, sz);
ASSERT(sz >= MIN_BLK_SZ);
@@ -456,7 +455,7 @@ unlink_free_block(Allctr_t *allctr, Block_t *block, Uint32 flags)
{
GFAllctr_t *gfallctr = (GFAllctr_t *) allctr;
GFFreeBlock_t *blk = (GFFreeBlock_t *) block;
- Uint sz = BLK_SZ(blk);
+ Uint sz = MBC_FBLK_SZ(&blk->block_head);
int i = BKT_IX(gfallctr, sz);
if (!blk->prev) {
@@ -618,7 +617,7 @@ check_block(Allctr_t *allctr, Block_t * blk, int free_block)
GFFreeBlock_t *fblk;
if(free_block) {
- Uint blk_sz = BLK_SZ(blk);
+ Uint blk_sz = is_sbc_blk(blk) ? SBC_BLK_SZ(blk) : MBC_BLK_SZ(blk);
bi = BKT_IX(gfallctr, blk_sz);
ASSERT(gfallctr->bucket_mask.main & (((UWord) 1) << IX2SMIX(bi)));
diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c
index 4b90e5394a..8cdf954dd2 100644
--- a/erts/emulator/beam/erl_init.c
+++ b/erts/emulator/beam/erl_init.c
@@ -44,6 +44,7 @@
#include "erl_thr_progress.h"
#include "erl_thr_queue.h"
#include "erl_async.h"
+#include "erl_ptab.h"
#ifdef HIPE
#include "hipe_mode_switch.h" /* for hipe_mode_switch_init() */
@@ -109,6 +110,11 @@ const int etp_lock_check = 1;
#else
const int etp_lock_check = 0;
#endif
+#ifdef WORDS_BIGENDIAN
+const int etp_big_endian = 1;
+#else
+const int etp_big_endian = 0;
+#endif
/*
* Note about VxWorks: All variables must be initialized by executable code,
* not by an initializer. Otherwise a new instance of the emulator will
@@ -121,9 +127,10 @@ extern void ConNormalExit(void);
extern void ConWaitForExit(void);
#endif
-static void erl_init(int ncpu);
-
-#define ERTS_MIN_COMPAT_REL 7
+static void erl_init(int ncpu,
+ int proc_tab_sz,
+ int port_tab_sz,
+ int port_tab_sz_ignore_files);
static erts_atomic_t exiting;
@@ -206,8 +213,6 @@ ErtsModifiedTimings erts_modified_timings[] = {
Export *erts_delay_trap = NULL;
-int erts_use_r9_pids_ports;
-
int ignore_break;
int replace_intr;
@@ -271,12 +276,18 @@ void
erts_short_init(void)
{
int ncpu = early_init(NULL, NULL);
- erl_init(ncpu);
+ erl_init(ncpu,
+ ERTS_DEFAULT_MAX_PROCESSES,
+ ERTS_DEFAULT_MAX_PORTS,
+ 0);
erts_initialized = 1;
}
static void
-erl_init(int ncpu)
+erl_init(int ncpu,
+ int proc_tab_sz,
+ int port_tab_sz,
+ int port_tab_sz_ignore_files)
{
init_benchmarking();
@@ -284,7 +295,7 @@ erl_init(int ncpu)
erts_init_gc();
erts_init_time();
erts_init_sys_common_misc();
- erts_init_process(ncpu);
+ erts_init_process(ncpu, proc_tab_sz);
erts_init_scheduling(no_schedulers,
no_schedulers_online);
erts_init_cpu_topology(); /* Must be after init_scheduling */
@@ -306,6 +317,7 @@ erl_init(int ncpu)
erts_bif_info_init();
erts_ddll_init();
init_emulator();
+ erts_ptab_init(); /* Must be after init_emulator() */
erts_bp_init();
init_db(); /* Must be after init_emulator */
erts_bif_timer_init();
@@ -313,7 +325,7 @@ erl_init(int ncpu)
init_dist();
erl_drv_thr_init();
erts_init_async();
- init_io();
+ erts_init_io(port_tab_sz, port_tab_sz_ignore_files);
init_load();
erts_init_bif();
erts_init_bif_chksum();
@@ -457,6 +469,7 @@ load_preloaded(void)
/* be helpful (or maybe downright rude:-) */
void erts_usage(void)
{
+ int this_rel = this_rel_num();
erts_fprintf(stderr, "Usage: %s [flags] [ -- [init_args] ]\n", progname(program));
erts_fprintf(stderr, "The flags are:\n\n");
@@ -490,16 +503,20 @@ void erts_usage(void)
/* erts_fprintf(stderr, "-i module set the boot module (default init)\n"); */
erts_fprintf(stderr, "-K boolean enable or disable kernel poll\n");
-
+ erts_fprintf(stderr, "-n[s|a|d] Control behavior of signals to ports\n");
+ erts_fprintf(stderr, " Note that this flag is deprecated!\n");
erts_fprintf(stderr, "-M<X> <Y> memory allocator switches,\n");
erts_fprintf(stderr, " see the erts_alloc(3) documentation for more info.\n");
erts_fprintf(stderr, "-P number set maximum number of processes on this node,\n");
erts_fprintf(stderr, " valid range is [%d-%d]\n",
- ERTS_MIN_PROCESSES, ERTS_MAX_PROCESSES);
+ ERTS_MIN_PROCESSES, ERTS_MAX_PROCESSES);
+ erts_fprintf(stderr, "-Q number set maximum number of ports on this node,\n");
+ erts_fprintf(stderr, " valid range is [%d-%d]\n",
+ ERTS_MIN_PORTS, ERTS_MAX_PORTS);
erts_fprintf(stderr, "-R number set compatibility release number,\n");
erts_fprintf(stderr, " valid range [%d-%d]\n",
- ERTS_MIN_COMPAT_REL, this_rel_num());
+ this_rel-2, this_rel);
erts_fprintf(stderr, "-r force ets memory block to be moved on realloc\n");
erts_fprintf(stderr, "-rg amount set reader groups limit\n");
@@ -519,6 +536,7 @@ void erts_usage(void)
erts_fprintf(stderr, " valid range is [%d-%d]\n",
ERTS_SCHED_THREAD_MIN_STACK_SIZE,
ERTS_SCHED_THREAD_MAX_STACK_SIZE);
+ erts_fprintf(stderr, "-spp Bool set port parallelism scheduling hint\n");
erts_fprintf(stderr, "-S n1:n2 set number of schedulers (n1), and number of\n");
erts_fprintf(stderr, " schedulers online (n2), valid range for both\n");
erts_fprintf(stderr, " numbers are [1-%d]\n",
@@ -612,7 +630,6 @@ early_init(int *argc, char **argv) /*
erts_printf_eterm_func = erts_printf_term;
erts_disable_tolerant_timeofday = 0;
display_items = 200;
- erts_proc.max = ERTS_DEFAULT_MAX_PROCESSES;
erts_backtrace_depth = DEFAULT_BACKTRACE_SIZE;
erts_async_max_threads = 0;
erts_async_thread_suggested_stack_size = ERTS_ASYNC_THREAD_MIN_STACK_SIZE;
@@ -641,8 +658,6 @@ early_init(int *argc, char **argv) /*
erts_compat_rel = this_rel_num();
- erts_use_r9_pids_ports = 0;
-
erts_sys_pre_init();
erts_atomic_init_nob(&exiting, 0);
#ifdef ERTS_SMP
@@ -897,11 +912,13 @@ erl_start(int argc, char **argv)
{
int i = 1;
char* arg=NULL;
- char* Parg = NULL;
int have_break_handler = 1;
char envbuf[21]; /* enough for any 64-bit integer */
size_t envbufsz;
int ncpu = early_init(&argc, argv);
+ int proc_tab_sz = ERTS_DEFAULT_MAX_PROCESSES;
+ int port_tab_sz = ERTS_DEFAULT_MAX_PORTS;
+ int port_tab_sz_ignore_files = 0;
envbufsz = sizeof(envbuf);
if (erts_sys_getenv_raw(ERL_MAX_ETS_TABLES_ENV, envbuf, &envbufsz) == 0)
@@ -972,6 +989,7 @@ erl_start(int argc, char **argv)
break;
case 'a':
erts_set_user_requested_filename_encoding(ERL_FILENAME_UNKNOWN);
+ break;
default:
erts_fprintf(stderr, "bad filename encoding %s, can be (l,u or a)\n", arg);
erts_usage();
@@ -1152,12 +1170,53 @@ erl_start(int argc, char **argv)
arg);
break;
- case 'P':
- /* set maximum number of processes */
- Parg = get_arg(argv[i]+2, argv[i+1], &i);
- erts_proc.max = atoi(Parg);
- /* Check of result is delayed until later. This is because +R
- may be given after +P. */
+ case 'n':
+ arg = get_arg(argv[i]+2, argv[i+1], &i);
+ switch (arg[0]) {
+ case 's': /* synchronous */
+ erts_port_synchronous_ops = 1;
+ erts_port_schedule_all_ops = 0;
+ break;
+ case 'a': /* asynchronous */
+ erts_port_synchronous_ops = 0;
+ erts_port_schedule_all_ops = 1;
+ break;
+ case 'd': /* Default - schedule on conflict (asynchronous) */
+ erts_port_synchronous_ops = 0;
+ erts_port_schedule_all_ops = 0;
+ break;
+ default:
+ bad_n_option:
+ erts_fprintf(stderr, "bad -n option %s\n", arg);
+ erts_usage();
+ }
+ if (arg[1] != '\0')
+ goto bad_n_option;
+ break;
+
+ case 'P': /* set maximum number of processes */
+ arg = get_arg(argv[i]+2, argv[i+1], &i);
+ errno = 0;
+ proc_tab_sz = strtol(arg, NULL, 10);
+ if (errno != 0
+ || proc_tab_sz < ERTS_MIN_PROCESSES
+ || ERTS_MAX_PROCESSES < proc_tab_sz) {
+ erts_fprintf(stderr, "bad number of processes %s\n", arg);
+ erts_usage();
+ }
+ break;
+
+ case 'Q': /* set maximum number of ports */
+ arg = get_arg(argv[i]+2, argv[i+1], &i);
+ errno = 0;
+ port_tab_sz = strtol(arg, NULL, 10);
+ if (errno != 0
+ || port_tab_sz < ERTS_MIN_PROCESSES
+ || ERTS_MAX_PROCESSES < port_tab_sz) {
+ erts_fprintf(stderr, "bad number of ports %s\n", arg);
+ erts_usage();
+ }
+ port_tab_sz_ignore_files = 1;
break;
case 'S' : /* Was handled in early_init() just read past it */
@@ -1259,6 +1318,19 @@ erl_start(int argc, char **argv)
erts_usage();
}
}
+ else if (has_prefix("pp", sub_param)) {
+ arg = get_arg(sub_param+2, argv[i+1], &i);
+ if (sys_strcmp(arg, "true") == 0)
+ erts_port_parallelism = 1;
+ else if (sys_strcmp(arg, "false") == 0)
+ erts_port_parallelism = 0;
+ else {
+ erts_fprintf(stderr,
+ "bad port parallelism scheduling hint %s\n",
+ arg);
+ erts_usage();
+ }
+ }
else if (sys_strcmp("nsp", sub_param) == 0)
erts_use_sender_punish = 0;
else if (sys_strcmp("wt", sub_param) == 0) {
@@ -1340,22 +1412,19 @@ erl_start(int argc, char **argv)
case 'R': {
/* set compatibility release */
+ int this_rel;
arg = get_arg(argv[i]+2, argv[i+1], &i);
erts_compat_rel = atoi(arg);
- if (erts_compat_rel < ERTS_MIN_COMPAT_REL
- || erts_compat_rel > this_rel_num()) {
+ this_rel = this_rel_num();
+ if (erts_compat_rel < this_rel - 2 || this_rel < erts_compat_rel) {
erts_fprintf(stderr, "bad compatibility release number %s\n", arg);
erts_usage();
}
- ASSERT(ERTS_MIN_COMPAT_REL >= 7);
switch (erts_compat_rel) {
- case 7:
- case 8:
- case 9:
- erts_use_r9_pids_ports = 1;
+ /* Currently no compat features... */
default:
break;
}
@@ -1397,8 +1466,6 @@ erl_start(int argc, char **argv)
}
break;
}
- case 'n': /* XXX obsolete */
- break;
case 'c':
if (argv[i][2] == 0) { /* -c: documented option */
erts_disable_tolerant_timeofday = 1;
@@ -1453,15 +1520,6 @@ erl_start(int argc, char **argv)
i++;
}
- /* Delayed check of +P flag */
- if (erts_proc.max < ERTS_MIN_PROCESSES
- || erts_proc.max > ERTS_MAX_PROCESSES
- || (erts_use_r9_pids_ports
- && erts_proc.max > ERTS_MAX_R9_PROCESSES)) {
- erts_fprintf(stderr, "bad number of processes %s\n", Parg);
- erts_usage();
- }
-
/* Restart will not reinstall the break handler */
#ifdef __WIN32__
if (ignore_break)
@@ -1482,7 +1540,10 @@ erl_start(int argc, char **argv)
boot_argc = argc - i; /* Number of arguments to init */
boot_argv = &argv[i];
- erl_init(ncpu);
+ erl_init(ncpu,
+ proc_tab_sz,
+ port_tab_sz,
+ port_tab_sz_ignore_files);
load_preloaded();
erts_end_staging_code_ix();
diff --git a/erts/emulator/beam/erl_lock_check.c b/erts/emulator/beam/erl_lock_check.c
index 11fed4079d..69bb4be717 100644
--- a/erts/emulator/beam/erl_lock_check.c
+++ b/erts/emulator/beam/erl_lock_check.c
@@ -93,9 +93,8 @@ static erts_lc_lock_order_t erts_lock_order[] = {
{ "proc_msgq", "pid" },
{ "dist_entry", "address" },
{ "dist_entry_links", "address" },
- { "code_ix_queue", NULL },
+ { "code_write_permission", NULL },
{ "proc_status", "pid" },
- { "proc_tab", NULL },
{ "ports_snapshot", NULL },
{ "meta_name_tab", "address" },
{ "meta_main_tab_slot", "address" },
@@ -115,9 +114,6 @@ static erts_lc_lock_order_t erts_lock_order[] = {
#if defined(ENABLE_CHILD_WAITER_THREAD) || defined(ERTS_SMP)
{ "child_status", NULL },
#endif
-#ifdef __WIN32__
- { "sys_driver_data_lock", NULL },
-#endif
{ "drv_ev_state_grow", NULL, },
{ "drv_ev_state", "address" },
{ "safe_hash", "address" },
@@ -127,6 +123,7 @@ static erts_lc_lock_order_t erts_lock_order[] = {
{ "schdlr_sspnd", NULL },
{ "migration_info_update", NULL },
{ "run_queue", "address" },
+ { "process_table", NULL },
{ "cpu_info", NULL },
{ "pollset", "address" },
#ifdef __WIN32__
@@ -157,12 +154,10 @@ static erts_lc_lock_order_t erts_lock_order[] = {
{ "pmmap", NULL },
#endif
#ifdef ERTS_SMP
+ { "port_sched_lock", "port_id" },
{ "port_task_pre_alloc_lock", "address" },
- { "port_taskq_pre_alloc_lock", "address" },
{ "proclist_pre_alloc_lock", "address" },
- { "port_tasks_lock", NULL },
- { "get_free_port", NULL },
- { "port_state", "address" },
+ { "port_table", NULL },
{ "xports_list_pre_alloc_lock", "address" },
{ "inet_buffer_stack_lock", NULL },
{ "gc_info", NULL },
@@ -247,6 +242,7 @@ typedef struct {
typedef struct erts_lc_locked_locks_t_ erts_lc_locked_locks_t;
struct erts_lc_locked_locks_t_ {
char *thread_name;
+ int emu_thread;
erts_tid_t tid;
erts_lc_locked_locks_t *next;
erts_lc_locked_locks_t *prev;
@@ -364,6 +360,7 @@ create_locked_locks(char *thread_name)
if (!l_lcks->thread_name)
lc_abort();
+ l_lcks->emu_thread = 0;
l_lcks->tid = erts_thr_self();
l_lcks->required.first = NULL;
l_lcks->required.last = NULL;
@@ -671,7 +668,7 @@ erts_lc_set_thread_name(char *thread_name)
{
erts_lc_locked_locks_t *l_lcks = get_my_locked_locks();
if (!l_lcks)
- (void) create_locked_locks(thread_name);
+ l_lcks = create_locked_locks(thread_name);
else {
ASSERT(l_lcks->thread_name);
free((void *) l_lcks->thread_name);
@@ -679,6 +676,14 @@ erts_lc_set_thread_name(char *thread_name)
if (!l_lcks->thread_name)
lc_abort();
}
+ l_lcks->emu_thread = 1;
+}
+
+int
+erts_lc_is_emu_thr(void)
+{
+ erts_lc_locked_locks_t *l_lcks = get_my_locked_locks();
+ return l_lcks->emu_thread;
}
int
diff --git a/erts/emulator/beam/erl_lock_check.h b/erts/emulator/beam/erl_lock_check.h
index b67f36fa06..068340abe7 100644
--- a/erts/emulator/beam/erl_lock_check.h
+++ b/erts/emulator/beam/erl_lock_check.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2005-2012. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -102,9 +102,10 @@ void erts_lc_unrequire_lock_flg(erts_lc_lock_t *lck, Uint16 op_flags);
void erts_lc_require_lock(erts_lc_lock_t *lck);
void erts_lc_unrequire_lock(erts_lc_lock_t *lck);
+int erts_lc_is_emu_thr(void);
#define ERTS_LC_ASSERT(A) \
- ((void) ((A) ? 1 : erts_lc_assert_failed(__FILE__, __LINE__, #A)))
+ ((void) (((A) || ERTS_SOMEONE_IS_CRASH_DUMPING) ? 1 : erts_lc_assert_failed(__FILE__, __LINE__, #A)))
#ifdef ERTS_SMP
#define ERTS_SMP_LC_ASSERT(A) ERTS_LC_ASSERT(A)
#else
diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c
index e397f075d1..325d77e911 100644
--- a/erts/emulator/beam/erl_message.c
+++ b/erts/emulator/beam/erl_message.c
@@ -495,7 +495,7 @@ queue_message(Process *c_p,
#ifndef ERTS_SMP
res = receiver->msg.len;
#else
- res = receiver->u.alive.msg_inq.len;
+ res = receiver->msg_inq.len;
if (*receiver_locks & ERTS_PROC_LOCK_MAIN) {
/*
* We move 'in queue' to 'private queue' and place
@@ -894,8 +894,8 @@ erts_send_message(Process* sender,
#ifdef USE_VM_PROBES
*sender_name = *receiver_name = '\0';
if (DTRACE_ENABLED(message_send)) {
- erts_snprintf(sender_name, sizeof(DTRACE_CHARBUF_NAME(sender_name)), "%T", sender->id);
- erts_snprintf(receiver_name, sizeof(DTRACE_CHARBUF_NAME(receiver_name)), "%T", receiver->id);
+ erts_snprintf(sender_name, sizeof(DTRACE_CHARBUF_NAME(sender_name)), "%T", sender->common.id);
+ erts_snprintf(receiver_name, sizeof(DTRACE_CHARBUF_NAME(receiver_name)), "%T", receiver->common.id);
}
#endif
if (SEQ_TRACE_TOKEN(sender) != NIL && !(flags & ERTS_SND_FLG_NO_SEQ_TRACE)) {
@@ -917,7 +917,7 @@ erts_send_message(Process* sender,
seq_trace_update_send(sender);
seq_trace_output(stoken, message, SEQ_TRACE_SEND,
- receiver->id, sender);
+ receiver->common.id, sender);
seq_trace_size = 6; /* TUPLE5 */
#ifdef USE_VM_PROBES
}
@@ -948,7 +948,7 @@ erts_send_message(Process* sender,
#ifdef DTRACE_TAG_HARDDEBUG
erts_fprintf(stderr,
"Dtrace -> (%T) Spreading tag (%T) with "
- "message %T!\r\n",sender->id, utag, message);
+ "message %T!\r\n",sender->common.id, utag, message);
#endif
}
#endif
@@ -1096,7 +1096,6 @@ erts_send_message(Process* sender,
}
BM_SWAP_TIMER(send,system);
#endif /* #ifndef ERTS_SMP */
- return;
}
return res;
}
@@ -1137,7 +1136,7 @@ erts_deliver_exit_message(Eterm from, Process *to, ErtsProcLocks *to_locksp,
save = TUPLE3(hp, am_EXIT, from_copy, mess);
hp += 4;
/* the trace token must in this case be updated by the caller */
- seq_trace_output(token, save, SEQ_TRACE_SEND, to->id, NULL);
+ seq_trace_output(token, save, SEQ_TRACE_SEND, to->common.id, NULL);
temptoken = copy_struct(token, sz_token, &hp, &bp->off_heap);
erts_queue_message(to, to_locksp, bp, save, temptoken
#ifdef USE_VM_PROBES
diff --git a/erts/emulator/beam/erl_message.h b/erts/emulator/beam/erl_message.h
index 2ae94965b1..771eba431f 100644
--- a/erts/emulator/beam/erl_message.h
+++ b/erts/emulator/beam/erl_message.h
@@ -127,21 +127,21 @@ typedef struct {
/* Move in message queue to end of private message queue */
#define ERTS_SMP_MSGQ_MV_INQ2PRIVQ(P) \
do { \
- if ((P)->u.alive.msg_inq.first) { \
- *(P)->msg.last = (P)->u.alive.msg_inq.first; \
- (P)->msg.last = (P)->u.alive.msg_inq.last; \
- (P)->msg.len += (P)->u.alive.msg_inq.len; \
- (P)->u.alive.msg_inq.first = NULL; \
- (P)->u.alive.msg_inq.last = &(P)->u.alive.msg_inq.first; \
- (P)->u.alive.msg_inq.len = 0; \
+ if ((P)->msg_inq.first) { \
+ *(P)->msg.last = (P)->msg_inq.first; \
+ (P)->msg.last = (P)->msg_inq.last; \
+ (P)->msg.len += (P)->msg_inq.len; \
+ (P)->msg_inq.first = NULL; \
+ (P)->msg_inq.last = &(P)->msg_inq.first; \
+ (P)->msg_inq.len = 0; \
} \
} while (0)
/* Add message last in message queue */
#define LINK_MESSAGE(p, mp) do { \
- *(p)->u.alive.msg_inq.last = (mp); \
- (p)->u.alive.msg_inq.last = &(mp)->next; \
- (p)->u.alive.msg_inq.len++; \
+ *(p)->msg_inq.last = (mp); \
+ (p)->msg_inq.last = &(mp)->next; \
+ (p)->msg_inq.len++; \
} while(0)
#else
@@ -245,6 +245,9 @@ void erts_move_msg_attached_data_to_heap(Eterm **, ErlOffHeap *, ErlMessage *);
Eterm erts_msg_distext2heap(Process *, ErtsProcLocks *, ErlHeapFragment **,
Eterm *, ErtsDistExternal *);
+void erts_cleanup_offheap(ErlOffHeap *offheap);
+
+
ERTS_GLB_INLINE Uint erts_msg_used_frag_sz(const ErlMessage *msg);
ERTS_GLB_INLINE Uint erts_msg_attached_data_size(ErlMessage *msg);
diff --git a/erts/emulator/beam/erl_monitors.c b/erts/emulator/beam/erl_monitors.c
index 1a84950120..63175c44d6 100644
--- a/erts/emulator/beam/erl_monitors.c
+++ b/erts/emulator/beam/erl_monitors.c
@@ -971,7 +971,7 @@ Eterm erts_debug_dump_monitors_1(BIF_ALIST_1)
}
} else {
erts_printf("Dumping pid monitors--------------------\n");
- erts_dump_monitors(rp->monitors,0);
+ erts_dump_monitors(ERTS_P_MONITORS(rp),0);
erts_printf("Monitors dumped-------------------------\n");
erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_LINK);
BIF_RET(am_true);
@@ -985,12 +985,15 @@ Eterm erts_debug_dump_links_1(BIF_ALIST_1)
Process *rp;
DistEntry *dep;
if (is_internal_port(pid)) {
- Port *rport = erts_id2port(pid, p, ERTS_PROC_LOCK_MAIN);
+ Port *rport = erts_id2port_sflgs(pid,
+ p,
+ ERTS_PROC_LOCK_MAIN,
+ ERTS_PORT_SFLGS_INVALID_LOOKUP);
if (rport) {
erts_printf("Dumping port links----------------------\n");
- erts_dump_links(rport->nlinks,0);
+ erts_dump_links(ERTS_P_LINKS(rport), 0);
erts_printf("Links dumped----------------------------\n");
- erts_smp_port_unlock(rport);
+ erts_port_release(rport);
BIF_RET(am_true);
} else {
BIF_ERROR(p,BADARG);
@@ -1014,7 +1017,7 @@ Eterm erts_debug_dump_links_1(BIF_ALIST_1)
} else {
erts_printf("Dumping pid links-----------------------\n");
- erts_dump_links(rp->nlinks,0);
+ erts_dump_links(ERTS_P_LINKS(rp), 0);
erts_printf("Links dumped----------------------------\n");
erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_LINK);
BIF_RET(am_true);
diff --git a/erts/emulator/beam/erl_monitors.h b/erts/emulator/beam/erl_monitors.h
index d3f6d410dd..a7fa4e0145 100644
--- a/erts/emulator/beam/erl_monitors.h
+++ b/erts/emulator/beam/erl_monitors.h
@@ -137,8 +137,6 @@ typedef struct erts_suspend_monitor {
#define ERTS_LINK_ROOT(Linkp) ((Linkp)->shared.root)
#define ERTS_LINK_REFC(Linkp) ((Linkp)->shared.refc)
-#define ERTS_LINK_ROOT_AS_UINT(Linkp) (*((Uint *) &((Linkp)->root)))
-
Uint erts_tot_link_lh_size(void);
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index 0dca588847..1bd2d933b2 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -263,7 +263,7 @@ ErlNifEnv* enif_alloc_env(void)
HEAP_LIMIT(&msg_env->phony_proc) = phony_heap;
HEAP_END(&msg_env->phony_proc) = phony_heap;
MBUF(&msg_env->phony_proc) = NULL;
- msg_env->phony_proc.id = ERTS_INVALID_PID;
+ msg_env->phony_proc.common.id = ERTS_INVALID_PID;
#ifdef FORCE_HEAP_FRAGS
msg_env->phony_proc.space_verified = 0;
msg_env->phony_proc.space_verified_from = NULL;
@@ -287,7 +287,7 @@ void enif_clear_env(ErlNifEnv* env)
struct enif_msg_environment_t* menv = (struct enif_msg_environment_t*)env;
Process* p = &menv->phony_proc;
ASSERT(p == menv->env.proc);
- ASSERT(p->id == ERTS_INVALID_PID);
+ ASSERT(p->common.id == ERTS_INVALID_PID);
ASSERT(MBUF(p) == menv->env.heap_frag);
if (MBUF(p) != NULL) {
erts_cleanup_offheap(&MSO(p));
@@ -319,7 +319,7 @@ int enif_send(ErlNifEnv* env, const ErlNifPid* to_pid,
if (env != NULL) {
c_p = env->proc;
- if (receiver == c_p->id) {
+ if (receiver == c_p->common.id) {
rp_locks = ERTS_PROC_LOCK_MAIN;
flush_me = 1;
}
@@ -341,7 +341,7 @@ int enif_send(ErlNifEnv* env, const ErlNifPid* to_pid,
: erts_pid2proc_opt(c_p, ERTS_PROC_LOCK_MAIN,
receiver, rp_locks, ERTS_P2P_FLG_SMP_INC_REFC));
if (rp == NULL) {
- ASSERT(env == NULL || receiver != c_p->id);
+ ASSERT(env == NULL || receiver != c_p->common.id);
return 0;
}
flush_env(msg_env);
@@ -397,7 +397,7 @@ static int is_offheap(const ErlOffHeap* oh)
ErlNifPid* enif_self(ErlNifEnv* caller_env, ErlNifPid* pid)
{
- pid->pid = caller_env->proc->id;
+ pid->pid = caller_env->proc->common.id;
return pid;
}
int enif_get_local_pid(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifPid* pid)
@@ -505,7 +505,7 @@ int enif_inspect_iolist_as_binary(ErlNifEnv* env, Eterm term, ErlNifBinary* bin)
{
struct enif_tmp_obj_t* tobj;
ErtsAlcType_t allocator;
- Uint sz;
+ ErlDrvSizeT sz;
if (is_binary(term)) {
return enif_inspect_binary(env,term,bin);
}
@@ -531,7 +531,7 @@ int enif_inspect_iolist_as_binary(ErlNifEnv* env, Eterm term, ErlNifBinary* bin)
bin->size = sz;
bin->bin_term = THE_NON_VALUE;
bin->ref_bin = NULL;
- io_list_to_buf(term, (char*) bin->data, sz);
+ erts_iolist_to_buf(term, (char*) bin->data, sz);
ADD_READONLY_CHECK(env, bin->data, bin->size);
return 1;
}
@@ -1396,6 +1396,44 @@ size_t enif_sizeof_resource(void* obj)
return ERTS_MAGIC_BIN_DATA_SIZE(bin) - offsetof(ErlNifResource,data);
}
+
+void* enif_dlopen(const char* lib,
+ void (*err_handler)(void*,const char*), void* err_arg)
+{
+ ErtsSysDdllError errdesc = ERTS_SYS_DDLL_ERROR_INIT;
+ void* handle;
+ void* init_func;
+ if (erts_sys_ddll_open2(lib, &handle, &errdesc) == ERL_DE_NO_ERROR) {
+ if (erts_sys_ddll_load_nif_init(handle, &init_func, &errdesc) == ERL_DE_NO_ERROR) {
+ erts_sys_ddll_call_nif_init(init_func);
+ }
+ }
+ else {
+ if (err_handler != NULL) {
+ (*err_handler)(err_arg, errdesc.str);
+ }
+ handle = NULL;
+ }
+ erts_sys_ddll_free_error(&errdesc);
+ return handle;
+}
+
+void* enif_dlsym(void* handle, const char* symbol,
+ void (*err_handler)(void*,const char*), void* err_arg)
+{
+ ErtsSysDdllError errdesc = ERTS_SYS_DDLL_ERROR_INIT;
+ void* ret;
+ if (erts_sys_ddll_sym2(handle, symbol, &ret, &errdesc) != ERL_DE_NO_ERROR) {
+ if (err_handler != NULL) {
+ (*err_handler)(err_arg, errdesc.str);
+ }
+ erts_sys_ddll_free_error(&errdesc);
+ return NULL;
+ }
+ return ret;
+}
+
+
/***************************************************************************
** load_nif/2 **
***************************************************************************/
@@ -1806,7 +1844,7 @@ void erl_nif_init()
#ifdef USE_VM_PROBES
void dtrace_nifenv_str(ErlNifEnv *env, char *process_buf)
{
- dtrace_pid_str(env->proc->id, process_buf);
+ dtrace_pid_str(env->proc->common.id, process_buf);
}
#endif
diff --git a/erts/emulator/beam/erl_nif_api_funcs.h b/erts/emulator/beam/erl_nif_api_funcs.h
index 6396af09d0..51ff1eaa48 100644
--- a/erts/emulator/beam/erl_nif_api_funcs.h
+++ b/erts/emulator/beam/erl_nif_api_funcs.h
@@ -138,6 +138,8 @@ ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_uint64,(ErlNifEnv*, ErlNifUInt64));
ERL_NIF_API_FUNC_DECL(int,enif_is_exception,(ErlNifEnv*, ERL_NIF_TERM term));
ERL_NIF_API_FUNC_DECL(int,enif_make_reverse_list,(ErlNifEnv*, ERL_NIF_TERM term, ERL_NIF_TERM *list));
ERL_NIF_API_FUNC_DECL(int,enif_is_number,(ErlNifEnv*, ERL_NIF_TERM term));
+ERL_NIF_API_FUNC_DECL(void*,enif_dlopen,(const char* lib, void (*err_handler)(void*,const char*), void* err_arg));
+ERL_NIF_API_FUNC_DECL(void*,enif_dlsym,(void* handle, const char* symbol, void (*err_handler)(void*,const char*), void* err_arg));
/*
** Add new entries here to keep compatibility on Windows!!!
@@ -260,6 +262,8 @@ ERL_NIF_API_FUNC_DECL(int,enif_is_number,(ErlNifEnv*, ERL_NIF_TERM term));
# define enif_is_exception ERL_NIF_API_FUNC_MACRO(enif_is_exception)
# define enif_make_reverse_list ERL_NIF_API_FUNC_MACRO(enif_make_reverse_list)
# define enif_is_number ERL_NIF_API_FUNC_MACRO(enif_is_number)
+# define enif_dlopen ERL_NIF_API_FUNC_MACRO(enif_dlopen)
+# define enif_dlsym ERL_NIF_API_FUNC_MACRO(enif_dlsym)
/*
** Add new entries here
diff --git a/erts/emulator/beam/erl_node_container_utils.h b/erts/emulator/beam/erl_node_container_utils.h
index 7b4cb7b042..667bda255b 100644
--- a/erts/emulator/beam/erl_node_container_utils.h
+++ b/erts/emulator/beam/erl_node_container_utils.h
@@ -20,7 +20,7 @@
#ifndef ERL_NODE_CONTAINER_UTILS_H__
#define ERL_NODE_CONTAINER_UTILS_H__
-#include "erl_term.h"
+#include "erl_ptab.h"
/*
* Note regarding node containers:
@@ -29,9 +29,6 @@
* the emulator) for the Erlang data types that contain a reference
* to a node, i.e. pids, ports, and references.
*
- * Observe! The layouts of the node container data types have been
- * changed in R9.
- *
* Node containers are divided into internal and external node containers.
* An internal node container refer to the current incarnation of the
* node which it reside on. An external node container refer to
@@ -52,13 +49,6 @@
* reference is a boxed data type. An internal node container have an
* implicit reference to the 'erts_this_node' element in the node table.
*
- * Due to the R9 changes in layouts of node containers there are room to
- * store more data than previously. Today (R9) this extra space is unused,
- * but it is planned to be used in the future. For example only 18 bits
- * are used for data in a pid but there is room for 28 bits of data (on a
- * 32-bit machine). Some preparations have been made in the emulator for
- * usage of this extra space.
- *
* OBSERVE! Pids doesn't use fixed size 'serial' and 'number' fields any
* more. Previously the 15 bit 'number' field of a pid was used as index
* into the process table, and the 3 bit 'serial' field was used as a
@@ -104,8 +94,6 @@
#define internal_dist_entry(x) (erts_this_node->dist_entry)
#define external_dist_entry(x) (external_node((x))->dist_entry)
-extern int erts_use_r9_pids_ports;
-
/*
* For this node (and previous incarnations of this node), 0 is used as
* channel no. For other nodes, the atom index of the atom corresponding
@@ -128,47 +116,20 @@ extern int erts_use_r9_pids_ports;
* Pids *
\* */
-#define erts_max_processes erts_proc.max
-
-typedef struct {
- erts_smp_atomic_t *tab;
- int max;
- int tab_cache_lines;
- int pix_per_cache_line;
- int pix_cl_mask;
- int pix_cl_shift;
- int pix_cli_mask;
- int pix_cli_shift;
-} ErtsProcTab;
-
-extern ErtsProcTab erts_proc;
-
-ERTS_GLB_INLINE int erts_pid_data2ix(Eterm pid_data);
-
-#if ERTS_GLB_INLINE_INCL_FUNC_DEF
-
-ERTS_GLB_INLINE int erts_pid_data2ix(Eterm pid_data)
-{
- int n, pix;
-
- n = (int) pid_data;
- if (erts_proc.pix_cl_mask) {
- pix = ((n & erts_proc.pix_cl_mask) << erts_proc.pix_cl_shift);
- pix += ((n >> erts_proc.pix_cli_shift) & erts_proc.pix_cli_mask);
- }
- else {
- n %= erts_proc.max;
- pix = n % erts_proc.tab_cache_lines;
- pix *= erts_proc.pix_per_cache_line;
- pix += n / erts_proc.tab_cache_lines;
- }
- ASSERT(0 <= pix && pix < erts_proc.max);
- return pix;
-}
+extern ErtsPTab erts_proc;
-#endif
+#define make_internal_pid(D) erts_ptab_make_id(&erts_proc, \
+ (D), \
+ _TAG_IMMED1_PID)
-#define internal_pid_index(x) erts_pid_data2ix(internal_pid_data((x)))
+#define internal_pid_index(PID) (ASSERT_EXPR(is_internal_pid((PID))), \
+ erts_ptab_id2pix(&erts_proc, (PID)))
+
+#define internal_pid_data(PID) (ASSERT_EXPR(is_internal_pid((PID))), \
+ erts_ptab_id2data(&erts_proc, (PID)))
+
+#define internal_pid_number(x) _GET_PID_NUM(internal_pid_data((x)))
+#define internal_pid_serial(x) _GET_PID_SER(internal_pid_data((x)))
#define internal_pid_node_name(x) (internal_pid_node((x))->sysname)
#define external_pid_node_name(x) (external_pid_node((x))->sysname)
@@ -208,34 +169,37 @@ ERTS_GLB_INLINE int erts_pid_data2ix(Eterm pid_data)
|| is_external_pid((x)))
#define is_not_pid(x) (!is_pid(x))
-#define ERTS_MAX_R9_PROCESSES (1 << ERTS_R9_PROC_BITS)
-
/*
* Maximum number of processes. We want the number to fit in a SMALL on
* 32-bit CPU.
*/
-#define ERTS_MAX_PROCESSES ((SWORD_CONSTANT(1) << 27)-1)
-#if (ERTS_MAX_PROCESSES > MAX_SMALL)
-# error "The maximum number of processes must fit in a SMALL."
-#endif
-
+#define ERTS_MAX_PROCESSES (ERTS_PTAB_MAX_SIZE-1)
#define ERTS_MAX_PID_DATA ((1 << _PID_DATA_SIZE) - 1)
#define ERTS_MAX_PID_NUMBER ((1 << _PID_NUM_SIZE) - 1)
#define ERTS_MAX_PID_SERIAL ((1 << _PID_SER_SIZE) - 1)
-#define ERTS_MAX_PID_R9_SERIAL ((1 << _PID_R9_SER_SIZE) - 1)
-#define ERTS_R9_PROC_BITS (_PID_R9_SER_SIZE + _PID_NUM_SIZE)
#define ERTS_PROC_BITS (_PID_SER_SIZE + _PID_NUM_SIZE)
-#define ERTS_INVALID_PID make_internal_pid(ERTS_MAX_PID_DATA)
+#define ERTS_INVALID_PID ERTS_PTAB_INVALID_ID(_TAG_IMMED1_PID)
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* Ports *
\* */
-#define internal_port_index(x) (internal_port_data((x)) \
- & erts_port_tab_index_mask)
+extern ErtsPTab erts_port;
+
+#define make_internal_port(D) erts_ptab_make_id(&erts_port, \
+ (D), \
+ _TAG_IMMED1_PORT)
+
+#define internal_port_index(PRT) (ASSERT_EXPR(is_internal_port((PRT))), \
+ erts_ptab_id2pix(&erts_port, (PRT)))
+
+#define internal_port_data(PRT) (ASSERT_EXPR(is_internal_port((PRT))), \
+ erts_ptab_id2data(&erts_port, (PRT)))
+
+#define internal_port_number(x) _GET_PORT_NUM(internal_port_data((x)))
#define internal_port_node_name(x) (internal_port_node((x))->sysname)
#define external_port_node_name(x) (external_port_node((x))->sysname)
@@ -274,18 +238,18 @@ ERTS_GLB_INLINE int erts_pid_data2ix(Eterm pid_data)
#define is_not_port(x) (!is_port(x))
/* Highest port-ID part in a term of type Port
- Not necessarily the same as the variable erts_max_ports
+ Not necessarily the same as current maximum port table size
which defines the maximum number of simultaneous Ports
in the Erlang node. ERTS_MAX_PORTS is a hard upper limit.
*/
-#define ERTS_MAX_R9_PORTS (1 << ERTS_R9_PORTS_BITS)
-#define ERTS_MAX_PORTS (1 << ERTS_PORTS_BITS)
-
+#define ERTS_MAX_PORTS (ERTS_PTAB_MAX_SIZE-1)
#define ERTS_MAX_PORT_DATA ((1 << _PORT_DATA_SIZE) - 1)
#define ERTS_MAX_PORT_NUMBER ((1 << _PORT_NUM_SIZE) - 1)
-#define ERTS_R9_PORTS_BITS (_PORT_R9_NUM_SIZE)
#define ERTS_PORTS_BITS (_PORT_NUM_SIZE)
+
+#define ERTS_INVALID_PORT ERTS_PTAB_INVALID_ID(_TAG_IMMED1_PORT)
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* Refs *
\* */
diff --git a/erts/emulator/beam/erl_node_tables.c b/erts/emulator/beam/erl_node_tables.c
index 40837d3817..ebfba065d1 100644
--- a/erts/emulator/beam/erl_node_tables.c
+++ b/erts/emulator/beam/erl_node_tables.c
@@ -116,8 +116,7 @@ dist_table_alloc(void *dep_tmpl)
dep->qsize = 0;
dep->out_queue.first = NULL;
dep->out_queue.last = NULL;
- dep->suspended.first = NULL;
- dep->suspended.last = NULL;
+ dep->suspended = NULL;
dep->finalized_out_queue.first = NULL;
dep->finalized_out_queue.last = NULL;
@@ -769,8 +768,7 @@ void erts_init_node_tables(void)
erts_this_dist_entry->qsize = 0;
erts_this_dist_entry->out_queue.first = NULL;
erts_this_dist_entry->out_queue.last = NULL;
- erts_this_dist_entry->suspended.first = NULL;
- erts_this_dist_entry->suspended.last = NULL;
+ erts_this_dist_entry->suspended = NULL;
erts_this_dist_entry->finalized_out_queue.first = NULL;
erts_this_dist_entry->finalized_out_queue.last = NULL;
@@ -1268,7 +1266,7 @@ setup_reference_table(void)
ErlHeapFragment *hfp;
DistEntry *dep;
HashInfo hi;
- int i;
+ int i, max;
DeclareTmpHeapNoproc(heap,3);
inserted_bins = NULL;
@@ -1297,8 +1295,9 @@ setup_reference_table(void)
UnUseTmpHeapNoproc(3);
+ max = erts_ptab_max(&erts_proc);
/* Insert all processes */
- for (i = 0; i < erts_max_processes; i++) {
+ for (i = 0; i < max; i++) {
Process *proc = erts_pix2proc(i);
if (proc) {
ErlMessage *msg;
@@ -1306,12 +1305,12 @@ setup_reference_table(void)
/* Insert Heap */
insert_offheap(&(proc->off_heap),
HEAP_REF,
- proc->id);
+ proc->common.id);
/* Insert message buffers */
for(hfp = proc->mbuf; hfp; hfp = hfp->next)
insert_offheap(&(hfp->off_heap),
HEAP_REF,
- proc->id);
+ proc->common.id);
/* Insert msg msg buffers */
for (msg = proc->msg.first; msg; msg = msg->next) {
ErlHeapFragment *heap_frag = NULL;
@@ -1321,7 +1320,7 @@ setup_reference_table(void)
else {
if (msg->data.dist_ext->dep)
insert_dist_entry(msg->data.dist_ext->dep,
- HEAP_REF, proc->id, 0);
+ HEAP_REF, proc->common.id, 0);
if (is_not_nil(ERL_MESSAGE_TOKEN(msg)))
heap_frag = erts_dist_ext_trailer(msg->data.dist_ext);
}
@@ -1329,10 +1328,10 @@ setup_reference_table(void)
if (heap_frag)
insert_offheap(&(heap_frag->off_heap),
HEAP_REF,
- proc->id);
+ proc->common.id);
}
#ifdef ERTS_SMP
- for (msg = proc->u.alive.msg_inq.first; msg; msg = msg->next) {
+ for (msg = proc->msg_inq.first; msg; msg = msg->next) {
ErlHeapFragment *heap_frag = NULL;
if (msg->data.attached) {
if (is_value(ERL_MESSAGE_TERM(msg)))
@@ -1340,7 +1339,7 @@ setup_reference_table(void)
else {
if (msg->data.dist_ext->dep)
insert_dist_entry(msg->data.dist_ext->dep,
- HEAP_REF, proc->id, 0);
+ HEAP_REF, proc->common.id, 0);
if (is_not_nil(ERL_MESSAGE_TOKEN(msg)))
heap_frag = erts_dist_ext_trailer(msg->data.dist_ext);
}
@@ -1348,19 +1347,19 @@ setup_reference_table(void)
if (heap_frag)
insert_offheap(&(heap_frag->off_heap),
HEAP_REF,
- proc->id);
+ proc->common.id);
}
#endif
/* Insert links */
- if(proc->nlinks)
- insert_links(proc->nlinks, proc->id);
- if(proc->monitors)
- insert_monitors(proc->monitors, proc->id);
+ if (ERTS_P_LINKS(proc))
+ insert_links(ERTS_P_LINKS(proc), proc->common.id);
+ if (ERTS_P_MONITORS(proc))
+ insert_monitors(ERTS_P_MONITORS(proc), proc->common.id);
/* Insert controller */
{
DistEntry *dep = ERTS_PROC_GET_DIST_ENTRY(proc);
if (dep)
- insert_dist_entry(dep, CTRL_REF, proc->id, 0);
+ insert_dist_entry(dep, CTRL_REF, proc->common.id, 0);
}
}
}
@@ -1370,21 +1369,33 @@ setup_reference_table(void)
#endif
/* Insert all ports */
- for (i = 0; i < erts_max_ports; i++) {
- if (erts_port[i].status & ERTS_PORT_SFLGS_DEAD)
+ max = erts_ptab_max(&erts_port);
+ for (i = 0; i < max; i++) {
+ erts_aint32_t state;
+ Port *prt;
+
+ prt = erts_pix2port(i);
+ if (!prt)
+ continue;
+
+ state = erts_atomic32_read_nob(&prt->state);
+ if (state & ERTS_PORT_SFLGS_DEAD)
continue;
/* Insert links */
- if(erts_port[i].nlinks)
- insert_links(erts_port[i].nlinks, erts_port[i].id);
+ if (ERTS_P_LINKS(prt))
+ insert_links(ERTS_P_LINKS(prt), prt->common.id);
+ /* Insert monitors */
+ if (ERTS_P_MONITORS(prt))
+ insert_monitors(ERTS_P_MONITORS(prt), prt->common.id);
/* Insert port data */
- for(hfp = erts_port[i].bp; hfp; hfp = hfp->next)
- insert_offheap(&(hfp->off_heap), HEAP_REF, erts_port[i].id);
+ for(hfp = prt->bp; hfp; hfp = hfp->next)
+ insert_offheap(&(hfp->off_heap), HEAP_REF, prt->common.id);
/* Insert controller */
- if (erts_port[i].dist_entry)
- insert_dist_entry(erts_port[i].dist_entry,
+ if (prt->dist_entry)
+ insert_dist_entry(prt->dist_entry,
CTRL_REF,
- erts_port[i].id,
+ prt->common.id,
0);
}
diff --git a/erts/emulator/beam/erl_node_tables.h b/erts/emulator/beam/erl_node_tables.h
index 4a015bdef9..af60071ea5 100644
--- a/erts/emulator/beam/erl_node_tables.h
+++ b/erts/emulator/beam/erl_node_tables.h
@@ -84,10 +84,6 @@ typedef struct {
} ErtsDistOutputQueue;
struct ErtsProcList_;
-typedef struct {
- struct ErtsProcList_ *first;
- struct ErtsProcList_ *last;
-} ErtsDistSuspended;
/*
* Lock order:
@@ -100,7 +96,6 @@ typedef struct {
*/
struct erl_link;
-struct port;
typedef struct dist_entry_ {
HashBucket hash_bucket; /* Hash bucket */
@@ -135,13 +130,13 @@ typedef struct dist_entry_ {
Uint32 qflgs;
Sint qsize;
ErtsDistOutputQueue out_queue;
- ErtsDistSuspended suspended;
+ struct ErtsProcList_ *suspended;
ErtsDistOutputQueue finalized_out_queue;
erts_smp_atomic_t dist_cmd_scheduled;
ErtsPortTaskHandle dist_cmd;
- Uint (*send)(struct port *prt, ErtsDistOutputBuf *obuf);
+ Uint (*send)(Port *prt, ErtsDistOutputBuf *obuf);
struct cache* cache; /* The atom cache */
} DistEntry;
diff --git a/erts/emulator/beam/erl_port.h b/erts/emulator/beam/erl_port.h
new file mode 100644
index 0000000000..fb07f3d5bc
--- /dev/null
+++ b/erts/emulator/beam/erl_port.h
@@ -0,0 +1,944 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2012. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef ERL_PORT_TYPE__
+#define ERL_PORT_TYPE__
+typedef struct _erl_drv_port Port;
+typedef struct ErtsProc2PortSigData_ ErtsProc2PortSigData;
+#endif
+
+#if !defined(ERL_PORT_H__) && !defined(ERL_PORT_GET_PORT_TYPE_ONLY__)
+#define ERL_PORT_H__
+
+#include "erl_port_task.h"
+#include "erl_ptab.h"
+#include "erl_thr_progress.h"
+#include "erl_trace.h"
+
+#define ERTS_DEFAULT_MAX_PORTS (1 << 16)
+#define ERTS_MIN_PORTS 1024
+
+extern int erts_port_synchronous_ops;
+extern int erts_port_schedule_all_ops;
+extern int erts_port_parallelism;
+
+typedef struct erts_driver_t_ erts_driver_t;
+
+#define ERTS_INVALID_ERL_DRV_PORT ((ErlDrvPort) (SWord) -1)
+#define SMALL_IO_QUEUE 5 /* Number of fixed elements */
+
+typedef struct {
+ ErlDrvSizeT size; /* total size in bytes */
+
+ SysIOVec* v_start;
+ SysIOVec* v_end;
+ SysIOVec* v_head;
+ SysIOVec* v_tail;
+ SysIOVec v_small[SMALL_IO_QUEUE];
+
+ ErlDrvBinary** b_start;
+ ErlDrvBinary** b_end;
+ ErlDrvBinary** b_head;
+ ErlDrvBinary** b_tail;
+ ErlDrvBinary* b_small[SMALL_IO_QUEUE];
+} ErlIOQueue;
+
+typedef struct line_buf { /* Buffer used in line oriented I/O */
+ ErlDrvSizeT bufsiz; /* Size of character buffer */
+ ErlDrvSizeT ovlen; /* Length of overflow data */
+ ErlDrvSizeT ovsiz; /* Actual size of overflow buffer */
+ char data[1]; /* Starting point of buffer data,
+ data[0] is a flag indicating an unprocess CR,
+ The rest is the overflow buffer. */
+} LineBuf;
+
+/*
+ * Items part of erlang:port_info/1 result. Note am_registered_name
+ * *need* to be first.
+ */
+
+#define ERTS_PORT_INFO_1_ITEMS \
+ { am_registered_name, /* Needs to be first */ \
+ am_name, \
+ am_links, \
+ am_id, \
+ am_connected, \
+ am_input, \
+ am_output, \
+ am_os_pid }
+
+/*
+ * Port Specific Data.
+ *
+ * Only use PrtSD for very rarely used data.
+ */
+
+#define ERTS_PRTSD_SCHED_ID 0
+
+#define ERTS_PRTSD_SIZE 1
+
+typedef struct {
+ void *data[ERTS_PRTSD_SIZE];
+} ErtsPrtSD;
+
+#ifdef ERTS_SMP
+typedef struct ErtsXPortsList_ ErtsXPortsList;
+#endif
+
+/*
+ * Port locking:
+ *
+ * Locking is done either driver specific or port specific. When
+ * driver specific locking is used, all instances of the driver,
+ * i.e. ports running the driver, share the same lock. When port
+ * specific locking is used each instance have its own lock.
+ *
+ * Most fields in the Port structure are protected by the lock
+ * referred to by the 'lock' field. This lock is shared between
+ * all ports running the same driver when driver specific locking
+ * is used.
+ *
+ * The 'sched' field is protected by the run queue lock that the
+ * port currently is assigned to.
+ *
+ */
+
+struct _erl_drv_port {
+ ErtsPTabElementCommon common; /* *Need* to be first in struct */
+
+ ErtsPortTaskSched sched;
+ ErtsPortTaskHandle timeout_task;
+#ifdef ERTS_SMP
+ erts_mtx_t *lock;
+ ErtsXPortsList *xports;
+ erts_smp_atomic_t run_queue;
+#else
+ erts_atomic32_t refc;
+ int cleanup;
+#endif
+ erts_atomic_t connected; /* A connected process */
+ Eterm caller; /* Current caller. */
+ Eterm data; /* Data associated with port. */
+ ErlHeapFragment* bp; /* Heap fragment holding data (NULL if imm data). */
+ Uint bytes_in; /* Number of bytes read */
+ Uint bytes_out; /* Number of bytes written */
+
+ ErlIOQueue ioq; /* driver accessible i/o queue */
+ DistEntry *dist_entry; /* Dist entry used in DISTRIBUTION */
+ char *name; /* String used in the open */
+ erts_driver_t* drv_ptr;
+ UWord drv_data;
+ SWord os_pid; /* Child process ID */
+ ErtsProcList *suspended; /* List of suspended processes. */
+ LineBuf *linebuf; /* Buffer to hold data not ready for
+ process to get (line oriented I/O)*/
+ erts_atomic32_t state; /* Status and type flags */
+ int control_flags; /* Flags for port_control() */
+ ErlDrvPDL port_data_lock;
+
+ ErtsPrtSD *psd; /* Port specific data */
+};
+
+#define ERTS_PORT_GET_CONNECTED(PRT) \
+ ((Eterm) erts_atomic_read_nob(&(PRT)->connected))
+#define ERTS_PORT_SET_CONNECTED(PRT, PID) \
+ erts_atomic_set_relb(&(PRT)->connected, (erts_aint_t) (PID))
+#define ERTS_PORT_INIT_CONNECTED(PRT, PID) \
+ erts_atomic_init_nob(&(PRT)->connected, (erts_aint_t) (PID))
+
+
+struct erl_drv_port_data_lock {
+ erts_mtx_t mtx;
+ erts_atomic_t refc;
+ Port *prt;
+};
+
+ERTS_GLB_INLINE ErtsRunQueue *erts_port_runq(Port *prt);
+
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+
+ERTS_GLB_INLINE ErtsRunQueue *
+erts_port_runq(Port *prt)
+{
+#ifdef ERTS_SMP
+ ErtsRunQueue *rq1, *rq2;
+ rq1 = (ErtsRunQueue *) erts_smp_atomic_read_nob(&prt->run_queue);
+ if (!rq1)
+ return NULL;
+ while (1) {
+ erts_smp_runq_lock(rq1);
+ rq2 = (ErtsRunQueue *) erts_smp_atomic_read_nob(&prt->run_queue);
+ if (rq1 == rq2)
+ return rq1;
+ erts_smp_runq_unlock(rq1);
+ rq1 = rq2;
+ if (!rq1)
+ return NULL;
+ }
+#else
+ return ERTS_RUNQ_IX(0);
+#endif
+}
+
+#endif
+
+
+ERTS_GLB_INLINE void *erts_prtsd_get(Port *p, int ix);
+ERTS_GLB_INLINE void *erts_prtsd_set(Port *p, int ix, void *new);
+
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+
+ERTS_GLB_INLINE void *
+erts_prtsd_get(Port *prt, int ix)
+{
+ return prt->psd ? prt->psd->data[ix] : NULL;
+}
+
+ERTS_GLB_INLINE void *
+erts_prtsd_set(Port *prt, int ix, void *data)
+{
+ if (prt->psd) {
+ void *old = prt->psd->data[ix];
+ prt->psd->data[ix] = data;
+ return old;
+ }
+ else {
+ prt->psd = erts_alloc(ERTS_ALC_T_PRTSD, sizeof(ErtsPrtSD));
+ prt->psd->data[ix] = data;
+ return NULL;
+ }
+}
+
+#endif
+
+extern erts_smp_atomic_t erts_bytes_out; /* no bytes written out */
+extern erts_smp_atomic_t erts_bytes_in; /* no bytes sent into the system */
+
+
+/* port status flags */
+
+#define ERTS_PORT_SFLG_CONNECTED ((Uint32) (1 << 0))
+/* Port have begun exiting */
+#define ERTS_PORT_SFLG_EXITING ((Uint32) (1 << 1))
+/* Distribution port */
+#define ERTS_PORT_SFLG_DISTRIBUTION ((Uint32) (1 << 2))
+#define ERTS_PORT_SFLG_BINARY_IO ((Uint32) (1 << 3))
+#define ERTS_PORT_SFLG_SOFT_EOF ((Uint32) (1 << 4))
+/* Flow control */
+/* Port is closing (no i/o accepted) */
+#define ERTS_PORT_SFLG_CLOSING ((Uint32) (1 << 5))
+/* Send a closed message when terminating */
+#define ERTS_PORT_SFLG_SEND_CLOSED ((Uint32) (1 << 6))
+/* Line orinted io on port */
+#define ERTS_PORT_SFLG_LINEBUF_IO ((Uint32) (1 << 7))
+/* Immortal port (only certain system ports) */
+#define ERTS_PORT_SFLG_FREE ((Uint32) (1 << 8))
+#define ERTS_PORT_SFLG_INITIALIZING ((Uint32) (1 << 9))
+/* Port uses port specific locking (opposed to driver specific locking) */
+#define ERTS_PORT_SFLG_PORT_SPECIFIC_LOCK ((Uint32) (1 << 10))
+#define ERTS_PORT_SFLG_INVALID ((Uint32) (1 << 11))
+/* Last port to terminate halts the emulator */
+#define ERTS_PORT_SFLG_HALT ((Uint32) (1 << 12))
+#ifdef DEBUG
+/* Only debug: make sure all flags aren't cleared unintentionally */
+#define ERTS_PORT_SFLG_PORT_DEBUG ((Uint32) (1 << 31))
+#endif
+
+/* Combinations of port status flags */
+#define ERTS_PORT_SFLGS_DEAD \
+ (ERTS_PORT_SFLG_FREE | ERTS_PORT_SFLG_INITIALIZING)
+#define ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP \
+ (ERTS_PORT_SFLGS_DEAD | ERTS_PORT_SFLG_INVALID)
+#define ERTS_PORT_SFLGS_INVALID_LOOKUP \
+ (ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP \
+ | ERTS_PORT_SFLG_EXITING \
+ | ERTS_PORT_SFLG_CLOSING)
+#define ERTS_PORT_SFLGS_INVALID_TRACER_LOOKUP \
+ (ERTS_PORT_SFLGS_INVALID_LOOKUP \
+ | ERTS_PORT_SFLG_DISTRIBUTION)
+
+
+/*
+ * Costs in reductions for some port operations.
+ */
+#define ERTS_PORT_REDS_EXECUTE 10
+#define ERTS_PORT_REDS_FREE 100
+#define ERTS_PORT_REDS_TIMEOUT 400
+#define ERTS_PORT_REDS_INPUT 400
+#define ERTS_PORT_REDS_OUTPUT 400
+#define ERTS_PORT_REDS_EVENT 400
+#define ERTS_PORT_REDS_CMD_OUTPUTV 400
+#define ERTS_PORT_REDS_CMD_OUTPUT 400
+#define ERTS_PORT_REDS_EXIT 300
+#define ERTS_PORT_REDS_CONNECT 40
+#define ERTS_PORT_REDS_UNLINK 40
+#define ERTS_PORT_REDS_LINK 40
+#define ERTS_PORT_REDS_BADSIG 40
+#define ERTS_PORT_REDS_CONTROL 400
+#define ERTS_PORT_REDS_CALL 400
+#define ERTS_PORT_REDS_INFO 100
+#define ERTS_PORT_REDS_SET_DATA 40
+#define ERTS_PORT_REDS_GET_DATA 40
+#define ERTS_PORT_REDS_TERMINATE 200
+
+void print_port_info(Port *, int, void *);
+void erts_port_free(Port *);
+#ifndef ERTS_SMP
+void erts_port_cleanup(Port *);
+#endif
+void erts_fire_port_monitor(Port *prt, Eterm ref);
+#ifdef ERTS_SMP
+int erts_port_handle_xports(Port *);
+#endif
+
+#if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK)
+int erts_lc_is_port_locked(Port *);
+#endif
+
+ERTS_GLB_INLINE void erts_port_inc_refc(Port *prt);
+ERTS_GLB_INLINE void erts_port_dec_refc(Port *prt);
+ERTS_GLB_INLINE void erts_port_add_refc(Port *prt, Sint32 add_refc);
+
+ERTS_GLB_INLINE int erts_smp_port_trylock(Port *prt);
+ERTS_GLB_INLINE void erts_smp_port_lock(Port *prt);
+ERTS_GLB_INLINE void erts_smp_port_unlock(Port *prt);
+
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+
+ERTS_GLB_INLINE void erts_port_inc_refc(Port *prt)
+{
+#ifdef ERTS_SMP
+ erts_ptab_inc_refc(&prt->common);
+#else
+ erts_atomic32_inc_nob(&prt->refc);
+#endif
+}
+
+ERTS_GLB_INLINE void erts_port_dec_refc(Port *prt)
+{
+#ifdef ERTS_SMP
+ int referred = erts_ptab_dec_test_refc(&prt->common);
+ if (!referred)
+ erts_port_free(prt);
+#else
+ int refc = erts_atomic32_dec_read_nob(&prt->refc);
+ if (refc == 0)
+ erts_port_free(prt);
+#endif
+}
+
+ERTS_GLB_INLINE void erts_port_add_refc(Port *prt, Sint32 add_refc)
+{
+#ifdef ERTS_SMP
+ int referred = erts_ptab_add_test_refc(&prt->common, add_refc);
+ if (!referred)
+ erts_port_free(prt);
+#else
+ int refc = erts_atomic32_add_read_nob(&prt->refc, add_refc);
+ if (refc == 0)
+ erts_port_free(prt);
+#endif
+}
+
+ERTS_GLB_INLINE int
+erts_smp_port_trylock(Port *prt)
+{
+#ifdef ERTS_SMP
+ /* *Need* to be a managed thread */
+ ERTS_SMP_LC_ASSERT(erts_thr_progress_is_managed_thread());
+ return erts_mtx_trylock(prt->lock);
+#else
+ return 0;
+#endif
+}
+
+ERTS_GLB_INLINE void
+erts_smp_port_lock(Port *prt)
+{
+#ifdef ERTS_SMP
+ /* *Need* to be a managed thread */
+ ERTS_SMP_LC_ASSERT(erts_thr_progress_is_managed_thread());
+ erts_mtx_lock(prt->lock);
+#endif
+}
+
+ERTS_GLB_INLINE void
+erts_smp_port_unlock(Port *prt)
+{
+#ifdef ERTS_SMP
+ /* *Need* to be a managed thread */
+ ERTS_SMP_LC_ASSERT(erts_thr_progress_is_managed_thread());
+ erts_mtx_unlock(prt->lock);
+#endif
+}
+
+#endif /* #if ERTS_GLB_INLINE_INCL_FUNC_DEF */
+
+
+#define ERTS_INVALID_PORT_OPT(PP, ID, FLGS) \
+ (!(PP) \
+ || (erts_atomic32_read_nob(&(PP)->state) & (FLGS)) \
+ || (PP)->common.id != (ID))
+
+/* port lookup */
+
+#define INVALID_PORT(PP, ID) \
+ ERTS_INVALID_PORT_OPT((PP), (ID), ERTS_PORT_SFLGS_INVALID_LOOKUP)
+
+/* Invalidate trace port if anything suspicious, for instance
+ * that the port is a distribution port or it is busy.
+ */
+#define INVALID_TRACER_PORT(PP, ID) \
+ ERTS_INVALID_PORT_OPT((PP), (ID), ERTS_PORT_SFLGS_INVALID_TRACER_LOOKUP)
+
+#define ERTS_PORT_SCHED_ID(P, ID) \
+ ((Uint) (UWord) erts_prtsd_set((P), ERTS_PSD_SCHED_ID, (void *) (UWord) (ID)))
+
+extern const Port erts_invalid_port;
+#define ERTS_PORT_LOCK_BUSY ((Port *) &erts_invalid_port)
+
+int erts_is_port_ioq_empty(Port *);
+void erts_terminate_port(Port *);
+
+#ifdef ERTS_SMP
+Port *erts_de2port(DistEntry *, Process *, ErtsProcLocks);
+#endif
+
+ERTS_GLB_INLINE Port *erts_pix2port(int);
+ERTS_GLB_INLINE Port *erts_port_lookup_raw(Eterm);
+ERTS_GLB_INLINE Port *erts_port_lookup(Eterm, Uint32);
+ERTS_GLB_INLINE Port*erts_id2port(Eterm id);
+ERTS_GLB_INLINE Port *erts_id2port_sflgs(Eterm, Process *, ErtsProcLocks, Uint32);
+ERTS_GLB_INLINE void erts_port_release(Port *);
+#ifdef ERTS_SMP
+ERTS_GLB_INLINE Port *erts_thr_id2port_sflgs(Eterm id, Uint32 invalid_sflgs);
+ERTS_GLB_INLINE void erts_thr_port_release(Port *prt);
+#endif
+ERTS_GLB_INLINE Port *erts_thr_drvport2port_raw(ErlDrvPort, int);
+ERTS_GLB_INLINE Port *erts_drvport2port_raw(ErlDrvPort drvport);
+ERTS_GLB_INLINE Port *erts_drvport2port(ErlDrvPort, erts_aint32_t *);
+ERTS_GLB_INLINE Port *erts_drvportid2port(Eterm);
+ERTS_GLB_INLINE Eterm erts_drvport2id(ErlDrvPort);
+ERTS_GLB_INLINE Uint32 erts_portid2status(Eterm);
+ERTS_GLB_INLINE int erts_is_port_alive(Eterm);
+ERTS_GLB_INLINE int erts_is_valid_tracer_port(Eterm);
+ERTS_GLB_INLINE int erts_port_driver_callback_epilogue(Port *, erts_aint32_t *);
+
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+
+ERTS_GLB_INLINE Port *erts_pix2port(int ix)
+{
+ Port *prt;
+ ASSERT(0 <= ix && ix < erts_ptab_max(&erts_port));
+ prt = (Port *) erts_ptab_pix2intptr_nob(&erts_port, ix);
+ return prt == ERTS_PORT_LOCK_BUSY ? NULL : prt;
+}
+
+ERTS_GLB_INLINE Port *
+erts_port_lookup_raw(Eterm id)
+{
+ Port *prt;
+
+ ERTS_SMP_LC_ASSERT(erts_thr_progress_lc_is_delaying());
+
+ if (is_not_internal_port(id))
+ return NULL;
+
+ prt = (Port *) erts_ptab_pix2intptr_ddrb(&erts_port,
+ internal_port_index(id));
+ return prt && prt->common.id == id ? prt : NULL;
+}
+
+ERTS_GLB_INLINE Port *
+erts_port_lookup(Eterm id, Uint32 invalid_sflgs)
+{
+ Port *prt = erts_port_lookup_raw(id);
+ return (!prt
+ ? NULL
+ : ((invalid_sflgs & erts_atomic32_read_nob(&prt->state))
+ ? NULL
+ : prt));
+}
+
+
+ERTS_GLB_INLINE Port*
+erts_id2port(Eterm id)
+{
+ erts_aint32_t state;
+ Port *prt;
+
+ /* Only allowed to be called from managed threads */
+ ERTS_SMP_LC_ASSERT(erts_thr_progress_is_managed_thread());
+
+ if (is_not_internal_port(id))
+ return NULL;
+
+ prt = (Port *) erts_ptab_pix2intptr_ddrb(&erts_port,
+ internal_port_index(id));
+
+ if (!prt || prt->common.id != id)
+ return NULL;
+
+ erts_smp_port_lock(prt);
+ state = erts_atomic32_read_nob(&prt->state);
+ if (state & ERTS_PORT_SFLGS_INVALID_LOOKUP) {
+ erts_smp_port_unlock(prt);
+ return NULL;
+ }
+
+ return prt;
+}
+
+
+ERTS_GLB_INLINE Port*
+erts_id2port_sflgs(Eterm id,
+ Process *c_p, ErtsProcLocks c_p_locks,
+ Uint32 invalid_sflgs)
+{
+#ifdef ERTS_SMP
+ int no_proc_locks = !c_p || !c_p_locks;
+#endif
+ erts_aint32_t state;
+ Port *prt;
+
+ /* Only allowed to be called from managed threads */
+ ERTS_SMP_LC_ASSERT(erts_thr_progress_is_managed_thread());
+
+ if (is_not_internal_port(id))
+ return NULL;
+
+ prt = (Port *) erts_ptab_pix2intptr_ddrb(&erts_port,
+ internal_port_index(id));
+
+ if (!prt || prt->common.id != id)
+ return NULL;
+
+#ifdef ERTS_SMP
+ if (no_proc_locks)
+ erts_smp_port_lock(prt);
+ else if (erts_smp_port_trylock(prt) == EBUSY) {
+ /* Unlock process locks, and acquire locks in lock order... */
+ erts_smp_proc_unlock(c_p, c_p_locks);
+ erts_smp_port_lock(prt);
+ erts_smp_proc_lock(c_p, c_p_locks);
+ }
+#endif
+ state = erts_atomic32_read_nob(&prt->state);
+ if (state & invalid_sflgs) {
+#ifdef ERTS_SMP
+ erts_smp_port_unlock(prt);
+#endif
+ return NULL;
+ }
+
+ return prt;
+}
+
+ERTS_GLB_INLINE void
+erts_port_release(Port *prt)
+{
+ /* Only allowed to be called from managed threads */
+ ERTS_SMP_LC_ASSERT(erts_thr_progress_is_managed_thread());
+#ifdef ERTS_SMP
+ erts_smp_port_unlock(prt);
+#else
+ if (prt->cleanup) {
+ prt->cleanup = 0;
+ erts_port_cleanup(prt);
+ }
+#endif
+}
+
+#ifdef ERTS_SMP
+
+/*
+ * erts_thr_id2port_sflgs() and erts_thr_port_release() can
+ * be used by unmanaged threads in the SMP case.
+ */
+ERTS_GLB_INLINE Port *
+erts_thr_id2port_sflgs(Eterm id, Uint32 invalid_sflgs)
+{
+ Port *prt;
+ ErtsThrPrgrDelayHandle dhndl;
+
+ if (is_not_internal_port(id))
+ return NULL;
+
+ dhndl = erts_thr_progress_unmanaged_delay();
+
+ prt = (Port *) erts_ptab_pix2intptr_ddrb(&erts_port,
+ internal_port_index(id));
+
+ if (!prt || prt->common.id != id) {
+ erts_thr_progress_unmanaged_continue(dhndl);
+ prt = NULL;
+ }
+ else {
+ erts_aint32_t state;
+ if (dhndl != ERTS_THR_PRGR_DHANDLE_MANAGED) {
+ erts_port_inc_refc(prt);
+ erts_thr_progress_unmanaged_continue(dhndl);
+ }
+
+ erts_mtx_lock(prt->lock);
+ state = erts_atomic32_read_nob(&prt->state);
+ if (state & invalid_sflgs) {
+ erts_mtx_unlock(prt->lock);
+ if (dhndl != ERTS_THR_PRGR_DHANDLE_MANAGED)
+ erts_port_dec_refc(prt);
+ prt = NULL;
+ }
+ }
+
+ return prt;
+}
+
+ERTS_GLB_INLINE void
+erts_thr_port_release(Port *prt)
+{
+ erts_mtx_unlock(prt->lock);
+#ifdef ERTS_SMP
+ if (!erts_thr_progress_is_managed_thread())
+ erts_port_dec_refc(prt);
+#endif
+}
+
+#endif
+
+ERTS_GLB_INLINE Port*
+erts_thr_drvport2port_raw(ErlDrvPort drvport, int lock_pdl)
+{
+#if ERTS_ENABLE_LOCK_CHECK
+ int emu_thread = erts_lc_is_emu_thr();
+#endif
+ if (drvport == ERTS_INVALID_ERL_DRV_PORT)
+ return NULL;
+ else {
+ Port *prt = (Port *) drvport;
+ if (lock_pdl && prt->port_data_lock)
+ driver_pdl_lock(prt->port_data_lock);
+#if ERTS_ENABLE_LOCK_CHECK
+ if (!ERTS_IS_CRASH_DUMPING) {
+ if (emu_thread) {
+ ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
+ ERTS_LC_ASSERT(!prt->port_data_lock
+ || erts_lc_mtx_is_locked(&prt->port_data_lock->mtx));
+ }
+ else {
+ ERTS_LC_ASSERT(prt->port_data_lock);
+ ERTS_LC_ASSERT(erts_lc_mtx_is_locked(&prt->port_data_lock->mtx));
+ }
+ }
+#endif
+ return prt;
+ }
+}
+
+ERTS_GLB_INLINE Port*
+erts_drvport2port_raw(ErlDrvPort drvport)
+{
+ ERTS_LC_ASSERT(erts_lc_is_emu_thr());
+ if (drvport == ERTS_INVALID_ERL_DRV_PORT)
+ return NULL;
+ else {
+ Port *prt = (Port *) drvport;
+ ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)
+ || ERTS_IS_CRASH_DUMPING);
+ return prt;
+ }
+}
+
+ERTS_GLB_INLINE Port*
+erts_drvport2port(ErlDrvPort drvport, erts_aint32_t *statep)
+{
+ Port *prt = erts_drvport2port_raw(drvport);
+ erts_aint32_t state;
+ if (!prt)
+ return NULL;
+ state = erts_atomic32_read_nob(&prt->state);
+ if (state & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP)
+ return NULL;
+ if (statep)
+ *statep = state;
+ return prt;
+}
+
+ERTS_GLB_INLINE Port*
+erts_drvportid2port(Eterm id)
+{
+ Port *prt;
+ erts_aint32_t state;
+ if (is_not_internal_port(id))
+ return NULL;
+ prt = (Port *) erts_ptab_pix2intptr_nob(&erts_port,
+ internal_port_index(id));
+ if (!prt)
+ return NULL;
+ ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)
+ || ERTS_IS_CRASH_DUMPING);
+ if (prt->common.id != id)
+ return NULL;
+ state = erts_atomic32_read_nob(&prt->state);
+ if (state & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP)
+ return NULL;
+ return prt;
+}
+
+ERTS_GLB_INLINE Eterm
+erts_drvport2id(ErlDrvPort drvport)
+{
+ Port *prt = erts_drvport2port_raw(drvport);
+ if (!prt)
+ return am_undefined;
+ else
+ return prt->common.id;
+}
+
+ERTS_GLB_INLINE Uint32
+erts_portid2status(Eterm id)
+{
+ Port *prt = erts_port_lookup_raw(id);
+ if (prt)
+ return (Uint32) erts_atomic32_read_acqb(&prt->state);
+ else
+ return ERTS_PORT_SFLG_INVALID;
+}
+
+ERTS_GLB_INLINE int
+erts_is_port_alive(Eterm id)
+{
+ return !(erts_portid2status(id) & (ERTS_PORT_SFLG_INVALID
+ | ERTS_PORT_SFLGS_DEAD));
+}
+
+ERTS_GLB_INLINE int
+erts_is_valid_tracer_port(Eterm id)
+{
+ return !(erts_portid2status(id) & ERTS_PORT_SFLGS_INVALID_TRACER_LOOKUP);
+}
+
+ERTS_GLB_INLINE int
+erts_port_driver_callback_epilogue(Port *prt, erts_aint32_t *statep)
+{
+ int reds = 0;
+ erts_aint32_t state;
+
+ ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
+
+ state = erts_atomic32_read_nob(&prt->state);
+ if ((state & ERTS_PORT_SFLG_CLOSING) && erts_is_port_ioq_empty(prt)) {
+ reds += ERTS_PORT_REDS_TERMINATE;
+ erts_terminate_port(prt);
+ state = erts_atomic32_read_nob(&prt->state);
+ ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
+ }
+
+#ifdef ERTS_SMP
+ if (prt->xports) {
+ reds += erts_port_handle_xports(prt);
+ ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
+ ASSERT(!prt->xports);
+ }
+#endif
+
+ if (statep)
+ *statep = state;
+
+ return reds;
+}
+
+#endif /* #if ERTS_GLB_INLINE_INCL_FUNC_DEF */
+
+void erts_port_resume_procs(Port *);
+
+struct binary;
+
+#define ERTS_P2P_SIG_TYPE_BAD 0
+#define ERTS_P2P_SIG_TYPE_OUTPUT 1
+#define ERTS_P2P_SIG_TYPE_OUTPUTV 2
+#define ERTS_P2P_SIG_TYPE_CONNECT 3
+#define ERTS_P2P_SIG_TYPE_EXIT 4
+#define ERTS_P2P_SIG_TYPE_CONTROL 5
+#define ERTS_P2P_SIG_TYPE_CALL 6
+#define ERTS_P2P_SIG_TYPE_INFO 7
+#define ERTS_P2P_SIG_TYPE_LINK 8
+#define ERTS_P2P_SIG_TYPE_UNLINK 9
+#define ERTS_P2P_SIG_TYPE_SET_DATA 10
+#define ERTS_P2P_SIG_TYPE_GET_DATA 11
+
+#define ERTS_P2P_SIG_TYPE_BITS 4
+#define ERTS_P2P_SIG_TYPE_MASK \
+ ((1 << ERTS_P2P_SIG_TYPE_BITS) - 1)
+
+#define ERTS_P2P_SIG_DATA_FLG(N) \
+ (1 << (ERTS_P2P_SIG_TYPE_BITS + (N)))
+#define ERTS_P2P_SIG_DATA_FLG_BANG_OP ERTS_P2P_SIG_DATA_FLG(0)
+#define ERTS_P2P_SIG_DATA_FLG_REPLY ERTS_P2P_SIG_DATA_FLG(1)
+#define ERTS_P2P_SIG_DATA_FLG_NOSUSPEND ERTS_P2P_SIG_DATA_FLG(2)
+#define ERTS_P2P_SIG_DATA_FLG_FORCE ERTS_P2P_SIG_DATA_FLG(3)
+#define ERTS_P2P_SIG_DATA_FLG_BAD_OUTPUT ERTS_P2P_SIG_DATA_FLG(4)
+#define ERTS_P2P_SIG_DATA_FLG_BROKEN_LINK ERTS_P2P_SIG_DATA_FLG(5)
+#define ERTS_P2P_SIG_DATA_FLG_SCHED ERTS_P2P_SIG_DATA_FLG(6)
+
+struct ErtsProc2PortSigData_ {
+ int flags;
+ Eterm caller;
+ Uint32 ref[ERTS_MAX_REF_NUMBERS];
+ union {
+ struct {
+ Eterm from;
+ ErlIOVec *evp;
+ ErlDrvBinary *cbinp;
+ } outputv;
+ struct {
+ Eterm from;
+ char *bufp;
+ ErlDrvSizeT size;
+ } output;
+ struct {
+ Eterm from;
+ Eterm connected;
+ } connect;
+ struct {
+ Eterm from;
+ Eterm reason;
+ ErlHeapFragment *bp;
+ } exit;
+ struct {
+ struct binary *binp;
+ unsigned int command;
+ char *bufp;
+ ErlDrvSizeT size;
+ } control;
+ struct {
+ unsigned int command;
+ char *bufp;
+ ErlDrvSizeT size;
+ } call;
+ struct {
+ Eterm item;
+ } info;
+ struct {
+ Eterm port;
+ Eterm to;
+ } link;
+ struct {
+ Eterm from;
+ } unlink;
+ struct {
+ ErlHeapFragment *bp;
+ Eterm data;
+ } set_data;
+ } u;
+} ;
+
+ERTS_GLB_INLINE int
+erts_proc2port_sig_is_command_op(ErtsProc2PortSigData *sigdp);
+ERTS_GLB_INLINE ErlDrvSizeT
+erts_proc2port_sig_command_data_size(ErtsProc2PortSigData *sigdp);
+
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+
+ERTS_GLB_INLINE int
+erts_proc2port_sig_is_command_op(ErtsProc2PortSigData *sigdp)
+{
+ switch (sigdp->flags & ERTS_P2P_SIG_TYPE_MASK) {
+ case ERTS_P2P_SIG_TYPE_OUTPUT: return !0;
+ case ERTS_P2P_SIG_TYPE_OUTPUTV: return !0;
+ default: return 0;
+ }
+}
+
+ERTS_GLB_INLINE ErlDrvSizeT
+erts_proc2port_sig_command_data_size(ErtsProc2PortSigData *sigdp)
+{
+ switch (sigdp->flags & ERTS_P2P_SIG_TYPE_MASK) {
+ case ERTS_P2P_SIG_TYPE_OUTPUT: return sigdp->u.output.size;
+ case ERTS_P2P_SIG_TYPE_OUTPUTV: return sigdp->u.outputv.evp->size;
+ default: return (ErlDrvSizeT) 0;
+ }
+}
+
+#endif
+
+#define ERTS_PROC2PORT_SIG_EXEC 0
+#define ERTS_PROC2PORT_SIG_ABORT 1
+#define ERTS_PROC2PORT_SIG_ABORT_NOSUSPEND 2
+#define ERTS_PROC2PORT_SIG_ABORT_CLOSED 3
+
+typedef int (*ErtsProc2PortSigCallback)(Port *,
+ erts_aint32_t,
+ int,
+ ErtsProc2PortSigData *);
+
+typedef enum {
+ ERTS_PORT_OP_BADARG,
+ ERTS_PORT_OP_CALLER_EXIT,
+ ERTS_PORT_OP_BUSY,
+ ERTS_PORT_OP_BUSY_SCHEDULED,
+ ERTS_PORT_OP_SCHEDULED,
+ ERTS_PORT_OP_DROPPED,
+ ERTS_PORT_OP_DONE
+} ErtsPortOpResult;
+
+ErtsPortOpResult
+erts_schedule_proc2port_signal(Process *,
+ Port *,
+ Eterm,
+ Eterm *,
+ ErtsProc2PortSigData *,
+ int,
+ ErtsProc2PortSigCallback);
+
+int erts_deliver_port_exit(Port *, Eterm, Eterm, int);
+
+/*
+ * Port signal flags
+ */
+#define ERTS_PORT_SIG_FLG_BANG_OP ERTS_P2P_SIG_DATA_FLG_BANG_OP
+#define ERTS_PORT_SIG_FLG_NOSUSPEND ERTS_P2P_SIG_DATA_FLG_NOSUSPEND
+#define ERTS_PORT_SIG_FLG_FORCE ERTS_P2P_SIG_DATA_FLG_FORCE
+#define ERTS_PORT_SIG_FLG_BROKEN_LINK ERTS_P2P_SIG_DATA_FLG_BROKEN_LINK
+#define ERTS_PORT_SIG_FLG_BAD_OUTPUT ERTS_P2P_SIG_DATA_FLG_BAD_OUTPUT
+#define ERTS_PORT_SIG_FLG_FORCE_SCHED ERTS_P2P_SIG_DATA_FLG_SCHED
+/* ERTS_PORT_SIG_FLG_FORCE_IMM_CALL only when crash dumping... */
+#define ERTS_PORT_SIG_FLG_FORCE_IMM_CALL ERTS_P2P_SIG_DATA_FLG_BAD_OUTPUT
+
+/*
+ * Port ! {Owner, {command, Data}}
+ * Port ! {Owner, {connect, NewOwner}}
+ * Port ! {Owner, close}
+ */
+ErtsPortOpResult erts_port_command(Process *, int, Port *, Eterm, Eterm *);
+
+/*
+ * Signals from processes to ports.
+ */
+ErtsPortOpResult erts_port_output(Process *, int, Port *, Eterm, Eterm, Eterm *);
+ErtsPortOpResult erts_port_exit(Process *, int, Port *, Eterm, Eterm, Eterm *);
+ErtsPortOpResult erts_port_connect(Process *, int, Port *, Eterm, Eterm, Eterm *);
+ErtsPortOpResult erts_port_link(Process *, Port *, Eterm, Eterm *);
+ErtsPortOpResult erts_port_unlink(Process *, Port *, Eterm, Eterm *);
+ErtsPortOpResult erts_port_control(Process *, Port *, unsigned int, Eterm, Eterm *);
+ErtsPortOpResult erts_port_call(Process *, Port *, unsigned int, Eterm, Eterm *);
+ErtsPortOpResult erts_port_info(Process *, Port *, Eterm, Eterm *);
+ErtsPortOpResult erts_port_set_data(Process *, Port *, Eterm, Eterm *);
+ErtsPortOpResult erts_port_get_data(Process *, Port *, Eterm *);
+
+#endif
diff --git a/erts/emulator/beam/erl_port_task.c b/erts/emulator/beam/erl_port_task.c
index 86454fe1fa..8ceadcdb8c 100644
--- a/erts/emulator/beam/erl_port_task.c
+++ b/erts/emulator/beam/erl_port_task.c
@@ -33,36 +33,29 @@
#include "erl_port_task.h"
#include "dist.h"
#include "dtrace-wrapper.h"
+#include <stdarg.h>
#if defined(DEBUG) && 0
-#define HARD_DEBUG
+#define ERTS_HARD_DEBUG_TASK_QUEUES
+#else
+#undef ERTS_HARD_DEBUG_TASK_QUEUES
#endif
-/*
- * Costs in reductions for some port operations.
- */
-#define ERTS_PORT_REDS_EXECUTE 0
-#define ERTS_PORT_REDS_FREE 50
-#define ERTS_PORT_REDS_TIMEOUT 200
-#define ERTS_PORT_REDS_INPUT 200
-#define ERTS_PORT_REDS_OUTPUT 200
-#define ERTS_PORT_REDS_EVENT 200
-#define ERTS_PORT_REDS_TERMINATE 100
-
-
-#define ERTS_PORT_TASK_INVALID_PORT(P, ID) \
- ((erts_port_status_get((P)) & ERTS_PORT_SFLGS_DEAD) || (P)->id != (ID))
-
-#define ERTS_PORT_IS_IN_RUNQ(RQ, P) \
- ((P)->sched.next || (P)->sched.prev || (RQ)->ports.start == (P))
+#ifdef ERTS_HARD_DEBUG_TASK_QUEUES
+static void chk_task_queues(Port *pp, ErtsPortTask *execq, int processing_busy_queue);
+#define ERTS_PT_DBG_CHK_TASK_QS(PP, EQ, PBQ) \
+ chk_task_queues((PP), (EQ), (PBQ))
+#else
+#define ERTS_PT_DBG_CHK_TASK_QS(PP, EQ, PBQ)
+#endif
#ifdef USE_VM_PROBES
#define DTRACE_DRIVER(PROBE_NAME, PP) \
- if (DTRACE_ENABLED(driver_ready_input)) { \
+ if (DTRACE_ENABLED(PROBE_NAME)) { \
DTRACE_CHARBUF(process_str, DTRACE_TERM_BUF_SIZE); \
DTRACE_CHARBUF(port_str, DTRACE_TERM_BUF_SIZE); \
\
- dtrace_pid_str(PP->connected, process_str); \
+ dtrace_pid_str(ERTS_PORT_GET_CONNECTED(PP), process_str); \
dtrace_port_str(PP, port_str); \
DTRACE3(PROBE_NAME, process_str, port_str, PP->name); \
}
@@ -72,83 +65,768 @@
erts_smp_atomic_t erts_port_task_outstanding_io_tasks;
-struct ErtsPortTaskQueue_ {
- ErtsPortTask *first;
- ErtsPortTask *last;
- Port *port;
-};
+#define ERTS_PT_STATE_SCHEDULED 0
+#define ERTS_PT_STATE_ABORTED 1
+#define ERTS_PT_STATE_EXECUTING 2
+
+typedef union {
+ struct { /* I/O tasks */
+ ErlDrvEvent event;
+ ErlDrvEventData event_data;
+ } io;
+ struct {
+ ErtsProc2PortSigCallback callback;
+ ErtsProc2PortSigData data;
+ } psig;
+} ErtsPortTaskTypeData;
struct ErtsPortTask_ {
- ErtsPortTask *prev;
- ErtsPortTask *next;
- ErtsPortTaskQueue *queue;
- ErtsPortTaskHandle *handle;
+ erts_smp_atomic32_t state;
ErtsPortTaskType type;
- ErlDrvEvent event;
- ErlDrvEventData event_data;
+ union {
+ struct {
+ ErtsPortTask *next;
+ ErtsPortTaskHandle *handle;
+ int flags;
+ Uint32 ref[ERTS_MAX_REF_NUMBERS];
+ ErtsPortTaskTypeData td;
+ } alive;
+ ErtsThrPrgrLaterOp release;
+ } u;
};
-#ifdef HARD_DEBUG
-#define ERTS_PT_CHK_PORTQ(RQ) check_port_queue((RQ), NULL, 0)
-#define ERTS_PT_CHK_PRES_PORTQ(RQ, PP) check_port_queue((RQ), (PP), -1)
-#define ERTS_PT_CHK_IN_PORTQ(RQ, PP) check_port_queue((RQ), (PP), 1)
-#define ERTS_PT_CHK_NOT_IN_PORTQ(RQ, PP) check_port_queue((RQ), (PP), 0)
-#define ERTS_PT_CHK_TASKQ(Q) check_task_queue((Q), NULL, 0)
-#define ERTS_PT_CHK_IN_TASKQ(Q, T) check_task_queue((Q), (T), 1)
-#define ERTS_PT_CHK_NOT_IN_TASKQ(Q, T) check_task_queue((Q), (T), 0)
-static void
-check_port_queue(Port *chk_pp, int inq);
-static void
-check_task_queue(ErtsPortTaskQueue *ptqp,
- ErtsPortTask *chk_ptp,
- int inq);
-#else
-#define ERTS_PT_CHK_PORTQ(RQ)
-#define ERTS_PT_CHK_PRES_PORTQ(RQ, PP)
-#define ERTS_PT_CHK_IN_PORTQ(RQ, PP)
-#define ERTS_PT_CHK_NOT_IN_PORTQ(RQ, PP)
-#define ERTS_PT_CHK_TASKQ(Q)
-#define ERTS_PT_CHK_IN_TASKQ(Q, T)
-#define ERTS_PT_CHK_NOT_IN_TASKQ(Q, T)
+struct ErtsPortTaskHandleList_ {
+ ErtsPortTaskHandle handle;
+ union {
+ ErtsPortTaskHandleList *next;
+#ifdef ERTS_SMP
+ ErtsThrPrgrLaterOp release;
#endif
+ } u;
+};
+
+typedef struct ErtsPortTaskBusyCaller_ ErtsPortTaskBusyCaller;
+struct ErtsPortTaskBusyCaller_ {
+ ErtsPortTaskBusyCaller *next;
+ Eterm caller;
+ SWord count;
+ ErtsPortTask *last;
+};
+
+#define ERTS_PORT_TASK_BUSY_CALLER_TABLE_BUCKETS 17
+struct ErtsPortTaskBusyCallerTable_ {
+ ErtsPortTaskBusyCaller *bucket[ERTS_PORT_TASK_BUSY_CALLER_TABLE_BUCKETS];
+ ErtsPortTaskBusyCaller pre_alloc_busy_caller;
+};
+
-static void handle_remaining_tasks(ErtsRunQueue *runq, Port *pp);
+static void begin_port_cleanup(Port *pp,
+ ErtsPortTask **execq,
+ int *processing_busy_q_p);
ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(port_task,
ErtsPortTask,
- 200,
+ 1000,
ERTS_ALC_T_PORT_TASK)
-ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(port_taskq,
- ErtsPortTaskQueue,
+
+ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(busy_caller_table,
+ ErtsPortTaskBusyCallerTable,
50,
- ERTS_ALC_T_PORT_TASKQ)
+ ERTS_ALC_T_BUSY_CALLER_TAB)
+
+#ifdef ERTS_SMP
+static void
+call_port_task_free(void *vptp)
+{
+ port_task_free((ErtsPortTask *) vptp);
+}
+#endif
+
+static ERTS_INLINE void
+schedule_port_task_free(ErtsPortTask *ptp)
+{
+#ifdef ERTS_SMP
+ erts_schedule_thr_prgr_later_op(call_port_task_free,
+ (void *) ptp,
+ &ptp->u.release);
+#else
+ port_task_free(ptp);
+#endif
+}
+
+static ERTS_INLINE ErtsPortTask *
+p2p_sig_data_to_task(ErtsProc2PortSigData *sigdp)
+{
+ ErtsPortTask *ptp;
+ char *ptr = (char *) sigdp;
+ ptr -= offsetof(ErtsPortTask, u.alive.td.psig.data);
+ ptp = (ErtsPortTask *) ptr;
+ ASSERT(ptp->type == ERTS_PORT_TASK_PROC_SIG);
+ return ptp;
+}
+
+ErtsProc2PortSigData *
+erts_port_task_alloc_p2p_sig_data(void)
+{
+ ErtsPortTask *ptp = port_task_alloc();
+
+ ptp->type = ERTS_PORT_TASK_PROC_SIG;
+ ptp->u.alive.flags = ERTS_PT_FLG_SIG_DEP;
+ erts_smp_atomic32_init_nob(&ptp->state, ERTS_PT_STATE_SCHEDULED);
+
+ ASSERT(ptp == p2p_sig_data_to_task(&ptp->u.alive.td.psig.data));
+
+ return &ptp->u.alive.td.psig.data;
+}
+
+static ERTS_INLINE Eterm
+task_caller(ErtsPortTask *ptp)
+{
+ Eterm caller;
+
+ ASSERT(ptp->type == ERTS_PORT_TASK_PROC_SIG);
+
+ caller = ptp->u.alive.td.psig.data.caller;
+
+ ASSERT(is_internal_pid(caller) || is_internal_port(caller));
+
+ return caller;
+}
+
+/*
+ * Busy queue management
+ */
+
+static ERTS_INLINE int
+caller2bix(Eterm caller)
+{
+ ASSERT(is_internal_pid(caller) || is_internal_port(caller));
+ return (int) (_GET_PID_DATA(caller) % ERTS_PORT_TASK_BUSY_CALLER_TABLE_BUCKETS);
+}
+
+
+static void
+popped_from_busy_queue(Port *pp, ErtsPortTask *ptp, int last)
+{
+ ErtsPortTaskBusyCaller **prev_bcpp = NULL, *bcp;
+ ErtsPortTaskBusyCallerTable *tabp = pp->sched.taskq.local.busy.table;
+ Eterm caller = task_caller(ptp);
+ int bix = caller2bix(caller);
+
+ ASSERT(is_internal_pid(caller));
+
+ ASSERT(tabp);
+ bcp = tabp->bucket[bix];
+ prev_bcpp = &tabp->bucket[bix];
+ ASSERT(bcp);
+ while (bcp->caller != caller) {
+ prev_bcpp = &bcp->next;
+ bcp = bcp->next;
+ ASSERT(bcp);
+ }
+ ASSERT(bcp->count > 0);
+ if (--bcp->count != 0) {
+ ASSERT(!last);
+ }
+ else {
+ *prev_bcpp = bcp->next;
+ if (bcp == &tabp->pre_alloc_busy_caller)
+ bcp->caller = am_undefined;
+ else
+ erts_free(ERTS_ALC_T_BUSY_CALLER, bcp);
+ if (last) {
+#ifdef DEBUG
+ erts_aint32_t flags =
+#endif
+ erts_smp_atomic32_read_band_nob(
+ &pp->sched.flags,
+ ~ERTS_PTS_FLG_HAVE_BUSY_TASKS);
+ ASSERT(flags & ERTS_PTS_FLG_HAVE_BUSY_TASKS);
+#ifdef DEBUG
+ for (bix = 0; bix < ERTS_PORT_TASK_BUSY_CALLER_TABLE_BUCKETS; bix++) {
+ ASSERT(!tabp->bucket[bix]);
+ }
+#endif
+ busy_caller_table_free(tabp);
+ pp->sched.taskq.local.busy.first = NULL;
+ pp->sched.taskq.local.busy.last = NULL;
+ pp->sched.taskq.local.busy.table = NULL;
+ }
+ }
+}
+
+static void
+busy_wait_move_to_busy_queue(Port *pp, ErtsPortTask *ptp)
+{
+ ErtsPortTaskBusyCallerTable *tabp = pp->sched.taskq.local.busy.table;
+ Eterm caller = task_caller(ptp);
+ ErtsPortTaskBusyCaller *bcp;
+ int bix;
+
+ ASSERT(is_internal_pid(caller));
+ /*
+ * Port is busy and this task type needs to wait until not busy.
+ */
+
+ ASSERT(ptp->u.alive.flags & ERTS_PT_FLG_WAIT_BUSY);
+
+ ptp->u.alive.next = NULL;
+ if (pp->sched.taskq.local.busy.last) {
+ ASSERT(pp->sched.taskq.local.busy.first);
+ pp->sched.taskq.local.busy.last->u.alive.next = ptp;
+ }
+ else {
+ int i;
+ erts_aint32_t flags;
+
+ pp->sched.taskq.local.busy.first = ptp;
+ flags = erts_smp_atomic32_read_bor_nob(&pp->sched.flags,
+ ERTS_PTS_FLG_HAVE_BUSY_TASKS);
+ ASSERT(!(flags & ERTS_PTS_FLG_HAVE_BUSY_TASKS));
+
+ ASSERT(!tabp);
+
+ tabp = busy_caller_table_alloc();
+ pp->sched.taskq.local.busy.table = tabp;
+ for (i = 0; i < ERTS_PORT_TASK_BUSY_CALLER_TABLE_BUCKETS; i++)
+ tabp->bucket[i] = NULL;
+ tabp->pre_alloc_busy_caller.caller = am_undefined;
+ }
+ pp->sched.taskq.local.busy.last = ptp;
+
+ bix = caller2bix(caller);
+ ASSERT(tabp);
+ bcp = tabp->bucket[bix];
+
+ while (bcp && bcp->caller != caller)
+ bcp = bcp->next;
+
+ if (bcp)
+ bcp->count++;
+ else {
+ if (tabp->pre_alloc_busy_caller.caller == am_undefined)
+ bcp = &tabp->pre_alloc_busy_caller;
+ else
+ bcp = erts_alloc(ERTS_ALC_T_BUSY_CALLER,
+ sizeof(ErtsPortTaskBusyCaller));
+ bcp->caller = caller;
+ bcp->count = 1;
+ bcp->next = tabp->bucket[bix];
+ tabp->bucket[bix] = bcp;
+ }
+
+ bcp->last = ptp;
+}
+
+static ERTS_INLINE int
+check_sig_dep_move_to_busy_queue(Port *pp, ErtsPortTask *ptp)
+{
+ ErtsPortTaskBusyCallerTable *tabp = pp->sched.taskq.local.busy.table;
+ ErtsPortTask *last_ptp;
+ ErtsPortTaskBusyCaller *bcp;
+ int bix;
+ Eterm caller;
+
+ ASSERT(ptp->u.alive.flags & ERTS_PT_FLG_SIG_DEP);
+ ASSERT(pp->sched.taskq.local.busy.last);
+ ASSERT(tabp);
+
+
+ /*
+ * We are either not busy, or the task does not imply wait on busy port.
+ * However, due to the signaling order requirements the task might depend
+ * on other tasks in the busy queue.
+ */
+
+ caller = task_caller(ptp);
+ bix = caller2bix(caller);
+ bcp = tabp->bucket[bix];
+ while (bcp && bcp->caller != caller)
+ bcp = bcp->next;
+
+ if (!bcp)
+ return 0;
+
+ /*
+ * There are other tasks that we depend on in the busy queue;
+ * move into busy queue.
+ */
+
+ bcp->count++;
+ last_ptp = bcp->last;
+ ptp->u.alive.next = last_ptp->u.alive.next;
+ if (!ptp->u.alive.next) {
+ ASSERT(pp->sched.taskq.local.busy.last == last_ptp);
+ pp->sched.taskq.local.busy.last = ptp;
+ }
+ last_ptp->u.alive.next = ptp;
+ bcp->last = ptp;
+
+ return 1;
+}
+
+static void
+no_sig_dep_move_from_busyq(Port *pp)
+{
+ ErtsPortTaskBusyCallerTable *tabp = pp->sched.taskq.local.busy.table;
+ ErtsPortTask *first_ptp, *last_ptp, *ptp;
+ ErtsPortTaskBusyCaller **prev_bcpp = NULL, *bcp = NULL;
+
+ /*
+ * Move tasks at the head of the busy queue that no longer
+ * have any dependencies to busy wait tasks into the ordinary
+ * queue.
+ */
+
+ first_ptp = ptp = pp->sched.taskq.local.busy.first;
+
+ ASSERT(ptp && !(ptp->u.alive.flags & ERTS_PT_FLG_WAIT_BUSY));
+ ASSERT(tabp);
+
+ do {
+ Eterm caller = task_caller(ptp);
+
+ if (!bcp || bcp->caller != caller) {
+ int bix = caller2bix(caller);
+
+ prev_bcpp = &tabp->bucket[bix];
+ bcp = tabp->bucket[bix];
+ ASSERT(bcp);
+ while (bcp->caller != caller) {
+ ASSERT(bcp);
+ prev_bcpp = &bcp->next;
+ bcp = bcp->next;
+ }
+ }
+
+ ASSERT(bcp->caller == caller);
+ ASSERT(bcp->count > 0);
+
+ if (--bcp->count == 0) {
+ *prev_bcpp = bcp->next;
+ if (bcp == &tabp->pre_alloc_busy_caller)
+ bcp->caller = am_undefined;
+ else
+ erts_free(ERTS_ALC_T_BUSY_CALLER, bcp);
+ }
+
+ last_ptp = ptp;
+ ptp = ptp->u.alive.next;
+ } while (ptp && !(ptp->u.alive.flags & ERTS_PT_FLG_WAIT_BUSY));
+
+ pp->sched.taskq.local.busy.first = last_ptp->u.alive.next;
+ if (!pp->sched.taskq.local.busy.first) {
+#ifdef DEBUG
+ int bix;
+ erts_aint32_t flags =
+#endif
+ erts_smp_atomic32_read_band_nob(
+ &pp->sched.flags,
+ ~ERTS_PTS_FLG_HAVE_BUSY_TASKS);
+ ASSERT(flags & ERTS_PTS_FLG_HAVE_BUSY_TASKS);
+#ifdef DEBUG
+ for (bix = 0; bix < ERTS_PORT_TASK_BUSY_CALLER_TABLE_BUCKETS; bix++) {
+ ASSERT(!tabp->bucket[bix]);
+ }
+#endif
+ busy_caller_table_free(tabp);
+ pp->sched.taskq.local.busy.last = NULL;
+ pp->sched.taskq.local.busy.table = NULL;
+ }
+ last_ptp->u.alive.next = pp->sched.taskq.local.first;
+ pp->sched.taskq.local.first = first_ptp;
+}
+
+#ifdef ERTS_HARD_DEBUG_TASK_QUEUES
+
+static void
+chk_task_queues(Port *pp, ErtsPortTask *execq, int processing_busy_queue)
+{
+ Sint tot_count, tot_table_count;
+ int bix;
+ ErtsPortTask *ptp, *last;
+ ErtsPortTask *first = processing_busy_queue ? execq : pp->sched.taskq.local.busy.first;
+ ErtsPortTask *nb_task_queue = processing_busy_queue ? pp->sched.taskq.local.first : execq;
+ ErtsPortTaskBusyCallerTable *tabp = pp->sched.taskq.local.busy.table;
+ ErtsPortTaskBusyCaller *bcp;
+
+ if (!first) {
+ ASSERT(!tabp);
+ ASSERT(!pp->sched.taskq.local.busy.last);
+ ASSERT(!(erts_smp_atomic32_read_nob(&pp->sched.flags) & ERTS_PTS_FLG_HAVE_BUSY_TASKS));
+ return;
+ }
+
+ ASSERT(erts_smp_atomic32_read_nob(&pp->sched.flags) & ERTS_PTS_FLG_HAVE_BUSY_TASKS);
+ ASSERT(tabp);
+
+ tot_count = 0;
+ ptp = first;
+ while (ptp) {
+ Sint count = 0;
+ Eterm caller = task_caller(ptp);
+ int bix = caller2bix(caller);
+ for (bcp = tabp->bucket[bix]; bcp; bcp = bcp->next)
+ if (bcp->caller == caller)
+ break;
+ ASSERT(bcp && bcp->caller == caller);
+
+ ASSERT(bcp->last);
+ while (1) {
+ ErtsPortTask *ptp2;
+
+ ASSERT(caller == task_caller(ptp));
+ count++;
+ tot_count++;
+ last = ptp;
+
+ for (ptp2 = nb_task_queue; ptp2; ptp2 = ptp2->u.alive.next) {
+ ASSERT(ptp != ptp2);
+ }
+
+ if (ptp == bcp->last)
+ break;
+ ptp = ptp->u.alive.next;
+ }
+
+ ASSERT(count == bcp->count);
+ ptp = ptp->u.alive.next;
+ }
+
+ tot_table_count = 0;
+ for (bix = 0; bix < ERTS_PORT_TASK_BUSY_CALLER_TABLE_BUCKETS; bix++) {
+ for (bcp = tabp->bucket[bix]; bcp; bcp = bcp->next)
+ tot_table_count += bcp->count;
+ }
+
+ ASSERT(tot_count == tot_table_count);
+
+ ASSERT(last == pp->sched.taskq.local.busy.last);
+}
+
+#endif /* ERTS_HARD_DEBUG_TASK_QUEUES */
/*
* Task handle manipulation.
*/
+static ERTS_INLINE void
+reset_port_task_handle(ErtsPortTaskHandle *pthp)
+{
+ erts_smp_atomic_set_relb(pthp, (erts_aint_t) NULL);
+}
+
static ERTS_INLINE ErtsPortTask *
handle2task(ErtsPortTaskHandle *pthp)
{
- return (ErtsPortTask *) erts_smp_atomic_read_nob(pthp);
+ return (ErtsPortTask *) erts_smp_atomic_read_acqb(pthp);
}
static ERTS_INLINE void
reset_handle(ErtsPortTask *ptp)
{
- if (ptp->handle) {
- ASSERT(ptp == handle2task(ptp->handle));
- erts_smp_atomic_set_nob(ptp->handle, (erts_aint_t) NULL);
+ if (ptp->u.alive.handle) {
+ ASSERT(ptp == handle2task(ptp->u.alive.handle));
+ reset_port_task_handle(ptp->u.alive.handle);
}
}
static ERTS_INLINE void
set_handle(ErtsPortTask *ptp, ErtsPortTaskHandle *pthp)
{
- ptp->handle = pthp;
+ ptp->u.alive.handle = pthp;
if (pthp) {
- erts_smp_atomic_set_nob(pthp, (erts_aint_t) ptp);
- ASSERT(ptp == handle2task(ptp->handle));
+ erts_smp_atomic_set_relb(pthp, (erts_aint_t) ptp);
+ ASSERT(ptp == handle2task(ptp->u.alive.handle));
+ }
+}
+
+
+/*
+ * Busy port queue management
+ */
+
+static erts_aint32_t
+check_unset_busy_port_q(Port *pp,
+ erts_aint32_t flags,
+ ErtsPortTaskBusyPortQ *bpq)
+{
+ ErlDrvSizeT qsize, low;
+ int resume_procs = 0;
+
+ ASSERT(bpq);
+ ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(pp));
+
+ erts_port_task_sched_lock(&pp->sched);
+ qsize = (ErlDrvSizeT) erts_smp_atomic_read_nob(&bpq->size);
+ low = (ErlDrvSizeT) erts_smp_atomic_read_nob(&bpq->low);
+ if (qsize < low) {
+ erts_aint32_t mask = ~(ERTS_PTS_FLG_CHK_UNSET_BUSY_PORT_Q
+ | ERTS_PTS_FLG_BUSY_PORT_Q);
+ flags = erts_smp_atomic32_read_band_relb(&pp->sched.flags, mask);
+ if ((flags & ERTS_PTS_FLGS_BUSY) == ERTS_PTS_FLG_BUSY_PORT_Q)
+ resume_procs = 1;
+ }
+ else if (flags & ERTS_PTS_FLG_CHK_UNSET_BUSY_PORT_Q) {
+ flags = erts_smp_atomic32_read_band_relb(&pp->sched.flags,
+ ~ERTS_PTS_FLG_CHK_UNSET_BUSY_PORT_Q);
+ flags &= ~ERTS_PTS_FLG_CHK_UNSET_BUSY_PORT_Q;
+ }
+ erts_port_task_sched_unlock(&pp->sched);
+ if (resume_procs)
+ erts_port_resume_procs(pp);
+
+ return flags;
+}
+
+static ERTS_INLINE void
+aborted_proc2port_data(Port *pp, ErlDrvSizeT size)
+{
+ ErtsPortTaskBusyPortQ *bpq;
+ erts_aint32_t flags;
+ ErlDrvSizeT qsz;
+
+ ASSERT(pp->sched.taskq.bpq);
+
+ if (size == 0)
+ return;
+
+ bpq = pp->sched.taskq.bpq;
+
+ qsz = (ErlDrvSizeT) erts_smp_atomic_add_read_acqb(&bpq->size,
+ (erts_aint_t) -size);
+ ASSERT(qsz + size > qsz);
+ flags = erts_smp_atomic32_read_nob(&pp->sched.flags);
+ ASSERT(pp->sched.taskq.bpq);
+ if ((flags & (ERTS_PTS_FLG_CHK_UNSET_BUSY_PORT_Q
+ | ERTS_PTS_FLG_BUSY_PORT_Q)) != ERTS_PTS_FLG_BUSY_PORT_Q)
+ return;
+ if (qsz < (ErlDrvSizeT) erts_smp_atomic_read_nob(&bpq->low))
+ erts_smp_atomic32_read_bor_nob(&pp->sched.flags,
+ ERTS_PTS_FLG_CHK_UNSET_BUSY_PORT_Q);
+}
+
+static ERTS_INLINE void
+dequeued_proc2port_data(Port *pp, ErlDrvSizeT size)
+{
+ ErtsPortTaskBusyPortQ *bpq;
+ erts_aint32_t flags;
+ ErlDrvSizeT qsz;
+
+ ASSERT(pp->sched.taskq.bpq);
+
+ if (size == 0)
+ return;
+
+ bpq = pp->sched.taskq.bpq;
+
+ qsz = (ErlDrvSizeT) erts_smp_atomic_add_read_acqb(&bpq->size,
+ (erts_aint_t) -size);
+ ASSERT(qsz + size > qsz);
+ flags = erts_smp_atomic32_read_nob(&pp->sched.flags);
+ if (!(flags & ERTS_PTS_FLG_BUSY_PORT_Q))
+ return;
+ if (qsz < (ErlDrvSizeT) erts_smp_atomic_read_acqb(&bpq->low))
+ check_unset_busy_port_q(pp, flags, bpq);
+}
+
+static ERTS_INLINE erts_aint32_t
+enqueue_proc2port_data(Port *pp,
+ ErtsProc2PortSigData *sigdp,
+ erts_aint32_t flags)
+{
+ ErtsPortTaskBusyPortQ *bpq = pp->sched.taskq.bpq;
+ if (sigdp && bpq) {
+ ErlDrvSizeT size = erts_proc2port_sig_command_data_size(sigdp);
+ if (size) {
+ erts_aint_t asize = erts_smp_atomic_add_read_acqb(&bpq->size,
+ (erts_aint_t) size);
+ ErlDrvSizeT qsz = (ErlDrvSizeT) asize;
+
+ ASSERT(qsz - size < qsz);
+
+ if (!(flags & ERTS_PTS_FLG_BUSY_PORT_Q) && qsz > bpq->high) {
+ flags = erts_smp_atomic32_read_bor_acqb(&pp->sched.flags,
+ ERTS_PTS_FLG_BUSY_PORT_Q);
+ flags |= ERTS_PTS_FLG_BUSY_PORT_Q;
+ qsz = (ErlDrvSizeT) erts_smp_atomic_read_acqb(&bpq->size);
+ if (qsz < (ErlDrvSizeT) erts_smp_atomic_read_nob(&bpq->low)) {
+ flags = (erts_smp_atomic32_read_bor_relb(
+ &pp->sched.flags,
+ ERTS_PTS_FLG_CHK_UNSET_BUSY_PORT_Q));
+ flags |= ERTS_PTS_FLG_CHK_UNSET_BUSY_PORT_Q;
+ }
+ }
+ ASSERT(!(flags & ERTS_PTS_FLG_EXIT));
+ }
+ }
+ return flags;
+}
+
+/*
+ * erl_drv_busy_msgq_limits() is called by drivers either reading or
+ * writing the limits.
+ *
+ * A limit of zero is interpreted as a read only request (using a
+ * limit of zero would not be useful). Other values are interpreted
+ * as a write-read request.
+ */
+
+void
+erl_drv_busy_msgq_limits(ErlDrvPort dport, ErlDrvSizeT *lowp, ErlDrvSizeT *highp)
+{
+ Port *pp = erts_drvport2port(dport, NULL);
+ ErtsPortTaskBusyPortQ *bpq = pp->sched.taskq.bpq;
+ int written = 0, resume_procs = 0;
+ ErlDrvSizeT low, high;
+
+ if (!pp || !bpq) {
+ if (lowp)
+ *lowp = ERL_DRV_BUSY_MSGQ_DISABLED;
+ if (highp)
+ *highp = ERL_DRV_BUSY_MSGQ_DISABLED;
+ return;
+ }
+
+ low = lowp ? *lowp : 0;
+ high = highp ? *highp : 0;
+
+ erts_port_task_sched_lock(&pp->sched);
+
+ if (low == ERL_DRV_BUSY_MSGQ_DISABLED
+ || high == ERL_DRV_BUSY_MSGQ_DISABLED) {
+ /* Disable busy msgq feature */
+ erts_aint32_t flags;
+ pp->sched.taskq.bpq = NULL;
+ flags = ~(ERTS_PTS_FLG_BUSY_PORT_Q|ERTS_PTS_FLG_CHK_UNSET_BUSY_PORT_Q);
+ flags = erts_smp_atomic32_read_band_acqb(&pp->sched.flags, flags);
+ if ((flags & ERTS_PTS_FLGS_BUSY) == ERTS_PTS_FLG_BUSY_PORT_Q)
+ resume_procs = 1;
+ }
+ else {
+
+ if (!low)
+ low = (ErlDrvSizeT) erts_smp_atomic_read_nob(&bpq->low);
+ else {
+ if (bpq->high < low)
+ bpq->high = low;
+ erts_smp_atomic_set_relb(&bpq->low, (erts_aint_t) low);
+ written = 1;
+ }
+
+ if (!high)
+ high = bpq->high;
+ else {
+ if (low > high) {
+ low = high;
+ erts_smp_atomic_set_relb(&bpq->low, (erts_aint_t) low);
+ }
+ bpq->high = high;
+ written = 1;
+ }
+
+ if (written) {
+ ErlDrvSizeT size = (ErlDrvSizeT) erts_smp_atomic_read_nob(&bpq->size);
+ if (size > high)
+ erts_smp_atomic32_read_bor_relb(&pp->sched.flags,
+ ERTS_PTS_FLG_BUSY_PORT_Q);
+ else if (size < low)
+ erts_smp_atomic32_read_bor_relb(&pp->sched.flags,
+ ERTS_PTS_FLG_CHK_UNSET_BUSY_PORT_Q);
+ }
+ }
+
+ erts_port_task_sched_unlock(&pp->sched);
+
+ if (resume_procs)
+ erts_port_resume_procs(pp);
+ if (lowp)
+ *lowp = low;
+ if (highp)
+ *highp = high;
+}
+
+/*
+ * No-suspend handles.
+ */
+
+#ifdef ERTS_SMP
+static void
+free_port_task_handle_list(void *vpthlp)
+{
+ erts_free(ERTS_ALC_T_PT_HNDL_LIST, vpthlp);
+}
+#endif
+
+static void
+schedule_port_task_handle_list_free(ErtsPortTaskHandleList *pthlp)
+{
+#ifdef ERTS_SMP
+ erts_schedule_thr_prgr_later_op(free_port_task_handle_list,
+ (void *) pthlp,
+ &pthlp->u.release);
+#else
+ erts_free(ERTS_ALC_T_PT_HNDL_LIST, pthlp);
+#endif
+}
+
+static ERTS_INLINE void
+abort_nosuspend_task(Port *pp,
+ ErtsPortTaskType type,
+ ErtsPortTaskTypeData *tdp)
+{
+
+ ASSERT(type == ERTS_PORT_TASK_PROC_SIG);
+
+ if (!pp->sched.taskq.bpq)
+ tdp->psig.callback(NULL,
+ ERTS_PORT_SFLG_INVALID,
+ ERTS_PROC2PORT_SIG_ABORT_NOSUSPEND,
+ &tdp->psig.data);
+ else {
+ ErlDrvSizeT size = erts_proc2port_sig_command_data_size(&tdp->psig.data);
+ tdp->psig.callback(NULL,
+ ERTS_PORT_SFLG_INVALID,
+ ERTS_PROC2PORT_SIG_ABORT_NOSUSPEND,
+ &tdp->psig.data);
+ aborted_proc2port_data(pp, size);
+ }
+}
+
+static ErtsPortTaskHandleList *
+get_free_nosuspend_handles(Port *pp)
+{
+ ErtsPortTaskHandleList *nshp, *last_nshp = NULL;
+
+ ERTS_SMP_LC_ASSERT(erts_port_task_sched_lock_is_locked(&pp->sched));
+
+ nshp = pp->sched.taskq.local.busy.nosuspend;
+
+ while (nshp && !erts_port_task_is_scheduled(&nshp->handle)) {
+ last_nshp = nshp;
+ nshp = nshp->u.next;
+ }
+
+ if (!last_nshp)
+ nshp = NULL;
+ else {
+ nshp = pp->sched.taskq.local.busy.nosuspend;
+ pp->sched.taskq.local.busy.nosuspend = last_nshp->u.next;
+ last_nshp->u.next = NULL;
+ if (!pp->sched.taskq.local.busy.nosuspend)
+ erts_smp_atomic32_read_band_nob(&pp->sched.flags,
+ ~ERTS_PTS_FLG_HAVE_NS_TASKS);
+ }
+ return nshp;
+}
+
+static void
+free_nosuspend_handles(ErtsPortTaskHandleList *free_nshp)
+{
+ while (free_nshp) {
+ ErtsPortTaskHandleList *nshp = free_nshp;
+ free_nshp = free_nshp->u.next;
+ schedule_port_task_handle_list_free(nshp);
}
}
@@ -161,7 +839,6 @@ enqueue_port(ErtsRunQueue *runq, Port *pp)
{
ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq));
pp->sched.next = NULL;
- pp->sched.in_runq = 1;
if (runq->ports.end) {
ASSERT(runq->ports.start);
runq->ports.end->sched.next = pp;
@@ -199,285 +876,423 @@ pop_port(ErtsRunQueue *runq)
return pp;
}
+/*
+ * Task queue operations
+ */
-#ifdef HARD_DEBUG
+static ERTS_INLINE int
+enqueue_task(Port *pp,
+ ErtsPortTask *ptp,
+ ErtsProc2PortSigData *sigdp,
+ ErtsPortTaskHandleList *ns_pthlp,
+ erts_aint32_t *flagsp)
-static void
-check_port_queue(ErtsRunQueue *runq, Port *chk_pp, int inq)
{
- Port *pp;
- Port *last_pp;
- Port *first_pp = runq->ports.start;
- int no_forward = 0, no_backward = 0;
- int found_forward = 0, found_backward = 0;
- if (!first_pp) {
- ASSERT(!runq->ports.end);
- }
+ int res;
+ erts_aint32_t fail_flags = ERTS_PTS_FLG_EXIT;
+ erts_aint32_t flags;
+ ptp->u.alive.next = NULL;
+ if (ns_pthlp)
+ fail_flags |= ERTS_PTS_FLG_BUSY_PORT;
+ erts_port_task_sched_lock(&pp->sched);
+ flags = erts_smp_atomic32_read_nob(&pp->sched.flags);
+ if (flags & fail_flags)
+ res = 0;
else {
- ASSERT(!first_pp->sched.prev);
- for (pp = first_pp; pp; pp = pp->sched.next) {
- ASSERT(pp->sched.taskq);
- if (pp->sched.taskq->first)
- no_forward++;
- if (chk_pp == pp)
- found_forward = 1;
- if (!pp->sched.prev) {
- ASSERT(first_pp == pp);
- }
- if (!pp->sched.next) {
- ASSERT(runq->ports.end == pp);
- last_pp = pp;
- }
- }
- for (pp = last_pp; pp; pp = pp->sched.prev) {
- ASSERT(pp->sched.taskq);
- if (pp->sched.taskq->last)
- no_backward++;
- if (chk_pp == pp)
- found_backward = 1;
- if (!pp->sched.prev) {
- ASSERT(first_pp == pp);
- }
- if (!pp->sched.next) {
- ASSERT(runq->ports.end == pp);
- }
- check_task_queue(pp->sched.taskq, NULL, 0);
+ if (ns_pthlp) {
+ ns_pthlp->u.next = pp->sched.taskq.local.busy.nosuspend;
+ pp->sched.taskq.local.busy.nosuspend = ns_pthlp;
}
- ASSERT(no_forward == no_backward);
- }
- ASSERT(no_forward == RUNQ_READ_LEN(&runq->ports.info.len));
- if (chk_pp) {
- if (chk_pp->sched.taskq || chk_pp->sched.exe_taskq) {
- ASSERT(chk_pp->sched.taskq != chk_pp->sched.exe_taskq);
- }
- ASSERT(!chk_pp->sched.taskq || chk_pp->sched.taskq->first);
- if (inq < 0)
- inq = chk_pp->sched.taskq && !chk_pp->sched.exe_taskq;
- if (inq) {
- ASSERT(found_forward && found_backward);
+ if (pp->sched.taskq.in.last) {
+ ASSERT(pp->sched.taskq.in.first);
+ ASSERT(!pp->sched.taskq.in.last->u.alive.next);
+
+ pp->sched.taskq.in.last->u.alive.next = ptp;
}
else {
- ASSERT(!found_forward && !found_backward);
- }
- }
-}
-
-#endif
-
-/*
- * Task queue operations
- */
+ ASSERT(!pp->sched.taskq.in.first);
-static ERTS_INLINE ErtsPortTaskQueue *
-port_taskq_init(ErtsPortTaskQueue *ptqp, Port *pp)
-{
- if (ptqp) {
- ptqp->first = NULL;
- ptqp->last = NULL;
- ptqp->port = pp;
+ pp->sched.taskq.in.first = ptp;
+ }
+ pp->sched.taskq.in.last = ptp;
+ flags = enqueue_proc2port_data(pp, sigdp, flags);
+ res = 1;
}
- return ptqp;
+ erts_port_task_sched_unlock(&pp->sched);
+ *flagsp = flags;
+ return res;
}
static ERTS_INLINE void
-enqueue_task(ErtsPortTaskQueue *ptqp, ErtsPortTask *ptp)
+prepare_exec(Port *pp, ErtsPortTask **execqp, int *processing_busy_q_p)
{
- ERTS_PT_CHK_NOT_IN_TASKQ(ptqp, ptp);
- ptp->next = NULL;
- ptp->prev = ptqp->last;
- ptp->queue = ptqp;
- if (ptqp->last) {
- ASSERT(ptqp->first);
- ptqp->last->next = ptp;
+ erts_aint32_t act = erts_smp_atomic32_read_nob(&pp->sched.flags);
+
+ if (!pp->sched.taskq.local.busy.first || (act & ERTS_PTS_FLG_BUSY_PORT)) {
+ *execqp = pp->sched.taskq.local.first;
+ *processing_busy_q_p = 0;
}
else {
- ASSERT(!ptqp->first);
- ptqp->first = ptp;
+ *execqp = pp->sched.taskq.local.busy.first;
+ *processing_busy_q_p = 1;
+ }
+
+ ERTS_PT_DBG_CHK_TASK_QS(pp, *execqp, *processing_busy_q_p);
+
+ while (1) {
+ erts_aint32_t new, exp;
+
+ new = exp = act;
+
+ new &= ~ERTS_PTS_FLG_IN_RUNQ;
+ new |= ERTS_PTS_FLG_EXEC;
+
+ act = erts_smp_atomic32_cmpxchg_nob(&pp->sched.flags, new, exp);
+
+ ASSERT(act & ERTS_PTS_FLG_IN_RUNQ);
+
+ if (exp == act)
+ break;
}
- ptqp->last = ptp;
- ERTS_PT_CHK_IN_TASKQ(ptqp, ptp);
}
-static ERTS_INLINE void
-push_task(ErtsPortTaskQueue *ptqp, ErtsPortTask *ptp)
+/* finalize_exec() return value != 0 if port should remain active */
+static ERTS_INLINE int
+finalize_exec(Port *pp, ErtsPortTask **execq, int processing_busy_q)
{
- ERTS_PT_CHK_NOT_IN_TASKQ(ptqp, ptp);
- ptp->next = ptqp->first;
- ptp->prev = NULL;
- ptp->queue = ptqp;
- if (ptqp->first) {
- ASSERT(ptqp->last);
- ptqp->first->prev = ptp;
- }
+ erts_aint32_t act;
+
+ if (!processing_busy_q)
+ pp->sched.taskq.local.first = *execq;
else {
- ASSERT(!ptqp->last);
- ptqp->last = ptp;
+ pp->sched.taskq.local.busy.first = *execq;
+ ASSERT(*execq);
}
- ptqp->first = ptp;
- ERTS_PT_CHK_IN_TASKQ(ptqp, ptp);
+
+ ERTS_PT_DBG_CHK_TASK_QS(pp, *execq, processing_busy_q);
+
+ *execq = NULL;
+
+ act = erts_smp_atomic32_read_nob(&pp->sched.flags);
+ if (act & ERTS_PTS_FLG_CHK_UNSET_BUSY_PORT_Q)
+ act = check_unset_busy_port_q(pp, act, pp->sched.taskq.bpq);
+
+ while (1) {
+ erts_aint32_t new, exp;
+
+ new = exp = act;
+
+ new &= ~ERTS_PTS_FLG_EXEC;
+ if (act & ERTS_PTS_FLG_HAVE_TASKS)
+ new |= ERTS_PTS_FLG_IN_RUNQ;
+
+ act = erts_smp_atomic32_cmpxchg_relb(&pp->sched.flags, new, exp);
+
+ ASSERT(!(act & ERTS_PTS_FLG_IN_RUNQ));
+
+ if (exp == act)
+ break;
+ }
+
+ return (act & ERTS_PTS_FLG_HAVE_TASKS) != 0;
}
-static ERTS_INLINE void
-dequeue_task(ErtsPortTask *ptp)
+static ERTS_INLINE erts_aint32_t
+select_queue_for_exec(Port *pp, ErtsPortTask **execqp, int *processing_busy_q_p)
{
- ASSERT(ptp);
- ASSERT(ptp->queue);
- ERTS_PT_CHK_IN_TASKQ(ptp->queue, ptp);
- if (ptp->next)
- ptp->next->prev = ptp->prev;
- else {
- ASSERT(ptp->queue->last == ptp);
- ptp->queue->last = ptp->prev;
+ erts_aint32_t flags = erts_smp_atomic32_read_nob(&pp->sched.flags);
+
+ if (flags & ERTS_PTS_FLG_CHK_UNSET_BUSY_PORT_Q)
+ flags = check_unset_busy_port_q(pp, flags, pp->sched.taskq.bpq);
+
+ ERTS_PT_DBG_CHK_TASK_QS(pp, *execqp, *processing_busy_q_p);
+
+ if (flags & ERTS_PTS_FLG_BUSY_PORT) {
+ if (*processing_busy_q_p) {
+ ErtsPortTask *ptp;
+
+ ptp = pp->sched.taskq.local.busy.first = *execqp;
+ if (!ptp)
+ pp->sched.taskq.local.busy.last = NULL;
+ else if (!(ptp->u.alive.flags & ERTS_PT_FLG_WAIT_BUSY))
+ no_sig_dep_move_from_busyq(pp);
+
+ *execqp = pp->sched.taskq.local.first;
+ *processing_busy_q_p = 0;
+
+ ERTS_PT_DBG_CHK_TASK_QS(pp, *execqp, *processing_busy_q_p);
+ }
+
+ return flags;
}
- if (ptp->prev)
- ptp->prev->next = ptp->next;
- else {
- ASSERT(ptp->queue->first == ptp);
- ptp->queue->first = ptp->next;
+
+ /* Not busy */
+
+ if (!*processing_busy_q_p && pp->sched.taskq.local.busy.first) {
+ pp->sched.taskq.local.first = *execqp;
+ *execqp = pp->sched.taskq.local.busy.first;
+ *processing_busy_q_p = 1;
+
+ ERTS_PT_DBG_CHK_TASK_QS(pp, *execqp, *processing_busy_q_p);
}
- ASSERT(ptp->queue->first || !ptp->queue->last);
- ASSERT(ptp->queue->last || !ptp->queue->first);
- ERTS_PT_CHK_NOT_IN_TASKQ(ptp->queue, ptp);
+ return flags;
}
-static ERTS_INLINE ErtsPortTask *
-pop_task(ErtsPortTaskQueue *ptqp)
+/*
+ * check_task_for_exec() returns a value !0 if the task
+ * is ok to execute; otherwise 0.
+ */
+static ERTS_INLINE int
+check_task_for_exec(Port *pp,
+ erts_aint32_t flags,
+ ErtsPortTask **execqp,
+ int *processing_busy_q_p,
+ ErtsPortTask *ptp)
{
- ErtsPortTask *ptp = ptqp->first;
- if (!ptp) {
- ASSERT(!ptqp->last);
+
+ if (!*processing_busy_q_p) {
+ /* Processing normal queue */
+
+ ERTS_PT_DBG_CHK_TASK_QS(pp, ptp, *processing_busy_q_p);
+
+ if ((flags & ERTS_PTS_FLG_BUSY_PORT)
+ && (ptp->u.alive.flags & ERTS_PT_FLG_WAIT_BUSY)) {
+
+ busy_wait_move_to_busy_queue(pp, ptp);
+ ERTS_PT_DBG_CHK_TASK_QS(pp, *execqp, *processing_busy_q_p);
+
+ return 0;
+ }
+
+ if (pp->sched.taskq.local.busy.last
+ && (ptp->u.alive.flags & ERTS_PT_FLG_SIG_DEP)) {
+
+ int res = !check_sig_dep_move_to_busy_queue(pp, ptp);
+ ERTS_PT_DBG_CHK_TASK_QS(pp, *execqp, *processing_busy_q_p);
+
+ return res;
+ }
+
}
else {
- ERTS_PT_CHK_IN_TASKQ(ptqp, ptp);
- ASSERT(!ptp->prev);
- ptqp->first = ptp->next;
- if (ptqp->first)
- ptqp->first->prev = NULL;
- else {
- ASSERT(ptqp->last == ptp);
- ptqp->last = NULL;
+ /* Processing busy queue */
+
+ ASSERT(!(flags & ERTS_PTS_FLG_BUSY_PORT));
+
+ ERTS_PT_DBG_CHK_TASK_QS(pp, ptp, *processing_busy_q_p);
+
+ popped_from_busy_queue(pp, ptp, !*execqp);
+
+ if (!*execqp) {
+ *execqp = pp->sched.taskq.local.first;
+ *processing_busy_q_p = 0;
}
- ASSERT(ptp->queue->first || !ptp->queue->last);
- ASSERT(ptp->queue->last || !ptp->queue->first);
+
+ ERTS_PT_DBG_CHK_TASK_QS(pp, *execqp, *processing_busy_q_p);
+
}
- ERTS_PT_CHK_NOT_IN_TASKQ(ptqp, ptp);
- return ptp;
+
+ return 1;
}
-#ifdef HARD_DEBUG
+static ErtsPortTask *
+fetch_in_queue(Port *pp, ErtsPortTask **execqp)
+{
+ ErtsPortTask *ptp;
+ ErtsPortTaskHandleList *free_nshp = NULL;
-static void
-check_task_queue(ErtsPortTaskQueue *ptqp,
- ErtsPortTask *chk_ptp,
- int inq)
+ erts_port_task_sched_lock(&pp->sched);
+
+ ptp = pp->sched.taskq.in.first;
+ pp->sched.taskq.in.first = NULL;
+ pp->sched.taskq.in.last = NULL;
+ if (ptp)
+ *execqp = ptp->u.alive.next;
+ else
+ erts_smp_atomic32_read_band_nob(&pp->sched.flags,
+ ~ERTS_PTS_FLG_HAVE_TASKS);
+
+
+ if (pp->sched.taskq.local.busy.nosuspend)
+ free_nshp = get_free_nosuspend_handles(pp);
+
+ erts_port_task_sched_unlock(&pp->sched);
+
+ if (free_nshp)
+ free_nosuspend_handles(free_nshp);
+
+ return ptp;
+}
+
+static ERTS_INLINE ErtsPortTask *
+select_task_for_exec(Port *pp,
+ ErtsPortTask **execqp,
+ int *processing_busy_q_p)
{
ErtsPortTask *ptp;
- ErtsPortTask *last_ptp;
- ErtsPortTask *first_ptp = ptqp->first;
- int found_forward = 0, found_backward = 0;
- if (!first_ptp) {
- ASSERT(!ptqp->last);
- }
- else {
- ASSERT(!first_ptp->prev);
- for (ptp = first_ptp; ptp; ptp = ptp->next) {
- ASSERT(ptp->queue == ptqp);
- if (chk_ptp == ptp)
- found_forward = 1;
- if (!ptp->prev) {
- ASSERT(first_ptp == ptp);
- }
- if (!ptp->next) {
- ASSERT(ptqp->last == ptp);
- last_ptp = ptp;
- }
- }
- for (ptp = last_ptp; ptp; ptp = ptp->prev) {
- ASSERT(ptp->queue == ptqp);
- if (chk_ptp == ptp)
- found_backward = 1;
- if (!ptp->prev) {
- ASSERT(first_ptp == ptp);
- }
- if (!ptp->next) {
- ASSERT(ptqp->last == ptp);
- }
- }
- }
- if (chk_ptp) {
- if (inq) {
- ASSERT(found_forward && found_backward);
- }
+ erts_aint32_t flags;
+
+ flags = select_queue_for_exec(pp, execqp, processing_busy_q_p);
+
+ while (1) {
+ ptp = *execqp;
+ if (ptp)
+ *execqp = ptp->u.alive.next;
else {
- ASSERT(!found_forward && !found_backward);
+ ptp = fetch_in_queue(pp, execqp);
+ if (!ptp)
+ return NULL;
}
+ if (check_task_for_exec(pp, flags, execqp, processing_busy_q_p, ptp))
+ return ptp;
}
}
-#endif
/*
* Abort a scheduled task.
*/
int
-erts_port_task_abort(Eterm id, ErtsPortTaskHandle *pthp)
+erts_port_task_abort(ErtsPortTaskHandle *pthp)
{
- ErtsRunQueue *runq;
- ErtsPortTaskQueue *ptqp;
+ int res;
ErtsPortTask *ptp;
- Port *pp;
-
- pp = &erts_port[internal_port_index(id)];
- runq = erts_port_runq(pp);
- if (!runq)
- return 1;
+#ifdef ERTS_SMP
+ ErtsThrPrgrDelayHandle dhndl = erts_thr_progress_unmanaged_delay();
+#endif
ptp = handle2task(pthp);
+ if (!ptp)
+ res = -1;
+ else {
+ erts_aint32_t old_state;
+
+#ifdef DEBUG
+ ErtsPortTaskHandle *saved_pthp = ptp->u.alive.handle;
+ ERTS_SMP_READ_MEMORY_BARRIER;
+ old_state = erts_smp_atomic32_read_nob(&ptp->state);
+ if (old_state == ERTS_PT_STATE_SCHEDULED) {
+ ASSERT(saved_pthp == pthp);
+ }
+#endif
- if (!ptp) {
- erts_smp_runq_unlock(runq);
- return 1;
+ old_state = erts_smp_atomic32_cmpxchg_nob(&ptp->state,
+ ERTS_PT_STATE_ABORTED,
+ ERTS_PT_STATE_SCHEDULED);
+ if (old_state != ERTS_PT_STATE_SCHEDULED)
+ res = - 1; /* Task already aborted, executing, or executed */
+ else {
+
+ reset_port_task_handle(pthp);
+
+ switch (ptp->type) {
+ case ERTS_PORT_TASK_INPUT:
+ case ERTS_PORT_TASK_OUTPUT:
+ case ERTS_PORT_TASK_EVENT:
+ ASSERT(erts_smp_atomic_read_nob(
+ &erts_port_task_outstanding_io_tasks) > 0);
+ erts_smp_atomic_dec_relb(&erts_port_task_outstanding_io_tasks);
+ break;
+ case ERTS_PORT_TASK_PROC_SIG:
+ ERTS_INTERNAL_ERROR("Aborted process to port signal");
+ break;
+ default:
+ break;
+ }
+
+ res = 0;
+ }
}
- ASSERT(ptp->handle == pthp);
- ptqp = ptp->queue;
- ASSERT(pp == ptqp->port);
+#ifdef ERTS_SMP
+ erts_thr_progress_unmanaged_continue(dhndl);
+#endif
- ERTS_PT_CHK_PRES_PORTQ(runq, pp);
- ASSERT(ptqp);
- ASSERT(ptqp->first);
+ return res;
+}
- dequeue_task(ptp);
- reset_handle(ptp);
+void
+erts_port_task_abort_nosuspend_tasks(Port *pp)
+{
+ erts_aint32_t flags;
+ ErtsPortTaskHandleList *abort_list;
+#ifdef ERTS_SMP
+ ErtsThrPrgrDelayHandle dhndl = ERTS_THR_PRGR_DHANDLE_INVALID;
+#endif
- switch (ptp->type) {
- case ERTS_PORT_TASK_INPUT:
- case ERTS_PORT_TASK_OUTPUT:
- case ERTS_PORT_TASK_EVENT:
- ASSERT(erts_smp_atomic_read_nob(&erts_port_task_outstanding_io_tasks) > 0);
- erts_smp_atomic_dec_relb(&erts_port_task_outstanding_io_tasks);
- break;
- default:
- break;
- }
+ erts_port_task_sched_lock(&pp->sched);
+ flags = erts_smp_atomic32_read_band_nob(&pp->sched.flags,
+ ~ERTS_PTS_FLG_HAVE_NS_TASKS);
+ abort_list = pp->sched.taskq.local.busy.nosuspend;
+ pp->sched.taskq.local.busy.nosuspend = NULL;
+ erts_port_task_sched_unlock(&pp->sched);
- ASSERT(ptqp == pp->sched.taskq || ptqp == pp->sched.exe_taskq);
+ while (abort_list) {
+#ifdef DEBUG
+ ErtsPortTaskHandle *saved_pthp;
+#endif
+ ErtsPortTaskType type;
+ ErtsPortTaskTypeData td;
+ ErtsPortTaskHandle *pthp;
+ ErtsPortTask *ptp;
+ ErtsPortTaskHandleList *pthlp;
+ erts_aint32_t old_state;
- if (ptqp->first || pp->sched.taskq != ptqp)
- ptqp = NULL;
- else
- pp->sched.taskq = NULL;
+ pthlp = abort_list;
+ abort_list = pthlp->u.next;
- ERTS_PT_CHK_PRES_PORTQ(runq, pp);
+#ifdef ERTS_SMP
+ if (dhndl != ERTS_THR_PRGR_DHANDLE_MANAGED)
+ dhndl = erts_thr_progress_unmanaged_delay();
+#endif
- erts_smp_runq_unlock(runq);
+ pthp = &pthlp->handle;
+ ptp = handle2task(pthp);
+ if (!ptp) {
+#ifdef ERTS_SMP
+ if (dhndl != ERTS_THR_PRGR_DHANDLE_MANAGED)
+ erts_thr_progress_unmanaged_continue(dhndl);
+#endif
+ schedule_port_task_handle_list_free(pthlp);
+ continue;
+ }
- port_task_free(ptp);
- if (ptqp)
- port_taskq_free(ptqp);
+#ifdef DEBUG
+ saved_pthp = ptp->u.alive.handle;
+ ERTS_SMP_READ_MEMORY_BARRIER;
+ old_state = erts_smp_atomic32_read_nob(&ptp->state);
+ if (old_state == ERTS_PT_STATE_SCHEDULED) {
+ ASSERT(saved_pthp == pthp);
+ }
+#endif
- return 0;
+ old_state = erts_smp_atomic32_cmpxchg_nob(&ptp->state,
+ ERTS_PT_STATE_ABORTED,
+ ERTS_PT_STATE_SCHEDULED);
+ if (old_state != ERTS_PT_STATE_SCHEDULED) {
+ /* Task already aborted, executing, or executed */
+#ifdef ERTS_SMP
+ if (dhndl != ERTS_THR_PRGR_DHANDLE_MANAGED)
+ erts_thr_progress_unmanaged_continue(dhndl);
+#endif
+ schedule_port_task_handle_list_free(pthlp);
+ continue;
+ }
+
+ reset_port_task_handle(pthp);
+
+ type = ptp->type;
+ td = ptp->u.alive.td;
+
+#ifdef ERTS_SMP
+ if (dhndl != ERTS_THR_PRGR_DHANDLE_MANAGED)
+ erts_thr_progress_unmanaged_continue(dhndl);
+#endif
+ schedule_port_task_handle_list_free(pthlp);
+
+ abort_nosuspend_task(pp, type, &td);
+ }
}
/*
@@ -488,240 +1303,264 @@ int
erts_port_task_schedule(Eterm id,
ErtsPortTaskHandle *pthp,
ErtsPortTaskType type,
- ErlDrvEvent event,
- ErlDrvEventData event_data)
+ ...)
{
+ ErtsProc2PortSigData *sigdp = NULL;
+ ErtsPortTaskHandleList *ns_pthlp = NULL;
+#ifdef ERTS_SMP
+ ErtsRunQueue *xrunq;
+ ErtsThrPrgrDelayHandle dhndl;
+#endif
ErtsRunQueue *runq;
Port *pp;
- ErtsPortTask *ptp;
- int enq_port = 0;
-
- /*
- * NOTE: We might not have the port lock here. We are only
- * allowed to access the 'sched', 'tab_status',
- * and 'id' fields of the port struct while
- * tasks_lock is held.
- */
+ ErtsPortTask *ptp = NULL;
+ erts_aint32_t act, add_flags;
if (pthp && erts_port_task_is_scheduled(pthp)) {
ASSERT(0);
- erts_port_task_abort(id, pthp);
+ erts_port_task_abort(pthp);
}
- ptp = port_task_alloc();
-
ASSERT(is_internal_port(id));
- pp = &erts_port[internal_port_index(id)];
- runq = erts_port_runq(pp);
-
- if (!runq || ERTS_PORT_TASK_INVALID_PORT(pp, id)) {
- if (runq)
- erts_smp_runq_unlock(runq);
- return -1;
- }
- ASSERT(!erts_port_task_is_scheduled(pthp));
-
- ERTS_PT_CHK_PRES_PORTQ(runq, pp);
+#ifdef ERTS_SMP
+ dhndl = erts_thr_progress_unmanaged_delay();
+#endif
- if (!pp->sched.taskq) {
- pp->sched.taskq = port_taskq_init(port_taskq_alloc(), pp);
- enq_port = !pp->sched.in_runq && !pp->sched.exe_taskq;
- }
+ pp = erts_port_lookup_raw(id);
#ifdef ERTS_SMP
- if (enq_port) {
- ErtsRunQueue *xrunq = erts_check_emigration_need(runq, ERTS_PORT_PRIO_LEVEL);
- if (xrunq) {
- /* Port emigrated ... */
- erts_smp_atomic_set_nob(&pp->run_queue, (erts_aint_t) xrunq);
- erts_smp_runq_unlock(runq);
- runq = erts_port_runq(pp);
- if (!runq)
- return -1;
- }
+ if (dhndl != ERTS_THR_PRGR_DHANDLE_MANAGED) {
+ if (pp)
+ erts_port_inc_refc(pp);
+ erts_thr_progress_unmanaged_continue(dhndl);
}
#endif
- ASSERT(pp->sched.taskq);
- ASSERT(ptp);
+ if (!pp)
+ goto fail;
- ptp->type = type;
- ptp->event = event;
- ptp->event_data = event_data;
+ if (type != ERTS_PORT_TASK_PROC_SIG) {
+ ptp = port_task_alloc();
- set_handle(ptp, pthp);
+ ptp->type = type;
+ ptp->u.alive.flags = 0;
+
+ erts_smp_atomic32_init_nob(&ptp->state, ERTS_PT_STATE_SCHEDULED);
+
+ set_handle(ptp, pthp);
+ }
switch (type) {
- case ERTS_PORT_TASK_FREE:
- erl_exit(ERTS_ABORT_EXIT,
- "erts_port_task_schedule(): Cannot schedule free task\n");
- break;
case ERTS_PORT_TASK_INPUT:
- case ERTS_PORT_TASK_OUTPUT:
- case ERTS_PORT_TASK_EVENT:
+ case ERTS_PORT_TASK_OUTPUT: {
+ va_list argp;
+ va_start(argp, type);
+ ptp->u.alive.td.io.event = va_arg(argp, ErlDrvEvent);
+ va_end(argp);
+ erts_smp_atomic_inc_relb(&erts_port_task_outstanding_io_tasks);
+ break;
+ }
+ case ERTS_PORT_TASK_EVENT: {
+ va_list argp;
+ va_start(argp, type);
+ ptp->u.alive.td.io.event = va_arg(argp, ErlDrvEvent);
+ ptp->u.alive.td.io.event_data = va_arg(argp, ErlDrvEventData);
+ va_end(argp);
erts_smp_atomic_inc_relb(&erts_port_task_outstanding_io_tasks);
- /* Fall through... */
+ break;
+ }
+ case ERTS_PORT_TASK_PROC_SIG: {
+ va_list argp;
+ ASSERT(!pthp);
+ va_start(argp, type);
+ sigdp = va_arg(argp, ErtsProc2PortSigData *);
+ ptp = p2p_sig_data_to_task(sigdp);
+ ptp->u.alive.td.psig.callback = va_arg(argp, ErtsProc2PortSigCallback);
+ ptp->u.alive.flags |= va_arg(argp, int);
+ va_end(argp);
+ if (!(ptp->u.alive.flags & ERTS_PT_FLG_NOSUSPEND))
+ set_handle(ptp, pthp);
+ else {
+ ns_pthlp = erts_alloc(ERTS_ALC_T_PT_HNDL_LIST,
+ sizeof(ErtsPortTaskHandleList));
+ set_handle(ptp, &ns_pthlp->handle);
+ }
+ break;
+ }
default:
- enqueue_task(pp->sched.taskq, ptp);
break;
}
-#ifndef ERTS_SMP
- /*
- * When (!enq_port && !pp->sched.exe_taskq) is true in the smp case,
- * the port might not be in the run queue. If this is the case, another
- * thread is in the process of enqueueing the port. This very seldom
- * occur, but do occur and is a valid scenario. Debug info showing this
- * enqueue in progress must be introduced before we can enable (modified
- * versions of these) assertions in the smp case again.
- */
-#if defined(HARD_DEBUG)
- if (pp->sched.exe_taskq || enq_port)
- ERTS_PT_CHK_NOT_IN_PORTQ(runq, pp);
- else
- ERTS_PT_CHK_IN_PORTQ(runq, pp);
-#elif defined(DEBUG)
- if (!enq_port && !pp->sched.exe_taskq) {
- /* We should be in port run q */
- ASSERT(pp->sched.in_runq);
+ if (!enqueue_task(pp, ptp, sigdp, ns_pthlp, &act)) {
+ reset_handle(ptp);
+ if (ns_pthlp && !(act & ERTS_PTS_FLG_EXIT))
+ goto abort_nosuspend;
+ else
+ goto fail;
}
-#endif
-#endif
- if (!enq_port) {
- ERTS_PT_CHK_PRES_PORTQ(runq, pp);
- erts_smp_runq_unlock(runq);
- }
- else {
- enqueue_port(runq, pp);
- ERTS_PT_CHK_PRES_PORTQ(runq, pp);
-
- if (erts_system_profile_flags.runnable_ports) {
- profile_runnable_port(pp, am_active);
+ add_flags = ERTS_PTS_FLG_HAVE_TASKS;
+ if (ns_pthlp)
+ add_flags |= ERTS_PTS_FLG_HAVE_NS_TASKS;
+
+ while (1) {
+ erts_aint32_t new, exp;
+
+ if ((act & add_flags) == add_flags
+ && (act & (ERTS_PTS_FLG_IN_RUNQ|ERTS_PTS_FLG_EXEC)))
+ goto done; /* Done */
+
+ new = exp = act;
+ new |= add_flags;
+ if (!(act & (ERTS_PTS_FLG_IN_RUNQ|ERTS_PTS_FLG_EXEC)))
+ new |= ERTS_PTS_FLG_IN_RUNQ;
+
+ act = erts_smp_atomic32_cmpxchg_relb(&pp->sched.flags, new, exp);
+
+ if (exp == act) {
+ if (!(act & (ERTS_PTS_FLG_IN_RUNQ|ERTS_PTS_FLG_EXEC)))
+ break; /* Need to enqueue port */
+ goto done; /* Done */
}
+ if (act & ERTS_PTS_FLG_EXIT)
+ goto done; /* Died after our task insert... */
+ }
+
+ /* Enqueue port on run-queue */
+
+ runq = erts_port_runq(pp);
+ if (!runq)
+ ERTS_INTERNAL_ERROR("Missing run-queue");
+
+#ifdef ERTS_SMP
+ xrunq = erts_check_emigration_need(runq, ERTS_PORT_PRIO_LEVEL);
+ if (xrunq) {
+ /* Port emigrated ... */
+ erts_smp_atomic_set_nob(&pp->run_queue, (erts_aint_t) xrunq);
erts_smp_runq_unlock(runq);
+ runq = erts_port_runq(pp);
+ if (!runq)
+ ERTS_INTERNAL_ERROR("Missing run-queue");
+ }
+#endif
- erts_smp_notify_inc_runq(runq);
+ enqueue_port(runq, pp);
+
+ if (erts_system_profile_flags.runnable_ports) {
+ profile_runnable_port(pp, am_active);
}
+
+ erts_smp_runq_unlock(runq);
+
+ erts_smp_notify_inc_runq(runq);
+
+done:
+
+#ifdef ERTS_SMP
+ if (dhndl != ERTS_THR_PRGR_DHANDLE_MANAGED)
+ erts_port_dec_refc(pp);
+#endif
+
return 0;
+
+abort_nosuspend:
+
+#ifdef ERTS_SMP
+ if (dhndl != ERTS_THR_PRGR_DHANDLE_MANAGED)
+ erts_port_dec_refc(pp);
+#endif
+
+ abort_nosuspend_task(pp, ptp->type, &ptp->u.alive.td);
+
+ ASSERT(ns_pthlp);
+ erts_free(ERTS_ALC_T_PT_HNDL_LIST, ns_pthlp);
+ if (ptp)
+ port_task_free(ptp);
+
+ return 0;
+
+fail:
+
+#ifdef ERTS_SMP
+ if (dhndl != ERTS_THR_PRGR_DHANDLE_MANAGED)
+ erts_port_dec_refc(pp);
+#endif
+
+ if (ns_pthlp)
+ erts_free(ERTS_ALC_T_PT_HNDL_LIST, ns_pthlp);
+
+ if (ptp)
+ port_task_free(ptp);
+
+ return -1;
}
void
erts_port_task_free_port(Port *pp)
{
+ ErtsProcList *suspended;
+ erts_aint32_t flags;
ErtsRunQueue *runq;
- ErtsPortTaskQueue *ptqp;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(pp));
- ASSERT(!(pp->status & ERTS_PORT_SFLGS_DEAD));
+ ASSERT(!(erts_atomic32_read_nob(&pp->state) & ERTS_PORT_SFLGS_DEAD));
+
runq = erts_port_runq(pp);
- ASSERT(runq);
- ERTS_PT_CHK_PRES_PORTQ(runq, pp);
- ptqp = pp->sched.exe_taskq;
- if (ptqp) {
- /* I (this thread) am currently executing this port, free it
- when scheduled out... */
- ErtsPortTask *ptp;
- enqueue_free:
- ptp = port_task_alloc();
- erts_smp_port_state_lock(pp);
- pp->status &= ~ERTS_PORT_SFLG_CLOSING;
- pp->status |= ERTS_PORT_SFLG_FREE_SCHEDULED;
- erts_may_save_closed_port(pp);
- erts_smp_port_state_unlock(pp);
- ERTS_LC_ASSERT(erts_smp_atomic_read_nob(&pp->refc) > 1);
- ptp->type = ERTS_PORT_TASK_FREE;
- ptp->event = (ErlDrvEvent) -1;
- ptp->event_data = NULL;
- set_handle(ptp, NULL);
- push_task(ptqp, ptp);
- ERTS_PT_CHK_PRES_PORTQ(runq, pp);
- erts_smp_runq_unlock(runq);
- }
- else {
- if (pp->sched.in_runq) {
- ptqp = pp->sched.taskq;
- if (!ptqp)
- pp->sched.taskq = ptqp = port_taskq_init(port_taskq_alloc(), pp);
- goto enqueue_free;
- }
- ASSERT(!pp->sched.taskq);
- erts_smp_port_state_lock(pp);
- pp->status &= ~ERTS_PORT_SFLG_CLOSING;
- pp->status |= ERTS_PORT_SFLG_FREE_SCHEDULED;
- erts_may_save_closed_port(pp);
- erts_smp_port_state_unlock(pp);
- erts_smp_atomic_dec_nob(&pp->refc); /* Not alive */
- ERTS_LC_ASSERT(erts_smp_atomic_read_nob(&pp->refc) > 0); /* Lock */
- handle_remaining_tasks(runq, pp); /* May release runq lock */
- ASSERT(!pp->sched.exe_taskq && (!ptqp || !ptqp->first));
- pp->sched.taskq = NULL;
- ERTS_PT_CHK_PRES_PORTQ(runq, pp);
- erts_smp_runq_unlock(runq);
- }
-}
+ if (!runq)
+ ERTS_INTERNAL_ERROR("Missing run-queue");
+ erts_port_task_sched_lock(&pp->sched);
+ flags = erts_smp_atomic32_read_bor_relb(&pp->sched.flags,
+ ERTS_PTS_FLG_EXIT);
+ suspended = pp->suspended;
+ pp->suspended = NULL;
+ erts_port_task_sched_unlock(&pp->sched);
+ erts_atomic32_read_bset_relb(&pp->state,
+ (ERTS_PORT_SFLG_CLOSING
+ | ERTS_PORT_SFLG_FREE),
+ ERTS_PORT_SFLG_FREE);
-typedef struct {
- ErtsRunQueue *runq;
- int *resp;
-} ErtsPortTaskExeBlockData;
+ erts_smp_runq_unlock(runq);
+
+ if (erts_proclist_fetch(&suspended, NULL))
+ erts_resume_processes(suspended);
+
+ if (!(flags & (ERTS_PTS_FLG_IN_RUNQ|ERTS_PTS_FLG_EXEC)))
+ begin_port_cleanup(pp, NULL, NULL);
+}
/*
- * Run all scheduled tasks for the first port in run queue. If
- * new tasks appear while running reschedule port (free task is
- * an exception; it is always handled instantly).
+ * Execute scheduled tasks of a port.
*
* erts_port_task_execute() is called by scheduler threads between
- * scheduleing of processes. Sched lock should be held by caller.
+ * scheduling of processes. Run-queue lock should be held by caller.
*/
int
erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp)
{
Port *pp;
- ErtsPortTaskQueue *ptqp;
- ErtsPortTask *ptp;
+ ErtsPortTask *execq;
+ int processing_busy_q;
int res = 0;
int reds = ERTS_PORT_REDS_EXECUTE;
erts_aint_t io_tasks_executed = 0;
int fpe_was_unmasked;
+ erts_aint32_t state;
+ int active;
ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq));
- ERTS_PT_CHK_PORTQ(runq);
-
pp = pop_port(runq);
if (!pp) {
res = 0;
goto done;
}
- ASSERT(pp->sched.in_runq);
- pp->sched.in_runq = 0;
- if (!pp->sched.taskq) {
- if (erts_system_profile_flags.runnable_ports)
- profile_runnable_port(pp, am_inactive);
- res = (erts_smp_atomic_read_nob(&erts_port_task_outstanding_io_tasks)
- != (erts_aint_t) 0);
- goto done;
- }
+ erts_smp_runq_unlock(runq);
*curr_port_pp = pp;
-
- ASSERT(pp->sched.taskq->first);
- ptqp = pp->sched.taskq;
- pp->sched.taskq = NULL;
-
- ASSERT(!pp->sched.exe_taskq);
- pp->sched.exe_taskq = ptqp;
-
- if (erts_smp_port_trylock(pp) == EBUSY) {
- erts_smp_runq_unlock(runq);
- erts_smp_port_lock(pp);
- erts_smp_runq_lock(runq);
- }
if (erts_sched_stat.enabled) {
ErtsSchedulerData *esdp = erts_get_scheduler_data();
@@ -738,77 +1577,94 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp)
erts_smp_spin_unlock(&erts_sched_stat.lock);
}
+ prepare_exec(pp, &execq, &processing_busy_q);
+
+ erts_smp_port_lock(pp);
+
/* trace port scheduling, in */
if (IS_TRACED_FL(pp, F_TRACE_SCHED_PORTS)) {
trace_sched_ports(pp, am_in);
}
- ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(pp));
+ fpe_was_unmasked = erts_block_fpe();
- ERTS_PT_CHK_PRES_PORTQ(runq, pp);
- ptp = pop_task(ptqp);
+ state = erts_atomic32_read_nob(&pp->state);
+ goto begin_handle_tasks;
- fpe_was_unmasked = erts_block_fpe();
+ while (1) {
+ erts_aint32_t task_state;
+ ErtsPortTask *ptp;
- while (ptp) {
- ASSERT(pp->sched.taskq != pp->sched.exe_taskq);
+ ptp = select_task_for_exec(pp, &execq, &processing_busy_q);
+ if (!ptp)
+ break;
+
+ task_state = erts_smp_atomic32_cmpxchg_nob(&ptp->state,
+ ERTS_PT_STATE_EXECUTING,
+ ERTS_PT_STATE_SCHEDULED);
+ if (task_state != ERTS_PT_STATE_SCHEDULED) {
+ ASSERT(task_state == ERTS_PT_STATE_ABORTED);
+ goto aborted_port_task;
+ }
reset_handle(ptp);
- erts_smp_runq_unlock(runq);
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(pp));
ERTS_SMP_CHK_NO_PROC_LOCKS;
ASSERT(pp->drv_ptr);
switch (ptp->type) {
- case ERTS_PORT_TASK_FREE: /* May be pushed in q at any time */
- reds += ERTS_PORT_REDS_FREE;
- erts_smp_runq_lock(runq);
-
- erts_unblock_fpe(fpe_was_unmasked);
- ASSERT(pp->status & ERTS_PORT_SFLG_FREE_SCHEDULED);
- if (ptqp->first || (pp->sched.taskq && pp->sched.taskq->first))
- handle_remaining_tasks(runq, pp);
- ASSERT(!ptqp->first
- && (!pp->sched.taskq || !pp->sched.taskq->first));
- erts_smp_atomic_dec_nob(&pp->refc); /* Not alive */
- ERTS_LC_ASSERT(erts_smp_atomic_read_nob(&pp->refc) > 0); /* Lock */
-
- port_task_free(ptp);
- if (pp->sched.taskq)
- port_taskq_free(pp->sched.taskq);
- pp->sched.taskq = NULL;
-
- goto tasks_done;
case ERTS_PORT_TASK_TIMEOUT:
reds += ERTS_PORT_REDS_TIMEOUT;
- if (!(pp->status & ERTS_PORT_SFLGS_DEAD)) {
+ if (!(state & ERTS_PORT_SFLGS_DEAD)) {
DTRACE_DRIVER(driver_timeout, pp);
(*pp->drv_ptr->timeout)((ErlDrvData) pp->drv_data);
}
break;
case ERTS_PORT_TASK_INPUT:
reds += ERTS_PORT_REDS_INPUT;
- ASSERT((pp->status & ERTS_PORT_SFLGS_DEAD) == 0);
+ ASSERT((state & ERTS_PORT_SFLGS_DEAD) == 0);
DTRACE_DRIVER(driver_ready_input, pp);
/* NOTE some windows drivers use ->ready_input for input and output */
- (*pp->drv_ptr->ready_input)((ErlDrvData) pp->drv_data, ptp->event);
+ (*pp->drv_ptr->ready_input)((ErlDrvData) pp->drv_data,
+ ptp->u.alive.td.io.event);
io_tasks_executed++;
break;
case ERTS_PORT_TASK_OUTPUT:
reds += ERTS_PORT_REDS_OUTPUT;
- ASSERT((pp->status & ERTS_PORT_SFLGS_DEAD) == 0);
+ ASSERT((state & ERTS_PORT_SFLGS_DEAD) == 0);
DTRACE_DRIVER(driver_ready_output, pp);
- (*pp->drv_ptr->ready_output)((ErlDrvData) pp->drv_data, ptp->event);
+ (*pp->drv_ptr->ready_output)((ErlDrvData) pp->drv_data,
+ ptp->u.alive.td.io.event);
io_tasks_executed++;
break;
case ERTS_PORT_TASK_EVENT:
reds += ERTS_PORT_REDS_EVENT;
- ASSERT((pp->status & ERTS_PORT_SFLGS_DEAD) == 0);
+ ASSERT((state & ERTS_PORT_SFLGS_DEAD) == 0);
DTRACE_DRIVER(driver_event, pp);
- (*pp->drv_ptr->event)((ErlDrvData) pp->drv_data, ptp->event, ptp->event_data);
+ (*pp->drv_ptr->event)((ErlDrvData) pp->drv_data,
+ ptp->u.alive.td.io.event,
+ ptp->u.alive.td.io.event_data);
io_tasks_executed++;
break;
+ case ERTS_PORT_TASK_PROC_SIG: {
+ ErtsProc2PortSigData *sigdp = &ptp->u.alive.td.psig.data;
+ ASSERT((state & ERTS_PORT_SFLGS_DEAD) == 0);
+ if (!pp->sched.taskq.bpq)
+ reds += ptp->u.alive.td.psig.callback(pp,
+ state,
+ ERTS_PROC2PORT_SIG_EXEC,
+ sigdp);
+ else {
+ ErlDrvSizeT size = erts_proc2port_sig_command_data_size(sigdp);
+ reds += ptp->u.alive.td.psig.callback(pp,
+ state,
+ ERTS_PROC2PORT_SIG_EXEC,
+ sigdp);
+ dequeued_proc2port_data(pp, size);
+ }
+ break;
+ }
case ERTS_PORT_TASK_DIST_CMD:
reds += erts_dist_command(pp, CONTEXT_REDS-reds);
break;
@@ -819,33 +1675,30 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp)
break;
}
- if ((pp->status & ERTS_PORT_SFLG_CLOSING)
- && erts_is_port_ioq_empty(pp)) {
- reds += ERTS_PORT_REDS_TERMINATE;
- erts_terminate_port(pp);
- }
-
- ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(pp));
-
-#ifdef ERTS_SMP
- if (pp->xports)
- erts_smp_xports_unlock(pp);
- ASSERT(!pp->xports);
-#endif
+ reds += erts_port_driver_callback_epilogue(pp, &state);
- ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(pp));
+ aborted_port_task:
+ schedule_port_task_free(ptp);
- port_task_free(ptp);
+ begin_handle_tasks:
+ if (state & ERTS_PORT_SFLG_FREE) {
+ reds += ERTS_PORT_REDS_FREE;
+ begin_port_cleanup(pp, &execq, &processing_busy_q);
- erts_smp_runq_lock(runq);
+ break;
+ }
- ptp = pop_task(ptqp);
+ if (reds >= CONTEXT_REDS)
+ break;
}
- tasks_done:
-
erts_unblock_fpe(fpe_was_unmasked);
+ /* trace port scheduling, out */
+ if (IS_TRACED_FL(pp, F_TRACE_SCHED_PORTS)) {
+ trace_sched_ports(pp, am_out);
+ }
+
if (io_tasks_executed) {
ASSERT(erts_smp_atomic_read_nob(&erts_port_task_outstanding_io_tasks)
>= io_tasks_executed);
@@ -853,15 +1706,19 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp)
-1*io_tasks_executed);
}
- *curr_port_pp = NULL;
-
#ifdef ERTS_SMP
ASSERT(runq == (ErtsRunQueue *) erts_smp_atomic_read_nob(&pp->run_queue));
#endif
- if (!pp->sched.taskq) {
- ASSERT(pp->sched.exe_taskq);
- pp->sched.exe_taskq = NULL;
+ active = finalize_exec(pp, &execq, processing_busy_q);
+
+ erts_port_release(pp);
+
+ *curr_port_pp = NULL;
+
+ erts_smp_runq_lock(runq);
+
+ if (!active) {
if (erts_system_profile_flags.runnable_ports)
profile_runnable_port(pp, am_inactive);
}
@@ -870,16 +1727,13 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp)
ErtsRunQueue *xrunq;
#endif
- ASSERT(!(pp->status & ERTS_PORT_SFLGS_DEAD));
- ASSERT(pp->sched.taskq->first);
+ ASSERT(!(erts_atomic32_read_nob(&pp->state) & ERTS_PORT_SFLGS_DEAD));
#ifdef ERTS_SMP
xrunq = erts_check_emigration_need(runq, ERTS_PORT_PRIO_LEVEL);
if (!xrunq) {
#endif
enqueue_port(runq, pp);
- ASSERT(pp->sched.exe_taskq);
- pp->sched.exe_taskq = NULL;
/* No need to notify ourselves about inc in runq. */
#ifdef ERTS_SMP
}
@@ -889,128 +1743,213 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp)
erts_smp_runq_unlock(runq);
xrunq = erts_port_runq(pp);
- if (xrunq) {
- enqueue_port(xrunq, pp);
- ASSERT(pp->sched.exe_taskq);
- pp->sched.exe_taskq = NULL;
- erts_smp_runq_unlock(xrunq);
- erts_smp_notify_inc_runq(xrunq);
- }
+ ASSERT(xrunq);
+ enqueue_port(xrunq, pp);
+ erts_smp_runq_unlock(xrunq);
+ erts_smp_notify_inc_runq(xrunq);
erts_smp_runq_lock(runq);
}
#endif
}
+ done:
res = (erts_smp_atomic_read_nob(&erts_port_task_outstanding_io_tasks)
!= (erts_aint_t) 0);
- ERTS_PT_CHK_PRES_PORTQ(runq, pp);
+ runq->scheduler->reductions += reds;
- port_taskq_free(ptqp);
-
- /* trace port scheduling, out */
- if (IS_TRACED_FL(pp, F_TRACE_SCHED_PORTS)) {
- trace_sched_ports(pp, am_out);
- }
-#ifndef ERTS_SMP
- erts_port_release(pp);
-#else
- {
- erts_aint_t refc;
- erts_smp_mtx_unlock(pp->lock);
- refc = erts_smp_atomic_dec_read_nob(&pp->refc);
- ASSERT(refc >= 0);
- if (refc == 0) {
- erts_smp_runq_unlock(runq);
- erts_port_cleanup(pp); /* Might aquire runq lock */
- erts_smp_runq_lock(runq);
- res = (erts_smp_atomic_read_nob(&erts_port_task_outstanding_io_tasks)
- != (erts_aint_t) 0);
- }
- }
-#endif
-
- done:
ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq));
-
ERTS_PORT_REDUCTIONS_EXECUTED(runq, reds);
return res;
}
-/*
- * Handle remaining tasks after a free task.
- */
+#ifdef ERTS_SMP
+static void
+release_port(void *vport)
+{
+ erts_port_dec_refc((Port *) vport);
+}
+#endif
static void
-handle_remaining_tasks(ErtsRunQueue *runq, Port *pp)
+begin_port_cleanup(Port *pp, ErtsPortTask **execqp, int *processing_busy_q_p)
{
- int i;
- ErtsPortTask *ptp;
- ErtsPortTaskQueue *ptqps[] = {pp->sched.exe_taskq, pp->sched.taskq};
+ int i, max;
+ ErtsPortTaskBusyCallerTable *tabp;
+ ErtsPortTask *qs[3];
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(pp));
- for (i = 0; i < sizeof(ptqps)/sizeof(ErtsPortTaskQueue *); i++) {
- if (!ptqps[i])
- continue;
- ptp = pop_task(ptqps[i]);
- while (ptp) {
+ /*
+ * Abort remaining tasks...
+ *
+ * We want to process queues in the following order in order
+ * to preserve signal ordering guarantees:
+ * 1. Local busy queue
+ * 2. Local queue
+ * 3. In queue
+ */
+
+ max = 0;
+ if (!execqp) {
+ if (pp->sched.taskq.local.busy.first)
+ qs[max++] = pp->sched.taskq.local.busy.first;
+ if (pp->sched.taskq.local.first)
+ qs[max++] = pp->sched.taskq.local.first;
+ }
+ else {
+ if (*processing_busy_q_p) {
+ if (*execqp)
+ qs[max++] = *execqp;
+ if (pp->sched.taskq.local.first)
+ qs[max++] = pp->sched.taskq.local.first;
+ }
+ else {
+ if (pp->sched.taskq.local.busy.first)
+ qs[max++] = pp->sched.taskq.local.busy.first;
+ if (*execqp)
+ qs[max++] = *execqp;
+ }
+ *execqp = NULL;
+ *processing_busy_q_p = 0;
+ }
+ pp->sched.taskq.local.busy.first = NULL;
+ pp->sched.taskq.local.busy.last = NULL;
+ pp->sched.taskq.local.first = NULL;
+ tabp = pp->sched.taskq.local.busy.table;
+ if (tabp) {
+ int bix;
+ for (bix = 0; bix < ERTS_PORT_TASK_BUSY_CALLER_TABLE_BUCKETS; bix++) {
+ ErtsPortTaskBusyCaller *bcp = tabp->bucket[bix];
+ while (bcp) {
+ ErtsPortTaskBusyCaller *free_bcp = bcp;
+ bcp = bcp->next;
+ if (free_bcp != &tabp->pre_alloc_busy_caller)
+ erts_free(ERTS_ALC_T_BUSY_CALLER, free_bcp);
+ }
+ }
+
+ busy_caller_table_free(tabp);
+ pp->sched.taskq.local.busy.table = NULL;
+ }
+
+ erts_port_task_sched_lock(&pp->sched);
+ qs[max] = pp->sched.taskq.in.first;
+ pp->sched.taskq.in.first = NULL;
+ pp->sched.taskq.in.last = NULL;
+ erts_port_task_sched_unlock(&pp->sched);
+ if (qs[max])
+ max++;
+
+ for (i = 0; i < max; i++) {
+ while (1) {
+ erts_aint32_t state;
+ ErtsPortTask *ptp = qs[i];
+ if (!ptp)
+ break;
+
+ qs[i] = ptp->u.alive.next;
+
+ /* Normal case here is aborted tasks... */
+ state = erts_smp_atomic32_read_nob(&ptp->state);
+ if (state == ERTS_PT_STATE_ABORTED)
+ goto aborted_port_task;
+
+ state = erts_smp_atomic32_cmpxchg_nob(&ptp->state,
+ ERTS_PT_STATE_EXECUTING,
+ ERTS_PT_STATE_SCHEDULED);
+ if (state != ERTS_PT_STATE_SCHEDULED) {
+ ASSERT(state == ERTS_PT_STATE_ABORTED);
+ goto aborted_port_task;
+ }
+
reset_handle(ptp);
- erts_smp_runq_unlock(runq);
switch (ptp->type) {
- case ERTS_PORT_TASK_FREE:
case ERTS_PORT_TASK_TIMEOUT:
break;
case ERTS_PORT_TASK_INPUT:
- erts_stale_drv_select(pp->id, ptp->event, DO_READ, 1);
+ erts_stale_drv_select(pp->common.id,
+ ptp->u.alive.td.io.event,
+ DO_READ,
+ 1);
break;
case ERTS_PORT_TASK_OUTPUT:
- erts_stale_drv_select(pp->id, ptp->event, DO_WRITE, 1);
+ erts_stale_drv_select(pp->common.id,
+ ptp->u.alive.td.io.event,
+ DO_WRITE,
+ 1);
break;
case ERTS_PORT_TASK_EVENT:
- erts_stale_drv_select(pp->id, ptp->event, 0, 1);
+ erts_stale_drv_select(pp->common.id,
+ ptp->u.alive.td.io.event,
+ 0,
+ 1);
break;
case ERTS_PORT_TASK_DIST_CMD:
break;
+ case ERTS_PORT_TASK_PROC_SIG: {
+ ErtsProc2PortSigData *sigdp = &ptp->u.alive.td.psig.data;
+ if (!pp->sched.taskq.bpq)
+ ptp->u.alive.td.psig.callback(NULL,
+ ERTS_PORT_SFLG_INVALID,
+ ERTS_PROC2PORT_SIG_ABORT_CLOSED,
+ sigdp);
+ else {
+ ErlDrvSizeT size = erts_proc2port_sig_command_data_size(sigdp);
+ ptp->u.alive.td.psig.callback(NULL,
+ ERTS_PORT_SFLG_INVALID,
+ ERTS_PROC2PORT_SIG_ABORT_CLOSED,
+ sigdp);
+ aborted_proc2port_data(pp, size);
+ }
+ break;
+ }
default:
erl_exit(ERTS_ABORT_EXIT,
"Invalid port task type: %d\n",
(int) ptp->type);
}
- port_task_free(ptp);
-
- erts_smp_runq_lock(runq);
- ptp = pop_task(ptqps[i]);
+ aborted_port_task:
+ schedule_port_task_free(ptp);
}
}
- ASSERT(!pp->sched.taskq || !pp->sched.taskq->first);
+ erts_smp_atomic32_read_band_nob(&pp->sched.flags,
+ ~(ERTS_PTS_FLG_HAVE_BUSY_TASKS
+ |ERTS_PTS_FLG_HAVE_TASKS));
+
+ /*
+ * Schedule cleanup of port structure...
+ */
+#ifdef ERTS_SMP
+ erts_schedule_thr_prgr_later_op(release_port,
+ (void *) pp,
+ &pp->common.u.release);
+#else
+ pp->cleanup = 1;
+#endif
}
int
erts_port_is_scheduled(Port *pp)
{
- int res;
- ErtsRunQueue *runq = erts_port_runq(pp);
- if (!runq)
- return 0;
- res = pp->sched.taskq || pp->sched.exe_taskq;
- erts_smp_runq_unlock(runq);
- return res;
+ erts_aint32_t flags = erts_smp_atomic32_read_acqb(&pp->sched.flags);
+ return (flags & (ERTS_PTS_FLG_IN_RUNQ|ERTS_PTS_FLG_EXEC)) != 0;
}
#ifdef ERTS_SMP
+
void
erts_enqueue_port(ErtsRunQueue *rq, Port *pp)
{
ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
ASSERT(rq == (ErtsRunQueue *) erts_smp_atomic_read_nob(&pp->run_queue));
- ASSERT(pp->sched.in_runq);
+ ASSERT(erts_smp_atomic32_read_nob(&pp->sched.flags) & ERTS_PTS_FLG_IN_RUNQ);
enqueue_port(rq, pp);
}
@@ -1022,7 +1961,8 @@ erts_dequeue_port(ErtsRunQueue *rq)
pp = pop_port(rq);
ASSERT(!pp
|| rq == (ErtsRunQueue *) erts_smp_atomic_read_nob(&pp->run_queue));
- ASSERT(!pp || pp->sched.in_runq);
+ ASSERT(!pp || (erts_smp_atomic32_read_nob(&pp->sched.flags)
+ & ERTS_PTS_FLG_IN_RUNQ));
return pp;
}
@@ -1037,5 +1977,5 @@ erts_port_task_init(void)
erts_smp_atomic_init_nob(&erts_port_task_outstanding_io_tasks,
(erts_aint_t) 0);
init_port_task_alloc();
- init_port_taskq_alloc();
+ init_busy_caller_table_alloc();
}
diff --git a/erts/emulator/beam/erl_port_task.h b/erts/emulator/beam/erl_port_task.h
index fd88b1c1ff..ae6cd69ae2 100644
--- a/erts/emulator/beam/erl_port_task.h
+++ b/erts/emulator/beam/erl_port_task.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2006-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2006-2012. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -27,6 +27,9 @@
#define ERTS_PORT_TASK_H_BASIC_TYPES__
#include "erl_sys_driver.h"
#include "erl_smp.h"
+#define ERL_PORT_GET_PORT_TYPE_ONLY__
+#include "erl_port.h"
+#undef ERL_PORT_GET_PORT_TYPE_ONLY__
typedef erts_smp_atomic_t ErtsPortTaskHandle;
#endif
@@ -43,13 +46,19 @@ typedef erts_smp_atomic_t ErtsPortTaskHandle;
#define ERTS_INCLUDE_SCHEDULER_INTERNALS
#endif
+#define ERTS_PT_FLG_WAIT_BUSY (1 << 0)
+#define ERTS_PT_FLG_SIG_DEP (1 << 1)
+#define ERTS_PT_FLG_NOSUSPEND (1 << 2)
+#define ERTS_PT_FLG_REF (1 << 3)
+#define ERTS_PT_FLG_BAD_OUTPUT (1 << 4)
+
typedef enum {
- ERTS_PORT_TASK_FREE,
ERTS_PORT_TASK_INPUT,
ERTS_PORT_TASK_OUTPUT,
ERTS_PORT_TASK_EVENT,
ERTS_PORT_TASK_TIMEOUT,
- ERTS_PORT_TASK_DIST_CMD
+ ERTS_PORT_TASK_DIST_CMD,
+ ERTS_PORT_TASK_PROC_SIG
} ErtsPortTaskType;
#ifdef ERTS_INCLUDE_SCHEDULER_INTERNALS
@@ -57,19 +66,76 @@ typedef enum {
extern erts_smp_atomic_t erts_port_task_outstanding_io_tasks;
#endif
+#define ERTS_PTS_FLG_IN_RUNQ (((erts_aint32_t) 1) << 0)
+#define ERTS_PTS_FLG_EXEC (((erts_aint32_t) 1) << 1)
+#define ERTS_PTS_FLG_HAVE_TASKS (((erts_aint32_t) 1) << 2)
+#define ERTS_PTS_FLG_EXIT (((erts_aint32_t) 1) << 3)
+#define ERTS_PTS_FLG_BUSY_PORT (((erts_aint32_t) 1) << 4)
+#define ERTS_PTS_FLG_BUSY_PORT_Q (((erts_aint32_t) 1) << 5)
+#define ERTS_PTS_FLG_CHK_UNSET_BUSY_PORT_Q (((erts_aint32_t) 1) << 6)
+#define ERTS_PTS_FLG_HAVE_BUSY_TASKS (((erts_aint32_t) 1) << 7)
+#define ERTS_PTS_FLG_HAVE_NS_TASKS (((erts_aint32_t) 1) << 8)
+#define ERTS_PTS_FLG_PARALLELISM (((erts_aint32_t) 1) << 9)
+#define ERTS_PTS_FLG_FORCE_SCHED (((erts_aint32_t) 1) << 10)
+
+#define ERTS_PTS_FLGS_BUSY \
+ (ERTS_PTS_FLG_BUSY_PORT | ERTS_PTS_FLG_BUSY_PORT_Q)
+
+#define ERTS_PTS_FLGS_FORCE_SCHEDULE_OP \
+ (ERTS_PTS_FLG_EXIT \
+ | ERTS_PTS_FLG_HAVE_BUSY_TASKS \
+ | ERTS_PTS_FLG_HAVE_TASKS \
+ | ERTS_PTS_FLG_EXEC \
+ | ERTS_PTS_FLG_FORCE_SCHED)
+
+#define ERTS_PORT_TASK_DEFAULT_BUSY_PORT_Q_HIGH 8192
+#define ERTS_PORT_TASK_DEFAULT_BUSY_PORT_Q_LOW 4096
+
+typedef struct {
+ ErlDrvSizeT high;
+ erts_smp_atomic_t low;
+ erts_smp_atomic_t size;
+} ErtsPortTaskBusyPortQ;
+
typedef struct ErtsPortTask_ ErtsPortTask;
-typedef struct ErtsPortTaskQueue_ ErtsPortTaskQueue;
+typedef struct ErtsPortTaskBusyCallerTable_ ErtsPortTaskBusyCallerTable;
+typedef struct ErtsPortTaskHandleList_ ErtsPortTaskHandleList;
typedef struct {
Port *next;
- int in_runq;
- ErtsPortTaskQueue *taskq;
- ErtsPortTaskQueue *exe_taskq;
+ struct {
+ struct {
+ struct {
+ ErtsPortTask *first;
+ ErtsPortTask *last;
+ ErtsPortTaskBusyCallerTable *table;
+ ErtsPortTaskHandleList *nosuspend;
+ } busy;
+ ErtsPortTask *first;
+ } local;
+ struct {
+ ErtsPortTask *first;
+ ErtsPortTask *last;
+ } in;
+ ErtsPortTaskBusyPortQ *bpq;
+ } taskq;
+ erts_smp_atomic32_t flags;
+#ifdef ERTS_SMP
+ erts_mtx_t mtx;
+#endif
} ErtsPortTaskSched;
ERTS_GLB_INLINE void erts_port_task_handle_init(ErtsPortTaskHandle *pthp);
ERTS_GLB_INLINE int erts_port_task_is_scheduled(ErtsPortTaskHandle *pthp);
-ERTS_GLB_INLINE void erts_port_task_init_sched(ErtsPortTaskSched *ptsp);
+ERTS_GLB_INLINE void erts_port_task_pre_init_sched(ErtsPortTaskSched *ptsp,
+ ErtsPortTaskBusyPortQ *bpq);
+ERTS_GLB_INLINE void erts_port_task_init_sched(ErtsPortTaskSched *ptsp,
+ Eterm id);
+ERTS_GLB_INLINE void erts_port_task_fini_sched(ErtsPortTaskSched *ptsp);
+ERTS_GLB_INLINE void erts_port_task_sched_lock(ErtsPortTaskSched *ptsp);
+ERTS_GLB_INLINE void erts_port_task_sched_unlock(ErtsPortTaskSched *ptsp);
+ERTS_GLB_INLINE int erts_port_task_sched_lock_is_locked(ErtsPortTaskSched *ptsp);
+
#ifdef ERTS_INCLUDE_SCHEDULER_INTERNALS
ERTS_GLB_INLINE int erts_port_task_have_outstanding_io_tasks(void);
#endif
@@ -88,13 +154,75 @@ erts_port_task_is_scheduled(ErtsPortTaskHandle *pthp)
return ((void *) erts_smp_atomic_read_nob(pthp)) != NULL;
}
+ERTS_GLB_INLINE void erts_port_task_pre_init_sched(ErtsPortTaskSched *ptsp,
+ ErtsPortTaskBusyPortQ *bpq)
+{
+ if (bpq) {
+ erts_aint_t low = (erts_aint_t) ERTS_PORT_TASK_DEFAULT_BUSY_PORT_Q_LOW;
+ erts_smp_atomic_init_nob(&bpq->low, low);
+ bpq->high = (ErlDrvSizeT) ERTS_PORT_TASK_DEFAULT_BUSY_PORT_Q_HIGH;
+ erts_smp_atomic_init_nob(&bpq->size, (erts_aint_t) 0);
+ }
+ ptsp->taskq.bpq = bpq;
+}
+
ERTS_GLB_INLINE void
-erts_port_task_init_sched(ErtsPortTaskSched *ptsp)
+erts_port_task_init_sched(ErtsPortTaskSched *ptsp, Eterm instr_id)
{
+#ifdef ERTS_SMP
+ char *lock_str = "port_sched_lock";
+#endif
ptsp->next = NULL;
- ptsp->in_runq = 0;
- ptsp->taskq = NULL;
- ptsp->exe_taskq = NULL;
+ ptsp->taskq.local.busy.first = NULL;
+ ptsp->taskq.local.busy.last = NULL;
+ ptsp->taskq.local.busy.table = NULL;
+ ptsp->taskq.local.busy.nosuspend = NULL;
+ ptsp->taskq.local.first = NULL;
+ ptsp->taskq.in.first = NULL;
+ ptsp->taskq.in.last = NULL;
+ erts_smp_atomic32_init_nob(&ptsp->flags, 0);
+#ifdef ERTS_SMP
+#ifdef ERTS_ENABLE_LOCK_COUNT
+ if (!(erts_lcnt_rt_options & ERTS_LCNT_OPT_PORTLOCK))
+ lock_str = NULL;
+#endif
+ erts_mtx_init_x(&ptsp->mtx, lock_str, instr_id);
+#endif
+}
+
+ERTS_GLB_INLINE void
+erts_port_task_sched_lock(ErtsPortTaskSched *ptsp)
+{
+#ifdef ERTS_SMP
+ erts_mtx_lock(&ptsp->mtx);
+#endif
+}
+
+ERTS_GLB_INLINE void
+erts_port_task_sched_unlock(ErtsPortTaskSched *ptsp)
+{
+#ifdef ERTS_SMP
+ erts_mtx_unlock(&ptsp->mtx);
+#endif
+}
+
+ERTS_GLB_INLINE int
+erts_port_task_sched_lock_is_locked(ErtsPortTaskSched *ptsp)
+{
+#if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK)
+ return erts_lc_mtx_is_locked(&ptsp->mtx);
+#else
+ return 0;
+#endif
+}
+
+
+ERTS_GLB_INLINE void
+erts_port_task_fini_sched(ErtsPortTaskSched *ptsp)
+{
+#ifdef ERTS_SMP
+ erts_mtx_destroy(&ptsp->mtx);
+#endif
}
#ifdef ERTS_INCLUDE_SCHEDULER_INTERNALS
@@ -115,14 +243,16 @@ int erts_port_task_execute(ErtsRunQueue *, Port **);
void erts_port_task_init(void);
#endif
-int erts_port_task_abort(Eterm id, ErtsPortTaskHandle *);
+int erts_port_task_abort(ErtsPortTaskHandle *);
+void erts_port_task_abort_nosuspend_tasks(Port *);
+
int erts_port_task_schedule(Eterm,
ErtsPortTaskHandle *,
ErtsPortTaskType,
- ErlDrvEvent,
- ErlDrvEventData);
+ ...);
void erts_port_task_free_port(Port *);
int erts_port_is_scheduled(Port *);
+ErtsProc2PortSigData *erts_port_task_alloc_p2p_sig_data(void);
#ifdef ERTS_SMP
void erts_enqueue_port(ErtsRunQueue *rq, Port *pp);
diff --git a/erts/emulator/beam/erl_posix_str.c b/erts/emulator/beam/erl_posix_str.c
index 02db10905b..deb7e3e173 100644
--- a/erts/emulator/beam/erl_posix_str.c
+++ b/erts/emulator/beam/erl_posix_str.c
@@ -619,6 +619,7 @@ erl_errno_id(error)
case WSAEINVALIDPROVIDER: return "einvalidprovider";
#endif
#ifdef WSAEPROVIDERFAILEDINIT
+ /* You could get this if SYSTEMROOT env variable is set incorrectly */
case WSAEPROVIDERFAILEDINIT: return "eproviderfailedinit";
#endif
#ifdef WSASYSCALLFAILURE
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index ddc43e621d..aaca4b5f59 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -42,6 +42,10 @@
#include "erl_thr_queue.h"
#include "erl_async.h"
#include "dtrace-wrapper.h"
+#include "erl_ptab.h"
+
+#define ERTS_DELAYED_WAKEUP_INFINITY (~(Uint64) 0)
+#define ERTS_DELAYED_WAKEUP_REDUCTIONS ((Uint64) CONTEXT_REDS/2)
#define ERTS_RUNQ_CHECK_BALANCE_REDS_PER_SCHED (2000*CONTEXT_REDS)
#define ERTS_RUNQ_CALL_CHECK_BALANCE_REDS \
@@ -133,155 +137,16 @@ do { \
#define ERTS_EMPTY_RUNQ_PORTS(RQ) \
(RUNQ_READ_LEN(&(RQ)->ports.info.len) == 0 && (RQ)->misc.start == NULL)
+const Process erts_invalid_process = {{ERTS_INVALID_PID}};
+
extern BeamInstr beam_apply[];
extern BeamInstr beam_exit[];
extern BeamInstr beam_continue_exit[];
-#ifdef ARCH_32
-
-union {
- erts_smp_dw_atomic_t pid_data;
- char align[ERTS_CACHE_LINE_SIZE];
-} last erts_align_attribute(ERTS_CACHE_LINE_SIZE);
-
-
-static ERTS_INLINE Uint64
-dw_aint_to_uint64(erts_dw_aint_t *dw)
-{
-#ifdef ETHR_SU_DW_NAINT_T__
- return (Uint64) dw->dw_sint;
-#else
- Uint64 res;
- res = (Uint64) ((Uint32) dw->sint[ERTS_DW_AINT_HIGH_WORD]);
- res <<= 32;
- res |= (Uint64) ((Uint32) dw->sint[ERTS_DW_AINT_LOW_WORD]);
- return res;
-#endif
-}
-
-static void
-unint64_to_dw_aint(erts_dw_aint_t *dw, Uint64 val)
-{
-#ifdef ETHR_SU_DW_NAINT_T__
- dw->dw_sint = (ETHR_SU_DW_NAINT_T__) val;
-#else
- dw->sint[ERTS_DW_AINT_LOW_WORD] = (erts_aint_t) (val & 0xffffffff);
- dw->sint[ERTS_DW_AINT_HIGH_WORD] = (erts_aint_t) ((val >> 32) & 0xffffffff);
-#endif
-}
-
-static ERTS_INLINE void
-last_pid_data_init_nob(Uint64 val)
-{
- erts_dw_aint_t dw;
- unint64_to_dw_aint(&dw, val);
- erts_smp_dw_atomic_init_nob(&last.pid_data, &dw);
-}
-
-static ERTS_INLINE void
-last_pid_data_set_relb(Uint64 val)
-{
- erts_dw_aint_t dw;
- unint64_to_dw_aint(&dw, val);
- erts_smp_dw_atomic_set_relb(&last.pid_data, &dw);
-}
-
-static ERTS_INLINE Uint64
-last_pid_data_read_nob(void)
-{
- erts_dw_aint_t dw;
- erts_smp_dw_atomic_read_nob(&last.pid_data, &dw);
- return dw_aint_to_uint64(&dw);
-}
-
-static ERTS_INLINE Uint64
-last_pid_data_read_acqb(void)
-{
- erts_dw_aint_t dw;
- erts_smp_dw_atomic_read_acqb(&last.pid_data, &dw);
- return dw_aint_to_uint64(&dw);
-}
-
-static ERTS_INLINE Uint64
-last_pid_data_cmpxchg_relb(Uint64 new, Uint64 exp)
-{
- erts_dw_aint_t dw_new, dw_xchg;
-
- unint64_to_dw_aint(&dw_new, new);
- unint64_to_dw_aint(&dw_xchg, exp);
-
- if (erts_smp_dw_atomic_cmpxchg_relb(&last.pid_data, &dw_new, &dw_xchg))
- return exp;
- else
- return dw_aint_to_uint64(&dw_xchg);
-}
-
-#elif defined(ARCH_64)
-
-union {
- erts_smp_atomic_t pid_data;
- char align[ERTS_CACHE_LINE_SIZE];
-} last erts_align_attribute(ERTS_CACHE_LINE_SIZE);
-
-static ERTS_INLINE void
-last_pid_data_init_nob(Uint64 val)
-{
- erts_smp_atomic_init_nob(&last.pid_data, (erts_aint_t) val);
-}
-
-static ERTS_INLINE void
-last_pid_data_set_relb(Uint64 val)
-{
- erts_smp_atomic_set_relb(&last.pid_data, (erts_aint_t) val);
-}
-
-static ERTS_INLINE Uint64
-last_pid_data_read_nob(void)
-{
- return (Uint64) erts_smp_atomic_read_nob(&last.pid_data);
-}
-
-static ERTS_INLINE Uint64
-last_pid_data_read_acqb(void)
-{
- return (Uint64) erts_smp_atomic_read_acqb(&last.pid_data);
-}
-
-static ERTS_INLINE Uint64
-last_pid_data_cmpxchg_relb(Uint64 new, Uint64 exp)
-{
- return (Uint64) erts_smp_atomic_cmpxchg_relb(&last.pid_data,
- (erts_aint_t) new,
- (erts_aint_t) exp);
-}
-
-#else
-# error "Not 64-bit, nor 32-bit architecture..."
-#endif
-
-static ERTS_INLINE int
-last_pid_data_cmp(Uint64 lpd1, Uint64 lpd2)
-{
- Uint64 lpd1_wrap;
-
- if (lpd1 == lpd2)
- return 0;
-
- lpd1_wrap = lpd1 + (((Uint64) 1) << 63);
-
- if (lpd1 < lpd1_wrap)
- return (lpd1 < lpd2 && lpd2 < lpd1_wrap) ? -1 : 1;
- else
- return (lpd1_wrap <= lpd2 && lpd2 < lpd1) ? 1 : -1;
-}
-
-
-#define ERTS_PID_DATA_MASK__ ((1 << _PID_DATA_SIZE) - 1)
-
int erts_sched_compact_load;
Uint erts_no_schedulers;
-ErtsProcTab erts_proc erts_align_attribute(ERTS_CACHE_LINE_SIZE);
+ErtsPTab erts_proc erts_align_attribute(ERTS_CACHE_LINE_SIZE);
int erts_sched_thread_suggested_stack_size = -1;
@@ -368,8 +233,6 @@ erts_sched_stat_t erts_sched_stat;
static erts_tsd_key_t sched_data_key;
#endif
-erts_smp_rwmtx_t erts_proc_tab_rwmtx;
-
static erts_smp_atomic32_t function_calls;
#ifdef ERTS_SMP
@@ -406,29 +269,6 @@ struct erts_system_profile_flags_t erts_system_profile_flags;
#if ERTS_MAX_PROCESSES > 0x7fffffff
#error "Need to store process_count in another type"
#endif
-static erts_smp_atomic32_t process_count;
-
-typedef struct ErtsTermProcElement_ ErtsTermProcElement;
-struct ErtsTermProcElement_ {
- ErtsTermProcElement *next;
- ErtsTermProcElement *prev;
- int ix;
- union {
- struct {
- Eterm pid;
- Uint64 spawned;
- Uint64 exited;
- } process;
- struct {
- Uint64 interval;
- } bif_invocation;
- } u;
-};
-
-static struct {
- ErtsTermProcElement *start;
- ErtsTermProcElement *end;
-} saved_term_procs;
ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(misc_op_list,
ErtsMiscOpList,
@@ -490,8 +330,6 @@ do { \
* Local functions.
*/
-static void init_processes_bif(void);
-static void save_terminating_process(Process *p);
static void exec_misc_ops(ErtsRunQueue *);
static void print_function_from_pc(int to, void *to_arg, BeamInstr* x);
static int stack_element_dump(int to, void *to_arg, Process* p, Eterm* sp,
@@ -530,10 +368,6 @@ dbg_chk_aux_work_val(erts_aint32_t value)
#ifdef ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN
valid |= ERTS_SSI_AUX_WORK_CHECK_CHILDREN;
#endif
-#ifdef ERTS_SMP
- valid |= ERTS_SSI_AUX_WORK_CODE_IX_ACTIVATION;
- valid |= ERTS_SSI_AUX_WORK_FINISH_BP;
-#endif
#ifdef ERTS_SSI_AUX_WORK_REAP_PORTS
valid |= ERTS_SSI_AUX_WORK_REAP_PORTS;
#endif
@@ -563,39 +397,17 @@ erts_smp_lc_runq_is_locked(ErtsRunQueue *runq)
}
#endif
-static erts_interval_t *proc_interval;
-
-static void
-proc_interval_init(void)
-{
- proc_interval = erts_alloc_permanent_cache_aligned(
- ERTS_ALC_T_PROC_INTERVAL,
- sizeof(erts_interval_t));
- erts_smp_interval_init(proc_interval);
-}
-
-static ERTS_INLINE Uint64
-get_proc_interval(void)
-{
- return erts_smp_current_interval_nob(proc_interval);
-}
static ERTS_INLINE Uint64
ensure_later_proc_interval(Uint64 interval)
{
- return erts_smp_ensure_later_interval_nob(proc_interval, interval);
-}
-
-static ERTS_INLINE Uint64
-step_proc_interval(void)
-{
- return erts_smp_step_interval_nob(proc_interval);
+ return erts_smp_ensure_later_interval_nob(erts_ptab_interval(&erts_proc), interval);
}
Uint64
erts_get_proc_interval(void)
{
- return get_proc_interval();
+ return erts_smp_current_interval_nob(erts_ptab_interval(&erts_proc));
}
Uint64
@@ -607,7 +419,7 @@ erts_ensure_later_proc_interval(Uint64 interval)
Uint64
erts_step_proc_interval(void)
{
- return step_proc_interval();
+ return erts_smp_step_interval_nob(erts_ptab_interval(&erts_proc));
}
void
@@ -655,20 +467,18 @@ erts_pre_init_process(void)
#endif
}
+#ifdef ERTS_SMP
+static void
+release_process(void *vproc)
+{
+ erts_smp_proc_dec_refc((Process *) vproc);
+}
+#endif
+
/* initialize the scheduler */
void
-erts_init_process(int ncpu)
+erts_init_process(int ncpu, int proc_tab_size)
{
- int proc_tab_sz;
- int max_proc_bits;
- int proc_bits = ERTS_PROC_BITS;
- erts_smp_atomic_t *proc_entry;
- char *proc_tab_end;
- erts_smp_rwmtx_opt_t proc_tab_rwmtx_opts = ERTS_SMP_RWMTX_OPT_DEFAULT_INITER;
- proc_tab_rwmtx_opts.type = ERTS_SMP_RWMTX_TYPE_EXTREMELY_FREQUENT_READ;
- proc_tab_rwmtx_opts.lived = ERTS_SMP_RWMTX_LONG_LIVED;
-
- proc_interval_init();
#ifdef ERTS_SMP
erts_disable_proc_not_running_opt = 0;
@@ -677,52 +487,16 @@ erts_init_process(int ncpu)
init_proclist_alloc();
- erts_smp_atomic32_init_nob(&process_count, 0);
-
- if (erts_use_r9_pids_ports)
- proc_bits = ERTS_R9_PROC_BITS;
-
- if (erts_proc.max > (1 << proc_bits))
- erts_proc.max = 1 << proc_bits;
-
- proc_tab_sz = ERTS_ALC_CACHE_LINE_ALIGN_SIZE(erts_proc.max
- * sizeof(erts_smp_atomic_t));
- erts_proc.tab = erts_alloc(ERTS_ALC_T_PROC_TABLE, proc_tab_sz);
- proc_tab_end = ((char *) erts_proc.tab) + proc_tab_sz;
- proc_entry = erts_proc.tab;
- while (proc_tab_end > ((char *) proc_entry)) {
- erts_smp_atomic_init_nob(proc_entry, ERTS_AINT_NULL);
- proc_entry++;
- }
-
- erts_smp_rwmtx_init_opt(&erts_proc_tab_rwmtx,
- &proc_tab_rwmtx_opts,
- "proc_tab");
- last_pid_data_init_nob(~((Uint64) 0));
-
- max_proc_bits = erts_fit_in_bits_int32((Sint32) erts_proc.max - 1);
-
- erts_proc.tab_cache_lines = proc_tab_sz/ERTS_CACHE_LINE_SIZE;
- erts_proc.pix_per_cache_line = ERTS_CACHE_LINE_SIZE/sizeof(erts_smp_atomic_t);
- if ((erts_proc.max & (erts_proc.max - 1))
- | (erts_proc.pix_per_cache_line & (erts_proc.pix_per_cache_line - 1))) {
- /*
- * erts_proc.max or erts_proc.pix_per_cache_line
- * not a power of 2 :(
- */
- erts_proc.pix_cl_mask = 0;
- erts_proc.pix_cl_shift = 0;
- erts_proc.pix_cli_mask = 0;
- erts_proc.pix_cli_shift = 0;
- }
- else {
- ASSERT((erts_proc.tab_cache_lines
- & (erts_proc.tab_cache_lines - 1)) == 0);
- erts_proc.pix_cl_mask = erts_proc.tab_cache_lines-1;
- erts_proc.pix_cl_shift = erts_fit_in_bits_int32(erts_proc.pix_per_cache_line-1);
- erts_proc.pix_cli_shift = erts_fit_in_bits_int32(erts_proc.pix_cl_mask);
- erts_proc.pix_cli_mask = (1 << (max_proc_bits - erts_proc.pix_cli_shift)) - 1;
- }
+ erts_ptab_init_table(&erts_proc,
+ ERTS_ALC_T_PROC_TABLE,
+#ifdef ERTS_SMP
+ release_process,
+#else
+ NULL,
+#endif
+ (ErtsPTabElementCommon *) &erts_invalid_process.common,
+ proc_tab_size,
+ "process_table");
last_reductions = 0;
last_exact_reductions = 0;
@@ -733,7 +507,6 @@ void
erts_late_init_process(void)
{
int ix;
- init_processes_bif();
erts_smp_spinlock_init(&erts_sched_stat.lock, "sched_stat");
for (ix = 0; ix < ERTS_NO_PRIO_LEVELS; ix++) {
@@ -981,9 +754,9 @@ static ERTS_INLINE ErtsProcList *
proclist_create(Process *p)
{
ErtsProcList *plp = proclist_alloc();
- ensure_later_proc_interval(p->started_interval);
- plp->pid = p->id;
- plp->started_interval = p->started_interval;
+ ensure_later_proc_interval(p->common.u.alive.started_interval);
+ plp->pid = p->common.id;
+ plp->started_interval = p->common.u.alive.started_interval;
return plp;
}
@@ -993,12 +766,6 @@ proclist_destroy(ErtsProcList *plp)
proclist_free(plp);
}
-static ERTS_INLINE int
-proclist_same(ErtsProcList *plp, Process *p)
-{
- return plp->pid == p->id && plp->started_interval == p->started_interval;
-}
-
ErtsProcList *
erts_proclist_create(Process *p)
{
@@ -1011,12 +778,6 @@ erts_proclist_destroy(ErtsProcList *plp)
proclist_destroy(plp);
}
-int
-erts_proclist_same(ErtsProcList *plp, Process *p)
-{
- return proclist_same(plp, p);
-}
-
void *
erts_psd_set_init(Process *p, ErtsProcLocks plocks, int ix, void *data)
{
@@ -1180,9 +941,15 @@ haw_thr_prgr_current_check_progress(ErtsAuxWorkData *awdp)
}
static ERTS_INLINE erts_aint32_t
-handle_delayed_aux_work_wakeup(ErtsAuxWorkData *awdp, erts_aint32_t aux_work)
+handle_delayed_aux_work_wakeup(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting)
{
int jix, max_jix;
+
+ ASSERT(awdp->delayed_wakeup.next != ERTS_DELAYED_WAKEUP_INFINITY);
+
+ if (!waiting && awdp->delayed_wakeup.next > awdp->esdp->reductions)
+ return aux_work;
+
unset_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_DELAYED_AW_WAKEUP);
ERTS_THR_MEMORY_BARRIER;
@@ -1198,11 +965,14 @@ handle_delayed_aux_work_wakeup(ErtsAuxWorkData *awdp, erts_aint32_t aux_work)
set_aux_work_flags_wakeup_nob(ERTS_SCHED_SLEEP_INFO_IX(sched-1),
aux_work);
}
+ awdp->delayed_wakeup.next = ERTS_DELAYED_WAKEUP_INFINITY;
return aux_work & ~ERTS_SSI_AUX_WORK_DELAYED_AW_WAKEUP;
}
static ERTS_INLINE void
-schedule_aux_work_wakeup(ErtsAuxWorkData *awdp, int sched, erts_aint32_t aux_work)
+schedule_aux_work_wakeup(ErtsAuxWorkData *awdp,
+ int sched,
+ erts_aint32_t aux_work)
{
int jix = awdp->delayed_wakeup.sched2jix[sched];
if (jix >= 0) {
@@ -1215,7 +985,20 @@ schedule_aux_work_wakeup(ErtsAuxWorkData *awdp, int sched, erts_aint32_t aux_wor
awdp->delayed_wakeup.job[jix].sched = sched;
awdp->delayed_wakeup.job[jix].aux_work = aux_work;
}
- set_aux_work_flags_wakeup_nob(awdp->ssi, ERTS_SSI_AUX_WORK_DELAYED_AW_WAKEUP);
+
+ if (awdp->delayed_wakeup.next != ERTS_DELAYED_WAKEUP_INFINITY) {
+ ASSERT(erts_atomic32_read_nob(&awdp->ssi->aux_work)
+ & ERTS_SSI_AUX_WORK_DELAYED_AW_WAKEUP);
+ }
+ else {
+ awdp->delayed_wakeup.next = (awdp->esdp->reductions
+ + ERTS_DELAYED_WAKEUP_REDUCTIONS);
+
+ ASSERT(!(erts_atomic32_read_nob(&awdp->ssi->aux_work)
+ & ERTS_SSI_AUX_WORK_DELAYED_AW_WAKEUP));
+ set_aux_work_flags_wakeup_nob(awdp->ssi,
+ ERTS_SSI_AUX_WORK_DELAYED_AW_WAKEUP);
+ }
}
#endif
@@ -1294,7 +1077,8 @@ misc_aux_work_clean(ErtsThrQ_t *q,
static ERTS_INLINE erts_aint32_t
handle_misc_aux_work(ErtsAuxWorkData *awdp,
- erts_aint32_t aux_work)
+ erts_aint32_t aux_work,
+ int waiting)
{
ErtsThrQ_t *q = &misc_aux_work_queues[awdp->sched_id].q;
@@ -1314,7 +1098,8 @@ handle_misc_aux_work(ErtsAuxWorkData *awdp,
static ERTS_INLINE erts_aint32_t
handle_misc_aux_work_thr_prgr(ErtsAuxWorkData *awdp,
- erts_aint32_t aux_work)
+ erts_aint32_t aux_work,
+ int waiting)
{
if (!erts_thr_progress_has_reached_this(haw_thr_prgr_current(awdp),
awdp->misc.thr_prgr))
@@ -1393,7 +1178,8 @@ erts_notify_check_async_ready_queue(void *vno)
static ERTS_INLINE erts_aint32_t
handle_async_ready(ErtsAuxWorkData *awdp,
- erts_aint32_t aux_work)
+ erts_aint32_t aux_work,
+ int waiting)
{
ErtsSchedulerSleepInfo *ssi = awdp->ssi;
unset_aux_work_flags(ssi, ERTS_SSI_AUX_WORK_ASYNC_READY);
@@ -1415,7 +1201,8 @@ handle_async_ready(ErtsAuxWorkData *awdp,
static ERTS_INLINE erts_aint32_t
handle_async_ready_clean(ErtsAuxWorkData *awdp,
- erts_aint32_t aux_work)
+ erts_aint32_t aux_work,
+ int waiting)
{
void *thr_prgr_p;
@@ -1450,95 +1237,9 @@ handle_async_ready_clean(ErtsAuxWorkData *awdp,
#endif /* ERTS_USE_ASYNC_READY_Q */
-#ifdef ERTS_SMP
-void
-erts_notify_code_ix_activation(Process* p, ErtsThrPrgrVal later)
-{
- ErtsAuxWorkData* awdp = &p->scheduler_data->aux_work_data;
- ASSERT(awdp->code_ix_activation.code_stager == NULL);
- awdp->code_ix_activation.code_stager = p;
- awdp->code_ix_activation.thr_prgr = later;
- erts_smp_proc_inc_refc(p);
- set_aux_work_flags_wakeup_relb(p->scheduler_data->ssi,
- ERTS_SSI_AUX_WORK_CODE_IX_ACTIVATION);
-}
-
-static erts_aint32_t
-handle_code_ix_activation(ErtsAuxWorkData *awdp, erts_aint32_t aux_work)
-{
- Process* p;
- if (!erts_thr_progress_has_reached(awdp->code_ix_activation.thr_prgr)) {
- return aux_work & ~ERTS_SSI_AUX_WORK_CODE_IX_ACTIVATION;
- }
- unset_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_CODE_IX_ACTIVATION);
- p = awdp->code_ix_activation.code_stager;
- ASSERT(p);
-#ifdef DEBUG
- awdp->code_ix_activation.code_stager = NULL;
-#endif
- erts_commit_staging_code_ix();
- erts_release_code_write_permission();
- erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS);
- if (!ERTS_PROC_IS_EXITING(p)) {
- erts_resume(p, ERTS_PROC_LOCK_STATUS);
- }
- erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS);
- erts_smp_proc_dec_refc(p);
- return aux_work & ~ERTS_SSI_AUX_WORK_CODE_IX_ACTIVATION;
-}
-#endif /* ERTS_SMP */
-
-#ifdef ERTS_SMP
-void
-erts_notify_finish_breakpointing(Process* p)
-{
- ErtsAuxWorkData* awdp = &p->scheduler_data->aux_work_data;
-
- ASSERT(awdp->bp_ix_activation.stager == NULL);
- awdp->bp_ix_activation.stager = p;
- awdp->bp_ix_activation.thr_prgr = erts_thr_progress_later(awdp->esdp);
- erts_thr_progress_wakeup(awdp->esdp, awdp->bp_ix_activation.thr_prgr);
- erts_smp_proc_inc_refc(p);
- set_aux_work_flags_wakeup_relb(p->scheduler_data->ssi,
- ERTS_SSI_AUX_WORK_FINISH_BP);
-}
-
-static erts_aint32_t
-handle_finish_bp(ErtsAuxWorkData* awdp, erts_aint32_t aux_work)
-{
- ErtsThrPrgrVal current = haw_thr_prgr_current(awdp);
-
- if (!erts_thr_progress_has_reached_this(current,
- awdp->bp_ix_activation.thr_prgr)) {
- return aux_work & ~ERTS_SSI_AUX_WORK_FINISH_BP;
- }
- if (erts_finish_breakpointing()) { /* Not done */
- /* Arrange for being called again */
- awdp->bp_ix_activation.thr_prgr =
- erts_thr_progress_later(awdp->esdp);
- erts_thr_progress_wakeup(awdp->esdp, awdp->bp_ix_activation.thr_prgr);
- } else { /* Done */
- Process* p;
-
- unset_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_FINISH_BP);
- p = awdp->bp_ix_activation.stager;
-#ifdef DEBUG
- awdp->bp_ix_activation.stager = NULL;
-#endif
- erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS);
- if (!ERTS_PROC_IS_EXITING(p)) {
- erts_resume(p, ERTS_PROC_LOCK_STATUS);
- }
- erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS);
- erts_smp_proc_dec_refc(p);
- erts_release_code_write_permission();
- }
- return aux_work & ~ERTS_SSI_AUX_WORK_FINISH_BP;
-}
-#endif /* ERTS_SMP */
static ERTS_INLINE erts_aint32_t
-handle_fix_alloc(ErtsAuxWorkData *awdp, erts_aint32_t aux_work)
+handle_fix_alloc(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting)
{
ErtsSchedulerSleepInfo *ssi = awdp->ssi;
erts_aint32_t res;
@@ -1572,7 +1273,7 @@ erts_alloc_notify_delayed_dealloc(int ix)
}
static ERTS_INLINE erts_aint32_t
-handle_delayed_dealloc(ErtsAuxWorkData *awdp, erts_aint32_t aux_work)
+handle_delayed_dealloc(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting)
{
ErtsSchedulerSleepInfo *ssi = awdp->ssi;
int need_thr_progress = 0;
@@ -1610,7 +1311,7 @@ handle_delayed_dealloc(ErtsAuxWorkData *awdp, erts_aint32_t aux_work)
}
static ERTS_INLINE erts_aint32_t
-handle_delayed_dealloc_thr_prgr(ErtsAuxWorkData *awdp, erts_aint32_t aux_work)
+handle_delayed_dealloc_thr_prgr(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting)
{
ErtsSchedulerSleepInfo *ssi;
int need_thr_progress;
@@ -1660,7 +1361,7 @@ handle_delayed_dealloc_thr_prgr(ErtsAuxWorkData *awdp, erts_aint32_t aux_work)
#define ERTS_MAX_THR_PRGR_LATER_OPS 50
static ERTS_INLINE erts_aint32_t
-handle_thr_prgr_later_op(ErtsAuxWorkData *awdp, erts_aint32_t aux_work)
+handle_thr_prgr_later_op(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting)
{
int lops;
ErtsThrPrgrVal current = haw_thr_prgr_current(awdp);
@@ -1670,6 +1371,9 @@ handle_thr_prgr_later_op(ErtsAuxWorkData *awdp, erts_aint32_t aux_work)
if (!erts_thr_progress_has_reached_this(current, lop->later))
return aux_work & ~ERTS_SSI_AUX_WORK_THR_PRGR_LATER_OP;
awdp->later_op.first = lop->next;
+ if (!awdp->later_op.first) {
+ awdp->later_op.last = NULL;
+ }
lop->func(lop->data);
if (!awdp->later_op.first) {
awdp->later_op.last = NULL;
@@ -1806,7 +1510,7 @@ erts_smp_notify_check_children_needed(void)
}
static ERTS_INLINE erts_aint32_t
-handle_check_children(ErtsAuxWorkData *awdp, erts_aint32_t aux_work)
+handle_check_children(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting)
{
unset_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_CHECK_CHILDREN);
erts_check_children();
@@ -1829,42 +1533,37 @@ erts_smp_atomic32_t erts_halt_progress;
int erts_halt_code;
static ERTS_INLINE erts_aint32_t
-handle_reap_ports(ErtsAuxWorkData *awdp, erts_aint32_t aux_work)
+handle_reap_ports(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting)
{
unset_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_REAP_PORTS);
awdp->esdp->run_queue->halt_in_progress = 1;
if (erts_smp_atomic32_dec_read_acqb(&erts_halt_progress) == 0) {
- int i;
+ int i, max = erts_ptab_max(&erts_port);
erts_smp_atomic32_set_nob(&erts_halt_progress, 1);
- for (i = 0; i < erts_max_ports; i++) {
- Port *prt = &erts_port[i];
- erts_smp_port_state_lock(prt);
- if ((prt->status & (ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP
- | ERTS_PORT_SFLG_HALT))) {
- erts_smp_port_state_unlock(prt);
+ for (i = 0; i < max; i++) {
+ erts_aint32_t state;
+ Port *prt = erts_pix2port(i);
+ if (!prt)
continue;
- }
- /* We need to set the halt flag - get the port lock */
-#ifdef ERTS_SMP
- erts_smp_atomic_inc_nob(&prt->refc);
-#endif
- erts_smp_port_state_unlock(prt);
-#ifdef ERTS_SMP
- erts_smp_mtx_lock(prt->lock);
-#endif
- if ((prt->status & (ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP
- | ERTS_PORT_SFLG_HALT))) {
- erts_port_release(prt);
- continue;
- }
- erts_port_status_bor_set(prt, ERTS_PORT_SFLG_HALT);
- erts_smp_atomic32_inc_nob(&erts_halt_progress);
- if (prt->status & (ERTS_PORT_SFLG_EXITING
- | ERTS_PORT_SFLG_CLOSING)) {
- erts_port_release(prt);
+ state = erts_atomic32_read_acqb(&prt->state);
+ if (state & (ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP
+ | ERTS_PORT_SFLG_HALT))
continue;
+
+ /* We need to set the halt flag - get the port lock */
+
+ erts_smp_port_lock(prt);
+
+ state = erts_atomic32_read_nob(&prt->state);
+ if (!(state & (ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP
+ | ERTS_PORT_SFLG_HALT))) {
+ state = erts_atomic32_read_bor_relb(&prt->state,
+ ERTS_PORT_SFLG_HALT);
+ erts_smp_atomic32_inc_nob(&erts_halt_progress);
+ if (!(state & (ERTS_PORT_SFLG_EXITING|ERTS_PORT_SFLG_CLOSING)))
+ erts_deliver_port_exit(prt, prt->common.id, am_killed, 0);
}
- erts_do_exit_port(prt, prt->id, am_killed);
+
erts_port_release(prt);
}
if (erts_smp_atomic32_dec_read_nob(&erts_halt_progress) == 0) {
@@ -1877,7 +1576,7 @@ handle_reap_ports(ErtsAuxWorkData *awdp, erts_aint32_t aux_work)
#if HAVE_ERTS_MSEG
static ERTS_INLINE erts_aint32_t
-handle_mseg_cache_check(ErtsAuxWorkData *awdp, erts_aint32_t aux_work)
+handle_mseg_cache_check(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting)
{
unset_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_MSEG_CACHE_CHECK);
erts_mseg_cache_check();
@@ -1887,7 +1586,7 @@ handle_mseg_cache_check(ErtsAuxWorkData *awdp, erts_aint32_t aux_work)
#endif
static ERTS_INLINE erts_aint32_t
-handle_setup_aux_work_timer(ErtsAuxWorkData *awdp, erts_aint32_t aux_work)
+handle_setup_aux_work_timer(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting)
{
unset_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_SET_TMO);
setup_aux_work_timer();
@@ -1901,7 +1600,7 @@ handle_aux_work(ErtsAuxWorkData *awdp, erts_aint32_t orig_aux_work, int waiting)
#define HANDLE_AUX_WORK(FLG, HNDLR) \
ignore |= FLG; \
if (aux_work & FLG) { \
- aux_work = HNDLR(awdp, aux_work); \
+ aux_work = HNDLR(awdp, aux_work, waiting); \
ERTS_DBG_CHK_AUX_WORK_VAL(aux_work); \
if (!(aux_work & ~ignore)) { \
ERTS_DBG_CHK_AUX_WORK_VAL(aux_work); \
@@ -1981,19 +1680,9 @@ handle_aux_work(ErtsAuxWorkData *awdp, erts_aint32_t orig_aux_work, int waiting)
handle_mseg_cache_check);
#endif
-#ifdef ERTS_SMP
- HANDLE_AUX_WORK(ERTS_SSI_AUX_WORK_CODE_IX_ACTIVATION,
- handle_code_ix_activation);
-#endif
-
HANDLE_AUX_WORK(ERTS_SSI_AUX_WORK_REAP_PORTS,
handle_reap_ports);
-#ifdef ERTS_SMP
- HANDLE_AUX_WORK(ERTS_SSI_AUX_WORK_FINISH_BP,
- handle_finish_bp);
-#endif
-
ERTS_DBG_CHK_AUX_WORK_VAL(aux_work);
#ifdef ERTS_SMP
@@ -3251,12 +2940,12 @@ resume_run_queue(ErtsRunQueue *rq)
erts_smp_runq_lock(rq);
- (void) ERTS_RUNQ_FLGS_MASK_SET(rq,
- (ERTS_RUNQ_FLG_OUT_OF_WORK
- | ERTS_RUNQ_FLG_HALFTIME_OUT_OF_WORK
- | ERTS_RUNQ_FLG_SUSPENDED),
- (ERTS_RUNQ_FLG_OUT_OF_WORK
- | ERTS_RUNQ_FLG_HALFTIME_OUT_OF_WORK));
+ (void) ERTS_RUNQ_FLGS_READ_BSET(rq,
+ (ERTS_RUNQ_FLG_OUT_OF_WORK
+ | ERTS_RUNQ_FLG_HALFTIME_OUT_OF_WORK
+ | ERTS_RUNQ_FLG_SUSPENDED),
+ (ERTS_RUNQ_FLG_OUT_OF_WORK
+ | ERTS_RUNQ_FLG_HALFTIME_OUT_OF_WORK));
rq->check_balance_reds = ERTS_RUNQ_CALL_CHECK_BALANCE_REDS;
for (pix = 0; pix < ERTS_NO_PROC_PRIO_LEVELS; pix++) {
@@ -4278,7 +3967,7 @@ erts_fprintf(stderr, "--------------------------------\n");
ERTS_DBG_CHK_FULL_REDS_HISTORY(rq);
rq->out_of_work_count = 0;
- (void) ERTS_RUNQ_FLGS_MASK_SET(rq, ERTS_RUNQ_FLGS_MIGRATION_INFO, flags);
+ (void) ERTS_RUNQ_FLGS_READ_BSET(rq, ERTS_RUNQ_FLGS_MIGRATION_INFO, flags);
rq->max_len = rq->len;
for (pix = 0; pix < ERTS_NO_PRIO_LEVELS; pix++) {
@@ -4681,6 +4370,7 @@ init_aux_work_data(ErtsAuxWorkData *awdp, ErtsSchedulerData *esdp, char *dawwp)
awdp->async_ready.queue = NULL;
#endif
#ifdef ERTS_SMP
+ awdp->delayed_wakeup.next = ERTS_DELAYED_WAKEUP_INFINITY;
if (!dawwp) {
awdp->delayed_wakeup.job = NULL;
awdp->delayed_wakeup.sched2jix = NULL;
@@ -4875,6 +4565,9 @@ erts_init_scheduling(int no_schedulers, int no_schedulers_online)
#ifdef ERTS_SMP
daww_ptr += daww_sz;
#endif
+
+ esdp->reductions = 0;
+
init_sched_wall_time(&esdp->sched_wall_time);
}
@@ -4960,6 +4653,11 @@ erts_init_scheduling(int no_schedulers, int no_schedulers_online)
erts_smp_atomic32_init_relb(&erts_halt_progress, -1);
erts_halt_code = 0;
+
+#if !defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK)
+ erts_lc_set_thread_name("scheduler 1");
+#endif
+
}
ErtsRunQueue *
@@ -5637,8 +5335,7 @@ erts_block_multi_scheduling(Process *p, ErtsProcLocks plocks, int on, int all)
else if (on) { /* ------ BLOCK ------ */
if (schdlr_sspnd.msb.procs) {
plp = proclist_create(p);
- plp->next = schdlr_sspnd.msb.procs;
- schdlr_sspnd.msb.procs = plp;
+ erts_proclist_store_last(&schdlr_sspnd.msb.procs, plp);
p->flags |= F_HAVE_BLCKD_MSCHED;
ASSERT(erts_smp_atomic32_read_nob(&schdlr_sspnd.active) == 1);
ASSERT(p->scheduler_data->no == 1);
@@ -5723,8 +5420,7 @@ erts_block_multi_scheduling(Process *p, ErtsProcLocks plocks, int on, int all)
~ERTS_SCHDLR_SSPND_CHNG_WAITER);
}
plp = proclist_create(p);
- plp->next = schdlr_sspnd.msb.procs;
- schdlr_sspnd.msb.procs = plp;
+ erts_proclist_store_last(&schdlr_sspnd.msb.procs, plp);
ASSERT(p->scheduler_data);
}
}
@@ -5735,20 +5431,16 @@ erts_block_multi_scheduling(Process *p, ErtsProcLocks plocks, int on, int all)
}
else { /* ------ UNBLOCK ------ */
if (p->flags & F_HAVE_BLCKD_MSCHED) {
- ErtsProcList **plpp = &schdlr_sspnd.msb.procs;
- plp = schdlr_sspnd.msb.procs;
+ ErtsProcList *plp = erts_proclist_peek_first(schdlr_sspnd.msb.procs);
while (plp) {
- if (!proclist_same(plp, p)){
- plpp = &plp->next;
- plp = plp->next;
- }
- else {
- *plpp = plp->next;
- proclist_destroy(plp);
+ ErtsProcList *tmp_plp = plp;
+ plp = erts_proclist_peek_next(schdlr_sspnd.msb.procs, plp);
+ if (erts_proclist_same(tmp_plp, p)) {
+ erts_proclist_remove(&schdlr_sspnd.msb.procs, tmp_plp);
+ proclist_destroy(tmp_plp);
if (!all)
break;
- plp = *plpp;
}
}
}
@@ -5817,23 +5509,25 @@ erts_multi_scheduling_blockers(Process *p)
Eterm res = NIL;
erts_smp_mtx_lock(&schdlr_sspnd.mtx);
- if (schdlr_sspnd.msb.procs) {
+ if (!erts_proclist_is_empty(schdlr_sspnd.msb.procs)) {
Eterm *hp, *hp_end;
ErtsProcList *plp1, *plp2;
- Uint max_size;
- ASSERT(schdlr_sspnd.msb.procs);
- for (max_size = 0, plp1 = schdlr_sspnd.msb.procs;
+ Uint max_size = 0;
+
+ for (plp1 = erts_proclist_peek_first(schdlr_sspnd.msb.procs);
plp1;
- plp1 = plp1->next) {
+ plp1 = erts_proclist_peek_next(schdlr_sspnd.msb.procs, plp1)) {
max_size += 2;
}
ASSERT(max_size);
hp = HAlloc(p, max_size);
hp_end = hp + max_size;
- for (plp1 = schdlr_sspnd.msb.procs; plp1; plp1 = plp1->next) {
- for (plp2 = schdlr_sspnd.msb.procs;
+ for (plp1 = erts_proclist_peek_first(schdlr_sspnd.msb.procs);
+ plp1;
+ plp1 = erts_proclist_peek_next(schdlr_sspnd.msb.procs, plp1)) {
+ for (plp2 = erts_proclist_peek_first(schdlr_sspnd.msb.procs);
plp2->pid != plp1->pid;
- plp2 = plp2->next);
+ plp2 = erts_proclist_peek_next(schdlr_sspnd.msb.procs, plp2));
if (plp2 == plp1) {
res = CONS(hp, plp1->pid, res);
hp += 2;
@@ -6085,7 +5779,7 @@ handle_pend_sync_suspend(Process *suspendee,
ASSERT(is_nil(suspender->suspendee));
if (suspendee_alive) {
erts_suspend(suspendee, suspendee_locks, NULL);
- suspender->suspendee = suspendee->id;
+ suspender->suspendee = suspendee->common.id;
}
/* suspender is suspended waiting for suspendee to suspend;
resume suspender */
@@ -6106,7 +5800,7 @@ pid2proc_not_running(Process *c_p, ErtsProcLocks c_p_locks,
ERTS_SMP_LC_ASSERT(c_p_locks & ERTS_PROC_LOCK_MAIN);
ERTS_SMP_LC_ASSERT(pid_locks & (ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS));
- if (c_p->id == pid)
+ if (c_p->common.id == pid)
return erts_pid2proc(c_p, c_p_locks, pid, pid_locks);
if (c_p_locks & ERTS_PROC_LOCK_STATUS)
@@ -6158,7 +5852,7 @@ pid2proc_not_running(Process *c_p, ErtsProcLocks c_p_locks,
*/
if (!c_p->pending_suspenders) {
/* Mark rp pending for suspend by c_p */
- add_pend_suspend(rp, c_p->id, handle_pend_sync_suspend);
+ add_pend_suspend(rp, c_p->common.id, handle_pend_sync_suspend);
ASSERT(is_nil(c_p->suspendee));
/* Suspend c_p; when rp is suspended c_p will be resumed. */
@@ -6264,20 +5958,20 @@ handle_pend_bif_sync_suspend(Process *suspendee,
ASSERT(is_nil(suspender->suspendee));
if (!suspendee_alive)
erts_delete_suspend_monitor(&suspender->suspend_monitors,
- suspendee->id);
+ suspendee->common.id);
else {
#ifdef DEBUG
int res;
#endif
ErtsSuspendMonitor *smon;
smon = erts_lookup_suspend_monitor(suspender->suspend_monitors,
- suspendee->id);
+ suspendee->common.id);
#ifdef DEBUG
res =
#endif
do_bif_suspend_process(suspendee, smon, suspendee);
ASSERT(!smon || res != 0);
- suspender->suspendee = suspendee->id;
+ suspender->suspendee = suspendee->common.id;
}
/* suspender is suspended waiting for suspendee to suspend;
resume suspender */
@@ -6306,14 +6000,14 @@ handle_pend_bif_async_suspend(Process *suspendee,
ASSERT(is_nil(suspender->suspendee));
if (!suspendee_alive)
erts_delete_suspend_monitor(&suspender->suspend_monitors,
- suspendee->id);
+ suspendee->common.id);
else {
#ifdef DEBUG
int res;
#endif
ErtsSuspendMonitor *smon;
smon = erts_lookup_suspend_monitor(suspender->suspend_monitors,
- suspendee->id);
+ suspendee->common.id);
#ifdef DEBUG
res =
#endif
@@ -6358,7 +6052,7 @@ suspend_process_2(BIF_ALIST_2)
int unless_suspending = 0;
- if (BIF_P->id == BIF_ARG_1)
+ if (BIF_P->common.id == BIF_ARG_1)
goto badarg; /* We are not allowed to suspend ourselves */
if (is_not_nil(BIF_ARG_2)) {
@@ -6454,7 +6148,7 @@ suspend_process_2(BIF_ALIST_2)
if (!do_bif_suspend_process(BIF_P, smon, suspendee))
add_pend_suspend(suspendee,
- BIF_P->id,
+ BIF_P->common.id,
handle_pend_bif_async_suspend);
res = am_true;
@@ -6517,7 +6211,7 @@ suspend_process_2(BIF_ALIST_2)
else {
/* Mark suspendee pending for suspend by BIF_P */
add_pend_suspend(suspendee,
- BIF_P->id,
+ BIF_P->common.id,
handle_pend_bif_sync_suspend);
ASSERT(is_nil(BIF_P->suspendee));
@@ -6591,7 +6285,7 @@ resume_process_1(BIF_ALIST_1)
Process *suspendee;
int is_active;
- if (BIF_P->id == BIF_ARG_1)
+ if (BIF_P->common.id == BIF_ARG_1)
BIF_ERROR(BIF_P, BADARG);
erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_LINK);
@@ -6716,7 +6410,8 @@ erts_process_status(Process *c_p, ErtsProcLocks c_p_locks,
for (i = 0; i < erts_no_schedulers; i++) {
esdp = ERTS_SCHEDULER_IX(i);
erts_smp_runq_lock(esdp->run_queue);
- if (esdp->free_process && esdp->free_process->id == rpid) {
+ if (esdp->free_process
+ && esdp->free_process->common.id == rpid) {
res = am_free;
erts_smp_runq_unlock(esdp->run_queue);
break;
@@ -6737,27 +6432,31 @@ erts_process_status(Process *c_p, ErtsProcLocks c_p_locks,
void
erts_suspend(Process* c_p, ErtsProcLocks c_p_locks, Port *busy_port)
{
-#ifdef DEBUG
- int res;
-#endif
+ int suspend;
+
ASSERT(c_p == erts_get_current_process());
ERTS_SMP_LC_ASSERT(c_p_locks == erts_proc_lc_my_proc_locks(c_p));
if (!(c_p_locks & ERTS_PROC_LOCK_STATUS))
erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_STATUS);
+ if (busy_port)
+ suspend = erts_save_suspend_process_on_port(busy_port, c_p);
+ else
+ suspend = 1;
+
+ if (suspend) {
#ifdef DEBUG
- res =
+ int res =
#endif
- suspend_process(c_p, c_p);
-
- ASSERT(res);
-
- if (busy_port)
- erts_wake_process_later(busy_port, c_p);
+ suspend_process(c_p, c_p);
+ ASSERT(res);
+ }
if (!(c_p_locks & ERTS_PROC_LOCK_STATUS))
erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_STATUS);
+ if (suspend && busy_port && erts_system_monitor_flags.busy_port)
+ monitor_generic(c_p, am_busy_port, busy_port->common.id);
}
void
@@ -6772,16 +6471,19 @@ erts_resume(Process* process, ErtsProcLocks process_locks)
}
int
-erts_resume_processes(ErtsProcList *plp)
+erts_resume_processes(ErtsProcList *list)
{
+ /* 'list' is expected to have been fetched (i.e. not a ring anymore) */
int nresumed = 0;
+ ErtsProcList *plp = list;
+
while (plp) {
Process *proc;
ErtsProcList *fplp;
ASSERT(is_internal_pid(plp->pid));
proc = erts_pid2proc(NULL, 0, plp->pid, ERTS_PROC_LOCK_STATUS);
if (proc) {
- if (proclist_same(plp, proc)) {
+ if (erts_proclist_same(plp, proc)) {
resume_process(proc);
nresumed++;
}
@@ -6934,9 +6636,8 @@ Process *schedule(Process *p, int calls)
state = erts_smp_atomic32_read_acqb(&p->state);
if (IS_TRACED(p)) {
- if (IS_TRACED_FL(p, F_TRACE_CALLS) && !(state & ERTS_PSFLG_FREE)) {
+ if (IS_TRACED_FL(p, F_TRACE_CALLS) && !(state & ERTS_PSFLG_FREE))
erts_schedule_time_break(p, ERTS_BP_CALL_TIME_SCHEDULE_OUT);
- }
if (state & (ERTS_PSFLG_FREE|ERTS_PSFLG_EXITING)) {
if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED_EXIT))
trace_sched(p, ((state & ERTS_PSFLG_FREE)
@@ -6949,7 +6650,7 @@ Process *schedule(Process *p, int calls)
else if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED_PROCS))
trace_virtual_sched(p, am_out);
}
- }
+ }
#ifdef ERTS_SMP
if (state & ERTS_PSFLG_PENDING_EXIT)
@@ -6960,6 +6661,8 @@ Process *schedule(Process *p, int calls)
| ERTS_PROC_LOCK_STATUS));
#endif
+ esdp->reductions += reds;
+
schedule_out_process(rq, state, p); /* Returns with rq locked! */
ERTS_PROC_REDUCTIONS_EXECUTED(rq,
@@ -7011,9 +6714,8 @@ Process *schedule(Process *p, int calls)
#ifdef ERTS_SMP
{
ErtsProcList *pnd_xtrs = rq->procs.pending_exiters;
- rq->procs.pending_exiters = NULL;
-
- if (pnd_xtrs) {
+ if (erts_proclist_fetch(&pnd_xtrs, NULL)) {
+ rq->procs.pending_exiters = NULL;
erts_smp_runq_unlock(rq);
handle_pending_exiters(pnd_xtrs);
erts_smp_runq_lock(rq);
@@ -7309,7 +7011,7 @@ Process *schedule(Process *p, int calls)
erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS);
#ifdef ERTS_SMP
- if (is_not_nil(p->tracer_proc))
+ if (is_not_nil(ERTS_TRACER_PROC(p)))
erts_check_my_tracer_proc(p);
#endif
@@ -7512,70 +7214,6 @@ erts_get_exact_total_reductions(Process *c_p, Uint *redsp, Uint *diffp)
erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN);
}
-/*
- * erts_test_next_pid() is only used for testing.
- */
-Sint
-erts_test_next_pid(int set, Uint next)
-{
- Uint64 lpd;
- Sint res;
- Eterm pid_data;
- int first_pix = -1;
-
- erts_smp_rwmtx_rwlock(&erts_proc_tab_rwmtx);
-
- if (!set)
- lpd = last_pid_data_read_nob();
- else {
-
- lpd = (Uint64) next;
- pid_data = (Eterm) (lpd & ERTS_PID_DATA_MASK__);
- if (ERTS_INVALID_PID == make_internal_pid(pid_data)) {
- lpd += erts_proc.max;
- ASSERT(erts_pid_data2ix(pid_data)
- == erts_pid_data2ix(lpd & ERTS_PID_DATA_MASK__));
- }
- last_pid_data_set_relb(lpd);
- }
-
- while (1) {
- int pix;
- lpd++;
- pix = (int) (lpd % erts_proc.max);
- if (first_pix < 0)
- first_pix = pix;
- else if (pix == first_pix) {
- res = -1;
- break;
- }
- if (ERTS_AINT_NULL == erts_smp_atomic_read_nob(&erts_proc.tab[pix])) {
- pid_data = (Eterm) (lpd & ERTS_PID_DATA_MASK__);
- if (ERTS_INVALID_PID == make_internal_pid(pid_data)) {
- lpd += erts_proc.max;
- ASSERT(erts_pid_data2ix(pid_data)
- == erts_pid_data2ix(lpd & ERTS_PID_DATA_MASK__));
- }
- res = lpd & ERTS_PID_DATA_MASK__;
- break;
- }
- }
-
- erts_smp_rwmtx_rwunlock(&erts_proc_tab_rwmtx);
-
- return res;
-
-}
-
-Uint erts_process_count(void)
-{
- erts_aint32_t res = erts_smp_atomic32_read_nob(&process_count);
- if (res > erts_proc.max)
- return erts_proc.max;
- ASSERT(res >= 0);
- return (Uint) res;
-}
-
void
erts_free_proc(Process *p)
{
@@ -7585,132 +7223,66 @@ erts_free_proc(Process *p)
erts_free(ERTS_ALC_T_PROC, (void *) p);
}
+typedef struct {
+ Process *proc;
+ erts_aint32_t state;
+ ErtsRunQueue *run_queue;
+} ErtsEarlyProcInit;
+
+static void early_init_process_struct(void *varg, Eterm data)
+{
+ ErtsEarlyProcInit *arg = (ErtsEarlyProcInit *) varg;
+ Process *proc = arg->proc;
+
+ proc->common.id = make_internal_pid(data);
+ erts_smp_atomic32_init_relb(&proc->state, arg->state);
+
+#ifdef ERTS_SMP
+ RUNQ_SET_RQ(&proc->run_queue, arg->run_queue);
+
+ erts_proc_lock_init(proc); /* All locks locked */
+#endif
+
+}
+
/*
** Allocate process and find out where to place next process.
*/
static Process*
alloc_process(ErtsRunQueue *rq, erts_aint32_t state)
{
- int pix;
- Process* p;
- Uint64 lpd, exp_lpd;
- Eterm pid_data;
- erts_aint32_t proc_count;
-#ifdef DEBUG
- Eterm pid;
-#endif
-
- erts_smp_rwmtx_rlock(&erts_proc_tab_rwmtx);
-
- proc_count = erts_smp_atomic32_inc_read_acqb(&process_count);
- if (proc_count > erts_proc.max) {
- while (1) {
- erts_aint32_t act_proc_count;
-
- act_proc_count = erts_smp_atomic32_cmpxchg_relb(&process_count,
- proc_count-1,
- proc_count);
- if (act_proc_count == proc_count)
- goto system_limit;
- proc_count = act_proc_count;
- if (proc_count <= erts_proc.max)
- break;
- }
- }
+ ErtsEarlyProcInit init_arg;
+ Process *p;
- p = (Process*) erts_alloc_fnf(ERTS_ALC_T_PROC, sizeof(Process));
+ p = erts_alloc_fnf(ERTS_ALC_T_PROC, sizeof(Process));
if (!p)
- goto enomem;
-
- p->approx_started = erts_get_approx_time();
- p->started_interval = get_proc_interval();
-
- lpd = last_pid_data_read_acqb();
-
- /* Reserve slot */
- while (1) {
- lpd++;
- pix = erts_pid_data2ix((Eterm) (lpd & ERTS_PID_DATA_MASK__));
- if (erts_smp_atomic_read_nob(&erts_proc.tab[pix]) == ERTS_AINT_NULL) {
- erts_aint_t val;
- val = erts_smp_atomic_cmpxchg_relb(&erts_proc.tab[pix],
- ((erts_aint_t)
- ERTS_PROC_LOCK_BUSY),
- ERTS_AINT_NULL);
-
- if (ERTS_AINT_NULL == val)
- break;
- }
- }
-
- pid_data = (Eterm) lpd & ERTS_PID_DATA_MASK__;
+ return NULL;
- p->id = make_internal_pid(pid_data);
- if (p->id == ERTS_INVALID_PID) {
- /* Do not use the invalid pid; change serial */
- lpd += erts_proc.max;
- ASSERT(pix == erts_pid_data2ix((Eterm) (lpd & ERTS_PID_DATA_MASK__)));
- pid_data = (Eterm) lpd & ERTS_PID_DATA_MASK__;
- p->id = make_internal_pid(pid_data);
- ASSERT(p->id != ERTS_INVALID_PID);
- }
+ init_arg.proc = (Process *) p;
+ init_arg.run_queue = rq;
+ init_arg.state = state;
- exp_lpd = last_pid_data_read_nob();
+ ASSERT(((char *) p) == ((char *) &p->common));
- /* Move last pid data forward */
- while (1) {
- Uint64 act_lpd;
- if (last_pid_data_cmp(lpd, exp_lpd) < 0)
- break;
- act_lpd = last_pid_data_cmpxchg_relb(lpd, exp_lpd);
- if (act_lpd == exp_lpd)
- break;
- exp_lpd = act_lpd;
+ if (!erts_ptab_new_element(&erts_proc,
+ &p->common,
+ (void *) &init_arg,
+ early_init_process_struct)) {
+ erts_free(ERTS_ALC_T_PROC, p);
+ return NULL;
}
-#ifdef ERTS_SMP
- RUNQ_SET_RQ(&p->run_queue, rq);
-#endif
-
- erts_smp_atomic32_init_relb(&p->state, state);
-
-#ifdef DEBUG
- pid = p->id;
-#endif
-
-#ifdef ERTS_SMP
- erts_proc_lock_init(p); /* All locks locked */
-#endif
-
- /* Move into slot reserved */
-#ifdef DEBUG
- ASSERT(ERTS_PROC_LOCK_BUSY
- == (Process *) erts_smp_atomic_xchg_relb(&erts_proc.tab[pix],
- (erts_aint_t) p));
-#else
- erts_smp_atomic_set_relb(&erts_proc.tab[pix], (erts_aint_t) p);
-#endif
-
- ASSERT(internal_pid_serial(p->id) <= (erts_use_r9_pids_ports
- ? ERTS_MAX_PID_R9_SERIAL
- : ERTS_MAX_PID_SERIAL));
-
- erts_smp_rwmtx_runlock(&erts_proc_tab_rwmtx);
-
+ ASSERT(internal_pid_serial(p->common.id) <= ERTS_MAX_PID_SERIAL);
+
+ p->approx_started = erts_get_approx_time();
p->rcount = 0;
- ASSERT(p == (Process *)
- erts_smp_atomic_read_nob(
- &erts_proc.tab[internal_pid_index(pid)]));
-
- return p;
-
-enomem:
-system_limit:
- erts_smp_rwmtx_runlock(&erts_proc_tab_rwmtx);
- return NULL;
+ ASSERT(p == (Process *) (erts_ptab_pix2intptr_nob(
+ &erts_proc,
+ internal_pid_index(p->common.id))));
+ return p;
}
Eterm
@@ -7857,21 +7429,21 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
p->reds = 0;
#ifdef ERTS_SMP
- p->u.alive.ptimer = NULL;
+ p->common.u.alive.ptimer = NULL;
#else
- sys_memset(&p->u.alive.tm, 0, sizeof(ErlTimer));
+ sys_memset(&p->common.u.alive.tm, 0, sizeof(ErlTimer));
#endif
- p->reg = NULL;
- p->nlinks = NULL;
- p->monitors = NULL;
+ p->common.u.alive.reg = NULL;
+ ERTS_P_LINKS(p) = NULL;
+ ERTS_P_MONITORS(p) = NULL;
p->nodes_monitors = NULL;
p->suspend_monitors = NULL;
ASSERT(is_pid(parent->group_leader));
if (parent->group_leader == ERTS_INVALID_PID)
- p->group_leader = p->id;
+ p->group_leader = p->common.id;
else {
/* Needs to be done after the heap has been set up */
p->group_leader =
@@ -7880,18 +7452,18 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
: STORE_NC(&p->htop, &p->off_heap, parent->group_leader);
}
- erts_get_default_tracing(&p->trace_flags, &p->tracer_proc);
+ erts_get_default_tracing(&ERTS_TRACE_FLAGS(p), &ERTS_TRACER_PROC(p));
p->msg.first = NULL;
p->msg.last = &p->msg.first;
p->msg.save = &p->msg.first;
p->msg.len = 0;
#ifdef ERTS_SMP
- p->u.alive.msg_inq.first = NULL;
- p->u.alive.msg_inq.last = &p->u.alive.msg_inq.first;
- p->u.alive.msg_inq.len = 0;
+ p->msg_inq.first = NULL;
+ p->msg_inq.last = &p->msg_inq.first;
+ p->msg_inq.len = 0;
#endif
- p->bif_timers = NULL;
+ p->u.bif_timers = NULL;
p->mbuf = NULL;
p->mbuf_sz = 0;
p->psd = NULL;
@@ -7903,7 +7475,9 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
DT_UTAG(p) = NIL;
DT_UTAG_FLAGS(p) = 0;
#endif
- p->parent = parent->id == ERTS_INVALID_PID ? NIL : parent->id;
+ p->parent = (parent->common.id == ERTS_INVALID_PID
+ ? NIL
+ : parent->common.id);
INIT_HOLE_CHECK(p);
#ifdef DEBUG
@@ -7911,18 +7485,19 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
#endif
if (IS_TRACED(parent)) {
- if (parent->trace_flags & F_TRACE_SOS) {
- p->trace_flags |= (parent->trace_flags & TRACEE_FLAGS);
- p->tracer_proc = parent->tracer_proc;
+ if (ERTS_TRACE_FLAGS(parent) & F_TRACE_SOS) {
+ ERTS_TRACE_FLAGS(p) |= (ERTS_TRACE_FLAGS(parent) & TRACEE_FLAGS);
+ ERTS_TRACER_PROC(p) = ERTS_TRACER_PROC(parent);
}
if (ARE_TRACE_FLAGS_ON(parent, F_TRACE_PROCS)) {
- trace_proc_spawn(parent, p->id, mod, func, args);
+ trace_proc_spawn(parent, p->common.id, mod, func, args);
}
- if (parent->trace_flags & F_TRACE_SOS1) { /* Overrides TRACE_CHILDREN */
- p->trace_flags |= (parent->trace_flags & TRACEE_FLAGS);
- p->tracer_proc = parent->tracer_proc;
- p->trace_flags &= ~(F_TRACE_SOS1 | F_TRACE_SOS);
- parent->trace_flags &= ~(F_TRACE_SOS1 | F_TRACE_SOS);
+ if (ERTS_TRACE_FLAGS(parent) & F_TRACE_SOS1) {
+ /* Overrides TRACE_CHILDREN */
+ ERTS_TRACE_FLAGS(p) |= (ERTS_TRACE_FLAGS(parent) & TRACEE_FLAGS);
+ ERTS_TRACER_PROC(p) = ERTS_TRACER_PROC(parent);
+ ERTS_TRACE_FLAGS(p) &= ~(F_TRACE_SOS1 | F_TRACE_SOS);
+ ERTS_TRACE_FLAGS(parent) &= ~(F_TRACE_SOS1 | F_TRACE_SOS);
}
}
@@ -7935,27 +7510,27 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
int ret;
#endif
if (IS_TRACED_FL(parent, F_TRACE_PROCS)) {
- trace_proc(parent, parent, am_link, p->id);
+ trace_proc(parent, parent, am_link, p->common.id);
}
#ifdef DEBUG
- ret = erts_add_link(&(parent->nlinks), LINK_PID, p->id);
+ ret = erts_add_link(&ERTS_P_LINKS(parent), LINK_PID, p->common.id);
ASSERT(ret == 0);
- ret = erts_add_link(&(p->nlinks), LINK_PID, parent->id);
+ ret = erts_add_link(&ERTS_P_LINKS(p), LINK_PID, parent->common.id);
ASSERT(ret == 0);
#else
- erts_add_link(&(parent->nlinks), LINK_PID, p->id);
- erts_add_link(&(p->nlinks), LINK_PID, parent->id);
+ erts_add_link(&ERTS_P_LINKS(parent), LINK_PID, p->common.id);
+ erts_add_link(&ERTS_P_LINKS(p), LINK_PID, parent->common.id);
#endif
if (IS_TRACED(parent)) {
- if (parent->trace_flags & (F_TRACE_SOL|F_TRACE_SOL1)) {
- p->trace_flags |= (parent->trace_flags & TRACEE_FLAGS);
- p->tracer_proc = parent->tracer_proc; /* maybe steal */
+ if (ERTS_TRACE_FLAGS(parent) & (F_TRACE_SOL|F_TRACE_SOL1)) {
+ ERTS_TRACE_FLAGS(p) |= (ERTS_TRACE_FLAGS(parent)&TRACEE_FLAGS);
+ ERTS_TRACER_PROC(p) = ERTS_TRACER_PROC(parent); /*maybe steal*/
- if (parent->trace_flags & F_TRACE_SOL1) { /* maybe override */
- p ->trace_flags &= ~(F_TRACE_SOL1 | F_TRACE_SOL);
- parent->trace_flags &= ~(F_TRACE_SOL1 | F_TRACE_SOL);
+ if (ERTS_TRACE_FLAGS(parent) & F_TRACE_SOL1) {/*maybe override*/
+ ERTS_TRACE_FLAGS(p) &= ~(F_TRACE_SOL1 | F_TRACE_SOL);
+ ERTS_TRACE_FLAGS(parent) &= ~(F_TRACE_SOL1 | F_TRACE_SOL);
}
}
}
@@ -7968,8 +7543,8 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
Eterm mref;
mref = erts_make_ref(parent);
- erts_add_monitor(&(parent->monitors), MON_ORIGIN, mref, p->id, NIL);
- erts_add_monitor(&(p->monitors), MON_TARGET, mref, parent->id, NIL);
+ erts_add_monitor(&ERTS_P_MONITORS(parent), MON_ORIGIN, mref, p->common.id, NIL);
+ erts_add_monitor(&ERTS_P_MONITORS(p), MON_TARGET, mref, parent->common.id, NIL);
so->mref = mref;
}
@@ -7977,8 +7552,8 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
p->scheduler_data = NULL;
p->suspendee = NIL;
p->pending_suspenders = NULL;
- p->u.alive.pending_exit.reason = THE_NON_VALUE;
- p->u.alive.pending_exit.bp = NULL;
+ p->pending_exit.reason = THE_NON_VALUE;
+ p->pending_exit.bp = NULL;
#endif
#if !defined(NO_FPE_SIGNALS) || defined(HIPE)
@@ -7987,7 +7562,7 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL);
- res = p->id;
+ res = p->common.id;
/*
* Schedule process for execution.
@@ -7995,7 +7570,7 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
schedule_process(p, state, 0);
- VERBOSE(DEBUG_PROCESSES, ("Created a new process: %T\n",p->id));
+ VERBOSE(DEBUG_PROCESSES, ("Created a new process: %T\n",p->common.id));
#ifdef USE_VM_PROBES
if (DTRACE_ENABLED(process_spawn)) {
@@ -8030,10 +7605,10 @@ void erts_init_empty_process(Process *p)
p->min_heap_size = 0;
p->min_vheap_size = 0;
p->rcount = 0;
- p->id = ERTS_INVALID_PID;
+ p->common.id = ERTS_INVALID_PID;
p->reds = 0;
- p->tracer_proc = NIL;
- p->trace_flags = F_INITIAL_TRACE_FLAGS;
+ ERTS_TRACER_PROC(p) = NIL;
+ ERTS_TRACE_FLAGS(p) = F_INITIAL_TRACE_FLAGS;
p->group_leader = ERTS_INVALID_PID;
p->flags = 0;
p->fvalue = NIL;
@@ -8046,14 +7621,14 @@ void erts_init_empty_process(Process *p)
p->bin_old_vheap = 0;
p->bin_vheap_mature = 0;
#ifdef ERTS_SMP
- p->u.alive.ptimer = NULL;
+ p->common.u.alive.ptimer = NULL;
#else
- memset(&(p->u.alive.tm), 0, sizeof(ErlTimer));
+ memset(&(p->common.u.alive.tm), 0, sizeof(ErlTimer));
#endif
p->next = NULL;
p->off_heap.first = NULL;
p->off_heap.overhead = 0;
- p->reg = NULL;
+ p->common.u.alive.reg = NULL;
p->heap_sz = 0;
p->high_water = NULL;
p->old_hend = NULL;
@@ -8062,15 +7637,15 @@ void erts_init_empty_process(Process *p)
p->mbuf = NULL;
p->mbuf_sz = 0;
p->psd = NULL;
- p->monitors = NULL;
- p->nlinks = NULL; /* List of links */
+ ERTS_P_MONITORS(p) = NULL;
+ ERTS_P_LINKS(p) = NULL; /* List of links */
p->nodes_monitors = NULL;
p->suspend_monitors = NULL;
p->msg.first = NULL;
p->msg.last = &p->msg.first;
p->msg.save = &p->msg.first;
p->msg.len = 0;
- p->bif_timers = NULL;
+ p->u.bif_timers = NULL;
p->dictionary = NULL;
p->seq_trace_clock = 0;
p->seq_trace_lastcnt = 0;
@@ -8098,7 +7673,7 @@ void erts_init_empty_process(Process *p)
p->parent = NIL;
p->approx_started = 0;
- p->started_interval = 0;
+ p->common.u.alive.started_interval = 0;
#ifdef HIPE
hipe_init_process(&p->hipe);
@@ -8116,13 +7691,13 @@ void erts_init_empty_process(Process *p)
#ifdef ERTS_SMP
p->scheduler_data = NULL;
- p->u.alive.msg_inq.first = NULL;
- p->u.alive.msg_inq.last = &p->u.alive.msg_inq.first;
- p->u.alive.msg_inq.len = 0;
+ p->msg_inq.first = NULL;
+ p->msg_inq.last = &p->msg_inq.first;
+ p->msg_inq.len = 0;
p->suspendee = NIL;
p->pending_suspenders = NULL;
- p->u.alive.pending_exit.reason = THE_NON_VALUE;
- p->u.alive.pending_exit.bp = NULL;
+ p->pending_exit.reason = THE_NON_VALUE;
+ p->pending_exit.bp = NULL;
erts_proc_lock_init(p);
erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL);
RUNQ_SET_RQ(&p->run_queue, ERTS_RUNQ_IX(0));
@@ -8144,25 +7719,25 @@ erts_debug_verify_clean_empty_process(Process* p)
ASSERT(p->stop == NULL);
ASSERT(p->hend == NULL);
ASSERT(p->heap == NULL);
- ASSERT(p->id == ERTS_INVALID_PID);
- ASSERT(p->tracer_proc == NIL);
- ASSERT(p->trace_flags == F_INITIAL_TRACE_FLAGS);
+ ASSERT(p->common.id == ERTS_INVALID_PID);
+ ASSERT(ERTS_TRACER_PROC(p) == NIL);
+ ASSERT(ERTS_TRACE_FLAGS(p) == F_INITIAL_TRACE_FLAGS);
ASSERT(p->group_leader == ERTS_INVALID_PID);
ASSERT(p->next == NULL);
- ASSERT(p->reg == NULL);
+ ASSERT(p->common.u.alive.reg == NULL);
ASSERT(p->heap_sz == 0);
ASSERT(p->high_water == NULL);
ASSERT(p->old_hend == NULL);
ASSERT(p->old_htop == NULL);
ASSERT(p->old_heap == NULL);
- ASSERT(p->monitors == NULL);
- ASSERT(p->nlinks == NULL);
+ ASSERT(ERTS_P_MONITORS(p) == NULL);
+ ASSERT(ERTS_P_LINKS(p) == NULL);
ASSERT(p->nodes_monitors == NULL);
ASSERT(p->suspend_monitors == NULL);
ASSERT(p->msg.first == NULL);
ASSERT(p->msg.len == 0);
- ASSERT(p->bif_timers == NULL);
+ ASSERT(p->u.bif_timers == NULL);
ASSERT(p->dictionary == NULL);
ASSERT(p->catches == 0);
ASSERT(p->cp == NULL);
@@ -8172,12 +7747,12 @@ erts_debug_verify_clean_empty_process(Process* p)
ASSERT(p->parent == NIL);
#ifdef ERTS_SMP
- ASSERT(p->u.alive.msg_inq.first == NULL);
- ASSERT(p->u.alive.msg_inq.len == 0);
+ ASSERT(p->msg_inq.first == NULL);
+ ASSERT(p->msg_inq.len == 0);
ASSERT(p->suspendee == NIL);
ASSERT(p->pending_suspenders == NULL);
- ASSERT(p->u.alive.pending_exit.reason == THE_NON_VALUE);
- ASSERT(p->u.alive.pending_exit.bp == NULL);
+ ASSERT(p->pending_exit.reason == THE_NON_VALUE);
+ ASSERT(p->pending_exit.bp == NULL);
#endif
/* Thing that erts_cleanup_empty_process() cleans up */
@@ -8219,7 +7794,7 @@ delete_process(Process* p)
{
ErlMessage* mp;
- VERBOSE(DEBUG_PROCESSES, ("Removing process: %T\n",p->id));
+ VERBOSE(DEBUG_PROCESSES, ("Removing process: %T\n",p->common.id));
/* Cleanup psd */
@@ -8293,8 +7868,6 @@ delete_process(Process* p)
mp = next_mp;
}
- ASSERT(!p->monitors);
- ASSERT(!p->nlinks);
ASSERT(!p->nodes_monitors);
ASSERT(!p->suspend_monitors);
@@ -8358,7 +7931,7 @@ void
erts_handle_pending_exit(Process *c_p, ErtsProcLocks locks)
{
ErtsProcLocks xlocks;
- ASSERT(is_value(c_p->u.alive.pending_exit.reason));
+ ASSERT(is_value(c_p->pending_exit.reason));
ERTS_SMP_LC_ASSERT(erts_proc_lc_my_proc_locks(c_p) == locks);
ERTS_SMP_LC_ASSERT(locks & ERTS_PROC_LOCK_MAIN);
ERTS_SMP_LC_ASSERT(!((ERTS_PSFLG_EXITING|ERTS_PSFLG_FREE)
@@ -8377,10 +7950,10 @@ erts_handle_pending_exit(Process *c_p, ErtsProcLocks locks)
set_proc_exiting(c_p,
erts_smp_atomic32_read_acqb(&c_p->state),
- c_p->u.alive.pending_exit.reason,
- c_p->u.alive.pending_exit.bp);
- c_p->u.alive.pending_exit.reason = THE_NON_VALUE;
- c_p->u.alive.pending_exit.bp = NULL;
+ c_p->pending_exit.reason,
+ c_p->pending_exit.bp);
+ c_p->pending_exit.reason = THE_NON_VALUE;
+ c_p->pending_exit.bp = NULL;
if (xlocks)
erts_smp_proc_unlock(c_p, xlocks);
@@ -8389,12 +7962,14 @@ erts_handle_pending_exit(Process *c_p, ErtsProcLocks locks)
static void
handle_pending_exiters(ErtsProcList *pnd_xtrs)
{
+ /* 'list' is expected to have been fetched (i.e. not a ring anymore) */
ErtsProcList *plp = pnd_xtrs;
- ErtsProcList *free_plp;
+
while (plp) {
+ ErtsProcList *free_plp;
Process *p = erts_pid2proc(NULL, 0, plp->pid, ERTS_PROC_LOCKS_ALL);
if (p) {
- if (proclist_same(plp, p)) {
+ if (erts_proclist_same(plp, p)) {
erts_aint32_t state = erts_smp_atomic32_read_acqb(&p->state);
if (!(state & ERTS_PSFLG_RUNNING)) {
ASSERT(state & ERTS_PSFLG_PENDING_EXIT);
@@ -8423,8 +7998,7 @@ save_pending_exiter(Process *p)
erts_smp_runq_lock(rq);
- plp->next = rq->procs.pending_exiters;
- rq->procs.pending_exiters = plp;
+ erts_proclist_store_last(&rq->procs.pending_exiters, plp);
erts_smp_runq_unlock(rq);
wake_scheduler(rq, 1);
@@ -8471,7 +8045,7 @@ send_exit_message(Process *to, ErtsProcLocks *to_locksp,
hp = bp->mem;
mess = copy_struct(exit_term, term_size, &hp, &bp->off_heap);
/* the trace token must in this case be updated by the caller */
- seq_trace_output(token, mess, SEQ_TRACE_SEND, to->id, NULL);
+ seq_trace_output(token, mess, SEQ_TRACE_SEND, to->common.id, NULL);
temp_token = copy_struct(token, sz_token, &hp, &bp->off_heap);
erts_queue_message(to, to_locksp, bp, mess, temp_token
#ifdef USE_VM_PROBES
@@ -8601,7 +8175,7 @@ send_exit_signal(Process *c_p, /* current process if and only
else if (reason != am_normal || (flags & ERTS_XSIG_FLG_NO_IGN_NORMAL)) {
#ifdef ERTS_SMP
if (!(state & (ERTS_PSFLG_EXITING|ERTS_PSFLG_PENDING_EXIT))) {
- ASSERT(!rp->u.alive.pending_exit.bp);
+ ASSERT(!rp->pending_exit.bp);
if (rp == c_p && (*rp_locks & ERTS_PROC_LOCK_MAIN)) {
/* Ensure that all locks on c_p are locked before
@@ -8651,7 +8225,7 @@ send_exit_signal(Process *c_p, /* current process if and only
set_pending_exit:
if (is_immed(rsn)) {
- rp->u.alive.pending_exit.reason = rsn;
+ rp->pending_exit.reason = rsn;
}
else {
Eterm *hp;
@@ -8659,11 +8233,11 @@ send_exit_signal(Process *c_p, /* current process if and only
ErlHeapFragment *bp = new_message_buffer(sz);
hp = &bp->mem[0];
- rp->u.alive.pending_exit.reason = copy_struct(rsn,
- sz,
- &hp,
- &bp->off_heap);
- rp->u.alive.pending_exit.bp = bp;
+ rp->pending_exit.reason = copy_struct(rsn,
+ sz,
+ &hp,
+ &bp->off_heap);
+ rp->pending_exit.bp = bp;
}
erts_smp_atomic32_read_bor_relb(&rp->state,
ERTS_PSFLG_PENDING_EXIT);
@@ -8762,7 +8336,7 @@ static void doit_exit_monitor(ErtsMonitor *mon, void *vpcontext)
if (!rp) {
goto done;
}
- rmon = erts_remove_monitor(&(rp->monitors),mon->ref);
+ rmon = erts_remove_monitor(&ERTS_P_MONITORS(rp), mon->ref);
erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_LINK);
if (rmon == NULL) {
goto done;
@@ -8797,7 +8371,7 @@ static void doit_exit_monitor(ErtsMonitor *mon, void *vpcontext)
ASSERT(mon->type == MON_TARGET);
ASSERT(is_pid(mon->pid) || is_internal_port(mon->pid));
if (is_internal_port(mon->pid)) {
- Port *prt = erts_id2port(mon->pid, NULL, 0);
+ Port *prt = erts_id2port(mon->pid);
if (prt == NULL) {
goto done;
}
@@ -8813,13 +8387,13 @@ static void doit_exit_monitor(ErtsMonitor *mon, void *vpcontext)
goto done;
}
UseTmpHeapNoproc(3);
- rmon = erts_remove_monitor(&(rp->monitors),mon->ref);
+ rmon = erts_remove_monitor(&ERTS_P_MONITORS(rp), mon->ref);
if (rmon) {
erts_destroy_monitor(rmon);
watched = (is_atom(mon->name)
? TUPLE2(lhp, mon->name,
erts_this_dist_entry->sysname)
- : pcontext->p->id);
+ : pcontext->p->common.id);
erts_queue_monitor_message(rp, &rp_locks, mon->ref, am_process,
watched, pcontext->reason);
}
@@ -8884,21 +8458,22 @@ static void doit_exit_link(ErtsLink *lnk, void *vpcontext)
switch(lnk->type) {
case LINK_PID:
if(is_internal_port(item)) {
- Port *prt = erts_id2port(item, NULL, 0);
- if (prt) {
- rlnk = erts_remove_link(&prt->nlinks, p->id);
- if (rlnk)
- erts_destroy_link(rlnk);
- erts_do_exit_port(prt, p->id, reason);
- erts_port_release(prt);
- }
+ Port *prt = erts_port_lookup(item, ERTS_PORT_SFLGS_INVALID_LOOKUP);
+ if (prt)
+ erts_port_exit(NULL,
+ (ERTS_PORT_SIG_FLG_FORCE_SCHED
+ | ERTS_PORT_SIG_FLG_BROKEN_LINK),
+ prt,
+ p->common.id,
+ reason,
+ NULL);
}
else if(is_external_port(item)) {
erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
erts_dsprintf(dsbufp,
"Erroneous link between %T and external port %T "
"found\n",
- p->id,
+ p->common.id,
item);
erts_send_error_to_logger_nogl(dsbufp);
ASSERT(0); /* It isn't possible to setup such a link... */
@@ -8908,14 +8483,14 @@ static void doit_exit_link(ErtsLink *lnk, void *vpcontext)
| ERTS_PROC_LOCKS_XSIG_SEND);
rp = erts_pid2proc(NULL, 0, item, rp_locks);
if (rp) {
- rlnk = erts_remove_link(&(rp->nlinks), p->id);
+ rlnk = erts_remove_link(&ERTS_P_LINKS(rp), p->common.id);
/* If rlnk == NULL, we got unlinked while exiting,
i.e., do nothing... */
if (rlnk) {
int xres;
erts_destroy_link(rlnk);
xres = send_exit_signal(NULL,
- p->id,
+ p->common.id,
rp,
&rp_locks,
reason,
@@ -8927,7 +8502,7 @@ static void doit_exit_link(ErtsLink *lnk, void *vpcontext)
if (xres >= 0 && IS_TRACED_FL(rp, F_TRACE_PROCS)) {
/* We didn't exit the process and it is traced */
if (IS_TRACED_FL(rp, F_TRACE_PROCS)) {
- trace_proc(p, rp, am_getting_unlinked, p->id);
+ trace_proc(p, rp, am_getting_unlinked, p->common.id);
}
}
}
@@ -8941,12 +8516,12 @@ static void doit_exit_link(ErtsLink *lnk, void *vpcontext)
ErtsDSigData dsd;
int code;
ErtsDistLinkData dld;
- erts_remove_dist_link(&dld, p->id, item, dep);
+ erts_remove_dist_link(&dld, p->common.id, item, dep);
erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN);
code = erts_dsig_prepare(&dsd, dep, p, ERTS_DSP_NO_LOCK, 0);
if (code == ERTS_DSIG_PREP_CONNECTED) {
- code = erts_dsig_send_exit_tt(&dsd, p->id, item, reason,
- SEQ_TRACE_TOKEN(p));
+ code = erts_dsig_send_exit_tt(&dsd, p->common.id, item,
+ reason, SEQ_TRACE_TOKEN(p));
ASSERT(code == ERTS_DSIG_SEND_OK);
}
erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN);
@@ -8961,7 +8536,7 @@ static void doit_exit_link(ErtsLink *lnk, void *vpcontext)
/* dist entries have node links in a separate structure to
avoid confusion */
erts_smp_de_links_lock(dep);
- rlnk = erts_remove_link(&(dep->node_links), p->id);
+ rlnk = erts_remove_link(&(dep->node_links), p->common.id);
erts_smp_de_links_unlock(dep);
if (rlnk)
erts_destroy_link(rlnk);
@@ -8989,15 +8564,6 @@ resume_suspend_monitor(ErtsSuspendMonitor *smon, void *vc_p)
erts_destroy_suspend_monitor(smon);
}
-#ifdef ERTS_SMP
-static void
-proc_dec_refc(void *vproc)
-{
- erts_smp_proc_dec_refc((Process *) vproc);
-}
-#endif
-
-
/* this function fishishes a process and propagates exit messages - called
by process_main when a process dies */
void
@@ -9035,10 +8601,10 @@ erts_do_exit_process(Process* p, Eterm reason)
state = set_proc_exiting_state(p, erts_smp_atomic32_read_nob(&p->state));
if (state & ERTS_PSFLG_PENDING_EXIT) {
/* Process exited before pending exit was received... */
- p->u.alive.pending_exit.reason = THE_NON_VALUE;
- if (p->u.alive.pending_exit.bp) {
- free_message_buffer(p->u.alive.pending_exit.bp);
- p->u.alive.pending_exit.bp = NULL;
+ p->pending_exit.reason = THE_NON_VALUE;
+ if (p->pending_exit.bp) {
+ free_message_buffer(p->pending_exit.bp);
+ p->pending_exit.bp = NULL;
}
}
@@ -9055,23 +8621,25 @@ erts_do_exit_process(Process* p, Eterm reason)
trace_proc(p, p, am_exit, reason);
}
- erts_trace_check_exiting(p->id);
+ erts_trace_check_exiting(p->common.id);
- ASSERT((p->trace_flags & F_INITIAL_TRACE_FLAGS) == F_INITIAL_TRACE_FLAGS);
+ ASSERT((ERTS_TRACE_FLAGS(p) & F_INITIAL_TRACE_FLAGS)
+ == F_INITIAL_TRACE_FLAGS);
cancel_timer(p); /* Always cancel timer just in case */
- /*
- * The timer of this process can *not* be used anymore. The field used
- * for the timer is now used for misc exiting data.
- */
- p->u.exit_data = NULL;
-
- if (p->bif_timers)
+ if (p->u.bif_timers)
erts_cancel_bif_timers(p, ERTS_PROC_LOCKS_ALL);
erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL_MINOR);
+ /*
+ * The p->u.bif_timers of this process can *not* be used anymore;
+ * will be overwritten by misc termination data.
+ */
+ p->u.terminate = NULL;
+
+
erts_continue_exit_process(p);
}
@@ -9143,9 +8711,9 @@ erts_continue_exit_process(Process *p)
* The registered name *should* be the last "erlang resource" to
* cleanup.
*/
- if (p->reg) {
+ if (p->common.u.alive.reg) {
(void) erts_unregister_name(p, ERTS_PROC_LOCK_MAIN, NULL, THE_NON_VALUE);
- ASSERT(!p->reg);
+ ASSERT(!p->common.u.alive.reg);
}
erts_smp_proc_lock(p, ERTS_PROC_LOCKS_ALL_MINOR);
@@ -9159,22 +8727,18 @@ erts_continue_exit_process(Process *p)
yield_allowed = 0;
#endif
+ /*
+ * Note! The monitor and link fields will be overwritten
+ * by erts_ptab_delete_element() below.
+ */
+ mon = ERTS_P_MONITORS(p);
+ lnk = ERTS_P_LINKS(p);
+
{
- int maybe_save;
- int pix;
/* Do *not* use erts_get_runq_proc() */
ErtsRunQueue *rq;
rq = erts_get_runq_current(ERTS_GET_SCHEDULER_DATA_FROM_PROC(p));
- pix = internal_pid_index(p->id);
-
- erts_smp_rwmtx_rlock(&erts_proc_tab_rwmtx);
- maybe_save = saved_term_procs.end != NULL;
- if (maybe_save) {
- erts_smp_rwmtx_runlock(&erts_proc_tab_rwmtx);
- erts_smp_rwmtx_rwlock(&erts_proc_tab_rwmtx);
- }
-
erts_smp_runq_lock(rq);
#ifdef ERTS_SMP
@@ -9185,22 +8749,11 @@ erts_continue_exit_process(Process *p)
p->scheduler_data->current_process = NULL;
p->scheduler_data->free_process = p;
#endif
- /* Time of death! */
- erts_smp_atomic_set_relb(&erts_proc.tab[pix], ERTS_AINT_NULL);
- ASSERT(erts_smp_atomic32_read_nob(&process_count) > 0);
- erts_smp_atomic32_dec_relb(&process_count);
+ /* Time of death! */
+ erts_ptab_delete_element(&erts_proc, &p->common);
erts_smp_runq_unlock(rq);
-
- if (!maybe_save)
- erts_smp_rwmtx_runlock(&erts_proc_tab_rwmtx);
- else {
- if (saved_term_procs.end)
- save_terminating_process(p);
- erts_smp_rwmtx_rwunlock(&erts_proc_tab_rwmtx);
- }
-
}
/*
@@ -9210,12 +8763,6 @@ erts_continue_exit_process(Process *p)
* when the monitors and/or links hit.
*/
- mon = p->monitors;
- p->monitors = NULL; /* to avoid recursive deletion during traversal */
-
- lnk = p->nlinks;
- p->nlinks = NULL;
-
{
/* Inactivate and notify free */
erts_aint32_t n, e, a = erts_smp_atomic32_read_nob(&p->state);
@@ -9259,7 +8806,7 @@ erts_continue_exit_process(Process *p)
UseTmpHeap(4,p);
hp = &tmp_heap[0];
- exit_tuple = TUPLE3(hp, am_EXIT, p->id, reason);
+ exit_tuple = TUPLE3(hp, am_EXIT, p->common.id, reason);
exit_tuple_sz = size_object(exit_tuple);
@@ -9285,9 +8832,6 @@ erts_continue_exit_process(Process *p)
delete_process(p);
#ifdef ERTS_SMP
- erts_schedule_thr_prgr_later_op(proc_dec_refc,
- (void *) p,
- &p->u.release_data);
erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN);
ERTS_SMP_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p);
#endif
@@ -9339,9 +8883,9 @@ cancel_timer(Process* p)
ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_MAIN & erts_proc_lc_my_proc_locks(p));
p->flags &= ~(F_INSLPQUEUE|F_TIMO);
#ifdef ERTS_SMP
- erts_cancel_smp_ptimer(p->u.alive.ptimer);
+ erts_cancel_smp_ptimer(p->common.u.alive.ptimer);
#else
- erts_cancel_timer(&p->u.alive.tm);
+ erts_cancel_timer(&p->common.u.alive.tm);
#endif
}
@@ -9362,12 +8906,12 @@ set_timer(Process* p, Uint timeout)
p->flags &= ~F_TIMO;
#ifdef ERTS_SMP
- erts_create_smp_ptimer(&p->u.alive.ptimer,
- p->id,
+ erts_create_smp_ptimer(&p->common.u.alive.ptimer,
+ p->common.id,
(ErlTimeoutProc) timeout_proc,
timeout);
#else
- erts_set_timer(&p->u.alive.tm,
+ erts_set_timer(&p->common.u.alive.tm,
(ErlTimeoutProc) timeout_proc,
NULL,
(void*) p,
@@ -9385,7 +8929,7 @@ erts_stack_dump(int to, void *to_arg, Process *p)
Eterm* sp;
int yreg = -1;
- if (p->trace_flags & F_SENSITIVE) {
+ if (ERTS_TRACE_FLAGS(p) & F_SENSITIVE) {
return;
}
erts_program_counter_info(to, to_arg, p);
@@ -9473,1068 +9017,6 @@ stack_element_dump(int to, void *to_arg, Process* p, Eterm* sp, int yreg)
return yreg;
}
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
- * The processes/0 BIF implementation. *
-\* */
-
-
-#define ERTS_PROCESSES_BIF_TAB_INSPECT_INDICES_PER_RED 25
-#define ERTS_PROCESSES_BIF_TAB_CHUNK_SIZE 1000
-#define ERTS_PROCESSES_BIF_MIN_START_REDS \
- (ERTS_PROCESSES_BIF_TAB_CHUNK_SIZE \
- / ERTS_PROCESSES_BIF_TAB_INSPECT_INDICES_PER_RED)
-
-#define ERTS_PROCESSES_BIF_TAB_FREE_TERM_PROC_REDS 1
-
-#define ERTS_PROCESSES_BIF_INSPECT_TERM_PROC_PER_RED 10
-
-#define ERTS_PROCESSES_INSPECT_TERM_PROC_MAX_REDS \
- (ERTS_PROCESSES_BIF_TAB_CHUNK_SIZE \
- / ERTS_PROCESSES_BIF_TAB_INSPECT_INDICES_PER_RED)
-
-
-#define ERTS_PROCESSES_BIF_BUILD_RESULT_CONSES_PER_RED 75
-
-#define ERTS_PROCS_DBG_DO_TRACE 0
-
-#ifdef DEBUG
-# define ERTS_PROCESSES_BIF_DEBUGLEVEL 100
-#else
-# define ERTS_PROCESSES_BIF_DEBUGLEVEL 0
-#endif
-
-#define ERTS_PROCS_DBGLVL_CHK_HALLOC 1
-#define ERTS_PROCS_DBGLVL_CHK_FOUND_PIDS 5
-#define ERTS_PROCS_DBGLVL_CHK_PIDS 10
-#define ERTS_PROCS_DBGLVL_CHK_TERM_PROC_LIST 20
-#define ERTS_PROCS_DBGLVL_CHK_RESLIST 20
-
-#if ERTS_PROCESSES_BIF_DEBUGLEVEL == 0
-# define ERTS_PROCS_ASSERT(EXP)
-#else
-# define ERTS_PROCS_ASSERT(EXP) \
- ((void) ((EXP) \
- ? 1 \
- : (debug_processes_assert_error(#EXP, __FILE__, __LINE__), 0)))
-#endif
-
-
-#if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_HALLOC
-# define ERTS_PROCS_DBG_SAVE_HEAP_ALLOC(PBDP, HP, SZ) \
-do { \
- ERTS_PROCS_ASSERT(!(PBDP)->debug.heap); \
- ERTS_PROCS_ASSERT(!(PBDP)->debug.heap_size); \
- (PBDP)->debug.heap = (HP); \
- (PBDP)->debug.heap_size = (SZ); \
-} while (0)
-# define ERTS_PROCS_DBG_VERIFY_HEAP_ALLOC_USED(PBDP, HP) \
-do { \
- ERTS_PROCS_ASSERT((PBDP)->debug.heap); \
- ERTS_PROCS_ASSERT((PBDP)->debug.heap_size); \
- ERTS_PROCS_ASSERT((PBDP)->debug.heap + (PBDP)->debug.heap_size == (HP));\
- (PBDP)->debug.heap = NULL; \
- (PBDP)->debug.heap_size = 0; \
-} while (0)
-# define ERTS_PROCS_DBG_HEAP_ALLOC_INIT(PBDP) \
-do { \
- (PBDP)->debug.heap = NULL; \
- (PBDP)->debug.heap_size = 0; \
-} while (0)
-#else
-# define ERTS_PROCS_DBG_SAVE_HEAP_ALLOC(PBDP, HP, SZ)
-# define ERTS_PROCS_DBG_VERIFY_HEAP_ALLOC_USED(PBDP, HP)
-# define ERTS_PROCS_DBG_HEAP_ALLOC_INIT(PBDP)
-#endif
-
-#if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_RESLIST
-# define ERTS_PROCS_DBG_CHK_RESLIST(R) debug_processes_check_res_list((R))
-#else
-# define ERTS_PROCS_DBG_CHK_RESLIST(R)
-#endif
-
-#if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_PIDS
-# define ERTS_PROCS_DBG_SAVE_PIDS(PBDP) debug_processes_save_all_pids((PBDP))
-# define ERTS_PROCS_DBG_VERIFY_PIDS(PBDP) \
-do { \
- if (!(PBDP)->debug.correct_pids_verified) \
- debug_processes_verify_all_pids((PBDP)); \
-} while (0)
-# define ERTS_PROCS_DBG_CLEANUP_CHK_PIDS(PBDP) \
-do { \
- if ((PBDP)->debug.correct_pids) { \
- erts_free(ERTS_ALC_T_PROCS_PIDS, \
- (PBDP)->debug.correct_pids); \
- (PBDP)->debug.correct_pids = NULL; \
- } \
-} while(0)
-# define ERTS_PROCS_DBG_CHK_PIDS_INIT(PBDP) \
-do { \
- (PBDP)->debug.correct_pids_verified = 0; \
- (PBDP)->debug.correct_pids = NULL; \
-} while (0)
-#else
-# define ERTS_PROCS_DBG_SAVE_PIDS(PBDP)
-# define ERTS_PROCS_DBG_VERIFY_PIDS(PBDP)
-# define ERTS_PROCS_DBG_CLEANUP_CHK_PIDS(PBDP)
-# define ERTS_PROCS_DBG_CHK_PIDS_INIT(PBDP)
-#endif
-
-#if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_FOUND_PIDS
-# define ERTS_PROCS_DBG_CHK_PID_FOUND(PBDP, PID, IC) \
- debug_processes_check_found_pid((PBDP), (PID), (IC), 1)
-# define ERTS_PROCS_DBG_CHK_PID_NOT_FOUND(PBDP, PID, IC) \
- debug_processes_check_found_pid((PBDP), (PID), (IC), 0)
-#else
-# define ERTS_PROCS_DBG_CHK_PID_FOUND(PBDP, PID, IC)
-# define ERTS_PROCS_DBG_CHK_PID_NOT_FOUND(PBDP, PID, IC)
-#endif
-
-#if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_TERM_PROC_LIST
-# define ERTS_PROCS_DBG_CHK_TPLIST() \
- debug_processes_check_term_proc_list()
-# define ERTS_PROCS_DBG_CHK_FREELIST(FL) \
- debug_processes_check_term_proc_free_list(FL)
-#else
-# define ERTS_PROCS_DBG_CHK_TPLIST()
-# define ERTS_PROCS_DBG_CHK_FREELIST(FL)
-#endif
-
-#if ERTS_PROCESSES_BIF_DEBUGLEVEL == 0
-#if ERTS_PROCS_DBG_DO_TRACE
-# define ERTS_PROCS_DBG_INIT(P, PBDP) (PBDP)->debug.caller = (P)->id
-# else
-# define ERTS_PROCS_DBG_INIT(P, PBDP)
-# endif
-# define ERTS_PROCS_DBG_CLEANUP(PBDP)
-#else
-# define ERTS_PROCS_DBG_INIT(P, PBDP) \
-do { \
- (PBDP)->debug.caller = (P)->id; \
- ERTS_PROCS_DBG_HEAP_ALLOC_INIT((PBDP)); \
- ERTS_PROCS_DBG_CHK_PIDS_INIT((PBDP)); \
-} while (0)
-# define ERTS_PROCS_DBG_CLEANUP(PBDP) \
-do { \
- ERTS_PROCS_DBG_CLEANUP_CHK_PIDS((PBDP)); \
-} while (0)
-#endif
-
-#if ERTS_PROCS_DBG_DO_TRACE
-# define ERTS_PROCS_DBG_TRACE(PID, FUNC, WHAT) \
- erts_fprintf(stderr, "%T %s:%d:%s(): %s\n", \
- (PID), __FILE__, __LINE__, #FUNC, #WHAT)
-#else
-# define ERTS_PROCS_DBG_TRACE(PID, FUNC, WHAT)
-#endif
-
-static Uint processes_bif_tab_chunks;
-static Export processes_trap_export;
-
-typedef struct {
- Uint64 interval;
-} ErtsProcessesBifChunkInfo;
-
-typedef enum {
- INITIALIZING,
- INSPECTING_TABLE,
- INSPECTING_TERMINATED_PROCESSES,
- BUILDING_RESULT,
- RETURN_RESULT
-} ErtsProcessesBifState;
-
-typedef struct {
- ErtsProcessesBifState state;
- Eterm caller;
- ErtsProcessesBifChunkInfo *chunk;
- int tix;
- int pid_ix;
- int pid_sz;
- Eterm *pid;
- ErtsTermProcElement *bif_invocation; /* Only used when > 1 chunk */
-
-#if ERTS_PROCESSES_BIF_DEBUGLEVEL != 0 || ERTS_PROCS_DBG_DO_TRACE
- struct {
- Eterm caller;
-#if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_FOUND_PIDS
- Uint64 *pid_started;
-#endif
-#if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_HALLOC
- Eterm *heap;
- Uint heap_size;
-#endif
-#if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_PIDS
- int correct_pids_verified;
- Eterm *correct_pids;
-#endif
- } debug;
-#endif
-
-} ErtsProcessesBifData;
-
-
-#if ERTS_PROCESSES_BIF_DEBUGLEVEL != 0
-static void debug_processes_assert_error(char* expr, char* file, int line);
-#endif
-#if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_RESLIST
-static void debug_processes_check_res_list(Eterm list);
-#endif
-#if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_PIDS
-static void debug_processes_save_all_pids(ErtsProcessesBifData *pbdp);
-static void debug_processes_verify_all_pids(ErtsProcessesBifData *pbdp);
-#endif
-#if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_FOUND_PIDS
-static void debug_processes_check_found_pid(ErtsProcessesBifData *pbdp,
- Eterm pid,
- Uint64 ic,
- int pid_should_be_found);
-#endif
-#if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_TERM_PROC_LIST
-static void debug_processes_check_term_proc_list(void);
-static void debug_processes_check_term_proc_free_list(ErtsTermProcElement *tpep);
-#endif
-
-static void
-save_terminating_process(Process *p)
-{
- ErtsTermProcElement *tpep = erts_alloc(ERTS_ALC_T_PROCS_TPROC_EL,
- sizeof(ErtsTermProcElement));
- ERTS_PROCS_ASSERT(saved_term_procs.start && saved_term_procs.end);
- ERTS_SMP_LC_ASSERT(erts_lc_rwmtx_is_rwlocked(&erts_proc_tab_rwmtx));
-
- ERTS_PROCS_DBG_CHK_TPLIST();
-
- tpep->prev = saved_term_procs.end;
- tpep->next = NULL;
- tpep->ix = internal_pid_index(p->id);
- tpep->u.process.pid = p->id;
- tpep->u.process.spawned = p->started_interval;
- tpep->u.process.exited = get_proc_interval();
-
- saved_term_procs.end->next = tpep;
- saved_term_procs.end = tpep;
-
- ERTS_PROCS_DBG_CHK_TPLIST();
-
- ERTS_PROCS_ASSERT(tpep->prev->ix >= 0
- ? (tpep->u.process.exited
- >= tpep->prev->u.process.exited)
- : (tpep->u.process.exited
- >= tpep->prev->u.bif_invocation.interval));
-}
-
-static void
-cleanup_processes_bif_data(Binary *bp)
-{
- ErtsProcessesBifData *pbdp = ERTS_MAGIC_BIN_DATA(bp);
-
- ERTS_PROCS_DBG_TRACE(pbdp->debug.caller, cleanup_processes_bif_data, call);
-
- if (pbdp->state != INITIALIZING) {
-
- if (pbdp->chunk) {
- erts_free(ERTS_ALC_T_PROCS_CNKINF, pbdp->chunk);
- pbdp->chunk = NULL;
- }
- if (pbdp->pid) {
- erts_free(ERTS_ALC_T_PROCS_PIDS, pbdp->pid);
- pbdp->pid = NULL;
- }
-
-#if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_FOUND_PIDS
- if (pbdp->debug.pid_started) {
- erts_free(ERTS_ALC_T_PROCS_PIDS, pbdp->debug.pid_started);
- pbdp->debug.pid_started = NULL;
- }
-#endif
-
- if (pbdp->bif_invocation) {
- ErtsTermProcElement *tpep;
-
- erts_smp_rwmtx_rwlock(&erts_proc_tab_rwmtx);
-
- ERTS_PROCS_DBG_TRACE(pbdp->debug.caller,
- cleanup_processes_bif_data,
- term_proc_cleanup);
-
- tpep = pbdp->bif_invocation;
- pbdp->bif_invocation = NULL;
-
- ERTS_PROCS_DBG_CHK_TPLIST();
-
- if (tpep->prev) {
- /*
- * Only remove this bif invokation when we
- * have preceding invokations.
- */
- tpep->prev->next = tpep->next;
- if (tpep->next)
- tpep->next->prev = tpep->prev;
- else {
- /*
- * At the time of writing this branch cannot be
- * reached. I don't want to remove this code though
- * since it may be possible to reach this line
- * in the future if the cleanup order in
- * erts_do_exit_process() is changed. The ASSERT(0)
- * is only here to make us aware that the reorder
- * has happened. /rickard
- */
- ASSERT(0);
- saved_term_procs.end = tpep->prev;
- }
- erts_free(ERTS_ALC_T_PROCS_TPROC_EL, tpep);
- }
- else {
- /*
- * Free all elements until next bif invokation
- * is found.
- */
- ERTS_PROCS_ASSERT(saved_term_procs.start == tpep);
- do {
- ErtsTermProcElement *ftpep = tpep;
- tpep = tpep->next;
- erts_free(ERTS_ALC_T_PROCS_TPROC_EL, ftpep);
- } while (tpep && tpep->ix >= 0);
- saved_term_procs.start = tpep;
- if (tpep)
- tpep->prev = NULL;
- else
- saved_term_procs.end = NULL;
- }
-
- ERTS_PROCS_DBG_CHK_TPLIST();
-
- erts_smp_rwmtx_rwunlock(&erts_proc_tab_rwmtx);
-
- }
- }
-
- ERTS_PROCS_DBG_TRACE(pbdp->debug.caller,
- cleanup_processes_bif_data,
- return);
- ERTS_PROCS_DBG_CLEANUP(pbdp);
-}
-
-static int
-processes_bif_engine(Process *p, Eterm *res_accp, Binary *mbp)
-{
- ErtsProcessesBifData *pbdp = ERTS_MAGIC_BIN_DATA(mbp);
- int have_reds;
- int reds;
- int locked = 0;
-
- do {
- switch (pbdp->state) {
- case INITIALIZING:
- pbdp->chunk = erts_alloc(ERTS_ALC_T_PROCS_CNKINF,
- (sizeof(ErtsProcessesBifChunkInfo)
- * processes_bif_tab_chunks));
- pbdp->tix = 0;
- pbdp->pid_ix = 0;
-
- erts_smp_rwmtx_rwlock(&erts_proc_tab_rwmtx);
- locked = 1;
-
- ERTS_PROCS_DBG_TRACE(p->id, processes_bif_engine, init);
-
- pbdp->pid_sz = erts_process_count();
- pbdp->pid = erts_alloc(ERTS_ALC_T_PROCS_PIDS,
- sizeof(Eterm)*pbdp->pid_sz);
-
-#if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_FOUND_PIDS
- pbdp->debug.pid_started = erts_alloc(ERTS_ALC_T_PROCS_PIDS,
- sizeof(Uint64)*pbdp->pid_sz);
-#endif
-
- ERTS_PROCS_DBG_SAVE_PIDS(pbdp);
-
- if (processes_bif_tab_chunks == 1)
- pbdp->bif_invocation = NULL;
- else {
- /*
- * We will have to access the table multiple times
- * releasing the table lock in between chunks.
- */
- pbdp->bif_invocation = erts_alloc(ERTS_ALC_T_PROCS_TPROC_EL,
- sizeof(ErtsTermProcElement));
- pbdp->bif_invocation->ix = -1;
- pbdp->bif_invocation->u.bif_invocation.interval
- = step_proc_interval();
- ERTS_PROCS_DBG_CHK_TPLIST();
-
- pbdp->bif_invocation->next = NULL;
- if (saved_term_procs.end) {
- pbdp->bif_invocation->prev = saved_term_procs.end;
- saved_term_procs.end->next = pbdp->bif_invocation;
- ERTS_PROCS_ASSERT(saved_term_procs.start);
- }
- else {
- pbdp->bif_invocation->prev = NULL;
- saved_term_procs.start = pbdp->bif_invocation;
- }
- saved_term_procs.end = pbdp->bif_invocation;
-
- ERTS_PROCS_DBG_CHK_TPLIST();
-
- }
-
- pbdp->state = INSPECTING_TABLE;
- /* Fall through */
-
- case INSPECTING_TABLE: {
- int ix = pbdp->tix;
- int indices = ERTS_PROCESSES_BIF_TAB_CHUNK_SIZE;
- int cix = ix / ERTS_PROCESSES_BIF_TAB_CHUNK_SIZE;
- int end_ix = ix + indices;
- Uint64 *invocation_interval_p;
-
- invocation_interval_p
- = (pbdp->bif_invocation
- ? &pbdp->bif_invocation->u.bif_invocation.interval
- : NULL);
-
- ERTS_PROCS_ASSERT(is_nil(*res_accp));
- if (!locked) {
- erts_smp_rwmtx_rwlock(&erts_proc_tab_rwmtx);
- locked = 1;
- }
-
- ERTS_SMP_LC_ASSERT(erts_lc_rwmtx_is_rwlocked(&erts_proc_tab_rwmtx));
- ERTS_PROCS_DBG_TRACE(p->id, processes_bif_engine, insp_table);
-
- if (cix != 0)
- pbdp->chunk[cix].interval = step_proc_interval();
- else if (pbdp->bif_invocation)
- pbdp->chunk[0].interval = *invocation_interval_p;
- /* else: interval is irrelevant */
-
- if (end_ix >= erts_proc.max) {
- ERTS_PROCS_ASSERT(cix+1 == processes_bif_tab_chunks);
- end_ix = erts_proc.max;
- indices = end_ix - ix;
- /* What to do when done with this chunk */
- pbdp->state = (processes_bif_tab_chunks == 1
- ? BUILDING_RESULT
- : INSPECTING_TERMINATED_PROCESSES);
- }
-
- for (; ix < end_ix; ix++) {
- Process *rp = erts_pix2proc(ix);
- if (rp
- && (!invocation_interval_p
- || rp->started_interval < *invocation_interval_p)) {
- ERTS_PROCS_ASSERT(is_internal_pid(rp->id));
- pbdp->pid[pbdp->pid_ix] = rp->id;
-
-#if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_FOUND_PIDS
- pbdp->debug.pid_started[pbdp->pid_ix] = rp->started_interval;
-#endif
-
- pbdp->pid_ix++;
- ERTS_PROCS_ASSERT(pbdp->pid_ix <= pbdp->pid_sz);
- }
- }
-
- pbdp->tix = end_ix;
-
- erts_smp_rwmtx_rwunlock(&erts_proc_tab_rwmtx);
- locked = 0;
-
- reds = indices/ERTS_PROCESSES_BIF_TAB_INSPECT_INDICES_PER_RED;
- BUMP_REDS(p, reds);
-
- have_reds = ERTS_BIF_REDS_LEFT(p);
-
- if (have_reds && pbdp->state == INSPECTING_TABLE) {
- ix = pbdp->tix;
- indices = ERTS_PROCESSES_BIF_TAB_CHUNK_SIZE;
- end_ix = ix + indices;
- if (end_ix > erts_proc.max) {
- end_ix = erts_proc.max;
- indices = end_ix - ix;
- }
-
- reds = indices/ERTS_PROCESSES_BIF_TAB_INSPECT_INDICES_PER_RED;
-
- /* Pretend we have no reds left if we haven't got enough
- reductions to complete next chunk */
- if (reds > have_reds)
- have_reds = 0;
- }
-
- break;
- }
-
- case INSPECTING_TERMINATED_PROCESSES: {
- int i;
- int max_reds;
- int free_term_procs = 0;
- Uint64 invocation_interval;
- ErtsTermProcElement *tpep;
- ErtsTermProcElement *free_list = NULL;
-
- tpep = pbdp->bif_invocation;
- ERTS_PROCS_ASSERT(tpep);
- invocation_interval = tpep->u.bif_invocation.interval;
-
- max_reds = have_reds = ERTS_BIF_REDS_LEFT(p);
- if (max_reds > ERTS_PROCESSES_INSPECT_TERM_PROC_MAX_REDS)
- max_reds = ERTS_PROCESSES_INSPECT_TERM_PROC_MAX_REDS;
-
- reds = 0;
- erts_smp_rwmtx_rwlock(&erts_proc_tab_rwmtx);
- ERTS_PROCS_DBG_TRACE(p->id, processes_bif_engine, insp_term_procs);
-
- ERTS_PROCS_DBG_CHK_TPLIST();
-
- if (tpep->prev)
- tpep->prev->next = tpep->next;
- else {
- ERTS_PROCS_ASSERT(saved_term_procs.start == tpep);
- saved_term_procs.start = tpep->next;
-
- if (saved_term_procs.start && saved_term_procs.start->ix >= 0) {
- free_list = saved_term_procs.start;
- free_term_procs = 1;
- }
- }
-
- if (tpep->next)
- tpep->next->prev = tpep->prev;
- else
- saved_term_procs.end = tpep->prev;
-
- tpep = tpep->next;
-
- i = 0;
- while (reds < max_reds && tpep) {
- if (tpep->ix < 0) {
- if (free_term_procs) {
- ERTS_PROCS_ASSERT(free_list);
- ERTS_PROCS_ASSERT(tpep->prev);
-
- tpep->prev->next = NULL; /* end of free_list */
- saved_term_procs.start = tpep;
- tpep->prev = NULL;
- free_term_procs = 0;
- }
- }
- else {
- int cix = tpep->ix/ERTS_PROCESSES_BIF_TAB_CHUNK_SIZE;
- Uint64 chunk_interval = pbdp->chunk[cix].interval;
- Eterm pid = tpep->u.process.pid;
- ERTS_PROCS_ASSERT(is_internal_pid(pid));
-
- if (tpep->u.process.spawned < invocation_interval) {
- if (tpep->u.process.exited < chunk_interval) {
- ERTS_PROCS_DBG_CHK_PID_NOT_FOUND(pbdp,
- pid,
- tpep->u.process.spawned);
- pbdp->pid[pbdp->pid_ix] = pid;
-#if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_FOUND_PIDS
- pbdp->debug.pid_started[pbdp->pid_ix]
- = tpep->u.process.spawned;
-#endif
- pbdp->pid_ix++;
- ERTS_PROCS_ASSERT(pbdp->pid_ix <= pbdp->pid_sz);
- }
- else {
- ERTS_PROCS_DBG_CHK_PID_FOUND(pbdp,
- pid,
- tpep->u.process.spawned);
- }
- }
- else {
- ERTS_PROCS_DBG_CHK_PID_NOT_FOUND(pbdp,
- pid,
- tpep->u.process.spawned);
- }
-
- i++;
- if (i == ERTS_PROCESSES_BIF_INSPECT_TERM_PROC_PER_RED) {
- reds++;
- i = 0;
- }
- if (free_term_procs)
- reds += ERTS_PROCESSES_BIF_TAB_FREE_TERM_PROC_REDS;
- }
- tpep = tpep->next;
- }
-
- if (free_term_procs) {
- ERTS_PROCS_ASSERT(free_list);
- saved_term_procs.start = tpep;
- if (!tpep)
- saved_term_procs.end = NULL;
- else {
- ERTS_PROCS_ASSERT(tpep->prev);
- tpep->prev->next = NULL; /* end of free_list */
- tpep->prev = NULL;
- }
- }
-
- if (!tpep) {
- /* Done */
- ERTS_PROCS_ASSERT(pbdp->pid_ix == pbdp->pid_sz);
- pbdp->state = BUILDING_RESULT;
- pbdp->bif_invocation->next = free_list;
- free_list = pbdp->bif_invocation;
- pbdp->bif_invocation = NULL;
- }
- else {
- /* Link in bif_invocation again where we left off */
- pbdp->bif_invocation->prev = tpep->prev;
- pbdp->bif_invocation->next = tpep;
- tpep->prev = pbdp->bif_invocation;
- if (pbdp->bif_invocation->prev)
- pbdp->bif_invocation->prev->next = pbdp->bif_invocation;
- else {
- ERTS_PROCS_ASSERT(saved_term_procs.start == tpep);
- saved_term_procs.start = pbdp->bif_invocation;
- }
- }
-
- ERTS_PROCS_DBG_CHK_TPLIST();
- ERTS_PROCS_DBG_CHK_FREELIST(free_list);
- erts_smp_rwmtx_rwunlock(&erts_proc_tab_rwmtx);
-
- /*
- * We do the actual free of term proc structures now when we
- * have released the table lock instead of when we encountered
- * them. This since free() isn't for free and we don't want to
- * unnecessarily block other schedulers.
- */
- while (free_list) {
- tpep = free_list;
- free_list = tpep->next;
- erts_free(ERTS_ALC_T_PROCS_TPROC_EL, tpep);
- }
-
- have_reds -= reds;
- if (have_reds < 0)
- have_reds = 0;
- BUMP_REDS(p, reds);
- break;
- }
-
- case BUILDING_RESULT: {
- int conses, ix, min_ix;
- Eterm *hp;
- Eterm res = *res_accp;
-
- ERTS_PROCS_DBG_VERIFY_PIDS(pbdp);
- ERTS_PROCS_DBG_CHK_RESLIST(res);
-
- ERTS_PROCS_DBG_TRACE(p->id, processes_bif_engine, begin_build_res);
-
- have_reds = ERTS_BIF_REDS_LEFT(p);
- conses = ERTS_PROCESSES_BIF_BUILD_RESULT_CONSES_PER_RED*have_reds;
- min_ix = pbdp->pid_ix - conses;
- if (min_ix < 0) {
- min_ix = 0;
- conses = pbdp->pid_ix;
- }
-
- hp = HAlloc(p, conses*2);
- ERTS_PROCS_DBG_SAVE_HEAP_ALLOC(pbdp, hp, conses*2);
-
- for (ix = pbdp->pid_ix - 1; ix >= min_ix; ix--) {
- ERTS_PROCS_ASSERT(is_internal_pid(pbdp->pid[ix]));
- res = CONS(hp, pbdp->pid[ix], res);
- hp += 2;
- }
-
- ERTS_PROCS_DBG_VERIFY_HEAP_ALLOC_USED(pbdp, hp);
-
- pbdp->pid_ix = min_ix;
- if (min_ix == 0)
- pbdp->state = RETURN_RESULT;
- else {
- pbdp->pid_sz = min_ix;
- pbdp->pid = erts_realloc(ERTS_ALC_T_PROCS_PIDS,
- pbdp->pid,
- sizeof(Eterm)*pbdp->pid_sz);
-#if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_FOUND_PIDS
- pbdp->debug.pid_started = erts_realloc(ERTS_ALC_T_PROCS_PIDS,
- pbdp->debug.pid_started,
- (sizeof(Uint64)
- * pbdp->pid_sz));
-#endif
- }
- reds = conses/ERTS_PROCESSES_BIF_BUILD_RESULT_CONSES_PER_RED;
- BUMP_REDS(p, reds);
- have_reds -= reds;
-
- ERTS_PROCS_DBG_CHK_RESLIST(res);
- ERTS_PROCS_DBG_TRACE(p->id, processes_bif_engine, end_build_res);
- *res_accp = res;
- break;
- }
- case RETURN_RESULT:
- cleanup_processes_bif_data(mbp);
- return 1;
-
- default:
- erl_exit(ERTS_ABORT_EXIT,
- "erlang:processes/0: Invalid state: %d\n",
- (int) pbdp->state);
- }
-
-
- } while (have_reds || pbdp->state == RETURN_RESULT);
-
- return 0;
-}
-
-/*
- * processes_trap/2 is a hidden BIF that processes/0 traps to.
- */
-
-static BIF_RETTYPE processes_trap(BIF_ALIST_2)
-{
- Eterm res_acc;
- Binary *mbp;
-
- /*
- * This bif cannot be called from erlang code. It can only be
- * trapped to from processes/0; therefore, a bad argument
- * is a processes/0 internal error.
- */
-
- ERTS_PROCS_DBG_TRACE(BIF_P->id, processes_trap, call);
- ERTS_PROCS_ASSERT(is_nil(BIF_ARG_1) || is_list(BIF_ARG_1));
-
- res_acc = BIF_ARG_1;
-
- ERTS_PROCS_ASSERT(ERTS_TERM_IS_MAGIC_BINARY(BIF_ARG_2));
-
- mbp = ((ProcBin *) binary_val(BIF_ARG_2))->val;
-
- ERTS_PROCS_ASSERT(ERTS_MAGIC_BIN_DESTRUCTOR(mbp)
- == cleanup_processes_bif_data);
- ERTS_PROCS_ASSERT(
- ((ErtsProcessesBifData *) ERTS_MAGIC_BIN_DATA(mbp))->debug.caller
- == BIF_P->id);
-
- if (processes_bif_engine(BIF_P, &res_acc, mbp)) {
- ERTS_PROCS_DBG_TRACE(BIF_P->id, processes_trap, return);
- BIF_RET(res_acc);
- }
- else {
- ERTS_PROCS_DBG_TRACE(BIF_P->id, processes_trap, trap);
- ERTS_BIF_YIELD2(&processes_trap_export, BIF_P, res_acc, BIF_ARG_2);
- }
-}
-
-
-
-/*
- * The actual processes/0 BIF.
- */
-
-BIF_RETTYPE processes_0(BIF_ALIST_0)
-{
- /*
- * A requirement: The list of pids returned should be a consistent
- * snapshot of all processes existing at some point
- * in time during the execution of processes/0. Since
- * processes might terminate while processes/0 is
- * executing, we have to keep track of terminated
- * processes and add them to the result. We also
- * ignore processes created after processes/0 has
- * begun executing.
- */
- Eterm res_acc = NIL;
- Binary *mbp = erts_create_magic_binary(sizeof(ErtsProcessesBifData),
- cleanup_processes_bif_data);
- ErtsProcessesBifData *pbdp = ERTS_MAGIC_BIN_DATA(mbp);
-
- ERTS_PROCS_DBG_TRACE(BIF_P->id, processes_0, call);
- pbdp->state = INITIALIZING;
- ERTS_PROCS_DBG_INIT(BIF_P, pbdp);
-
- if (ERTS_BIF_REDS_LEFT(BIF_P) >= ERTS_PROCESSES_BIF_MIN_START_REDS
- && processes_bif_engine(BIF_P, &res_acc, mbp)) {
- erts_bin_free(mbp);
- ERTS_PROCS_DBG_CHK_RESLIST(res_acc);
- ERTS_PROCS_DBG_TRACE(BIF_P->id, processes_0, return);
- BIF_RET(res_acc);
- }
- else {
- Eterm *hp;
- Eterm magic_bin;
- ERTS_PROCS_DBG_CHK_RESLIST(res_acc);
- hp = HAlloc(BIF_P, PROC_BIN_SIZE);
- ERTS_PROCS_DBG_SAVE_HEAP_ALLOC(pbdp, hp, PROC_BIN_SIZE);
- magic_bin = erts_mk_magic_binary_term(&hp, &MSO(BIF_P), mbp);
- ERTS_PROCS_DBG_VERIFY_HEAP_ALLOC_USED(pbdp, hp);
- ERTS_PROCS_DBG_TRACE(BIF_P->id, processes_0, trap);
- ERTS_BIF_YIELD2(&processes_trap_export, BIF_P, res_acc, magic_bin);
- }
-}
-
-static void
-init_processes_bif(void)
-{
- saved_term_procs.start = NULL;
- saved_term_procs.end = NULL;
- processes_bif_tab_chunks = (((erts_proc.max - 1)
- / ERTS_PROCESSES_BIF_TAB_CHUNK_SIZE)
- + 1);
-
- /* processes_trap/2 is a hidden BIF that the processes/0 BIF traps to. */
- erts_init_trap_export(&processes_trap_export, am_erlang, am_processes_trap, 2,
- &processes_trap);
-
-}
-
-/*
- * Debug stuff
- */
-
-#if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK)
-int
-erts_dbg_check_halloc_lock(Process *p)
-{
- if (ERTS_PROC_LOCK_MAIN & erts_proc_lc_my_proc_locks(p))
- return 1;
- if (p->id == ERTS_INVALID_PID)
- return 1;
- if (p->scheduler_data && p == p->scheduler_data->match_pseudo_process)
- return 1;
- if (erts_thr_progress_is_blocking())
- return 1;
- return 0;
-}
-#endif
-
-Eterm
-erts_debug_processes(Process *c_p)
-{
- /* This is the old processes/0 BIF. */
- int i;
- Uint need;
- Eterm res;
- Eterm* hp;
- Process *p;
- Eterm *hp_end;
-
- erts_smp_rwmtx_rwlock(&erts_proc_tab_rwmtx);
-
- res = NIL;
- need = erts_process_count() * 2;
- hp = HAlloc(c_p, need); /* we need two heap words for each pid */
- hp_end = hp + need;
-
- /* make the list by scanning bakward */
-
-
- for (i = erts_proc.max-1; i >= 0; i--) {
- p = erts_pix2proc(i);
- if (p) {
- res = CONS(hp, p->id, res);
- hp += 2;
- }
- }
-
- erts_smp_rwmtx_rwunlock(&erts_proc_tab_rwmtx);
-
- HRelease(c_p, hp_end, hp);
-
- return res;
-}
-
-Eterm
-erts_debug_processes_bif_info(Process *c_p)
-{
- ERTS_DECL_AM(processes_bif_info);
- Eterm elements[] = {
- AM_processes_bif_info,
- make_small((Uint) ERTS_PROCESSES_BIF_MIN_START_REDS),
- make_small((Uint) processes_bif_tab_chunks),
- make_small((Uint) ERTS_PROCESSES_BIF_TAB_CHUNK_SIZE),
- make_small((Uint) ERTS_PROCESSES_BIF_TAB_INSPECT_INDICES_PER_RED),
- make_small((Uint) ERTS_PROCESSES_BIF_TAB_FREE_TERM_PROC_REDS),
- make_small((Uint) ERTS_PROCESSES_BIF_INSPECT_TERM_PROC_PER_RED),
- make_small((Uint) ERTS_PROCESSES_INSPECT_TERM_PROC_MAX_REDS),
- make_small((Uint) ERTS_PROCESSES_BIF_BUILD_RESULT_CONSES_PER_RED),
- make_small((Uint) ERTS_PROCESSES_BIF_DEBUGLEVEL)
- };
- Uint sz = 0;
- Eterm *hp;
- (void) erts_bld_tuplev(NULL, &sz, sizeof(elements)/sizeof(Eterm), elements);
- hp = HAlloc(c_p, sz);
- return erts_bld_tuplev(&hp, NULL, sizeof(elements)/sizeof(Eterm), elements);
-}
-
-#if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_FOUND_PIDS
-static void
-debug_processes_check_found_pid(ErtsProcessesBifData *pbdp,
- Eterm pid,
- Uint64 ic,
- int pid_should_be_found)
-{
- int i;
- for (i = 0; i < pbdp->pid_ix; i++) {
- if (pbdp->pid[i] == pid && pbdp->debug.pid_started[i] == ic) {
- ERTS_PROCS_ASSERT(pid_should_be_found);
- return;
- }
- }
- ERTS_PROCS_ASSERT(!pid_should_be_found);
-}
-#endif
-
-#if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_RESLIST
-static void
-debug_processes_check_res_list(Eterm list)
-{
- while (is_list(list)) {
- Eterm* consp = list_val(list);
- Eterm hd = CAR(consp);
- ERTS_PROCS_ASSERT(is_internal_pid(hd));
- list = CDR(consp);
- }
-
- ERTS_PROCS_ASSERT(is_nil(list));
-}
-#endif
-
-#if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_PIDS
-
-static void
-debug_processes_save_all_pids(ErtsProcessesBifData *pbdp)
-{
- int ix, tix, cpix;
- pbdp->debug.correct_pids_verified = 0;
- pbdp->debug.correct_pids = erts_alloc(ERTS_ALC_T_PROCS_PIDS,
- sizeof(Eterm)*pbdp->pid_sz);
-
- for (tix = 0, cpix = 0; tix < erts_proc.max; tix++) {
- Process *rp = erts_pix2proc(tix);
- if (rp) {
- ERTS_PROCS_ASSERT(is_internal_pid(rp->id));
- pbdp->debug.correct_pids[cpix++] = rp->id;
- ERTS_PROCS_ASSERT(cpix <= pbdp->pid_sz);
- }
- }
- ERTS_PROCS_ASSERT(cpix == pbdp->pid_sz);
-
- for (ix = 0; ix < pbdp->pid_sz; ix++)
- pbdp->pid[ix] = make_small(ix);
-}
-
-static void
-debug_processes_verify_all_pids(ErtsProcessesBifData *pbdp)
-{
- int ix, cpix;
-
- ERTS_PROCS_ASSERT(pbdp->pid_ix == pbdp->pid_sz);
-
- for (ix = 0; ix < pbdp->pid_sz; ix++) {
- int found = 0;
- Eterm pid = pbdp->pid[ix];
- ERTS_PROCS_ASSERT(is_internal_pid(pid));
- for (cpix = ix; cpix < pbdp->pid_sz; cpix++) {
- if (pbdp->debug.correct_pids[cpix] == pid) {
- pbdp->debug.correct_pids[cpix] = NIL;
- found = 1;
- break;
- }
- }
- if (!found) {
- for (cpix = 0; cpix < ix; cpix++) {
- if (pbdp->debug.correct_pids[cpix] == pid) {
- pbdp->debug.correct_pids[cpix] = NIL;
- found = 1;
- break;
- }
- }
- }
- ERTS_PROCS_ASSERT(found);
- }
- pbdp->debug.correct_pids_verified = 1;
-
- erts_free(ERTS_ALC_T_PROCS_PIDS, pbdp->debug.correct_pids);
- pbdp->debug.correct_pids = NULL;
-}
-#endif /* ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_PIDS */
-
-#if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_TERM_PROC_LIST
-static void
-debug_processes_check_term_proc_list(void)
-{
- ERTS_SMP_LC_ASSERT(erts_lc_rwmtx_is_rwlocked(&erts_proc_tab_rwmtx));
- if (!saved_term_procs.start)
- ERTS_PROCS_ASSERT(!saved_term_procs.end);
- else {
- Uint64 curr_interval = get_proc_interval();
- Uint64 *prev_x_interval_p = NULL;
- ErtsTermProcElement *tpep;
-
- for (tpep = saved_term_procs.start; tpep; tpep = tpep->next) {
- if (!tpep->prev)
- ERTS_PROCS_ASSERT(saved_term_procs.start == tpep);
- else
- ERTS_PROCS_ASSERT(tpep->prev->next == tpep);
- if (!tpep->next)
- ERTS_PROCS_ASSERT(saved_term_procs.end == tpep);
- else
- ERTS_PROCS_ASSERT(tpep->next->prev == tpep);
- if (tpep->ix < 0) {
- Uint64 interval = tpep->u.bif_invocation.interval;
- ERTS_PROCS_ASSERT(interval <= curr_interval);
- }
- else {
- Uint64 s_interval = tpep->u.process.spawned;
- Uint64 x_interval = tpep->u.process.exited;
-
- ERTS_PROCS_ASSERT(s_interval <= x_interval);
- if (prev_x_interval_p)
- ERTS_PROCS_ASSERT(*prev_x_interval_p <= x_interval);
- prev_x_interval_p = &tpep->u.process.exited;
- ERTS_PROCS_ASSERT(is_internal_pid(tpep->u.process.pid));
- ERTS_PROCS_ASSERT(tpep->ix
- == internal_pid_index(tpep->u.process.pid));
- }
- }
-
- }
-}
-
-static void
-debug_processes_check_term_proc_free_list(ErtsTermProcElement *free_list)
-{
- if (saved_term_procs.start) {
- ErtsTermProcElement *ftpep;
- ErtsTermProcElement *tpep;
-
- for (ftpep = free_list; ftpep; ftpep = ftpep->next) {
- for (tpep = saved_term_procs.start; tpep; tpep = tpep->next)
- ERTS_PROCS_ASSERT(ftpep != tpep);
- }
- }
-}
-
-#endif
-
-#if ERTS_PROCESSES_BIF_DEBUGLEVEL != 0
-
-static void
-debug_processes_assert_error(char* expr, char* file, int line)
-{
- fflush(stdout);
- erts_fprintf(stderr, "%s:%d: Assertion failed: %s\n", file, line, expr);
- fflush(stderr);
- abort();
-}
-
-#endif
-
-/* *\
- * End of the processes/0 BIF implementation. *
-\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
/*
* A nice system halt closing all open port goes as follows:
* 1) This function schedules the aux work ERTS_SSI_AUX_WORK_REAP_PORTS
@@ -10561,3 +9043,19 @@ void erl_halt(int code)
notify_reap_ports_relb();
}
}
+
+#if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK)
+int
+erts_dbg_check_halloc_lock(Process *p)
+{
+ if (ERTS_PROC_LOCK_MAIN & erts_proc_lc_my_proc_locks(p))
+ return 1;
+ if (p->common.id == ERTS_INVALID_PID)
+ return 1;
+ if (p->scheduler_data && p == p->scheduler_data->match_pseudo_process)
+ return 1;
+ if (erts_thr_progress_is_blocking())
+ return 1;
+ return 0;
+}
+#endif
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index 1436e246d6..6d1032c292 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -42,6 +42,9 @@ typedef struct process Process;
#include "erl_process_lock.h" /* Only pull out important types... */
#undef ERTS_PROCESS_LOCK_ONLY_PROC_LOCK_TYPE__
+#define ERL_PORT_GET_PORT_TYPE_ONLY__
+#include "erl_port.h"
+#undef ERL_PORT_GET_PORT_TYPE_ONLY__
#include "erl_vm.h"
#include "erl_smp.h"
#include "erl_message.h"
@@ -66,11 +69,10 @@ typedef struct process Process;
#undef ERL_THR_PROGRESS_TSD_TYPE_ONLY
struct ErtsNodesMonitor_;
-struct port;
#define ERTS_MAX_NO_OF_SCHEDULERS 1024
-#define ERTS_DEFAULT_MAX_PROCESSES (1 << 15)
+#define ERTS_DEFAULT_MAX_PROCESSES (1 << 18)
#define ERTS_HEAP_ALLOC(Type, Size) \
erts_alloc((Type), (Size))
@@ -205,32 +207,10 @@ extern int erts_sched_thread_suggested_stack_size;
((Uint32) erts_smp_atomic32_read_nob(&(RQ)->flags))
#define ERTS_RUNQ_FLGS_GET_MB(RQ) \
((Uint32) erts_smp_atomic32_read_mb(&(RQ)->flags))
-#define ERTS_RUNQ_FLGS_MASK_SET(RQ, MSK, FLGS) \
- ((Uint32) erts_smp_atomic32_mask_set_relb(&(RQ)->flags, \
- (erts_aint32_t) (MSK), \
- (erts_aint32_t) (FLGS)))
-
-ERTS_GLB_INLINE erts_aint32_t
-erts_smp_atomic32_mask_set_relb(erts_smp_atomic32_t *a32p,
- erts_aint32_t mask,
- erts_aint32_t set);
-#if ERTS_GLB_INLINE_INCL_FUNC_DEF
-ERTS_GLB_INLINE erts_aint32_t
-erts_smp_atomic32_mask_set_relb(erts_smp_atomic32_t *a32p,
- erts_aint32_t mask,
- erts_aint32_t set)
-{
- erts_aint32_t act = erts_smp_atomic32_read_nob(a32p);
- while (1) {
- erts_aint32_t exp = act;
- erts_aint32_t new = exp & ~mask;
- new |= (mask & set);
- act = erts_smp_atomic32_cmpxchg_relb(a32p, new, exp);
- if (act == exp)
- return act;
- }
-}
-#endif
+#define ERTS_RUNQ_FLGS_READ_BSET(RQ, MSK, FLGS) \
+ ((Uint32) erts_smp_atomic32_read_bset_relb(&(RQ)->flags, \
+ (erts_aint32_t) (MSK), \
+ (erts_aint32_t) (FLGS)))
typedef enum {
ERTS_SCHDLR_SSPND_DONE_MSCHED_BLOCKED,
@@ -283,9 +263,7 @@ typedef enum {
#define ERTS_SSI_AUX_WORK_CHECK_CHILDREN (((erts_aint32_t) 1) << 10)
#define ERTS_SSI_AUX_WORK_SET_TMO (((erts_aint32_t) 1) << 11)
#define ERTS_SSI_AUX_WORK_MSEG_CACHE_CHECK (((erts_aint32_t) 1) << 12)
-#define ERTS_SSI_AUX_WORK_CODE_IX_ACTIVATION (((erts_aint32_t) 1) << 13)
-#define ERTS_SSI_AUX_WORK_REAP_PORTS (((erts_aint32_t) 1) << 14)
-#define ERTS_SSI_AUX_WORK_FINISH_BP (((erts_aint32_t) 1) << 15)
+#define ERTS_SSI_AUX_WORK_REAP_PORTS (((erts_aint32_t) 1) << 13)
typedef struct ErtsSchedulerSleepInfo_ ErtsSchedulerSleepInfo;
@@ -313,6 +291,7 @@ struct ErtsProcList_ {
Eterm pid;
Uint64 started_interval;
ErtsProcList* next;
+ ErtsProcList* prev;
};
typedef struct ErtsMiscOpList_ ErtsMiscOpList;
@@ -403,8 +382,8 @@ struct ErtsRunQueue_ {
struct {
ErtsRunQueueInfo info;
- struct port *start;
- struct port *end;
+ Port *start;
+ Port *end;
} ports;
};
@@ -480,14 +459,7 @@ typedef struct {
#endif
#ifdef ERTS_SMP
struct {
- Process* code_stager;
- ErtsThrPrgrVal thr_prgr;
- } code_ix_activation;
- struct {
- Process* stager;
- ErtsThrPrgrVal thr_prgr;
- } bp_ix_activation;
- struct {
+ Uint64 next;
int *sched2jix;
int jix;
ErtsDelayedAuxWorkWakeupJob *job;
@@ -521,7 +493,7 @@ struct ErtsSchedulerData_ {
ErtsSchedulerSleepInfo *ssi;
Process *current_process;
Uint no; /* Scheduler number */
- struct port *current_port;
+ Port *current_port;
ErtsRunQueue *run_queue;
int virtual_reds;
int cpu_id; /* >= 0 when bound */
@@ -530,6 +502,7 @@ struct ErtsSchedulerData_ {
ErtsSchedAllocData alloc_data;
+ Uint64 reductions;
ErtsSchedWallTime sched_wall_time;
#ifdef ERTS_DO_VERIFY_UNUSED_TEMP_ALLOC
@@ -745,8 +718,8 @@ struct ErtsPendingSuspend_ {
# define BIN_OLD_VHEAP(p) (p)->bin_old_vheap
struct process {
- Eterm id; /* The pid of this process
- (need to be first in struct) */
+ ErtsPTabElementCommon common; /* *Need* to be first in struct */
+
/* All fields in the PCB that differs between different heap
* architectures, have been moved to the end of this struct to
* make sure that as few offsets as possible differ. Different
@@ -790,12 +763,8 @@ struct process {
* Only valid for the current process.
*/
Uint32 rcount; /* suspend count */
- int prio; /* Priority of process */
int schedule_count; /* Times left to reschedule a low prio process */
Uint reds; /* No of reductions for this process */
- Eterm tracer_proc; /* If proc is traced, this is the tracer
- (can NOT be boxed) */
- Uint trace_flags; /* Trace flags (used to be in flags) */
Eterm group_leader; /* Pid in charge
(can be boxed) */
Uint flags; /* Trap exit, etc (no trace flags anymore) */
@@ -805,10 +774,6 @@ struct process {
Process *next; /* Pointer to next process in run queue */
- struct reg_proc *reg; /* NULL iff not registered */
- ErtsLink *nlinks;
- ErtsMonitor *monitors; /* The process monitors, both ends */
-
struct ErtsNodesMonitor_ *nodes_monitors;
ErtsSuspendMonitor *suspend_monitors; /* Processes suspended by
@@ -817,7 +782,10 @@ struct process {
ErlMessageQueue msg; /* Message queue */
- ErtsBifTimer *bif_timers; /* Bif timers aiming at this process */
+ union {
+ ErtsBifTimer *bif_timers; /* Bif timers aiming at this process */
+ void *terminate;
+ } u;
ProcDict *dictionary; /* Process dictionary, may be NULL */
@@ -842,7 +810,6 @@ struct process {
*/
Eterm parent; /* Pid of process that created this process. */
erts_approx_time_t approx_started; /* Time when started. */
- Uint64 started_interval;
/* This is the place, where all fields that differs between memory
* architectures, have gone to.
@@ -864,25 +831,11 @@ struct process {
Uint64 bin_old_vheap_sz; /* Virtual old heap block size for binaries */
Uint64 bin_old_vheap; /* Virtual old heap size for binaries */
- union {
- struct {
-#ifdef ERTS_SMP
- ErtsSmpPTimer *ptimer;
- ErlMessageInQueue msg_inq;
- ErtsPendExit pending_exit;
-#else
- ErlTimer tm; /* Timer entry */
-#endif
- } alive; /* when process is alive */
-#ifdef ERTS_SMP
- ErtsThrPrgrLaterOp release_data; /* when releasing process struct */
-#endif
- void *exit_data; /* Misc data referred during termination */
- } u;
-
erts_smp_atomic32_t state; /* Process state flags (see ERTS_PSFLG_*) */
#ifdef ERTS_SMP
+ ErlMessageInQueue msg_inq;
+ ErtsPendExit pending_exit;
erts_proc_lock_t lock;
ErtsSchedulerData *scheduler_data;
Eterm suspendee;
@@ -912,6 +865,8 @@ struct process {
#endif
};
+extern const Process erts_invalid_process;
+
#ifdef CHECK_FOR_HOLES
# define INIT_HOLE_CHECK(p) \
do { \
@@ -1036,8 +991,6 @@ Eterm* erts_heap_alloc(Process* p, Uint need, Uint xtra);
Eterm* erts_set_hole_marker(Eterm* ptr, Uint sz);
#endif
-extern erts_smp_rwmtx_t erts_proc_tab_rwmtx;
-extern erts_smp_atomic_t *erts_proc_tab;
extern Uint erts_default_process_flags;
extern erts_smp_rwmtx_t erts_cpu_bind_rwmtx;
/* If any of the erts_system_monitor_* variables are set (enabled),
@@ -1065,10 +1018,6 @@ struct erts_system_profile_flags_t {
unsigned int exclusive : 1;
};
extern struct erts_system_profile_flags_t erts_system_profile_flags;
-
-#define IS_TRACED(p) ( (p)->tracer_proc != NIL )
-#define ARE_TRACE_FLAGS_ON(p,tf) ( ((p)->trace_flags & (tf|F_SENSITIVE)) == (tf) )
-#define IS_TRACED_FL(p,tf) ( IS_TRACED(p) && ARE_TRACE_FLAGS_ON(p,tf) )
/* process flags */
#define F_HIBERNATE_SCHED (1 << 0) /* Schedule out after hibernate op */
@@ -1179,7 +1128,172 @@ Uint64 erts_step_proc_interval(void);
ErtsProcList *erts_proclist_create(Process *);
void erts_proclist_destroy(ErtsProcList *);
-int erts_proclist_same(ErtsProcList *, Process *);
+
+ERTS_GLB_INLINE int erts_proclist_same(ErtsProcList *, Process *);
+ERTS_GLB_INLINE void erts_proclist_store_first(ErtsProcList **, ErtsProcList *);
+ERTS_GLB_INLINE void erts_proclist_store_last(ErtsProcList **, ErtsProcList *);
+ERTS_GLB_INLINE ErtsProcList *erts_proclist_peek_first(ErtsProcList *);
+ERTS_GLB_INLINE ErtsProcList *erts_proclist_peek_last(ErtsProcList *);
+ERTS_GLB_INLINE ErtsProcList *erts_proclist_peek_next(ErtsProcList *, ErtsProcList *);
+ERTS_GLB_INLINE ErtsProcList *erts_proclist_peek_prev(ErtsProcList *, ErtsProcList *);
+ERTS_GLB_INLINE ErtsProcList *erts_proclist_fetch_first(ErtsProcList **);
+ERTS_GLB_INLINE ErtsProcList *erts_proclist_fetch_last(ErtsProcList **);
+ERTS_GLB_INLINE int erts_proclist_fetch(ErtsProcList **, ErtsProcList **);
+ERTS_GLB_INLINE void erts_proclist_remove(ErtsProcList **, ErtsProcList *);
+ERTS_GLB_INLINE int erts_proclist_is_empty(ErtsProcList *);
+ERTS_GLB_INLINE int erts_proclist_is_first(ErtsProcList *, ErtsProcList *);
+ERTS_GLB_INLINE int erts_proclist_is_last(ErtsProcList *, ErtsProcList *);
+
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+
+ERTS_GLB_INLINE int
+erts_proclist_same(ErtsProcList *plp, Process *p)
+{
+ return (plp->pid == p->common.id
+ && (plp->started_interval
+ == p->common.u.alive.started_interval));
+}
+
+ERTS_GLB_INLINE void erts_proclist_store_first(ErtsProcList **list,
+ ErtsProcList *element)
+{
+ if (!*list)
+ element->next = element->prev = element;
+ else {
+ element->prev = (*list)->prev;
+ element->next = *list;
+ element->prev->next = element;
+ element->next->prev = element;
+ }
+ *list = element;
+}
+
+ERTS_GLB_INLINE void erts_proclist_store_last(ErtsProcList **list,
+ ErtsProcList *element)
+{
+ if (!*list) {
+ element->next = element->prev = element;
+ *list = element;
+ }
+ else {
+ element->prev = (*list)->prev;
+ element->next = *list;
+ element->prev->next = element;
+ element->next->prev = element;
+ }
+}
+
+ERTS_GLB_INLINE ErtsProcList *erts_proclist_peek_first(ErtsProcList *list)
+{
+ return list;
+}
+
+ERTS_GLB_INLINE ErtsProcList *erts_proclist_peek_last(ErtsProcList *list)
+{
+ if (!list)
+ return NULL;
+ else
+ return list->prev;
+}
+
+ERTS_GLB_INLINE ErtsProcList *erts_proclist_peek_next(ErtsProcList *list,
+ ErtsProcList *element)
+{
+ ErtsProcList *next;
+ ASSERT(list && element);
+ next = element->next;
+ return list == next ? NULL : next;
+}
+
+ERTS_GLB_INLINE ErtsProcList *erts_proclist_peek_prev(ErtsProcList *list,
+ ErtsProcList *element)
+{
+ ErtsProcList *prev;
+ ASSERT(list && element);
+ prev = element->prev;
+ return list == element ? NULL : prev;
+}
+
+ERTS_GLB_INLINE ErtsProcList *erts_proclist_fetch_first(ErtsProcList **list)
+{
+ if (!*list)
+ return NULL;
+ else {
+ ErtsProcList *res = *list;
+ if (res == *list)
+ *list = NULL;
+ else
+ *list = res->next;
+ res->next->prev = res->prev;
+ res->prev->next = res->next;
+ return res;
+ }
+}
+
+ERTS_GLB_INLINE ErtsProcList *erts_proclist_fetch_last(ErtsProcList **list)
+{
+ if (!*list)
+ return NULL;
+ else {
+ ErtsProcList *res = (*list)->prev;
+ if (res == *list)
+ *list = NULL;
+ res->next->prev = res->prev;
+ res->prev->next = res->next;
+ return res;
+ }
+}
+
+ERTS_GLB_INLINE int erts_proclist_fetch(ErtsProcList **list_first,
+ ErtsProcList **list_last)
+{
+ if (!*list_first) {
+ if (list_last)
+ *list_last = NULL;
+ return 0;
+ }
+ else {
+ if (list_last)
+ *list_last = (*list_first)->prev;
+ (*list_first)->prev->next = NULL;
+ (*list_first)->prev = NULL;
+ return !0;
+ }
+}
+
+ERTS_GLB_INLINE void erts_proclist_remove(ErtsProcList **list,
+ ErtsProcList *element)
+{
+ ASSERT(list && *list);
+ if (*list == element) {
+ *list = element->next;
+ if (*list == element)
+ *list = NULL;
+ }
+ element->next->prev = element->prev;
+ element->prev->next = element->next;
+}
+
+ERTS_GLB_INLINE int erts_proclist_is_empty(ErtsProcList *list)
+{
+ return list == NULL;
+}
+
+ERTS_GLB_INLINE int erts_proclist_is_first(ErtsProcList *list,
+ ErtsProcList *element)
+{
+ ASSERT(list && element);
+ return list == element;
+}
+
+ERTS_GLB_INLINE int erts_proclist_is_last(ErtsProcList *list,
+ ErtsProcList *element)
+{
+ ASSERT(list && element);
+ return list->prev == element;
+}
+
+#endif
int erts_sched_set_wakeup_other_thresold(char *str);
int erts_sched_set_wakeup_other_type(char *str);
@@ -1229,7 +1343,7 @@ void erts_schedule_multi_misc_aux_work(int ignore_self,
erts_aint32_t erts_set_aux_work_timeout(int, erts_aint32_t, int);
void erts_sched_notify_check_cpu_bind(void);
Uint erts_active_schedulers(void);
-void erts_init_process(int);
+void erts_init_process(int, int);
Eterm erts_process_status(Process *, ErtsProcLocks, Process *, Eterm);
Uint erts_run_queues_len(Uint *);
void erts_add_to_runq(Process *);
@@ -1248,7 +1362,6 @@ void set_timer(Process*, Uint);
void cancel_timer(Process*);
/* Begin System profile */
Uint erts_runnable_process_count(void);
-Uint erts_process_count(void);
/* End System profile */
void erts_init_empty_process(Process *p);
void erts_cleanup_empty_process(Process* p);
@@ -1272,7 +1385,7 @@ Eterm erts_sched_stat_term(Process *p, int total);
void erts_free_proc(Process *);
-void erts_suspend(Process*, ErtsProcLocks, struct port*);
+void erts_suspend(Process*, ErtsProcLocks, Port*);
void erts_resume(Process*, ErtsProcLocks);
int erts_resume_processes(ErtsProcList *);
@@ -1297,9 +1410,6 @@ void erts_deep_process_dump(int, void *);
Eterm erts_get_reader_groups_map(Process *c_p);
Eterm erts_debug_reader_groups_map(Process *c_p, int groups);
-Sint erts_test_next_pid(int, Uint);
-Eterm erts_debug_processes(Process *c_p);
-Eterm erts_debug_processes_bif_info(Process *c_p);
Uint erts_debug_nbalance(void);
int erts_debug_wait_deallocations(Process *c_p);
@@ -1611,7 +1721,7 @@ ERTS_GLB_INLINE
Eterm erts_get_current_pid(void)
{
Process *proc = erts_get_current_process();
- return proc ? proc->id : THE_NON_VALUE;
+ return proc ? proc->common.id : THE_NON_VALUE;
}
ERTS_GLB_INLINE
@@ -1820,10 +1930,10 @@ extern int erts_disable_proc_not_running_opt;
/* Minimum NUMBER of processes for a small system to start */
-#ifdef ERTS_SMP
+#define ERTS_MIN_PROCESSES 1024
+#if defined(ERTS_SMP) && ERTS_MIN_PROCESSES < ERTS_NO_OF_PIX_LOCKS
+#undef ERTS_MIN_PROCESSES
#define ERTS_MIN_PROCESSES ERTS_NO_OF_PIX_LOCKS
-#else
-#define ERTS_MIN_PROCESSES 16
#endif
void erts_smp_notify_inc_runq(ErtsRunQueue *runq);
diff --git a/erts/emulator/beam/erl_process_dict.c b/erts/emulator/beam/erl_process_dict.c
index 93466da3aa..bf384c66e1 100644
--- a/erts/emulator/beam/erl_process_dict.c
+++ b/erts/emulator/beam/erl_process_dict.c
@@ -360,7 +360,7 @@ static void pd_hash_erase(Process *p, Eterm id, Eterm *ret)
erts_fprintf(stderr,
"Process dictionary for process %T is broken, trying to "
"display term found in line %d:\n"
- "%T\n", p->id, __LINE__, old);
+ "%T\n", p->common.id, __LINE__, old);
#endif
erl_exit(1, "Damaged process dictionary found during erase/1.");
}
@@ -405,7 +405,7 @@ Eterm erts_pd_hash_get(Process *p, Eterm id)
erts_fprintf(stderr,
"Process dictionary for process %T is broken, trying to "
"display term found in line %d:\n"
- "%T\n", p->id, __LINE__, tmp);
+ "%T\n", p->common.id, __LINE__, tmp);
#endif
erl_exit(1, "Damaged process dictionary found during get/1.");
}
@@ -614,7 +614,7 @@ static Eterm pd_hash_put(Process *p, Eterm id, Eterm value)
erts_fprintf(stderr,
"Process dictionary for process %T is broken, trying to "
"display term found in line %d:\n"
- "%T\n", p->id, __LINE__, old);
+ "%T\n", p->common.id, __LINE__, old);
#endif
erl_exit(1, "Damaged process dictionary found during put/2.");
diff --git a/erts/emulator/beam/erl_process_dump.c b/erts/emulator/beam/erl_process_dump.c
index 542c5ed0d9..ba74dfd6a1 100644
--- a/erts/emulator/beam/erl_process_dump.c
+++ b/erts/emulator/beam/erl_process_dump.c
@@ -60,11 +60,11 @@ extern BeamInstr beam_continue_exit[];
void
erts_deep_process_dump(int to, void *to_arg)
{
- int i;
+ int i, max = erts_ptab_max(&erts_proc);
all_binaries = NULL;
- for (i = 0; i < erts_max_processes; i++) {
+ for (i = 0; i < max; i++) {
Process *p = erts_pix2proc(i);
if (p && p->i != ENULL) {
erts_aint32_t state = erts_smp_atomic32_read_acqb(&p->state);
@@ -85,8 +85,8 @@ dump_process_info(int to, void *to_arg, Process *p)
ERTS_SMP_MSGQ_MV_INQ2PRIVQ(p);
- if ((p->trace_flags & F_SENSITIVE) == 0 && p->msg.first) {
- erts_print(to, to_arg, "=proc_messages:%T\n", p->id);
+ if ((ERTS_TRACE_FLAGS(p) & F_SENSITIVE) == 0 && p->msg.first) {
+ erts_print(to, to_arg, "=proc_messages:%T\n", p->common.id);
for (mp = p->msg.first; mp != NULL; mp = mp->next) {
Eterm mesg = ERL_MESSAGE_TERM(mp);
if (is_value(mesg))
@@ -100,21 +100,21 @@ dump_process_info(int to, void *to_arg, Process *p)
}
}
- if ((p->trace_flags & F_SENSITIVE) == 0) {
+ if ((ERTS_TRACE_FLAGS(p) & F_SENSITIVE) == 0) {
if (p->dictionary) {
- erts_print(to, to_arg, "=proc_dictionary:%T\n", p->id);
+ erts_print(to, to_arg, "=proc_dictionary:%T\n", p->common.id);
erts_deep_dictionary_dump(to, to_arg,
p->dictionary, dump_element_nl);
}
}
- if ((p->trace_flags & F_SENSITIVE) == 0) {
- erts_print(to, to_arg, "=proc_stack:%T\n", p->id);
+ if ((ERTS_TRACE_FLAGS(p) & F_SENSITIVE) == 0) {
+ erts_print(to, to_arg, "=proc_stack:%T\n", p->common.id);
for (sp = p->stop; sp < STACK_START(p); sp++) {
yreg = stack_element_dump(to, to_arg, p, sp, yreg);
}
- erts_print(to, to_arg, "=proc_heap:%T\n", p->id);
+ erts_print(to, to_arg, "=proc_heap:%T\n", p->common.id);
for (sp = p->stop; sp < STACK_START(p); sp++) {
Eterm term = *sp;
diff --git a/erts/emulator/beam/erl_process_lock.c b/erts/emulator/beam/erl_process_lock.c
index 7777ba1d3d..2db5df06b4 100644
--- a/erts/emulator/beam/erl_process_lock.c
+++ b/erts/emulator/beam/erl_process_lock.c
@@ -66,8 +66,7 @@
#endif
#include "erl_process.h"
-
-const Process erts_proc_lock_busy = {ERTS_INVALID_PID};
+#include "erl_thr_progress.h"
#ifdef ERTS_SMP
@@ -399,7 +398,7 @@ wait_for_locks(Process *p,
ErtsProcLocks need_locks,
ErtsProcLocks olflgs)
{
- erts_pix_lock_t *pix_lock = pixlck ? pixlck : ERTS_PID2PIXLOCK(p->id);
+ erts_pix_lock_t *pix_lock = pixlck ? pixlck : ERTS_PID2PIXLOCK(p->common.id);
erts_tse_t *wtr;
/* Acquire a waiter object on which this thread can wait. */
@@ -553,7 +552,7 @@ erts_proc_unlock_failed(Process *p,
erts_pix_lock_t *pixlck,
ErtsProcLocks wait_locks)
{
- erts_pix_lock_t *pix_lock = pixlck ? pixlck : ERTS_PID2PIXLOCK(p->id);
+ erts_pix_lock_t *pix_lock = pixlck ? pixlck : ERTS_PID2PIXLOCK(p->common.id);
#if ERTS_PROC_LOCK_ATOMIC_IMPL
erts_pix_lock(pix_lock);
@@ -580,7 +579,7 @@ erts_proc_lock_prepare_proc_lock_waiter(void)
*/
static void
-proc_safelock(int is_sched,
+proc_safelock(int is_managed,
Process *a_proc,
ErtsProcLocks a_have_locks,
ErtsProcLocks a_need_locks,
@@ -603,40 +602,40 @@ proc_safelock(int is_sched,
* Locks with the same lock order should be locked on p1 before p2.
*/
if (a_proc) {
- if (a_proc->id < b_proc->id) {
+ if (a_proc->common.id < b_proc->common.id) {
p1 = a_proc;
#ifdef ERTS_ENABLE_LOCK_CHECK
- pid1 = a_proc->id;
+ pid1 = a_proc->common.id;
#endif
need_locks1 = a_need_locks;
have_locks1 = a_have_locks;
p2 = b_proc;
#ifdef ERTS_ENABLE_LOCK_CHECK
- pid2 = b_proc->id;
+ pid2 = b_proc->common.id;
#endif
need_locks2 = b_need_locks;
have_locks2 = b_have_locks;
}
- else if (a_proc->id > b_proc->id) {
+ else if (a_proc->common.id > b_proc->common.id) {
p1 = b_proc;
#ifdef ERTS_ENABLE_LOCK_CHECK
- pid1 = b_proc->id;
+ pid1 = b_proc->common.id;
#endif
need_locks1 = b_need_locks;
have_locks1 = b_have_locks;
p2 = a_proc;
#ifdef ERTS_ENABLE_LOCK_CHECK
- pid2 = a_proc->id;
+ pid2 = a_proc->common.id;
#endif
need_locks2 = a_need_locks;
have_locks2 = a_have_locks;
}
else {
ERTS_LC_ASSERT(a_proc == b_proc);
- ERTS_LC_ASSERT(a_proc->id == b_proc->id);
+ ERTS_LC_ASSERT(a_proc->common.id == b_proc->common.id);
p1 = a_proc;
#ifdef ERTS_ENABLE_LOCK_CHECK
- pid1 = a_proc->id;
+ pid1 = a_proc->common.id;
#endif
need_locks1 = a_need_locks | b_need_locks;
have_locks1 = a_have_locks | b_have_locks;
@@ -651,7 +650,7 @@ proc_safelock(int is_sched,
else {
p1 = b_proc;
#ifdef ERTS_ENABLE_LOCK_CHECK
- pid1 = b_proc->id;
+ pid1 = b_proc->common.id;
#endif
need_locks1 = b_need_locks;
have_locks1 = b_have_locks;
@@ -706,7 +705,7 @@ proc_safelock(int is_sched,
if (unlock_locks) {
have_locks1 &= ~unlock_locks;
need_locks1 |= unlock_locks;
- if (!is_sched && !have_locks1) {
+ if (!is_managed && !have_locks1) {
refc1 = 1;
erts_smp_proc_inc_refc(p1);
}
@@ -716,7 +715,7 @@ proc_safelock(int is_sched,
if (unlock_locks) {
have_locks2 &= ~unlock_locks;
need_locks2 |= unlock_locks;
- if (!is_sched && !have_locks2) {
+ if (!is_managed && !have_locks2) {
refc2 = 1;
erts_smp_proc_inc_refc(p2);
}
@@ -797,7 +796,7 @@ proc_safelock(int is_sched,
}
#endif
- if (!is_sched) {
+ if (!is_managed) {
if (refc1)
erts_smp_proc_dec_refc(p1);
if (refc2)
@@ -830,7 +829,7 @@ erts_pid2proc_opt(Process *c_p,
int flags)
{
Process *dec_refc_proc = NULL;
- int need_ptl;
+ ErtsThrPrgrDelayHandle dhndl;
ErtsProcLocks need_locks;
Uint pix;
Process *proc;
@@ -853,8 +852,8 @@ erts_pid2proc_opt(Process *c_p,
ERTS_LC_ASSERT((pid_need_locks & ERTS_PROC_LOCKS_ALL) == pid_need_locks);
need_locks = pid_need_locks;
- if (c_p && c_p->id == pid) {
- ASSERT(c_p->id != ERTS_INVALID_PID);
+ if (c_p && c_p->common.id == pid) {
+ ASSERT(c_p->common.id != ERTS_INVALID_PID);
ASSERT(c_p == erts_pix2proc(pix));
if (!(flags & ERTS_P2P_FLG_ALLOW_OTHER_X)
@@ -868,15 +867,12 @@ erts_pid2proc_opt(Process *c_p,
}
}
- need_ptl = !erts_get_scheduler_id();
-
- if (need_ptl)
- erts_smp_rwmtx_rwlock(&erts_proc_tab_rwmtx);
+ dhndl = erts_thr_progress_unmanaged_delay();
- proc = (Process *) erts_smp_atomic_read_ddrb(&erts_proc.tab[pix]);
+ proc = (Process *) erts_ptab_pix2intptr_ddrb(&erts_proc, pix);
if (proc) {
- if (proc->id != pid)
+ if (proc->common.id != pid)
proc = NULL;
else if (!need_locks) {
if (flags & ERTS_P2P_FLG_SMP_INC_REFC)
@@ -935,6 +931,7 @@ erts_pid2proc_opt(Process *c_p,
if (flags & ERTS_P2P_FLG_TRY_LOCK)
proc = ERTS_PROC_LOCK_BUSY;
else {
+ int managed;
if (flags & ERTS_P2P_FLG_SMP_INC_REFC)
erts_smp_proc_inc_refc(proc);
@@ -942,14 +939,21 @@ erts_pid2proc_opt(Process *c_p,
erts_lcnt_proc_lock_unaquire(&proc->lock, lcnt_locks);
#endif
- if (need_ptl) {
+ managed = dhndl == ERTS_THR_PRGR_DHANDLE_MANAGED;
+ if (!managed) {
erts_smp_proc_inc_refc(proc);
+ erts_thr_progress_unmanaged_continue(dhndl);
dec_refc_proc = proc;
- erts_smp_rwmtx_rwunlock(&erts_proc_tab_rwmtx);
- need_ptl = 0;
+
+ /*
+ * We don't want to call
+ * erts_thr_progress_unmanaged_continue()
+ * again.
+ */
+ dhndl = ERTS_THR_PRGR_DHANDLE_MANAGED;
}
- proc_safelock(!need_ptl,
+ proc_safelock(managed,
c_p,
c_p_have_locks,
c_p_have_locks,
@@ -961,8 +965,8 @@ erts_pid2proc_opt(Process *c_p,
}
}
- if (need_ptl)
- erts_smp_rwmtx_rwunlock(&erts_proc_tab_rwmtx);
+ if (dhndl != ERTS_THR_PRGR_DHANDLE_MANAGED)
+ erts_thr_progress_unmanaged_continue(dhndl);
if (need_locks
&& proc
@@ -970,7 +974,7 @@ erts_pid2proc_opt(Process *c_p,
&& (!(flags & ERTS_P2P_FLG_ALLOW_OTHER_X)
? ERTS_PROC_IS_EXITING(proc)
: (proc
- != (Process *) erts_smp_atomic_read_nob(&erts_proc.tab[pix])))) {
+ != (Process *) erts_ptab_pix2intptr_nob(&erts_proc, pix)))) {
erts_smp_proc_unlock(proc, need_locks);
@@ -1012,22 +1016,22 @@ erts_proc_lock_init(Process *p)
erts_proc_lc_trylock(p, ERTS_PROC_LOCKS_ALL, 1);
#endif
#elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL
- erts_mtx_init_x(&p->lock.main, "proc_main", p->id);
+ erts_mtx_init_x(&p->lock.main, "proc_main", p->common.id);
ethr_mutex_lock(&p->lock.main.mtx);
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_lc_trylock(1, &p->lock.main.lc);
#endif
- erts_mtx_init_x(&p->lock.link, "proc_link", p->id);
+ erts_mtx_init_x(&p->lock.link, "proc_link", p->common.id);
ethr_mutex_lock(&p->lock.link.mtx);
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_lc_trylock(1, &p->lock.link.lc);
#endif
- erts_mtx_init_x(&p->lock.msgq, "proc_msgq", p->id);
+ erts_mtx_init_x(&p->lock.msgq, "proc_msgq", p->common.id);
ethr_mutex_lock(&p->lock.msgq.mtx);
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_lc_trylock(1, &p->lock.msgq.lc);
#endif
- erts_mtx_init_x(&p->lock.status, "proc_status", p->id);
+ erts_mtx_init_x(&p->lock.status, "proc_status", p->common.id);
ethr_mutex_lock(&p->lock.status.mtx);
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_lc_trylock(1, &p->lock.status.lc);
@@ -1064,11 +1068,11 @@ erts_proc_lock_fin(Process *p)
#if ERTS_PROC_LOCK_OWN_IMPL && defined(ERTS_ENABLE_LOCK_COUNT)
void erts_lcnt_proc_lock_init(Process *p) {
if (erts_lcnt_rt_options & ERTS_LCNT_OPT_PROCLOCK) {
- if (p->id != ERTS_INVALID_PID) {
- erts_lcnt_init_lock_x(&(p->lock.lcnt_main), "proc_main", ERTS_LCNT_LT_PROCLOCK, p->id);
- erts_lcnt_init_lock_x(&(p->lock.lcnt_msgq), "proc_msgq", ERTS_LCNT_LT_PROCLOCK, p->id);
- erts_lcnt_init_lock_x(&(p->lock.lcnt_link), "proc_link", ERTS_LCNT_LT_PROCLOCK, p->id);
- erts_lcnt_init_lock_x(&(p->lock.lcnt_status), "proc_status", ERTS_LCNT_LT_PROCLOCK, p->id);
+ if (p->common.id != ERTS_INVALID_PID) {
+ erts_lcnt_init_lock_x(&(p->lock.lcnt_main), "proc_main", ERTS_LCNT_LT_PROCLOCK, p->common.id);
+ erts_lcnt_init_lock_x(&(p->lock.lcnt_msgq), "proc_msgq", ERTS_LCNT_LT_PROCLOCK, p->common.id);
+ erts_lcnt_init_lock_x(&(p->lock.lcnt_link), "proc_link", ERTS_LCNT_LT_PROCLOCK, p->common.id);
+ erts_lcnt_init_lock_x(&(p->lock.lcnt_status), "proc_status", ERTS_LCNT_LT_PROCLOCK, p->common.id);
} else {
erts_lcnt_init_lock(&(p->lock.lcnt_main), "proc_main", ERTS_LCNT_LT_PROCLOCK);
erts_lcnt_init_lock(&(p->lock.lcnt_msgq), "proc_msgq", ERTS_LCNT_LT_PROCLOCK);
@@ -1176,10 +1180,11 @@ void erts_lcnt_proc_trylock(erts_proc_lock_t *lock, ErtsProcLocks locks, int res
}
-void erts_lcnt_enable_proc_lock_count(int enable) {
- int i;
+void erts_lcnt_enable_proc_lock_count(int enable)
+{
+ int i, max = erts_ptab_max(&erts_proc);
- for (i = 0; i < erts_max_processes; ++i) {
+ for (i = 0; i < max; ++i) {
Process* p = erts_pix2proc(i);
if (p) {
if (enable) {
@@ -1208,7 +1213,7 @@ void
erts_proc_lc_lock(Process *p, ErtsProcLocks locks)
{
erts_lc_lock_t lck = ERTS_LC_LOCK_INIT(-1,
- p->id,
+ p->common.id,
ERTS_LC_FLG_LT_PROCLOCK);
if (locks & ERTS_PROC_LOCK_MAIN) {
lck.id = lc_id.proc_lock_main;
@@ -1232,7 +1237,7 @@ void
erts_proc_lc_trylock(Process *p, ErtsProcLocks locks, int locked)
{
erts_lc_lock_t lck = ERTS_LC_LOCK_INIT(-1,
- p->id,
+ p->common.id,
ERTS_LC_FLG_LT_PROCLOCK);
if (locks & ERTS_PROC_LOCK_MAIN) {
lck.id = lc_id.proc_lock_main;
@@ -1256,7 +1261,7 @@ void
erts_proc_lc_unlock(Process *p, ErtsProcLocks locks)
{
erts_lc_lock_t lck = ERTS_LC_LOCK_INIT(-1,
- p->id,
+ p->common.id,
ERTS_LC_FLG_LT_PROCLOCK);
if (locks & ERTS_PROC_LOCK_STATUS) {
lck.id = lc_id.proc_lock_status;
@@ -1283,7 +1288,7 @@ erts_proc_lc_might_unlock(Process *p, ErtsProcLocks locks)
{
#if ERTS_PROC_LOCK_OWN_IMPL
erts_lc_lock_t lck = ERTS_LC_LOCK_INIT(-1,
- p->id,
+ p->common.id,
ERTS_LC_FLG_LT_PROCLOCK);
if (locks & ERTS_PROC_LOCK_STATUS) {
lck.id = lc_id.proc_lock_status;
@@ -1318,7 +1323,7 @@ erts_proc_lc_require_lock(Process *p, ErtsProcLocks locks)
{
#if ERTS_PROC_LOCK_OWN_IMPL
erts_lc_lock_t lck = ERTS_LC_LOCK_INIT(-1,
- p->id,
+ p->common.id,
ERTS_LC_FLG_LT_PROCLOCK);
if (locks & ERTS_PROC_LOCK_MAIN) {
lck.id = lc_id.proc_lock_main;
@@ -1353,7 +1358,7 @@ erts_proc_lc_unrequire_lock(Process *p, ErtsProcLocks locks)
{
#if ERTS_PROC_LOCK_OWN_IMPL
erts_lc_lock_t lck = ERTS_LC_LOCK_INIT(-1,
- p->id,
+ p->common.id,
ERTS_LC_FLG_LT_PROCLOCK);
if (locks & ERTS_PROC_LOCK_STATUS) {
lck.id = lc_id.proc_lock_status;
@@ -1390,7 +1395,7 @@ erts_proc_lc_trylock_force_busy(Process *p, ErtsProcLocks locks)
{
if (locks & ERTS_PROC_LOCKS_ALL) {
erts_lc_lock_t lck = ERTS_LC_LOCK_INIT(-1,
- p->id,
+ p->common.id,
ERTS_LC_FLG_LT_PROCLOCK);
if (locks & ERTS_PROC_LOCK_MAIN)
@@ -1415,7 +1420,7 @@ void erts_proc_lc_chk_only_proc_main(Process *p)
{
#if ERTS_PROC_LOCK_OWN_IMPL
erts_lc_lock_t proc_main = ERTS_LC_LOCK_INIT(lc_id.proc_lock_main,
- p->id,
+ p->common.id,
ERTS_LC_FLG_LT_PROCLOCK);
erts_lc_check_exact(&proc_main, 1);
#elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL
@@ -1439,19 +1444,19 @@ erts_proc_lc_chk_have_proc_locks(Process *p, ErtsProcLocks locks)
ERTS_PROC_LC_EMPTY_LOCK_INIT};
if (locks & ERTS_PROC_LOCK_MAIN) {
have_locks[have_locks_len].id = lc_id.proc_lock_main;
- have_locks[have_locks_len++].extra = p->id;
+ have_locks[have_locks_len++].extra = p->common.id;
}
if (locks & ERTS_PROC_LOCK_LINK) {
have_locks[have_locks_len].id = lc_id.proc_lock_link;
- have_locks[have_locks_len++].extra = p->id;
+ have_locks[have_locks_len++].extra = p->common.id;
}
if (locks & ERTS_PROC_LOCK_MSGQ) {
have_locks[have_locks_len].id = lc_id.proc_lock_msgq;
- have_locks[have_locks_len++].extra = p->id;
+ have_locks[have_locks_len++].extra = p->common.id;
}
if (locks & ERTS_PROC_LOCK_STATUS) {
have_locks[have_locks_len].id = lc_id.proc_lock_status;
- have_locks[have_locks_len++].extra = p->id;
+ have_locks[have_locks_len++].extra = p->common.id;
}
#elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL
erts_lc_lock_t have_locks[4];
@@ -1484,35 +1489,35 @@ erts_proc_lc_chk_proc_locks(Process *p, ErtsProcLocks locks)
if (locks & ERTS_PROC_LOCK_MAIN) {
have_locks[have_locks_len].id = lc_id.proc_lock_main;
- have_locks[have_locks_len++].extra = p->id;
+ have_locks[have_locks_len++].extra = p->common.id;
}
else {
have_not_locks[have_not_locks_len].id = lc_id.proc_lock_main;
- have_not_locks[have_not_locks_len++].extra = p->id;
+ have_not_locks[have_not_locks_len++].extra = p->common.id;
}
if (locks & ERTS_PROC_LOCK_LINK) {
have_locks[have_locks_len].id = lc_id.proc_lock_link;
- have_locks[have_locks_len++].extra = p->id;
+ have_locks[have_locks_len++].extra = p->common.id;
}
else {
have_not_locks[have_not_locks_len].id = lc_id.proc_lock_link;
- have_not_locks[have_not_locks_len++].extra = p->id;
+ have_not_locks[have_not_locks_len++].extra = p->common.id;
}
if (locks & ERTS_PROC_LOCK_MSGQ) {
have_locks[have_locks_len].id = lc_id.proc_lock_msgq;
- have_locks[have_locks_len++].extra = p->id;
+ have_locks[have_locks_len++].extra = p->common.id;
}
else {
have_not_locks[have_not_locks_len].id = lc_id.proc_lock_msgq;
- have_not_locks[have_not_locks_len++].extra = p->id;
+ have_not_locks[have_not_locks_len++].extra = p->common.id;
}
if (locks & ERTS_PROC_LOCK_STATUS) {
have_locks[have_locks_len].id = lc_id.proc_lock_status;
- have_locks[have_locks_len++].extra = p->id;
+ have_locks[have_locks_len++].extra = p->common.id;
}
else {
have_not_locks[have_not_locks_len].id = lc_id.proc_lock_status;
- have_not_locks[have_not_locks_len++].extra = p->id;
+ have_not_locks[have_not_locks_len++].extra = p->common.id;
}
#elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL
erts_lc_lock_t have_locks[4];
@@ -1547,16 +1552,16 @@ erts_proc_lc_my_proc_locks(Process *p)
ErtsProcLocks res = 0;
#if ERTS_PROC_LOCK_OWN_IMPL
erts_lc_lock_t locks[4] = {ERTS_LC_LOCK_INIT(lc_id.proc_lock_main,
- p->id,
+ p->common.id,
ERTS_LC_FLG_LT_PROCLOCK),
ERTS_LC_LOCK_INIT(lc_id.proc_lock_link,
- p->id,
+ p->common.id,
ERTS_LC_FLG_LT_PROCLOCK),
ERTS_LC_LOCK_INIT(lc_id.proc_lock_msgq,
- p->id,
+ p->common.id,
ERTS_LC_FLG_LT_PROCLOCK),
ERTS_LC_LOCK_INIT(lc_id.proc_lock_status,
- p->id,
+ p->common.id,
ERTS_LC_FLG_LT_PROCLOCK)};
#elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL
erts_lc_lock_t locks[4] = {p->lock.main.lc,
@@ -1587,7 +1592,7 @@ erts_proc_lc_chk_no_proc_locks(char *file, int line)
lc_id.proc_lock_msgq,
lc_id.proc_lock_status};
erts_lc_have_lock_ids(resv, ids, 4);
- if (resv[0] || resv[1] || resv[2] || resv[3]) {
+ if (!ERTS_IS_CRASH_DUMPING && (resv[0] || resv[1] || resv[2] || resv[3])) {
erts_lc_fail("%s:%d: Thread has process locks locked when expected "
"not to have any process locks locked",
file, line);
diff --git a/erts/emulator/beam/erl_process_lock.h b/erts/emulator/beam/erl_process_lock.h
index 4aec19c8c3..9dd503f3cb 100644
--- a/erts/emulator/beam/erl_process_lock.h
+++ b/erts/emulator/beam/erl_process_lock.h
@@ -176,8 +176,8 @@ typedef struct erts_proc_lock_t_ {
* on multiple processes, locks on processes with low process ids
* have to be locked before locks on processes with high process
* ids. E.g., if the main and the message queue locks are to be
- * locked on processes p1 and p2 and p1->id < p2->id, then locks
- * should be locked in the following order:
+ * locked on processes p1 and p2 and p1->common.id < p2->common.id,
+ * then locks should be locked in the following order:
* 1. main lock on p1
* 2. main lock on p2
* 3. message queue lock on p1
@@ -203,7 +203,7 @@ typedef struct erts_proc_lock_t_ {
& ~ERTS_PROC_LOCK_MAIN)
-#define ERTS_PIX_LOCKS_BITS 8
+#define ERTS_PIX_LOCKS_BITS 10
#define ERTS_NO_OF_PIX_LOCKS (1 << ERTS_PIX_LOCKS_BITS)
@@ -767,7 +767,7 @@ erts_smp_proc_lock(Process *p, ErtsProcLocks locks)
#if ERTS_PROC_LOCK_ATOMIC_IMPL
NULL,
#else
- ERTS_PID2PIXLOCK(p->id),
+ ERTS_PID2PIXLOCK(p->common.id),
#endif /*ERTS_PROC_LOCK_ATOMIC_IMPL*/
locks, file, line);
#elif defined(ERTS_SMP)
@@ -775,7 +775,7 @@ erts_smp_proc_lock(Process *p, ErtsProcLocks locks)
#if ERTS_PROC_LOCK_ATOMIC_IMPL
NULL,
#else
- ERTS_PID2PIXLOCK(p->id),
+ ERTS_PID2PIXLOCK(p->common.id),
#endif /*ERTS_PROC_LOCK_ATOMIC_IMPL*/
locks);
#endif /*ERTS_SMP*/
@@ -789,7 +789,7 @@ erts_smp_proc_unlock(Process *p, ErtsProcLocks locks)
#if ERTS_PROC_LOCK_ATOMIC_IMPL
NULL,
#else
- ERTS_PID2PIXLOCK(p->id),
+ ERTS_PID2PIXLOCK(p->common.id),
#endif
locks);
#endif
@@ -805,7 +805,7 @@ erts_smp_proc_trylock(Process *p, ErtsProcLocks locks)
#if ERTS_PROC_LOCK_ATOMIC_IMPL
NULL,
#else
- ERTS_PID2PIXLOCK(p->id),
+ ERTS_PID2PIXLOCK(p->common.id),
#endif
locks);
#endif
@@ -814,21 +814,15 @@ erts_smp_proc_trylock(Process *p, ErtsProcLocks locks)
ERTS_GLB_INLINE void erts_smp_proc_inc_refc(Process *p)
{
#ifdef ERTS_SMP
-#ifdef ERTS_ENABLE_LOCK_CHECK
- erts_aint32_t refc = erts_atomic32_inc_read_nob(&p->lock.refc);
- ERTS_SMP_LC_ASSERT(refc > 1);
-#else
- erts_atomic32_inc_nob(&p->lock.refc);
-#endif
+ erts_ptab_inc_refc(&p->common);
#endif
}
ERTS_GLB_INLINE void erts_smp_proc_dec_refc(Process *p)
{
#ifdef ERTS_SMP
- erts_aint32_t refc = erts_atomic32_dec_read_nob(&p->lock.refc);
- ERTS_SMP_LC_ASSERT(refc >= 0);
- if (refc == 0)
+ int referred = erts_ptab_dec_test_refc(&p->common);
+ if (!referred)
erts_free_proc(p);
#endif
}
@@ -836,10 +830,8 @@ ERTS_GLB_INLINE void erts_smp_proc_dec_refc(Process *p)
ERTS_GLB_INLINE void erts_smp_proc_add_refc(Process *p, Sint32 add_refc)
{
#ifdef ERTS_SMP
- erts_aint32_t refc = erts_atomic32_add_read_nob(&p->lock.refc,
- (erts_aint32_t) add_refc);
- ERTS_SMP_LC_ASSERT(refc >= 0);
- if (refc == 0)
+ int referred = erts_ptab_add_test_refc(&p->common, add_refc);
+ if (!referred)
erts_free_proc(p);
#endif
}
@@ -875,8 +867,7 @@ void erts_proc_safelock(Process *a_proc,
#define ERTS_P2P_FLG_TRY_LOCK (1 << 1)
#define ERTS_P2P_FLG_SMP_INC_REFC (1 << 2)
-#define ERTS_PROC_LOCK_BUSY ((Process *) &erts_proc_lock_busy)
-extern const Process erts_proc_lock_busy;
+#define ERTS_PROC_LOCK_BUSY ((Process *) &erts_invalid_process)
#define erts_pid2proc(PROC, HL, PID, NL) \
erts_pid2proc_opt((PROC), (HL), (PID), (NL), 0)
@@ -896,33 +887,24 @@ Process *erts_pid2proc_opt(Process *, ErtsProcLocks, Eterm, ErtsProcLocks, int);
ERTS_GLB_INLINE Process *erts_pix2proc(int ix)
{
Process *proc;
- ASSERT(0 <= ix && ix < erts_proc.max);
- proc = (Process *) erts_smp_atomic_read_nob(&erts_proc.tab[ix]);
+ ASSERT(0 <= ix && ix < erts_ptab_max(&erts_proc));
+ proc = (Process *) erts_ptab_pix2intptr_nob(&erts_proc, ix);
return proc == ERTS_PROC_LOCK_BUSY ? NULL : proc;
}
ERTS_GLB_INLINE Process *erts_proc_lookup_raw(Eterm pid)
{
Process *proc;
- int pix;
- /*
- * In SMP case: Only scheduler threads are allowed
- * to use this function. Other threads need to
- * atomicaly increment refc at lookup, i.e., use
- * erts_pid2proc_opt() with ERTS_P2P_FLG_SMP_INC_REFC.
- */
- ERTS_SMP_LC_ASSERT(erts_get_scheduler_id());
+ ERTS_SMP_LC_ASSERT(erts_thr_progress_lc_is_delaying());
if (is_not_internal_pid(pid))
return NULL;
- pix = internal_pid_index(pid);
- proc = (Process *) erts_smp_atomic_read_ddrb(&erts_proc.tab[pix]);
-
- if (proc && proc->id != pid)
+ proc = (Process *) erts_ptab_pix2intptr_ddrb(&erts_proc,
+ internal_pid_index(pid));
+ if (proc && proc->common.id != pid)
return NULL;
-
return proc;
}
diff --git a/erts/emulator/beam/erl_ptab.c b/erts/emulator/beam/erl_ptab.c
new file mode 100644
index 0000000000..87beeafa1a
--- /dev/null
+++ b/erts/emulator/beam/erl_ptab.c
@@ -0,0 +1,1566 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2012. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/*
+ * Description: Process/Port table implementation.
+ *
+ * Author: Rickard Green
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#define ERTS_PTAB_WANT_BIF_IMPL__
+#define ERTS_PTAB_WANT_DEBUG_FUNCS__
+#include "erl_ptab.h"
+#include "global.h"
+#include "erl_binary.h"
+
+typedef struct ErtsPTabListBifData_ ErtsPTabListBifData;
+
+#define ERTS_PTAB_LIST_BIF_TAB_INSPECT_INDICES_PER_RED 25
+#define ERTS_PTAB_LIST_BIF_TAB_CHUNK_SIZE 1000
+#define ERTS_PTAB_LIST_BIF_MIN_START_REDS \
+ (ERTS_PTAB_LIST_BIF_TAB_CHUNK_SIZE \
+ / ERTS_PTAB_LIST_BIF_TAB_INSPECT_INDICES_PER_RED)
+
+#define ERTS_PTAB_LIST_BIF_TAB_FREE_DELETED_REDS 1
+
+#define ERTS_PTAB_LIST_BIF_INSPECT_DELETED_PER_RED 10
+
+#define ERTS_PTAB_LIST_INSPECT_DELETED_MAX_REDS \
+ (ERTS_PTAB_LIST_BIF_TAB_CHUNK_SIZE \
+ / ERTS_PTAB_LIST_BIF_TAB_INSPECT_INDICES_PER_RED)
+
+
+#define ERTS_PTAB_LIST_BIF_BUILD_RESULT_CONSES_PER_RED 75
+
+#define ERTS_PTAB_LIST_DBG_DO_TRACE 0
+
+#ifdef DEBUG
+# define ERTS_PTAB_LIST_BIF_DEBUGLEVEL 100
+#else
+# define ERTS_PTAB_LIST_BIF_DEBUGLEVEL 0
+#endif
+
+#define ERTS_PTAB_LIST_DBGLVL_CHK_HALLOC 1
+#define ERTS_PTAB_LIST_DBGLVL_CHK_FOUND_PIDS 5
+#define ERTS_PTAB_LIST_DBGLVL_CHK_PIDS 10
+#define ERTS_PTAB_LIST_DBGLVL_CHK_DEL_LIST 20
+#define ERTS_PTAB_LIST_DBGLVL_CHK_RESLIST 20
+
+#if ERTS_PTAB_LIST_BIF_DEBUGLEVEL == 0
+# define ERTS_PTAB_LIST_ASSERT(EXP)
+#else
+# define ERTS_PTAB_LIST_ASSERT(EXP) \
+ ((void) ((EXP) \
+ ? 1 \
+ : (debug_ptab_list_assert_error(#EXP, \
+ __FILE__, \
+ __LINE__, \
+ __func__), \
+ 0)))
+#endif
+
+
+#if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_HALLOC
+# define ERTS_PTAB_LIST_DBG_SAVE_HEAP_ALLOC(PTLBDP, HP, SZ) \
+do { \
+ ERTS_PTAB_LIST_ASSERT(!(PTLBDP)->debug.heap); \
+ ERTS_PTAB_LIST_ASSERT(!(PTLBDP)->debug.heap_size); \
+ (PTLBDP)->debug.heap = (HP); \
+ (PTLBDP)->debug.heap_size = (SZ); \
+} while (0)
+# define ERTS_PTAB_LIST_DBG_VERIFY_HEAP_ALLOC_USED(PTLBDP, HP) \
+do { \
+ ERTS_PTAB_LIST_ASSERT((PTLBDP)->debug.heap); \
+ ERTS_PTAB_LIST_ASSERT((PTLBDP)->debug.heap_size); \
+ ERTS_PTAB_LIST_ASSERT(((PTLBDP)->debug.heap \
+ + (PTLBDP)->debug.heap_size) \
+ == (HP)); \
+ (PTLBDP)->debug.heap = NULL; \
+ (PTLBDP)->debug.heap_size = 0; \
+} while (0)
+# define ERTS_PTAB_LIST_DBG_HEAP_ALLOC_INIT(PTLBDP) \
+do { \
+ (PTLBDP)->debug.heap = NULL; \
+ (PTLBDP)->debug.heap_size = 0; \
+} while (0)
+#else
+# define ERTS_PTAB_LIST_DBG_SAVE_HEAP_ALLOC(PTLBDP, HP, SZ)
+# define ERTS_PTAB_LIST_DBG_VERIFY_HEAP_ALLOC_USED(PTLBDP, HP)
+# define ERTS_PTAB_LIST_DBG_HEAP_ALLOC_INIT(PTLBDP)
+#endif
+
+#if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_RESLIST
+# define ERTS_PTAB_LIST_DBG_CHK_RESLIST(R) \
+ debug_ptab_list_check_res_list((R))
+#else
+# define ERTS_PTAB_LIST_DBG_CHK_RESLIST(R)
+#endif
+
+#if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_PIDS
+# define ERTS_PTAB_LIST_DBG_SAVE_PIDS(PTLBDP) \
+ debug_ptab_list_save_all_pids((PTLBDP))
+# define ERTS_PTAB_LIST_DBG_VERIFY_PIDS(PTLBDP) \
+do { \
+ if (!(PTLBDP)->debug.correct_pids_verified) \
+ debug_ptab_list_verify_all_pids((PTLBDP)); \
+} while (0)
+# define ERTS_PTAB_LIST_DBG_CLEANUP_CHK_PIDS(PTLBDP) \
+do { \
+ if ((PTLBDP)->debug.correct_pids) { \
+ erts_free(ERTS_ALC_T_PTAB_LIST_PIDS, \
+ (PTLBDP)->debug.correct_pids); \
+ (PTLBDP)->debug.correct_pids = NULL; \
+ } \
+} while(0)
+# define ERTS_PTAB_LIST_DBG_CHK_PIDS_INIT(PTLBDP) \
+do { \
+ (PTLBDP)->debug.correct_pids_verified = 0; \
+ (PTLBDP)->debug.correct_pids = NULL; \
+} while (0)
+#else
+# define ERTS_PTAB_LIST_DBG_SAVE_PIDS(PTLBDP)
+# define ERTS_PTAB_LIST_DBG_VERIFY_PIDS(PTLBDP)
+# define ERTS_PTAB_LIST_DBG_CLEANUP_CHK_PIDS(PTLBDP)
+# define ERTS_PTAB_LIST_DBG_CHK_PIDS_INIT(PTLBDP)
+#endif
+
+#if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_FOUND_PIDS
+# define ERTS_PTAB_LIST_DBG_CHK_PID_FOUND(PTLBDP, PID, IC) \
+ debug_ptab_list_check_found_pid((PTLBDP), (PID), (IC), 1)
+# define ERTS_PTAB_LIST_DBG_CHK_PID_NOT_FOUND(PTLBDP, PID, IC) \
+ debug_ptab_list_check_found_pid((PTLBDP), (PID), (IC), 0)
+#else
+# define ERTS_PTAB_LIST_DBG_CHK_PID_FOUND(PTLBDP, PID, IC)
+# define ERTS_PTAB_LIST_DBG_CHK_PID_NOT_FOUND(PTLBDP, PID, IC)
+#endif
+
+#if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_DEL_LIST
+# define ERTS_PTAB_LIST_DBG_CHK_DEL_LIST(PTab) \
+ debug_ptab_list_check_del_list((PTab))
+# define ERTS_PTAB_LIST_DBG_CHK_FREELIST(PTab, FL) \
+ debug_ptab_list_check_del_free_list((PTab), (FL))
+#else
+# define ERTS_PTAB_LIST_DBG_CHK_DEL_LIST(PTab)
+# define ERTS_PTAB_LIST_DBG_CHK_FREELIST(PTab, FL)
+#endif
+
+#if ERTS_PTAB_LIST_BIF_DEBUGLEVEL == 0
+#if ERTS_PTAB_LIST_DBG_DO_TRACE
+# define ERTS_PTAB_LIST_DBG_INIT(P, PTLBDP) \
+ (PTLBDP)->debug.caller = (P)->common.id
+# else
+# define ERTS_PTAB_LIST_DBG_INIT(P, PTLBDP)
+# endif
+# define ERTS_PTAB_LIST_DBG_CLEANUP(PTLBDP)
+#else
+# define ERTS_PTAB_LIST_DBG_INIT(P, PTLBDP) \
+do { \
+ (PTLBDP)->debug.caller = (P)->common.id; \
+ ERTS_PTAB_LIST_DBG_HEAP_ALLOC_INIT((PTLBDP)); \
+ ERTS_PTAB_LIST_DBG_CHK_PIDS_INIT((PTLBDP)); \
+} while (0)
+# define ERTS_PTAB_LIST_DBG_CLEANUP(PTLBDP) \
+do { \
+ ERTS_PTAB_LIST_DBG_CLEANUP_CHK_PIDS((PTLBDP)); \
+} while (0)
+#endif
+
+#if ERTS_PTAB_LIST_DBG_DO_TRACE
+# define ERTS_PTAB_LIST_DBG_TRACE(PID, WHAT) \
+ erts_fprintf(stderr, "%T %s:%d:%s(): %s\n", \
+ (PID), __FILE__, __LINE__, __func__, #WHAT)
+#else
+# define ERTS_PTAB_LIST_DBG_TRACE(PID, WHAT)
+#endif
+
+
+#if ERTS_PTAB_LIST_BIF_DEBUGLEVEL != 0
+static void debug_ptab_list_assert_error(char* expr,
+ const char* file,
+ int line,
+ const char *func);
+#endif
+#if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_RESLIST
+static void debug_ptab_list_check_res_list(Eterm list);
+#endif
+#if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_PIDS
+static void debug_ptab_list_save_all_pids(ErtsPTabListBifData *ptlbdp);
+static void debug_ptab_list_verify_all_pids(ErtsPTabListBifData *ptlbdp);
+#endif
+#if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_FOUND_PIDS
+static void debug_ptab_list_check_found_pid(ErtsPTabListBifData *ptlbdp,
+ Eterm pid,
+ Uint64 ic,
+ int pid_should_be_found);
+#endif
+#if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_DEL_LIST
+static void debug_ptab_list_check_del_list(ErtsPTab *ptab);
+static void debug_ptab_list_check_del_free_list(ErtsPTab *ptab,
+ ErtsPTabDeletedElement *ptdep);
+#endif
+
+struct ErtsPTabDeletedElement_ {
+ ErtsPTabDeletedElement *next;
+ ErtsPTabDeletedElement *prev;
+ int ix;
+ union {
+ struct {
+ Eterm id;
+ Uint64 inserted;
+ Uint64 deleted;
+ } element;
+ struct {
+ Uint64 interval;
+ } bif_invocation;
+ } u;
+};
+
+static Export ptab_list_continue_export;
+
+typedef struct {
+ Uint64 interval;
+} ErtsPTabListBifChunkInfo;
+
+typedef enum {
+ INITIALIZING,
+ INSPECTING_TABLE,
+ INSPECTING_DELETED,
+ BUILDING_RESULT,
+ RETURN_RESULT
+} ErtsPTabListBifState;
+
+struct ErtsPTabListBifData_ {
+ ErtsPTab *ptab;
+ ErtsPTabListBifState state;
+ Eterm caller;
+ ErtsPTabListBifChunkInfo *chunk;
+ int tix;
+ int pid_ix;
+ int pid_sz;
+ Eterm *pid;
+ ErtsPTabDeletedElement *bif_invocation; /* Only used when > 1 chunk */
+
+#if ERTS_PTAB_LIST_BIF_DEBUGLEVEL != 0 || ERTS_PTAB_LIST_DBG_DO_TRACE
+ struct {
+ Eterm caller;
+#if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_FOUND_PIDS
+ Uint64 *pid_started;
+#endif
+#if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_HALLOC
+ Eterm *heap;
+ Uint heap_size;
+#endif
+#if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_PIDS
+ int correct_pids_verified;
+ Eterm *correct_pids;
+#endif
+ } debug;
+#endif
+
+};
+
+#ifdef ARCH_32
+
+static ERTS_INLINE Uint64
+dw_aint_to_uint64(erts_dw_aint_t *dw)
+{
+#ifdef ETHR_SU_DW_NAINT_T__
+ return (Uint64) dw->dw_sint;
+#else
+ Uint64 res;
+ res = (Uint64) ((Uint32) dw->sint[ERTS_DW_AINT_HIGH_WORD]);
+ res <<= 32;
+ res |= (Uint64) ((Uint32) dw->sint[ERTS_DW_AINT_LOW_WORD]);
+ return res;
+#endif
+}
+
+static void
+unint64_to_dw_aint(erts_dw_aint_t *dw, Uint64 val)
+{
+#ifdef ETHR_SU_DW_NAINT_T__
+ dw->dw_sint = (ETHR_SU_DW_NAINT_T__) val;
+#else
+ dw->sint[ERTS_DW_AINT_LOW_WORD] = (erts_aint_t) (val & 0xffffffff);
+ dw->sint[ERTS_DW_AINT_HIGH_WORD] = (erts_aint_t) ((val >> 32) & 0xffffffff);
+#endif
+}
+
+static ERTS_INLINE void
+last_data_init_nob(ErtsPTab *ptab, Uint64 val)
+{
+ erts_dw_aint_t dw;
+ unint64_to_dw_aint(&dw, val);
+ erts_smp_dw_atomic_init_nob(&ptab->vola.tile.last_data, &dw);
+}
+
+static ERTS_INLINE void
+last_data_set_relb(ErtsPTab *ptab, Uint64 val)
+{
+ erts_dw_aint_t dw;
+ unint64_to_dw_aint(&dw, val);
+ erts_smp_dw_atomic_set_relb(&ptab->vola.tile.last_data, &dw);
+}
+
+static ERTS_INLINE Uint64
+last_data_read_nob(ErtsPTab *ptab)
+{
+ erts_dw_aint_t dw;
+ erts_smp_dw_atomic_read_nob(&ptab->vola.tile.last_data, &dw);
+ return dw_aint_to_uint64(&dw);
+}
+
+static ERTS_INLINE Uint64
+last_data_read_acqb(ErtsPTab *ptab)
+{
+ erts_dw_aint_t dw;
+ erts_smp_dw_atomic_read_acqb(&ptab->vola.tile.last_data, &dw);
+ return dw_aint_to_uint64(&dw);
+}
+
+static ERTS_INLINE Uint64
+last_data_cmpxchg_relb(ErtsPTab *ptab, Uint64 new, Uint64 exp)
+{
+ erts_dw_aint_t dw_new, dw_xchg;
+
+ unint64_to_dw_aint(&dw_new, new);
+ unint64_to_dw_aint(&dw_xchg, exp);
+
+ if (erts_smp_dw_atomic_cmpxchg_relb(&ptab->vola.tile.last_data,
+ &dw_new,
+ &dw_xchg))
+ return exp;
+ else
+ return dw_aint_to_uint64(&dw_xchg);
+}
+
+#elif defined(ARCH_64)
+
+union {
+ erts_smp_atomic_t pid_data;
+ char align[ERTS_CACHE_LINE_SIZE];
+} last erts_align_attribute(ERTS_CACHE_LINE_SIZE);
+
+static ERTS_INLINE void
+last_data_init_nob(ErtsPTab *ptab, Uint64 val)
+{
+ erts_smp_atomic_init_nob(&ptab->vola.tile.last_data, (erts_aint_t) val);
+}
+
+static ERTS_INLINE void
+last_data_set_relb(ErtsPTab *ptab, Uint64 val)
+{
+ erts_smp_atomic_set_relb(&ptab->vola.tile.last_data, (erts_aint_t) val);
+}
+
+static ERTS_INLINE Uint64
+last_data_read_nob(ErtsPTab *ptab)
+{
+ return (Uint64) erts_smp_atomic_read_nob(&ptab->vola.tile.last_data);
+}
+
+static ERTS_INLINE Uint64
+last_data_read_acqb(ErtsPTab *ptab)
+{
+ return (Uint64) erts_smp_atomic_read_acqb(&ptab->vola.tile.last_data);
+}
+
+static ERTS_INLINE Uint64
+last_data_cmpxchg_relb(ErtsPTab *ptab, Uint64 new, Uint64 exp)
+{
+ return (Uint64) erts_smp_atomic_cmpxchg_relb(&ptab->vola.tile.last_data,
+ (erts_aint_t) new,
+ (erts_aint_t) exp);
+}
+
+#else
+# error "Not 64-bit, nor 32-bit architecture..."
+#endif
+
+static ERTS_INLINE int
+last_data_cmp(Uint64 ld1, Uint64 ld2)
+{
+ Uint64 ld1_wrap;
+
+ if (ld1 == ld2)
+ return 0;
+
+ ld1_wrap = ld1 + (((Uint64) 1) << 63);
+
+ if (ld1 < ld1_wrap)
+ return (ld1 < ld2 && ld2 < ld1_wrap) ? -1 : 1;
+ else
+ return (ld1_wrap <= ld2 && ld2 < ld1) ? 1 : -1;
+}
+
+#define ERTS_PTAB_LastData2EtermData(LD) \
+ ((Eterm) ((LD) & ~(~((Uint64) 0) << ERTS_PTAB_ID_DATA_SIZE)))
+
+void
+erts_ptab_init_table(ErtsPTab *ptab,
+ ErtsAlcType_t atype,
+ void (*release_element)(void *),
+ ErtsPTabElementCommon *invalid_element,
+ int size,
+ char *name)
+{
+ size_t tab_sz;
+ int bits;
+ char *tab_end;
+ erts_smp_atomic_t *tab_entry;
+ erts_smp_rwmtx_opt_t rwmtx_opts = ERTS_SMP_RWMTX_OPT_DEFAULT_INITER;
+ rwmtx_opts.type = ERTS_SMP_RWMTX_TYPE_EXTREMELY_FREQUENT_READ;
+ rwmtx_opts.lived = ERTS_SMP_RWMTX_LONG_LIVED;
+
+ erts_smp_rwmtx_init_opt(&ptab->list.data.rwmtx, &rwmtx_opts, name);
+ erts_smp_atomic32_init_nob(&ptab->vola.tile.count, 0);
+ last_data_init_nob(ptab, ~((Uint64) 0));
+
+ /* A size that is a power of 2 is to prefer performance wise */
+ bits = erts_fit_in_bits_int32(size-1);
+ size = 1 << bits;
+ if (size > ERTS_PTAB_MAX_SIZE) {
+ size = ERTS_PTAB_MAX_SIZE;
+ bits = erts_fit_in_bits_int32((Sint32) size - 1);
+ }
+
+ ptab->r.o.max = size;
+
+ tab_sz = ERTS_ALC_CACHE_LINE_ALIGN_SIZE(size*sizeof(erts_smp_atomic_t));
+ ptab->r.o.tab = erts_alloc_permanent_cache_aligned(atype, tab_sz);
+ tab_end = ((char *) ptab->r.o.tab) + tab_sz;
+ tab_entry = ptab->r.o.tab;
+ while (tab_end > ((char *) tab_entry)) {
+ erts_smp_atomic_init_nob(tab_entry, ERTS_AINT_NULL);
+ tab_entry++;
+ }
+
+ ptab->r.o.tab_cache_lines = tab_sz/ERTS_CACHE_LINE_SIZE;
+ ptab->r.o.pix_per_cache_line = (ERTS_CACHE_LINE_SIZE
+ / sizeof(erts_smp_atomic_t));
+ ASSERT((ptab->r.o.max & (ptab->r.o.max - 1)) == 0); /* power of 2 */
+ ASSERT((ptab->r.o.pix_per_cache_line
+ & (ptab->r.o.pix_per_cache_line - 1)) == 0); /* power of 2 */
+ ASSERT((ptab->r.o.tab_cache_lines
+ & (ptab->r.o.tab_cache_lines - 1)) == 0); /* power of 2 */
+
+ ptab->r.o.pix_mask
+ = (1 << bits) - 1;
+ ptab->r.o.pix_cl_mask
+ = ptab->r.o.tab_cache_lines-1;
+ ptab->r.o.pix_cl_shift
+ = erts_fit_in_bits_int32(ptab->r.o.pix_per_cache_line-1);
+ ptab->r.o.pix_cli_shift
+ = erts_fit_in_bits_int32(ptab->r.o.pix_cl_mask);
+ ptab->r.o.pix_cli_mask
+ = (1 << (bits - ptab->r.o.pix_cli_shift)) - 1;
+
+ ASSERT(ptab->r.o.pix_cl_shift + ptab->r.o.pix_cli_shift == bits);
+
+ ptab->r.o.invalid_element = invalid_element;
+ ptab->r.o.invalid_data = erts_ptab_id2data(ptab, invalid_element->id);
+ ptab->r.o.release_element = release_element;
+
+ erts_smp_interval_init(&ptab->list.data.interval);
+ ptab->list.data.deleted.start = NULL;
+ ptab->list.data.deleted.end = NULL;
+ ptab->list.data.chunks = (((ptab->r.o.max - 1)
+ / ERTS_PTAB_LIST_BIF_TAB_CHUNK_SIZE)
+ + 1);
+
+ if (size == ERTS_PTAB_MAX_SIZE) {
+ int pix;
+ /*
+ * We want a table size of a power of 2 which ERTS_PTAB_MAX_SIZE
+ * is. We only have ERTS_PTAB_MAX_SIZE-1 unique identifiers and
+ * we don't want to shrink the size to ERTS_PTAB_MAX_SIZE/2.
+ *
+ * In order to fix this, we insert a pointer from the table
+ * to the invalid_element, wich will be interpreted as a
+ * slot currently being modified. This way we will be able to
+ * have ERTS_PTAB_MAX_SIZE-1 valid elements in the table while
+ * still having a table size of the power of 2.
+ */
+ erts_smp_atomic32_inc_nob(&ptab->vola.tile.count);
+ pix = erts_ptab_data2pix(ptab, ptab->r.o.invalid_data);
+ erts_smp_atomic_set_relb(&ptab->r.o.tab[pix],
+ (erts_aint_t) ptab->r.o.invalid_element);
+ }
+
+}
+
+int
+erts_ptab_initialized(ErtsPTab *ptab)
+{
+ return ptab->r.o.tab != NULL;
+}
+
+int
+erts_ptab_new_element(ErtsPTab *ptab,
+ ErtsPTabElementCommon *ptab_el,
+ void *init_arg,
+ void (*init_ptab_el)(void *, Eterm))
+{
+ int pix;
+ Uint64 ld, exp_ld;
+ Eterm data;
+ erts_aint32_t count;
+ erts_aint_t invalid = (erts_aint_t) ptab->r.o.invalid_element;
+
+ erts_ptab_rlock(ptab);
+
+ count = erts_smp_atomic32_inc_read_acqb(&ptab->vola.tile.count);
+ if (count > ptab->r.o.max) {
+ while (1) {
+ erts_aint32_t act_count;
+
+ act_count = erts_smp_atomic32_cmpxchg_relb(&ptab->vola.tile.count,
+ count-1,
+ count);
+ if (act_count == count) {
+ erts_ptab_runlock(ptab);
+ return 0;
+ }
+ count = act_count;
+ if (count <= ptab->r.o.max)
+ break;
+ }
+ }
+
+ ptab_el->u.alive.started_interval
+ = erts_smp_current_interval_nob(erts_ptab_interval(ptab));
+
+ ld = last_data_read_acqb(ptab);
+
+ /* Reserve slot */
+ while (1) {
+ ld++;
+ pix = erts_ptab_data2pix(ptab, ERTS_PTAB_LastData2EtermData(ld));
+ if (erts_smp_atomic_read_nob(&ptab->r.o.tab[pix]) == ERTS_AINT_NULL) {
+ erts_aint_t val;
+ val = erts_smp_atomic_cmpxchg_relb(&ptab->r.o.tab[pix],
+ invalid,
+ ERTS_AINT_NULL);
+
+ if (ERTS_AINT_NULL == val)
+ break;
+ }
+ }
+
+ data = ERTS_PTAB_LastData2EtermData(ld);
+
+ if (data == ptab->r.o.invalid_data) {
+ /* Do not use invalid data; fix it... */
+ ld += ptab->r.o.max;
+ ASSERT(pix == erts_ptab_data2pix(ptab,
+ ERTS_PTAB_LastData2EtermData(ld)));
+ data = ERTS_PTAB_LastData2EtermData(ld);
+ ASSERT(data != ptab->r.o.invalid_data);
+ }
+
+ exp_ld = last_data_read_nob(ptab);
+
+ /* Move last data forward */
+ while (1) {
+ Uint64 act_ld;
+ if (last_data_cmp(ld, exp_ld) < 0)
+ break;
+ act_ld = last_data_cmpxchg_relb(ptab, ld, exp_ld);
+ if (act_ld == exp_ld)
+ break;
+ exp_ld = act_ld;
+ }
+
+ init_ptab_el(init_arg, data);
+
+#ifdef ERTS_SMP
+ erts_smp_atomic32_init_nob(&ptab_el->refc, 1);
+#endif
+
+ /* Move into slot reserved */
+#ifdef DEBUG
+ ASSERT(invalid == erts_smp_atomic_xchg_relb(&ptab->r.o.tab[pix],
+ (erts_aint_t) ptab_el));
+#else
+ erts_smp_atomic_set_relb(&ptab->r.o.tab[pix], (erts_aint_t) ptab_el);
+#endif
+
+ erts_ptab_runlock(ptab);
+
+ return 1;
+}
+
+static void
+save_deleted_element(ErtsPTab *ptab, ErtsPTabElementCommon *ptab_el)
+{
+ ErtsPTabDeletedElement *ptdep = erts_alloc(ERTS_ALC_T_PTAB_LIST_DEL,
+ sizeof(ErtsPTabDeletedElement));
+ ERTS_PTAB_LIST_ASSERT(ptab->list.data.deleted.start
+ && ptab->list.data.deleted.end);
+ ERTS_SMP_LC_ASSERT(erts_smp_lc_ptab_is_rwlocked(ptab));
+
+ ERTS_PTAB_LIST_DBG_CHK_DEL_LIST(ptab);
+
+ ptdep->prev = ptab->list.data.deleted.end;
+ ptdep->next = NULL;
+ ptdep->ix = erts_ptab_id2pix(ptab, ptab_el->id);
+ ptdep->u.element.id = ptab_el->id;
+ ptdep->u.element.inserted = ptab_el->u.alive.started_interval;
+ ptdep->u.element.deleted =
+ erts_smp_current_interval_nob(erts_ptab_interval(ptab));
+
+ ptab->list.data.deleted.end->next = ptdep;
+ ptab->list.data.deleted.end = ptdep;
+
+ ERTS_PTAB_LIST_DBG_CHK_DEL_LIST(ptab);
+
+ ERTS_PTAB_LIST_ASSERT(ptdep->prev->ix >= 0
+ ? (ptdep->u.element.deleted
+ >= ptdep->prev->u.element.deleted)
+ : (ptdep->u.element.deleted
+ >= ptdep->prev->u.bif_invocation.interval));
+}
+
+void
+erts_ptab_delete_element(ErtsPTab *ptab,
+ ErtsPTabElementCommon *ptab_el)
+{
+ int maybe_save;
+ int pix = erts_ptab_id2pix(ptab, ptab_el->id);
+
+ ASSERT(erts_get_scheduler_id()); /* *Need* to be a scheduler */
+
+ erts_ptab_rlock(ptab);
+ maybe_save = ptab->list.data.deleted.end != NULL;
+ if (maybe_save) {
+ erts_ptab_runlock(ptab);
+ erts_ptab_rwlock(ptab);
+ }
+
+ erts_smp_atomic_set_relb(&ptab->r.o.tab[pix], ERTS_AINT_NULL);
+
+ ASSERT(erts_smp_atomic32_read_nob(&ptab->vola.tile.count) > 0);
+ erts_smp_atomic32_dec_relb(&ptab->vola.tile.count);
+
+ if (!maybe_save)
+ erts_ptab_runlock(ptab);
+ else {
+ if (ptab->list.data.deleted.end)
+ save_deleted_element(ptab, ptab_el);
+ erts_ptab_rwunlock(ptab);
+ }
+
+ if (ptab->r.o.release_element)
+ erts_schedule_thr_prgr_later_op(ptab->r.o.release_element,
+ (void *) ptab_el,
+ &ptab_el->u.release);
+}
+
+/*
+ * erts_ptab_list() implements BIFs listing the content of the table,
+ * e.g. erlang:processes/0.
+ */
+static void cleanup_ptab_list_bif_data(Binary *bp);
+static int ptab_list_bif_engine(Process *c_p, Eterm *res_accp, Binary *mbp);
+
+
+BIF_RETTYPE
+erts_ptab_list(Process *c_p, ErtsPTab *ptab)
+{
+ /*
+ * A requirement: The list of identifiers returned should be a
+ * consistent snapshot of all elements existing
+ * in the table at some point in time during the
+ * execution of the BIF calling this function.
+ * Since elements might be deleted while the BIF
+ * is executing, we have to keep track of all
+ * deleted elements and add them to the result.
+ * We also ignore elements created after the BIF
+ * has begun executing.
+ */
+ BIF_RETTYPE ret_val;
+ Eterm res_acc = NIL;
+ Binary *mbp = erts_create_magic_binary(sizeof(ErtsPTabListBifData),
+ cleanup_ptab_list_bif_data);
+ ErtsPTabListBifData *ptlbdp = ERTS_MAGIC_BIN_DATA(mbp);
+
+ ERTS_PTAB_LIST_DBG_TRACE(c_p->common.id, call);
+ ptlbdp->ptab = ptab;
+ ptlbdp->state = INITIALIZING;
+ ERTS_PTAB_LIST_DBG_INIT(c_p, ptlbdp);
+
+ if (ERTS_BIF_REDS_LEFT(c_p) >= ERTS_PTAB_LIST_BIF_MIN_START_REDS
+ && ptab_list_bif_engine(c_p, &res_acc, mbp)) {
+ erts_bin_free(mbp);
+ ERTS_PTAB_LIST_DBG_CHK_RESLIST(res_acc);
+ ERTS_PTAB_LIST_DBG_TRACE(c_p->common.id, return);
+ ERTS_BIF_PREP_RET(ret_val, res_acc);
+ }
+ else {
+ Eterm *hp;
+ Eterm magic_bin;
+ ERTS_PTAB_LIST_DBG_CHK_RESLIST(res_acc);
+ hp = HAlloc(c_p, PROC_BIN_SIZE);
+ ERTS_PTAB_LIST_DBG_SAVE_HEAP_ALLOC(ptlbdp, hp, PROC_BIN_SIZE);
+ magic_bin = erts_mk_magic_binary_term(&hp, &MSO(c_p), mbp);
+ ERTS_PTAB_LIST_DBG_VERIFY_HEAP_ALLOC_USED(ptlbdp, hp);
+ ERTS_PTAB_LIST_DBG_TRACE(c_p->common.id, trap);
+ ERTS_BIF_PREP_YIELD2(ret_val,
+ &ptab_list_continue_export,
+ c_p,
+ res_acc,
+ magic_bin);
+ }
+ return ret_val;
+}
+
+static void
+cleanup_ptab_list_bif_data(Binary *bp)
+{
+ ErtsPTabListBifData *ptlbdp = ERTS_MAGIC_BIN_DATA(bp);
+ ErtsPTab *ptab = ptlbdp->ptab;
+
+ ERTS_PTAB_LIST_DBG_TRACE(ptlbdp->debug.caller, call);
+
+ if (ptlbdp->state != INITIALIZING) {
+
+ if (ptlbdp->chunk) {
+ erts_free(ERTS_ALC_T_PTAB_LIST_CNKI, ptlbdp->chunk);
+ ptlbdp->chunk = NULL;
+ }
+ if (ptlbdp->pid) {
+ erts_free(ERTS_ALC_T_PTAB_LIST_PIDS, ptlbdp->pid);
+ ptlbdp->pid = NULL;
+ }
+
+#if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_FOUND_PIDS
+ if (ptlbdp->debug.pid_started) {
+ erts_free(ERTS_ALC_T_PTAB_LIST_PIDS, ptlbdp->debug.pid_started);
+ ptlbdp->debug.pid_started = NULL;
+ }
+#endif
+
+ if (ptlbdp->bif_invocation) {
+ ErtsPTabDeletedElement *ptdep;
+
+ erts_ptab_rwlock(ptab);
+
+ ERTS_PTAB_LIST_DBG_TRACE(ptlbdp->debug.caller, deleted_cleanup);
+
+ ptdep = ptlbdp->bif_invocation;
+ ptlbdp->bif_invocation = NULL;
+
+ ERTS_PTAB_LIST_DBG_CHK_DEL_LIST(ptab);
+
+ if (ptdep->prev) {
+ /*
+ * Only remove this bif invokation when we
+ * have preceding invokations.
+ */
+ ptdep->prev->next = ptdep->next;
+ if (ptdep->next)
+ ptdep->next->prev = ptdep->prev;
+ else {
+ /*
+ * At the time of writing this branch cannot be
+ * reached. I don't want to remove this code though
+ * since it may be possible to reach this line
+ * in the future if the cleanup order in
+ * erts_do_exit_process() is changed. The ASSERT(0)
+ * is only here to make us aware that the reorder
+ * has happened. /rickard
+ */
+ ASSERT(0);
+ ptab->list.data.deleted.end = ptdep->prev;
+ }
+ erts_free(ERTS_ALC_T_PTAB_LIST_DEL, ptdep);
+ }
+ else {
+ /*
+ * Free all elements until next bif invokation
+ * is found.
+ */
+ ERTS_PTAB_LIST_ASSERT(ptab->list.data.deleted.start == ptdep);
+ do {
+ ErtsPTabDeletedElement *fptdep = ptdep;
+ ptdep = ptdep->next;
+ erts_free(ERTS_ALC_T_PTAB_LIST_DEL, fptdep);
+ } while (ptdep && ptdep->ix >= 0);
+ ptab->list.data.deleted.start = ptdep;
+ if (ptdep)
+ ptdep->prev = NULL;
+ else
+ ptab->list.data.deleted.end = NULL;
+ }
+
+ ERTS_PTAB_LIST_DBG_CHK_DEL_LIST(ptab);
+
+ erts_ptab_rwunlock(ptab);
+
+ }
+ }
+
+ ERTS_PTAB_LIST_DBG_TRACE(ptlbdp->debug.caller, return);
+ ERTS_PTAB_LIST_DBG_CLEANUP(ptlbdp);
+}
+
+static int
+ptab_list_bif_engine(Process *c_p, Eterm *res_accp, Binary *mbp)
+{
+ ErtsPTabListBifData *ptlbdp = ERTS_MAGIC_BIN_DATA(mbp);
+ ErtsPTab *ptab = ptlbdp->ptab;
+ int have_reds;
+ int reds;
+ int locked = 0;
+
+ do {
+ switch (ptlbdp->state) {
+ case INITIALIZING:
+ ptlbdp->chunk = erts_alloc(ERTS_ALC_T_PTAB_LIST_CNKI,
+ (sizeof(ErtsPTabListBifChunkInfo)
+ * ptab->list.data.chunks));
+ ptlbdp->tix = 0;
+ ptlbdp->pid_ix = 0;
+
+ erts_ptab_rwlock(ptab);
+ locked = 1;
+
+ ERTS_PTAB_LIST_DBG_TRACE(c_p->common.id, init);
+
+ ptlbdp->pid_sz = erts_ptab_count(ptab);
+ ptlbdp->pid = erts_alloc(ERTS_ALC_T_PTAB_LIST_PIDS,
+ sizeof(Eterm)*ptlbdp->pid_sz);
+
+#if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_FOUND_PIDS
+ ptlbdp->debug.pid_started
+ = erts_alloc(ERTS_ALC_T_PTAB_LIST_PIDS,
+ sizeof(Uint64)*ptlbdp->pid_sz);
+#endif
+
+ ERTS_PTAB_LIST_DBG_SAVE_PIDS(ptlbdp);
+
+ if (ptab->list.data.chunks == 1)
+ ptlbdp->bif_invocation = NULL;
+ else {
+ /*
+ * We will have to access the table multiple times
+ * releasing the table lock in between chunks.
+ */
+ ptlbdp->bif_invocation
+ = erts_alloc(ERTS_ALC_T_PTAB_LIST_DEL,
+ sizeof(ErtsPTabDeletedElement));
+ ptlbdp->bif_invocation->ix = -1;
+ ptlbdp->bif_invocation->u.bif_invocation.interval
+ = erts_smp_step_interval_nob(erts_ptab_interval(ptab));
+ ERTS_PTAB_LIST_DBG_CHK_DEL_LIST(ptab);
+
+ ptlbdp->bif_invocation->next = NULL;
+ if (ptab->list.data.deleted.end) {
+ ptlbdp->bif_invocation->prev = ptab->list.data.deleted.end;
+ ptab->list.data.deleted.end->next = ptlbdp->bif_invocation;
+ ERTS_PTAB_LIST_ASSERT(ptab->list.data.deleted.start);
+ }
+ else {
+ ptlbdp->bif_invocation->prev = NULL;
+ ptab->list.data.deleted.start = ptlbdp->bif_invocation;
+ }
+ ptab->list.data.deleted.end = ptlbdp->bif_invocation;
+
+ ERTS_PTAB_LIST_DBG_CHK_DEL_LIST(ptab);
+
+ }
+
+ ptlbdp->state = INSPECTING_TABLE;
+ /* Fall through */
+
+ case INSPECTING_TABLE: {
+ int ix = ptlbdp->tix;
+ int indices = ERTS_PTAB_LIST_BIF_TAB_CHUNK_SIZE;
+ int cix = ix / ERTS_PTAB_LIST_BIF_TAB_CHUNK_SIZE;
+ int end_ix = ix + indices;
+ Uint64 *invocation_interval_p;
+ ErtsPTabElementCommon *invalid_element;
+
+ invocation_interval_p
+ = (ptlbdp->bif_invocation
+ ? &ptlbdp->bif_invocation->u.bif_invocation.interval
+ : NULL);
+
+ ERTS_PTAB_LIST_ASSERT(is_nil(*res_accp));
+ if (!locked) {
+ erts_ptab_rwlock(ptab);
+ locked = 1;
+ }
+
+ ERTS_SMP_LC_ASSERT(erts_smp_lc_ptab_is_rwlocked(ptab));
+ ERTS_PTAB_LIST_DBG_TRACE(p->common.id, insp_table);
+
+ if (cix != 0)
+ ptlbdp->chunk[cix].interval
+ = erts_smp_step_interval_nob(erts_ptab_interval(ptab));
+ else if (ptlbdp->bif_invocation)
+ ptlbdp->chunk[0].interval = *invocation_interval_p;
+ /* else: interval is irrelevant */
+
+ if (end_ix >= ptab->r.o.max) {
+ ERTS_PTAB_LIST_ASSERT(cix+1 == ptab->list.data.chunks);
+ end_ix = ptab->r.o.max;
+ indices = end_ix - ix;
+ /* What to do when done with this chunk */
+ ptlbdp->state = (ptab->list.data.chunks == 1
+ ? BUILDING_RESULT
+ : INSPECTING_DELETED);
+ }
+
+ invalid_element = ptab->r.o.invalid_element;
+ for (; ix < end_ix; ix++) {
+ ErtsPTabElementCommon *el;
+ el = (ErtsPTabElementCommon *) erts_ptab_pix2intptr_nob(ptab,
+ ix);
+ if (el
+ && el != invalid_element
+ && (!invocation_interval_p
+ || el->u.alive.started_interval < *invocation_interval_p)) {
+ ERTS_PTAB_LIST_ASSERT(erts_ptab_is_valid_id(el->id));
+ ptlbdp->pid[ptlbdp->pid_ix] = el->id;
+
+#if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_FOUND_PIDS
+ ptlbdp->debug.pid_started[ptlbdp->pid_ix]
+ = el->u.alive.started_interval;
+#endif
+
+ ptlbdp->pid_ix++;
+ ERTS_PTAB_LIST_ASSERT(ptlbdp->pid_ix <= ptlbdp->pid_sz);
+ }
+ }
+
+ ptlbdp->tix = end_ix;
+
+ erts_ptab_rwunlock(ptab);
+ locked = 0;
+
+ reds = indices/ERTS_PTAB_LIST_BIF_TAB_INSPECT_INDICES_PER_RED;
+ BUMP_REDS(c_p, reds);
+
+ have_reds = ERTS_BIF_REDS_LEFT(c_p);
+
+ if (have_reds && ptlbdp->state == INSPECTING_TABLE) {
+ ix = ptlbdp->tix;
+ indices = ERTS_PTAB_LIST_BIF_TAB_CHUNK_SIZE;
+ end_ix = ix + indices;
+ if (end_ix > ptab->r.o.max) {
+ end_ix = ptab->r.o.max;
+ indices = end_ix - ix;
+ }
+
+ reds = indices/ERTS_PTAB_LIST_BIF_TAB_INSPECT_INDICES_PER_RED;
+
+ /* Pretend we have no reds left if we haven't got enough
+ reductions to complete next chunk */
+ if (reds > have_reds)
+ have_reds = 0;
+ }
+
+ break;
+ }
+
+ case INSPECTING_DELETED: {
+ int i;
+ int max_reds;
+ int free_deleted = 0;
+ Uint64 invocation_interval;
+ ErtsPTabDeletedElement *ptdep;
+ ErtsPTabDeletedElement *free_list = NULL;
+
+ ptdep = ptlbdp->bif_invocation;
+ ERTS_PTAB_LIST_ASSERT(ptdep);
+ invocation_interval = ptdep->u.bif_invocation.interval;
+
+ max_reds = have_reds = ERTS_BIF_REDS_LEFT(c_p);
+ if (max_reds > ERTS_PTAB_LIST_INSPECT_DELETED_MAX_REDS)
+ max_reds = ERTS_PTAB_LIST_INSPECT_DELETED_MAX_REDS;
+
+ reds = 0;
+ erts_ptab_rwlock(ptab);
+ ERTS_PTAB_LIST_DBG_TRACE(p->common.id, insp_term_procs);
+
+ ERTS_PTAB_LIST_DBG_CHK_DEL_LIST(ptab);
+
+ if (ptdep->prev)
+ ptdep->prev->next = ptdep->next;
+ else {
+ ERTS_PTAB_LIST_ASSERT(ptab->list.data.deleted.start == ptdep);
+ ptab->list.data.deleted.start = ptdep->next;
+
+ if (ptab->list.data.deleted.start
+ && ptab->list.data.deleted.start->ix >= 0) {
+ free_list = ptab->list.data.deleted.start;
+ free_deleted = 1;
+ }
+ }
+
+ if (ptdep->next)
+ ptdep->next->prev = ptdep->prev;
+ else
+ ptab->list.data.deleted.end = ptdep->prev;
+
+ ptdep = ptdep->next;
+
+ i = 0;
+ while (reds < max_reds && ptdep) {
+ if (ptdep->ix < 0) {
+ if (free_deleted) {
+ ERTS_PTAB_LIST_ASSERT(free_list);
+ ERTS_PTAB_LIST_ASSERT(ptdep->prev);
+
+ ptdep->prev->next = NULL; /* end of free_list */
+ ptab->list.data.deleted.start = ptdep;
+ ptdep->prev = NULL;
+ free_deleted = 0;
+ }
+ }
+ else {
+ int cix = ptdep->ix/ERTS_PTAB_LIST_BIF_TAB_CHUNK_SIZE;
+ Uint64 chunk_interval = ptlbdp->chunk[cix].interval;
+ Eterm pid = ptdep->u.element.id;
+ ERTS_PTAB_LIST_ASSERT(erts_ptab_is_valid_id(pid));
+
+ if (ptdep->u.element.inserted < invocation_interval) {
+ if (ptdep->u.element.deleted < chunk_interval) {
+ ERTS_PTAB_LIST_DBG_CHK_PID_NOT_FOUND(
+ ptlbdp,
+ pid,
+ ptdep->u.element.inserted);
+ ptlbdp->pid[ptlbdp->pid_ix] = pid;
+#if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_FOUND_PIDS
+ ptlbdp->debug.pid_started[ptlbdp->pid_ix]
+ = ptdep->u.element.inserted;
+#endif
+ ptlbdp->pid_ix++;
+ ERTS_PTAB_LIST_ASSERT(ptlbdp->pid_ix
+ <= ptlbdp->pid_sz);
+ }
+ else {
+ ERTS_PTAB_LIST_DBG_CHK_PID_FOUND(
+ ptlbdp,
+ pid,
+ ptdep->u.element.inserted);
+ }
+ }
+ else {
+ ERTS_PTAB_LIST_DBG_CHK_PID_NOT_FOUND(
+ ptlbdp,
+ pid,
+ ptdep->u.element.inserted);
+ }
+
+ i++;
+ if (i == ERTS_PTAB_LIST_BIF_INSPECT_DELETED_PER_RED) {
+ reds++;
+ i = 0;
+ }
+ if (free_deleted)
+ reds += ERTS_PTAB_LIST_BIF_TAB_FREE_DELETED_REDS;
+ }
+ ptdep = ptdep->next;
+ }
+
+ if (free_deleted) {
+ ERTS_PTAB_LIST_ASSERT(free_list);
+ ptab->list.data.deleted.start = ptdep;
+ if (!ptdep)
+ ptab->list.data.deleted.end = NULL;
+ else {
+ ERTS_PTAB_LIST_ASSERT(ptdep->prev);
+ ptdep->prev->next = NULL; /* end of free_list */
+ ptdep->prev = NULL;
+ }
+ }
+
+ if (!ptdep) {
+ /* Done */
+ ERTS_PTAB_LIST_ASSERT(ptlbdp->pid_ix == ptlbdp->pid_sz);
+ ptlbdp->state = BUILDING_RESULT;
+ ptlbdp->bif_invocation->next = free_list;
+ free_list = ptlbdp->bif_invocation;
+ ptlbdp->bif_invocation = NULL;
+ }
+ else {
+ /* Link in bif_invocation again where we left off */
+ ptlbdp->bif_invocation->prev = ptdep->prev;
+ ptlbdp->bif_invocation->next = ptdep;
+ ptdep->prev = ptlbdp->bif_invocation;
+ if (ptlbdp->bif_invocation->prev)
+ ptlbdp->bif_invocation->prev->next = ptlbdp->bif_invocation;
+ else {
+ ERTS_PTAB_LIST_ASSERT(ptab->list.data.deleted.start
+ == ptdep);
+ ptab->list.data.deleted.start = ptlbdp->bif_invocation;
+ }
+ }
+
+ ERTS_PTAB_LIST_DBG_CHK_DEL_LIST(ptab);
+ ERTS_PTAB_LIST_DBG_CHK_FREELIST(ptab, free_list);
+ erts_ptab_rwunlock(ptab);
+
+ /*
+ * We do the actual free of deleted structures now when we
+ * have released the table lock instead of when we encountered
+ * them. This since free() isn't for free and we don't want to
+ * unnecessarily block other schedulers.
+ */
+ while (free_list) {
+ ptdep = free_list;
+ free_list = ptdep->next;
+ erts_free(ERTS_ALC_T_PTAB_LIST_DEL, ptdep);
+ }
+
+ have_reds -= reds;
+ if (have_reds < 0)
+ have_reds = 0;
+ BUMP_REDS(c_p, reds);
+ break;
+ }
+
+ case BUILDING_RESULT: {
+ int conses, ix, min_ix;
+ Eterm *hp;
+ Eterm res = *res_accp;
+
+ ERTS_PTAB_LIST_DBG_VERIFY_PIDS(ptlbdp);
+ ERTS_PTAB_LIST_DBG_CHK_RESLIST(res);
+
+ ERTS_PTAB_LIST_DBG_TRACE(p->common.id, begin_build_res);
+
+ have_reds = ERTS_BIF_REDS_LEFT(c_p);
+ conses = ERTS_PTAB_LIST_BIF_BUILD_RESULT_CONSES_PER_RED*have_reds;
+ min_ix = ptlbdp->pid_ix - conses;
+ if (min_ix < 0) {
+ min_ix = 0;
+ conses = ptlbdp->pid_ix;
+ }
+
+ if (conses) {
+ hp = HAlloc(c_p, conses*2);
+ ERTS_PTAB_LIST_DBG_SAVE_HEAP_ALLOC(ptlbdp, hp, conses*2);
+
+ for (ix = ptlbdp->pid_ix - 1; ix >= min_ix; ix--) {
+ ERTS_PTAB_LIST_ASSERT(erts_ptab_is_valid_id(ptlbdp->pid[ix]));
+ res = CONS(hp, ptlbdp->pid[ix], res);
+ hp += 2;
+ }
+
+ ERTS_PTAB_LIST_DBG_VERIFY_HEAP_ALLOC_USED(ptlbdp, hp);
+ }
+
+ ptlbdp->pid_ix = min_ix;
+ if (min_ix == 0)
+ ptlbdp->state = RETURN_RESULT;
+ else {
+ ptlbdp->pid_sz = min_ix;
+ ptlbdp->pid = erts_realloc(ERTS_ALC_T_PTAB_LIST_PIDS,
+ ptlbdp->pid,
+ sizeof(Eterm)*ptlbdp->pid_sz);
+#if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_FOUND_PIDS
+ ptlbdp->debug.pid_started
+ = erts_realloc(ERTS_ALC_T_PTAB_LIST_PIDS,
+ ptlbdp->debug.pid_started,
+ sizeof(Uint64) * ptlbdp->pid_sz);
+#endif
+ }
+ reds = conses/ERTS_PTAB_LIST_BIF_BUILD_RESULT_CONSES_PER_RED;
+ BUMP_REDS(c_p, reds);
+ have_reds -= reds;
+
+ ERTS_PTAB_LIST_DBG_CHK_RESLIST(res);
+ ERTS_PTAB_LIST_DBG_TRACE(c_p->common.id, end_build_res);
+ *res_accp = res;
+ break;
+ }
+ case RETURN_RESULT:
+ cleanup_ptab_list_bif_data(mbp);
+ return 1;
+
+ default:
+ erl_exit(ERTS_ABORT_EXIT,
+ "%s:%d:ptab_list_bif_engine(): Invalid state: %d\n",
+ __FILE__, __LINE__, (int) ptlbdp->state);
+ }
+
+
+ } while (have_reds || ptlbdp->state == RETURN_RESULT);
+
+ return 0;
+}
+
+/*
+ * ptab_list_continue/2 is a hidden BIF that the original BIF traps to
+ * if there are too much work to do in one go.
+ */
+
+static BIF_RETTYPE ptab_list_continue(BIF_ALIST_2)
+{
+ Eterm res_acc;
+ Binary *mbp;
+
+ /*
+ * This bif cannot be called from erlang code. It can only be
+ * trapped to from other BIFs; therefore, a bad argument
+ * is an internal error and should never occur...
+ */
+
+ ERTS_PTAB_LIST_DBG_TRACE(BIF_P->common.id, call);
+ ERTS_PTAB_LIST_ASSERT(is_nil(BIF_ARG_1) || is_list(BIF_ARG_1));
+
+ res_acc = BIF_ARG_1;
+
+ ERTS_PTAB_LIST_ASSERT(ERTS_TERM_IS_MAGIC_BINARY(BIF_ARG_2));
+
+ mbp = ((ProcBin *) binary_val(BIF_ARG_2))->val;
+
+ ERTS_PTAB_LIST_ASSERT(ERTS_MAGIC_BIN_DESTRUCTOR(mbp)
+ == cleanup_ptab_list_bif_data);
+ ERTS_PTAB_LIST_ASSERT(
+ ((ErtsPTabListBifData *) ERTS_MAGIC_BIN_DATA(mbp))->debug.caller
+ == BIF_P->common.id);
+
+ if (ptab_list_bif_engine(BIF_P, &res_acc, mbp)) {
+ ERTS_PTAB_LIST_DBG_TRACE(BIF_P->common.id, return);
+ BIF_RET(res_acc);
+ }
+ else {
+ ERTS_PTAB_LIST_DBG_TRACE(BIF_P->common.id, trap);
+ ERTS_BIF_YIELD2(&ptab_list_continue_export, BIF_P, res_acc, BIF_ARG_2);
+ }
+}
+
+void
+erts_ptab_init(void)
+{
+ /* ptab_list_continue/2 is a hidden BIF that the original BIF traps to. */
+ erts_init_trap_export(&ptab_list_continue_export,
+ am_erlang, am_ptab_list_continue, 2,
+ &ptab_list_continue);
+
+}
+
+/*
+ * Debug stuff
+ */
+
+Sint
+erts_ptab_test_next_id(ErtsPTab *ptab, int set, Uint next)
+{
+ Uint64 ld;
+ Sint res;
+ Eterm data;
+ int first_pix = -1;
+
+ erts_ptab_rwlock(ptab);
+
+ if (!set)
+ ld = last_data_read_nob(ptab);
+ else {
+
+ ld = (Uint64) next;
+ data = ERTS_PTAB_LastData2EtermData(ld);
+ if (ptab->r.o.invalid_data == data) {
+ ld += ptab->r.o.max;
+ ASSERT(erts_ptab_data2pix(ptab, data)
+ == erts_ptab_data2pix(ptab,
+ ERTS_PTAB_LastData2EtermData(ld)));
+ }
+ last_data_set_relb(ptab, ld);
+ }
+
+ while (1) {
+ int pix;
+ ld++;
+ pix = (int) (ld % ptab->r.o.max);
+ if (first_pix < 0)
+ first_pix = pix;
+ else if (pix == first_pix) {
+ res = -1;
+ break;
+ }
+ if (ERTS_AINT_NULL == erts_ptab_pix2intptr_nob(ptab, pix)) {
+ data = ERTS_PTAB_LastData2EtermData(ld);
+ if (ptab->r.o.invalid_data == data) {
+ ld += ptab->r.o.max;
+ ASSERT(erts_ptab_data2pix(ptab, data)
+ == erts_ptab_data2pix(ptab,
+ ERTS_PTAB_LastData2EtermData(ld)));
+ data = ERTS_PTAB_LastData2EtermData(ld);
+ }
+ res = data;
+ break;
+ }
+ }
+
+ erts_ptab_rwunlock(ptab);
+
+ return res;
+}
+
+static ERTS_INLINE ErtsPTabElementCommon *
+ptab_pix2el(ErtsPTab *ptab, int ix)
+{
+ ErtsPTabElementCommon *ptab_el;
+ ASSERT(0 <= ix && ix < ptab->r.o.max);
+ ptab_el = (ErtsPTabElementCommon *) erts_ptab_pix2intptr_nob(ptab, ix);
+ if (ptab_el == ptab->r.o.invalid_element)
+ return NULL;
+ else
+ return ptab_el;
+}
+
+Eterm
+erts_debug_ptab_list(Process *c_p, ErtsPTab *ptab)
+{
+ int i;
+ Uint need;
+ Eterm res;
+ Eterm* hp;
+ Eterm *hp_end;
+
+ erts_ptab_rwlock(ptab);
+
+ res = NIL;
+ need = erts_ptab_count(ptab) * 2;
+ hp = HAlloc(c_p, need); /* we need two heap words for each id */
+ hp_end = hp + need;
+
+ /* make the list by scanning bakward */
+
+
+ for (i = ptab->r.o.max-1; i >= 0; i--) {
+ ErtsPTabElementCommon *el = ptab_pix2el(ptab, i);
+ if (el) {
+ res = CONS(hp, el->id, res);
+ hp += 2;
+ }
+ }
+
+ erts_ptab_rwunlock(ptab);
+
+ HRelease(c_p, hp_end, hp);
+
+ return res;
+}
+
+Eterm
+erts_debug_ptab_list_bif_info(Process *c_p, ErtsPTab *ptab)
+{
+ ERTS_DECL_AM(ptab_list_bif_info);
+ Eterm elements[] = {
+ AM_ptab_list_bif_info,
+ make_small((Uint) ERTS_PTAB_LIST_BIF_MIN_START_REDS),
+ make_small((Uint) ptab->list.data.chunks),
+ make_small((Uint) ERTS_PTAB_LIST_BIF_TAB_CHUNK_SIZE),
+ make_small((Uint) ERTS_PTAB_LIST_BIF_TAB_INSPECT_INDICES_PER_RED),
+ make_small((Uint) ERTS_PTAB_LIST_BIF_TAB_FREE_DELETED_REDS),
+ make_small((Uint) ERTS_PTAB_LIST_BIF_INSPECT_DELETED_PER_RED),
+ make_small((Uint) ERTS_PTAB_LIST_INSPECT_DELETED_MAX_REDS),
+ make_small((Uint) ERTS_PTAB_LIST_BIF_BUILD_RESULT_CONSES_PER_RED),
+ make_small((Uint) ERTS_PTAB_LIST_BIF_DEBUGLEVEL)
+ };
+ Uint sz = 0;
+ Eterm *hp;
+ (void) erts_bld_tuplev(NULL, &sz, sizeof(elements)/sizeof(Eterm), elements);
+ hp = HAlloc(c_p, sz);
+ return erts_bld_tuplev(&hp, NULL, sizeof(elements)/sizeof(Eterm), elements);
+}
+
+#if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_FOUND_PIDS
+static void
+debug_ptab_list_check_found_pid(ErtsPTabListBifData *ptlbdp,
+ Eterm pid,
+ Uint64 ic,
+ int pid_should_be_found)
+{
+ int i;
+ for (i = 0; i < ptlbdp->pid_ix; i++) {
+ if (ptlbdp->pid[i] == pid && ptlbdp->debug.pid_started[i] == ic) {
+ ERTS_PTAB_LIST_ASSERT(pid_should_be_found);
+ return;
+ }
+ }
+ ERTS_PTAB_LIST_ASSERT(!pid_should_be_found);
+}
+#endif
+
+#if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_RESLIST
+static void
+debug_ptab_list_check_res_list(Eterm list)
+{
+ while (is_list(list)) {
+ Eterm* consp = list_val(list);
+ Eterm hd = CAR(consp);
+ ERTS_PTAB_LIST_ASSERT(erts_ptab_is_valid_id(hd));
+ list = CDR(consp);
+ }
+
+ ERTS_PTAB_LIST_ASSERT(is_nil(list));
+}
+#endif
+
+#if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_PIDS
+
+static void
+debug_ptab_list_save_all_pids(ErtsPTabListBifData *ptlbdp)
+{
+ int ix, tix, cpix;
+ ErtsPTab *ptab = ptlbdp->ptab;
+ ptlbdp->debug.correct_pids_verified = 0;
+ ptlbdp->debug.correct_pids = erts_alloc(ERTS_ALC_T_PTAB_LIST_PIDS,
+ sizeof(Eterm)*ptlbdp->pid_sz);
+
+ for (tix = 0, cpix = 0; tix < ptab->r.o.max; tix++) {
+ ErtsPTabElementCommon *el = ptab_pix2el(ptab, tix);
+ if (el) {
+ ERTS_PTAB_LIST_ASSERT(erts_ptab_is_valid_id(el->id));
+ ptlbdp->debug.correct_pids[cpix++] = el->id;
+ ERTS_PTAB_LIST_ASSERT(cpix <= ptlbdp->pid_sz);
+ }
+ }
+ ERTS_PTAB_LIST_ASSERT(cpix == ptlbdp->pid_sz);
+
+ for (ix = 0; ix < ptlbdp->pid_sz; ix++)
+ ptlbdp->pid[ix] = make_small(ix);
+}
+
+static void
+debug_ptab_list_verify_all_pids(ErtsPTabListBifData *ptlbdp)
+{
+ int ix, cpix;
+
+ ERTS_PTAB_LIST_ASSERT(ptlbdp->pid_ix == ptlbdp->pid_sz);
+
+ for (ix = 0; ix < ptlbdp->pid_sz; ix++) {
+ int found = 0;
+ Eterm pid = ptlbdp->pid[ix];
+ ERTS_PTAB_LIST_ASSERT(erts_ptab_is_valid_id(pid));
+ for (cpix = ix; cpix < ptlbdp->pid_sz; cpix++) {
+ if (ptlbdp->debug.correct_pids[cpix] == pid) {
+ ptlbdp->debug.correct_pids[cpix] = NIL;
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ for (cpix = 0; cpix < ix; cpix++) {
+ if (ptlbdp->debug.correct_pids[cpix] == pid) {
+ ptlbdp->debug.correct_pids[cpix] = NIL;
+ found = 1;
+ break;
+ }
+ }
+ }
+ ERTS_PTAB_LIST_ASSERT(found);
+ }
+ ptlbdp->debug.correct_pids_verified = 1;
+
+ erts_free(ERTS_ALC_T_PTAB_LIST_PIDS, ptlbdp->debug.correct_pids);
+ ptlbdp->debug.correct_pids = NULL;
+}
+#endif /* ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_PIDS */
+
+#if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_DEL_LIST
+static void
+debug_ptab_list_check_del_list(ErtsPTab *ptab)
+{
+ ERTS_SMP_LC_ASSERT(erts_smp_lc_ptab_is_rwlocked(ptab));
+ if (!ptab->list.data.deleted.start)
+ ERTS_PTAB_LIST_ASSERT(!ptab->list.data.deleted.end);
+ else {
+ Uint64 curr_interval = erts_smp_current_interval_nob(erts_ptab_interval(ptab));
+ Uint64 *prev_x_interval_p = NULL;
+ ErtsPTabDeletedElement *ptdep;
+
+ for (ptdep = ptab->list.data.deleted.start;
+ ptdep;
+ ptdep = ptdep->next) {
+ if (!ptdep->prev)
+ ERTS_PTAB_LIST_ASSERT(ptab->list.data.deleted.start == ptdep);
+ else
+ ERTS_PTAB_LIST_ASSERT(ptdep->prev->next == ptdep);
+ if (!ptdep->next)
+ ERTS_PTAB_LIST_ASSERT(ptab->list.data.deleted.end == ptdep);
+ else
+ ERTS_PTAB_LIST_ASSERT(ptdep->next->prev == ptdep);
+ if (ptdep->ix < 0) {
+ Uint64 interval = ptdep->u.bif_invocation.interval;
+ ERTS_PTAB_LIST_ASSERT(interval <= curr_interval);
+ }
+ else {
+ Uint64 s_interval = ptdep->u.element.inserted;
+ Uint64 x_interval = ptdep->u.element.deleted;
+
+ ERTS_PTAB_LIST_ASSERT(s_interval <= x_interval);
+ if (prev_x_interval_p)
+ ERTS_PTAB_LIST_ASSERT(*prev_x_interval_p <= x_interval);
+ prev_x_interval_p = &ptdep->u.element.deleted;
+ ERTS_PTAB_LIST_ASSERT(
+ erts_ptab_is_valid_id(ptdep->u.element.id));
+ ERTS_PTAB_LIST_ASSERT(erts_ptab_id2pix(ptab,
+ ptdep->u.element.id)
+ == ptdep->ix);
+
+ }
+ }
+
+ }
+}
+
+static void
+debug_ptab_list_check_del_free_list(ErtsPTab *ptab,
+ ErtsPTabDeletedElement *free_list)
+{
+ if (ptab->list.data.deleted.start) {
+ ErtsPTabDeletedElement *fptdep;
+ ErtsPTabDeletedElement *ptdep;
+
+ for (fptdep = free_list; fptdep; fptdep = fptdep->next) {
+ for (ptdep = ptab->list.data.deleted.start;
+ ptdep;
+ ptdep = ptdep->next) {
+ ERTS_PTAB_LIST_ASSERT(fptdep != ptdep);
+ }
+ }
+ }
+}
+
+#endif
+
+#if ERTS_PTAB_LIST_BIF_DEBUGLEVEL != 0
+
+static void
+debug_ptab_list_assert_error(char* expr, const char* file, int line, const char *func)
+{
+ fflush(stdout);
+ erts_fprintf(stderr, "%s:%d:%s(): Assertion failed: %s\n",
+ (char *) file, line, (char *) func, expr);
+ fflush(stderr);
+ abort();
+}
+
+#endif
diff --git a/erts/emulator/beam/erl_ptab.h b/erts/emulator/beam/erl_ptab.h
new file mode 100644
index 0000000000..8a130f42a3
--- /dev/null
+++ b/erts/emulator/beam/erl_ptab.h
@@ -0,0 +1,472 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2012. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/*
+ * Description: Process/Port table implementation.
+ *
+ * Author: Rickard Green
+ */
+
+#ifndef ERL_PTAB_H__
+#define ERL_PTAB_H__
+
+#include "sys.h"
+#include "erl_term.h"
+#include "erl_time.h"
+#include "erl_utils.h"
+#define ERL_THR_PROGRESS_TSD_TYPE_ONLY
+#include "erl_thr_progress.h"
+#undef ERL_THR_PROGRESS_TSD_TYPE_ONLY
+#include "erl_alloc.h"
+#include "erl_monitors.h"
+
+#define ERTS_TRACER_PROC(P) ((P)->common.tracer_proc)
+#define ERTS_TRACE_FLAGS(P) ((P)->common.trace_flags)
+
+#define ERTS_P_LINKS(P) ((P)->common.u.alive.links)
+#define ERTS_P_MONITORS(P) ((P)->common.u.alive.monitors)
+
+#define IS_TRACED(p) \
+ (ERTS_TRACER_PROC((p)) != NIL)
+#define ARE_TRACE_FLAGS_ON(p,tf) \
+ ((ERTS_TRACE_FLAGS((p)) & (tf|F_SENSITIVE)) == (tf))
+#define IS_TRACED_FL(p,tf) \
+ ( IS_TRACED(p) && ARE_TRACE_FLAGS_ON(p,tf) )
+
+typedef struct {
+ Eterm id;
+#ifdef ERTS_SMP
+ erts_atomic32_t refc;
+#endif
+ Eterm tracer_proc;
+ Uint trace_flags;
+ union {
+ /* --- While being alive --- */
+ struct {
+ Uint64 started_interval;
+ struct reg_proc *reg;
+ ErtsLink *links;
+ ErtsMonitor *monitors;
+#ifdef ERTS_SMP
+ ErtsSmpPTimer *ptimer;
+#else
+ ErlTimer tm;
+#endif
+ } alive;
+
+ /* --- While being released --- */
+ ErtsThrPrgrLaterOp release;
+ } u;
+} ErtsPTabElementCommon;
+
+typedef struct ErtsPTabDeletedElement_ ErtsPTabDeletedElement;
+
+typedef struct {
+ erts_smp_rwmtx_t rwmtx;
+ erts_interval_t interval;
+ struct {
+ ErtsPTabDeletedElement *start;
+ ErtsPTabDeletedElement *end;
+ } deleted;
+ int chunks;
+} ErtsPTabListData;
+
+typedef struct {
+#ifdef ARCH_32
+ erts_smp_dw_atomic_t last_data;
+#else
+ erts_smp_atomic_t last_data;
+#endif
+ erts_smp_atomic32_t count;
+} ErtsPTabVolatileData;
+
+typedef struct {
+ erts_smp_atomic_t *tab;
+ Uint32 max;
+ Uint32 tab_cache_lines;
+ Uint32 pix_per_cache_line;
+ Uint32 pix_mask;
+ Uint32 pix_cl_mask;
+ Uint32 pix_cl_shift;
+ Uint32 pix_cli_mask;
+ Uint32 pix_cli_shift;
+ ErtsPTabElementCommon *invalid_element;
+ Eterm invalid_data;
+ void (*release_element)(void *);
+} ErtsPTabReadOnlyData;
+
+typedef struct {
+ /*
+ * Data mainly modified when someone is listing
+ * the content of the table.
+ */
+ union {
+ ErtsPTabListData data;
+ char algn[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(ErtsPTabListData))];
+ } list;
+
+ /*
+ * Frequently modified data.
+ */
+ union {
+ ErtsPTabVolatileData tile;
+ char algn[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(ErtsPTabVolatileData))];
+ } vola;
+
+ /*
+ * Read only data.
+ */
+ union {
+ ErtsPTabReadOnlyData o;
+ char algn[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(ErtsPTabReadOnlyData))];
+ } r;
+} ErtsPTab;
+
+#define ERTS_PTAB_ID_DATA_SIZE 28
+#define ERTS_PTAB_ID_DATA_SHIFT (_TAG_IMMED1_SIZE)
+/* ERTS_PTAB_MAX_SIZE must be a power of 2 */
+#define ERTS_PTAB_MAX_SIZE (SWORD_CONSTANT(1) << 27)
+#if (ERTS_PTAB_MAX_SIZE-1) > MAX_SMALL
+# error "The maximum number of processes/ports must fit in a SMALL."
+#endif
+
+
+/*
+ * Currently pids and ports are allowed.
+ */
+#if _PID_DATA_SIZE != ERTS_PTAB_ID_DATA_SIZE
+# error "Unexpected pid data size"
+#endif
+#if _PID_DATA_SHIFT != ERTS_PTAB_ID_DATA_SHIFT
+# error "Unexpected pid tag size"
+#endif
+#if _PORT_DATA_SIZE != ERTS_PTAB_ID_DATA_SIZE
+# error "Unexpected port data size"
+#endif
+#if _PORT_DATA_SHIFT != ERTS_PTAB_ID_DATA_SHIFT
+# error "Unexpected port tag size"
+#endif
+
+#define ERTS_PTAB_INVALID_ID(TAG) \
+ ((Eterm) \
+ ((((1 << ERTS_PTAB_ID_DATA_SIZE) - 1) << ERTS_PTAB_ID_DATA_SHIFT) \
+ | (TAG)))
+
+#define erts_ptab_is_valid_id(ID) \
+ (is_internal_pid((ID)) || is_internal_port((ID)))
+
+void erts_ptab_init(void);
+void erts_ptab_init_table(ErtsPTab *ptab,
+ ErtsAlcType_t atype,
+ void (*release_element)(void *),
+ ErtsPTabElementCommon *invalid_element,
+ int size,
+ char *name);
+int erts_ptab_new_element(ErtsPTab *ptab,
+ ErtsPTabElementCommon *ptab_el,
+ void *init_arg,
+ void (*init_ptab_el)(void *, Eterm));
+void erts_ptab_delete_element(ErtsPTab *ptab,
+ ErtsPTabElementCommon *ptab_el);
+int erts_ptab_initialized(ErtsPTab *ptab);
+
+ERTS_GLB_INLINE erts_interval_t *erts_ptab_interval(ErtsPTab *ptab);
+ERTS_GLB_INLINE int erts_ptab_max(ErtsPTab *ptab);
+ERTS_GLB_INLINE int erts_ptab_count(ErtsPTab *ptab);
+ERTS_GLB_INLINE Uint erts_ptab_pixdata2data(ErtsPTab *ptab, Eterm pixdata);
+ERTS_GLB_INLINE Uint32 erts_ptab_pixdata2pix(ErtsPTab *ptab, Eterm pixdata);
+ERTS_GLB_INLINE Uint32 erts_ptab_data2pix(ErtsPTab *ptab, Eterm data);
+ERTS_GLB_INLINE Uint erts_ptab_data2pixdata(ErtsPTab *ptab, Eterm data);
+ERTS_GLB_INLINE Eterm erts_ptab_make_id(ErtsPTab *ptab, Eterm data, Eterm tag);
+ERTS_GLB_INLINE int erts_ptab_id2pix(ErtsPTab *ptab, Eterm id);
+ERTS_GLB_INLINE Uint erts_ptab_id2data(ErtsPTab *ptab, Eterm id);
+ERTS_GLB_INLINE erts_aint_t erts_ptab_pix2intptr_nob(ErtsPTab *ptab, int ix);
+ERTS_GLB_INLINE erts_aint_t erts_ptab_pix2intptr_ddrb(ErtsPTab *ptab, int ix);
+ERTS_GLB_INLINE erts_aint_t erts_ptab_pix2intptr_rb(ErtsPTab *ptab, int ix);
+ERTS_GLB_INLINE erts_aint_t erts_ptab_pix2intptr_acqb(ErtsPTab *ptab, int ix);
+ERTS_GLB_INLINE void erts_ptab_inc_refc(ErtsPTabElementCommon *ptab_el);
+ERTS_GLB_INLINE int erts_ptab_dec_test_refc(ErtsPTabElementCommon *ptab_el);
+ERTS_GLB_INLINE int erts_ptab_add_test_refc(ErtsPTabElementCommon *ptab_el,
+ Sint32 add_refc);
+ERTS_GLB_INLINE void erts_ptab_rlock(ErtsPTab *ptab);
+ERTS_GLB_INLINE int erts_ptab_tryrlock(ErtsPTab *ptab);
+ERTS_GLB_INLINE void erts_ptab_runlock(ErtsPTab *ptab);
+ERTS_GLB_INLINE void erts_ptab_rwlock(ErtsPTab *ptab);
+ERTS_GLB_INLINE int erts_ptab_tryrwlock(ErtsPTab *ptab);
+ERTS_GLB_INLINE void erts_ptab_rwunlock(ErtsPTab *ptab);
+ERTS_GLB_INLINE int erts_smp_lc_ptab_is_rlocked(ErtsPTab *ptab);
+ERTS_GLB_INLINE int erts_smp_lc_ptab_is_rwlocked(ErtsPTab *ptab);
+
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+
+ERTS_GLB_INLINE erts_interval_t *
+erts_ptab_interval(ErtsPTab *ptab)
+{
+ return &ptab->list.data.interval;
+}
+
+ERTS_GLB_INLINE int
+erts_ptab_max(ErtsPTab *ptab)
+{
+ int max = ptab->r.o.max;
+ return max == ERTS_PTAB_MAX_SIZE ? max - 1 : max;
+}
+
+ERTS_GLB_INLINE int
+erts_ptab_count(ErtsPTab *ptab)
+{
+ int max = ptab->r.o.max;
+ erts_aint32_t res = erts_smp_atomic32_read_nob(&ptab->vola.tile.count);
+ if (max == ERTS_PTAB_MAX_SIZE) {
+ max--;
+ res--;
+ }
+ if (res > max)
+ return max;
+ ASSERT(res >= 0);
+ return (int) res;
+
+}
+
+ERTS_GLB_INLINE Uint erts_ptab_pixdata2data(ErtsPTab *ptab, Eterm pixdata)
+{
+ Uint32 data = ((Uint32) pixdata) & ~ptab->r.o.pix_mask;
+ data |= (pixdata >> ptab->r.o.pix_cl_shift) & ptab->r.o.pix_cl_mask;
+ data |= (pixdata & ptab->r.o.pix_cli_mask) << ptab->r.o.pix_cli_shift;
+ return data;
+}
+
+ERTS_GLB_INLINE Uint32 erts_ptab_pixdata2pix(ErtsPTab *ptab, Eterm pixdata)
+{
+ return ((Uint32) pixdata) & ptab->r.o.pix_mask;
+}
+
+ERTS_GLB_INLINE Uint32 erts_ptab_data2pix(ErtsPTab *ptab, Eterm data)
+{
+ Uint32 n, pix;
+ n = (Uint32) data;
+ pix = ((n & ptab->r.o.pix_cl_mask) << ptab->r.o.pix_cl_shift);
+ pix += ((n >> ptab->r.o.pix_cli_shift) & ptab->r.o.pix_cli_mask);
+ ASSERT(0 <= pix && pix < ptab->r.o.max);
+ return pix;
+}
+
+ERTS_GLB_INLINE Uint erts_ptab_data2pixdata(ErtsPTab *ptab, Eterm data)
+{
+ Uint pixdata = data & ~((Uint) ptab->r.o.pix_mask);
+ pixdata |= (Uint) erts_ptab_data2pix(ptab, data);
+ ASSERT(data == erts_ptab_pixdata2data(ptab, pixdata));
+ return pixdata;
+}
+
+#if ERTS_SIZEOF_TERM == 8
+
+ERTS_GLB_INLINE Eterm
+erts_ptab_make_id(ErtsPTab *ptab, Eterm data, Eterm tag)
+{
+ HUint huint;
+ Uint32 low_data = (Uint32) data;
+ low_data &= (1 << ERTS_PTAB_ID_DATA_SIZE) - 1;
+ low_data <<= ERTS_PTAB_ID_DATA_SHIFT;
+ huint.hval[ERTS_HUINT_HVAL_HIGH] = erts_ptab_data2pix(ptab, data);
+ huint.hval[ERTS_HUINT_HVAL_LOW] = low_data | ((Uint32) tag);
+ return (Eterm) huint.val;
+}
+
+ERTS_GLB_INLINE int
+erts_ptab_id2pix(ErtsPTab *ptab, Eterm id)
+{
+ HUint huint;
+ huint.val = id;
+ return (int) huint.hval[ERTS_HUINT_HVAL_HIGH];
+}
+
+ERTS_GLB_INLINE Uint
+erts_ptab_id2data(ErtsPTab *ptab, Eterm id)
+{
+ HUint huint;
+ huint.val = id;
+ return (Uint) (huint.hval[ERTS_HUINT_HVAL_LOW] >> ERTS_PTAB_ID_DATA_SHIFT);
+}
+
+#elif ERTS_SIZEOF_TERM == 4
+
+ERTS_GLB_INLINE Eterm
+erts_ptab_make_id(ErtsPTab *ptab, Eterm data, Eterm tag)
+{
+ Eterm id;
+ data &= ((1 << ERTS_PTAB_ID_DATA_SIZE) - 1);
+ id = (Eterm) erts_ptab_data2pixdata(ptab, data);
+ return (id << ERTS_PTAB_ID_DATA_SHIFT) | tag;
+}
+
+ERTS_GLB_INLINE int
+erts_ptab_id2pix(ErtsPTab *ptab, Eterm id)
+{
+ Uint pixdata = (Uint) id;
+ pixdata >>= ERTS_PTAB_ID_DATA_SHIFT;
+ return (int) erts_ptab_pixdata2pix(ptab, pixdata);
+}
+
+ERTS_GLB_INLINE Uint
+erts_ptab_id2data(ErtsPTab *ptab, Eterm id)
+{
+ Uint pixdata = (Uint) id;
+ pixdata >>= ERTS_PTAB_ID_DATA_SHIFT;
+ return erts_ptab_pixdata2data(ptab, pixdata);
+}
+
+#else
+#error "Unsupported size of term"
+#endif
+
+ERTS_GLB_INLINE erts_aint_t erts_ptab_pix2intptr_nob(ErtsPTab *ptab, int ix)
+{
+ ASSERT(0 <= ix && ix < ptab->r.o.max);
+ return erts_smp_atomic_read_nob(&ptab->r.o.tab[ix]);
+}
+
+ERTS_GLB_INLINE erts_aint_t erts_ptab_pix2intptr_ddrb(ErtsPTab *ptab, int ix)
+{
+ ASSERT(0 <= ix && ix < ptab->r.o.max);
+ return erts_smp_atomic_read_ddrb(&ptab->r.o.tab[ix]);
+}
+
+ERTS_GLB_INLINE erts_aint_t erts_ptab_pix2intptr_rb(ErtsPTab *ptab, int ix)
+{
+ ASSERT(0 <= ix && ix < ptab->r.o.max);
+ return erts_smp_atomic_read_rb(&ptab->r.o.tab[ix]);
+}
+
+ERTS_GLB_INLINE erts_aint_t erts_ptab_pix2intptr_acqb(ErtsPTab *ptab, int ix)
+{
+ ASSERT(0 <= ix && ix < ptab->r.o.max);
+ return erts_smp_atomic_read_acqb(&ptab->r.o.tab[ix]);
+}
+
+ERTS_GLB_INLINE void erts_ptab_inc_refc(ErtsPTabElementCommon *ptab_el)
+{
+#ifdef ERTS_SMP
+#ifdef ERTS_ENABLE_LOCK_CHECK
+ erts_aint32_t refc = erts_atomic32_inc_read_nob(&ptab_el->refc);
+ ERTS_SMP_LC_ASSERT(refc > 1);
+#else
+ erts_atomic32_inc_nob(&ptab_el->refc);
+#endif
+#endif
+}
+
+ERTS_GLB_INLINE int erts_ptab_dec_test_refc(ErtsPTabElementCommon *ptab_el)
+{
+#ifdef ERTS_SMP
+ erts_aint32_t refc = erts_atomic32_dec_read_nob(&ptab_el->refc);
+ ERTS_SMP_LC_ASSERT(refc >= 0);
+ return (int) refc;
+#else
+ return 0;
+#endif
+}
+
+ERTS_GLB_INLINE int erts_ptab_add_test_refc(ErtsPTabElementCommon *ptab_el,
+ Sint32 add_refc)
+{
+#ifdef ERTS_SMP
+ erts_aint32_t refc;
+
+#ifndef ERTS_ENABLE_LOCK_CHECK
+ if (add_refc >= 0) {
+ erts_atomic32_add_nob(&ptab_el->refc,
+ (erts_aint32_t) add_refc);
+ return 1;
+ }
+#endif
+
+ refc = erts_atomic32_add_read_nob(&ptab_el->refc,
+ (erts_aint32_t) add_refc);
+ ERTS_SMP_LC_ASSERT(refc >= 0);
+ return (int) refc;
+#else
+ return 0;
+#endif
+}
+
+ERTS_GLB_INLINE void erts_ptab_rlock(ErtsPTab *ptab)
+{
+ erts_smp_rwmtx_rlock(&ptab->list.data.rwmtx);
+}
+
+ERTS_GLB_INLINE int erts_ptab_tryrlock(ErtsPTab *ptab)
+{
+ return erts_smp_rwmtx_tryrlock(&ptab->list.data.rwmtx);
+}
+
+ERTS_GLB_INLINE void erts_ptab_runlock(ErtsPTab *ptab)
+{
+ erts_smp_rwmtx_runlock(&ptab->list.data.rwmtx);
+}
+
+ERTS_GLB_INLINE void erts_ptab_rwlock(ErtsPTab *ptab)
+{
+ erts_smp_rwmtx_rwlock(&ptab->list.data.rwmtx);
+}
+
+ERTS_GLB_INLINE int erts_ptab_tryrwlock(ErtsPTab *ptab)
+{
+ return erts_smp_rwmtx_tryrwlock(&ptab->list.data.rwmtx);
+}
+
+ERTS_GLB_INLINE void erts_ptab_rwunlock(ErtsPTab *ptab)
+{
+ erts_smp_rwmtx_rwunlock(&ptab->list.data.rwmtx);
+}
+
+ERTS_GLB_INLINE int erts_smp_lc_ptab_is_rlocked(ErtsPTab *ptab)
+{
+ return erts_smp_lc_rwmtx_is_rlocked(&ptab->list.data.rwmtx);
+}
+
+ERTS_GLB_INLINE int erts_smp_lc_ptab_is_rwlocked(ErtsPTab *ptab)
+{
+ return erts_smp_lc_rwmtx_is_rwlocked(&ptab->list.data.rwmtx);
+}
+
+#endif
+
+#endif
+
+#if defined(ERTS_PTAB_WANT_BIF_IMPL__) && !defined(ERTS_PTAB_LIST__)
+#define ERTS_PTAB_LIST__
+
+#include "erl_process.h"
+#include "bif.h"
+
+BIF_RETTYPE erts_ptab_list(struct process *c_p, ErtsPTab *ptab);
+
+#endif
+
+#if defined(ERTS_PTAB_WANT_DEBUG_FUNCS__) && !defined(ERTS_PTAB_DEBUG_FUNCS__)
+#define ERTS_PTAB_DEBUG_FUNCS__
+#include "erl_process.h"
+
+/* Debug functions */
+Sint erts_ptab_test_next_id(ErtsPTab *ptab, int set, Uint next);
+Eterm erts_debug_ptab_list(Process *c_p, ErtsPTab *ptab);
+Eterm erts_debug_ptab_list_bif_info(Process *c_p, ErtsPTab *ptab);
+
+#endif
diff --git a/erts/emulator/beam/erl_resolv_dns.c b/erts/emulator/beam/erl_resolv_dns.c
deleted file mode 100644
index 9d76fa89f8..0000000000
--- a/erts/emulator/beam/erl_resolv_dns.c
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1997-2009. All Rights Reserved.
- *
- * The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * %CopyrightEnd%
- */
-
-/*
- * Set this to non-zero value if DNS should be used.
- */
-int erl_use_resolver = 1;
diff --git a/erts/emulator/beam/erl_resolv_nodns.c b/erts/emulator/beam/erl_resolv_nodns.c
deleted file mode 100644
index f14ab68e27..0000000000
--- a/erts/emulator/beam/erl_resolv_nodns.c
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1997-2009. All Rights Reserved.
- *
- * The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * %CopyrightEnd%
- */
-
-/*
- * Set this to non-zero value if DNS should be used.
- */
-int erl_use_resolver = 0;
diff --git a/erts/emulator/beam/erl_smp.h b/erts/emulator/beam/erl_smp.h
index a32e9d9d7c..34c90c0bda 100644
--- a/erts/emulator/beam/erl_smp.h
+++ b/erts/emulator/beam/erl_smp.h
@@ -274,6 +274,7 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic_read_band_nob erts_atomic_read_band_nob
#define erts_smp_atomic_xchg_nob erts_atomic_xchg_nob
#define erts_smp_atomic_cmpxchg_nob erts_atomic_cmpxchg_nob
+#define erts_smp_atomic_read_bset_nob erts_atomic_read_bset_nob
#define erts_smp_atomic_init_mb erts_atomic_init_mb
#define erts_smp_atomic_set_mb erts_atomic_set_mb
@@ -288,6 +289,7 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic_read_band_mb erts_atomic_read_band_mb
#define erts_smp_atomic_xchg_mb erts_atomic_xchg_mb
#define erts_smp_atomic_cmpxchg_mb erts_atomic_cmpxchg_mb
+#define erts_smp_atomic_read_bset_mb erts_atomic_read_bset_mb
#define erts_smp_atomic_init_acqb erts_atomic_init_acqb
#define erts_smp_atomic_set_acqb erts_atomic_set_acqb
@@ -302,6 +304,7 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic_read_band_acqb erts_atomic_read_band_acqb
#define erts_smp_atomic_xchg_acqb erts_atomic_xchg_acqb
#define erts_smp_atomic_cmpxchg_acqb erts_atomic_cmpxchg_acqb
+#define erts_smp_atomic_read_bset_acqb erts_atomic_read_bset_acqb
#define erts_smp_atomic_init_relb erts_atomic_init_relb
#define erts_smp_atomic_set_relb erts_atomic_set_relb
@@ -316,6 +319,7 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic_read_band_relb erts_atomic_read_band_relb
#define erts_smp_atomic_xchg_relb erts_atomic_xchg_relb
#define erts_smp_atomic_cmpxchg_relb erts_atomic_cmpxchg_relb
+#define erts_smp_atomic_read_bset_relb erts_atomic_read_bset_relb
#define erts_smp_atomic_init_ddrb erts_atomic_init_ddrb
#define erts_smp_atomic_set_ddrb erts_atomic_set_ddrb
@@ -330,6 +334,7 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic_read_band_ddrb erts_atomic_read_band_ddrb
#define erts_smp_atomic_xchg_ddrb erts_atomic_xchg_ddrb
#define erts_smp_atomic_cmpxchg_ddrb erts_atomic_cmpxchg_ddrb
+#define erts_smp_atomic_read_bset_ddrb erts_atomic_read_bset_ddrb
#define erts_smp_atomic_init_rb erts_atomic_init_rb
#define erts_smp_atomic_set_rb erts_atomic_set_rb
@@ -344,6 +349,7 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic_read_band_rb erts_atomic_read_band_rb
#define erts_smp_atomic_xchg_rb erts_atomic_xchg_rb
#define erts_smp_atomic_cmpxchg_rb erts_atomic_cmpxchg_rb
+#define erts_smp_atomic_read_bset_rb erts_atomic_read_bset_rb
#define erts_smp_atomic_init_wb erts_atomic_init_wb
#define erts_smp_atomic_set_wb erts_atomic_set_wb
@@ -358,6 +364,7 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic_read_band_wb erts_atomic_read_band_wb
#define erts_smp_atomic_xchg_wb erts_atomic_xchg_wb
#define erts_smp_atomic_cmpxchg_wb erts_atomic_cmpxchg_wb
+#define erts_smp_atomic_read_bset_wb erts_atomic_read_bset_wb
/* 32-bit atomics */
@@ -374,6 +381,7 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic32_read_band_nob erts_atomic32_read_band_nob
#define erts_smp_atomic32_xchg_nob erts_atomic32_xchg_nob
#define erts_smp_atomic32_cmpxchg_nob erts_atomic32_cmpxchg_nob
+#define erts_smp_atomic32_read_bset_nob erts_atomic32_read_bset_nob
#define erts_smp_atomic32_init_mb erts_atomic32_init_mb
#define erts_smp_atomic32_set_mb erts_atomic32_set_mb
@@ -388,6 +396,7 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic32_read_band_mb erts_atomic32_read_band_mb
#define erts_smp_atomic32_xchg_mb erts_atomic32_xchg_mb
#define erts_smp_atomic32_cmpxchg_mb erts_atomic32_cmpxchg_mb
+#define erts_smp_atomic32_read_bset_mb erts_atomic32_read_bset_mb
#define erts_smp_atomic32_init_acqb erts_atomic32_init_acqb
#define erts_smp_atomic32_set_acqb erts_atomic32_set_acqb
@@ -402,6 +411,7 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic32_read_band_acqb erts_atomic32_read_band_acqb
#define erts_smp_atomic32_xchg_acqb erts_atomic32_xchg_acqb
#define erts_smp_atomic32_cmpxchg_acqb erts_atomic32_cmpxchg_acqb
+#define erts_smp_atomic32_read_bset_acqb erts_atomic32_read_bset_acqb
#define erts_smp_atomic32_init_relb erts_atomic32_init_relb
#define erts_smp_atomic32_set_relb erts_atomic32_set_relb
@@ -416,6 +426,7 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic32_read_band_relb erts_atomic32_read_band_relb
#define erts_smp_atomic32_xchg_relb erts_atomic32_xchg_relb
#define erts_smp_atomic32_cmpxchg_relb erts_atomic32_cmpxchg_relb
+#define erts_smp_atomic32_read_bset_relb erts_atomic32_read_bset_relb
#define erts_smp_atomic32_init_ddrb erts_atomic32_init_ddrb
#define erts_smp_atomic32_set_ddrb erts_atomic32_set_ddrb
@@ -430,6 +441,7 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic32_read_band_ddrb erts_atomic32_read_band_ddrb
#define erts_smp_atomic32_xchg_ddrb erts_atomic32_xchg_ddrb
#define erts_smp_atomic32_cmpxchg_ddrb erts_atomic32_cmpxchg_ddrb
+#define erts_smp_atomic32_read_bset_ddrb erts_atomic32_read_bset_ddrb
#define erts_smp_atomic32_init_rb erts_atomic32_init_rb
#define erts_smp_atomic32_set_rb erts_atomic32_set_rb
@@ -444,6 +456,7 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic32_read_band_rb erts_atomic32_read_band_rb
#define erts_smp_atomic32_xchg_rb erts_atomic32_xchg_rb
#define erts_smp_atomic32_cmpxchg_rb erts_atomic32_cmpxchg_rb
+#define erts_smp_atomic32_read_bset_rb erts_atomic32_read_bset_rb
#define erts_smp_atomic32_init_wb erts_atomic32_init_wb
#define erts_smp_atomic32_set_wb erts_atomic32_set_wb
@@ -458,6 +471,7 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic32_read_band_wb erts_atomic32_read_band_wb
#define erts_smp_atomic32_xchg_wb erts_atomic32_xchg_wb
#define erts_smp_atomic32_cmpxchg_wb erts_atomic32_cmpxchg_wb
+#define erts_smp_atomic32_read_bset_wb erts_atomic32_read_bset_wb
#else /* !ERTS_SMP */
@@ -513,6 +527,7 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic_read_band_nob erts_no_atomic_read_band
#define erts_smp_atomic_xchg_nob erts_no_atomic_xchg
#define erts_smp_atomic_cmpxchg_nob erts_no_atomic_cmpxchg
+#define erts_smp_atomic_read_bset_nob erts_no_atomic_read_bset
#define erts_smp_atomic_init_mb erts_no_atomic_set
#define erts_smp_atomic_set_mb erts_no_atomic_set
@@ -527,6 +542,7 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic_read_band_mb erts_no_atomic_read_band
#define erts_smp_atomic_xchg_mb erts_no_atomic_xchg
#define erts_smp_atomic_cmpxchg_mb erts_no_atomic_cmpxchg
+#define erts_smp_atomic_read_bset_mb erts_no_atomic_read_bset
#define erts_smp_atomic_init_acqb erts_no_atomic_set
#define erts_smp_atomic_set_acqb erts_no_atomic_set
@@ -541,6 +557,7 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic_read_band_acqb erts_no_atomic_read_band
#define erts_smp_atomic_xchg_acqb erts_no_atomic_xchg
#define erts_smp_atomic_cmpxchg_acqb erts_no_atomic_cmpxchg
+#define erts_smp_atomic_read_bset_acqb erts_no_atomic_read_bset
#define erts_smp_atomic_init_relb erts_no_atomic_set
#define erts_smp_atomic_set_relb erts_no_atomic_set
@@ -555,6 +572,7 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic_read_band_relb erts_no_atomic_read_band
#define erts_smp_atomic_xchg_relb erts_no_atomic_xchg
#define erts_smp_atomic_cmpxchg_relb erts_no_atomic_cmpxchg
+#define erts_smp_atomic_read_bset_relb erts_no_atomic_read_bset
#define erts_smp_atomic_init_ddrb erts_no_atomic_set
#define erts_smp_atomic_set_ddrb erts_no_atomic_set
@@ -569,6 +587,7 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic_read_band_ddrb erts_no_atomic_read_band
#define erts_smp_atomic_xchg_ddrb erts_no_atomic_xchg
#define erts_smp_atomic_cmpxchg_ddrb erts_no_atomic_cmpxchg
+#define erts_smp_atomic_read_bset_ddrb erts_no_atomic_read_bset
#define erts_smp_atomic_init_rb erts_no_atomic_set
#define erts_smp_atomic_set_rb erts_no_atomic_set
@@ -583,6 +602,7 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic_read_band_rb erts_no_atomic_read_band
#define erts_smp_atomic_xchg_rb erts_no_atomic_xchg
#define erts_smp_atomic_cmpxchg_rb erts_no_atomic_cmpxchg
+#define erts_smp_atomic_read_bset_rb erts_no_atomic_read_bset
#define erts_smp_atomic_init_wb erts_no_atomic_set
#define erts_smp_atomic_set_wb erts_no_atomic_set
@@ -597,6 +617,7 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic_read_band_wb erts_no_atomic_read_band
#define erts_smp_atomic_xchg_wb erts_no_atomic_xchg
#define erts_smp_atomic_cmpxchg_wb erts_no_atomic_cmpxchg
+#define erts_smp_atomic_read_bset_wb erts_no_atomic_read_bset
/* 32-bit atomics */
@@ -613,6 +634,7 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic32_read_band_nob erts_no_atomic32_read_band
#define erts_smp_atomic32_xchg_nob erts_no_atomic32_xchg
#define erts_smp_atomic32_cmpxchg_nob erts_no_atomic32_cmpxchg
+#define erts_smp_atomic32_read_bset_nob erts_no_atomic32_read_bset
#define erts_smp_atomic32_init_mb erts_no_atomic32_set
#define erts_smp_atomic32_set_mb erts_no_atomic32_set
@@ -627,6 +649,7 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic32_read_band_mb erts_no_atomic32_read_band
#define erts_smp_atomic32_xchg_mb erts_no_atomic32_xchg
#define erts_smp_atomic32_cmpxchg_mb erts_no_atomic32_cmpxchg
+#define erts_smp_atomic32_read_bset_mb erts_no_atomic32_read_bset
#define erts_smp_atomic32_init_acqb erts_no_atomic32_set
#define erts_smp_atomic32_set_acqb erts_no_atomic32_set
@@ -641,6 +664,7 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic32_read_band_acqb erts_no_atomic32_read_band
#define erts_smp_atomic32_xchg_acqb erts_no_atomic32_xchg
#define erts_smp_atomic32_cmpxchg_acqb erts_no_atomic32_cmpxchg
+#define erts_smp_atomic32_read_bset_acqb erts_no_atomic32_read_bset
#define erts_smp_atomic32_init_relb erts_no_atomic32_set
#define erts_smp_atomic32_set_relb erts_no_atomic32_set
@@ -655,6 +679,7 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic32_read_band_relb erts_no_atomic32_read_band
#define erts_smp_atomic32_xchg_relb erts_no_atomic32_xchg
#define erts_smp_atomic32_cmpxchg_relb erts_no_atomic32_cmpxchg
+#define erts_smp_atomic32_read_bset_relb erts_no_atomic32_read_bset
#define erts_smp_atomic32_init_ddrb erts_no_atomic32_set
#define erts_smp_atomic32_set_ddrb erts_no_atomic32_set
@@ -669,6 +694,7 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic32_read_band_ddrb erts_no_atomic32_read_band
#define erts_smp_atomic32_xchg_ddrb erts_no_atomic32_xchg
#define erts_smp_atomic32_cmpxchg_ddrb erts_no_atomic32_cmpxchg
+#define erts_smp_atomic32_read_bset_ddrb erts_no_atomic32_read_bset
#define erts_smp_atomic32_init_rb erts_no_atomic32_set
#define erts_smp_atomic32_set_rb erts_no_atomic32_set
@@ -683,6 +709,7 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic32_read_band_rb erts_no_atomic32_read_band
#define erts_smp_atomic32_xchg_rb erts_no_atomic32_xchg
#define erts_smp_atomic32_cmpxchg_rb erts_no_atomic32_cmpxchg
+#define erts_smp_atomic32_read_bset_rb erts_no_atomic32_read_bset
#define erts_smp_atomic32_init_wb erts_no_atomic32_set
#define erts_smp_atomic32_set_wb erts_no_atomic32_set
@@ -697,6 +724,7 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig);
#define erts_smp_atomic32_read_band_wb erts_no_atomic32_read_band
#define erts_smp_atomic32_xchg_wb erts_no_atomic32_xchg
#define erts_smp_atomic32_cmpxchg_wb erts_no_atomic32_cmpxchg
+#define erts_smp_atomic32_read_bset_wb erts_no_atomic32_read_bset
#endif /* !ERTS_SMP */
diff --git a/erts/emulator/beam/erl_sys_driver.h b/erts/emulator/beam/erl_sys_driver.h
index d429d0ce96..b991a2840c 100644
--- a/erts/emulator/beam/erl_sys_driver.h
+++ b/erts/emulator/beam/erl_sys_driver.h
@@ -31,7 +31,6 @@
#define ERL_SYS_DRV
typedef long ErlDrvEvent; /* An event to be selected on. */
-typedef long ErlDrvPort; /* A port descriptor. */
/* typedef struct _SysDriverOpts SysDriverOpts; defined in sys.h */
diff --git a/erts/emulator/beam/erl_term.c b/erts/emulator/beam/erl_term.c
index bf7774f882..4587cd84d1 100644
--- a/erts/emulator/beam/erl_term.c
+++ b/erts/emulator/beam/erl_term.c
@@ -133,7 +133,7 @@ ET_DEFINE_CHECKED(Uint,unsigned_val,Eterm,is_small);
ET_DEFINE_CHECKED(Sint,signed_val,Eterm,is_small);
ET_DEFINE_CHECKED(Uint,atom_val,Eterm,is_atom);
ET_DEFINE_CHECKED(Uint,header_arity,Eterm,is_header);
-ET_DEFINE_CHECKED(Uint,arityval,Eterm,is_arity_value);
+ET_DEFINE_CHECKED(Uint,arityval,Eterm,is_sane_arity_value);
ET_DEFINE_CHECKED(Uint,thing_arityval,Eterm,is_thing);
ET_DEFINE_CHECKED(Uint,thing_subtag,Eterm,is_thing);
ET_DEFINE_CHECKED(Eterm*,binary_val,Wterm,is_binary);
@@ -144,9 +144,7 @@ ET_DEFINE_CHECKED(Uint,bignum_header_arity,Eterm,_is_bignum_header);
ET_DEFINE_CHECKED(Eterm*,big_val,Wterm,is_big);
ET_DEFINE_CHECKED(Eterm*,float_val,Wterm,is_float);
ET_DEFINE_CHECKED(Eterm*,tuple_val,Wterm,is_tuple);
-ET_DEFINE_CHECKED(Uint,internal_pid_data,Eterm,is_internal_pid);
ET_DEFINE_CHECKED(struct erl_node_*,internal_pid_node,Eterm,is_internal_pid);
-ET_DEFINE_CHECKED(Uint,internal_port_data,Eterm,is_internal_port);
ET_DEFINE_CHECKED(struct erl_node_*,internal_port_node,Eterm,is_internal_port);
ET_DEFINE_CHECKED(Eterm*,internal_ref_val,Wterm,is_internal_ref);
ET_DEFINE_CHECKED(Uint,internal_ref_data_words,Wterm,is_internal_ref);
diff --git a/erts/emulator/beam/erl_term.h b/erts/emulator/beam/erl_term.h
index c270d13365..fb3ef9cd6c 100644
--- a/erts/emulator/beam/erl_term.h
+++ b/erts/emulator/beam/erl_term.h
@@ -300,8 +300,17 @@ _ET_DECLARE_CHECKED(Uint,header_arity,Eterm)
#define header_arity(x) _ET_APPLY(header_arity,(x))
/* arityval access methods */
+/* Erlang Spec. 4.7.3 defines max arity to 65535
+ * we will however enforce max arity of 16777215 (24 bits)
+ * (checked in bifs and asserted in debug)
+ */
+#define MAX_ARITYVAL ((((Uint)1) << 24) - 1)
+#define ERTS_MAX_TUPLE_SIZE MAX_ARITYVAL
+
#define make_arityval(sz) _make_header((sz),_TAG_HEADER_ARITYVAL)
#define is_arity_value(x) (((x) & _TAG_HEADER_MASK) == _TAG_HEADER_ARITYVAL)
+#define is_sane_arity_value(x) ((((x) & _TAG_HEADER_MASK) == _TAG_HEADER_ARITYVAL) && \
+ (((x) >> _HEADER_ARITY_OFFS) <= MAX_ARITYVAL))
#define is_not_arity_value(x) (!is_arity_value((x)))
#define _unchecked_arityval(x) _unchecked_header_arity((x))
_ET_DECLARE_CHECKED(Uint,arityval,Eterm)
@@ -542,12 +551,6 @@ _ET_DECLARE_CHECKED(Eterm*,tuple_val,Wterm)
#define _GETBITS(X,Pos,Size) (((X) >> (Pos)) & ~(~((Uint) 0) << (Size)))
/*
- * Observe! New layout for pids, ports and references in R9 (see also note
- * in erl_node_container_utils.h).
- */
-
-
-/*
* Creation in node specific data (pids, ports, refs)
*/
@@ -584,7 +587,6 @@ _ET_DECLARE_CHECKED(Eterm*,tuple_val,Wterm)
*
*/
-#define _PID_R9_SER_SIZE 3
#define _PID_SER_SIZE (_PID_DATA_SIZE - _PID_NUM_SIZE)
#define _PID_NUM_SIZE 15
@@ -598,23 +600,13 @@ _ET_DECLARE_CHECKED(Eterm*,tuple_val,Wterm)
#define make_pid_data(Ser, Num) \
((Uint) ((Ser) << _PID_NUM_SIZE | (Num)))
-#define make_internal_pid(X) \
- ((Eterm) (((X) << _PID_DATA_SHIFT) | _TAG_IMMED1_PID))
-
#define is_internal_pid(x) (((x) & _TAG_IMMED1_MASK) == _TAG_IMMED1_PID)
#define is_not_internal_pid(x) (!is_internal_pid((x)))
-#define _unchecked_internal_pid_data(x) _GET_PID_DATA((x))
-_ET_DECLARE_CHECKED(Uint,internal_pid_data,Eterm)
-#define internal_pid_data(x) _ET_APPLY(internal_pid_data,(x))
-
#define _unchecked_internal_pid_node(x) erts_this_node
_ET_DECLARE_CHECKED(struct erl_node_*,internal_pid_node,Eterm)
#define internal_pid_node(x) _ET_APPLY(internal_pid_node,(x))
-#define internal_pid_number(x) _GET_PID_NUM(internal_pid_data((x)))
-#define internal_pid_serial(x) _GET_PID_SER(internal_pid_data((x)))
-
#define internal_pid_data_words(x) (1)
/*
@@ -644,7 +636,6 @@ _ET_DECLARE_CHECKED(struct erl_node_*,internal_pid_node,Eterm)
* N : node number
*
*/
-#define _PORT_R9_NUM_SIZE 18
#define _PORT_NUM_SIZE _PORT_DATA_SIZE
#define _PORT_DATA_SIZE 28
@@ -654,18 +645,9 @@ _ET_DECLARE_CHECKED(struct erl_node_*,internal_pid_node,Eterm)
#define _GET_PORT_NUM(X) _GETBITS((X), 0, _PORT_NUM_SIZE)
-#define make_internal_port(X) \
- ((Eterm) (((X) << _PORT_DATA_SHIFT) | _TAG_IMMED1_PORT))
-
#define is_internal_port(x) (((x) & _TAG_IMMED1_MASK) == _TAG_IMMED1_PORT)
#define is_not_internal_port(x) (!is_internal_port(x))
-#define _unchecked_internal_port_data(x) _GET_PORT_DATA((x))
-_ET_DECLARE_CHECKED(Uint,internal_port_data,Eterm)
-#define internal_port_data(x) _ET_APPLY(internal_port_data,(x))
-
-#define internal_port_number(x) _GET_PORT_NUM(internal_port_data((x)))
-
#define _unchecked_internal_port_node(x) erts_this_node
_ET_DECLARE_CHECKED(struct erl_node_*,internal_port_node,Eterm)
#define internal_port_node(x) _ET_APPLY(internal_port_node,(x))
diff --git a/erts/emulator/beam/erl_thr_progress.c b/erts/emulator/beam/erl_thr_progress.c
index 88524bdd4c..9678d7e08b 100644
--- a/erts/emulator/beam/erl_thr_progress.c
+++ b/erts/emulator/beam/erl_thr_progress.c
@@ -96,17 +96,14 @@
#define ERTS_THR_PRGR_LFLG_BLOCK (((erts_aint32_t) 1) << 31)
#define ERTS_THR_PRGR_LFLG_NO_LEADER (((erts_aint32_t) 1) << 30)
-#define ERTS_THR_PRGR_LFLG_ACTIVE_MASK (~(ERTS_THR_PRGR_LFLG_NO_LEADER \
- | ERTS_THR_PRGR_LFLG_BLOCK))
+#define ERTS_THR_PRGR_LFLG_WAITING_UM (((erts_aint32_t) 1) << 29)
+#define ERTS_THR_PRGR_LFLG_ACTIVE_MASK (~(ERTS_THR_PRGR_LFLG_NO_LEADER \
+ | ERTS_THR_PRGR_LFLG_BLOCK \
+ | ERTS_THR_PRGR_LFLG_WAITING_UM))
-#define ERTS_THR_PRGR_LFLGS_ACTIVE(LFLGS) \
+#define ERTS_THR_PRGR_LFLGS_ACTIVE(LFLGS) \
((LFLGS) & ERTS_THR_PRGR_LFLG_ACTIVE_MASK)
-#define ERTS_THR_PRGR_LFLGS_ALL_WAITING(LFLGS) \
- (((LFLGS) & (ERTS_THR_PRGR_LFLG_NO_LEADER \
- |ERTS_THR_PRGR_LFLG_ACTIVE_MASK)) \
- == ERTS_THR_PRGR_LFLG_NO_LEADER)
-
/*
* We use a 64-bit value for thread progress. By this wrapping of
* the thread progress will more or less never occur.
@@ -262,6 +259,11 @@ typedef struct {
erts_atomic32_t managed_count;
erts_atomic32_t managed_id;
erts_atomic32_t unmanaged_id;
+ int chk_next_ix;
+ struct {
+ int waiting;
+ erts_atomic32_t current;
+ } umrefc_ix;
} ErtsThrPrgrMiscData;
typedef struct {
@@ -276,12 +278,18 @@ typedef union {
char align__[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(ErtsThrPrgrElement))];
} ErtsThrPrgrArray;
+typedef union {
+ erts_atomic_t refc;
+ char align__[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(erts_atomic_t))];
+} ErtsThrPrgrUnmanagedRefc;
+
typedef struct {
union {
ErtsThrPrgrMiscData data;
char align__[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(
sizeof(ErtsThrPrgrMiscData))];
} misc;
+ ErtsThrPrgrUnmanagedRefc umrefc[2];
ErtsThrPrgrArray *thr;
struct {
int no;
@@ -346,7 +354,9 @@ init_tmp_thr_prgr_data(ErtsThrPrgrData *tpd)
tpd->is_managed = 0;
tpd->is_blocking = 0;
tpd->is_temporary = 1;
-
+#ifdef ERTS_ENABLE_LOCK_CHECK
+ tpd->is_delaying = 0;
+#endif
erts_tsd_set(erts_thr_prgr_data_key__, (void *) tpd);
}
@@ -461,6 +471,12 @@ erts_thr_progress_init(int no_schedulers, int managed, int unmanaged)
erts_atomic32_init_nob(&intrnl->misc.data.managed_count, 0);
erts_atomic32_init_nob(&intrnl->misc.data.managed_id, no_schedulers);
erts_atomic32_init_nob(&intrnl->misc.data.unmanaged_id, -1);
+ intrnl->misc.data.chk_next_ix = 0;
+ intrnl->misc.data.umrefc_ix.waiting = -1;
+ erts_atomic32_init_nob(&intrnl->misc.data.umrefc_ix.current, 0);
+
+ erts_atomic_init_nob(&intrnl->umrefc[0].refc, (erts_aint_t) 0);
+ erts_atomic_init_nob(&intrnl->umrefc[1].refc, (erts_aint_t) 0);
intrnl->thr = (ErtsThrPrgrArray *) ptr;
ptr += thr_arr_sz;
@@ -547,6 +563,9 @@ erts_thr_progress_register_unmanaged_thread(ErtsThrPrgrCallbacks *callbacks)
tpd->is_managed = 0;
tpd->is_blocking = is_blocking;
tpd->is_temporary = 0;
+#ifdef ERTS_ENABLE_LOCK_CHECK
+ tpd->is_delaying = 0;
+#endif
ASSERT(tpd->id >= 0);
if (tpd->id >= intrnl->unmanaged.no)
erl_exit(ERTS_ABORT_EXIT,
@@ -600,6 +619,9 @@ erts_thr_progress_register_managed_thread(ErtsSchedulerData *esdp,
tpd->is_managed = 1;
tpd->is_blocking = is_blocking;
tpd->is_temporary = 0;
+#ifdef ERTS_ENABLE_LOCK_CHECK
+ tpd->is_delaying = 1;
+#endif
init_wakeup_request_array(&tpd->wakeup_request[0]);
@@ -607,8 +629,8 @@ erts_thr_progress_register_managed_thread(ErtsSchedulerData *esdp,
tpd->leader = 0;
tpd->active = 1;
- tpd->previous.local = 0;
- tpd->previous.current = ERTS_THR_PRGR_VAL_WAITING;
+ tpd->confirmed = 0;
+ tpd->leader_state.current = ERTS_THR_PRGR_VAL_WAITING;
erts_tsd_set(erts_thr_prgr_data_key__, (void *) tpd);
erts_atomic32_inc_nob(&intrnl->misc.data.lflgs);
@@ -651,60 +673,113 @@ leader_update(ErtsThrPrgrData *tpd)
block_thread(tpd);
}
else {
+ ErtsThrPrgrVal current;
+ int ix, chk_next_ix, umrefc_ix, my_ix, no_managed, waiting_unmanaged;
erts_aint32_t lflgs;
ErtsThrPrgrVal next;
- int ix, sz, make_progress;
+ erts_aint_t refc;
- if (tpd->previous.current == ERTS_THR_PRGR_VAL_WAITING) {
- /* Took over as leader from another thread */
- tpd->previous.current = read_acqb(&erts_thr_prgr__.current);
- tpd->previous.next = tpd->previous.current;
- tpd->previous.next++;
- if (tpd->previous.next == ERTS_THR_PRGR_VAL_WAITING)
- tpd->previous.next = 0;
- }
+ my_ix = tpd->id;
- if (tpd->previous.local == tpd->previous.current) {
- ErtsThrPrgrVal val = tpd->previous.current + 1;
- if (val == ERTS_THR_PRGR_VAL_WAITING)
- val = 0;
- tpd->previous.local = val;
- set_mb(&intrnl->thr[tpd->id].data.current, val);
+ if (tpd->leader_state.current == ERTS_THR_PRGR_VAL_WAITING) {
+ /* Took over as leader from another thread */
+ tpd->leader_state.current = read_nob(&erts_thr_prgr__.current);
+ tpd->leader_state.next = tpd->leader_state.current;
+ tpd->leader_state.next++;
+ if (tpd->leader_state.next == ERTS_THR_PRGR_VAL_WAITING)
+ tpd->leader_state.next = 0;
+ tpd->leader_state.chk_next_ix = intrnl->misc.data.chk_next_ix;
+ tpd->leader_state.umrefc_ix.waiting = intrnl->misc.data.umrefc_ix.waiting;
+ tpd->leader_state.umrefc_ix.current =
+ (int) erts_atomic32_read_nob(&intrnl->misc.data.umrefc_ix.current);
+
+ if (tpd->confirmed == tpd->leader_state.current) {
+ ErtsThrPrgrVal val = tpd->leader_state.current + 1;
+ if (val == ERTS_THR_PRGR_VAL_WAITING)
+ val = 0;
+ tpd->confirmed = val;
+ set_mb(&intrnl->thr[my_ix].data.current, val);
+ }
}
- next = tpd->previous.next;
- make_progress = 1;
- sz = intrnl->managed.no;
- for (ix = 0; ix < sz; ix++) {
- ErtsThrPrgrVal tmp;
- tmp = read_nob(&intrnl->thr[ix].data.current);
- if (tmp != next && tmp != ERTS_THR_PRGR_VAL_WAITING) {
- make_progress = 0;
- ASSERT(erts_thr_progress_has_passed__(next, tmp));
- break;
+ next = tpd->leader_state.next;
+
+ waiting_unmanaged = 0;
+ umrefc_ix = -1; /* Shut up annoying warning */
+
+ chk_next_ix = tpd->leader_state.chk_next_ix;
+ no_managed = intrnl->managed.no;
+ ASSERT(0 <= chk_next_ix && chk_next_ix <= no_managed);
+ /* Check manged threads */
+ if (chk_next_ix < no_managed) {
+ for (ix = chk_next_ix; ix < no_managed; ix++) {
+ ErtsThrPrgrVal tmp;
+ if (ix == my_ix)
+ continue;
+ tmp = read_nob(&intrnl->thr[ix].data.current);
+ if (tmp != next && tmp != ERTS_THR_PRGR_VAL_WAITING) {
+ tpd->leader_state.chk_next_ix = ix;
+ ASSERT(erts_thr_progress_has_passed__(next, tmp));
+ goto done;
+ }
}
}
- if (make_progress) {
- ErtsThrPrgrVal current = next;
+ /* Check unmanged threads */
+ waiting_unmanaged = tpd->leader_state.umrefc_ix.waiting != -1;
+ umrefc_ix = (waiting_unmanaged
+ ? tpd->leader_state.umrefc_ix.waiting
+ : tpd->leader_state.umrefc_ix.current);
+ refc = erts_atomic_read_nob(&intrnl->umrefc[umrefc_ix].refc);
+ ASSERT(refc >= 0);
+ if (refc != 0) {
+ int new_umrefc_ix;
+
+ if (waiting_unmanaged)
+ goto done;
+
+ new_umrefc_ix = (umrefc_ix + 1) & 0x1;
+ tpd->leader_state.umrefc_ix.waiting = umrefc_ix;
+ tpd->leader_state.chk_next_ix = no_managed;
+ erts_atomic32_set_nob(&intrnl->misc.data.umrefc_ix.current,
+ (erts_aint32_t) new_umrefc_ix);
+ ETHR_MEMBAR(ETHR_StoreLoad);
+ refc = erts_atomic_read_nob(&intrnl->umrefc[umrefc_ix].refc);
+ ASSERT(refc >= 0);
+ waiting_unmanaged = 1;
+ if (refc != 0)
+ goto done;
+ }
- next++;
- if (next == ERTS_THR_PRGR_VAL_WAITING)
- next = 0;
+ /* Make progress */
+ current = next;
- set_nob(&intrnl->thr[tpd->id].data.current, next);
- set_mb(&erts_thr_prgr__.current, current);
- tpd->previous.local = next;
- tpd->previous.next = next;
- tpd->previous.current = current;
+ next++;
+ if (next == ERTS_THR_PRGR_VAL_WAITING)
+ next = 0;
+
+ set_nob(&intrnl->thr[my_ix].data.current, next);
+ set_mb(&erts_thr_prgr__.current, current);
+ tpd->confirmed = next;
+ tpd->leader_state.next = next;
+ tpd->leader_state.current = current;
#if ERTS_THR_PRGR_PRINT_VAL
- if (current % 1000 == 0)
- erts_fprintf(stderr, "%b64u\n", current);
+ if (current % 1000 == 0)
+ erts_fprintf(stderr, "%b64u\n", current);
#endif
- handle_wakeup_requests(current);
+ handle_wakeup_requests(current);
+
+ if (waiting_unmanaged) {
+ waiting_unmanaged = 0;
+ tpd->leader_state.umrefc_ix.waiting = -1;
+ erts_atomic32_read_band_nob(&intrnl->misc.data.lflgs,
+ ~ERTS_THR_PRGR_LFLG_WAITING_UM);
}
+ tpd->leader_state.chk_next_ix = 0;
+
+ done:
if (tpd->active) {
lflgs = erts_atomic32_read_nob(&intrnl->misc.data.lflgs);
@@ -712,20 +787,44 @@ leader_update(ErtsThrPrgrData *tpd)
(void) block_thread(tpd);
}
else {
+ int force_wakeup_check = 0;
+ erts_aint32_t set_flags = ERTS_THR_PRGR_LFLG_NO_LEADER;
tpd->leader = 0;
- tpd->previous.current = ERTS_THR_PRGR_VAL_WAITING;
+ tpd->leader_state.current = ERTS_THR_PRGR_VAL_WAITING;
#if ERTS_THR_PRGR_PRINT_LEADER
erts_fprintf(stderr, "L <- %d\n", tpd->id);
#endif
ERTS_THR_PROGRESS_STATE_DEBUG_SET_LEADER(tpd->id, 0);
+ if (waiting_unmanaged)
+ set_flags |= ERTS_THR_PRGR_LFLG_WAITING_UM;
+
lflgs = erts_atomic32_read_bor_relb(&intrnl->misc.data.lflgs,
- ERTS_THR_PRGR_LFLG_NO_LEADER);
+ set_flags);
+ lflgs |= set_flags;
if (lflgs & ERTS_THR_PRGR_LFLG_BLOCK)
lflgs = block_thread(tpd);
- if (ERTS_THR_PRGR_LFLGS_ACTIVE(lflgs) == 0 && got_sched_wakeups())
+
+ if (waiting_unmanaged) {
+ /* Need to check umrefc again */
+ ETHR_MEMBAR(ETHR_StoreLoad);
+ refc = erts_atomic_read_nob(&intrnl->umrefc[umrefc_ix].refc);
+ if (refc == 0) {
+ /* Need to force wakeup check */
+ force_wakeup_check = 1;
+ }
+ }
+
+ if ((force_wakeup_check
+ || ((lflgs & (ERTS_THR_PRGR_LFLG_NO_LEADER
+ | ERTS_THR_PRGR_LFLG_WAITING_UM
+ | ERTS_THR_PRGR_LFLG_ACTIVE_MASK))
+ == ERTS_THR_PRGR_LFLG_NO_LEADER))
+ && got_sched_wakeups()) {
+ /* Someone need to make progress */
wakeup_managed(0);
+ }
}
}
@@ -744,11 +843,11 @@ update(ErtsThrPrgrData *tpd)
erts_aint32_t lflgs;
res = 0;
val = read_acqb(&erts_thr_prgr__.current);
- if (tpd->previous.local == val) {
+ if (tpd->confirmed == val) {
val++;
if (val == ERTS_THR_PRGR_VAL_WAITING)
val = 0;
- tpd->previous.local = val;
+ tpd->confirmed = val;
set_mb(&intrnl->thr[tpd->id].data.current, val);
}
@@ -801,12 +900,19 @@ erts_thr_progress_prepare_wait(ErtsSchedulerData *esdp)
block_count_dec();
- tpd->previous.local = ERTS_THR_PRGR_VAL_WAITING;
+ tpd->confirmed = ERTS_THR_PRGR_VAL_WAITING;
set_mb(&intrnl->thr[tpd->id].data.current, ERTS_THR_PRGR_VAL_WAITING);
lflgs = erts_atomic32_read_nob(&intrnl->misc.data.lflgs);
- if (ERTS_THR_PRGR_LFLGS_ALL_WAITING(lflgs) && got_sched_wakeups())
- wakeup_managed(0); /* Someone need to make progress */
+
+ if ((lflgs & (ERTS_THR_PRGR_LFLG_NO_LEADER
+ | ERTS_THR_PRGR_LFLG_WAITING_UM
+ | ERTS_THR_PRGR_LFLG_ACTIVE_MASK))
+ == ERTS_THR_PRGR_LFLG_NO_LEADER
+ && got_sched_wakeups()) {
+ /* Someone need to make progress */
+ wakeup_managed(0);
+ }
}
void
@@ -828,7 +934,7 @@ erts_thr_progress_finalize_wait(ErtsSchedulerData *esdp)
val++;
if (val == ERTS_THR_PRGR_VAL_WAITING)
val = 0;
- tpd->previous.local = val;
+ tpd->confirmed = val;
set_mb(&intrnl->thr[tpd->id].data.current, val);
val = read_acqb(&erts_thr_prgr__.current);
if (current == val)
@@ -875,6 +981,68 @@ erts_thr_progress_active(ErtsSchedulerData *esdp, int on)
}
+static ERTS_INLINE void
+unmanaged_continue(ErtsThrPrgrDelayHandle handle)
+{
+ int umrefc_ix = (int) handle;
+ erts_aint_t refc;
+
+ ASSERT(umrefc_ix == 0 || umrefc_ix == 1);
+ refc = erts_atomic_dec_read_relb(&intrnl->umrefc[umrefc_ix].refc);
+ ASSERT(refc >= 0);
+ if (refc == 0) {
+ erts_aint_t lflgs;
+ ERTS_THR_READ_MEMORY_BARRIER;
+ lflgs = erts_atomic32_read_nob(&intrnl->misc.data.lflgs);
+ if ((lflgs & (ERTS_THR_PRGR_LFLG_NO_LEADER
+ | ERTS_THR_PRGR_LFLG_WAITING_UM
+ | ERTS_THR_PRGR_LFLG_ACTIVE_MASK))
+ == (ERTS_THR_PRGR_LFLG_NO_LEADER|ERTS_THR_PRGR_LFLG_WAITING_UM)
+ && got_sched_wakeups()) {
+ /* Others waiting for us... */
+ wakeup_managed(0);
+ }
+ }
+}
+
+void
+erts_thr_progress_unmanaged_continue__(ErtsThrPrgrDelayHandle handle)
+{
+#ifdef ERTS_ENABLE_LOCK_CHECK
+ ErtsThrPrgrData *tpd = perhaps_thr_prgr_data(NULL);
+ ERTS_LC_ASSERT(tpd && tpd->is_delaying);
+ tpd->is_delaying = 0;
+ return_tmp_thr_prgr_data(tpd);
+#endif
+ ASSERT(!erts_thr_progress_is_managed_thread());
+
+ unmanaged_continue(handle);
+}
+
+ErtsThrPrgrDelayHandle
+erts_thr_progress_unmanaged_delay__(void)
+{
+ int umrefc_ix;
+ ASSERT(!erts_thr_progress_is_managed_thread());
+ umrefc_ix = (int) erts_atomic32_read_acqb(&intrnl->misc.data.umrefc_ix.current);
+ while (1) {
+ int tmp_ix;
+ erts_atomic_inc_acqb(&intrnl->umrefc[umrefc_ix].refc);
+ tmp_ix = (int) erts_atomic32_read_acqb(&intrnl->misc.data.umrefc_ix.current);
+ if (tmp_ix == umrefc_ix)
+ break;
+ unmanaged_continue(umrefc_ix);
+ umrefc_ix = tmp_ix;
+ }
+#ifdef ERTS_ENABLE_LOCK_CHECK
+ {
+ ErtsThrPrgrData *tpd = tmp_thr_prgr_data(NULL);
+ tpd->is_delaying = 1;
+ }
+#endif
+ return (ErtsThrPrgrDelayHandle) umrefc_ix;
+}
+
static ERTS_INLINE int
has_reached_wakeup(ErtsThrPrgrVal wakeup)
{
@@ -931,7 +1099,7 @@ request_wakeup_managed(ErtsThrPrgrData *tpd, ErtsThrPrgrVal value)
*/
ASSERT(tpd->is_managed);
- ASSERT(tpd->previous.local != ERTS_THR_PRGR_VAL_WAITING);
+ ASSERT(tpd->confirmed != ERTS_THR_PRGR_VAL_WAITING);
if (has_reached_wakeup(value)) {
wakeup_managed(tpd->id);
@@ -946,7 +1114,7 @@ request_wakeup_managed(ErtsThrPrgrData *tpd, ErtsThrPrgrVal value)
tpd->wakeup_request[wix]));
- if (tpd->previous.local == value) {
+ if (tpd->confirmed == value) {
/*
* We have already confirmed this value. We need to request
* wakeup for a value later than our latest confirmed value in
diff --git a/erts/emulator/beam/erl_thr_progress.h b/erts/emulator/beam/erl_thr_progress.h
index e72321cf48..1416aa6166 100644
--- a/erts/emulator/beam/erl_thr_progress.h
+++ b/erts/emulator/beam/erl_thr_progress.h
@@ -53,9 +53,22 @@ typedef Uint64 ErtsThrPrgrVal;
#define ERTS_THR_PRGR_WAKEUP_DATA_SIZE 4 /* Need to be an even power of 2. */
typedef struct {
+ ErtsThrPrgrVal next;
+ ErtsThrPrgrVal current;
+ int chk_next_ix;
+ struct {
+ int current;
+ int waiting;
+ } umrefc_ix;
+} ErtsThrPrgrLeaderState;
+
+typedef struct {
int id;
int is_managed;
int is_blocking;
+#ifdef ERTS_ENABLE_LOCK_CHECK
+ int is_delaying; /* managed is always delaying */
+#endif
int is_temporary;
/* --- Part below only for registered threads --- */
@@ -66,11 +79,8 @@ typedef struct {
int leader; /* Needs to be first in the managed threads part */
int active;
- struct {
- ErtsThrPrgrVal local;
- ErtsThrPrgrVal next;
- ErtsThrPrgrVal current;
- } previous;
+ ErtsThrPrgrVal confirmed;
+ ErtsThrPrgrLeaderState leader_state;
} ErtsThrPrgrData;
void erts_thr_progress_fatal_error_block(SWord timeout,
@@ -121,6 +131,11 @@ typedef struct {
ERTS_THR_PRGR_ATOMIC current;
} ErtsThrPrgr;
+typedef int ErtsThrPrgrDelayHandle;
+#define ERTS_THR_PRGR_DHANDLE_MANAGED ((ErtsThrPrgrDelayHandle) -1)
+/* ERTS_THR_PRGR_DHANDLE_MANAGED implies managed thread */
+#define ERTS_THR_PRGR_DHANDLE_INVALID ((ErtsThrPrgrDelayHandle) -2)
+
extern ErtsThrPrgr erts_thr_prgr__;
void erts_thr_progress_pre_init(void);
@@ -136,6 +151,8 @@ int erts_thr_progress_update(ErtsSchedulerData *esdp);
int erts_thr_progress_leader_update(ErtsSchedulerData *esdp);
void erts_thr_progress_prepare_wait(ErtsSchedulerData *esdp);
void erts_thr_progress_finalize_wait(ErtsSchedulerData *esdp);
+ErtsThrPrgrDelayHandle erts_thr_progress_unmanaged_delay__(void);
+void erts_thr_progress_unmanaged_continue__(int umrefc_ix);
void erts_thr_progress_dbg_print_state(void);
@@ -148,6 +165,11 @@ ERTS_GLB_INLINE ErtsThrPrgrVal erts_thr_prgr_read_acqb__(ERTS_THR_PRGR_ATOMIC *a
ERTS_GLB_INLINE ErtsThrPrgrVal erts_thr_prgr_read_mb__(ERTS_THR_PRGR_ATOMIC *atmc);
ERTS_GLB_INLINE int erts_thr_progress_is_managed_thread(void);
+ERTS_GLB_INLINE ErtsThrPrgrDelayHandle erts_thr_progress_unmanaged_delay(void);
+ERTS_GLB_INLINE void erts_thr_progress_unmanaged_continue(ErtsThrPrgrDelayHandle handle);
+#ifdef ERTS_ENABLE_LOCK_CHECK
+ERTS_GLB_INLINE int erts_thr_progress_lc_is_delaying(void);
+#endif
ERTS_GLB_INLINE ErtsThrPrgrVal erts_thr_progress_current_to_later__(ErtsThrPrgrVal val);
ERTS_GLB_INLINE ErtsThrPrgrVal erts_thr_progress_later(ErtsSchedulerData *);
ERTS_GLB_INLINE ErtsThrPrgrVal erts_thr_progress_current(void);
@@ -229,6 +251,35 @@ erts_thr_progress_is_managed_thread(void)
return tpd && tpd->is_managed;
}
+ERTS_GLB_INLINE ErtsThrPrgrDelayHandle
+erts_thr_progress_unmanaged_delay(void)
+{
+ if (erts_thr_progress_is_managed_thread())
+ return ERTS_THR_PRGR_DHANDLE_MANAGED; /* Nothing to do */
+ else
+ return erts_thr_progress_unmanaged_delay__();
+}
+
+ERTS_GLB_INLINE void
+erts_thr_progress_unmanaged_continue(ErtsThrPrgrDelayHandle handle)
+{
+ ASSERT(handle != ERTS_THR_PRGR_DHANDLE_MANAGED
+ || erts_thr_progress_is_managed_thread());
+ if (handle != ERTS_THR_PRGR_DHANDLE_MANAGED)
+ erts_thr_progress_unmanaged_continue__(handle);
+}
+
+#ifdef ERTS_ENABLE_LOCK_CHECK
+
+ERTS_GLB_INLINE int
+erts_thr_progress_lc_is_delaying(void)
+{
+ ErtsThrPrgrData *tpd = erts_tsd_get(erts_thr_prgr_data_key__);
+ return tpd && tpd->is_delaying;
+}
+
+#endif
+
ERTS_GLB_INLINE ErtsThrPrgrVal
erts_thr_progress_current_to_later__(ErtsThrPrgrVal val)
{
@@ -248,7 +299,7 @@ erts_thr_progress_later(ErtsSchedulerData *esdp)
if (esdp) {
tpd = &esdp->thr_progress_data;
managed_thread:
- val = tpd->previous.local;
+ val = tpd->confirmed;
ERTS_THR_MEMORY_BARRIER;
}
else {
diff --git a/erts/emulator/beam/erl_threads.h b/erts/emulator/beam/erl_threads.h
index 17628286bc..1dc3ffeb3c 100644
--- a/erts/emulator/beam/erl_threads.h
+++ b/erts/emulator/beam/erl_threads.h
@@ -533,6 +533,9 @@ ERTS_GLB_INLINE erts_aint_t erts_no_atomic_xchg(erts_no_atomic_t *xchgp,
ERTS_GLB_INLINE erts_aint_t erts_no_atomic_cmpxchg(erts_no_atomic_t *xchgp,
erts_aint_t new,
erts_aint_t expected);
+ERTS_GLB_INLINE erts_aint_t erts_no_atomic_read_bset(erts_no_atomic_t *var,
+ erts_aint_t mask,
+ erts_aint_t set);
ERTS_GLB_INLINE void erts_no_atomic32_set(erts_no_atomic32_t *var,
erts_aint32_t i);
ERTS_GLB_INLINE erts_aint32_t erts_no_atomic32_read(erts_no_atomic32_t *var);
@@ -553,6 +556,9 @@ ERTS_GLB_INLINE erts_aint32_t erts_no_atomic32_xchg(erts_no_atomic32_t *xchgp,
ERTS_GLB_INLINE erts_aint32_t erts_no_atomic32_cmpxchg(erts_no_atomic32_t *xchgp,
erts_aint32_t new,
erts_aint32_t expected);
+ERTS_GLB_INLINE erts_aint32_t erts_no_atomic32_read_bset(erts_no_atomic32_t *var,
+ erts_aint32_t mask,
+ erts_aint32_t set);
ERTS_GLB_INLINE void erts_spinlock_init_x_opt(erts_spinlock_t *lock,
char *name,
@@ -612,6 +618,78 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig);
#ifdef USE_THREADS
+ERTS_GLB_INLINE erts_aint_t
+erts_atomic_read_bset_nob(erts_atomic_t *var,
+ erts_aint_t mask,
+ erts_aint_t set);
+ERTS_GLB_INLINE erts_aint_t
+erts_atomic_read_bset_ddrb(erts_atomic_t *var,
+ erts_aint_t mask,
+ erts_aint_t set);
+ERTS_GLB_INLINE erts_aint_t
+erts_atomic_read_bset_rb(erts_atomic_t *var,
+ erts_aint_t mask,
+ erts_aint_t set);
+ERTS_GLB_INLINE erts_aint_t
+erts_atomic_read_bset_wb(erts_atomic_t *var,
+ erts_aint_t mask,
+ erts_aint_t set);
+ERTS_GLB_INLINE erts_aint_t
+erts_atomic_read_bset_acqb(erts_atomic_t *var,
+ erts_aint_t mask,
+ erts_aint_t set);
+ERTS_GLB_INLINE erts_aint_t
+erts_atomic_read_bset_relb(erts_atomic_t *var,
+ erts_aint_t mask,
+ erts_aint_t set);
+ERTS_GLB_INLINE erts_aint_t
+erts_atomic_read_bset_mb(erts_atomic_t *var,
+ erts_aint_t mask,
+ erts_aint_t set);
+ERTS_GLB_INLINE erts_aint32_t
+erts_atomic32_read_bset_nob(erts_atomic32_t *var,
+ erts_aint32_t mask,
+ erts_aint32_t set);
+ERTS_GLB_INLINE erts_aint32_t
+erts_atomic32_read_bset_ddrb(erts_atomic32_t *var,
+ erts_aint32_t mask,
+ erts_aint32_t set);
+ERTS_GLB_INLINE erts_aint32_t
+erts_atomic32_read_bset_rb(erts_atomic32_t *var,
+ erts_aint32_t mask,
+ erts_aint32_t set);
+ERTS_GLB_INLINE erts_aint32_t
+erts_atomic32_read_bset_wb(erts_atomic32_t *var,
+ erts_aint32_t mask,
+ erts_aint32_t set);
+ERTS_GLB_INLINE erts_aint32_t
+erts_atomic32_read_bset_acqb(erts_atomic32_t *var,
+ erts_aint32_t mask,
+ erts_aint32_t set);
+ERTS_GLB_INLINE erts_aint32_t
+erts_atomic32_read_bset_relb(erts_atomic32_t *var,
+ erts_aint32_t mask,
+ erts_aint32_t set);
+ERTS_GLB_INLINE erts_aint32_t
+erts_atomic32_read_bset_mb(erts_atomic32_t *var,
+ erts_aint32_t mask,
+ erts_aint32_t set);
+
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+#define ERTS_ATOMIC_BSET_IMPL__(Type, ReadOp, CmpxchgOp, VarP, Mask, Set) \
+do { \
+ Type act = ReadOp((VarP)); \
+ while (1) { \
+ Type exp = act; \
+ Type new = exp & ~(Mask); \
+ new |= ((Mask) & (Set)); \
+ act = CmpxchgOp((VarP), new, exp); \
+ if (act == exp) \
+ return act; \
+ } \
+} while (0)
+#endif
+
/*
* See "Documentation of atomics and memory barriers" at the top
* of this file for info on atomics.
@@ -670,6 +748,19 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig);
#define erts_atomic_xchg_nob ethr_atomic_xchg
#define erts_atomic_cmpxchg_nob ethr_atomic_cmpxchg
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+ERTS_GLB_INLINE erts_aint_t
+erts_atomic_read_bset_nob(erts_atomic_t *var,
+ erts_aint_t mask,
+ erts_aint_t set)
+{
+ ERTS_ATOMIC_BSET_IMPL__(erts_aint_t,
+ ethr_atomic_read,
+ ethr_atomic_cmpxchg,
+ var, mask, set);
+}
+#endif
+
#define erts_atomic_init_mb ethr_atomic_init_mb
#define erts_atomic_set_mb ethr_atomic_set_mb
#define erts_atomic_read_mb ethr_atomic_read_mb
@@ -684,6 +775,19 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig);
#define erts_atomic_xchg_mb ethr_atomic_xchg_mb
#define erts_atomic_cmpxchg_mb ethr_atomic_cmpxchg_mb
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+ERTS_GLB_INLINE erts_aint_t
+erts_atomic_read_bset_mb(erts_atomic_t *var,
+ erts_aint_t mask,
+ erts_aint_t set)
+{
+ ERTS_ATOMIC_BSET_IMPL__(erts_aint_t,
+ ethr_atomic_read,
+ ethr_atomic_cmpxchg_mb,
+ var, mask, set);
+}
+#endif
+
#define erts_atomic_init_acqb ethr_atomic_init_acqb
#define erts_atomic_set_acqb ethr_atomic_set_acqb
#define erts_atomic_read_acqb ethr_atomic_read_acqb
@@ -698,6 +802,19 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig);
#define erts_atomic_xchg_acqb ethr_atomic_xchg_acqb
#define erts_atomic_cmpxchg_acqb ethr_atomic_cmpxchg_acqb
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+ERTS_GLB_INLINE erts_aint_t
+erts_atomic_read_bset_acqb(erts_atomic_t *var,
+ erts_aint_t mask,
+ erts_aint_t set)
+{
+ ERTS_ATOMIC_BSET_IMPL__(erts_aint_t,
+ ethr_atomic_read,
+ ethr_atomic_cmpxchg_acqb,
+ var, mask, set);
+}
+#endif
+
#define erts_atomic_init_relb ethr_atomic_init_relb
#define erts_atomic_set_relb ethr_atomic_set_relb
#define erts_atomic_read_relb ethr_atomic_read_relb
@@ -712,6 +829,19 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig);
#define erts_atomic_xchg_relb ethr_atomic_xchg_relb
#define erts_atomic_cmpxchg_relb ethr_atomic_cmpxchg_relb
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+ERTS_GLB_INLINE erts_aint_t
+erts_atomic_read_bset_relb(erts_atomic_t *var,
+ erts_aint_t mask,
+ erts_aint_t set)
+{
+ ERTS_ATOMIC_BSET_IMPL__(erts_aint_t,
+ ethr_atomic_read,
+ ethr_atomic_cmpxchg_relb,
+ var, mask, set);
+}
+#endif
+
#define erts_atomic_init_ddrb ethr_atomic_init_ddrb
#define erts_atomic_set_ddrb ethr_atomic_set_ddrb
#define erts_atomic_read_ddrb ethr_atomic_read_ddrb
@@ -726,6 +856,19 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig);
#define erts_atomic_xchg_ddrb ethr_atomic_xchg_ddrb
#define erts_atomic_cmpxchg_ddrb ethr_atomic_cmpxchg_ddrb
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+ERTS_GLB_INLINE erts_aint_t
+erts_atomic_read_bset_ddrb(erts_atomic_t *var,
+ erts_aint_t mask,
+ erts_aint_t set)
+{
+ ERTS_ATOMIC_BSET_IMPL__(erts_aint_t,
+ ethr_atomic_read,
+ ethr_atomic_cmpxchg_ddrb,
+ var, mask, set);
+}
+#endif
+
#define erts_atomic_init_rb ethr_atomic_init_rb
#define erts_atomic_set_rb ethr_atomic_set_rb
#define erts_atomic_read_rb ethr_atomic_read_rb
@@ -740,6 +883,19 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig);
#define erts_atomic_xchg_rb ethr_atomic_xchg_rb
#define erts_atomic_cmpxchg_rb ethr_atomic_cmpxchg_rb
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+ERTS_GLB_INLINE erts_aint_t
+erts_atomic_read_bset_rb(erts_atomic_t *var,
+ erts_aint_t mask,
+ erts_aint_t set)
+{
+ ERTS_ATOMIC_BSET_IMPL__(erts_aint_t,
+ ethr_atomic_read,
+ ethr_atomic_cmpxchg_rb,
+ var, mask, set);
+}
+#endif
+
#define erts_atomic_init_wb ethr_atomic_init_wb
#define erts_atomic_set_wb ethr_atomic_set_wb
#define erts_atomic_read_wb ethr_atomic_read_wb
@@ -754,6 +910,19 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig);
#define erts_atomic_xchg_wb ethr_atomic_xchg_wb
#define erts_atomic_cmpxchg_wb ethr_atomic_cmpxchg_wb
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+ERTS_GLB_INLINE erts_aint_t
+erts_atomic_read_bset_wb(erts_atomic_t *var,
+ erts_aint_t mask,
+ erts_aint_t set)
+{
+ ERTS_ATOMIC_BSET_IMPL__(erts_aint_t,
+ ethr_atomic_read,
+ ethr_atomic_cmpxchg_wb,
+ var, mask, set);
+}
+#endif
+
/* 32-bit atomics */
#define erts_atomic32_init_nob ethr_atomic32_init
@@ -770,6 +939,19 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig);
#define erts_atomic32_xchg_nob ethr_atomic32_xchg
#define erts_atomic32_cmpxchg_nob ethr_atomic32_cmpxchg
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+ERTS_GLB_INLINE erts_aint32_t
+erts_atomic32_read_bset_nob(erts_atomic32_t *var,
+ erts_aint32_t mask,
+ erts_aint32_t set)
+{
+ ERTS_ATOMIC_BSET_IMPL__(erts_aint32_t,
+ ethr_atomic32_read,
+ ethr_atomic32_cmpxchg,
+ var, mask, set);
+}
+#endif
+
#define erts_atomic32_init_mb ethr_atomic32_init_mb
#define erts_atomic32_set_mb ethr_atomic32_set_mb
#define erts_atomic32_read_mb ethr_atomic32_read_mb
@@ -784,6 +966,19 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig);
#define erts_atomic32_xchg_mb ethr_atomic32_xchg_mb
#define erts_atomic32_cmpxchg_mb ethr_atomic32_cmpxchg_mb
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+ERTS_GLB_INLINE erts_aint32_t
+erts_atomic32_read_bset_mb(erts_atomic32_t *var,
+ erts_aint32_t mask,
+ erts_aint32_t set)
+{
+ ERTS_ATOMIC_BSET_IMPL__(erts_aint32_t,
+ ethr_atomic32_read,
+ ethr_atomic32_cmpxchg_mb,
+ var, mask, set);
+}
+#endif
+
#define erts_atomic32_init_acqb ethr_atomic32_init_acqb
#define erts_atomic32_set_acqb ethr_atomic32_set_acqb
#define erts_atomic32_read_acqb ethr_atomic32_read_acqb
@@ -798,6 +993,19 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig);
#define erts_atomic32_xchg_acqb ethr_atomic32_xchg_acqb
#define erts_atomic32_cmpxchg_acqb ethr_atomic32_cmpxchg_acqb
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+ERTS_GLB_INLINE erts_aint32_t
+erts_atomic32_read_bset_acqb(erts_atomic32_t *var,
+ erts_aint32_t mask,
+ erts_aint32_t set)
+{
+ ERTS_ATOMIC_BSET_IMPL__(erts_aint32_t,
+ ethr_atomic32_read,
+ ethr_atomic32_cmpxchg_acqb,
+ var, mask, set);
+}
+#endif
+
#define erts_atomic32_init_relb ethr_atomic32_init_relb
#define erts_atomic32_set_relb ethr_atomic32_set_relb
#define erts_atomic32_read_relb ethr_atomic32_read_relb
@@ -812,6 +1020,19 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig);
#define erts_atomic32_xchg_relb ethr_atomic32_xchg_relb
#define erts_atomic32_cmpxchg_relb ethr_atomic32_cmpxchg_relb
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+ERTS_GLB_INLINE erts_aint32_t
+erts_atomic32_read_bset_relb(erts_atomic32_t *var,
+ erts_aint32_t mask,
+ erts_aint32_t set)
+{
+ ERTS_ATOMIC_BSET_IMPL__(erts_aint32_t,
+ ethr_atomic32_read,
+ ethr_atomic32_cmpxchg_relb,
+ var, mask, set);
+}
+#endif
+
#define erts_atomic32_init_ddrb ethr_atomic32_init_ddrb
#define erts_atomic32_set_ddrb ethr_atomic32_set_ddrb
#define erts_atomic32_read_ddrb ethr_atomic32_read_ddrb
@@ -826,6 +1047,19 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig);
#define erts_atomic32_xchg_ddrb ethr_atomic32_xchg_ddrb
#define erts_atomic32_cmpxchg_ddrb ethr_atomic32_cmpxchg_ddrb
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+ERTS_GLB_INLINE erts_aint32_t
+erts_atomic32_read_bset_ddrb(erts_atomic32_t *var,
+ erts_aint32_t mask,
+ erts_aint32_t set)
+{
+ ERTS_ATOMIC_BSET_IMPL__(erts_aint32_t,
+ ethr_atomic32_read,
+ ethr_atomic32_cmpxchg_ddrb,
+ var, mask, set);
+}
+#endif
+
#define erts_atomic32_init_rb ethr_atomic32_init_rb
#define erts_atomic32_set_rb ethr_atomic32_set_rb
#define erts_atomic32_read_rb ethr_atomic32_read_rb
@@ -840,6 +1074,19 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig);
#define erts_atomic32_xchg_rb ethr_atomic32_xchg_rb
#define erts_atomic32_cmpxchg_rb ethr_atomic32_cmpxchg_rb
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+ERTS_GLB_INLINE erts_aint32_t
+erts_atomic32_read_bset_rb(erts_atomic32_t *var,
+ erts_aint32_t mask,
+ erts_aint32_t set)
+{
+ ERTS_ATOMIC_BSET_IMPL__(erts_aint32_t,
+ ethr_atomic32_read,
+ ethr_atomic32_cmpxchg_rb,
+ var, mask, set);
+}
+#endif
+
#define erts_atomic32_init_wb ethr_atomic32_init_wb
#define erts_atomic32_set_wb ethr_atomic32_set_wb
#define erts_atomic32_read_wb ethr_atomic32_read_wb
@@ -854,6 +1101,21 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig);
#define erts_atomic32_xchg_wb ethr_atomic32_xchg_wb
#define erts_atomic32_cmpxchg_wb ethr_atomic32_cmpxchg_wb
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+ERTS_GLB_INLINE erts_aint32_t
+erts_atomic32_read_bset_wb(erts_atomic32_t *var,
+ erts_aint32_t mask,
+ erts_aint32_t set)
+{
+ ERTS_ATOMIC_BSET_IMPL__(erts_aint32_t,
+ ethr_atomic32_read,
+ ethr_atomic32_cmpxchg_wb,
+ var, mask, set);
+}
+#endif
+
+#undef ERTS_ATOMIC_BSET_IMPL__
+
#else /* !USE_THREADS */
/* Double word size atomics */
@@ -908,6 +1170,7 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig);
#define erts_atomic_read_band_nob erts_no_atomic_read_band
#define erts_atomic_xchg_nob erts_no_atomic_xchg
#define erts_atomic_cmpxchg_nob erts_no_atomic_cmpxchg
+#define erts_atomic_read_bset_nob erts_no_atomic_read_bset
#define erts_atomic_init_mb erts_no_atomic_set
#define erts_atomic_set_mb erts_no_atomic_set
@@ -922,6 +1185,7 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig);
#define erts_atomic_read_band_mb erts_no_atomic_read_band
#define erts_atomic_xchg_mb erts_no_atomic_xchg
#define erts_atomic_cmpxchg_mb erts_no_atomic_cmpxchg
+#define erts_atomic_read_bset_mb erts_no_atomic_read_bset
#define erts_atomic_init_acqb erts_no_atomic_set
#define erts_atomic_set_acqb erts_no_atomic_set
@@ -936,6 +1200,7 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig);
#define erts_atomic_read_band_acqb erts_no_atomic_read_band
#define erts_atomic_xchg_acqb erts_no_atomic_xchg
#define erts_atomic_cmpxchg_acqb erts_no_atomic_cmpxchg
+#define erts_atomic_read_bset_acqb erts_no_atomic_read_bset
#define erts_atomic_init_relb erts_no_atomic_set
#define erts_atomic_set_relb erts_no_atomic_set
@@ -950,6 +1215,7 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig);
#define erts_atomic_read_band_relb erts_no_atomic_read_band
#define erts_atomic_xchg_relb erts_no_atomic_xchg
#define erts_atomic_cmpxchg_relb erts_no_atomic_cmpxchg
+#define erts_atomic_read_bset_relb erts_no_atomic_read_bset
#define erts_atomic_init_ddrb erts_no_atomic_set
#define erts_atomic_set_ddrb erts_no_atomic_set
@@ -964,6 +1230,7 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig);
#define erts_atomic_read_band_ddrb erts_no_atomic_read_band
#define erts_atomic_xchg_ddrb erts_no_atomic_xchg
#define erts_atomic_cmpxchg_ddrb erts_no_atomic_cmpxchg
+#define erts_atomic_read_bset_ddrb erts_no_atomic_read_bset
#define erts_atomic_init_rb erts_no_atomic_set
#define erts_atomic_set_rb erts_no_atomic_set
@@ -978,6 +1245,7 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig);
#define erts_atomic_read_band_rb erts_no_atomic_read_band
#define erts_atomic_xchg_rb erts_no_atomic_xchg
#define erts_atomic_cmpxchg_rb erts_no_atomic_cmpxchg
+#define erts_atomic_read_bset_rb erts_no_atomic_read_bset
#define erts_atomic_init_wb erts_no_atomic_set
#define erts_atomic_set_wb erts_no_atomic_set
@@ -992,6 +1260,7 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig);
#define erts_atomic_read_band_wb erts_no_atomic_read_band
#define erts_atomic_xchg_wb erts_no_atomic_xchg
#define erts_atomic_cmpxchg_wb erts_no_atomic_cmpxchg
+#define erts_atomic_read_bset_wb erts_no_atomic_read_bset
/* 32-bit atomics */
@@ -1008,6 +1277,7 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig);
#define erts_atomic32_read_band_nob erts_no_atomic32_read_band
#define erts_atomic32_xchg_nob erts_no_atomic32_xchg
#define erts_atomic32_cmpxchg_nob erts_no_atomic32_cmpxchg
+#define erts_atomic32_read_bset_nob erts_no_atomic32_read_bset
#define erts_atomic32_init_mb erts_no_atomic32_set
#define erts_atomic32_set_mb erts_no_atomic32_set
@@ -1022,6 +1292,7 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig);
#define erts_atomic32_read_band_mb erts_no_atomic32_read_band
#define erts_atomic32_xchg_mb erts_no_atomic32_xchg
#define erts_atomic32_cmpxchg_mb erts_no_atomic32_cmpxchg
+#define erts_atomic32_read_bset_mb erts_no_atomic32_read_bset
#define erts_atomic32_init_acqb erts_no_atomic32_set
#define erts_atomic32_set_acqb erts_no_atomic32_set
@@ -1036,6 +1307,7 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig);
#define erts_atomic32_read_band_acqb erts_no_atomic32_read_band
#define erts_atomic32_xchg_acqb erts_no_atomic32_xchg
#define erts_atomic32_cmpxchg_acqb erts_no_atomic32_cmpxchg
+#define erts_atomic32_read_bset_acqb erts_no_atomic32_read_bset
#define erts_atomic32_init_relb erts_no_atomic32_set
#define erts_atomic32_set_relb erts_no_atomic32_set
@@ -1050,6 +1322,7 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig);
#define erts_atomic32_read_band_relb erts_no_atomic32_read_band
#define erts_atomic32_xchg_relb erts_no_atomic32_xchg
#define erts_atomic32_cmpxchg_relb erts_no_atomic32_cmpxchg
+#define erts_atomic32_read_bset_relb erts_no_atomic32_read_bset
#define erts_atomic32_init_ddrb erts_no_atomic32_set
#define erts_atomic32_set_ddrb erts_no_atomic32_set
@@ -1064,6 +1337,7 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig);
#define erts_atomic32_read_band_ddrb erts_no_atomic32_read_band
#define erts_atomic32_xchg_ddrb erts_no_atomic32_xchg
#define erts_atomic32_cmpxchg_ddrb erts_no_atomic32_cmpxchg
+#define erts_atomic32_read_bset_ddrb erts_no_atomic32_read_bset
#define erts_atomic32_init_rb erts_no_atomic32_set
#define erts_atomic32_set_rb erts_no_atomic32_set
@@ -1078,6 +1352,7 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig);
#define erts_atomic32_read_band_rb erts_no_atomic32_read_band
#define erts_atomic32_xchg_rb erts_no_atomic32_xchg
#define erts_atomic32_cmpxchg_rb erts_no_atomic32_cmpxchg
+#define erts_atomic32_read_bset_rb erts_no_atomic32_read_bset
#define erts_atomic32_init_wb erts_no_atomic32_set
#define erts_atomic32_set_wb erts_no_atomic32_set
@@ -1092,6 +1367,7 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig);
#define erts_atomic32_read_band_wb erts_no_atomic32_read_band
#define erts_atomic32_xchg_wb erts_no_atomic32_xchg
#define erts_atomic32_cmpxchg_wb erts_no_atomic32_cmpxchg
+#define erts_atomic32_read_bset_wb erts_no_atomic32_read_bset
#endif /* !USE_THREADS */
@@ -1856,6 +2132,17 @@ erts_no_atomic_cmpxchg(erts_no_atomic_t *xchgp,
return old;
}
+ERTS_GLB_INLINE erts_aint_t
+erts_no_atomic_read_bset(erts_no_atomic_t *var,
+ erts_aint_t mask,
+ erts_aint_t set)
+{
+ erts_aint_t old = *var;
+ *var &= ~mask;
+ *var |= (mask & set);
+ return old;
+}
+
/* atomic32 */
ERTS_GLB_INLINE void
@@ -1943,6 +2230,17 @@ erts_no_atomic32_cmpxchg(erts_no_atomic32_t *xchgp,
return old;
}
+ERTS_GLB_INLINE erts_aint32_t
+erts_no_atomic32_read_bset(erts_no_atomic32_t *var,
+ erts_aint32_t mask,
+ erts_aint32_t set)
+{
+ erts_aint32_t old = *var;
+ *var &= ~mask;
+ *var |= (mask & set);
+ return old;
+}
+
/* spinlock */
ERTS_GLB_INLINE void
diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c
index d04a91f18c..848877d43e 100644
--- a/erts/emulator/beam/erl_trace.c
+++ b/erts/emulator/beam/erl_trace.c
@@ -44,9 +44,9 @@
#undef DEBUG_PRINTOUTS
#endif
-extern Eterm beam_return_to_trace[1]; /* OpCode(i_return_to_trace) */
-extern Eterm beam_return_trace[1]; /* OpCode(i_return_trace) */
-extern Eterm beam_return_time_trace[1]; /* OpCode(i_return_time_trace) */
+extern BeamInstr beam_return_to_trace[1]; /* OpCode(i_return_to_trace) */
+extern BeamInstr beam_return_trace[1]; /* OpCode(i_return_trace) */
+extern BeamInstr beam_return_time_trace[1]; /* OpCode(i_return_time_trace) */
/* Pseudo export entries. Never filled in with data, only used to
yield unique pointers of the correct type. */
@@ -156,8 +156,8 @@ do { (RES) = (TPID); } while(0)
#define ERTS_TRACER_REF_TYPE Process *
#define ERTS_GET_TRACER_REF(RES, TPID, TRACEE_FLGS) \
do { \
- (RES) = erts_proc_lookup((TPID)); \
- if (!(RES) || !((RES)->trace_flags & F_TRACER)) { \
+ (RES) = erts_proc_lookup((TPID)); \
+ if (!(RES) || !(ERTS_TRACE_FLAGS((RES)) & F_TRACER)) { \
(TPID) = NIL; \
(TRACEE_FLGS) &= ~TRACEE_FLAGS; \
return; \
@@ -409,7 +409,7 @@ WRITE_SYS_MSG_TO_PORT(Eterm unused_to,
}
#ifndef ERTS_SMP
- if (!INVALID_TRACER_PORT(trace_port, trace_port->id))
+ if (!INVALID_TRACER_PORT(trace_port, trace_port->common.id))
#endif
erts_raw_port_command(trace_port, buffer, ptr-buffer);
@@ -441,7 +441,7 @@ do_send_schedfix_to_port(Port *trace_port, Eterm pid, Eterm timestamp) {
message = TUPLE5(hp, am_trace_ts, pid, am_out, mfarity, timestamp);
/* Note, hp is deliberately NOT incremented since it will be reused */
- do_send_to_port(trace_port->id,
+ do_send_to_port(trace_port->common.id,
trace_port,
pid,
SYS_MSG_TYPE_UNDEFINED,
@@ -451,7 +451,7 @@ do_send_schedfix_to_port(Port *trace_port, Eterm pid, Eterm timestamp) {
hp += 5;
hp = patch_ts(message, hp);
- do_send_to_port(trace_port->id,
+ do_send_to_port(trace_port->common.id,
trace_port,
pid,
SYS_MSG_TYPE_UNDEFINED,
@@ -508,7 +508,7 @@ send_to_port(Process *c_p, Eterm message,
#endif
do_send_to_port(*tracer_pid,
trace_port,
- c_p ? c_p->id : NIL,
+ c_p ? c_p->common.id : NIL,
SYS_MSG_TYPE_TRACE,
message);
#ifndef ERTS_SMP
@@ -543,7 +543,7 @@ send_to_port(Process *c_p, Eterm message,
trace_port->control_flags &= ~PORT_CONTROL_FLAG_HEAVY;
do_send_to_port(*tracer_pid,
trace_port,
- c_p ? c_p->id : NIL,
+ c_p ? c_p->common.id : NIL,
SYS_MSG_TYPE_TRACE,
message);
@@ -557,7 +557,7 @@ send_to_port(Process *c_p, Eterm message,
* just after writning the real trace message, and now gets scheduled
* in again.
*/
- do_send_schedfix_to_port(trace_port, c_p->id, ts);
+ do_send_schedfix_to_port(trace_port, c_p->common.id, ts);
}
erts_port_release(trace_port);
@@ -599,15 +599,14 @@ profile_send(Eterm from, Eterm message) {
if (profiler_port) {
do_send_to_port(profiler,
profiler_port,
- NIL, /* or current process->id */
+ NIL, /* or current process->common.id */
SYS_MSG_TYPE_SYSPROF,
message);
erts_port_release(profiler_port);
}
} else {
- ASSERT(is_internal_pid(profiler)
- && internal_pid_index(profiler) < erts_max_processes);
+ ASSERT(is_internal_pid(profiler));
profile_p = erts_proc_lookup(profiler);
@@ -673,7 +672,7 @@ seq_trace_send_to_port(Process *c_p,
#endif
do_send_to_port(seq_tracer,
trace_port,
- c_p ? c_p->id : NIL,
+ c_p ? c_p->common.id : NIL,
SYS_MSG_TYPE_SEQTRACE,
message);
@@ -704,7 +703,7 @@ seq_trace_send_to_port(Process *c_p,
trace_port->control_flags &= ~PORT_CONTROL_FLAG_HEAVY;
do_send_to_port(seq_tracer,
trace_port,
- c_p ? c_p->id : NIL,
+ c_p ? c_p->common.id : NIL,
SYS_MSG_TYPE_SEQTRACE,
message);
@@ -718,7 +717,7 @@ seq_trace_send_to_port(Process *c_p,
* just after writing the real trace message, and now gets scheduled
* in again.
*/
- do_send_schedfix_to_port(trace_port, c_p->id, ts);
+ do_send_schedfix_to_port(trace_port, c_p->common.id, ts);
}
erts_port_release(trace_port);
@@ -729,7 +728,9 @@ seq_trace_send_to_port(Process *c_p,
}
#define TS_HEAP_WORDS 5
-#define TS_SIZE(p) (((p)->trace_flags & F_TIMESTAMP) ? TS_HEAP_WORDS : 0)
+#define TS_SIZE(p) ((ERTS_TRACE_FLAGS((p)) & F_TIMESTAMP) \
+ ? TS_HEAP_WORDS \
+ : 0)
/*
* Patch a timestamp into a tuple. The tuple must be the last thing
@@ -764,17 +765,17 @@ send_to_tracer(Process *tracee,
erts_smp_mtx_lock(&smq_mtx);
- if (tracee->trace_flags & F_TIMESTAMP)
+ if (ERTS_TRACE_FLAGS(tracee) & F_TIMESTAMP)
*hpp = patch_ts(msg, *hpp);
- if (is_internal_pid(tracee->tracer_proc))
- ERTS_ENQ_TRACE_MSG(tracee->id, tracer_ref, msg, bp);
+ if (is_internal_pid(ERTS_TRACER_PROC(tracee)))
+ ERTS_ENQ_TRACE_MSG(tracee->common.id, tracer_ref, msg, bp);
else {
- ASSERT(is_internal_port(tracee->tracer_proc));
+ ASSERT(is_internal_port(ERTS_TRACER_PROC(tracee)));
send_to_port(no_fake_sched ? NULL : tracee,
msg,
- &tracee->tracer_proc,
- &tracee->trace_flags);
+ &ERTS_TRACER_PROC(tracee),
+ &ERTS_TRACE_FLAGS(tracee));
}
erts_smp_mtx_unlock(&smq_mtx);
@@ -792,7 +793,7 @@ trace_sched_aux(Process *p, Eterm what, int never_fake_sched)
ERTS_TRACER_REF_TYPE tracer_ref = ERTS_NULL_TRACER_REF;
int sched_no, curr_func, to_port, no_fake_sched;
- if (is_nil(p->tracer_proc))
+ if (is_nil(ERTS_TRACER_PROC(p)))
return;
no_fake_sched = never_fake_sched;
@@ -812,13 +813,14 @@ trace_sched_aux(Process *p, Eterm what, int never_fake_sched)
}
sched_no = IS_TRACED_FL(p, F_TRACE_SCHED_NO);
- to_port = is_internal_port(p->tracer_proc);
+ to_port = is_internal_port(ERTS_TRACER_PROC(p));
if (!to_port) {
- ASSERT(is_internal_pid(p->tracer_proc)
- && internal_pid_index(p->tracer_proc) < erts_max_processes);
+ ASSERT(is_internal_pid(ERTS_TRACER_PROC(p)));
- ERTS_GET_TRACER_REF(tracer_ref, p->tracer_proc, p->trace_flags);
+ ERTS_GET_TRACER_REF(tracer_ref,
+ ERTS_TRACER_PROC(p),
+ ERTS_TRACE_FLAGS(p));
}
if (ERTS_PROC_IS_EXITING(p))
@@ -851,7 +853,7 @@ trace_sched_aux(Process *p, Eterm what, int never_fake_sched)
}
if (!sched_no) {
- mess = TUPLE4(hp, am_trace, p->id, what, tmp);
+ mess = TUPLE4(hp, am_trace, p->common.id, what, tmp);
hp += 5;
}
else {
@@ -860,7 +862,7 @@ trace_sched_aux(Process *p, Eterm what, int never_fake_sched)
#else
Eterm sched_id = make_small(1);
#endif
- mess = TUPLE5(hp, am_trace, p->id, what, sched_id, tmp);
+ mess = TUPLE5(hp, am_trace, p->common.id, what, sched_id, tmp);
hp += 6;
}
@@ -912,19 +914,19 @@ trace_send(Process *p, Eterm to, Eterm msg)
operation = am_atom_put(s, sys_strlen(s));
}
- if (is_internal_port(p->tracer_proc)) {
+ if (is_internal_port(ERTS_TRACER_PROC(p))) {
#define LOCAL_HEAP_SIZE (11)
DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE);
UseTmpHeapNoproc(LOCAL_HEAP_SIZE);
hp = local_heap;
- mess = TUPLE5(hp, am_trace, p->id, operation, msg, to);
+ mess = TUPLE5(hp, am_trace, p->common.id, operation, msg, to);
hp += 6;
erts_smp_mtx_lock(&smq_mtx);
- if (p->trace_flags & F_TIMESTAMP) {
+ if (ERTS_TRACE_FLAGS(p) & F_TIMESTAMP) {
hp = patch_ts(mess, hp);
}
- send_to_port(p, mess, &p->tracer_proc, &p->trace_flags);
+ send_to_port(p, mess, &ERTS_TRACER_PROC(p), &ERTS_TRACE_FLAGS(p));
UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
#undef LOCAL_HEAP_SIZE
erts_smp_mtx_unlock(&smq_mtx);
@@ -934,10 +936,11 @@ trace_send(Process *p, Eterm to, Eterm msg)
ErlOffHeap *off_heap;
ERTS_TRACER_REF_TYPE tracer_ref;
- ASSERT(is_internal_pid(p->tracer_proc)
- && internal_pid_index(p->tracer_proc) < erts_max_processes);
+ ASSERT(is_internal_pid(ERTS_TRACER_PROC(p)));
- ERTS_GET_TRACER_REF(tracer_ref, p->tracer_proc, p->trace_flags);
+ ERTS_GET_TRACER_REF(tracer_ref,
+ ERTS_TRACER_PROC(p),
+ ERTS_TRACE_FLAGS(p));
sz_msg = size_object(msg);
sz_to = size_object(to);
@@ -953,16 +956,16 @@ trace_send(Process *p, Eterm to, Eterm msg)
sz_msg,
&hp,
off_heap);
- mess = TUPLE5(hp, am_trace, p->id/* Local pid */, operation, msg, to);
+ mess = TUPLE5(hp, am_trace, p->common.id, operation, msg, to);
hp += 6;
erts_smp_mtx_lock(&smq_mtx);
- if (p->trace_flags & F_TIMESTAMP) {
+ if (ERTS_TRACE_FLAGS(p) & F_TIMESTAMP) {
patch_ts(mess, hp);
}
- ERTS_ENQ_TRACE_MSG(p->id, tracer_ref, mess, bp);
+ ERTS_ENQ_TRACE_MSG(p->common.id, tracer_ref, mess, bp);
erts_smp_mtx_unlock(&smq_mtx);
}
}
@@ -977,19 +980,19 @@ trace_receive(Process *rp, Eterm msg)
size_t sz_msg;
Eterm* hp;
- if (is_internal_port(rp->tracer_proc)) {
+ if (is_internal_port(ERTS_TRACER_PROC(rp))) {
#define LOCAL_HEAP_SIZE (10)
DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE);
UseTmpHeapNoproc(LOCAL_HEAP_SIZE);
hp = local_heap;
- mess = TUPLE4(hp, am_trace, rp->id, am_receive, msg);
+ mess = TUPLE4(hp, am_trace, rp->common.id, am_receive, msg);
hp += 5;
erts_smp_mtx_lock(&smq_mtx);
- if (rp->trace_flags & F_TIMESTAMP) {
+ if (ERTS_TRACE_FLAGS(rp) & F_TIMESTAMP) {
hp = patch_ts(mess, hp);
}
- send_to_port(rp, mess, &rp->tracer_proc, &rp->trace_flags);
+ send_to_port(rp, mess, &ERTS_TRACER_PROC(rp), &ERTS_TRACE_FLAGS(rp));
UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
#undef LOCAL_HEAP_SIZE
erts_smp_mtx_unlock(&smq_mtx);
@@ -999,10 +1002,11 @@ trace_receive(Process *rp, Eterm msg)
ErlOffHeap *off_heap;
ERTS_TRACER_REF_TYPE tracer_ref;
- ASSERT(is_internal_pid(rp->tracer_proc)
- && internal_pid_index(rp->tracer_proc) < erts_max_processes);
+ ASSERT(is_internal_pid(ERTS_TRACER_PROC(rp)));
- ERTS_GET_TRACER_REF(tracer_ref, rp->tracer_proc, rp->trace_flags);
+ ERTS_GET_TRACER_REF(tracer_ref,
+ ERTS_TRACER_PROC(rp),
+ ERTS_TRACE_FLAGS(rp));
sz_msg = size_object(msg);
@@ -1011,16 +1015,16 @@ trace_receive(Process *rp, Eterm msg)
hp = ERTS_ALLOC_SYSMSG_HEAP(hsz, &bp, &off_heap, tracer_ref);
msg = copy_struct(msg, sz_msg, &hp, off_heap);
- mess = TUPLE4(hp, am_trace, rp->id/* Local pid */, am_receive, msg);
+ mess = TUPLE4(hp, am_trace, rp->common.id, am_receive, msg);
hp += 5;
erts_smp_mtx_lock(&smq_mtx);
- if (rp->trace_flags & F_TIMESTAMP) {
+ if (ERTS_TRACE_FLAGS(rp) & F_TIMESTAMP) {
patch_ts(mess, hp);
}
- ERTS_ENQ_TRACE_MSG(rp->id, tracer_ref, mess, bp);
+ ERTS_ENQ_TRACE_MSG(rp->common.id, tracer_ref, mess, bp);
erts_smp_mtx_unlock(&smq_mtx);
}
}
@@ -1030,14 +1034,14 @@ seq_trace_update_send(Process *p)
{
Eterm seq_tracer = erts_get_system_seq_tracer();
ASSERT((is_tuple(SEQ_TRACE_TOKEN(p)) || is_nil(SEQ_TRACE_TOKEN(p))));
- if ( (p->id == seq_tracer) || (SEQ_TRACE_TOKEN(p) == NIL)
+ if ( (p->common.id == seq_tracer) || (SEQ_TRACE_TOKEN(p) == NIL)
#ifdef USE_VM_PROBES
|| (SEQ_TRACE_TOKEN(p) == am_have_dt_utag)
#endif
) {
return 0;
}
- SEQ_TRACE_TOKEN_SENDER(p) = p->id; /* Internal pid */
+ SEQ_TRACE_TOKEN_SENDER(p) = p->common.id;
SEQ_TRACE_TOKEN_SERIAL(p) =
make_small(++(p -> seq_trace_clock));
SEQ_TRACE_TOKEN_LASTCNT(p) =
@@ -1074,7 +1078,7 @@ seq_trace_output_generic(Eterm token, Eterm msg, Uint type,
ASSERT(is_tuple(token) || is_nil(token));
if (SEQ_TRACE_T_SENDER(token) == seq_tracer || token == NIL ||
- (process && process->trace_flags & F_SENSITIVE)) {
+ (process && ERTS_TRACE_FLAGS(process) & F_SENSITIVE)) {
return;
}
@@ -1138,8 +1142,7 @@ seq_trace_output_generic(Eterm token, Eterm msg, Uint type,
Uint sz_label, sz_lastcnt_serial, sz_msg, sz_ts, sz_sender,
sz_exitfrom, sz_receiver;
- ASSERT(is_internal_pid(seq_tracer)
- && internal_pid_index(seq_tracer) < erts_max_processes);
+ ASSERT(is_internal_pid(seq_tracer));
#ifndef ERTS_SMP
@@ -1253,17 +1256,17 @@ erts_trace_return_to(Process *p, BeamInstr *pc)
hp += 4;
}
- mess = TUPLE4(hp, am_trace, p->id, am_return_to, mfa);
+ mess = TUPLE4(hp, am_trace, p->common.id, am_return_to, mfa);
hp += 5;
erts_smp_mtx_lock(&smq_mtx);
- if (p->trace_flags & F_TIMESTAMP) {
+ if (ERTS_TRACE_FLAGS(p) & F_TIMESTAMP) {
hp = patch_ts(mess, hp);
}
- if (is_internal_port(p->tracer_proc)) {
- send_to_port(p, mess, &p->tracer_proc, &p->trace_flags);
+ if (is_internal_port(ERTS_TRACER_PROC(p))) {
+ send_to_port(p, mess, &ERTS_TRACER_PROC(p), &ERTS_TRACE_FLAGS(p));
} else {
ErlHeapFragment *bp;
ErlOffHeap *off_heap;
@@ -1273,10 +1276,11 @@ erts_trace_return_to(Process *p, BeamInstr *pc)
/*
* Find the tracer.
*/
- ASSERT(is_internal_pid(p->tracer_proc)
- && internal_pid_index(p->tracer_proc) < erts_max_processes);
+ ASSERT(is_internal_pid(ERTS_TRACER_PROC(p)));
- ERTS_GET_TRACER_REF(tracer_ref, p->tracer_proc, p->trace_flags);
+ ERTS_GET_TRACER_REF(tracer_ref,
+ ERTS_TRACER_PROC(p),
+ ERTS_TRACE_FLAGS(p));
size = size_object(mess);
@@ -1286,7 +1290,7 @@ erts_trace_return_to(Process *p, BeamInstr *pc)
* Copy the trace message into the buffer and enqueue it.
*/
mess = copy_struct(mess, size, &hp, off_heap);
- ERTS_ENQ_TRACE_MSG(p->id, tracer_ref, mess, bp);
+ ERTS_ENQ_TRACE_MSG(p->common.id, tracer_ref, mess, bp);
}
UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
#undef LOCAL_HEAP_SIZE
@@ -1315,25 +1319,25 @@ erts_trace_return(Process* p, BeamInstr* fi, Eterm retval, Eterm *tracer_pid)
/* Breakpoint trace enabled without specifying tracer =>
* use process tracer and flags
*/
- tracer_pid = &p->tracer_proc;
+ tracer_pid = &ERTS_TRACER_PROC(p);
}
if (is_nil(*tracer_pid)) {
/* Trace disabled */
return;
}
ASSERT(is_internal_pid(*tracer_pid) || is_internal_port(*tracer_pid));
- if (*tracer_pid == p->id) {
+ if (*tracer_pid == p->common.id) {
/* Do not generate trace messages to oneself */
return;
}
- if (tracer_pid == &p->tracer_proc) {
+ if (tracer_pid == &ERTS_TRACER_PROC(p)) {
/* Tracer specified in process structure =>
* non-breakpoint trace =>
* use process flags
*/
- tracee_flags = &p->trace_flags;
+ tracee_flags = &ERTS_TRACE_FLAGS(p);
#ifdef ERTS_SMP
- tracee = p->id;
+ tracee = p->common.id;
#endif
} else {
/* Tracer not specified in process structure =>
@@ -1362,7 +1366,7 @@ erts_trace_return(Process* p, BeamInstr* fi, Eterm retval, Eterm *tracer_pid)
hp = local_heap;
mfa = TUPLE3(hp, mod, name, make_small(arity));
hp += 4;
- mess = TUPLE5(hp, am_trace, p->id, am_return_from, mfa, retval);
+ mess = TUPLE5(hp, am_trace, p->common.id, am_return_from, mfa, retval);
hp += 6;
erts_smp_mtx_lock(&smq_mtx);
if (*tracee_flags & F_TIMESTAMP) {
@@ -1382,8 +1386,7 @@ erts_trace_return(Process* p, BeamInstr* fi, Eterm retval, Eterm *tracer_pid)
Eterm* limit;
#endif
- ASSERT(is_internal_pid(*tracer_pid)
- && internal_pid_index(*tracer_pid) < erts_max_processes);
+ ASSERT(is_internal_pid(*tracer_pid));
ERTS_GET_TRACER_REF(tracer_ref, *tracer_pid, *tracee_flags);
@@ -1405,7 +1408,7 @@ erts_trace_return(Process* p, BeamInstr* fi, Eterm retval, Eterm *tracer_pid)
mfa = TUPLE3(hp, mod, name, make_small(arity));
hp += 4;
retval = copy_struct(retval, retval_size, &hp, off_heap);
- mess = TUPLE5(hp, am_trace, p->id/* Local pid */, am_return_from, mfa, retval);
+ mess = TUPLE5(hp, am_trace, p->common.id, am_return_from, mfa, retval);
hp += 6;
erts_smp_mtx_lock(&smq_mtx);
@@ -1446,25 +1449,25 @@ erts_trace_exception(Process* p, BeamInstr mfa[3], Eterm class, Eterm value,
/* Breakpoint trace enabled without specifying tracer =>
* use process tracer and flags
*/
- tracer_pid = &p->tracer_proc;
+ tracer_pid = &ERTS_TRACER_PROC(p);
}
if (is_nil(*tracer_pid)) {
/* Trace disabled */
return;
}
ASSERT(is_internal_pid(*tracer_pid) || is_internal_port(*tracer_pid));
- if (*tracer_pid == p->id) {
+ if (*tracer_pid == p->common.id) {
/* Do not generate trace messages to oneself */
return;
}
- if (tracer_pid == &p->tracer_proc) {
+ if (tracer_pid == &ERTS_TRACER_PROC(p)) {
/* Tracer specified in process structure =>
* non-breakpoint trace =>
* use process flags
*/
- tracee_flags = &p->trace_flags;
+ tracee_flags = &ERTS_TRACE_FLAGS(p);
#ifdef ERTS_SMP
- tracee = p->id;
+ tracee = p->common.id;
#endif
if (! (*tracee_flags & F_TRACE_CALLS)) {
return;
@@ -1492,7 +1495,7 @@ erts_trace_exception(Process* p, BeamInstr mfa[3], Eterm class, Eterm value,
hp += 4;
cv = TUPLE2(hp, class, value);
hp += 3;
- mess = TUPLE5(hp, am_trace, p->id, am_exception_from, mfa_tuple, cv);
+ mess = TUPLE5(hp, am_trace, p->common.id, am_exception_from, mfa_tuple, cv);
hp += 6;
ASSERT((hp - local_heap) <= LOCAL_HEAP_SIZE);
erts_smp_mtx_lock(&smq_mtx);
@@ -1514,8 +1517,7 @@ erts_trace_exception(Process* p, BeamInstr mfa[3], Eterm class, Eterm value,
Eterm* limit;
#endif
- ASSERT(is_internal_pid(*tracer_pid)
- && internal_pid_index(*tracer_pid) < erts_max_processes);
+ ASSERT(is_internal_pid(*tracer_pid));
ERTS_GET_TRACER_REF(tracer_ref, *tracer_pid, *tracee_flags);
@@ -1539,7 +1541,7 @@ erts_trace_exception(Process* p, BeamInstr mfa[3], Eterm class, Eterm value,
value = copy_struct(value, value_size, &hp, off_heap);
cv = TUPLE2(hp, class, value);
hp += 3;
- mess = TUPLE5(hp, am_trace, p->id/* Local pid */,
+ mess = TUPLE5(hp, am_trace, p->common.id,
am_exception_from, mfa_tuple, cv);
hp += 6;
@@ -1593,25 +1595,25 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec,
/* Breakpoint trace enabled without specifying tracer =>
* use process tracer and flags
*/
- tracer_pid = &p->tracer_proc;
+ tracer_pid = &ERTS_TRACER_PROC(p);
}
if (is_nil(*tracer_pid)) {
/* Trace disabled */
return 0;
}
ASSERT(is_internal_pid(*tracer_pid) || is_internal_port(*tracer_pid));
- if (*tracer_pid == p->id) {
+ if (*tracer_pid == p->common.id) {
/* Do not generate trace messages to oneself */
return 0;
}
- if (tracer_pid == &p->tracer_proc) {
+ if (tracer_pid == &ERTS_TRACER_PROC(p)) {
/* Tracer specified in process structure =>
* non-breakpoint trace =>
* use process flags
*/
- tracee_flags = &p->trace_flags;
+ tracee_flags = &ERTS_TRACE_FLAGS(p);
#ifdef ERTS_SMP
- tracee = p->id;
+ tracee = p->common.id;
#endif
} else {
/* Tracer not specified in process structure =>
@@ -1619,7 +1621,7 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec,
* meta trace =>
* use fixed flag set instead of process flags
*/
- if (p->trace_flags & F_SENSITIVE) {
+ if (ERTS_TRACE_FLAGS(p) & F_SENSITIVE) {
/* No trace messages for sensitive processes. */
return 0;
}
@@ -1677,7 +1679,7 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec,
if (!erts_is_valid_tracer_port(*tracer_pid)) {
#ifdef ERTS_SMP
- ASSERT(is_nil(tracee) || tracer_pid == &p->tracer_proc);
+ ASSERT(is_nil(tracee) || tracer_pid == &ERTS_TRACER_PROC(p));
if (is_not_nil(tracee))
erts_smp_proc_lock(p, ERTS_PROC_LOCKS_ALL_MINOR);
#endif
@@ -1779,7 +1781,7 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec,
* Build the trace tuple and send it to the port.
*/
- mess = TUPLE4(hp, am_trace, p->id, am_call, mfa_tuple);
+ mess = TUPLE4(hp, am_trace, p->common.id, am_call, mfa_tuple);
hp += 5;
if (pam_result != am_true) {
hp[-5] = make_arityval(5);
@@ -1814,21 +1816,21 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec,
Eterm* limit;
#endif
- ASSERT(is_internal_pid(*tracer_pid)
- && internal_pid_index(*tracer_pid) < erts_max_processes);
+ ASSERT(is_internal_pid(*tracer_pid));
tracer = erts_pid2proc(p, ERTS_PROC_LOCK_MAIN,
*tracer_pid, ERTS_PROC_LOCK_STATUS);
if (!tracer)
invalid_tracer = 1;
else {
- invalid_tracer = (tracer->trace_flags & F_TRACER) == 0;
+ invalid_tracer = !(ERTS_TRACE_FLAGS(tracer) & F_TRACER);
erts_smp_proc_unlock(tracer, ERTS_PROC_LOCK_STATUS);
}
if (invalid_tracer) {
#ifdef ERTS_SMP
- ASSERT(is_nil(tracee) || tracer_pid == &p->tracer_proc);
+ ASSERT(is_nil(tracee)
+ || tracer_pid == &ERTS_TRACER_PROC(p));
if (is_not_nil(tracee))
erts_smp_proc_lock(p, ERTS_PROC_LOCKS_ALL_MINOR);
#endif
@@ -1952,7 +1954,7 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec,
* Build the trace tuple and enqueue it.
*/
- mess = TUPLE4(hp, am_trace, p->id/* Local pid */, am_call, mfa_tuple);
+ mess = TUPLE4(hp, am_trace, p->common.id, am_call, mfa_tuple);
hp += 5;
if (pam_result != am_true) {
hp[-5] = make_arityval(5);
@@ -1990,17 +1992,17 @@ trace_proc(Process *c_p, Process *t_p, Eterm what, Eterm data)
ERTS_SMP_LC_ASSERT((erts_proc_lc_my_proc_locks(t_p) != 0)
|| erts_thr_progress_is_blocking());
- if (is_internal_port(t_p->tracer_proc)) {
+ if (is_internal_port(ERTS_TRACER_PROC(t_p))) {
#define LOCAL_HEAP_SIZE (5+5)
DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE);
UseTmpHeapNoproc(LOCAL_HEAP_SIZE);
hp = local_heap;
- mess = TUPLE4(hp, am_trace, t_p->id, what, data);
+ mess = TUPLE4(hp, am_trace, t_p->common.id, what, data);
hp += 5;
erts_smp_mtx_lock(&smq_mtx);
- if (t_p->trace_flags & F_TIMESTAMP) {
+ if (ERTS_TRACE_FLAGS(t_p) & F_TIMESTAMP) {
hp = patch_ts(mess, hp);
}
send_to_port(
@@ -2011,7 +2013,9 @@ trace_proc(Process *c_p, Process *t_p, Eterm what, Eterm data)
/* Fake schedule out and in are never sent when smp enabled */
c_p,
#endif
- mess, &t_p->tracer_proc, &t_p->trace_flags);
+ mess,
+ &ERTS_TRACER_PROC(t_p),
+ &ERTS_TRACE_FLAGS(t_p));
UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
#undef LOCAL_HEAP_SIZE
erts_smp_mtx_unlock(&smq_mtx);
@@ -2022,10 +2026,11 @@ trace_proc(Process *c_p, Process *t_p, Eterm what, Eterm data)
ERTS_TRACER_REF_TYPE tracer_ref;
size_t sz_data;
- ASSERT(is_internal_pid(t_p->tracer_proc)
- && internal_pid_index(t_p->tracer_proc) < erts_max_processes);
+ ASSERT(is_internal_pid(ERTS_TRACER_PROC(t_p)));
- ERTS_GET_TRACER_REF(tracer_ref, t_p->tracer_proc, t_p->trace_flags);
+ ERTS_GET_TRACER_REF(tracer_ref,
+ ERTS_TRACER_PROC(t_p),
+ ERTS_TRACE_FLAGS(t_p));
sz_data = size_object(data);
@@ -2034,16 +2039,16 @@ trace_proc(Process *c_p, Process *t_p, Eterm what, Eterm data)
hp = ERTS_ALLOC_SYSMSG_HEAP(need, &bp, &off_heap, tracer_ref);
tmp = copy_struct(data, sz_data, &hp, off_heap);
- mess = TUPLE4(hp, am_trace, t_p->id/* Local pid */, what, tmp);
+ mess = TUPLE4(hp, am_trace, t_p->common.id, what, tmp);
hp += 5;
erts_smp_mtx_lock(&smq_mtx);
- if (t_p->trace_flags & F_TIMESTAMP) {
+ if (ERTS_TRACE_FLAGS(t_p) & F_TIMESTAMP) {
hp = patch_ts(mess, hp);
}
- ERTS_ENQ_TRACE_MSG(t_p->id, tracer_ref, mess, bp);
+ ERTS_ENQ_TRACE_MSG(t_p->common.id, tracer_ref, mess, bp);
erts_smp_mtx_unlock(&smq_mtx);
}
}
@@ -2064,7 +2069,7 @@ trace_proc_spawn(Process *p, Eterm pid,
Eterm mess;
Eterm* hp;
- if (is_internal_port(p->tracer_proc)) {
+ if (is_internal_port(ERTS_TRACER_PROC(p))) {
#define LOCAL_HEAP_SIZE (4+6+5)
DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE);
UseTmpHeapNoproc(LOCAL_HEAP_SIZE);
@@ -2072,13 +2077,13 @@ trace_proc_spawn(Process *p, Eterm pid,
hp = local_heap;
mfa = TUPLE3(hp, mod, func, args);
hp += 4;
- mess = TUPLE5(hp, am_trace, p->id, am_spawn, pid, mfa);
+ mess = TUPLE5(hp, am_trace, p->common.id, am_spawn, pid, mfa);
hp += 6;
erts_smp_mtx_lock(&smq_mtx);
- if (p->trace_flags & F_TIMESTAMP) {
+ if (ERTS_TRACE_FLAGS(p) & F_TIMESTAMP) {
hp = patch_ts(mess, hp);
}
- send_to_port(p, mess, &p->tracer_proc, &p->trace_flags);
+ send_to_port(p, mess, &ERTS_TRACER_PROC(p), &ERTS_TRACE_FLAGS(p));
UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
#undef LOCAL_HEAP_SIZE
erts_smp_mtx_unlock(&smq_mtx);
@@ -2090,10 +2095,11 @@ trace_proc_spawn(Process *p, Eterm pid,
size_t sz_args, sz_pid;
Uint need;
- ASSERT(is_internal_pid(p->tracer_proc)
- && internal_pid_index(p->tracer_proc) < erts_max_processes);
+ ASSERT(is_internal_pid(ERTS_TRACER_PROC(p)));
- ERTS_GET_TRACER_REF(tracer_ref, p->tracer_proc, p->trace_flags);
+ ERTS_GET_TRACER_REF(tracer_ref,
+ ERTS_TRACER_PROC(p),
+ ERTS_TRACE_FLAGS(p));
sz_args = size_object(args);
sz_pid = size_object(pid);
@@ -2105,16 +2111,16 @@ trace_proc_spawn(Process *p, Eterm pid,
mfa = TUPLE3(hp, mod, func, tmp);
hp += 4;
tmp = copy_struct(pid, sz_pid, &hp, off_heap);
- mess = TUPLE5(hp, am_trace, p->id, am_spawn, tmp, mfa);
+ mess = TUPLE5(hp, am_trace, p->common.id, am_spawn, tmp, mfa);
hp += 6;
erts_smp_mtx_lock(&smq_mtx);
- if (p->trace_flags & F_TIMESTAMP) {
+ if (ERTS_TRACE_FLAGS(p) & F_TIMESTAMP) {
hp = patch_ts(mess, hp);
}
- ERTS_ENQ_TRACE_MSG(p->id, tracer_ref, mess, bp);
+ ERTS_ENQ_TRACE_MSG(p->common.id, tracer_ref, mess, bp);
erts_smp_mtx_unlock(&smq_mtx);
}
}
@@ -2204,7 +2210,7 @@ trace_gc(Process *p, Eterm what)
UseTmpHeap(LOCAL_HEAP_SIZE,p);
- if (is_internal_port(p->tracer_proc)) {
+ if (is_internal_port(ERTS_TRACER_PROC(p))) {
hp = local_heap;
#ifdef DEBUG
size = 0;
@@ -2216,10 +2222,11 @@ trace_gc(Process *p, Eterm what)
size += 5/*4-tuple*/ + TS_SIZE(p);
#endif
} else {
- ASSERT(is_internal_pid(p->tracer_proc)
- && internal_pid_index(p->tracer_proc) < erts_max_processes);
+ ASSERT(is_internal_pid(ERTS_TRACER_PROC(p)));
- ERTS_GET_TRACER_REF(tracer_ref, p->tracer_proc, p->trace_flags);
+ ERTS_GET_TRACER_REF(tracer_ref,
+ ERTS_TRACER_PROC(p),
+ ERTS_TRACE_FLAGS(p));
size = 0;
(void) erts_bld_atom_uint_2tup_list(NULL,
@@ -2243,19 +2250,19 @@ trace_gc(Process *p, Eterm what)
tags,
values);
- msg = TUPLE4(hp, am_trace, p->id/* Local pid */, what, msg);
+ msg = TUPLE4(hp, am_trace, p->common.id, what, msg);
hp += 5;
erts_smp_mtx_lock(&smq_mtx);
- if (p->trace_flags & F_TIMESTAMP) {
+ if (ERTS_TRACE_FLAGS(p) & F_TIMESTAMP) {
hp = patch_ts(msg, hp);
}
ASSERT(hp == limit);
- if (is_internal_port(p->tracer_proc))
- send_to_port(p, msg, &p->tracer_proc, &p->trace_flags);
+ if (is_internal_port(ERTS_TRACER_PROC(p)))
+ send_to_port(p, msg, &ERTS_TRACER_PROC(p), &ERTS_TRACE_FLAGS(p));
else
- ERTS_ENQ_TRACE_MSG(p->id, tracer_ref, msg, bp);
+ ERTS_ENQ_TRACE_MSG(p->common.id, tracer_ref, msg, bp);
erts_smp_mtx_unlock(&smq_mtx);
UnUseTmpHeap(LOCAL_HEAP_SIZE,p);
#undef LOCAL_HEAP_SIZE
@@ -2295,8 +2302,7 @@ monitor_long_gc(Process *p, Uint time) {
#endif
#ifndef ERTS_SMP
- ASSERT(is_internal_pid(system_monitor)
- && internal_pid_index(system_monitor) < erts_max_processes);
+ ASSERT(is_internal_pid(system_monitor));
monitor_p = erts_proc_lookup(system_monitor);
if (!monitor_p || p == monitor_p)
return;
@@ -2321,7 +2327,7 @@ monitor_long_gc(Process *p, Uint time) {
sizeof(values)/sizeof(Uint),
tags,
values);
- msg = TUPLE4(hp, am_monitor, p->id/* Local pid */, am_long_gc, list);
+ msg = TUPLE4(hp, am_monitor, p->common.id, am_long_gc, list);
#ifdef DEBUG
hp += 5 /* 4-tuple */;
@@ -2329,7 +2335,7 @@ monitor_long_gc(Process *p, Uint time) {
#endif
#ifdef ERTS_SMP
- enqueue_sys_msg(SYS_MSG_TYPE_SYSMON, p->id, NIL, msg, bp);
+ enqueue_sys_msg(SYS_MSG_TYPE_SYSMON, p->common.id, NIL, msg, bp);
#else
erts_queue_message(monitor_p, NULL, bp, msg, NIL
#ifdef USE_VM_PROBES
@@ -2370,8 +2376,7 @@ monitor_large_heap(Process *p) {
#ifndef ERTS_SMP
- ASSERT(is_internal_pid(system_monitor)
- && internal_pid_index(system_monitor) < erts_max_processes);
+ ASSERT(is_internal_pid(system_monitor));
monitor_p = erts_proc_lookup(system_monitor);
if (monitor_p || p == monitor_p) {
return;
@@ -2397,7 +2402,7 @@ monitor_large_heap(Process *p) {
sizeof(values)/sizeof(Uint),
tags,
values);
- msg = TUPLE4(hp, am_monitor, p->id/* Local pid */, am_large_heap, list);
+ msg = TUPLE4(hp, am_monitor, p->common.id, am_large_heap, list);
#ifdef DEBUG
hp += 5 /* 4-tuple */;
@@ -2405,7 +2410,7 @@ monitor_large_heap(Process *p) {
#endif
#ifdef ERTS_SMP
- enqueue_sys_msg(SYS_MSG_TYPE_SYSMON, p->id, NIL, msg, bp);
+ enqueue_sys_msg(SYS_MSG_TYPE_SYSMON, p->common.id, NIL, msg, bp);
#else
erts_queue_message(monitor_p, NULL, bp, msg, NIL
#ifdef USE_VM_PROBES
@@ -2425,8 +2430,7 @@ monitor_generic(Process *p, Eterm type, Eterm spec) {
Eterm *hp, msg;
#ifndef ERTS_SMP
- ASSERT(is_internal_pid(system_monitor)
- && internal_pid_index(system_monitor) < erts_max_processes);
+ ASSERT(is_internal_pid(system_monitor));
monitor_p = erts_proc_lookup(system_monitor);
if (!monitor_p || p == monitor_p)
return;
@@ -2434,11 +2438,11 @@ monitor_generic(Process *p, Eterm type, Eterm spec) {
hp = ERTS_ALLOC_SYSMSG_HEAP(5, &bp, &off_heap, monitor_p);
- msg = TUPLE4(hp, am_monitor, p->id/* Local pid */, type, spec);
+ msg = TUPLE4(hp, am_monitor, p->common.id, type, spec);
hp += 5;
#ifdef ERTS_SMP
- enqueue_sys_msg(SYS_MSG_TYPE_SYSMON, p->id, NIL, msg, bp);
+ enqueue_sys_msg(SYS_MSG_TYPE_SYSMON, p->common.id, NIL, msg, bp);
#else
erts_queue_message(monitor_p, NULL, bp, msg, NIL
#ifdef USE_VM_PROBES
@@ -2560,21 +2564,21 @@ trace_port_open(Port *p, Eterm calling_pid, Eterm drv_name) {
Eterm mess;
Eterm* hp;
- if (is_internal_port(p->tracer_proc)) {
+ if (is_internal_port(ERTS_TRACER_PROC(p))) {
#define LOCAL_HEAP_SIZE (5+6)
DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE);
UseTmpHeapNoproc(LOCAL_HEAP_SIZE);
hp = local_heap;
- mess = TUPLE5(hp, am_trace, calling_pid, am_open, p->id, drv_name);
+ mess = TUPLE5(hp, am_trace, calling_pid, am_open, p->common.id, drv_name);
hp += 6;
erts_smp_mtx_lock(&smq_mtx);
- if (p->trace_flags & F_TIMESTAMP) {
+ if (ERTS_TRACE_FLAGS(p) & F_TIMESTAMP) {
hp = patch_ts(mess, hp);
}
/* No fake schedule */
- send_to_port(NULL, mess, &p->tracer_proc, &p->trace_flags);
+ send_to_port(NULL, mess, &ERTS_TRACER_PROC(p), &ERTS_TRACE_FLAGS(p));
UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
#undef LOCAL_HEAP_SIZE
erts_smp_mtx_unlock(&smq_mtx);
@@ -2584,25 +2588,26 @@ trace_port_open(Port *p, Eterm calling_pid, Eterm drv_name) {
size_t sz_data;
ERTS_TRACER_REF_TYPE tracer_ref;
- ASSERT(is_internal_pid(p->tracer_proc)
- && internal_pid_index(p->tracer_proc) < erts_max_processes);
+ ASSERT(is_internal_pid(ERTS_TRACER_PROC(p)));
sz_data = 6 + TS_SIZE(p);
- ERTS_GET_TRACER_REF(tracer_ref, p->tracer_proc, p->trace_flags);
+ ERTS_GET_TRACER_REF(tracer_ref,
+ ERTS_TRACER_PROC(p),
+ ERTS_TRACE_FLAGS(p));
hp = ERTS_ALLOC_SYSMSG_HEAP(sz_data, &bp, &off_heap, tracer_ref);
- mess = TUPLE5(hp, am_trace, calling_pid, am_open, p->id, drv_name);
+ mess = TUPLE5(hp, am_trace, calling_pid, am_open, p->common.id, drv_name);
hp += 6;
erts_smp_mtx_lock(&smq_mtx);
- if (p->trace_flags & F_TIMESTAMP) {
+ if (ERTS_TRACE_FLAGS(p) & F_TIMESTAMP) {
hp = patch_ts(mess, hp);
}
- ERTS_ENQ_TRACE_MSG(p->id, tracer_ref, mess, bp);
+ ERTS_ENQ_TRACE_MSG(p->common.id, tracer_ref, mess, bp);
erts_smp_mtx_unlock(&smq_mtx);
}
@@ -2623,20 +2628,20 @@ trace_port(Port *t_p, Eterm what, Eterm data) {
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(t_p)
|| erts_thr_progress_is_blocking());
- if (is_internal_port(t_p->tracer_proc)) {
+ if (is_internal_port(ERTS_TRACER_PROC(t_p))) {
#define LOCAL_HEAP_SIZE (5+5)
DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE);
UseTmpHeapNoproc(LOCAL_HEAP_SIZE);
hp = local_heap;
- mess = TUPLE4(hp, am_trace, t_p->id, what, data);
+ mess = TUPLE4(hp, am_trace, t_p->common.id, what, data);
hp += 5;
erts_smp_mtx_lock(&smq_mtx);
- if (t_p->trace_flags & F_TIMESTAMP) {
+ if (ERTS_TRACE_FLAGS(t_p) & F_TIMESTAMP) {
hp = patch_ts(mess, hp);
}
/* No fake schedule */
- send_to_port(NULL, mess, &t_p->tracer_proc, &t_p->trace_flags);
+ send_to_port(NULL,mess,&ERTS_TRACER_PROC(t_p),&ERTS_TRACE_FLAGS(t_p));
UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
#undef LOCAL_HEAP_SIZE
erts_smp_mtx_unlock(&smq_mtx);
@@ -2646,25 +2651,26 @@ trace_port(Port *t_p, Eterm what, Eterm data) {
size_t sz_data;
ERTS_TRACER_REF_TYPE tracer_ref;
- ASSERT(is_internal_pid(t_p->tracer_proc)
- && internal_pid_index(t_p->tracer_proc) < erts_max_processes);
+ ASSERT(is_internal_pid(ERTS_TRACER_PROC(t_p)));
sz_data = 5 + TS_SIZE(t_p);
- ERTS_GET_TRACER_REF(tracer_ref, t_p->tracer_proc, t_p->trace_flags);
+ ERTS_GET_TRACER_REF(tracer_ref,
+ ERTS_TRACER_PROC(t_p),
+ ERTS_TRACE_FLAGS(t_p));
hp = ERTS_ALLOC_SYSMSG_HEAP(sz_data, &bp, &off_heap, tracer_ref);
- mess = TUPLE4(hp, am_trace, t_p->id, what, data);
+ mess = TUPLE4(hp, am_trace, t_p->common.id, what, data);
hp += 5;
erts_smp_mtx_lock(&smq_mtx);
- if (t_p->trace_flags & F_TIMESTAMP) {
+ if (ERTS_TRACE_FLAGS(t_p) & F_TIMESTAMP) {
hp = patch_ts(mess, hp);
}
- ERTS_ENQ_TRACE_MSG(t_p->id, tracer_ref, mess, bp);
+ ERTS_ENQ_TRACE_MSG(t_p->common.id, tracer_ref, mess, bp);
erts_smp_mtx_unlock(&smq_mtx);
}
}
@@ -2689,7 +2695,7 @@ trace_sched_ports_where(Port *p, Eterm what, Eterm where) {
int ws = 5;
Eterm sched_id = am_undefined;
- if (is_internal_port(p->tracer_proc)) {
+ if (is_internal_port(ERTS_TRACER_PROC(p))) {
#define LOCAL_HEAP_SIZE (5+6)
DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE);
UseTmpHeapNoproc(LOCAL_HEAP_SIZE);
@@ -2704,21 +2710,21 @@ trace_sched_ports_where(Port *p, Eterm what, Eterm where) {
#else
sched_id = make_small(1);
#endif
- mess = TUPLE5(hp, am_trace, p->id, what, sched_id, where);
+ mess = TUPLE5(hp, am_trace, p->common.id, what, sched_id, where);
ws = 6;
} else {
- mess = TUPLE4(hp, am_trace, p->id, what, where);
+ mess = TUPLE4(hp, am_trace, p->common.id, what, where);
ws = 5;
}
hp += ws;
erts_smp_mtx_lock(&smq_mtx);
- if (p->trace_flags & F_TIMESTAMP) {
+ if (ERTS_TRACE_FLAGS(p) & F_TIMESTAMP) {
hp = patch_ts(mess, hp);
}
/* No fake scheduling */
- send_to_port(NULL, mess, &p->tracer_proc, &p->trace_flags);
+ send_to_port(NULL, mess, &ERTS_TRACER_PROC(p), &ERTS_TRACE_FLAGS(p));
UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
#undef LOCAL_HEAP_SIZE
erts_smp_mtx_unlock(&smq_mtx);
@@ -2727,12 +2733,13 @@ trace_sched_ports_where(Port *p, Eterm what, Eterm where) {
ErlOffHeap *off_heap;
ERTS_TRACER_REF_TYPE tracer_ref;
- ASSERT(is_internal_pid(p->tracer_proc)
- && internal_pid_index(p->tracer_proc) < erts_max_processes);
+ ASSERT(is_internal_pid(ERTS_TRACER_PROC(p)));
if (IS_TRACED_FL(p, F_TRACE_SCHED_NO)) ws = 6; /* Make place for scheduler id */
- ERTS_GET_TRACER_REF(tracer_ref, p->tracer_proc, p->trace_flags);
+ ERTS_GET_TRACER_REF(tracer_ref,
+ ERTS_TRACER_PROC(p),
+ ERTS_TRACE_FLAGS(p));
hp = ERTS_ALLOC_SYSMSG_HEAP(ws+TS_SIZE(p), &bp, &off_heap, tracer_ref);
@@ -2744,19 +2751,19 @@ trace_sched_ports_where(Port *p, Eterm what, Eterm where) {
#else
sched_id = make_small(1);
#endif
- mess = TUPLE5(hp, am_trace, p->id, what, sched_id, where);
+ mess = TUPLE5(hp, am_trace, p->common.id, what, sched_id, where);
} else {
- mess = TUPLE4(hp, am_trace, p->id, what, where);
+ mess = TUPLE4(hp, am_trace, p->common.id, what, where);
}
hp += ws;
erts_smp_mtx_lock(&smq_mtx);
- if (p->trace_flags & F_TIMESTAMP) {
+ if (ERTS_TRACE_FLAGS(p) & F_TIMESTAMP) {
hp = patch_ts(mess, hp);
}
- ERTS_ENQ_TRACE_MSG(p->id, tracer_ref, mess, bp);
+ ERTS_ENQ_TRACE_MSG(p->common.id, tracer_ref, mess, bp);
erts_smp_mtx_unlock(&smq_mtx);
}
}
@@ -2792,14 +2799,14 @@ profile_runnable_port(Port *p, Eterm status) {
GET_NOW(&Ms, &s, &us);
timestamp = TUPLE3(hp, make_small(Ms), make_small(s), make_small(us)); hp += 4;
- msg = TUPLE5(hp, am_profile, p->id, status, count, timestamp); hp += 6;
+ msg = TUPLE5(hp, am_profile, p->common.id, status, count, timestamp); hp += 6;
#ifndef ERTS_SMP
- profile_send(p->id, msg);
+ profile_send(p->common.id, msg);
UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
#undef LOCAL_HEAP_SIZE
#else
- enqueue_sys_msg_unlocked(SYS_MSG_TYPE_SYSPROF, p->id, NIL, msg, bp);
+ enqueue_sys_msg_unlocked(SYS_MSG_TYPE_SYSPROF, p->common.id, NIL, msg, bp);
#endif
erts_smp_mtx_unlock(&smq_mtx);
}
@@ -2846,13 +2853,13 @@ profile_runnable_proc(Process *p, Eterm status){
GET_NOW(&Ms, &s, &us);
timestamp = TUPLE3(hp, make_small(Ms), make_small(s), make_small(us)); hp += 4;
- msg = TUPLE5(hp, am_profile, p->id, status, where, timestamp); hp += 6;
+ msg = TUPLE5(hp, am_profile, p->common.id, status, where, timestamp); hp += 6;
#ifndef ERTS_SMP
- profile_send(p->id, msg);
+ profile_send(p->common.id, msg);
UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
#undef LOCAL_HEAP_SIZE
#else
- enqueue_sys_msg_unlocked(SYS_MSG_TYPE_SYSPROF, p->id, NIL, msg, bp);
+ enqueue_sys_msg_unlocked(SYS_MSG_TYPE_SYSPROF, p->common.id, NIL, msg, bp);
#endif
erts_smp_mtx_unlock(&smq_mtx);
}
@@ -2865,16 +2872,19 @@ profile_runnable_proc(Process *p, Eterm status){
void
erts_check_my_tracer_proc(Process *p)
{
- if (is_internal_pid(p->tracer_proc)) {
- Process *tracer = erts_pid2proc(p, ERTS_PROC_LOCK_MAIN,
- p->tracer_proc, ERTS_PROC_LOCK_STATUS);
- int invalid_tracer = !tracer || !(tracer->trace_flags & F_TRACER);
+ if (is_internal_pid(ERTS_TRACER_PROC(p))) {
+ Process *tracer = erts_pid2proc(p,
+ ERTS_PROC_LOCK_MAIN,
+ ERTS_TRACER_PROC(p),
+ ERTS_PROC_LOCK_STATUS);
+ int invalid_tracer = (!tracer
+ || !(ERTS_TRACE_FLAGS(tracer) & F_TRACER));
if (tracer)
erts_smp_proc_unlock(tracer, ERTS_PROC_LOCK_STATUS);
if (invalid_tracer) {
erts_smp_proc_lock(p, ERTS_PROC_LOCKS_ALL_MINOR);
- p->trace_flags &= ~TRACEE_FLAGS;
- p->tracer_proc = NIL;
+ ERTS_TRACE_FLAGS(p) &= ~TRACEE_FLAGS;
+ ERTS_TRACER_PROC(p) = NIL;
erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL_MINOR);
}
}
@@ -3218,7 +3228,7 @@ sys_msg_dispatcher_func(void *unused)
proc = erts_pid2proc(NULL, 0, receiver, proc_locks);
if (!proc
|| (smqp->type == SYS_MSG_TYPE_TRACE
- && !(proc->trace_flags & F_TRACER))) {
+ && !(ERTS_TRACE_FLAGS(proc) & F_TRACER))) {
/* Bad tracer */
#ifdef DEBUG_PRINTOUTS
if (smqp->type == SYS_MSG_TYPE_TRACE && proc)
@@ -3245,16 +3255,14 @@ sys_msg_dispatcher_func(void *unused)
proc = erts_whereis_process(NULL,0,receiver,proc_locks,0);
if (!proc)
goto failure;
- else if (smqp->from == proc->id)
+ else if (smqp->from == proc->common.id)
goto drop_sys_msg;
else
goto queue_proc_msg;
}
else if (is_internal_port(receiver)) {
- port = erts_id2port_sflgs(receiver,
- NULL,
- 0,
- ERTS_PORT_SFLGS_INVALID_TRACER_LOOKUP);
+ port = erts_thr_id2port_sflgs(receiver,
+ ERTS_PORT_SFLGS_INVALID_TRACER_LOOKUP);
if (!port)
goto failure;
else {
@@ -3268,7 +3276,7 @@ sys_msg_dispatcher_func(void *unused)
#ifdef DEBUG_PRINTOUTS
erts_fprintf(stderr, "delivered\n");
#endif
- erts_port_release(port);
+ erts_thr_port_release(port);
if (smqp->bp)
free_message_buffer(smqp->bp);
}
diff --git a/erts/emulator/beam/erl_trace.h b/erts/emulator/beam/erl_trace.h
new file mode 100644
index 0000000000..50fb27aab0
--- /dev/null
+++ b/erts/emulator/beam/erl_trace.h
@@ -0,0 +1,141 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2012. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+
+#ifndef ERL_TRACE_H__
+#define ERL_TRACE_H__
+
+struct binary;
+
+/* erl_bif_trace.c */
+Eterm erl_seq_trace_info(Process *p, Eterm arg1);
+void erts_system_monitor_clear(Process *c_p);
+void erts_system_profile_clear(Process *c_p);
+
+/* erl_trace.c */
+void erts_init_trace(void);
+void erts_trace_check_exiting(Eterm exiting);
+Eterm erts_set_system_seq_tracer(Process *c_p,
+ ErtsProcLocks c_p_locks,
+ Eterm new);
+Eterm erts_get_system_seq_tracer(void);
+void erts_change_default_tracing(int setflags, Uint *flagsp, Eterm *tracerp);
+void erts_get_default_tracing(Uint *flagsp, Eterm *tracerp);
+void erts_set_system_monitor(Eterm monitor);
+Eterm erts_get_system_monitor(void);
+
+#ifdef ERTS_SMP
+void erts_check_my_tracer_proc(Process *);
+void erts_block_sys_msg_dispatcher(void);
+void erts_release_sys_msg_dispatcher(void);
+void erts_foreach_sys_msg_in_q(void (*func)(Eterm,
+ Eterm,
+ Eterm,
+ ErlHeapFragment *));
+void erts_queue_error_logger_message(Eterm, Eterm, ErlHeapFragment *);
+#endif
+
+void erts_send_sys_msg_proc(Eterm, Eterm, Eterm, ErlHeapFragment *);
+void trace_send(Process*, Eterm, Eterm);
+void trace_receive(Process*, Eterm);
+Uint32 erts_call_trace(Process *p, BeamInstr mfa[], struct binary *match_spec, Eterm* args,
+ int local, Eterm *tracer_pid);
+void erts_trace_return(Process* p, BeamInstr* fi, Eterm retval, Eterm *tracer_pid);
+void erts_trace_exception(Process* p, BeamInstr mfa[], Eterm class, Eterm value,
+ Eterm *tracer);
+void erts_trace_return_to(Process *p, BeamInstr *pc);
+void trace_sched(Process*, Eterm);
+void trace_proc(Process*, Process*, Eterm, Eterm);
+void trace_proc_spawn(Process*, Eterm pid, Eterm mod, Eterm func, Eterm args);
+void save_calls(Process *p, Export *);
+void trace_gc(Process *p, Eterm what);
+/* port tracing */
+void trace_virtual_sched(Process*, Eterm);
+void trace_sched_ports(Port *pp, Eterm);
+void trace_sched_ports_where(Port *pp, Eterm, Eterm);
+void trace_port(Port *, Eterm what, Eterm data);
+void trace_port_open(Port *, Eterm calling_pid, Eterm drv_name);
+
+/* system_profile */
+void erts_set_system_profile(Eterm profile);
+Eterm erts_get_system_profile(void);
+void profile_scheduler(Eterm scheduler_id, Eterm);
+void profile_scheduler_q(Eterm scheduler_id, Eterm state, Eterm no_schedulers, Uint Ms, Uint s, Uint us);
+void profile_runnable_proc(Process* p, Eterm status);
+void profile_runnable_port(Port* p, Eterm status);
+void erts_system_profile_setup_active_schedulers(void);
+
+/* system_monitor */
+void monitor_long_gc(Process *p, Uint time);
+void monitor_large_heap(Process *p);
+void monitor_generic(Process *p, Eterm type, Eterm spec);
+Uint erts_trace_flag2bit(Eterm flag);
+int erts_trace_flags(Eterm List,
+ Uint *pMask, Eterm *pTracer, int *pCpuTimestamp);
+Eterm erts_bif_trace(int bif_index, Process* p, Eterm* args, BeamInstr *I);
+
+#ifdef ERTS_SMP
+void erts_send_pending_trace_msgs(ErtsSchedulerData *esdp);
+#define ERTS_SMP_CHK_PEND_TRACE_MSGS(ESDP) \
+do { \
+ if ((ESDP)->pending_trace_msgs) \
+ erts_send_pending_trace_msgs((ESDP)); \
+} while (0)
+#else
+#define ERTS_SMP_CHK_PEND_TRACE_MSGS(ESDP)
+#endif
+
+#define seq_trace_output(token, msg, type, receiver, process) \
+seq_trace_output_generic((token), (msg), (type), (receiver), (process), NIL)
+#define seq_trace_output_exit(token, msg, type, receiver, exitfrom) \
+seq_trace_output_generic((token), (msg), (type), (receiver), NULL, (exitfrom))
+void seq_trace_output_generic(Eterm token, Eterm msg, Uint type,
+ Eterm receiver, Process *process, Eterm exitfrom);
+
+int seq_trace_update_send(Process *process);
+
+Eterm erts_seq_trace(Process *process,
+ Eterm atom_type, Eterm atom_true_or_false,
+ int build_result);
+
+struct trace_pattern_flags {
+ unsigned int breakpoint : 1; /* Set if any other is set */
+ unsigned int local : 1; /* Local call trace breakpoint */
+ unsigned int meta : 1; /* Metadata trace breakpoint */
+ unsigned int call_count : 1; /* Fast call count breakpoint */
+ unsigned int call_time : 1; /* Fast call time breakpoint */
+};
+extern const struct trace_pattern_flags erts_trace_pattern_flags_off;
+extern int erts_call_time_breakpoint_tracing;
+int erts_set_trace_pattern(Process*p, Eterm* mfa, int specified,
+ struct binary* match_prog_set,
+ struct binary *meta_match_prog_set,
+ int on, struct trace_pattern_flags,
+ Eterm meta_tracer_pid, int is_blocking);
+void
+erts_get_default_trace_pattern(int *trace_pattern_is_on,
+ struct binary **match_spec,
+ struct binary **meta_match_spec,
+ struct trace_pattern_flags *trace_pattern_flags,
+ Eterm *meta_tracer_pid);
+int erts_is_default_trace_enabled(void);
+void erts_bif_trace_init(void);
+int erts_finish_breakpointing(void);
+
+#endif /* ERL_TRACE_H__ */
diff --git a/erts/emulator/beam/erl_utils.h b/erts/emulator/beam/erl_utils.h
new file mode 100644
index 0000000000..a2064bd8a3
--- /dev/null
+++ b/erts/emulator/beam/erl_utils.h
@@ -0,0 +1,215 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2012. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef ERL_UTILS_H__
+#define ERL_UTILS_H__
+
+#include "sys.h"
+#include "erl_smp.h"
+#include "erl_printf.h"
+
+typedef struct {
+#ifdef DEBUG
+ int smp_api;
+#endif
+ union {
+ Uint64 not_atomic;
+#ifdef ARCH_64
+ erts_atomic_t atomic;
+#else
+ erts_dw_atomic_t atomic;
+#endif
+ } counter;
+} erts_interval_t;
+
+void erts_interval_init(erts_interval_t *);
+void erts_smp_interval_init(erts_interval_t *);
+Uint64 erts_step_interval_nob(erts_interval_t *);
+Uint64 erts_step_interval_relb(erts_interval_t *);
+Uint64 erts_smp_step_interval_nob(erts_interval_t *);
+Uint64 erts_smp_step_interval_relb(erts_interval_t *);
+Uint64 erts_ensure_later_interval_nob(erts_interval_t *, Uint64);
+Uint64 erts_ensure_later_interval_acqb(erts_interval_t *, Uint64);
+Uint64 erts_smp_ensure_later_interval_nob(erts_interval_t *, Uint64);
+Uint64 erts_smp_ensure_later_interval_acqb(erts_interval_t *, Uint64);
+#ifdef ARCH_32
+ERTS_GLB_INLINE Uint64 erts_interval_dw_aint_to_val__(erts_dw_aint_t *);
+#endif
+ERTS_GLB_INLINE Uint64 erts_current_interval_nob__(erts_interval_t *);
+ERTS_GLB_INLINE Uint64 erts_current_interval_acqb__(erts_interval_t *);
+ERTS_GLB_INLINE Uint64 erts_current_interval_nob(erts_interval_t *);
+ERTS_GLB_INLINE Uint64 erts_current_interval_acqb(erts_interval_t *);
+ERTS_GLB_INLINE Uint64 erts_smp_current_interval_nob(erts_interval_t *);
+ERTS_GLB_INLINE Uint64 erts_smp_current_interval_acqb(erts_interval_t *);
+
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+
+#ifdef ARCH_32
+
+ERTS_GLB_INLINE Uint64
+erts_interval_dw_aint_to_val__(erts_dw_aint_t *dw)
+{
+#ifdef ETHR_SU_DW_NAINT_T__
+ return (Uint64) dw->dw_sint;
+#else
+ Uint64 res;
+ res = (Uint64) ((Uint32) dw->sint[ERTS_DW_AINT_HIGH_WORD]);
+ res <<= 32;
+ res |= (Uint64) ((Uint32) dw->sint[ERTS_DW_AINT_LOW_WORD]);
+ return res;
+#endif
+}
+
+#endif
+
+ERTS_GLB_INLINE Uint64
+erts_current_interval_nob__(erts_interval_t *icp)
+{
+#ifdef ARCH_64
+ return (Uint64) erts_atomic_read_nob(&icp->counter.atomic);
+#else
+ erts_dw_aint_t dw;
+ erts_dw_atomic_read_nob(&icp->counter.atomic, &dw);
+ return erts_interval_dw_aint_to_val__(&dw);
+#endif
+}
+
+ERTS_GLB_INLINE Uint64
+erts_current_interval_acqb__(erts_interval_t *icp)
+{
+#ifdef ARCH_64
+ return (Uint64) erts_atomic_read_acqb(&icp->counter.atomic);
+#else
+ erts_dw_aint_t dw;
+ erts_dw_atomic_read_acqb(&icp->counter.atomic, &dw);
+ return erts_interval_dw_aint_to_val__(&dw);
+#endif
+}
+
+ERTS_GLB_INLINE Uint64
+erts_current_interval_nob(erts_interval_t *icp)
+{
+ ASSERT(!icp->smp_api);
+ return erts_current_interval_nob__(icp);
+}
+
+ERTS_GLB_INLINE Uint64
+erts_current_interval_acqb(erts_interval_t *icp)
+{
+ ASSERT(!icp->smp_api);
+ return erts_current_interval_acqb__(icp);
+}
+
+ERTS_GLB_INLINE Uint64
+erts_smp_current_interval_nob(erts_interval_t *icp)
+{
+ ASSERT(icp->smp_api);
+#ifdef ERTS_SMP
+ return erts_current_interval_nob__(icp);
+#else
+ return icp->counter.not_atomic;
+#endif
+}
+
+ERTS_GLB_INLINE Uint64
+erts_smp_current_interval_acqb(erts_interval_t *icp)
+{
+ ASSERT(icp->smp_api);
+#ifdef ERTS_SMP
+ return erts_current_interval_acqb__(icp);
+#else
+ return icp->counter.not_atomic;
+#endif
+}
+
+#endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */
+
+/*
+ * To be used to silence unused result warnings, but do not abuse it.
+ */
+void erts_silence_warn_unused_result(long unused);
+
+
+int erts_fit_in_bits_int64(Sint64);
+int erts_fit_in_bits_int32(Sint32);
+int list_length(Eterm);
+int erts_is_builtin(Eterm, Eterm, int);
+Uint32 make_broken_hash(Eterm);
+Uint32 block_hash(byte *, unsigned, Uint32);
+Uint32 make_hash2(Eterm);
+Uint32 make_hash(Eterm);
+
+
+Eterm erts_bld_atom(Uint **hpp, Uint *szp, char *str);
+Eterm erts_bld_uint(Uint **hpp, Uint *szp, Uint ui);
+Eterm erts_bld_uword(Uint **hpp, Uint *szp, UWord uw);
+Eterm erts_bld_uint64(Uint **hpp, Uint *szp, Uint64 ui64);
+Eterm erts_bld_sint64(Uint **hpp, Uint *szp, Sint64 si64);
+Eterm erts_bld_cons(Uint **hpp, Uint *szp, Eterm car, Eterm cdr);
+Eterm erts_bld_tuple(Uint **hpp, Uint *szp, Uint arity, ...);
+Eterm erts_bld_tuplev(Uint **hpp, Uint *szp, Uint arity, Eterm terms[]);
+Eterm erts_bld_string_n(Uint **hpp, Uint *szp, const char *str, Sint len);
+#define erts_bld_string(hpp,szp,str) erts_bld_string_n(hpp,szp,str,strlen(str))
+Eterm erts_bld_list(Uint **hpp, Uint *szp, Sint length, Eterm terms[]);
+Eterm erts_bld_2tup_list(Uint **hpp, Uint *szp,
+ Sint length, Eterm terms1[], Uint terms2[]);
+Eterm
+erts_bld_atom_uint_2tup_list(Uint **hpp, Uint *szp,
+ Sint length, Eterm atoms[], Uint uints[]);
+Eterm
+erts_bld_atom_2uint_3tup_list(Uint **hpp, Uint *szp, Sint length,
+ Eterm atoms[], Uint uints1[], Uint uints2[]);
+
+void erts_init_utils(void);
+void erts_init_utils_mem(void);
+
+erts_dsprintf_buf_t *erts_create_tmp_dsbuf(Uint);
+void erts_destroy_tmp_dsbuf(erts_dsprintf_buf_t *);
+
+#if HALFWORD_HEAP
+int eq_rel(Eterm a, Eterm* a_base, Eterm b, Eterm* b_base);
+# define eq(A,B) eq_rel(A,NULL,B,NULL)
+#else
+int eq(Eterm, Eterm);
+# define eq_rel(A,A_BASE,B,B_BASE) eq(A,B)
+#endif
+
+#define EQ(x,y) (((x) == (y)) || (is_not_both_immed((x),(y)) && eq((x),(y))))
+
+#if HALFWORD_HEAP
+Sint cmp_rel(Eterm, Eterm*, Eterm, Eterm*);
+#define CMP(A,B) cmp_rel(A,NULL,B,NULL)
+#else
+Sint cmp(Eterm, Eterm);
+#define cmp_rel(A,A_BASE,B,B_BASE) cmp(A,B)
+#define CMP(A,B) cmp(A,B)
+#endif
+#define cmp_lt(a,b) (CMP((a),(b)) < 0)
+#define cmp_le(a,b) (CMP((a),(b)) <= 0)
+#define cmp_eq(a,b) (CMP((a),(b)) == 0)
+#define cmp_ne(a,b) (CMP((a),(b)) != 0)
+#define cmp_ge(a,b) (CMP((a),(b)) >= 0)
+#define cmp_gt(a,b) (CMP((a),(b)) > 0)
+
+#define CMP_LT(a,b) ((a) != (b) && cmp_lt((a),(b)))
+#define CMP_GE(a,b) ((a) == (b) || cmp_ge((a),(b)))
+#define CMP_EQ(a,b) ((a) == (b) || cmp_eq((a),(b)))
+#define CMP_NE(a,b) ((a) != (b) && cmp_ne((a),(b)))
+
+#endif
diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h
index 1503d793ab..298241618f 100755
--- a/erts/emulator/beam/global.h
+++ b/erts/emulator/beam/global.h
@@ -39,38 +39,8 @@
#include "erl_sys_driver.h"
#include "erl_debug.h"
#include "error.h"
-
-typedef struct port Port;
-#include "erl_port_task.h"
-
-typedef struct erts_driver_t_ erts_driver_t;
-
-#define SMALL_IO_QUEUE 5 /* Number of fixed elements */
-
-typedef struct {
- ErlDrvSizeT size; /* total size in bytes */
-
- SysIOVec* v_start;
- SysIOVec* v_end;
- SysIOVec* v_head;
- SysIOVec* v_tail;
- SysIOVec v_small[SMALL_IO_QUEUE];
-
- ErlDrvBinary** b_start;
- ErlDrvBinary** b_end;
- ErlDrvBinary** b_head;
- ErlDrvBinary** b_tail;
- ErlDrvBinary* b_small[SMALL_IO_QUEUE];
-} ErlIOQueue;
-
-typedef struct line_buf { /* Buffer used in line oriented I/O */
- ErlDrvSizeT bufsiz; /* Size of character buffer */
- ErlDrvSizeT ovlen; /* Length of overflow data */
- ErlDrvSizeT ovsiz; /* Actual size of overflow buffer */
- char data[1]; /* Starting point of buffer data,
- data[0] is a flag indicating an unprocess CR,
- The rest is the overflow buffer. */
-} LineBuf;
+#include "erl_utils.h"
+#include "erl_port.h"
struct enif_environment_t /* ErlNifEnv */
{
@@ -90,162 +60,6 @@ extern void erts_print_nif_taints(int to, void* to_arg);
void erts_unload_nif(struct erl_module_nif* nif);
extern void erl_nif_init(void);
-/*
- * Port Specific Data.
- *
- * Only use PrtSD for very rarely used data.
- */
-
-#define ERTS_PRTSD_SCHED_ID 0
-
-#define ERTS_PRTSD_SIZE 1
-
-typedef struct {
- void *data[ERTS_PRTSD_SIZE];
-} ErtsPrtSD;
-
-#ifdef ERTS_SMP
-typedef struct ErtsXPortsList_ ErtsXPortsList;
-#endif
-
-/*
- * Port locking:
- *
- * Locking is done either driver specific or port specific. When
- * driver specific locking is used, all instances of the driver,
- * i.e. ports running the driver, share the same lock. When port
- * specific locking is used each instance have its own lock.
- *
- * Most fields in the Port structure are protected by the lock
- * referred to by the lock field. I'v called it the port lock.
- * This lock is shared between all ports running the same driver
- * when driver specific locking is used.
- *
- * The 'sched' field is protected by the port tasks lock
- * (see erl_port_tasks.c)
- *
- * The 'status' field is protected by a combination of the port lock,
- * the port tasks lock, and the state_lck. It may be read if
- * the state_lck, or the port lock is held. It may only be
- * modified if both the port lock and the state_lck is held
- * (with one exception; see below). When changeing status from alive
- * to dead or vice versa, also the port task lock has to be held.
- * This in order to guarantee that tasks are scheduled only for
- * ports that are alive.
- *
- * The status field may be modified with only the state_lck
- * held when status is changed from dead to alive. This since no
- * threads can have any references to the port other than via the
- * port table.
- *
- * /rickard
- */
-
-struct port {
- ErtsPortTaskSched sched;
- ErtsPortTaskHandle timeout_task;
- erts_smp_atomic_t refc;
-#ifdef ERTS_SMP
- erts_smp_mtx_t *lock;
- ErtsXPortsList *xports;
- erts_smp_atomic_t run_queue;
- erts_smp_spinlock_t state_lck; /* protects: id, status, snapshot */
-#endif
- Eterm id; /* The Port id of this port */
- Eterm connected; /* A connected process */
- Eterm caller; /* Current caller. */
- Eterm data; /* Data associated with port. */
- ErlHeapFragment* bp; /* Heap fragment holding data (NULL if imm data). */
- ErtsLink *nlinks;
- ErtsMonitor *monitors; /* Only MON_ORIGIN monitors of pid's */
- Uint bytes_in; /* Number of bytes read */
- Uint bytes_out; /* Number of bytes written */
-#ifdef ERTS_SMP
- ErtsSmpPTimer *ptimer;
-#else
- ErlTimer tm; /* Timer entry */
-#endif
-
- Eterm tracer_proc; /* If the port is traced, this is the tracer */
- Uint trace_flags; /* Trace flags */
-
- ErlIOQueue ioq; /* driver accessible i/o queue */
- DistEntry *dist_entry; /* Dist entry used in DISTRIBUTION */
- char *name; /* String used in the open */
- erts_driver_t* drv_ptr;
- UWord drv_data;
- SWord os_pid; /* Child process ID */
- ErtsProcList *suspended; /* List of suspended processes. */
- LineBuf *linebuf; /* Buffer to hold data not ready for
- process to get (line oriented I/O)*/
- Uint32 status; /* Status and type flags */
- int control_flags; /* Flags for port_control() */
- erts_aint32_t snapshot; /* Next snapshot that port should be part of */
- struct reg_proc *reg;
- ErlDrvPDL port_data_lock;
-
- ErtsPrtSD *psd; /* Port specific data */
-};
-
-
-ERTS_GLB_INLINE ErtsRunQueue *erts_port_runq(Port *prt);
-
-#if ERTS_GLB_INLINE_INCL_FUNC_DEF
-
-ERTS_GLB_INLINE ErtsRunQueue *
-erts_port_runq(Port *prt)
-{
-#ifdef ERTS_SMP
- ErtsRunQueue *rq1, *rq2;
- rq1 = (ErtsRunQueue *) erts_smp_atomic_read_nob(&prt->run_queue);
- if (!rq1)
- return NULL;
- while (1) {
- erts_smp_runq_lock(rq1);
- rq2 = (ErtsRunQueue *) erts_smp_atomic_read_nob(&prt->run_queue);
- if (rq1 == rq2)
- return rq1;
- erts_smp_runq_unlock(rq1);
- rq1 = rq2;
- if (!rq1)
- return NULL;
- }
-#else
- return ERTS_RUNQ_IX(0);
-#endif
-}
-
-#endif
-
-
-ERTS_GLB_INLINE void *erts_prtsd_get(Port *p, int ix);
-ERTS_GLB_INLINE void *erts_prtsd_set(Port *p, int ix, void *new);
-
-#if ERTS_GLB_INLINE_INCL_FUNC_DEF
-
-ERTS_GLB_INLINE void *
-erts_prtsd_get(Port *prt, int ix)
-{
- return prt->psd ? prt->psd->data[ix] : NULL;
-}
-
-ERTS_GLB_INLINE void *
-erts_prtsd_set(Port *prt, int ix, void *data)
-{
- if (prt->psd) {
- void *old = prt->psd->data[ix];
- prt->psd->data[ix] = data;
- return old;
- }
- else {
- prt->psd = erts_alloc(ERTS_ALC_T_PRTSD, sizeof(ErtsPrtSD));
- prt->psd->data[ix] = data;
- return NULL;
- }
-}
-
-#endif
-
/* Driver handle (wrapper for old plain handle) */
#define ERL_DE_OK 0
#define ERL_DE_UNLOAD 1
@@ -297,7 +111,7 @@ typedef struct {
or that wait for it to change state */
erts_refc_t refc; /* Number of ports/processes having
references to the driver */
- Uint port_count; /* Number of ports using the driver */
+ erts_smp_atomic32_t port_count; /* Number of ports using the driver */
Uint flags; /* ERL_DE_FL_KILL_PORTS */
int status; /* ERL_DE_xxx */
char *full_path; /* Full path of the driver */
@@ -349,7 +163,7 @@ struct erts_driver_t_ {
};
extern erts_driver_t *driver_list;
-extern erts_smp_mtx_t erts_driver_list_lock;
+extern erts_smp_rwmtx_t erts_driver_list_lock;
extern void erts_ddll_init(void);
extern void erts_ddll_lock_driver(DE_Handle *dh, char *name);
@@ -529,40 +343,9 @@ union erl_off_heap_ptr {
void* voidp;
};
-/* arrays that get malloced at startup */
-extern Port* erts_port;
-
-extern Uint erts_max_ports;
-extern Uint erts_port_tab_index_mask;
-extern erts_smp_atomic32_t erts_ports_snapshot;
-extern erts_smp_atomic_t erts_dead_ports_ptr;
-
-ERTS_GLB_INLINE void erts_may_save_closed_port(Port *prt);
-
-#if ERTS_GLB_INLINE_INCL_FUNC_DEF
-
-ERTS_GLB_INLINE void erts_may_save_closed_port(Port *prt)
-{
- ERTS_SMP_LC_ASSERT(erts_smp_lc_spinlock_is_locked(&prt->state_lck));
- if (prt->snapshot != erts_smp_atomic32_read_acqb(&erts_ports_snapshot)) {
- /* Dead ports are added from the end of the snapshot buffer */
- Eterm* tombstone;
- tombstone = (Eterm*) erts_smp_atomic_add_read_nob(&erts_dead_ports_ptr,
- -(erts_aint_t)sizeof(Eterm));
- ASSERT(tombstone+1 != NULL);
- ASSERT(prt->snapshot == erts_smp_atomic32_read_nob(&erts_ports_snapshot) - 1);
- *tombstone = prt->id;
- }
- /*else no ongoing snapshot or port was already included or created after snapshot */
-}
-
-#endif
-
/* controls warning mapping in error_logger */
extern Eterm node_cookie;
-extern erts_smp_atomic_t erts_bytes_out; /* no bytes written out */
-extern erts_smp_atomic_t erts_bytes_in; /* no bytes sent into the system */
extern Uint display_items; /* no of items to display in traces etc */
extern int erts_backtrace_depth;
@@ -700,54 +483,6 @@ do { \
#define WSTACK_ISEMPTY(s) (WSTK_CONCAT(s,_sp) == WSTK_CONCAT(s,_start))
#define WSTACK_POP(s) (*(--WSTK_CONCAT(s,_sp)))
-
-/* port status flags */
-
-#define ERTS_PORT_SFLG_CONNECTED ((Uint32) (1 << 0))
-/* Port have begun exiting */
-#define ERTS_PORT_SFLG_EXITING ((Uint32) (1 << 1))
-/* Distribution port */
-#define ERTS_PORT_SFLG_DISTRIBUTION ((Uint32) (1 << 2))
-#define ERTS_PORT_SFLG_BINARY_IO ((Uint32) (1 << 3))
-#define ERTS_PORT_SFLG_SOFT_EOF ((Uint32) (1 << 4))
-/* Flow control */
-#define ERTS_PORT_SFLG_PORT_BUSY ((Uint32) (1 << 5))
-/* Port is closing (no i/o accepted) */
-#define ERTS_PORT_SFLG_CLOSING ((Uint32) (1 << 6))
-/* Send a closed message when terminating */
-#define ERTS_PORT_SFLG_SEND_CLOSED ((Uint32) (1 << 7))
-/* Line orinted io on port */
-#define ERTS_PORT_SFLG_LINEBUF_IO ((Uint32) (1 << 8))
-/* Immortal port (only certain system ports) */
-#define ERTS_PORT_SFLG_IMMORTAL ((Uint32) (1 << 9))
-#define ERTS_PORT_SFLG_FREE ((Uint32) (1 << 10))
-#define ERTS_PORT_SFLG_FREE_SCHEDULED ((Uint32) (1 << 11))
-#define ERTS_PORT_SFLG_INITIALIZING ((Uint32) (1 << 12))
-/* Port uses port specific locking (opposed to driver specific locking) */
-#define ERTS_PORT_SFLG_PORT_SPECIFIC_LOCK ((Uint32) (1 << 13))
-#define ERTS_PORT_SFLG_INVALID ((Uint32) (1 << 14))
-/* Last port to terminate halts the emulator */
-#define ERTS_PORT_SFLG_HALT ((Uint32) (1 << 15))
-#ifdef DEBUG
-/* Only debug: make sure all flags aren't cleared unintentionally */
-#define ERTS_PORT_SFLG_PORT_DEBUG ((Uint32) (1 << 31))
-#endif
-
-/* Combinations of port status flags */
-#define ERTS_PORT_SFLGS_DEAD \
- (ERTS_PORT_SFLG_FREE \
- | ERTS_PORT_SFLG_FREE_SCHEDULED \
- | ERTS_PORT_SFLG_INITIALIZING)
-#define ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP \
- (ERTS_PORT_SFLGS_DEAD | ERTS_PORT_SFLG_INVALID)
-#define ERTS_PORT_SFLGS_INVALID_LOOKUP \
- (ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP \
- | ERTS_PORT_SFLG_CLOSING)
-#define ERTS_PORT_SFLGS_INVALID_TRACER_LOOKUP \
- (ERTS_PORT_SFLGS_INVALID_LOOKUP \
- | ERTS_PORT_SFLG_PORT_BUSY \
- | ERTS_PORT_SFLG_DISTRIBUTION)
-
/* binary.c */
void erts_emasculate_writable_binary(ProcBin* pb);
@@ -758,11 +493,35 @@ Eterm erts_realloc_binary(Eterm bin, size_t size);
/* erl_bif_info.c */
+Eterm
+erts_bld_port_info(Eterm **hpp,
+ ErlOffHeap *ohp,
+ Uint *szp,
+ Port *prt,
+ Eterm item);
+
void erts_bif_info_init(void);
/* bif.c */
Eterm erts_make_ref(Process *);
Eterm erts_make_ref_in_buffer(Eterm buffer[REF_THING_SIZE]);
+void erts_make_ref_in_array(Uint32 ref[ERTS_MAX_REF_NUMBERS]);
+
+ERTS_GLB_INLINE Eterm
+erts_proc_store_ref(Process *c_p, Uint32 ref[ERTS_MAX_REF_NUMBERS]);
+
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+
+ERTS_GLB_INLINE Eterm
+erts_proc_store_ref(Process *c_p, Uint32 ref[ERTS_MAX_REF_NUMBERS])
+{
+ Eterm *hp = HAlloc(c_p, REF_THING_SIZE);
+ write_ref_thing(hp, ref[0], ref[1], ref[2]);
+ return make_internal_ref(hp);
+}
+
+#endif
+
void erts_queue_monitor_message(Process *,
ErtsProcLocks*,
Eterm,
@@ -778,13 +537,6 @@ Eterm erl_send(Process *p, Eterm to, Eterm msg);
Eterm erl_is_function(Process* p, Eterm arg1, Eterm arg2);
-/* erl_bif_port.c */
-
-/* erl_bif_trace.c */
-Eterm erl_seq_trace_info(Process *p, Eterm arg1);
-void erts_system_monitor_clear(Process *c_p);
-void erts_system_profile_clear(Process *c_p);
-
/* beam_load.c */
typedef struct {
BeamInstr* current; /* Pointer to: Mod, Name, Arity */
@@ -960,11 +712,6 @@ void erts_free_heap_frags(Process* p);
/* io.c */
-struct erl_drv_port_data_lock {
- erts_mtx_t mtx;
- erts_atomic_t refc;
-};
-
typedef struct {
char *name;
char *driver_name;
@@ -973,474 +720,33 @@ typedef struct {
#define ERTS_SPAWN_DRIVER 1
#define ERTS_SPAWN_EXECUTABLE 2
#define ERTS_SPAWN_ANY (ERTS_SPAWN_DRIVER | ERTS_SPAWN_EXECUTABLE)
-
int erts_add_driver_entry(ErlDrvEntry *drv, DE_Handle *handle, int driver_list_locked);
void erts_destroy_driver(erts_driver_t *drv);
-void erts_wake_process_later(Port*, Process*);
-int erts_open_driver(erts_driver_t*, Eterm, char*, SysDriverOpts*, int *);
-int erts_is_port_ioq_empty(Port *);
-void erts_terminate_port(Port *);
-void close_port(Eterm);
-void init_io(void);
-void cleanup_io(void);
-void erts_do_exit_port(Port *, Eterm, Eterm);
-void erts_port_command(Process *, Eterm, Port *, Eterm);
-Eterm erts_port_control(Process*, Port*, Uint, Eterm);
-int erts_write_to_port(Eterm caller_id, Port *p, Eterm list);
-void print_port_info(int, void *, int);
+int erts_save_suspend_process_on_port(Port*, Process*);
+Port *erts_open_driver(erts_driver_t*, Eterm, char*, SysDriverOpts*, int *, int *);
+void erts_init_io(int, int);
void erts_raw_port_command(Port*, byte*, Uint);
-void driver_report_exit(int, int);
+void driver_report_exit(ErlDrvPort, int);
LineBuf* allocate_linebuf(int);
int async_ready(Port *, void*);
-Sint erts_test_next_port(int, Uint);
ErtsPortNames *erts_get_port_names(Eterm);
void erts_free_port_names(ErtsPortNames *);
Uint erts_port_ioq_size(Port *pp);
void erts_stale_drv_select(Eterm, ErlDrvEvent, int, int);
-void erts_port_cleanup(Port *);
-void erts_fire_port_monitor(Port *prt, Eterm ref);
-#ifdef ERTS_SMP
-void erts_smp_xports_unlock(Port *);
-#endif
+
+Port *erts_get_heart_port(void);
#if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_COUNT)
void erts_lcnt_enable_io_lock_count(int enable);
#endif
-#if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK)
-int erts_lc_is_port_locked(Port *);
-#endif
-
-ERTS_GLB_INLINE void erts_smp_port_state_lock(Port*);
-ERTS_GLB_INLINE void erts_smp_port_state_unlock(Port*);
-
-ERTS_GLB_INLINE int erts_smp_port_trylock(Port *prt);
-ERTS_GLB_INLINE void erts_smp_port_lock(Port *prt);
-ERTS_GLB_INLINE void erts_smp_port_unlock(Port *prt);
-
-#if ERTS_GLB_INLINE_INCL_FUNC_DEF
-
-ERTS_GLB_INLINE void
-erts_smp_port_state_lock(Port* prt)
-{
-#ifdef ERTS_SMP
- erts_smp_spin_lock(&prt->state_lck);
-#endif
-}
-
-ERTS_GLB_INLINE void
-erts_smp_port_state_unlock(Port *prt)
-{
-#ifdef ERTS_SMP
- erts_smp_spin_unlock(&prt->state_lck);
-#endif
-}
-
-
-ERTS_GLB_INLINE int
-erts_smp_port_trylock(Port *prt)
-{
- int res;
-
- ASSERT(erts_smp_atomic_read_nob(&prt->refc) > 0);
- erts_smp_atomic_inc_nob(&prt->refc);
-
-#ifdef ERTS_SMP
- res = erts_smp_mtx_trylock(prt->lock);
- if (res == EBUSY) {
- erts_smp_atomic_dec_nob(&prt->refc);
- }
-#else
- res = 0;
-#endif
-
- return res;
-}
-
-ERTS_GLB_INLINE void
-erts_smp_port_lock(Port *prt)
-{
- ASSERT(erts_smp_atomic_read_nob(&prt->refc) > 0);
- erts_smp_atomic_inc_nob(&prt->refc);
-#ifdef ERTS_SMP
- erts_smp_mtx_lock(prt->lock);
-#endif
-}
-
-ERTS_GLB_INLINE void
-erts_smp_port_unlock(Port *prt)
-{
- erts_aint_t refc;
-#ifdef ERTS_SMP
- erts_smp_mtx_unlock(prt->lock);
-#endif
- refc = erts_smp_atomic_dec_read_nob(&prt->refc);
- ASSERT(refc >= 0);
- if (refc == 0)
- erts_port_cleanup(prt);
-}
-
-#endif /* #if ERTS_GLB_INLINE_INCL_FUNC_DEF */
-
-
-#define ERTS_INVALID_PORT_OPT(PP, ID, FLGS) \
- (!(PP) || ((PP)->status & (FLGS)) || (PP)->id != (ID))
-
-/* port lookup */
-
-#define INVALID_PORT(PP, ID) \
- ERTS_INVALID_PORT_OPT((PP), (ID), ERTS_PORT_SFLGS_INVALID_LOOKUP)
-
-/* Invalidate trace port if anything suspicious, for instance
- * that the port is a distribution port or it is busy.
- */
-#define INVALID_TRACER_PORT(PP, ID) \
- ERTS_INVALID_PORT_OPT((PP), (ID), ERTS_PORT_SFLGS_INVALID_TRACER_LOOKUP)
-
-#define ERTS_PORT_SCHED_ID(P, ID) \
- ((Uint) (UWord) erts_prtsd_set((P), ERTS_PSD_SCHED_ID, (void *) (UWord) (ID)))
-
-#ifdef ERTS_SMP
-Port *erts_de2port(DistEntry *, Process *, ErtsProcLocks);
-#endif
-
-#define erts_id2port(ID, P, PL) \
- erts_id2port_sflgs((ID), (P), (PL), ERTS_PORT_SFLGS_INVALID_LOOKUP)
-
-ERTS_GLB_INLINE Port*erts_id2port_sflgs(Eterm, Process *, ErtsProcLocks, Uint32);
-ERTS_GLB_INLINE void erts_port_release(Port *);
-ERTS_GLB_INLINE Port*erts_drvport2port(ErlDrvPort);
-ERTS_GLB_INLINE Port*erts_drvportid2port(Eterm);
-ERTS_GLB_INLINE Uint32 erts_portid2status(Eterm id);
-ERTS_GLB_INLINE int erts_is_port_alive(Eterm id);
-ERTS_GLB_INLINE int erts_is_valid_tracer_port(Eterm id);
-ERTS_GLB_INLINE void erts_port_status_bandor_set(Port *, Uint32, Uint32);
-ERTS_GLB_INLINE void erts_port_status_band_set(Port *, Uint32);
-ERTS_GLB_INLINE void erts_port_status_bor_set(Port *, Uint32);
-ERTS_GLB_INLINE void erts_port_status_set(Port *, Uint32);
-ERTS_GLB_INLINE Uint32 erts_port_status_get(Port *);
-
-#if ERTS_GLB_INLINE_INCL_FUNC_DEF
-
-ERTS_GLB_INLINE Port*
-erts_id2port_sflgs(Eterm id, Process *c_p, ErtsProcLocks c_p_locks, Uint32 sflgs)
-{
-#ifdef ERTS_SMP
- int no_proc_locks = !c_p || !c_p_locks;
-#endif
- Port *prt;
-
- if (is_not_internal_port(id))
- return NULL;
-
- prt = &erts_port[internal_port_index(id)];
-
- erts_smp_port_state_lock(prt);
- if (ERTS_INVALID_PORT_OPT(prt, id, sflgs)) {
- erts_smp_port_state_unlock(prt);
- prt = NULL;
- }
- else {
- erts_smp_atomic_inc_nob(&prt->refc);
- erts_smp_port_state_unlock(prt);
-
-#ifdef ERTS_SMP
- if (no_proc_locks)
- erts_smp_mtx_lock(prt->lock);
- else if (erts_smp_mtx_trylock(prt->lock) == EBUSY) {
- /* Unlock process locks, and acquire locks in lock order... */
- erts_smp_proc_unlock(c_p, c_p_locks);
- erts_smp_mtx_lock(prt->lock);
- erts_smp_proc_lock(c_p, c_p_locks);
- }
-
- /* The id may not have changed... */
- ERTS_SMP_LC_ASSERT(prt->id == id);
- /* ... but status may have... */
- if (prt->status & sflgs) {
- erts_smp_port_unlock(prt); /* Also decrements refc... */
- prt = NULL;
- }
-#endif
-
- }
-
- return prt;
-}
-
-ERTS_GLB_INLINE void
-erts_port_release(Port *prt)
-{
- erts_smp_port_unlock(prt);
-}
-
-ERTS_GLB_INLINE Port*
-erts_drvport2port(ErlDrvPort drvport)
-{
- int ix = (int) drvport;
- if (ix < 0 || erts_max_ports <= ix)
- return NULL;
- if (erts_port[ix].status & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP)
- return NULL;
- ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(&erts_port[ix]));
- return &erts_port[ix];
-}
-
-ERTS_GLB_INLINE Port*
-erts_drvportid2port(Eterm id)
-{
- int ix;
- if (is_not_internal_port(id))
- return NULL;
- ix = (int) internal_port_index(id);
- if (erts_max_ports <= ix)
- return NULL;
- if (erts_port[ix].status & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP)
- return NULL;
- if (erts_port[ix].id != id)
- return NULL;
- ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(&erts_port[ix]));
- return &erts_port[ix];
-}
-
-ERTS_GLB_INLINE Uint32
-erts_portid2status(Eterm id)
-{
- if (is_not_internal_port(id))
- return ERTS_PORT_SFLG_INVALID;
- else {
- Uint32 status;
- int ix = internal_port_index(id);
- if (erts_max_ports <= ix)
- return ERTS_PORT_SFLG_INVALID;
- erts_smp_port_state_lock(&erts_port[ix]);
- if (erts_port[ix].id == id)
- status = erts_port[ix].status;
- else
- status = ERTS_PORT_SFLG_INVALID;
- erts_smp_port_state_unlock(&erts_port[ix]);
- return status;
- }
-}
-
-ERTS_GLB_INLINE int
-erts_is_port_alive(Eterm id)
-{
- return !(erts_portid2status(id) & (ERTS_PORT_SFLG_INVALID
- | ERTS_PORT_SFLGS_DEAD));
-}
-
-ERTS_GLB_INLINE int
-erts_is_valid_tracer_port(Eterm id)
-{
- return !(erts_portid2status(id) & ERTS_PORT_SFLGS_INVALID_TRACER_LOOKUP);
-}
-
-ERTS_GLB_INLINE void erts_port_status_bandor_set(Port *prt,
- Uint32 band_status,
- Uint32 bor_status)
-{
- ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
- erts_smp_port_state_lock(prt);
- prt->status &= band_status;
- prt->status |= bor_status;
- erts_smp_port_state_unlock(prt);
-}
-
-ERTS_GLB_INLINE void erts_port_status_band_set(Port *prt, Uint32 status)
-{
- ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
- erts_smp_port_state_lock(prt);
- prt->status &= status;
- erts_smp_port_state_unlock(prt);
-}
-
-ERTS_GLB_INLINE void erts_port_status_bor_set(Port *prt, Uint32 status)
-{
- ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
- erts_smp_port_state_lock(prt);
- prt->status |= status;
- erts_smp_port_state_unlock(prt);
-}
-
-ERTS_GLB_INLINE void erts_port_status_set(Port *prt, Uint32 status)
-{
- ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
- erts_smp_port_state_lock(prt);
- prt->status = status;
- erts_smp_port_state_unlock(prt);
-}
-
-ERTS_GLB_INLINE Uint32 erts_port_status_get(Port *prt)
-{
- Uint32 res;
- erts_smp_port_state_lock(prt);
- res = prt->status;
- erts_smp_port_state_unlock(prt);
- return res;
-}
-#endif /* #if ERTS_GLB_INLINE_INCL_FUNC_DEF */
-
/* erl_drv_thread.c */
void erl_drv_thr_init(void);
-/* time.c */
-
/* utils.c */
-
-typedef struct {
-#ifdef DEBUG
- int smp_api;
-#endif
- union {
- Uint64 not_atomic;
-#ifdef ARCH_64
- erts_atomic_t atomic;
-#else
- erts_dw_atomic_t atomic;
-#endif
- } counter;
-} erts_interval_t;
-
-void erts_interval_init(erts_interval_t *);
-void erts_smp_interval_init(erts_interval_t *);
-Uint64 erts_step_interval_nob(erts_interval_t *);
-Uint64 erts_step_interval_relb(erts_interval_t *);
-Uint64 erts_smp_step_interval_nob(erts_interval_t *);
-Uint64 erts_smp_step_interval_relb(erts_interval_t *);
-Uint64 erts_ensure_later_interval_nob(erts_interval_t *, Uint64);
-Uint64 erts_ensure_later_interval_acqb(erts_interval_t *, Uint64);
-Uint64 erts_smp_ensure_later_interval_nob(erts_interval_t *, Uint64);
-Uint64 erts_smp_ensure_later_interval_acqb(erts_interval_t *, Uint64);
-#ifdef ARCH_32
-ERTS_GLB_INLINE Uint64 erts_interval_dw_aint_to_val__(erts_dw_aint_t *);
-#endif
-ERTS_GLB_INLINE Uint64 erts_current_interval_nob__(erts_interval_t *);
-ERTS_GLB_INLINE Uint64 erts_current_interval_acqb__(erts_interval_t *);
-ERTS_GLB_INLINE Uint64 erts_current_interval_nob(erts_interval_t *);
-ERTS_GLB_INLINE Uint64 erts_current_interval_acqb(erts_interval_t *);
-ERTS_GLB_INLINE Uint64 erts_smp_current_interval_nob(erts_interval_t *);
-ERTS_GLB_INLINE Uint64 erts_smp_current_interval_acqb(erts_interval_t *);
-
-#if ERTS_GLB_INLINE_INCL_FUNC_DEF
-
-#ifdef ARCH_32
-
-ERTS_GLB_INLINE Uint64
-erts_interval_dw_aint_to_val__(erts_dw_aint_t *dw)
-{
-#ifdef ETHR_SU_DW_NAINT_T__
- return (Uint64) dw->dw_sint;
-#else
- Uint64 res;
- res = (Uint64) ((Uint32) dw->sint[ERTS_DW_AINT_HIGH_WORD]);
- res <<= 32;
- res |= (Uint64) ((Uint32) dw->sint[ERTS_DW_AINT_LOW_WORD]);
- return res;
-#endif
-}
-
-#endif
-
-ERTS_GLB_INLINE Uint64
-erts_current_interval_nob__(erts_interval_t *icp)
-{
-#ifdef ARCH_64
- return (Uint64) erts_atomic_read_nob(&icp->counter.atomic);
-#else
- erts_dw_aint_t dw;
- erts_dw_atomic_read_nob(&icp->counter.atomic, &dw);
- return erts_interval_dw_aint_to_val__(&dw);
-#endif
-}
-
-ERTS_GLB_INLINE Uint64
-erts_current_interval_acqb__(erts_interval_t *icp)
-{
-#ifdef ARCH_64
- return (Uint64) erts_atomic_read_acqb(&icp->counter.atomic);
-#else
- erts_dw_aint_t dw;
- erts_dw_atomic_read_acqb(&icp->counter.atomic, &dw);
- return erts_interval_dw_aint_to_val__(&dw);
-#endif
-}
-
-ERTS_GLB_INLINE Uint64
-erts_current_interval_nob(erts_interval_t *icp)
-{
- ASSERT(!icp->smp_api);
- return erts_current_interval_nob__(icp);
-}
-
-ERTS_GLB_INLINE Uint64
-erts_current_interval_acqb(erts_interval_t *icp)
-{
- ASSERT(!icp->smp_api);
- return erts_current_interval_acqb__(icp);
-}
-
-ERTS_GLB_INLINE Uint64
-erts_smp_current_interval_nob(erts_interval_t *icp)
-{
- ASSERT(icp->smp_api);
-#ifdef ERTS_SMP
- return erts_current_interval_nob__(icp);
-#else
- return icp->counter.not_atomic;
-#endif
-}
-
-ERTS_GLB_INLINE Uint64
-erts_smp_current_interval_acqb(erts_interval_t *icp)
-{
- ASSERT(icp->smp_api);
-#ifdef ERTS_SMP
- return erts_current_interval_acqb__(icp);
-#else
- return icp->counter.not_atomic;
-#endif
-}
-
-#endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */
-
-/*
- * To be used to silence unused result warnings, but do not abuse it.
- */
-void erts_silence_warn_unused_result(long unused);
-
void erts_cleanup_offheap(ErlOffHeap *offheap);
-int erts_fit_in_bits_int64(Sint64);
-int erts_fit_in_bits_int32(Sint32);
-int list_length(Eterm);
Export* erts_find_function(Eterm, Eterm, unsigned int, ErtsCodeIndex);
-int erts_is_builtin(Eterm, Eterm, int);
-Uint32 make_broken_hash(Eterm);
-Uint32 block_hash(byte *, unsigned, Uint32);
-Uint32 make_hash2(Eterm);
-Uint32 make_hash(Eterm);
-
-
-Eterm erts_bld_atom(Uint **hpp, Uint *szp, char *str);
-Eterm erts_bld_uint(Uint **hpp, Uint *szp, Uint ui);
-Eterm erts_bld_uword(Uint **hpp, Uint *szp, UWord uw);
-Eterm erts_bld_uint64(Uint **hpp, Uint *szp, Uint64 ui64);
-Eterm erts_bld_sint64(Uint **hpp, Uint *szp, Sint64 si64);
-Eterm erts_bld_cons(Uint **hpp, Uint *szp, Eterm car, Eterm cdr);
-Eterm erts_bld_tuple(Uint **hpp, Uint *szp, Uint arity, ...);
-Eterm erts_bld_tuplev(Uint **hpp, Uint *szp, Uint arity, Eterm terms[]);
-Eterm erts_bld_string_n(Uint **hpp, Uint *szp, const char *str, Sint len);
-#define erts_bld_string(hpp,szp,str) erts_bld_string_n(hpp,szp,str,strlen(str))
-Eterm erts_bld_list(Uint **hpp, Uint *szp, Sint length, Eterm terms[]);
-Eterm erts_bld_2tup_list(Uint **hpp, Uint *szp,
- Sint length, Eterm terms1[], Uint terms2[]);
-Eterm
-erts_bld_atom_uint_2tup_list(Uint **hpp, Uint *szp,
- Sint length, Eterm atoms[], Uint uints[]);
-Eterm
-erts_bld_atom_2uint_3tup_list(Uint **hpp, Uint *szp, Sint length,
- Eterm atoms[], Uint uints1[], Uint uints2[]);
Eterm store_external_or_ref_in_proc_(Process *, Eterm);
Eterm store_external_or_ref_(Uint **, ErlOffHeap*, Eterm);
@@ -1455,42 +761,6 @@ Eterm store_external_or_ref_(Uint **, ErlOffHeap*, Eterm);
(ASSERT_EXPR(is_node_container((NC))), \
IS_CONST((NC)) ? (NC) : store_external_or_ref_in_proc_((Pp), (NC)))
-void erts_init_utils(void);
-void erts_init_utils_mem(void);
-
-erts_dsprintf_buf_t *erts_create_tmp_dsbuf(Uint);
-void erts_destroy_tmp_dsbuf(erts_dsprintf_buf_t *);
-
-#if HALFWORD_HEAP
-int eq_rel(Eterm a, Eterm* a_base, Eterm b, Eterm* b_base);
-# define eq(A,B) eq_rel(A,NULL,B,NULL)
-#else
-int eq(Eterm, Eterm);
-# define eq_rel(A,A_BASE,B,B_BASE) eq(A,B)
-#endif
-
-#define EQ(x,y) (((x) == (y)) || (is_not_both_immed((x),(y)) && eq((x),(y))))
-
-#if HALFWORD_HEAP
-Sint cmp_rel(Eterm, Eterm*, Eterm, Eterm*);
-#define CMP(A,B) cmp_rel(A,NULL,B,NULL)
-#else
-Sint cmp(Eterm, Eterm);
-#define cmp_rel(A,A_BASE,B,B_BASE) cmp(A,B)
-#define CMP(A,B) cmp(A,B)
-#endif
-#define cmp_lt(a,b) (CMP((a),(b)) < 0)
-#define cmp_le(a,b) (CMP((a),(b)) <= 0)
-#define cmp_eq(a,b) (CMP((a),(b)) == 0)
-#define cmp_ne(a,b) (CMP((a),(b)) != 0)
-#define cmp_ge(a,b) (CMP((a),(b)) >= 0)
-#define cmp_gt(a,b) (CMP((a),(b)) > 0)
-
-#define CMP_LT(a,b) ((a) != (b) && cmp_lt((a),(b)))
-#define CMP_GE(a,b) ((a) == (b) || cmp_ge((a),(b)))
-#define CMP_EQ(a,b) ((a) == (b) || cmp_eq((a),(b)))
-#define CMP_NE(a,b) ((a) != (b) && cmp_ne((a),(b)))
-
/* duplicates from big.h */
int term_to_Uint(Eterm term, Uint *up);
int term_to_UWord(Eterm, UWord*);
@@ -1527,79 +797,6 @@ Eterm erts_convert_native_to_filename(Process *p, byte *bytes);
#define ERTS_UTF8_ERROR 2
#define ERTS_UTF8_ANALYZE_MORE 3
-/* erl_trace.c */
-void erts_init_trace(void);
-void erts_trace_check_exiting(Eterm exiting);
-Eterm erts_set_system_seq_tracer(Process *c_p,
- ErtsProcLocks c_p_locks,
- Eterm new);
-Eterm erts_get_system_seq_tracer(void);
-void erts_change_default_tracing(int setflags, Uint *flagsp, Eterm *tracerp);
-void erts_get_default_tracing(Uint *flagsp, Eterm *tracerp);
-void erts_set_system_monitor(Eterm monitor);
-Eterm erts_get_system_monitor(void);
-
-#ifdef ERTS_SMP
-void erts_check_my_tracer_proc(Process *);
-void erts_block_sys_msg_dispatcher(void);
-void erts_release_sys_msg_dispatcher(void);
-void erts_foreach_sys_msg_in_q(void (*func)(Eterm,
- Eterm,
- Eterm,
- ErlHeapFragment *));
-void erts_queue_error_logger_message(Eterm, Eterm, ErlHeapFragment *);
-#endif
-
-void erts_send_sys_msg_proc(Eterm, Eterm, Eterm, ErlHeapFragment *);
-void trace_send(Process*, Eterm, Eterm);
-void trace_receive(Process*, Eterm);
-Uint32 erts_call_trace(Process *p, BeamInstr mfa[], Binary *match_spec, Eterm* args,
- int local, Eterm *tracer_pid);
-void erts_trace_return(Process* p, BeamInstr* fi, Eterm retval, Eterm *tracer_pid);
-void erts_trace_exception(Process* p, BeamInstr mfa[], Eterm class, Eterm value,
- Eterm *tracer);
-void erts_trace_return_to(Process *p, BeamInstr *pc);
-void trace_sched(Process*, Eterm);
-void trace_proc(Process*, Process*, Eterm, Eterm);
-void trace_proc_spawn(Process*, Eterm pid, Eterm mod, Eterm func, Eterm args);
-void save_calls(Process *p, Export *);
-void trace_gc(Process *p, Eterm what);
-/* port tracing */
-void trace_virtual_sched(Process*, Eterm);
-void trace_sched_ports(Port *pp, Eterm);
-void trace_sched_ports_where(Port *pp, Eterm, Eterm);
-void trace_port(Port *, Eterm what, Eterm data);
-void trace_port_open(Port *, Eterm calling_pid, Eterm drv_name);
-
-/* system_profile */
-void erts_set_system_profile(Eterm profile);
-Eterm erts_get_system_profile(void);
-void profile_scheduler(Eterm scheduler_id, Eterm);
-void profile_scheduler_q(Eterm scheduler_id, Eterm state, Eterm no_schedulers, Uint Ms, Uint s, Uint us);
-void profile_runnable_proc(Process* p, Eterm status);
-void profile_runnable_port(Port* p, Eterm status);
-void erts_system_profile_setup_active_schedulers(void);
-
-/* system_monitor */
-void monitor_long_gc(Process *p, Uint time);
-void monitor_large_heap(Process *p);
-void monitor_generic(Process *p, Eterm type, Eterm spec);
-Uint erts_trace_flag2bit(Eterm flag);
-int erts_trace_flags(Eterm List,
- Uint *pMask, Eterm *pTracer, int *pCpuTimestamp);
-Eterm erts_bif_trace(int bif_index, Process* p, Eterm* args, BeamInstr *I);
-
-#ifdef ERTS_SMP
-void erts_send_pending_trace_msgs(ErtsSchedulerData *esdp);
-#define ERTS_SMP_CHK_PEND_TRACE_MSGS(ESDP) \
-do { \
- if ((ESDP)->pending_trace_msgs) \
- erts_send_pending_trace_msgs((ESDP)); \
-} while (0)
-#else
-#define ERTS_SMP_CHK_PEND_TRACE_MSGS(ESDP)
-#endif
-
void bin_write(int, void*, byte*, size_t);
int intlist_to_buf(Eterm, char*, int); /* most callers pass plain char*'s */
@@ -1617,9 +814,16 @@ char* Sint_to_buf(Sint, struct Sint_buf*);
#define ERTS_IOLIST_TYPE 2
Eterm buf_to_intlist(Eterm**, char*, size_t, Eterm); /* most callers pass plain char*'s */
-int io_list_to_buf(Eterm, char*, int);
-int io_list_to_buf2(Eterm, char*, int);
-int erts_iolist_size(Eterm, Uint *);
+
+#define ERTS_IOLIST_TO_BUF_OVERFLOW (~((ErlDrvSizeT) 0))
+#define ERTS_IOLIST_TO_BUF_TYPE_ERROR (~((ErlDrvSizeT) 1))
+#define ERTS_IOLIST_TO_BUF_FAILED(R) \
+ (((R) & (~((ErlDrvSizeT) 1))) == (~((ErlDrvSizeT) 1)))
+#define ERTS_IOLIST_TO_BUF_SUCCEEDED(R) \
+ (!ERTS_IOLIST_TO_BUF_FAILED((R)))
+
+ErlDrvSizeT erts_iolist_to_buf(Eterm, char*, ErlDrvSizeT);
+int erts_iolist_size(Eterm, ErlDrvSizeT *);
int is_string(Eterm);
void erl_at_exit(void (*) (void*), void*);
Eterm collect_memory(Process *);
@@ -1664,41 +868,6 @@ Uint erts_current_reductions(Process* current, Process *p);
int erts_print_system_version(int to, void *arg, Process *c_p);
int erts_hibernate(Process* c_p, Eterm module, Eterm function, Eterm args, Eterm* reg);
-#define seq_trace_output(token, msg, type, receiver, process) \
-seq_trace_output_generic((token), (msg), (type), (receiver), (process), NIL)
-#define seq_trace_output_exit(token, msg, type, receiver, exitfrom) \
-seq_trace_output_generic((token), (msg), (type), (receiver), NULL, (exitfrom))
-void seq_trace_output_generic(Eterm token, Eterm msg, Uint type,
- Eterm receiver, Process *process, Eterm exitfrom);
-
-int seq_trace_update_send(Process *process);
-
-Eterm erts_seq_trace(Process *process,
- Eterm atom_type, Eterm atom_true_or_false,
- int build_result);
-
-struct trace_pattern_flags {
- unsigned int breakpoint : 1; /* Set if any other is set */
- unsigned int local : 1; /* Local call trace breakpoint */
- unsigned int meta : 1; /* Metadata trace breakpoint */
- unsigned int call_count : 1; /* Fast call count breakpoint */
- unsigned int call_time : 1; /* Fast call time breakpoint */
-};
-extern const struct trace_pattern_flags erts_trace_pattern_flags_off;
-extern int erts_call_time_breakpoint_tracing;
-int erts_set_trace_pattern(Process*p, Eterm* mfa, int specified,
- Binary* match_prog_set, Binary *meta_match_prog_set,
- int on, struct trace_pattern_flags,
- Eterm meta_tracer_pid, int is_blocking);
-void
-erts_get_default_trace_pattern(int *trace_pattern_is_on,
- Binary **match_spec,
- Binary **meta_match_spec,
- struct trace_pattern_flags *trace_pattern_flags,
- Eterm *meta_tracer_pid);
-int erts_is_default_trace_enabled(void);
-void erts_bif_trace_init(void);
-int erts_finish_breakpointing(void);
/*
** Call_trace uses this API for the parameter matching functions
@@ -1940,15 +1109,15 @@ dtrace_pid_str(Eterm pid, char *process_buf)
ERTS_GLB_INLINE void
dtrace_proc_str(Process *process, char *process_buf)
{
- dtrace_pid_str(process->id, process_buf);
+ dtrace_pid_str(process->common.id, process_buf);
}
ERTS_GLB_INLINE void
dtrace_port_str(Port *port, char *port_buf)
{
erts_snprintf(port_buf, DTRACE_TERM_BUF_SIZE, "#Port<%lu.%lu>",
- port_channel_no(port->id),
- port_number(port->id));
+ port_channel_no(port->common.id),
+ port_number(port->common.id));
}
ERTS_GLB_INLINE void
diff --git a/erts/emulator/beam/index.c b/erts/emulator/beam/index.c
index 25d5cce0f3..79c3ecf1b3 100644
--- a/erts/emulator/beam/index.c
+++ b/erts/emulator/beam/index.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2012. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -82,7 +82,8 @@ index_put_entry(IndexTable* t, void* tmpl)
if (ix >= t->size) {
Uint sz;
if (ix >= t->limit) {
- erl_exit(1, "no more index entries in %s (max=%d)\n",
+ /* A core dump is unnecessary */
+ erl_exit(ERTS_DUMP_EXIT, "no more index entries in %s (max=%d)\n",
t->htable.name, t->limit);
}
sz = INDEX_PAGE_SIZE*sizeof(IndexSlot*);
diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c
index dec51f3be5..e466f0e299 100644
--- a/erts/emulator/beam/io.c
+++ b/erts/emulator/beam/io.c
@@ -43,6 +43,8 @@
#include "erl_version.h"
#include "error.h"
#include "erl_async.h"
+#define ERTS_WANT_EXTERNAL_TAGS
+#include "external.h"
#include "dtrace-wrapper.h"
extern ErlDrvEntry fd_driver_entry;
@@ -51,34 +53,40 @@ extern ErlDrvEntry spawn_driver_entry;
extern ErlDrvEntry *driver_tab[]; /* table of static drivers, only used during initialization */
erts_driver_t *driver_list; /* List of all drivers, static and dynamic. */
-erts_smp_mtx_t erts_driver_list_lock; /* Mutex for driver list */
+erts_smp_rwmtx_t erts_driver_list_lock; /* Mutex for driver list */
static erts_smp_tsd_key_t driver_list_lock_status_key; /*stop recursive locks when calling
driver init */
static erts_smp_tsd_key_t driver_list_last_error_key; /* Save last DDLL error on a
per thread basis (for BC interfaces) */
-Port* erts_port; /* The port table */
+ErtsPTab erts_port erts_align_attribute(ERTS_CACHE_LINE_SIZE); /* The port table */
erts_smp_atomic_t erts_bytes_out; /* No bytes sent out of the system */
erts_smp_atomic_t erts_bytes_in; /* No bytes gotten into the system */
-Uint erts_max_ports;
-Uint erts_port_tab_index_mask;
-
const ErlDrvTermData driver_term_nil = (ErlDrvTermData)NIL;
+const Port erts_invalid_port = {{ERTS_INVALID_PORT}};
+
erts_driver_t vanilla_driver;
erts_driver_t spawn_driver;
erts_driver_t fd_driver;
+int erts_port_synchronous_ops = 0;
+int erts_port_schedule_all_ops = 0;
+int erts_port_parallelism = 0;
+
+static void deliver_result(Eterm sender, Eterm pid, Eterm res);
static int init_driver(erts_driver_t *, ErlDrvEntry *, DE_Handle *);
static void terminate_port(Port *p);
static void pdl_init(void);
#ifdef ERTS_SMP
static void driver_monitor_lock_pdl(Port *p);
static void driver_monitor_unlock_pdl(Port *p);
+#define DRV_MONITOR_LOOKUP_PORT_LOCK_PDL(Port) erts_thr_drvport2port_raw((Port), 1)
#define DRV_MONITOR_LOCK_PDL(Port) driver_monitor_lock_pdl(Port)
#define DRV_MONITOR_UNLOCK_PDL(Port) driver_monitor_unlock_pdl(Port)
#else
+#define DRV_MONITOR_LOOKUP_PORT_LOCK_PDL(Port) erts_thr_drvport2port_raw((Port), 0)
#define DRV_MONITOR_LOCK_PDL(Port) /* nothing */
#define DRV_MONITOR_UNLOCK_PDL(Port) /* nothing */
#endif
@@ -89,36 +97,12 @@ static void driver_monitor_unlock_pdl(Port *p);
static ERTS_INLINE ErlIOQueue*
drvport2ioq(ErlDrvPort drvport)
{
- int ix = (int) drvport;
- Uint32 status;
-
- if (ix < 0 || erts_max_ports <= ix)
+ Port *prt = erts_thr_drvport2port_raw(drvport, 0);
+ erts_aint32_t state = erts_atomic32_read_nob(&prt->state);
+ if (state & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP)
return NULL;
-
- if (erts_get_scheduler_data()) {
- ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(&erts_port[ix]));
- ERTS_LC_ASSERT(!erts_port[ix].port_data_lock
- || erts_lc_mtx_is_locked(
- &erts_port[ix].port_data_lock->mtx));
-
- status = erts_port[ix].status;
- }
- else {
- erts_smp_port_state_lock(&erts_port[ix]);
- status = erts_port[ix].status;
- erts_smp_port_state_unlock(&erts_port[ix]);
-
- ERTS_LC_ASSERT((status & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP)
- || erts_port[ix].port_data_lock);
- ERTS_LC_ASSERT(!erts_port[ix].port_data_lock
- || erts_lc_mtx_is_locked(
- &erts_port[ix].port_data_lock->mtx));
-
- }
-
- return ((status & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP)
- ? NULL
- : &erts_port[ix].ioq);
+ else
+ return &prt->ioq;
}
static ERTS_INLINE int
@@ -196,27 +180,13 @@ typedef struct line_buf_context {
dtrace_port_str((PORT), port_str);
#endif
-/* The 'number' field in a port now has two parts: the lowest bits
- contain the index in the port table, and the higher bits are a counter
- which is incremented each time we look for a free port and start from
- the beginning of the table. erts_max_ports is the number of file descriptors,
- rounded up to a power of 2.
- To get the index from a port, use the macro 'internal_port_index';
- 'port_number' returns the whole number field.
-*/
-
-static erts_smp_spinlock_t get_free_port_lck;
-static Uint last_port_num;
-static Uint port_num_mask;
-erts_smp_atomic32_t erts_ports_snapshot; /* Identifies the _next_ snapshot (not the ongoing) */
-
-
static ERTS_INLINE void
kill_port(Port *pp)
{
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(pp));
+ erts_ptab_delete_element(&erts_port, &pp->common); /* Time of death */
erts_port_task_free_port(pp);
- ASSERT(pp->status & ERTS_PORT_SFLGS_DEAD);
+ /* In non-smp case the port structure may have been deallocated now */
}
#ifdef ERTS_SMP
@@ -227,146 +197,280 @@ erts_lc_is_port_locked(Port *prt)
{
if (!prt)
return 0;
+ ERTS_SMP_LC_ASSERT(prt->lock);
return erts_smp_lc_mtx_is_locked(prt->lock);
}
#endif
#endif /* #ifdef ERTS_SMP */
-static int
-get_free_port(void)
-{
- Uint num;
- Uint tries = erts_max_ports;
- Port* port;
+static void initq(Port* prt);
- erts_smp_spin_lock(&get_free_port_lck);
- num = last_port_num + 1;
- for (;; ++num) {
- port = &erts_port[num & erts_port_tab_index_mask];
+#if defined(ERTS_ENABLE_LOCK_CHECK) || defined(ERTS_ENABLE_LOCK_COUNT)
+#define ERTS_PORT_INIT_INSTR_NEED_ID 1
+#else
+#define ERTS_PORT_INIT_INSTR_NEED_ID 0
+#endif
- erts_smp_port_state_lock(port);
- if (port->status & ERTS_PORT_SFLG_FREE) {
- last_port_num = num;
- erts_smp_spin_unlock(&get_free_port_lck);
- break;
- }
- erts_smp_port_state_unlock(port);
+static ERTS_INLINE void port_init_instr(Port *prt
+#if ERTS_PORT_INIT_INSTR_NEED_ID
+ , Eterm id
+#endif
+ )
+{
+#if !ERTS_PORT_INIT_INSTR_NEED_ID
+ Eterm id = NIL; /* Not used */
+#endif
- if (--tries == 0) {
- erts_smp_spin_unlock(&get_free_port_lck);
- return -1;
- }
+ /*
+ * Stuff that need to be initialized with the port id
+ * in the instrumented case, but not in the normal case.
+ */
+#ifdef ERTS_SMP
+ ASSERT(prt->drv_ptr && prt->lock);
+ if (!prt->drv_ptr->lock) {
+ char *lock_str = "port_lock";
+#ifdef ERTS_ENABLE_LOCK_COUNT
+ if (!(erts_lcnt_rt_options & ERTS_LCNT_OPT_PORTLOCK))
+ lock_str = NULL;
+#endif
+ erts_mtx_init_locked_x(prt->lock, lock_str, id);
}
- port->status = ERTS_PORT_SFLG_INITIALIZING;
- ERTS_LC_ASSERT(erts_smp_atomic_read_nob(&port->refc) == 0);
- erts_smp_atomic_set_nob(&port->refc, 2); /* Port alive + lock */
- erts_smp_port_state_unlock(port);
- return num & port_num_mask;
+#endif
+ erts_port_task_init_sched(&prt->sched, id);
}
-/*
- * erts_test_next_port() is only used for testing.
- */
-Sint
-erts_test_next_port(int set, Uint next)
+#if !ERTS_PORT_INIT_INSTR_NEED_ID
+static ERTS_INLINE void port_init_instr_abort(Port *prt)
{
- Uint i, num;
- Sint res = -1;
-
- erts_smp_spin_lock(&get_free_port_lck);
- if (set) {
- last_port_num = (next - 1) & port_num_mask;
+#ifdef ERTS_SMP
+ ASSERT(prt->drv_ptr && prt->lock);
+ if (!prt->drv_ptr->lock) {
+ erts_mtx_unlock(prt->lock);
+ erts_mtx_destroy(prt->lock);
}
- num = last_port_num + 1;
+#endif
+ erts_port_task_fini_sched(&prt->sched);
+}
+#endif
- for (i=0; i < erts_max_ports && res<0; ++i, ++num) {
-
- Port* port = &erts_port[num & erts_port_tab_index_mask];
+static void insert_port_struct(void *vprt, Eterm data)
+{
+ Port *prt = (Port *) vprt;
+ Eterm id = make_internal_port(data);
+#if ERTS_PORT_INIT_INSTR_NEED_ID
+ /*
+ * This cannot be done earlier in the instrumented
+ * case since we don't now 'id' until now.
+ */
+ port_init_instr(prt, id);
+#endif
+ prt->common.id = id;
+ erts_atomic32_init_relb(&prt->state, ERTS_PORT_SFLG_INITIALIZING);
+}
- erts_smp_port_state_lock(port);
+#define ERTS_CREATE_PORT_FLAG_PARALLELISM (1 << 0)
- if (port->status & ERTS_PORT_SFLG_FREE) {
- last_port_num = num - 1;
- res = num & port_num_mask;
- }
- erts_smp_port_state_unlock(port);
+static Port *create_port(char *name,
+ erts_driver_t *driver,
+ erts_mtx_t *driver_lock,
+ int create_flags,
+ Eterm pid,
+ int *enop)
+{
+ ErtsPortTaskBusyPortQ *busy_port_queue;
+ Port *prt;
+ char *p;
+ size_t port_size, busy_port_queue_size, size;
+ erts_aint32_t state = ERTS_PORT_SFLG_CONNECTED;
+ erts_aint32_t x_pts_flgs = 0;
+#ifdef DEBUG
+ /* Make sure the debug flags survives until port is freed */
+ state |= ERTS_PORT_SFLG_PORT_DEBUG;
+#endif
+
+#ifdef ERTS_SMP
+ if (!driver_lock) {
+ /* Align size for mutex following port struct */
+ port_size = size = ERTS_ALC_DATA_ALIGN_SIZE(sizeof(Port));
+ size += sizeof(erts_mtx_t);
}
- erts_smp_spin_unlock(&get_free_port_lck);
- return res;
-}
+ else
+#endif
+ port_size = size = ERTS_ALC_DATA_ALIGN_SIZE(sizeof(Port));
+ busy_port_queue_size
+ = ((driver->flags & ERL_DRV_FLAG_NO_BUSY_MSGQ)
+ ? 0
+ : ERTS_ALC_DATA_ALIGN_SIZE(sizeof(ErtsPortTaskBusyPortQ)));
+ size += busy_port_queue_size;
-static void port_cleanup(Port *prt);
+ size += sys_strlen(name) + 1;
-#ifdef ERTS_SMP
+ p = erts_alloc_fnf(ERTS_ALC_T_PORT, size);
+ if (!p) {
+ if (enop)
+ *enop = ENOMEM;
+ return NULL;
+ }
-static void
-sched_port_cleanup(void *vprt)
-{
- Port *prt = (Port *) vprt;
- erts_smp_mtx_lock(prt->lock);
- port_cleanup(prt);
-}
+ prt = (Port *) p;
+ p += port_size;
-#endif
+ if (!busy_port_queue_size)
+ busy_port_queue = NULL;
+ else {
+ busy_port_queue = (ErtsPortTaskBusyPortQ *) p;
+ p += busy_port_queue_size;
+ }
-void
-erts_port_cleanup(Port *prt)
-{
#ifdef ERTS_SMP
- if (erts_smp_mtx_trylock(prt->lock) == EBUSY)
- erts_schedule_misc_op(sched_port_cleanup, (void *) prt);
- else
+ if (driver_lock) {
+ prt->lock = driver_lock;
+ erts_mtx_lock(driver_lock);
+ }
+ else {
+ prt->lock = (erts_mtx_t *) p;
+ p += sizeof(erts_mtx_t);
+ state |= ERTS_PORT_SFLG_PORT_SPECIFIC_LOCK;
+ }
+ erts_smp_atomic_set_nob(&prt->run_queue,
+ (erts_aint_t) erts_get_runq_current(NULL));
+ prt->xports = NULL;
+#else
+ erts_atomic32_init_nob(&prt->refc, 1);
+ prt->cleanup = 0;
#endif
- port_cleanup(prt);
-}
+
+ erts_port_task_pre_init_sched(&prt->sched, busy_port_queue);
-void
-port_cleanup(Port *prt)
-{
+ prt->name = p;
+ sys_strcpy(p, name);
+ prt->drv_ptr = driver;
+ ERTS_P_LINKS(prt) = NULL;
+ ERTS_P_MONITORS(prt) = NULL;
+ prt->linebuf = NULL;
+ prt->bp = NULL;
+ prt->suspended = NULL;
+ prt->data = am_undefined;
+ prt->port_data_lock = NULL;
+ prt->control_flags = 0;
+ prt->bytes_in = 0;
+ prt->bytes_out = 0;
+ prt->dist_entry = NULL;
+ ERTS_PORT_INIT_CONNECTED(prt, pid);
+ prt->common.u.alive.reg = NULL;
#ifdef ERTS_SMP
- Uint32 port_specific;
- erts_smp_mtx_t *mtx;
+ prt->common.u.alive.ptimer = NULL;
+#else
+ sys_memset(&prt->common.u.alive.tm, 0, sizeof(ErlTimer));
#endif
- erts_driver_t *driver;
+ erts_port_task_handle_init(&prt->timeout_task);
+ prt->psd = NULL;
+ prt->drv_data = (SWord) 0;
+ prt->os_pid = -1;
- erts_smp_port_state_lock(prt);
+ /* Set default tracing */
+ erts_get_default_tracing(&ERTS_TRACE_FLAGS(prt), &ERTS_TRACER_PROC(prt));
- ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
- driver = prt->drv_ptr;
- prt->drv_ptr = NULL;
- ASSERT(driver);
+ ASSERT(((char *) prt) == ((char *) &prt->common));
- ASSERT(prt->status & ERTS_PORT_SFLG_FREE_SCHEDULED);
- ERTS_LC_ASSERT(erts_smp_atomic_read_nob(&prt->refc) == 0);
+#if !ERTS_PORT_INIT_INSTR_NEED_ID
+ /*
+ * When 'id' isn't needed (the normal case), it is better to
+ * do the initialization here avoiding unnecessary contention
+ * on table...
+ */
+ port_init_instr(prt);
+#endif
- ASSERT(prt->status & ERTS_PORT_SFLG_PORT_DEBUG);
- ASSERT(!(prt->status & ERTS_PORT_SFLG_FREE));
- prt->status = ERTS_PORT_SFLG_FREE;
+ if (!erts_ptab_new_element(&erts_port,
+ &prt->common,
+ (void *) prt,
+ insert_port_struct)) {
+#if !ERTS_PORT_INIT_INSTR_NEED_ID
+ port_init_instr_abort(prt);
+#endif
#ifdef ERTS_SMP
+ if (driver_lock)
+ erts_mtx_unlock(driver_lock);
+#endif
+ if (enop)
+ *enop = 0;
+ return NULL;
+ }
+
+ ASSERT(prt == (Port *) (erts_ptab_pix2intptr_nob(
+ &erts_port,
+ internal_port_index(prt->common.id))));
+
+ initq(prt);
- port_specific = (prt->status & ERTS_PORT_SFLG_PORT_SPECIFIC_LOCK);
+ ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
- mtx = prt->lock;
- ASSERT(mtx);
+ if (erts_port_schedule_all_ops)
+ x_pts_flgs |= ERTS_PTS_FLG_FORCE_SCHED;
- prt->lock = NULL;
+ if (create_flags & ERTS_CREATE_PORT_FLAG_PARALLELISM)
+ x_pts_flgs |= ERTS_PTS_FLG_PARALLELISM;
- erts_smp_port_state_unlock(prt);
- erts_smp_mtx_unlock(mtx);
+ if (x_pts_flgs)
+ erts_smp_atomic32_read_bor_nob(&prt->sched.flags, x_pts_flgs);
- if (port_specific) {
- erts_smp_mtx_destroy(mtx);
- erts_free(ERTS_ALC_T_PORT_LOCK, mtx);
- }
-#endif
+ erts_atomic32_set_relb(&prt->state, state);
+ return prt;
+}
- if (driver->handle)
- erts_ddll_dereference_driver(driver->handle);
+#ifndef ERTS_SMP
+void
+erts_port_cleanup(Port *prt)
+{
+ if (prt->drv_ptr && prt->drv_ptr->handle)
+ erts_ddll_dereference_driver(prt->drv_ptr->handle);
+ prt->drv_ptr = NULL;
+ erts_port_dec_refc(prt);
}
+#endif
+
+void
+erts_port_free(Port *prt)
+{
+#if defined(ERTS_SMP) || defined(DEBUG) || defined(ERTS_ENABLE_LOCK_CHECK)
+ erts_aint32_t state = erts_atomic32_read_nob(&prt->state);
+#endif
+ ERTS_LC_ASSERT(state & (ERTS_PORT_SFLG_INITIALIZING
+ | ERTS_PORT_SFLG_FREE));
+ ASSERT(state & ERTS_PORT_SFLG_PORT_DEBUG);
+
+#ifdef ERTS_SMP
+ ERTS_LC_ASSERT(erts_atomic32_read_nob(&prt->common.refc) == 0);
+#else
+ ERTS_LC_ASSERT(erts_atomic32_read_nob(&prt->refc) == 0);
+#endif
+ erts_port_task_fini_sched(&prt->sched);
+
+#ifdef ERTS_SMP
+ ASSERT(prt->lock);
+ if (state & ERTS_PORT_SFLG_PORT_SPECIFIC_LOCK)
+ erts_mtx_destroy(prt->lock);
+
+ /*
+ * We cannot dereference a driver using driver
+ * locking until here in smp case. Otherwise,
+ * the driver lock may still be in use by others.
+ *
+ * In the non-smp case we cannot do it here since
+ * this function may be called by non-scheduler
+ * threads. This is done in erts_port_cleanup()
+ * in the non-smp case.
+ */
+ if (prt->drv_ptr->handle)
+ erts_ddll_dereference_driver(prt->drv_ptr->handle);
+#endif
+ erts_free(ERTS_ALC_T_PORT, prt);
+}
/*
** Initialize v_start to point to the small fixed vector.
@@ -414,94 +518,21 @@ static void stopq(Port* prt)
if (prt->port_data_lock) {
driver_pdl_unlock(prt->port_data_lock);
driver_pdl_dec_refc(prt->port_data_lock);
- prt->port_data_lock = NULL;
}
}
-
-
-static void
-setup_port(Port* prt, Eterm pid, erts_driver_t *driver,
- ErlDrvData drv_data, char *name, Uint32 xstatus)
-{
- ErtsRunQueue *runq = erts_get_runq_current(NULL);
- char *new_name, *old_name;
-#ifdef DEBUG
- /* Make sure the debug flags survives until port is freed */
- xstatus |= ERTS_PORT_SFLG_PORT_DEBUG;
-#endif
- ASSERT(runq);
- ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
-
-
- new_name = (char*) erts_alloc(ERTS_ALC_T_PORT_NAME, sys_strlen(name)+1);
- sys_strcpy(new_name, name);
- erts_smp_runq_lock(runq);
- erts_smp_port_state_lock(prt);
- prt->os_pid = -1;
- prt->status = ERTS_PORT_SFLG_CONNECTED | xstatus;
- prt->snapshot = erts_smp_atomic32_read_nob(&erts_ports_snapshot);
- old_name = prt->name;
- prt->name = new_name;
-#ifdef ERTS_SMP
- erts_smp_atomic_set_nob(&prt->run_queue, (erts_aint_t) runq);
-#endif
- ASSERT(!prt->drv_ptr);
- prt->drv_ptr = driver;
- erts_smp_port_state_unlock(prt);
- erts_smp_runq_unlock(runq);
-#ifdef ERTS_SMP
- ASSERT(!prt->xports);
-#endif
- if (old_name) {
- erts_free(ERTS_ALC_T_PORT_NAME, (void *) old_name);
- }
-
- prt->control_flags = 0;
- prt->connected = pid;
- prt->drv_data = (SWord) drv_data;
- prt->bytes_in = 0;
- prt->bytes_out = 0;
- prt->dist_entry = NULL;
- prt->reg = NULL;
-#ifdef ERTS_SMP
- prt->ptimer = NULL;
-#else
- sys_memset(&prt->tm, 0, sizeof(ErlTimer));
-#endif
- erts_port_task_handle_init(&prt->timeout_task);
- prt->suspended = NULL;
- sys_strcpy(prt->name, name);
- prt->nlinks = NULL;
- prt->monitors = NULL;
- prt->linebuf = NULL;
- prt->bp = NULL;
- prt->data = am_undefined;
- /* Set default tracing */
- erts_get_default_tracing(&(prt->trace_flags), &(prt->tracer_proc));
-
- prt->psd = NULL;
-
- initq(prt);
-}
-
-void
-erts_wake_process_later(Port *prt, Process *process)
+int
+erts_save_suspend_process_on_port(Port *prt, Process *process)
{
- ErtsProcList** p;
- ErtsProcList* new_p;
-
- ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
-
- if (prt->status & ERTS_PORT_SFLGS_DEAD)
- return;
-
- for (p = &(prt->suspended); *p != NULL; p = &((*p)->next))
- /* Empty loop body */;
-
- new_p = erts_proclist_create(process);
- new_p->next = NULL;
- *p = new_p;
+ int saved;
+ erts_aint32_t flags;
+ erts_port_task_sched_lock(&prt->sched);
+ flags = erts_smp_atomic32_read_nob(&prt->sched.flags);
+ saved = (flags & ERTS_PTS_FLGS_BUSY) && !(flags & ERTS_PTS_FLG_EXIT);
+ if (saved)
+ erts_proclist_store_last(&prt->suspended, erts_proclist_create(process));
+ erts_port_task_sched_unlock(&prt->sched);
+ return saved;
}
/*
@@ -513,47 +544,44 @@ erts_wake_process_later(Port *prt, Process *process)
(*error_number_ptr must contain either BADARG or SYSTEM_LIMIT).
The driver start function must obey the same conventions.
*/
-int
+Port *
erts_open_driver(erts_driver_t* driver, /* Pointer to driver. */
Eterm pid, /* Current process. */
char* name, /* Driver name. */
SysDriverOpts* opts, /* Options. */
- int *error_number_ptr) /* errno in case -2 is returned */
+ int *error_type_ptr, /* error type */
+ int *error_number_ptr) /* errno in case of error type -2 */
{
- int port_num;
- int port_ix;
+
+#undef ERTS_OPEN_DRIVER_RET
+#define ERTS_OPEN_DRIVER_RET(Prt, EType, ENo) \
+ do { \
+ if (error_type_ptr) \
+ *error_type_ptr = (EType); \
+ if (error_number_ptr) \
+ *error_number_ptr = (ENo); \
+ return (Prt); \
+ } while (0)
+
ErlDrvData drv_data = 0;
- Uint32 xstatus = 0;
Port *port;
int fpe_was_unmasked;
-
- if (error_number_ptr)
- *error_number_ptr = 0;
+ int error_type, error_number;
+ int port_errno = 0;
+ erts_mtx_t *driver_lock = NULL;
+ int cprt_flgs = 0;
ERTS_SMP_CHK_NO_PROC_LOCKS;
- if ((port_num = get_free_port()) < 0) {
- if (error_number_ptr) {
- *error_number_ptr = SYSTEM_LIMIT;
- }
- return -3;
- }
-
- port_ix = port_num & erts_port_tab_index_mask;
- port = &erts_port[port_ix];
- port->id = make_internal_port(port_num);
-
- erts_smp_mtx_lock(&erts_driver_list_lock);
+ erts_smp_rwmtx_rlock(&erts_driver_list_lock);
if (!driver) {
for (driver = driver_list; driver; driver = driver->next) {
if (sys_strcmp(driver->name, name) == 0)
break;
}
if (!driver) {
- erts_smp_mtx_unlock(&erts_driver_list_lock);
- if (error_number_ptr)
- *error_number_ptr = BADARG;
- return -3;
+ erts_smp_rwmtx_runlock(&erts_driver_list_lock);
+ ERTS_OPEN_DRIVER_RET(NULL, -3, BADARG);
}
}
if (driver == &spawn_driver) {
@@ -597,59 +625,49 @@ erts_open_driver(erts_driver_t* driver, /* Pointer to driver. */
}
if (driver == NULL || (driver != &spawn_driver && opts->exit_status)) {
- erts_smp_mtx_unlock(&erts_driver_list_lock);
- if (error_number_ptr) {
- *error_number_ptr = BADARG;
- }
- /* Need to mark the port as free again */
- erts_smp_port_state_lock(port);
- port->status = ERTS_PORT_SFLG_FREE;
- ERTS_LC_ASSERT(erts_smp_atomic_read_nob(&port->refc) == 2);
- erts_smp_atomic_set_nob(&port->refc, 0);
- erts_smp_port_state_unlock(port);
- return -3;
+ erts_smp_rwmtx_runlock(&erts_driver_list_lock);
+ ERTS_OPEN_DRIVER_RET(NULL, -3, BADARG);
}
- /*
- * We'll set up the port before calling the start function,
- * to allow message sending and setting timers in the start function.
- */
-
#ifdef ERTS_SMP
- ASSERT(!port->lock);
- port->lock = driver->lock;
- if (!port->lock) {
- port->lock = erts_alloc(ERTS_ALC_T_PORT_LOCK,
- sizeof(erts_smp_mtx_t));
- erts_smp_mtx_init_x(port->lock,
-#ifdef ERTS_ENABLE_LOCK_COUNT
- (erts_lcnt_rt_options & ERTS_LCNT_OPT_PORTLOCK) ? "port_lock" : NULL,
-#else
- "port_lock",
-#endif
- port->id);
- xstatus |= ERTS_PORT_SFLG_PORT_SPECIFIC_LOCK;
- }
+ driver_lock = driver->lock;
#endif
if (driver->handle != NULL) {
erts_ddll_increment_port_count(driver->handle);
erts_ddll_reference_driver(driver->handle);
}
- erts_smp_mtx_unlock(&erts_driver_list_lock);
+ erts_smp_rwmtx_runlock(&erts_driver_list_lock);
-#ifdef ERTS_SMP
- erts_smp_mtx_lock(port->lock);
-#endif
+ /*
+ * We'll set up the port before calling the start function,
+ * to allow message sending and setting timers in the start function.
+ */
+
+ if (opts->parallelism)
+ cprt_flgs |= ERTS_CREATE_PORT_FLAG_PARALLELISM;
- setup_port(port, pid, driver, drv_data, name, xstatus);
+ port = create_port(name, driver, driver_lock, cprt_flgs, pid, &port_errno);
+ if (!port) {
+ if (driver->handle) {
+ erts_smp_rwmtx_rlock(&erts_driver_list_lock);
+ erts_ddll_decrement_port_count(driver->handle);
+ erts_smp_rwmtx_runlock(&erts_driver_list_lock);
+ erts_ddll_dereference_driver(driver->handle);
+ }
+ if (port_errno)
+ ERTS_OPEN_DRIVER_RET(NULL, -2, port_errno);
+ else
+ ERTS_OPEN_DRIVER_RET(NULL, -3, SYSTEM_LIMIT);
+ }
if (IS_TRACED_FL(port, F_TRACE_PORTS)) {
trace_port_open(port,
pid,
am_atom_put(port->name, strlen(port->name)));
}
-
+
+ error_number = error_type = 0;
if (driver->start) {
if (IS_TRACED_FL(port, F_TRACE_SCHED_PORTS)) {
trace_sched_ports_where(port, am_in, am_start);
@@ -662,56 +680,63 @@ erts_open_driver(erts_driver_t* driver, /* Pointer to driver. */
}
#endif
fpe_was_unmasked = erts_block_fpe();
- drv_data = (*driver->start)((ErlDrvPort)(port_ix),
- name, opts);
+ drv_data = (*driver->start)((ErlDrvPort) port, name, opts);
+ if (((SWord) drv_data) == -1)
+ error_type = -1;
+ else if (((SWord) drv_data) == -2) {
+ /*
+ * We need to save errno quickly after the
+ * call to the 'start' callback before
+ * something else modify it.
+ */
+ error_type = -2;
+ error_number = errno;
+ }
+ else if (((SWord) drv_data) == -3) {
+ error_type = -3;
+ error_number = BADARG;
+ }
+
erts_unblock_fpe(fpe_was_unmasked);
port->caller = NIL;
if (IS_TRACED_FL(port, F_TRACE_SCHED_PORTS)) {
trace_sched_ports_where(port, am_out, am_start);
}
- if (error_number_ptr && ((SWord) drv_data) == (SWord) -2)
- *error_number_ptr = errno;
#ifdef ERTS_SMP
if (port->xports)
- erts_smp_xports_unlock(port);
+ erts_port_handle_xports(port);
ASSERT(!port->xports);
#endif
}
- if (((SWord)drv_data) == -1 ||
- ((SWord)drv_data) == -2 ||
- ((SWord)drv_data) == -3) {
- int res = (int) ((SWord) drv_data);
-
- if (res == -3 && error_number_ptr) {
- *error_number_ptr = BADARG;
- }
-
+ if (error_type) {
/*
* Must clean up the port.
*/
#ifdef ERTS_SMP
- erts_cancel_smp_ptimer(port->ptimer);
+ erts_cancel_smp_ptimer(port->common.u.alive.ptimer);
#else
- erts_cancel_timer(&(port->tm));
+ erts_cancel_timer(&(port->common.u.alive.tm));
#endif
stopq(port);
- kill_port(port);
if (port->linebuf != NULL) {
erts_free(ERTS_ALC_T_LINEBUF,
(void *) port->linebuf);
port->linebuf = NULL;
}
if (driver->handle != NULL) {
- erts_smp_mtx_lock(&erts_driver_list_lock);
+ erts_smp_rwmtx_rlock(&erts_driver_list_lock);
erts_ddll_decrement_port_count(driver->handle);
- erts_smp_mtx_unlock(&erts_driver_list_lock);
+ erts_smp_rwmtx_runlock(&erts_driver_list_lock);
}
+ kill_port(port);
erts_port_release(port);
- return res;
+ ERTS_OPEN_DRIVER_RET(NULL, error_type, error_number);
}
- port->drv_data = (SWord) drv_data;
- return port_ix;
+ port->drv_data = (UWord) drv_data;
+ ERTS_OPEN_DRIVER_RET(port, 0, 0);
+
+#undef ERTS_OPEN_DRIVER_RET
}
#ifdef ERTS_SMP
@@ -736,102 +761,122 @@ driver_create_port(ErlDrvPort creator_port_ix, /* Creating port */
char* name, /* Driver name */
ErlDrvData drv_data) /* Driver data */
{
+ int cprt_flgs = 0;
Port *creator_port;
Port* port;
erts_driver_t *driver;
Process *rp;
- int port_num;
- Eterm port_id;
- Uint32 xstatus = 0;
+ erts_mtx_t *driver_lock = NULL;
ERTS_SMP_CHK_NO_PROC_LOCKS;
- creator_port = erts_drvport2port(creator_port_ix);
+ /* Need to be called from a scheduler thread */
+ if (!erts_get_scheduler_id())
+ return ERTS_INVALID_ERL_DRV_PORT;
+
+ creator_port = erts_drvport2port(creator_port_ix, NULL);
if (!creator_port)
- return (ErlDrvTermData) -1;
+ return ERTS_INVALID_ERL_DRV_PORT;
+
+ rp = erts_proc_lookup(pid);
+ if (!rp)
+ return ERTS_INVALID_ERL_DRV_PORT;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(creator_port));
driver = creator_port->drv_ptr;
- erts_smp_mtx_lock(&erts_driver_list_lock);
+ erts_smp_rwmtx_rlock(&erts_driver_list_lock);
if (!erts_ddll_driver_ok(driver->handle)) {
- erts_smp_mtx_unlock(&erts_driver_list_lock);
- return (ErlDrvTermData) -1;
+ erts_smp_rwmtx_runlock(&erts_driver_list_lock);
+ return ERTS_INVALID_ERL_DRV_PORT;
}
- rp = erts_pid2proc(NULL, 0, pid, ERTS_PROC_LOCK_LINK);
- if (!rp) {
- erts_smp_mtx_unlock(&erts_driver_list_lock);
- return (ErlDrvTermData) -1; /* pid does not exist */
+ if (driver->handle != NULL) {
+ erts_ddll_increment_port_count(driver->handle);
+ erts_ddll_reference_referenced_driver(driver->handle);
+ }
+
+#ifdef ERTS_SMP
+ driver_lock = driver->lock;
+#endif
+
+ erts_smp_rwmtx_runlock(&erts_driver_list_lock);
+
+ /* Inherit parallelism flag from parent */
+ if (ERTS_PTS_FLG_PARALLELISM &
+ erts_smp_atomic32_read_nob(&creator_port->sched.flags))
+ cprt_flgs |= ERTS_CREATE_PORT_FLAG_PARALLELISM;
+ port = create_port(name, driver, driver_lock, cprt_flgs, pid, NULL);
+ if (!port) {
+ if (driver->handle) {
+ erts_smp_rwmtx_rlock(&erts_driver_list_lock);
+ erts_ddll_decrement_port_count(driver->handle);
+ erts_smp_rwmtx_runlock(&erts_driver_list_lock);
+ erts_ddll_dereference_driver(driver->handle);
+ }
+ return ERTS_INVALID_ERL_DRV_PORT;
}
- if ((port_num = get_free_port()) < 0) {
- errno = SYSTEM_LIMIT;
+ ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(port));
+
+ erts_smp_proc_lock(rp, ERTS_PROC_LOCK_LINK);
+ if (ERTS_PROC_IS_EXITING(rp)) {
erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_LINK);
- erts_smp_mtx_unlock(&erts_driver_list_lock);
- return (ErlDrvTermData) -1;
+ if (driver->handle) {
+ erts_smp_rwmtx_rlock(&erts_driver_list_lock);
+ erts_ddll_decrement_port_count(driver->handle);
+ erts_smp_rwmtx_runlock(&erts_driver_list_lock);
+ }
+ kill_port(port);
+ erts_port_release(port);
+ return ERTS_INVALID_ERL_DRV_PORT;
}
- port_id = make_internal_port(port_num);
- port = &erts_port[port_num & erts_port_tab_index_mask];
+ erts_add_link(&ERTS_P_LINKS(port), LINK_PID, pid);
+ erts_add_link(&ERTS_P_LINKS(rp), LINK_PID, port->common.id);
+ erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_LINK);
#ifdef ERTS_SMP
- ASSERT(!port->lock);
- port->lock = driver->lock;
- if (!port->lock) {
+ if (!driver_lock) {
ErtsXPortsList *xplp = xports_list_alloc();
xplp->port = port;
xplp->next = creator_port->xports;
creator_port->xports = xplp;
- port->lock = erts_alloc(ERTS_ALC_T_PORT_LOCK,
- sizeof(erts_smp_mtx_t));
- erts_smp_mtx_init_locked_x(port->lock,
-#ifdef ERTS_ENABLE_LOCK_COUNT
- (erts_lcnt_rt_options & ERTS_LCNT_OPT_PORTLOCK) ? "port_lock" : NULL,
-#else
- "port_lock",
-#endif
- port_id);
- xstatus |= ERTS_PORT_SFLG_PORT_SPECIFIC_LOCK;
}
-
#endif
- if (driver->handle != NULL) {
- erts_ddll_increment_port_count(driver->handle);
- erts_ddll_reference_referenced_driver(driver->handle);
- }
- erts_smp_mtx_unlock(&erts_driver_list_lock);
-
- ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(port));
-
- setup_port(port, pid, driver, drv_data, name, xstatus);
- port->id = port_id;
+ port->drv_data = (UWord) drv_data;
- erts_add_link(&(port->nlinks), LINK_PID, pid);
- erts_add_link(&(rp->nlinks), LINK_PID, port_id);
- erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_LINK);
- return port_num & erts_port_tab_index_mask;
+ return (ErlDrvPort) port;
}
#ifdef ERTS_SMP
-void
-erts_smp_xports_unlock(Port *prt)
+int erts_port_handle_xports(Port *prt)
{
+ int reds = 0;
ErtsXPortsList *xplp;
ASSERT(prt);
xplp = prt->xports;
ASSERT(xplp);
while (xplp) {
+ Port *rprt = xplp->port;
ErtsXPortsList *free_xplp;
- if (xplp->port->xports)
- erts_smp_xports_unlock(xplp->port);
- erts_port_release(xplp->port);
+ erts_aint32_t state;
+ if (rprt->xports)
+ reds += erts_port_handle_xports(rprt);
+ state = erts_atomic32_read_nob(&rprt->state);
+ if ((state & ERTS_PORT_SFLG_CLOSING) && erts_is_port_ioq_empty(rprt)) {
+ terminate_port(rprt);
+ reds += ERTS_PORT_REDS_TERMINATE;
+ }
+ erts_port_release(rprt);
free_xplp = xplp;
xplp = xplp->next;
xports_list_free(free_xplp);
+ reds++;
}
prt->xports = NULL;
+ return reds;
}
#endif
@@ -866,8 +911,8 @@ io_list_to_vec(Eterm obj, /* io-list */
DECLARE_ESTACK(s);
Eterm* objp;
char *buf = cbin->orig_bytes;
- ErlDrvSizeT len = cbin->orig_size;
- ErlDrvSizeT csize = 0;
+ Uint len = cbin->orig_size;
+ Uint csize = 0;
int vlen = 0;
char* cptr = buf;
@@ -982,7 +1027,7 @@ io_list_to_vec(Eterm obj, /* io-list */
#define IO_LIST_VEC_COUNT(obj) \
do { \
- ErlDrvSizeT _size = binary_size(obj); \
+ Uint _size = binary_size(obj); \
Eterm _real; \
ERTS_DECLARE_DUMMY(Uint _offset); \
int _bitoffs; \
@@ -1033,8 +1078,9 @@ do { \
*/
static int
-io_list_vec_len(Eterm obj, Uint* vsize, Uint* csize,
- Uint* pvsize, Uint* pcsize, Uint* total_size)
+io_list_vec_len(Eterm obj, int* vsize, Uint* csize,
+ Uint* pvsize, Uint* pcsize,
+ ErlDrvSizeT* total_size)
{
DECLARE_ESTACK(s);
Eterm* objp;
@@ -1045,7 +1091,7 @@ io_list_vec_len(Eterm obj, Uint* vsize, Uint* csize,
Uint p_v_size = 0;
Uint p_c_size = 0;
Uint p_in_clist = 0;
- Uint total;
+ Uint total; /* Uint due to halfword emulator */
goto L_jump_start; /* avoid a push */
@@ -1105,7 +1151,7 @@ io_list_vec_len(Eterm obj, Uint* vsize, Uint* csize,
if (total < c_size) {
goto L_overflow_error;
}
- *total_size = total;
+ *total_size = (ErlDrvSizeT) total;
DESTROY_ESTACK(s);
*vsize = v_size;
@@ -1120,56 +1166,724 @@ io_list_vec_len(Eterm obj, Uint* vsize, Uint* csize,
return 1;
}
-/* write data to a port */
-int erts_write_to_port(Eterm caller_id, Port *p, Eterm list)
-{
- char *buf;
- erts_driver_t *drv = p->drv_ptr;
- Uint size;
+typedef enum {
+ ERTS_TRY_IMM_DRV_CALL_OK,
+ ERTS_TRY_IMM_DRV_CALL_BUSY_LOCK,
+ ERTS_TRY_IMM_DRV_CALL_INVALID_PORT,
+ ERTS_TRY_IMM_DRV_CALL_INVALID_SCHED_FLAGS
+} ErtsTryImmDrvCallResult;
+
+typedef struct {
+ Process *c_p; /* Currently executing process (unlocked) */
+ Port *port; /* Port to operate on */
+ Eterm port_op; /* port operation as an atom */
+ erts_aint32_t state; /* in: invalid state; out: read state (if read) */
+ erts_aint32_t sched_flags; /* in: invalid flags; out: read flags (if read) */
+ int async; /* Asynchronous operation */
+ int pre_chk_sched_flags; /* Check sched flags before lock? */
int fpe_was_unmasked;
-
- ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(p));
+} ErtsTryImmDrvCallState;
+
+#define ERTS_INIT_TRY_IMM_DRV_CALL_STATE(C_P, PRT, SFLGS, PTS_FLGS, A, PRT_OP) \
+ {(C_P), (PRT), (PRT_OP), (SFLGS), (PTS_FLGS), (A), 1, 0}
+
+/*
+ * Try doing an immediate driver callback call from a process. If
+ * this fail, the operation should be scheduled in the normal case...
+ *
+ */
+static ERTS_INLINE ErtsTryImmDrvCallResult
+try_imm_drv_call(ErtsTryImmDrvCallState *sp)
+{
+ ErtsTryImmDrvCallResult res;
+ erts_aint32_t invalid_state, invalid_sched_flags;
+ Port *prt = sp->port;
+ Process *c_p = sp->c_p;
+
+ ASSERT(is_atom(sp->port_op));
+
+ invalid_sched_flags = ERTS_PTS_FLGS_FORCE_SCHEDULE_OP;
+ invalid_sched_flags |= sp->sched_flags;
+ if (sp->async)
+ invalid_sched_flags |= ERTS_PTS_FLG_PARALLELISM;
+
+ if (sp->pre_chk_sched_flags) {
+ sp->sched_flags = erts_smp_atomic32_read_nob(&prt->sched.flags);
+ if (sp->sched_flags & invalid_sched_flags)
+ return ERTS_TRY_IMM_DRV_CALL_INVALID_SCHED_FLAGS;
+ }
+
+ if (erts_smp_port_trylock(prt) == EBUSY)
+ return ERTS_TRY_IMM_DRV_CALL_BUSY_LOCK;
+
+ invalid_state = sp->state;
+ sp->state = erts_atomic32_read_nob(&prt->state);
+ if (sp->state & invalid_state) {
+ res = ERTS_TRY_IMM_DRV_CALL_INVALID_PORT;
+ goto locked_fail;
+ }
+
+ sp->sched_flags = erts_smp_atomic32_read_nob(&prt->sched.flags);
+ if (sp->sched_flags & invalid_sched_flags) {
+ res = ERTS_TRY_IMM_DRV_CALL_INVALID_SCHED_FLAGS;
+ goto locked_fail;
+ }
+
+ if (c_p) {
+ if (IS_TRACED_FL(c_p, F_TRACE_SCHED_PROCS))
+ trace_virtual_sched(c_p, am_out);
+ if (erts_system_profile_flags.runnable_procs
+ && erts_system_profile_flags.exclusive)
+ profile_runnable_proc(c_p, am_inactive);
+
+ erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN);
+ }
+
ERTS_SMP_CHK_NO_PROC_LOCKS;
- p->caller = caller_id;
- if (drv->outputv != NULL) {
- Uint vsize;
- Uint csize;
- Uint pvsize;
- Uint pcsize;
- ErlDrvSizeT blimit;
+ if (IS_TRACED_FL(prt, F_TRACE_SCHED_PORTS))
+ trace_sched_ports_where(prt, am_in, sp->port_op);
+ if (erts_system_profile_flags.runnable_ports
+ && !erts_port_is_scheduled(prt))
+ profile_runnable_port(prt, am_active);
+
+ sp->fpe_was_unmasked = erts_block_fpe();
+
+ return ERTS_TRY_IMM_DRV_CALL_OK;
+
+locked_fail:
+ erts_port_release(prt);
+ return res;
+}
+
+static ERTS_INLINE void
+finalize_imm_drv_call(ErtsTryImmDrvCallState *sp)
+{
+ Port *prt = sp->port;
+ Process *c_p = sp->c_p;
+
+ erts_port_driver_callback_epilogue(prt, NULL);
+
+ erts_unblock_fpe(sp->fpe_was_unmasked);
+
+ if (IS_TRACED_FL(prt, F_TRACE_SCHED_PORTS))
+ trace_sched_ports_where(prt, am_out, sp->port_op);
+ if (erts_system_profile_flags.runnable_ports
+ && !erts_port_is_scheduled(prt))
+ profile_runnable_port(prt, am_inactive);
+
+ erts_port_release(prt);
+
+ if (c_p) {
+ erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN);
+
+ if (IS_TRACED_FL(c_p, F_TRACE_SCHED_PROCS))
+ trace_virtual_sched(c_p, am_in);
+ if (erts_system_profile_flags.runnable_procs
+ && erts_system_profile_flags.exclusive)
+ profile_runnable_proc(c_p, am_active);
+ }
+}
+
+/*
+ * force_imm_drv_call()/finalize_force_imm_drv_call() should *only*
+ * be used while crash dumping...
+ */
+static ErtsTryImmDrvCallResult
+force_imm_drv_call(ErtsTryImmDrvCallState *sp)
+{
+ erts_aint32_t invalid_state;
+ Port *prt = sp->port;
+
+ ASSERT(ERTS_IS_CRASH_DUMPING)
+ ASSERT(is_atom(sp->port_op));
+
+ invalid_state = sp->state;
+ sp->state = erts_atomic32_read_nob(&prt->state);
+ if (sp->state & invalid_state)
+ return ERTS_TRY_IMM_DRV_CALL_INVALID_PORT;
+
+ sp->fpe_was_unmasked = erts_block_fpe();
+
+ return ERTS_TRY_IMM_DRV_CALL_OK;
+}
+
+static void
+finalize_force_imm_drv_call(ErtsTryImmDrvCallState *sp)
+{
+ erts_unblock_fpe(sp->fpe_was_unmasked);
+}
+
+#define ERTS_QUEUE_PORT_SCHED_OP_REPLY_SIZE (REF_THING_SIZE + 3)
+
+static ERTS_INLINE void
+queue_port_sched_op_reply(Process *rp,
+ ErtsProcLocks *rp_locksp,
+ Eterm *hp_start,
+ Eterm *hp,
+ Uint h_size,
+ ErlHeapFragment* bp,
+ Uint32 *ref_num,
+ Eterm msg)
+{
+ Eterm ref = make_internal_ref(hp);
+ write_ref_thing(hp, ref_num[0], ref_num[1], ref_num[2]);
+ hp += REF_THING_SIZE;
+
+ msg = TUPLE2(hp, ref, msg);
+ hp += 3;
+
+ if (!bp) {
+ HRelease(rp, hp_start + h_size, hp);
+ }
+ else {
+ Uint used_h_size = hp - hp_start;
+ ASSERT(h_size >= used_h_size);
+ if (h_size > used_h_size)
+ bp = erts_resize_message_buffer(bp, used_h_size, &msg, 1);
+ }
+
+ erts_queue_message(rp,
+ rp_locksp,
+ bp,
+ msg,
+ NIL
+#ifdef USE_VM_PROBES
+ , NIL
+#endif
+ );
+}
+
+static void
+port_sched_op_reply(Eterm to, Uint32 *ref_num, Eterm msg)
+{
+ Process *rp = erts_proc_lookup_raw(to);
+ if (rp) {
+ ErlOffHeap *ohp;
+ ErlHeapFragment* bp;
+ Eterm msg_copy;
+ Uint hsz, msg_sz;
+ Eterm *hp, *hp_start;
+ ErtsProcLocks rp_locks = 0;
+
+ hsz = ERTS_QUEUE_PORT_SCHED_OP_REPLY_SIZE;
+ if (is_immed(msg))
+ msg_sz = 0;
+ else {
+ msg_sz = size_object(msg);
+ hsz += msg_sz;
+ }
+
+ hp_start = hp = erts_alloc_message_heap(hsz,
+ &bp,
+ &ohp,
+ rp,
+ &rp_locks);
+ if (is_immed(msg))
+ msg_copy = msg;
+ else
+ msg_copy = copy_struct(msg, msg_sz, &hp, ohp);
+
+ queue_port_sched_op_reply(rp,
+ &rp_locks,
+ hp_start,
+ hp,
+ hsz,
+ bp,
+ ref_num,
+ msg_copy);
+
+ if (rp_locks)
+ erts_smp_proc_unlock(rp, rp_locks);
+ }
+}
+
+
+ErtsPortOpResult
+erts_schedule_proc2port_signal(Process *c_p,
+ Port *prt,
+ Eterm caller,
+ Eterm *refp,
+ ErtsProc2PortSigData *sigdp,
+ int task_flags,
+ ErtsProc2PortSigCallback callback)
+{
+ int sched_res;
+ if (!refp) {
+ if (c_p)
+ erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN);
+ }
+ else {
+ ASSERT(c_p);
+ sigdp->flags |= ERTS_P2P_SIG_DATA_FLG_REPLY;
+ erts_make_ref_in_array(sigdp->ref);
+ *refp = erts_proc_store_ref(c_p, sigdp->ref);
+
+ /*
+ * Caller needs to wait for a message containing
+ * the ref that we just created. No such message
+ * can exist in callers message queue at this time.
+ * We therefore move the save pointer of the
+ * callers message queue to the end of the queue.
+ *
+ * NOTE: It is of vital importance that the caller
+ * immediately do a receive unconditionaly
+ * waiting for the message with the reference;
+ * otherwise, next receive will *not* work
+ * as expected!
+ */
+ erts_smp_proc_lock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE);
+
+ if (ERTS_PROC_PENDING_EXIT(c_p)) {
+ /* need to exit caller instead */
+ erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE);
+ KILL_CATCHES(c_p);
+ c_p->freason = EXC_EXIT;
+ return ERTS_PORT_OP_CALLER_EXIT;
+ }
+
+ ERTS_SMP_MSGQ_MV_INQ2PRIVQ(c_p);
+ c_p->msg.save = c_p->msg.last;
+
+ erts_smp_proc_unlock(c_p,
+ (ERTS_PROC_LOCK_MAIN
+ | ERTS_PROC_LOCKS_MSG_RECEIVE));
+ }
+
+
+ sigdp->caller = caller;
+
+ /* Schedule port close call for later execution... */
+ sched_res = erts_port_task_schedule(prt->common.id,
+ NULL,
+ ERTS_PORT_TASK_PROC_SIG,
+ sigdp,
+ callback,
+ task_flags);
+
+ if (c_p)
+ erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN);
+
+ if (sched_res != 0) {
+ if (refp)
+ *refp = NIL;
+ return ERTS_PORT_OP_DROPPED;
+ }
+ return ERTS_PORT_OP_SCHEDULED;
+}
+
+static ERTS_INLINE void
+send_badsig(Port *prt)
+{
+ ErtsProcLocks rp_locks = ERTS_PROC_LOCKS_XSIG_SEND;
+ Process* rp;
+ Eterm connected = ERTS_PORT_GET_CONNECTED(prt);
+
+ ERTS_SMP_CHK_NO_PROC_LOCKS;
+ ERTS_LC_ASSERT(erts_get_scheduler_id());
+
+ ASSERT(is_internal_pid(connected));
+
+ rp = erts_proc_lookup_raw(connected);
+ if (rp) {
+ erts_smp_proc_lock(rp, rp_locks);
+ if (!ERTS_PROC_IS_EXITING(rp))
+ (void) erts_send_exit_signal(NULL,
+ prt->common.id,
+ rp,
+ &rp_locks,
+ am_badsig,
+ NIL,
+ NULL,
+ 0);
+ if (rp_locks)
+ erts_smp_proc_unlock(rp, rp_locks);
+ }
+}
+
+static void
+badsig_received(int bang_op,
+ Port *prt,
+ erts_aint32_t state,
+ int bad_output_value)
+{
+ /*
+ * if (bang_op)
+ * we are part of a "Prt ! Something" operation
+ * else
+ * we are part of a call to a port BIF
+ * behave accordingly...
+ */
+ if (!(state & ERTS_PORT_SFLGS_INVALID_LOOKUP)) {
+ if (bad_output_value) {
+ erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
+ erts_dsprintf(dsbufp, "Bad value on output port '%s'\n", prt->name);
+ erts_send_error_to_logger_nogl(dsbufp);
+ }
+ if (bang_op)
+ send_badsig(prt);
+ }
+}
+
+static int
+port_badsig(Port *prt, erts_aint32_t state, int op, ErtsProc2PortSigData *sigdp)
+{
+ if (op == ERTS_PROC2PORT_SIG_EXEC)
+ badsig_received(sigdp->flags & ERTS_P2P_SIG_DATA_FLG_BANG_OP,
+ prt,
+ state,
+ sigdp->flags & ERTS_P2P_SIG_DATA_FLG_BAD_OUTPUT);
+ if (sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY)
+ port_sched_op_reply(sigdp->caller, sigdp->ref, am_badarg);
+ return ERTS_PORT_REDS_BADSIG;
+}
+
+
+/*
+ * bad_port_signal() will
+ * - preserve signal order of signals.
+ * - send a 'badsig' exit signal to connected process if 'from' is an
+ * internal pid and the port is alive when the bad signal reaches
+ * it.
+ */
+static ErtsPortOpResult
+bad_port_signal(Process *c_p,
+ int flags,
+ Port *prt,
+ Eterm from,
+ Eterm *refp,
+ Eterm port_op)
+{
+ ErtsProc2PortSigData *sigdp;
+ ErtsTryImmDrvCallResult try_call_res;
+ ErtsTryImmDrvCallState try_call_state
+ = ERTS_INIT_TRY_IMM_DRV_CALL_STATE(
+ c_p,
+ prt,
+ ERTS_PORT_SFLGS_INVALID_LOOKUP,
+ 0,
+ !refp,
+ port_op);
+
+ try_call_res = try_imm_drv_call(&try_call_state);
+ switch (try_call_res) {
+ case ERTS_TRY_IMM_DRV_CALL_OK:
+ badsig_received(flags & ERTS_PORT_SIG_FLG_BANG_OP,
+ prt,
+ try_call_state.state,
+ flags & ERTS_PORT_SIG_FLG_BAD_OUTPUT);
+ finalize_imm_drv_call(&try_call_state);
+ return ERTS_PORT_OP_BADARG;
+ case ERTS_TRY_IMM_DRV_CALL_INVALID_PORT:
+ return ERTS_PORT_OP_DROPPED;
+ case ERTS_TRY_IMM_DRV_CALL_INVALID_SCHED_FLAGS:
+ case ERTS_TRY_IMM_DRV_CALL_BUSY_LOCK:
+ /* Schedule badsig() call instead... */
+ break;
+ }
+
+ sigdp = erts_port_task_alloc_p2p_sig_data();
+ sigdp->flags = (flags & ~ERTS_P2P_SIG_TYPE_MASK) | ERTS_P2P_SIG_TYPE_BAD;
+
+ return erts_schedule_proc2port_signal(c_p,
+ prt,
+ c_p->common.id,
+ refp,
+ sigdp,
+ 0,
+ port_badsig);
+}
+
+
+/*
+ * Driver outputv() callback
+ */
+
+static ERTS_INLINE void
+call_driver_outputv(int bang_op,
+ Eterm caller,
+ Eterm from,
+ Port *prt,
+ erts_driver_t *drv,
+ ErlIOVec *evp)
+{
+ /*
+ * if (bang_op)
+ * we are part of a "Prt ! {From, {command, Data}}" operation
+ * else
+ * we are part of a call to port_command/[2,3]
+ * behave accordingly...
+ */
+ if (bang_op && from != ERTS_PORT_GET_CONNECTED(prt))
+ send_badsig(prt);
+ else {
+ ErlDrvSizeT size = evp->size;
+
+ ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)
+ || ERTS_IS_CRASH_DUMPING);
+
+#ifdef USE_VM_PROBES
+ if (DTRACE_ENABLED(driver_outputv)) {
+ DTRACE_FORMAT_COMMON_PID_AND_PORT(caller, prt);
+ DTRACE4(driver_outputv, process_str, port_str, prt->name, size);
+ }
+#endif
+
+ prt->caller = caller;
+ (*drv->outputv)((ErlDrvData) prt->drv_data, evp);
+ prt->caller = NIL;
+
+ prt->bytes_out += size;
+ erts_smp_atomic_add_nob(&erts_bytes_out, size);
+ }
+}
+
+static ERTS_INLINE void
+cleanup_scheduled_outputv(ErlIOVec *ev, ErlDrvBinary *cbinp)
+{
+ int i;
+ /* Need to free all binaries */
+ for (i = 1; i < ev->vsize; i++)
+ if (ev->binv[i])
+ driver_free_binary(ev->binv[i]);
+ if (cbinp)
+ driver_free_binary(cbinp);
+ erts_free(ERTS_ALC_T_DRV_CMD_DATA, ev);
+}
+
+static int
+port_sig_outputv(Port *prt, erts_aint32_t state, int op, ErtsProc2PortSigData *sigdp)
+{
+ Eterm reply;
+
+ switch (op) {
+ case ERTS_PROC2PORT_SIG_EXEC:
+ /* Execution of a scheduled outputv() call */
+
+ ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
+
+ if (state & ERTS_PORT_SFLGS_INVALID_LOOKUP)
+ reply = am_badarg;
+ else {
+ call_driver_outputv(sigdp->flags & ERTS_P2P_SIG_DATA_FLG_BANG_OP,
+ sigdp->caller,
+ sigdp->u.outputv.from,
+ prt,
+ prt->drv_ptr,
+ sigdp->u.outputv.evp);
+ reply = am_true;
+ }
+ break;
+ case ERTS_PROC2PORT_SIG_ABORT_NOSUSPEND:
+ reply = am_false;
+ break;
+ default:
+ reply = am_badarg;
+ break;
+ }
+
+ if (sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY)
+ port_sched_op_reply(sigdp->caller, sigdp->ref, reply);
+
+ cleanup_scheduled_outputv(sigdp->u.outputv.evp,
+ sigdp->u.outputv.cbinp);
+
+ return ERTS_PORT_REDS_CMD_OUTPUTV;
+}
+
+/*
+ * Driver output() callback
+ */
+
+static ERTS_INLINE void
+call_driver_output(int bang_op,
+ Eterm caller,
+ Eterm from,
+ Port *prt,
+ erts_driver_t *drv,
+ char *bufp,
+ ErlDrvSizeT size)
+{
+ /*
+ * if (bang_op)
+ * we are part of a "Prt ! {From, {command, Data}}" operation
+ * else
+ * we are part of a call to port_command/[2,3]
+ * behave accordingly...
+ */
+ if (bang_op && from != ERTS_PORT_GET_CONNECTED(prt))
+ send_badsig(prt);
+ else {
+
+ ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)
+ || ERTS_IS_CRASH_DUMPING);
+
+#ifdef USE_VM_PROBES
+ if (DTRACE_ENABLED(driver_output)) {
+ DTRACE_FORMAT_COMMON_PID_AND_PORT(caller, prt);
+ DTRACE4(driver_output, process_str, port_str, prt->name, size);
+ }
+#endif
+
+ prt->caller = caller;
+ (*drv->output)((ErlDrvData) prt->drv_data, bufp, size);
+ prt->caller = NIL;
+
+ prt->bytes_out += size;
+ erts_smp_atomic_add_nob(&erts_bytes_out, size);
+ }
+}
+
+static ERTS_INLINE void
+cleanup_scheduled_output(char *bufp)
+{
+ erts_free(ERTS_ALC_T_DRV_CMD_DATA, bufp);
+}
+
+static int
+port_sig_output(Port *prt, erts_aint32_t state, int op, ErtsProc2PortSigData *sigdp)
+{
+ Eterm reply;
+
+ switch (op) {
+ case ERTS_PROC2PORT_SIG_EXEC:
+ /* Execution of a scheduled output() call */
+
+ ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
+
+ if (state & ERTS_PORT_SFLGS_INVALID_LOOKUP)
+ reply = am_badarg;
+ else {
+ call_driver_output(sigdp->flags & ERTS_P2P_SIG_DATA_FLG_BANG_OP,
+ sigdp->caller,
+ sigdp->u.output.from,
+ prt,
+ prt->drv_ptr,
+ sigdp->u.output.bufp,
+ sigdp->u.output.size);
+ reply = am_true;
+ }
+ break;
+ case ERTS_PROC2PORT_SIG_ABORT_NOSUSPEND:
+ reply = am_false;
+ break;
+ default:
+ reply = am_badarg;
+ break;
+ }
+
+ if (sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY)
+ port_sched_op_reply(sigdp->caller, sigdp->ref, reply);
+
+ cleanup_scheduled_output(sigdp->u.output.bufp);
+
+ return ERTS_PORT_REDS_CMD_OUTPUT;
+}
+
+ErtsPortOpResult
+erts_port_output(Process *c_p,
+ int flags,
+ Port *prt,
+ Eterm from,
+ Eterm list,
+ Eterm *refp)
+{
+ ErtsPortOpResult res;
+ ErtsProc2PortSigData *sigdp;
+ erts_driver_t *drv = prt->drv_ptr;
+ size_t size;
+ int try_call;
+ erts_aint32_t sched_flags, busy_flgs, invalid_flags;
+ int task_flags;
+ ErtsProc2PortSigCallback port_sig_callback;
+ ErlDrvBinary *cbin = NULL;
+ ErlIOVec *evp = NULL;
+ char *buf = NULL;
+ int force_immediate_call = (flags & ERTS_PORT_SIG_FLG_FORCE_IMM_CALL);
+
+ ASSERT((flags & ~(ERTS_PORT_SIG_FLG_BANG_OP
+ | ERTS_PORT_SIG_FLG_NOSUSPEND
+ | ERTS_PORT_SIG_FLG_FORCE
+ | ERTS_PORT_SIG_FLG_FORCE_IMM_CALL)) == 0);
+
+ busy_flgs = ((flags & ERTS_PORT_SIG_FLG_FORCE)
+ ? ((erts_aint32_t) 0)
+ : ERTS_PTS_FLGS_BUSY);
+ invalid_flags = busy_flgs;
+ if (!refp)
+ invalid_flags |= ERTS_PTS_FLG_PARALLELISM;
+
+ /*
+ * Assumes caller have checked that port is valid...
+ */
+
+ sched_flags = erts_smp_atomic32_read_nob(&prt->sched.flags);
+ if (sched_flags & (busy_flgs|ERTS_PTS_FLG_EXIT))
+ return ((sched_flags & ERTS_PTS_FLG_EXIT)
+ ? ERTS_PORT_OP_DROPPED
+ : ERTS_PORT_OP_BUSY);
+
+ try_call = (force_immediate_call /* crash dumping */
+ || !(sched_flags & (invalid_flags
+ | ERTS_PTS_FLGS_FORCE_SCHEDULE_OP)));
+
+#ifdef USE_VM_PROBES
+ if(DTRACE_ENABLED(port_command)) {
+ DTRACE_FORMAT_COMMON_PID_AND_PORT(c_p ? c_p->common.id : ERTS_INVALID_PID, prt);
+ DTRACE4(port_command, process_str, port_str, prt->name, "command");
+ }
+#endif
+
+ if (drv->outputv) {
+ ErlIOVec ev;
SysIOVec iv[SMALL_WRITE_VEC];
ErlDrvBinary* bv[SMALL_WRITE_VEC];
SysIOVec* ivp;
ErlDrvBinary** bvp;
- ErlDrvBinary* cbin;
- ErlIOVec ev;
+ int vsize;
+ Uint csize;
+ Uint pvsize;
+ Uint pcsize;
+ Uint blimit;
+ size_t iov_offset, binv_offset, alloc_size;
- if (io_list_vec_len(list, &vsize, &csize,
- &pvsize, &pcsize, &size)) {
+ if (io_list_vec_len(list, &vsize, &csize, &pvsize, &pcsize, &size))
goto bad_value;
+
+ iov_offset = ERTS_ALC_DATA_ALIGN_SIZE(sizeof(ErlIOVec));
+ binv_offset = iov_offset;
+ binv_offset += ERTS_ALC_DATA_ALIGN_SIZE((vsize+1)*sizeof(SysIOVec));
+ alloc_size = binv_offset;
+ alloc_size += (vsize+1)*sizeof(ErlDrvBinary *);
+
+ if (try_call && vsize < SMALL_WRITE_VEC) {
+ ivp = ev.iov = iv;
+ bvp = ev.binv = bv;
+ evp = &ev;
+ }
+ else {
+ char *ptr = erts_alloc((try_call
+ ? ERTS_ALC_T_TMP
+ : ERTS_ALC_T_DRV_CMD_DATA), alloc_size);
+
+ evp = (ErlIOVec *) ptr;
+ ivp = evp->iov = (SysIOVec *) (ptr + iov_offset);
+ bvp = evp->binv = (ErlDrvBinary **) (ptr + binv_offset);
}
+
/* To pack or not to pack (small binaries) ...? */
- vsize++;
- if (vsize <= SMALL_WRITE_VEC) {
+ if (vsize < SMALL_WRITE_VEC) {
/* Do NOT pack */
blimit = 0;
- } else {
+ }
+ else {
/* Do pack */
vsize = pvsize + 1;
csize = pcsize;
blimit = ERL_SMALL_IO_BIN_LIMIT;
}
/* Use vsize and csize from now on */
- if (vsize <= SMALL_WRITE_VEC) {
- ivp = iv;
- bvp = bv;
- } else {
- ivp = (SysIOVec *) erts_alloc(ERTS_ALC_T_TMP,
- vsize * sizeof(SysIOVec));
- bvp = (ErlDrvBinary**) erts_alloc(ERTS_ALC_T_TMP,
- vsize * sizeof(ErlDrvBinary*));
- }
+
cbin = driver_alloc_binary(csize);
if (!cbin)
erts_alloc_enomem(ERTS_ALC_T_DRV_BINARY, ERTS_SIZEOF_Binary(csize));
@@ -1178,210 +1892,761 @@ int erts_write_to_port(Eterm caller_id, Port *p, Eterm list)
ivp[0].iov_base = NULL;
ivp[0].iov_len = 0;
bvp[0] = NULL;
- ev.vsize = io_list_to_vec(list, ivp+1, bvp+1, cbin, blimit);
- if (ev.vsize < 0) {
- if (ivp != iv) {
- erts_free(ERTS_ALC_T_TMP, (void *) ivp);
- }
- if (bvp != bv) {
- erts_free(ERTS_ALC_T_TMP, (void *) bvp);
- }
+ evp->vsize = io_list_to_vec(list, ivp+1, bvp+1, cbin, blimit);
+ if (evp->vsize < 0) {
+ if (evp != &ev)
+ erts_free(try_call ? ERTS_ALC_T_TMP : ERTS_ALC_T_DRV_CMD_DATA,
+ evp);
driver_free_binary(cbin);
goto bad_value;
}
- ev.vsize++;
#if 0
/* This assertion may say something useful, but it can
be falsified during the emulator test suites. */
- ASSERT(ev.vsize == vsize);
-#endif
- ev.size = size; /* total size */
- ev.iov = ivp;
- ev.binv = bvp;
-#ifdef USE_VM_PROBES
- if (DTRACE_ENABLED(driver_outputv)) {
- DTRACE_FORMAT_COMMON_PID_AND_PORT(caller_id, p)
- DTRACE4(driver_outputv, process_str, port_str, p->name, size);
- }
+ ASSERT(evp->vsize == vsize);
#endif
- fpe_was_unmasked = erts_block_fpe();
- (*drv->outputv)((ErlDrvData)p->drv_data, &ev);
- erts_unblock_fpe(fpe_was_unmasked);
- if (ivp != iv) {
- erts_free(ERTS_ALC_T_TMP, (void *) ivp);
+ evp->vsize++;
+ evp->size = size; /* total size */
+
+ if (!try_call) {
+ int i;
+ /* Need to increase refc on all binaries */
+ for (i = 1; i < evp->vsize; i++)
+ if (bvp[i])
+ driver_binary_inc_refc(bvp[i]);
}
- if (bvp != bv) {
- erts_free(ERTS_ALC_T_TMP, (void *) bvp);
- }
- driver_free_binary(cbin);
- } else {
- int r;
-
- /* Try with an 8KB buffer first (will often be enough I guess). */
- size = 8*1024;
- /* See below why the extra byte is added. */
- buf = erts_alloc(ERTS_ALC_T_TMP, size+1);
- r = io_list_to_buf(list, buf, size);
+ else {
+ int i;
+ ErlIOVec *new_evp;
+ ErtsTryImmDrvCallResult try_call_res;
+ ErtsTryImmDrvCallState try_call_state
+ = ERTS_INIT_TRY_IMM_DRV_CALL_STATE(
+ c_p,
+ prt,
+ ERTS_PORT_SFLGS_INVALID_LOOKUP,
+ invalid_flags,
+ !refp,
+ am_command);
+
+ try_call_state.pre_chk_sched_flags = 0; /* already checked */
+ if (force_immediate_call)
+ try_call_res = force_imm_drv_call(&try_call_state);
+ else
+ try_call_res = try_imm_drv_call(&try_call_state);
+ switch (try_call_res) {
+ case ERTS_TRY_IMM_DRV_CALL_OK:
+ call_driver_outputv(flags & ERTS_PORT_SIG_FLG_BANG_OP,
+ c_p ? c_p->common.id : ERTS_INVALID_PID,
+ from,
+ prt,
+ drv,
+ evp);
+ if (force_immediate_call)
+ finalize_force_imm_drv_call(&try_call_state);
+ else
+ finalize_imm_drv_call(&try_call_state);
+ /* Fall through... */
+ case ERTS_TRY_IMM_DRV_CALL_INVALID_PORT:
+ driver_free_binary(cbin);
+ if (evp != &ev)
+ erts_free(ERTS_ALC_T_TMP, evp);
+ if (try_call_res == ERTS_TRY_IMM_DRV_CALL_OK)
+ return ERTS_PORT_OP_DONE;
+ else
+ return ERTS_PORT_OP_DROPPED;
+ case ERTS_TRY_IMM_DRV_CALL_INVALID_SCHED_FLAGS:
+ sched_flags = try_call_state.sched_flags;
+ case ERTS_TRY_IMM_DRV_CALL_BUSY_LOCK:
+ /* Schedule outputv() call instead... */
+ break;
+ }
-#ifdef USE_VM_PROBES
- if(DTRACE_ENABLED(port_command)) {
- DTRACE_FORMAT_COMMON_PID_AND_PORT(caller_id, p)
- DTRACE4(port_command, process_str, port_str, p->name, "command");
- }
+ /* Need to increase refc on all binaries */
+ for (i = 1; i < evp->vsize; i++)
+ if (bvp[i])
+ driver_binary_inc_refc(bvp[i]);
+
+ new_evp = erts_alloc(ERTS_ALC_T_DRV_CMD_DATA, alloc_size);
+
+ if (evp != &ev) {
+ sys_memcpy((void *) new_evp, (void *) evp, alloc_size);
+ new_evp->iov = (SysIOVec *) (((char *) new_evp)
+ + iov_offset);
+ bvp = new_evp->binv = (ErlDrvBinary **) (((char *) new_evp)
+ + binv_offset);
+
+#ifdef DEBUG
+ ASSERT(new_evp->vsize == evp->vsize);
+ ASSERT(new_evp->size == evp->size);
+ for (i = 0; i < evp->vsize; i++) {
+ ASSERT(new_evp->iov[i].iov_len == evp->iov[i].iov_len);
+ ASSERT(new_evp->iov[i].iov_base == evp->iov[i].iov_base);
+ ASSERT(new_evp->binv[i] == evp->binv[i]);
+ }
#endif
- if (r >= 0) {
- size -= r;
-#ifdef USE_VM_PROBES
- if (DTRACE_ENABLED(driver_output)) {
- DTRACE_FORMAT_COMMON_PID_AND_PORT(caller_id, p)
- DTRACE4(driver_output, process_str, port_str, p->name, size);
- }
+ erts_free(ERTS_ALC_T_TMP, evp);
+ }
+ else { /* from stack allocated structure; offsets may differ */
+
+ sys_memcpy((void *) new_evp, (void *) evp, sizeof(ErlIOVec));
+ new_evp->iov = (SysIOVec *) (((char *) new_evp)
+ + iov_offset);
+ sys_memcpy((void *) new_evp->iov,
+ (void *) evp->iov,
+ evp->vsize * sizeof(SysIOVec));
+ new_evp->binv = (ErlDrvBinary **) (((char *) new_evp)
+ + binv_offset);
+ sys_memcpy((void *) new_evp->binv,
+ (void *) evp->binv,
+ evp->vsize * sizeof(ErlDrvBinary *));
+
+#ifdef DEBUG
+ ASSERT(new_evp->vsize == evp->vsize);
+ ASSERT(new_evp->size == evp->size);
+ for (i = 0; i < evp->vsize; i++) {
+ ASSERT(new_evp->iov[i].iov_len == evp->iov[i].iov_len);
+ ASSERT(new_evp->iov[i].iov_base == evp->iov[i].iov_base);
+ ASSERT(new_evp->binv[i] == evp->binv[i]);
+ }
#endif
- fpe_was_unmasked = erts_block_fpe();
- (*drv->output)((ErlDrvData)p->drv_data, buf, size);
- erts_unblock_fpe(fpe_was_unmasked);
- erts_free(ERTS_ALC_T_TMP, buf);
+
+ }
+
+ evp = new_evp;
}
- else if (r == -2) {
- erts_free(ERTS_ALC_T_TMP, buf);
- goto bad_value;
+
+ sigdp = erts_port_task_alloc_p2p_sig_data();
+ sigdp->flags = ERTS_P2P_SIG_TYPE_OUTPUTV;
+ sigdp->u.outputv.from = from;
+ sigdp->u.outputv.evp = evp;
+ sigdp->u.outputv.cbinp = cbin;
+ port_sig_callback = port_sig_outputv;
+ }
+ else {
+ ErlDrvSizeT r;
+
+ /*
+ * Apperently there exist code that write 1 byte to
+ * much in buffer. Where it resides I don't know, but
+ * we can live with one byte extra allocated...
+ */
+
+ if (!try_call) {
+ if (erts_iolist_size(list, &size))
+ goto bad_value;
+
+ buf = erts_alloc(ERTS_ALC_T_DRV_CMD_DATA, size + 1);
+
+ r = erts_iolist_to_buf(list, buf, size);
+ ASSERT(ERTS_IOLIST_TO_BUF_SUCCEEDED(r));
}
else {
- ASSERT(r == -1); /* Overflow */
- erts_free(ERTS_ALC_T_TMP, buf);
- if (erts_iolist_size(list, &size)) {
- goto bad_value;
+ char *new_buf;
+ ErtsTryImmDrvCallResult try_call_res;
+ ErtsTryImmDrvCallState try_call_state
+ = ERTS_INIT_TRY_IMM_DRV_CALL_STATE(
+ c_p,
+ prt,
+ ERTS_PORT_SFLGS_INVALID_LOOKUP,
+ invalid_flags,
+ !refp,
+ am_command);
+
+ /* Try with an 8KB buffer first (will often be enough I guess). */
+ size = 8*1024;
+
+ buf = erts_alloc(ERTS_ALC_T_TMP, size + 1);
+ r = erts_iolist_to_buf(list, buf, size);
+
+ if (ERTS_IOLIST_TO_BUF_SUCCEEDED(r)) {
+ ASSERT(r <= size);
+ size -= r;
+ }
+ else {
+ erts_free(ERTS_ALC_T_TMP, buf);
+ if (r == ERTS_IOLIST_TO_BUF_TYPE_ERROR)
+ goto bad_value;
+ ASSERT(r == ERTS_IOLIST_TO_BUF_OVERFLOW);
+ if (erts_iolist_size(list, &size))
+ goto bad_value;
+ buf = erts_alloc(ERTS_ALC_T_TMP, size + 1);
+ r = erts_iolist_to_buf(list, buf, size);
+ ASSERT(ERTS_IOLIST_TO_BUF_SUCCEEDED(r));
}
- /*
- * I know drivers that pad space with '\0' this is clearly
- * incorrect but I don't feel like fixing them now, insted
- * add ONE extra byte.
- */
- buf = erts_alloc(ERTS_ALC_T_TMP, size+1);
- r = io_list_to_buf(list, buf, size);
-#ifdef USE_VM_PROBES
- if (DTRACE_ENABLED(driver_output)) {
- DTRACE_FORMAT_COMMON_PID_AND_PORT(caller_id, p)
- DTRACE4(driver_output, process_str, port_str, p->name, size);
- }
-#endif
- fpe_was_unmasked = erts_block_fpe();
- (*drv->output)((ErlDrvData)p->drv_data, buf, size);
- erts_unblock_fpe(fpe_was_unmasked);
+ try_call_state.pre_chk_sched_flags = 0; /* already checked */
+ if (force_immediate_call)
+ try_call_res = force_imm_drv_call(&try_call_state);
+ else
+ try_call_res = try_imm_drv_call(&try_call_state);
+ switch (try_call_res) {
+ case ERTS_TRY_IMM_DRV_CALL_OK:
+ call_driver_output(flags & ERTS_PORT_SIG_FLG_BANG_OP,
+ c_p ? c_p->common.id : ERTS_INVALID_PID,
+ from,
+ prt,
+ drv,
+ buf,
+ size);
+ if (force_immediate_call)
+ finalize_force_imm_drv_call(&try_call_state);
+ else
+ finalize_imm_drv_call(&try_call_state);
+ /* Fall through... */
+ case ERTS_TRY_IMM_DRV_CALL_INVALID_PORT:
+ erts_free(ERTS_ALC_T_TMP, buf);
+ if (try_call_res == ERTS_TRY_IMM_DRV_CALL_OK)
+ return ERTS_PORT_OP_DONE;
+ else
+ return ERTS_PORT_OP_DROPPED;
+ case ERTS_TRY_IMM_DRV_CALL_INVALID_SCHED_FLAGS:
+ sched_flags = try_call_state.sched_flags;
+ case ERTS_TRY_IMM_DRV_CALL_BUSY_LOCK:
+ /* Schedule outputv() call instead... */
+ break;
+ }
+
+ new_buf = erts_alloc(ERTS_ALC_T_DRV_CMD_DATA, size + 1);
+ sys_memcpy(new_buf, buf, size);
erts_free(ERTS_ALC_T_TMP, buf);
+ buf = new_buf;
}
+
+ sigdp = erts_port_task_alloc_p2p_sig_data();
+ sigdp->flags = ERTS_P2P_SIG_TYPE_OUTPUT;
+ sigdp->u.output.from = from;
+ sigdp->u.output.bufp = buf;
+ sigdp->u.output.size = size;
+ port_sig_callback = port_sig_output;
+ }
+
+ task_flags = ERTS_PT_FLG_WAIT_BUSY;
+ sigdp->flags |= flags;
+ if (flags & (ERTS_P2P_SIG_DATA_FLG_FORCE|ERTS_P2P_SIG_DATA_FLG_NOSUSPEND)) {
+ task_flags = 0;
+ if (flags & ERTS_P2P_SIG_DATA_FLG_FORCE)
+ sigdp->flags &= ~ERTS_P2P_SIG_DATA_FLG_NOSUSPEND;
+ else if (flags & ERTS_P2P_SIG_DATA_FLG_NOSUSPEND)
+ task_flags = ERTS_PT_FLG_NOSUSPEND;
+ }
+
+ res = erts_schedule_proc2port_signal(c_p,
+ prt,
+ c_p ? c_p->common.id : ERTS_INVALID_PID,
+ refp,
+ sigdp,
+ task_flags,
+ port_sig_callback);
+
+ if (res != ERTS_PORT_OP_SCHEDULED) {
+ if (drv->outputv)
+ cleanup_scheduled_outputv(evp, cbin);
+ else
+ cleanup_scheduled_output(buf);
+ return res;
}
- p->bytes_out += size;
- erts_smp_atomic_add_nob(&erts_bytes_out, size);
-#ifdef ERTS_SMP
- if (p->xports)
- erts_smp_xports_unlock(p);
- ASSERT(!p->xports);
+ if (!(sched_flags & ERTS_PTS_FLG_EXIT) && (sched_flags & busy_flgs))
+ return ERTS_PORT_OP_BUSY_SCHEDULED;
+
+ return res;
+
+bad_value:
+
+ flags |= ERTS_PORT_SIG_FLG_BAD_OUTPUT;
+ return bad_port_signal(c_p, flags, prt, from, refp, am_command);
+}
+
+static ERTS_INLINE ErtsPortOpResult
+call_deliver_port_exit(int bang_op,
+ Eterm from,
+ Port *prt,
+ erts_aint32_t state,
+ Eterm reason,
+ int broken_link)
+{
+ /*
+ * if (bang_op)
+ * we are part of a "Prt ! {From, close}" operation
+ * else
+ * we are part of a call to port_close(Port)
+ * behave accordingly...
+ */
+
+ if (state & ERTS_PORT_SFLGS_INVALID_LOOKUP)
+ return ERTS_PORT_OP_DROPPED;
+
+ if (bang_op && from != ERTS_PORT_GET_CONNECTED(prt)) {
+ send_badsig(prt);
+ return ERTS_PORT_OP_DROPPED;
+ }
+
+ if (broken_link) {
+ ErtsLink *lnk = erts_remove_link(&ERTS_P_LINKS(prt), from);
+ if (lnk)
+ erts_destroy_link(lnk);
+ else
+ return ERTS_PORT_OP_DROPPED;
+ }
+
+ if (!erts_deliver_port_exit(prt, from, reason, bang_op))
+ return ERTS_PORT_OP_DROPPED;
+
+#ifdef USE_VM_PROBES
+ if(DTRACE_ENABLED(port_command) && bang_op) {
+ DTRACE_FORMAT_COMMON_PID_AND_PORT(from, prt);
+ DTRACE4(port_command, process_str, port_str, prt->name, "close");
+ }
#endif
- p->caller = NIL;
- return 0;
- bad_value:
- p->caller = NIL;
- {
- erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
- erts_dsprintf(dsbufp, "Bad value on output port '%s'\n", p->name);
- erts_send_error_to_logger_nogl(dsbufp);
- return 1;
+ return ERTS_PORT_OP_DONE;
+}
+
+static int
+port_sig_exit(Port *prt,
+ erts_aint32_t state,
+ int op,
+ ErtsProc2PortSigData *sigdp)
+{
+ Eterm msg = am_badarg;
+ if (op == ERTS_PROC2PORT_SIG_EXEC) {
+ ErtsPortOpResult res;
+ int bang_op = sigdp->flags & ERTS_P2P_SIG_DATA_FLG_BANG_OP;
+ int broken_link = sigdp->flags & ERTS_P2P_SIG_DATA_FLG_BROKEN_LINK;
+ res = call_deliver_port_exit(bang_op,
+ sigdp->u.exit.from,
+ prt,
+ state,
+ sigdp->u.exit.reason,
+ broken_link);
+
+ if (res == ERTS_PORT_OP_DONE)
+ msg = am_true;
+ }
+ if (sigdp->u.exit.bp)
+ free_message_buffer(sigdp->u.exit.bp);
+ if (sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY)
+ port_sched_op_reply(sigdp->caller, sigdp->ref, msg);
+
+ return ERTS_PORT_REDS_EXIT;
+}
+
+ErtsPortOpResult
+erts_port_exit(Process *c_p,
+ int flags,
+ Port *prt,
+ Eterm from,
+ Eterm reason,
+ Eterm *refp)
+{
+ ErtsPortOpResult res;
+ ErtsProc2PortSigData *sigdp;
+ ErlHeapFragment *bp = NULL;
+
+ ASSERT((flags & ~(ERTS_PORT_SIG_FLG_BANG_OP
+ | ERTS_PORT_SIG_FLG_BROKEN_LINK
+ | ERTS_PORT_SIG_FLG_FORCE_SCHED)) == 0);
+
+ if (!(flags & ERTS_PORT_SIG_FLG_FORCE_SCHED)) {
+ ErtsTryImmDrvCallState try_call_state
+ = ERTS_INIT_TRY_IMM_DRV_CALL_STATE(c_p,
+ prt,
+ ERTS_PORT_SFLGS_INVALID_LOOKUP,
+ 0,
+ !refp,
+ am_exit);
+
+
+ switch (try_imm_drv_call(&try_call_state)) {
+ case ERTS_TRY_IMM_DRV_CALL_OK: {
+ res = call_deliver_port_exit(flags & ERTS_PORT_SIG_FLG_BANG_OP,
+ from,
+ prt,
+ try_call_state.state,
+ reason,
+ flags & ERTS_PORT_SIG_FLG_BROKEN_LINK);
+ finalize_imm_drv_call(&try_call_state);
+ return res;
+ }
+ case ERTS_TRY_IMM_DRV_CALL_INVALID_PORT:
+ return ERTS_PORT_OP_DROPPED;
+ default:
+ /* Schedule call instead... */
+ break;
+ }
}
+
+ sigdp = erts_port_task_alloc_p2p_sig_data();
+ sigdp->flags = ERTS_P2P_SIG_TYPE_EXIT | flags;
+ sigdp->u.exit.from = from;
+
+ if (is_immed(reason)) {
+ sigdp->u.exit.reason = reason;
+ sigdp->u.exit.bp = NULL;
+ }
+ else {
+ Eterm *hp;
+ Uint hsz = size_object(reason);
+ bp = new_message_buffer(hsz);
+ sigdp->u.exit.bp = bp;
+ hp = bp->mem;
+ sigdp->u.exit.reason = copy_struct(reason,
+ hsz,
+ &hp,
+ &bp->off_heap);
+ }
+
+ res = erts_schedule_proc2port_signal(c_p,
+ prt,
+ c_p ? c_p->common.id : from,
+ refp,
+ sigdp,
+ 0,
+ port_sig_exit);
+
+ if (res == ERTS_PORT_OP_DROPPED) {
+ if (bp)
+ free_message_buffer(bp);
+ }
+
+ return res;
}
-/* initialize the port array */
-void init_io(void)
+static ErtsPortOpResult
+set_port_connected(int bang_op,
+ Eterm from,
+ Port *prt,
+ erts_aint32_t state,
+ Eterm connect)
{
- int i;
- ErlDrvEntry** dp;
- char maxports[21]; /* enough for any 64-bit integer */
- size_t maxportssize = sizeof(maxports);
- Uint ports_bits = ERTS_PORTS_BITS;
- Sint port_extra_shift;
+ /*
+ * if (bang_op)
+ * we are part of a "Prt ! {From, {connect, Connect}}" operation
+ * else
+ * we are part of a call to port_connect(Port, Connect)
+ * behave accordingly...
+ */
-#ifdef ERTS_SMP
- init_xports_list_alloc();
+ if (state & ERTS_PORT_SFLGS_INVALID_LOOKUP)
+ return ERTS_PORT_OP_DROPPED;
+
+ if (bang_op) { /* Bang operation */
+ if (is_not_internal_pid(connect) || ERTS_PORT_GET_CONNECTED(prt) != from) {
+ send_badsig(prt);
+ return ERTS_PORT_OP_DROPPED;
+ }
+
+ ERTS_PORT_SET_CONNECTED(prt, connect);
+ deliver_result(prt->common.id, from, am_connected);
+
+#ifdef USE_VM_PROBES
+ if(DTRACE_ENABLED(port_command)) {
+ DTRACE_FORMAT_COMMON_PID_AND_PORT(from, prt);
+ DTRACE4(port_command, process_str, port_str, prt->name, "connect");
+ }
#endif
+ }
+ else { /* Port BIF operation */
+ Process *rp = erts_proc_lookup_raw(connect);
+ if (!rp)
+ return ERTS_PORT_OP_DROPPED;
+ erts_smp_proc_lock(rp, ERTS_PROC_LOCK_LINK);
+ if (ERTS_PROC_IS_EXITING(rp)) {
+ erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_LINK);
+ return ERTS_PORT_OP_DROPPED;
+ }
- pdl_init();
+ erts_add_link(&ERTS_P_LINKS(rp), LINK_PID, prt->common.id);
+ erts_add_link(&ERTS_P_LINKS(prt), LINK_PID, connect);
+
+ ERTS_PORT_SET_CONNECTED(prt, connect);
+
+ erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_LINK);
+
+#ifdef USE_VM_PROBES
+ if (DTRACE_ENABLED(port_connect)) {
+ DTRACE_CHARBUF(process_str, DTRACE_TERM_BUF_SIZE);
+ DTRACE_CHARBUF(port_str, DTRACE_TERM_BUF_SIZE);
+ DTRACE_CHARBUF(newprocess_str, DTRACE_TERM_BUF_SIZE);
+
+ dtrace_pid_str(connect, process_str);
+ erts_snprintf(port_str, sizeof(port_str), "%T", prt->common.id);
+ dtrace_proc_str(rp, newprocess_str);
+ DTRACE4(port_connect, process_str, port_str, prt->name, newprocess_str);
+ }
+#endif
+ }
- if (erts_sys_getenv_raw("ERL_MAX_PORTS", maxports, &maxportssize) == 0)
- erts_max_ports = atoi(maxports);
+ return ERTS_PORT_OP_DONE;
+}
+
+static int
+port_sig_connect(Port *prt, erts_aint32_t state, int op, ErtsProc2PortSigData *sigdp)
+{
+ Eterm msg = am_badarg;
+ if (op == ERTS_PROC2PORT_SIG_EXEC) {
+ ErtsPortOpResult res;
+ res = set_port_connected(sigdp->flags & ERTS_P2P_SIG_DATA_FLG_BANG_OP,
+ sigdp->u.connect.from,
+ prt,
+ state,
+ sigdp->u.connect.connected);
+ if (res == ERTS_PORT_OP_DONE)
+ msg = am_true;
+ }
+ if (sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY)
+ port_sched_op_reply(sigdp->caller, sigdp->ref, msg);
+ return ERTS_PORT_REDS_CONNECT;
+}
+
+ErtsPortOpResult
+erts_port_connect(Process *c_p,
+ int flags,
+ Port *prt,
+ Eterm from,
+ Eterm connect,
+ Eterm *refp)
+{
+ ErtsProc2PortSigData *sigdp;
+ Eterm connect_id;
+ ErtsTryImmDrvCallState try_call_state
+ = ERTS_INIT_TRY_IMM_DRV_CALL_STATE(c_p,
+ prt,
+ ERTS_PORT_SFLGS_INVALID_LOOKUP,
+ 0,
+ !refp,
+ am_connect);
+
+ ASSERT((flags & ~ERTS_PORT_SIG_FLG_BANG_OP) == 0);
+
+ if (is_not_internal_pid(connect))
+ connect_id = NIL; /* Fail in op (for signal order) */
else
- erts_max_ports = sys_max_files();
+ connect_id = connect;
+
+ switch (try_imm_drv_call(&try_call_state)) {
+ case ERTS_TRY_IMM_DRV_CALL_OK: {
+ ErtsPortOpResult res;
+ res = set_port_connected(flags & ERTS_PORT_SIG_FLG_BANG_OP,
+ from,
+ prt,
+ try_call_state.state,
+ connect_id);
+ finalize_imm_drv_call(&try_call_state);
+ return res;
+ }
+ case ERTS_TRY_IMM_DRV_CALL_INVALID_PORT:
+ return ERTS_PORT_OP_DROPPED;
+ default:
+ /* Schedule call instead... */
+ break;
+ }
+
+ sigdp = erts_port_task_alloc_p2p_sig_data();
+ sigdp->flags = ERTS_P2P_SIG_TYPE_CONNECT | flags;
+
+ sigdp->u.connect.from = from;
+ sigdp->u.connect.connected = connect_id;
+
+ return erts_schedule_proc2port_signal(c_p,
+ prt,
+ c_p->common.id,
+ refp,
+ sigdp,
+ 0,
+ port_sig_connect);
+}
- if (erts_max_ports > ERTS_MAX_PORTS)
- erts_max_ports = ERTS_MAX_PORTS;
- if (erts_max_ports < 1024)
- erts_max_ports = 1024;
+static void
+port_unlink(Port *prt, Eterm from)
+{
+ ErtsLink *lnk = erts_remove_link(&ERTS_P_LINKS(prt), from);
+ if (lnk)
+ erts_destroy_link(lnk);
+}
- if (erts_use_r9_pids_ports) {
- ports_bits = ERTS_R9_PORTS_BITS;
- if (erts_max_ports > ERTS_MAX_R9_PORTS)
- erts_max_ports = ERTS_MAX_R9_PORTS;
+static int
+port_sig_unlink(Port *prt, erts_aint32_t state, int op, ErtsProc2PortSigData *sigdp)
+{
+ if (op == ERTS_PROC2PORT_SIG_EXEC)
+ port_unlink(prt, sigdp->u.unlink.from);
+ if (sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY)
+ port_sched_op_reply(sigdp->caller, sigdp->ref, am_true);
+ return ERTS_PORT_REDS_UNLINK;
+}
+
+ErtsPortOpResult
+erts_port_unlink(Process *c_p, Port *prt, Eterm from, Eterm *refp)
+{
+ ErtsProc2PortSigData *sigdp;
+ ErtsTryImmDrvCallState try_call_state
+ = ERTS_INIT_TRY_IMM_DRV_CALL_STATE(c_p,
+ prt,
+ ERTS_PORT_SFLGS_DEAD,
+ 0,
+ !refp,
+ am_unlink);
+
+ switch (try_imm_drv_call(&try_call_state)) {
+ case ERTS_TRY_IMM_DRV_CALL_OK:
+ port_unlink(prt, from);
+ finalize_imm_drv_call(&try_call_state);
+ return ERTS_PORT_OP_DONE;
+ case ERTS_TRY_IMM_DRV_CALL_INVALID_PORT:
+ return ERTS_PORT_OP_DROPPED;
+ default:
+ /* Schedule call instead... */
+ break;
}
- port_extra_shift = erts_fit_in_bits_int32(erts_max_ports - 1);
- port_num_mask = (1 << ports_bits) - 1;
+ sigdp = erts_port_task_alloc_p2p_sig_data();
+ sigdp->flags = ERTS_P2P_SIG_TYPE_UNLINK;
+ sigdp->u.unlink.from = from;
+
+ return erts_schedule_proc2port_signal(c_p,
+ prt,
+ c_p ? c_p->common.id : from,
+ refp,
+ sigdp,
+ 0,
+ port_sig_unlink);
+}
- erts_port_tab_index_mask = ~(~((Uint) 0) << port_extra_shift);
- erts_max_ports = 1 << port_extra_shift;
+static void
+port_link_failure(Eterm port_id, Eterm linker)
+{
+ Process *rp;
+ ErtsProcLocks rp_locks = ERTS_PROC_LOCK_LINK|ERTS_PROC_LOCKS_XSIG_SEND;
+ ASSERT(is_internal_pid(linker));
+ rp = erts_pid2proc(NULL, 0, linker, rp_locks);
+ if (rp) {
+ ErtsLink *rlnk = erts_remove_link(&ERTS_P_LINKS(rp), port_id);
+ if (rlnk) {
+ int xres = erts_send_exit_signal(NULL,
+ port_id,
+ rp,
+ &rp_locks,
+ am_noproc,
+ NIL,
+ NULL,
+ 0);
+ if (xres >= 0 && IS_TRACED_FL(rp, F_TRACE_PROCS)) {
+ /* We didn't exit the process and it is traced */
+ if (IS_TRACED_FL(rp, F_TRACE_PROCS))
+ trace_proc(NULL, rp, am_getting_unlinked, port_id);
+ }
+ if (rp_locks)
+ erts_smp_proc_unlock(rp, rp_locks);
+ }
+ }
+}
- erts_smp_mtx_init(&erts_driver_list_lock,"driver_list");
- driver_list = NULL;
- erts_smp_tsd_key_create(&driver_list_lock_status_key);
- erts_smp_tsd_key_create(&driver_list_last_error_key);
+static void
+port_link(Port *prt, erts_aint32_t state, Eterm to)
+{
+ if (!(state & ERTS_PORT_SFLGS_INVALID_LOOKUP))
+ erts_add_link(&ERTS_P_LINKS(prt), LINK_PID, to);
+ else
+ port_link_failure(prt->common.id, to);
+}
- if (erts_max_ports * sizeof(Port) <= erts_max_ports) {
- /* More memory needed than the whole address space. */
- erts_alloc_enomem(ERTS_ALC_T_PORT_TABLE, ~((Uint) 0));
+static int
+port_sig_link(Port *prt, erts_aint32_t state, int op, ErtsProc2PortSigData *sigdp)
+{
+ if (op == ERTS_PROC2PORT_SIG_EXEC)
+ port_link(prt, state, sigdp->u.link.to);
+ else
+ port_link_failure(sigdp->u.link.port, sigdp->u.link.to);
+ if (sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY)
+ port_sched_op_reply(sigdp->caller, sigdp->ref, am_true);
+ return ERTS_PORT_REDS_LINK;
+}
+
+ErtsPortOpResult
+erts_port_link(Process *c_p, Port *prt, Eterm to, Eterm *refp)
+{
+ ErtsProc2PortSigData *sigdp;
+ ErtsTryImmDrvCallState try_call_state
+ = ERTS_INIT_TRY_IMM_DRV_CALL_STATE(c_p,
+ prt,
+ ERTS_PORT_SFLGS_INVALID_LOOKUP,
+ 0,
+ !refp,
+ am_link);
+
+ switch (try_imm_drv_call(&try_call_state)) {
+ case ERTS_TRY_IMM_DRV_CALL_OK:
+ port_link(prt, try_call_state.state, to);
+ finalize_imm_drv_call(&try_call_state);
+ return ERTS_PORT_OP_DONE;
+ case ERTS_TRY_IMM_DRV_CALL_INVALID_PORT:
+ return ERTS_PORT_OP_BADARG;
+ default:
+ /* Schedule call instead... */
+ break;
}
- erts_port = (Port *) erts_alloc(ERTS_ALC_T_PORT_TABLE,
- erts_max_ports * sizeof(Port));
+ sigdp = erts_port_task_alloc_p2p_sig_data();
+ sigdp->flags = ERTS_P2P_SIG_TYPE_LINK;
+ sigdp->u.link.port = prt->common.id;
+ sigdp->u.link.to = to;
+
+ return erts_schedule_proc2port_signal(c_p,
+ prt,
+ c_p ? c_p->common.id : to,
+ refp,
+ sigdp,
+ 0,
+ port_sig_link);
+}
- erts_smp_atomic_init_nob(&erts_bytes_out, 0);
- erts_smp_atomic_init_nob(&erts_bytes_in, 0);
+void erts_init_io(int port_tab_size,
+ int port_tab_size_ignore_files)
+{
+ ErlDrvEntry** dp;
+ erts_smp_rwmtx_opt_t drv_list_rwmtx_opts = ERTS_SMP_RWMTX_OPT_DEFAULT_INITER;
+ drv_list_rwmtx_opts.type = ERTS_SMP_RWMTX_TYPE_EXTREMELY_FREQUENT_READ;
+ drv_list_rwmtx_opts.lived = ERTS_SMP_RWMTX_LONG_LIVED;
- for (i = 0; i < erts_max_ports; i++) {
- erts_port_task_init_sched(&erts_port[i].sched);
- erts_smp_atomic_init_nob(&erts_port[i].refc, 0);
#ifdef ERTS_SMP
- erts_port[i].lock = NULL;
- erts_port[i].xports = NULL;
- erts_smp_spinlock_init_x(&erts_port[i].state_lck,
-#ifdef ERTS_ENABLE_LOCK_COUNT
- (erts_lcnt_rt_options & ERTS_LCNT_OPT_PORTLOCK) ? "port_state" : NULL,
-#else
- "port_state",
-#endif
- make_small(0));
+ init_xports_list_alloc();
#endif
- erts_port[i].tracer_proc = NIL;
- erts_port[i].trace_flags = 0;
- erts_port[i].drv_ptr = NULL;
- erts_port[i].status = ERTS_PORT_SFLG_FREE;
- erts_port[i].name = NULL;
- erts_port[i].nlinks = NULL;
- erts_port[i].monitors = NULL;
- erts_port[i].linebuf = NULL;
- erts_port[i].port_data_lock = NULL;
+ pdl_init();
+
+ if (!port_tab_size_ignore_files) {
+ int max_files = sys_max_files();
+ if (port_tab_size < max_files)
+ port_tab_size = max_files;
}
- erts_smp_atomic32_init_nob(&erts_ports_snapshot, (erts_aint32_t) 0);
- last_port_num = 0;
- erts_smp_spinlock_init(&get_free_port_lck, "get_free_port");
+ if (port_tab_size > ERTS_MAX_PORTS)
+ port_tab_size = ERTS_MAX_PORTS;
+ else if (port_tab_size < ERTS_MIN_PORTS)
+ port_tab_size = ERTS_MIN_PORTS;
+
+ erts_smp_rwmtx_init_opt(&erts_driver_list_lock,
+ &drv_list_rwmtx_opts,
+ "driver_list");
+ driver_list = NULL;
+ erts_smp_tsd_key_create(&driver_list_lock_status_key);
+ erts_smp_tsd_key_create(&driver_list_last_error_key);
+
+ erts_ptab_init_table(&erts_port,
+ ERTS_ALC_T_PORT_TABLE,
+ NULL,
+ (ErtsPTabElementCommon *) &erts_invalid_port.common,
+ port_tab_size,
+ "port_table");
+
+ erts_smp_atomic_init_nob(&erts_bytes_out, 0);
+ erts_smp_atomic_init_nob(&erts_bytes_in, 0);
sys_init_io();
erts_smp_tsd_set(driver_list_lock_status_key, (void *) 1);
- erts_smp_mtx_lock(&erts_driver_list_lock);
+ erts_smp_rwmtx_rwlock(&erts_driver_list_lock);
init_driver(&fd_driver, &fd_driver_entry, NULL);
init_driver(&vanilla_driver, &vanilla_driver_entry, NULL);
@@ -1390,28 +2655,64 @@ void init_io(void)
erts_add_driver_entry(*dp, NULL, 1);
erts_smp_tsd_set(driver_list_lock_status_key, NULL);
- erts_smp_mtx_unlock(&erts_driver_list_lock);
+ erts_smp_rwmtx_rwunlock(&erts_driver_list_lock);
}
#if defined(ERTS_ENABLE_LOCK_COUNT) && defined(ERTS_SMP)
-void erts_lcnt_enable_io_lock_count(int enable) {
- int i;
- for (i = 0; i < erts_max_ports; i++) {
- Port* p = &erts_port[i];
- if (enable) {
- erts_lcnt_init_lock_x(&p->state_lck.lcnt, "port_state", ERTS_LCNT_LT_SPINLOCK, make_small(i));
- if (p->lock) {
- erts_lcnt_init_lock_x(&p->lock->lcnt, "port_lock", ERTS_LCNT_LT_MUTEX, make_small(i));
- }
- } else {
- erts_lcnt_destroy_lock(&p->state_lck.lcnt);
- if (p->lock) {
- erts_lcnt_destroy_lock(&p->lock->lcnt);
- }
- }
+static ERTS_INLINE void lcnt_enable_drv_lock_count(erts_driver_t *dp, int enable)
+{
+ if (dp->lock) {
+ if (enable)
+ erts_lcnt_init_lock_x(&dp->lock->lcnt,
+ "driver_lock",
+ ERTS_LCNT_LT_MUTEX,
+ am_atom_put(dp->name,
+ sys_strlen(dp->name)));
+ else
+ erts_lcnt_destroy_lock(&dp->lock->lcnt);
+
+ }
+}
+
+static ERTS_INLINE void lcnt_enable_port_lock_count(Port *prt, int enable)
+{
+ erts_aint32_t state = erts_atomic32_read_nob(&prt->state);
+ if (!enable) {
+ erts_lcnt_destroy_lock(&prt->sched.mtx.lcnt);
+ if (state & ERTS_PORT_SFLG_PORT_SPECIFIC_LOCK)
+ erts_lcnt_destroy_lock(&prt->lock->lcnt);
+ }
+ else {
+ erts_lcnt_init_lock_x(&prt->sched.mtx.lcnt,
+ "port_sched_lock",
+ ERTS_LCNT_LT_MUTEX,
+ prt->common.id);
+ if (state & ERTS_PORT_SFLG_PORT_SPECIFIC_LOCK)
+ erts_lcnt_init_lock_x(&prt->lock->lcnt,
+ "port_lock",
+ ERTS_LCNT_LT_MUTEX,
+ prt->common.id);
}
}
+
+void erts_lcnt_enable_io_lock_count(int enable)
+{
+ erts_driver_t *dp;
+ int i, max = erts_ptab_max(&erts_port);
+
+ for (i = 0; i < max; i++) {
+ Port *prt = erts_pix2port(i);
+ if (prt)
+ lcnt_enable_port_lock_count(prt, enable);
+ }
+
+ lcnt_enable_drv_lock_count(&vanilla_driver, enable);
+ lcnt_enable_drv_lock_count(&spawn_driver, enable);
+ lcnt_enable_drv_lock_count(&fd_driver, enable);
+ for (dp = driver_list; dp; dp = dp->next)
+ lcnt_enable_drv_lock_count(dp, enable);
+}
#endif
/*
@@ -1594,9 +2895,7 @@ deliver_result(Eterm sender, Eterm pid, Eterm res)
ERTS_SMP_CHK_NO_PROC_LOCKS;
- ASSERT(is_internal_port(sender)
- && is_internal_pid(pid)
- && internal_pid_index(pid) < erts_max_processes);
+ ASSERT(is_internal_port(sender) && is_internal_pid(pid));
rp = (scheduler
? erts_proc_lookup(pid)
@@ -1608,16 +2907,19 @@ deliver_result(Eterm sender, Eterm pid, Eterm res)
ErlOffHeap *ohp;
Eterm* hp;
Uint sz_res;
- sz_res = size_object(res);
- hp = erts_alloc_message_heap(sz_res + 3, &bp, &ohp, rp, &rp_locks);
- res = copy_struct(res, sz_res, &hp, ohp);
- tuple = TUPLE2(hp, sender, res);
+
+ sz_res = size_object(res);
+ hp = erts_alloc_message_heap(sz_res + 3, &bp, &ohp, rp, &rp_locks);
+ res = copy_struct(res, sz_res, &hp, ohp);
+ tuple = TUPLE2(hp, sender, res);
erts_queue_message(rp, &rp_locks, bp, tuple, NIL
#ifdef USE_VM_PROBES
, NIL
#endif
);
- erts_smp_proc_unlock(rp, rp_locks);
+
+ if (rp_locks)
+ erts_smp_proc_unlock(rp, rp_locks);
if (!scheduler)
erts_smp_proc_dec_refc(rp);
@@ -1633,7 +2935,7 @@ deliver_result(Eterm sender, Eterm pid, Eterm res)
* len -- length of data
*/
-static void deliver_read_message(Port* prt, Eterm to,
+static void deliver_read_message(Port* prt, erts_aint32_t state, Eterm to,
char *hbuf, ErlDrvSizeT hlen,
char *buf, ErlDrvSizeT len, int eol)
{
@@ -1651,10 +2953,11 @@ static void deliver_read_message(Port* prt, Eterm to,
ERTS_SMP_CHK_NO_PROC_LOCKS;
need = 3 + 3 + 2*hlen;
- if (prt->status & ERTS_PORT_SFLG_LINEBUF_IO) {
+
+ if (state & ERTS_PORT_SFLG_LINEBUF_IO) {
need += 3;
}
- if (prt->status & ERTS_PORT_SFLG_BINARY_IO && buf != NULL) {
+ if ((state & ERTS_PORT_SFLG_BINARY_IO) && buf != NULL) {
need += PROC_BIN_SIZE;
} else {
need += 2*len;
@@ -1670,7 +2973,7 @@ static void deliver_read_message(Port* prt, Eterm to,
hp = erts_alloc_message_heap(need, &bp, &ohp, rp, &rp_locks);
listp = NIL;
- if ((prt->status & ERTS_PORT_SFLG_BINARY_IO) == 0) {
+ if ((state & ERTS_PORT_SFLG_BINARY_IO) == 0) {
listp = buf_to_intlist(&hp, buf, len, listp);
} else if (buf != NULL) {
ProcBin* pb;
@@ -1701,14 +3004,14 @@ static void deliver_read_message(Port* prt, Eterm to,
listp = buf_to_intlist(&hp, hbuf, hlen, listp);
}
- if (prt->status & ERTS_PORT_SFLG_LINEBUF_IO){
+ if (state & ERTS_PORT_SFLG_LINEBUF_IO){
listp = TUPLE2(hp, (eol) ? am_eol : am_noeol, listp);
hp += 3;
}
tuple = TUPLE2(hp, am_data, listp);
hp += 3;
- tuple = TUPLE2(hp, prt->id, tuple);
+ tuple = TUPLE2(hp, prt->common.id, tuple);
hp += 3;
erts_queue_message(rp, &rp_locks, bp, tuple, am_undefined
@@ -1726,7 +3029,8 @@ static void deliver_read_message(Port* prt, Eterm to,
* Deliver all lines in a line buffer, repeats calls to
* deliver_read_message, and takes the same parameters.
*/
-static void deliver_linebuf_message(Port* prt, Eterm to,
+static void deliver_linebuf_message(Port* prt, erts_aint_t state,
+ Eterm to,
char* hbuf, ErlDrvSizeT hlen,
char *buf, ErlDrvSizeT len)
{
@@ -1735,7 +3039,7 @@ static void deliver_linebuf_message(Port* prt, Eterm to,
if(init_linebuf_context(&lc,&(prt->linebuf), buf, len) < 0)
return;
while((ret = read_linebuf(&lc)) > LINEBUF_EMPTY)
- deliver_read_message(prt, to, hbuf, hlen, LINEBUF_DATA(lc),
+ deliver_read_message(prt, state, to, hbuf, hlen, LINEBUF_DATA(lc),
LINEBUF_DATALEN(lc), (ret == LINEBUF_EOL));
}
@@ -1746,20 +3050,25 @@ static void deliver_linebuf_message(Port* prt, Eterm to,
* Parameters:
* prt - Pointer to a Port structure for this port.
*/
-static void flush_linebuf_messages(Port *prt)
+static void flush_linebuf_messages(Port *prt, erts_aint32_t state)
{
LineBufContext lc;
int ret;
ERTS_SMP_LC_ASSERT(!prt || erts_lc_is_port_locked(prt));
- if(prt == NULL || !(prt->status & ERTS_PORT_SFLG_LINEBUF_IO))
+
+ if (!prt)
+ return;
+
+ if (!(state & ERTS_PORT_SFLG_LINEBUF_IO))
return;
if(init_linebuf_context(&lc,&(prt->linebuf), NULL, 0) < 0)
return;
while((ret = flush_linebuf(&lc)) > LINEBUF_EMPTY)
deliver_read_message(prt,
- prt->connected,
+ state,
+ ERTS_PORT_GET_CONNECTED(prt),
NULL,
0,
LINEBUF_DATA(lc),
@@ -1787,6 +3096,7 @@ deliver_vec_message(Port* prt, /* Port */
ErlOffHeap *ohp;
ErtsProcLocks rp_locks = 0;
int scheduler = erts_get_scheduler_id() != 0;
+ erts_aint32_t state;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
ERTS_SMP_CHK_NO_PROC_LOCKS;
@@ -1802,12 +3112,13 @@ deliver_vec_message(Port* prt, /* Port */
if (!rp)
return;
+ state = erts_atomic32_read_nob(&prt->state);
/*
* Calculate the exact number of heap words needed.
*/
need = 3 + 3; /* Heap space for two tuples */
- if (prt->status & ERTS_PORT_SFLG_BINARY_IO) {
+ if (state & ERTS_PORT_SFLG_BINARY_IO) {
need += (2+PROC_BIN_SIZE)*vsize - 2 + hlen*2;
} else {
need += (hlen+csize)*2;
@@ -1818,7 +3129,7 @@ deliver_vec_message(Port* prt, /* Port */
listp = NIL;
iov += vsize;
- if ((prt->status & ERTS_PORT_SFLG_BINARY_IO) == 0) {
+ if ((state & ERTS_PORT_SFLG_BINARY_IO) == 0) {
Eterm* thp = hp;
while (vsize--) {
iov--;
@@ -1871,7 +3182,7 @@ deliver_vec_message(Port* prt, /* Port */
tuple = TUPLE2(hp, am_data, listp);
hp += 3;
- tuple = TUPLE2(hp, prt->id, tuple);
+ tuple = TUPLE2(hp, prt->common.id, tuple);
hp += 3;
erts_queue_message(rp, &rp_locks, bp, tuple, am_undefined
@@ -1904,7 +3215,7 @@ static void deliver_bin_message(Port* prt, /* port */
/*
* Note.
*
- * The test for (p->status & ERTS_PORT_SFLGS_DEAD) == 0 is important since the
+ * The test for ERTS_PORT_SFLGS_DEAD is important since the
* driver's flush function might call driver_async, which when using no
* threads and being short circuited will notice that the io queue is empty
* (after calling the driver's async_ready) and recursively call
@@ -1920,7 +3231,7 @@ static void flush_port(Port *p)
if (p->drv_ptr->flush != NULL) {
#ifdef USE_VM_PROBES
if (DTRACE_ENABLED(driver_flush)) {
- DTRACE_FORMAT_COMMON_PID_AND_PORT(p->connected, p)
+ DTRACE_FORMAT_COMMON_PID_AND_PORT(ERTS_PORT_GET_CONNECTED(p), p)
DTRACE3(driver_flush, process_str, port_str, p->name);
}
#endif
@@ -1935,11 +3246,12 @@ static void flush_port(Port *p)
}
#ifdef ERTS_SMP
if (p->xports)
- erts_smp_xports_unlock(p);
+ erts_port_handle_xports(p);
ASSERT(!p->xports);
#endif
}
- if ((p->status & ERTS_PORT_SFLGS_DEAD) == 0 && is_port_ioq_empty(p)) {
+ if ((erts_atomic32_read_nob(&p->state) & ERTS_PORT_SFLGS_DEAD) == 0
+ && is_port_ioq_empty(p)) {
terminate_port(p);
}
}
@@ -1951,29 +3263,29 @@ terminate_port(Port *prt)
Eterm send_closed_port_id;
Eterm connected_id = NIL /* Initialize to silence compiler */;
erts_driver_t *drv;
- int halt;
+ erts_aint32_t state;
ERTS_SMP_CHK_NO_PROC_LOCKS;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
- ASSERT(!prt->nlinks);
- ASSERT(!prt->monitors);
+ ASSERT(!ERTS_P_LINKS(prt));
+ ASSERT(!ERTS_P_MONITORS(prt));
- /* prt->status may be altered by kill_port()below */
- halt = (prt->status & ERTS_PORT_SFLG_HALT) != 0;
- if (prt->status & ERTS_PORT_SFLG_SEND_CLOSED) {
- erts_port_status_band_set(prt, ~ERTS_PORT_SFLG_SEND_CLOSED);
- send_closed_port_id = prt->id;
- connected_id = prt->connected;
+ /* state may be altered by kill_port() below */
+ state = erts_atomic32_read_band_nob(&prt->state,
+ ~ERTS_PORT_SFLG_SEND_CLOSED);
+ if (state & ERTS_PORT_SFLG_SEND_CLOSED) {
+ send_closed_port_id = prt->common.id;
+ connected_id = ERTS_PORT_GET_CONNECTED(prt);
}
else {
send_closed_port_id = NIL;
}
#ifdef ERTS_SMP
- erts_cancel_smp_ptimer(prt->ptimer);
+ erts_cancel_smp_ptimer(prt->common.u.alive.ptimer);
#else
- erts_cancel_timer(&prt->tm);
+ erts_cancel_timer(&prt->common.u.alive.tm);
#endif
drv = prt->drv_ptr;
@@ -1981,7 +3293,7 @@ terminate_port(Port *prt)
int fpe_was_unmasked = erts_block_fpe();
#ifdef USE_VM_PROBES
if (DTRACE_ENABLED(driver_stop)) {
- DTRACE_FORMAT_COMMON_PID_AND_PORT(prt->connected, prt)
+ DTRACE_FORMAT_COMMON_PID_AND_PORT(connected_id, prt)
DTRACE3(driver_stop, process_str, drv->name, port_str);
}
#endif
@@ -1989,14 +3301,14 @@ terminate_port(Port *prt)
erts_unblock_fpe(fpe_was_unmasked);
#ifdef ERTS_SMP
if (prt->xports)
- erts_smp_xports_unlock(prt);
+ erts_port_handle_xports(prt);
ASSERT(!prt->xports);
#endif
}
if(drv->handle != NULL) {
- erts_smp_mtx_lock(&erts_driver_list_lock);
+ erts_smp_rwmtx_rlock(&erts_driver_list_lock);
erts_ddll_decrement_port_count(drv->handle);
- erts_smp_mtx_unlock(&erts_driver_list_lock);
+ erts_smp_rwmtx_runlock(&erts_driver_list_lock);
}
stopq(prt); /* clear queue memory */
if(prt->linebuf != NULL){
@@ -2012,20 +3324,21 @@ terminate_port(Port *prt)
if (prt->psd)
erts_free(ERTS_ALC_T_PRTSD, prt->psd);
+ ASSERT(prt->dist_entry == NULL);
+
kill_port(prt);
/*
* We don't want to send the closed message until after the
* port has been removed from the port table (in kill_port()).
*/
- if (halt && (erts_smp_atomic32_dec_read_nob(&erts_halt_progress) == 0)) {
- erts_smp_port_unlock(prt); /* We will exit and never return */
+ if ((state & ERTS_PORT_SFLG_HALT)
+ && (erts_smp_atomic32_dec_read_nob(&erts_halt_progress) == 0)) {
+ erts_port_release(prt); /* We will exit and never return */
erl_exit_flush_async(erts_halt_code, "");
}
if (is_internal_port(send_closed_port_id))
deliver_result(send_closed_port_id, connected_id, am_closed);
-
- ASSERT(prt->dist_entry == NULL);
}
void
@@ -2045,7 +3358,7 @@ static void sweep_one_monitor(ErtsMonitor *mon, void *vpsc)
if (!rp) {
goto done;
}
- rmon = erts_remove_monitor(&(rp->monitors),mon->ref);
+ rmon = erts_remove_monitor(&ERTS_P_MONITORS(rp), mon->ref);
erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_LINK);
if (rmon == NULL) {
goto done;
@@ -2099,7 +3412,7 @@ static void sweep_one_link(ErtsLink *lnk, void *vpsc)
ASSERT(is_internal_pid(lnk->pid));
rp = erts_pid2proc(NULL, 0, lnk->pid, rp_locks);
if (rp) {
- ErtsLink *rlnk = erts_remove_link(&(rp->nlinks), psc->port);
+ ErtsLink *rlnk = erts_remove_link(&ERTS_P_LINKS(rp), psc->port);
if (rlnk) {
int xres = erts_send_exit_signal(NULL,
@@ -2135,11 +3448,13 @@ static void sweep_one_link(ErtsLink *lnk, void *vpsc)
* that is to kill a port till reason kill. Then the port is stopped.
*
*/
-void
-erts_do_exit_port(Port *p, Eterm from, Eterm reason)
+
+int
+erts_deliver_port_exit(Port *p, Eterm from, Eterm reason, int send_closed)
{
ErtsLink *lnk;
Eterm rreason;
+ erts_aint32_t state;
ERTS_SMP_CHK_NO_PROC_LOCKS;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(p));
@@ -2159,66 +3474,76 @@ erts_do_exit_port(Port *p, Eterm from, Eterm reason)
}
#endif
- if ((p->status & (ERTS_PORT_SFLGS_DEAD
- | ERTS_PORT_SFLG_EXITING
- | ERTS_PORT_SFLG_IMMORTAL))
- || ((reason == am_normal) &&
- ((from != p->connected) && (from != p->id)))) {
- return;
- }
+ state = erts_atomic32_read_nob(&p->state);
+ if (state & (ERTS_PORT_SFLGS_DEAD
+ | ERTS_PORT_SFLG_EXITING
+ | ERTS_PORT_SFLG_CLOSING))
+ return 0;
+
+ if (reason == am_normal && from != ERTS_PORT_GET_CONNECTED(p) && from != p->common.id)
+ return 0;
+
+ if (send_closed)
+ erts_atomic32_read_bor_relb(&p->state,
+ ERTS_PORT_SFLG_SEND_CLOSED);
if (IS_TRACED_FL(p, F_TRACE_PORTS)) {
trace_port(p, am_closed, reason);
}
- erts_trace_check_exiting(p->id);
+ erts_trace_check_exiting(p->common.id);
/*
* Setting the port to not busy here, frees the list of pending
* processes and makes them runnable.
*/
- set_busy_port((ErlDrvPort)internal_port_index(p->id), 0);
+ set_busy_port((ErlDrvPort) p, 0);
- if (p->reg != NULL)
- (void) erts_unregister_name(NULL, 0, p, p->reg->name);
+ if (p->common.u.alive.reg != NULL)
+ (void) erts_unregister_name(NULL, 0, p, p->common.u.alive.reg->name);
- erts_port_status_bor_set(p, ERTS_PORT_SFLG_EXITING);
+ state = erts_atomic32_read_bor_relb(&p->state, ERTS_PORT_SFLG_EXITING);
{
- SweepContext sc = {p->id, rreason};
- lnk = p->nlinks;
- p->nlinks = NULL;
+ SweepContext sc = {p->common.id, rreason};
+ lnk = ERTS_P_LINKS(p);
+ ERTS_P_LINKS(p) = NULL;
erts_sweep_links(lnk, &sweep_one_link, &sc);
}
DRV_MONITOR_LOCK_PDL(p);
{
- ErtsMonitor *moni = p->monitors;
- p->monitors = NULL;
+ ErtsMonitor *moni = ERTS_P_MONITORS(p);
+ ERTS_P_MONITORS(p) = NULL;
erts_sweep_monitors(moni, &sweep_one_monitor, NULL);
}
DRV_MONITOR_UNLOCK_PDL(p);
- if ((p->status & ERTS_PORT_SFLG_DISTRIBUTION) && p->dist_entry) {
+ if ((state & ERTS_PORT_SFLG_DISTRIBUTION) && p->dist_entry) {
erts_do_net_exits(p->dist_entry, rreason);
erts_deref_dist_entry(p->dist_entry);
- p->dist_entry = NULL;
- erts_port_status_band_set(p, ~ERTS_PORT_SFLG_DISTRIBUTION);
+ p->dist_entry = NULL;
+ erts_atomic32_read_band_relb(&p->state,
+ ~ERTS_PORT_SFLG_DISTRIBUTION);
}
if ((reason != am_kill) && !is_port_ioq_empty(p)) {
- erts_port_status_bandor_set(p,
- ~ERTS_PORT_SFLG_EXITING, /* must turn it off */
- ERTS_PORT_SFLG_CLOSING);
+ /* must turn exiting flag off */
+ erts_atomic32_read_bset_relb(&p->state,
+ (ERTS_PORT_SFLG_EXITING
+ | ERTS_PORT_SFLG_CLOSING),
+ ERTS_PORT_SFLG_CLOSING);
flush_port(p);
}
else {
terminate_port(p);
}
+
+ return 1;
}
/* About the states ERTS_PORT_SFLG_EXITING and ERTS_PORT_SFLG_CLOSING used above.
**
-** ERTS_PORT_SFLG_EXITING is a recursion protection for erts_do_exit_port().
+** ERTS_PORT_SFLG_EXITING is a recursion protection for erts_deliver_port_exit().
** It is unclear whether this state is necessary or not, it might be possible
** to merge it with ERTS_PORT_SFLG_CLOSING. ERTS_PORT_SFLG_EXITING only persists
** over a section of sequential (but highly recursive) code.
@@ -2234,232 +3559,1108 @@ erts_do_exit_port(Port *p, Eterm from, Eterm reason)
** {PID, close}
** {PID, {command, io-list}}
** {PID, {connect, New_PID}}
-**
-**
*/
-void erts_port_command(Process *proc,
- Eterm caller_id,
- Port *port,
- Eterm command)
+ErtsPortOpResult
+erts_port_command(Process *c_p,
+ int flags,
+ Port *port,
+ Eterm command,
+ Eterm *refp)
{
Eterm *tp;
- Eterm pid;
- if (!port)
- return;
+ ASSERT(port);
- erts_smp_proc_unlock(proc, ERTS_PROC_LOCK_MAIN);
- ERTS_SMP_CHK_NO_PROC_LOCKS;
- ASSERT(!INVALID_PORT(port, port->id));
+ flags |= ERTS_PORT_SIG_FLG_BANG_OP;
if (is_tuple_arity(command, 2)) {
+ Eterm cntd;
tp = tuple_val(command);
- if ((pid = port->connected) == tp[1]) {
- /* PID must be connected */
+ cntd = tp[1];
+ if (is_internal_pid(cntd)) {
if (tp[2] == am_close) {
- erts_port_status_bor_set(port, ERTS_PORT_SFLG_SEND_CLOSED);
- erts_do_exit_port(port, pid, am_normal);
-
-#ifdef USE_VM_PROBES
- if(DTRACE_ENABLED(port_command)) {
- DTRACE_FORMAT_COMMON_PROC_AND_PORT(proc, port)
- DTRACE4(port_command, process_str, port_str, port->name, "close");
- }
-#endif
- goto done;
+ if (!erts_port_synchronous_ops)
+ refp = NULL;
+ flags &= ~ERTS_PORT_SIG_FLG_NOSUSPEND;
+ return erts_port_exit(c_p, flags, port, cntd, am_normal, refp);
} else if (is_tuple_arity(tp[2], 2)) {
tp = tuple_val(tp[2]);
if (tp[1] == am_command) {
- if (erts_write_to_port(caller_id, port, tp[2]) == 0)
- goto done;
- } else if ((tp[1] == am_connect) && is_internal_pid(tp[2])) {
-#ifdef USE_VM_PROBES
- if(DTRACE_ENABLED(port_command)) {
- DTRACE_FORMAT_COMMON_PROC_AND_PORT(proc, port)
- DTRACE4(port_command, process_str, port_str, port->name, "connect");
- }
-#endif
- port->connected = tp[2];
- deliver_result(port->id, pid, am_connected);
- goto done;
+ if (!(flags & ERTS_PORT_SIG_FLG_NOSUSPEND)
+ && !erts_port_synchronous_ops)
+ refp = NULL;
+ return erts_port_output(c_p, flags, port, cntd, tp[2], refp);
+ }
+ else if (tp[1] == am_connect) {
+ if (!erts_port_synchronous_ops)
+ refp = NULL;
+ flags &= ~ERTS_PORT_SIG_FLG_NOSUSPEND;
+ return erts_port_connect(c_p, flags, port, cntd, tp[2], refp);
}
}
}
}
- {
- ErtsProcLocks rp_locks = ERTS_PROC_LOCKS_XSIG_SEND;
- Process* rp = erts_pid2proc(NULL, 0,
- port->connected, rp_locks);
- if (rp) {
- (void) erts_send_exit_signal(NULL,
- port->id,
- rp,
- &rp_locks,
- am_badsig,
- NIL,
- NULL,
- 0);
- erts_smp_proc_unlock(rp, rp_locks);
- }
+ /* badsig */
+ if (!erts_port_synchronous_ops)
+ refp = NULL;
+ flags &= ~ERTS_PORT_SIG_FLG_NOSUSPEND;
+ return bad_port_signal(c_p, flags, port, c_p->common.id, refp, am_command);
+}
+
+static ERTS_INLINE ErtsPortOpResult
+call_driver_control(Eterm caller,
+ Port *prt,
+ unsigned int command,
+ char *bufp,
+ ErlDrvSizeT size,
+ char **resp_bufp,
+ ErlDrvSizeT *from_size)
+{
+ ErlDrvSSizeT cres;
+
+ if (!prt->drv_ptr->control)
+ return ERTS_PORT_OP_BADARG;
+
+#ifdef USE_VM_PROBES
+ if (DTRACE_ENABLED(port_control) || DTRACE_ENABLED(driver_control)) {
+ DTRACE_FORMAT_COMMON_PID_AND_PORT(caller, prt);
+ DTRACE4(port_control, process_str, port_str, prt->name, command);
+ DTRACE5(driver_control, process_str, port_str, prt->name,
+ command, size);
}
- done:
- erts_smp_proc_lock(proc, ERTS_PROC_LOCK_MAIN);
+#endif
+
+ prt->caller = caller;
+ cres = prt->drv_ptr->control((ErlDrvData) prt->drv_data,
+ command,
+ bufp,
+ size,
+ resp_bufp,
+ *from_size);
+ prt->caller = NIL;
+
+ if (cres < 0)
+ return ERTS_PORT_OP_BADARG;
+
+ *from_size = (ErlDrvSizeT) cres;
+
+ return ERTS_PORT_OP_DONE;
}
-/*
- * Control a port synchronously.
- * Returns either a list or a binary.
- */
-Eterm
-erts_port_control(Process* p, Port* prt, Uint command, Eterm iolist)
-{
- byte* to_port = NULL; /* Buffer to write to port. */
- /* Initialization is for shutting up
- warning about use before set. */
- Uint to_len = 0; /* Length of buffer. */
- int must_free = 0; /* True if the buffer should be freed. */
- char port_result[ERL_ONHEAP_BIN_LIMIT]; /* Default buffer for result from port. */
- char* port_resp; /* Pointer to result buffer. */
- ErlDrvSSizeT n;
- ErlDrvSSizeT (*control)
- (ErlDrvData, unsigned, char*, ErlDrvSizeT, char**, ErlDrvSizeT);
- int fpe_was_unmasked;
+static void
+cleanup_scheduled_control(Binary *binp, char *bufp)
+{
+ if (binp) {
+ if (erts_refc_dectest(&binp->refc, 0) == 0)
+ erts_bin_free(binp);
+ }
+ else {
+ if (bufp)
+ erts_free(ERTS_ALC_T_DRV_CTRL_DATA, bufp);
+ }
+}
- ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
- if ((control = prt->drv_ptr->control) == NULL) {
- return THE_NON_VALUE;
+static ERTS_INLINE Uint
+port_control_result_size(int control_flags,
+ char *resp_bufp,
+ ErlDrvSizeT *resp_size,
+ char *pre_alloc_buf)
+{
+ if (!resp_bufp)
+ return (Uint) 0;
+
+ if (control_flags & PORT_CONTROL_FLAG_BINARY) {
+ if (resp_bufp != pre_alloc_buf) {
+ ErlDrvBinary *dbin = (ErlDrvBinary *) resp_bufp;
+ *resp_size = dbin->orig_size;
+ if (*resp_size > ERL_ONHEAP_BIN_LIMIT)
+ return PROC_BIN_SIZE;
+ }
+ ASSERT(*resp_size <= ERL_ONHEAP_BIN_LIMIT);
+ return (Uint) heap_bin_size((*resp_size));
}
- /*
- * Convert the iolist to a buffer, pointed to by to_port,
- * and with its length in to_len.
- */
- if (is_binary(iolist) && binary_bitoffset(iolist) == 0) {
+ return (Uint) 2*(*resp_size);
+}
+
+static ERTS_INLINE Eterm
+write_port_control_result(int control_flags,
+ char *resp_bufp,
+ ErlDrvSizeT resp_size,
+ char *pre_alloc_buf,
+ Eterm **hpp,
+ ErlHeapFragment *bp,
+ ErlOffHeap *ohp)
+{
+ Eterm res;
+ if (!resp_bufp)
+ return NIL;
+ if (control_flags & PORT_CONTROL_FLAG_BINARY) {
+ /* Binary result */
+ ErlDrvBinary *dbin;
+ ErlHeapBin *hbin;
+
+ if (resp_bufp == pre_alloc_buf)
+ dbin = NULL;
+ else {
+ dbin = (ErlDrvBinary *) resp_bufp;
+ if (dbin->orig_size > ERL_ONHEAP_BIN_LIMIT) {
+ ProcBin* pb = (ProcBin *) *hpp;
+ *hpp += PROC_BIN_SIZE;
+ pb->thing_word = HEADER_PROC_BIN;
+ pb->size = dbin->orig_size;
+ pb->next = ohp->first;
+ ohp->first = (struct erl_off_heap_header *) pb;
+ pb->val = ErlDrvBinary2Binary(dbin);
+ pb->bytes = (byte*) dbin->orig_bytes;
+ pb->flags = 0;
+ OH_OVERHEAD(ohp, dbin->orig_size / sizeof(Eterm));
+ return make_binary(pb);
+ }
+ resp_bufp = dbin->orig_bytes;
+ resp_size = dbin->orig_size;
+ }
+
+ hbin = (ErlHeapBin *) *hpp;
+ *hpp += heap_bin_size(resp_size);
+ ASSERT(resp_size <= ERL_ONHEAP_BIN_LIMIT);
+ hbin->thing_word = header_heap_bin(resp_size);
+ hbin->size = resp_size;
+ sys_memcpy(hbin->data, resp_bufp, resp_size);
+ if (dbin)
+ driver_free_binary(dbin);
+ return make_binary(hbin);
+ }
+
+ /* List result */
+ res = buf_to_intlist(hpp, resp_bufp, resp_size, NIL);
+ if (resp_bufp != pre_alloc_buf)
+ driver_free(resp_bufp);
+ return res;
+}
+
+static int
+port_sig_control(Port *prt,
+ erts_aint32_t state,
+ int op,
+ ErtsProc2PortSigData *sigdp)
+{
+ ASSERT(sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY);
+
+ if (op == ERTS_PROC2PORT_SIG_EXEC) {
+ char resp_buf[ERL_ONHEAP_BIN_LIMIT];
+ ErlDrvSizeT resp_size = sizeof(resp_buf);
+ char *resp_bufp = &resp_buf[0];
+ ErtsPortOpResult res;
+
+ res = call_driver_control(sigdp->caller,
+ prt,
+ sigdp->u.control.command,
+ sigdp->u.control.bufp,
+ sigdp->u.control.size,
+ &resp_bufp,
+ &resp_size);
+
+ if (res == ERTS_PORT_OP_DONE) {
+ Eterm msg;
+ Eterm *hp, *hp_start;
+ ErlHeapFragment *bp;
+ ErlOffHeap *ohp;
+ Process *rp;
+ ErtsProcLocks rp_locks = 0;
+ Uint hsz;
+ int control_flags;
+
+ rp = erts_proc_lookup_raw(sigdp->caller);
+ if (!rp)
+ goto done;
+
+ control_flags = prt->control_flags;
+
+ hsz = ERTS_QUEUE_PORT_SCHED_OP_REPLY_SIZE;
+ hsz += port_control_result_size(control_flags,
+ resp_bufp,
+ &resp_size,
+ &resp_buf[0]);
+
+ hp_start = hp = erts_alloc_message_heap(hsz,
+ &bp,
+ &ohp,
+ rp,
+ &rp_locks);
+
+ msg = write_port_control_result(control_flags,
+ resp_bufp,
+ resp_size,
+ &resp_buf[0],
+ &hp,
+ bp,
+ ohp);
+
+ queue_port_sched_op_reply(rp,
+ &rp_locks,
+ hp_start,
+ hp,
+ hsz,
+ bp,
+ sigdp->ref,
+ msg);
+
+ if (rp_locks)
+ erts_smp_proc_unlock(rp, rp_locks);
+ goto done;
+ }
+ }
+
+ /* failure */
+
+ port_sched_op_reply(sigdp->caller, sigdp->ref, am_badarg);
+
+done:
+
+ cleanup_scheduled_control(sigdp->u.control.binp,
+ sigdp->u.control.bufp);
+
+ return ERTS_PORT_REDS_CONTROL;
+}
+
+
+ErtsPortOpResult
+erts_port_control(Process* c_p,
+ Port *prt,
+ unsigned int command,
+ Eterm data,
+ Eterm *retvalp)
+{
+ ErtsPortOpResult res;
+ char *bufp = NULL;
+ ErlDrvSizeT size = 0;
+ int try_call;
+ int tmp_alloced = 0;
+ erts_aint32_t sched_flags;
+ Binary *binp;
+ int copy;
+ ErtsProc2PortSigData *sigdp;
+
+ sched_flags = erts_smp_atomic32_read_nob(&prt->sched.flags);
+ if (sched_flags & ERTS_PTS_FLG_EXIT)
+ return ERTS_PORT_OP_BADARG;
+
+ try_call = !(sched_flags & ERTS_PTS_FLGS_FORCE_SCHEDULE_OP);
+
+ if (is_binary(data) && binary_bitoffset(data) == 0) {
+ byte *bytep;
ERTS_DECLARE_DUMMY(Uint bitoffs);
ERTS_DECLARE_DUMMY(Uint bitsize);
- ERTS_GET_BINARY_BYTES(iolist, to_port, bitoffs, bitsize);
- to_len = binary_size(iolist);
+ ERTS_GET_BINARY_BYTES(data, bytep, bitoffs, bitsize);
+ bufp = (char *) bytep;
+ size = binary_size(data);
} else {
int r;
- /* Try with an 8KB buffer first (will often be enough I guess). */
- to_len = 8*1024;
- to_port = erts_alloc(ERTS_ALC_T_TMP, to_len);
- must_free = 1;
+ if (!try_call) {
+ if (erts_iolist_size(data, &size))
+ return ERTS_PORT_OP_BADARG;
+ bufp = erts_alloc(ERTS_ALC_T_DRV_CTRL_DATA, size);
+ r = erts_iolist_to_buf(data, bufp, size);
+ ASSERT(r == 0);
+ }
+ else {
+ /* Try with an 8KB buffer first (will often be enough I guess). */
+ size = 8*1024;
+ bufp = erts_alloc(ERTS_ALC_T_TMP, size);
+ tmp_alloced = 1;
+
+ r = erts_iolist_to_buf(data, bufp, size);
+ if (ERTS_IOLIST_TO_BUF_SUCCEEDED(r)) {
+ size -= r;
+ } else {
+ if (r == ERTS_IOLIST_TO_BUF_TYPE_ERROR) { /* Type error */
+ erts_free(ERTS_ALC_T_TMP, bufp);
+ return ERTS_PORT_OP_BADARG;
+ }
+ else {
+ ASSERT(r == ERTS_IOLIST_TO_BUF_OVERFLOW); /* Overflow */
+ erts_free(ERTS_ALC_T_TMP, bufp);
+ if (erts_iolist_size(data, &size))
+ return ERTS_PORT_OP_BADARG; /* Type error */
+ }
+ bufp = erts_alloc(ERTS_ALC_T_TMP, size);
+ r = erts_iolist_to_buf(data, bufp, size);
+ ASSERT(r == 0);
+ }
+ }
+ }
- /*
- * In versions before R10B, we used to reserve random
- * amounts of extra memory. From R10B, we allocate the
- * exact amount.
- */
- r = io_list_to_buf(iolist, (char*) to_port, to_len);
- if (r >= 0) {
- to_len -= r;
- } else if (r == -2) { /* Type error */
- erts_free(ERTS_ALC_T_TMP, (void *) to_port);
- return THE_NON_VALUE;
- } else {
- ASSERT(r == -1); /* Overflow */
- erts_free(ERTS_ALC_T_TMP, (void *) to_port);
- if (erts_iolist_size(iolist, &to_len)) { /* Type error */
- return THE_NON_VALUE;
+ if (try_call) {
+ char resp_buf[ERL_ONHEAP_BIN_LIMIT];
+ char* resp_bufp = &resp_buf[0];
+ ErlDrvSizeT resp_size = sizeof(resp_buf);
+ ErtsTryImmDrvCallResult try_call_res;
+ ErtsTryImmDrvCallState try_call_state
+ = ERTS_INIT_TRY_IMM_DRV_CALL_STATE(
+ c_p,
+ prt,
+ ERTS_PORT_SFLGS_INVALID_LOOKUP,
+ 0,
+ 0,
+ am_control);
+
+ try_call_res = try_imm_drv_call(&try_call_state);
+ switch (try_call_res) {
+ case ERTS_TRY_IMM_DRV_CALL_OK: {
+ Eterm *hp;
+ Uint hsz;
+ int control_flags;
+
+ res = call_driver_control(c_p->common.id,
+ prt,
+ command,
+ bufp,
+ size,
+ &resp_bufp,
+ &resp_size);
+ finalize_imm_drv_call(&try_call_state);
+ if (tmp_alloced)
+ erts_free(ERTS_ALC_T_TMP, bufp);
+ if (res == ERTS_PORT_OP_BADARG) {
+ return ERTS_PORT_OP_BADARG;
}
- must_free = 1;
- to_port = erts_alloc(ERTS_ALC_T_TMP, to_len);
- r = io_list_to_buf(iolist, (char*) to_port, to_len);
- ASSERT(r == 0);
+
+ control_flags = prt->control_flags;
+
+ hsz = port_control_result_size(control_flags,
+ resp_bufp,
+ &resp_size,
+ &resp_buf[0]);
+ hp = HAlloc(c_p, hsz);
+ *retvalp = write_port_control_result(control_flags,
+ resp_bufp,
+ resp_size,
+ &resp_buf[0],
+ &hp,
+ NULL,
+ &c_p->off_heap);
+ return ERTS_PORT_OP_DONE;
+ }
+ case ERTS_TRY_IMM_DRV_CALL_INVALID_PORT:
+ if (tmp_alloced)
+ erts_free(ERTS_ALC_T_TMP, bufp);
+ return ERTS_PORT_OP_BADARG;
+ default:
+ /* Schedule control() call instead... */
+ break;
}
}
- prt->caller = p->id; /* Internal pid */
+ /* Convert data into something that can be scheduled */
- erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN);
- ERTS_SMP_CHK_NO_PROC_LOCKS;
+ copy = tmp_alloced;
+
+ binp = NULL;
+
+ if (is_binary(data) && binary_bitoffset(data) == 0) {
+ Eterm *ebinp = binary_val_rel(data, NULL);
+ ASSERT(!tmp_alloced);
+ if (*ebinp == HEADER_SUB_BIN)
+ ebinp = binary_val_rel(((ErlSubBin *) ebinp)->orig, NULL);
+ if (*ebinp != HEADER_PROC_BIN)
+ copy = 1;
+ else {
+ binp = ((ProcBin *) ebinp)->val;
+ ASSERT(bufp < bufp + size);
+ ASSERT(binp->orig_bytes <= bufp
+ && bufp + size <= binp->orig_bytes + binp->orig_size);
+ erts_refc_inc(&binp->refc, 1);
+ }
+ }
+
+ if (copy) {
+ char *old_bufp = bufp;
+ bufp = erts_alloc(ERTS_ALC_T_DRV_CTRL_DATA, size);
+ sys_memcpy(bufp, old_bufp, size);
+ if (tmp_alloced)
+ erts_free(ERTS_ALC_T_TMP, old_bufp);
+ }
+
+ sigdp = erts_port_task_alloc_p2p_sig_data();
+ sigdp->flags = ERTS_P2P_SIG_TYPE_CONTROL;
+ sigdp->u.control.binp = binp;
+ sigdp->u.control.command = command;
+ sigdp->u.control.bufp = bufp;
+ sigdp->u.control.size = size;
+
+ res = erts_schedule_proc2port_signal(c_p,
+ prt,
+ c_p->common.id,
+ retvalp,
+ sigdp,
+ 0,
+ port_sig_control);
+ if (res != ERTS_PORT_OP_SCHEDULED) {
+ cleanup_scheduled_control(binp, bufp);
+ return ERTS_PORT_OP_BADARG;
+ }
+ return res;
+}
+
+static ERTS_INLINE ErtsPortOpResult
+call_driver_call(Eterm caller,
+ Port *prt,
+ unsigned int command,
+ char *bufp,
+ ErlDrvSizeT size,
+ char **resp_bufp,
+ ErlDrvSizeT *from_size,
+ unsigned *ret_flagsp)
+{
+ ErlDrvSSizeT cres;
+
+ if (!prt->drv_ptr->call)
+ return ERTS_PORT_OP_BADARG;
#ifdef USE_VM_PROBES
- if (DTRACE_ENABLED(port_control) || DTRACE_ENABLED(driver_control)) {
- DTRACE_FORMAT_COMMON_PROC_AND_PORT(p, prt);
- DTRACE4(port_control, process_str, port_str, prt->name, command);
- DTRACE5(driver_control, process_str, port_str, prt->name,
- command, to_len);
+ if (DTRACE_ENABLED(driver_call)) {
+ DTRACE_CHARBUF(process_str, DTRACE_TERM_BUF_SIZE);
+ DTRACE_CHARBUF(port_str, DTRACE_TERM_BUF_SIZE);
+
+ dtrace_pid_str(caller, process_str);
+ dtrace_port_str(prt, port_str);
+ DTRACE5(driver_call, process_str, port_str, prt->name, command, size);
}
#endif
- /*
- * Call the port's control routine.
- */
+ prt->caller = caller;
+ cres = prt->drv_ptr->call((ErlDrvData) prt->drv_data,
+ command,
+ bufp,
+ size,
+ resp_bufp,
+ *from_size,
+ ret_flagsp);
+ prt->caller = NIL;
- port_resp = port_result;
- fpe_was_unmasked = erts_block_fpe();
- n = control((ErlDrvData)prt->drv_data, command, (char*)to_port, to_len,
- &port_resp, sizeof(port_result));
- erts_unblock_fpe(fpe_was_unmasked);
- if (must_free) {
- erts_free(ERTS_ALC_T_TMP, (void *) to_port);
+ if (cres <= 0
+ || ((byte) (*resp_bufp)[0]) != VERSION_MAGIC)
+ return ERTS_PORT_OP_BADARG;
+
+ *from_size = (ErlDrvSizeT) cres;
+
+ return ERTS_PORT_OP_DONE;
+}
+
+
+static
+void cleanup_scheduled_call(char *bufp)
+{
+ if (bufp)
+ erts_free(ERTS_ALC_T_DRV_CALL_DATA, bufp);
+}
+
+static int
+port_sig_call(Port *prt,
+ erts_aint32_t state,
+ int op,
+ ErtsProc2PortSigData *sigdp)
+{
+ char resp_buf[256];
+ ErlDrvSizeT resp_size = sizeof(resp_buf);
+ char *resp_bufp = &resp_buf[0];
+ unsigned ret_flags = 0U;
+
+
+ ASSERT(sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY);
+
+ if (op == ERTS_PROC2PORT_SIG_EXEC) {
+ ErtsPortOpResult res;
+
+ res = call_driver_call(sigdp->caller,
+ prt,
+ sigdp->u.call.command,
+ sigdp->u.call.bufp,
+ sigdp->u.call.size,
+ &resp_bufp,
+ &resp_size,
+ &ret_flags);
+
+ if (res == ERTS_PORT_OP_DONE) {
+ Eterm msg;
+ Eterm *hp;
+ ErlHeapFragment *bp;
+ ErlOffHeap *ohp;
+ Process *rp;
+ ErtsProcLocks rp_locks = 0;
+ Uint hsz;
+
+ rp = erts_proc_lookup_raw(sigdp->caller);
+ if (!rp)
+ goto done;
+
+ hsz = erts_decode_ext_size((byte *) resp_bufp, resp_size);
+ if (hsz >= 0) {
+ Eterm *hp_start;
+ byte *endp;
+
+ hsz += 3; /* ok tuple */
+ hsz += ERTS_QUEUE_PORT_SCHED_OP_REPLY_SIZE;
+
+ hp_start = hp = erts_alloc_message_heap(hsz,
+ &bp,
+ &ohp,
+ rp,
+ &rp_locks);
+ endp = (byte *) resp_bufp;
+ msg = erts_decode_ext(&hp, ohp, &endp);
+ if (is_value(msg)) {
+ msg = TUPLE2(hp, am_ok, msg);
+ hp += 3;
+
+ queue_port_sched_op_reply(rp,
+ &rp_locks,
+ hp_start,
+ hp,
+ hsz,
+ bp,
+ sigdp->ref,
+ msg);
+
+ if (rp_locks)
+ erts_smp_proc_unlock(rp, rp_locks);
+ goto done;
+ }
+ if (bp)
+ free_message_buffer(bp);
+ if (rp_locks)
+ erts_smp_proc_unlock(rp, rp_locks);
+ }
+ }
}
- prt->caller = NIL;
-#ifdef ERTS_SMP
- if (prt->xports)
- erts_smp_xports_unlock(prt);
- ASSERT(!prt->xports);
-#endif
- erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN);
- /*
- * Handle the result.
- */
+ port_sched_op_reply(sigdp->caller, sigdp->ref, am_badarg);
+
+done:
+
+ if (resp_bufp != &resp_buf[0] && !(ret_flags & DRIVER_CALL_KEEP_BUFFER))
+ driver_free(resp_bufp);
+
+ cleanup_scheduled_call(sigdp->u.call.bufp);
+
+ return ERTS_PORT_REDS_CALL;
+}
+
+
+ErtsPortOpResult
+erts_port_call(Process* c_p,
+ Port *prt,
+ unsigned int command,
+ Eterm data,
+ Eterm *retvalp)
+{
+ ErtsPortOpResult res;
+ char input_buf[256];
+ char *bufp;
+ byte *endp;
+ ErlDrvSizeT size;
+ int try_call;
+ erts_aint32_t sched_flags;
+ ErtsProc2PortSigData *sigdp;
- if (n < 0) {
- return THE_NON_VALUE;
+ sched_flags = erts_smp_atomic32_read_nob(&prt->sched.flags);
+ if (sched_flags & ERTS_PTS_FLG_EXIT) {
+ return ERTS_PORT_OP_BADARG;
}
- if ((prt->control_flags & PORT_CONTROL_FLAG_BINARY) == 0) { /* List result */
- Eterm ret;
- Eterm* hp = HAlloc(p, 2*n);
- ret = buf_to_intlist(&hp, port_resp, n, NIL);
- if (port_resp != port_result) {
- driver_free(port_resp);
+ try_call = !(sched_flags & ERTS_PTS_FLGS_FORCE_SCHEDULE_OP);
+
+ size = erts_encode_ext_size(data);
+
+ if (!try_call)
+ bufp = erts_alloc(ERTS_ALC_T_DRV_CALL_DATA, size);
+ else if (size <= sizeof(input_buf))
+ bufp = &input_buf[0];
+ else
+ bufp = erts_alloc(ERTS_ALC_T_TMP, size);
+
+ endp = (byte *) bufp;
+ erts_encode_ext(data, &endp);
+
+ if (endp - (byte *) bufp > size)
+ ERTS_INTERNAL_ERROR("erts_internal:port_call() - Buffer overflow");
+
+ size = endp - (byte *) bufp;
+
+ if (try_call) {
+ char resp_buf[255];
+ char* resp_bufp = &resp_buf[0];
+ ErlDrvSizeT resp_size = sizeof(resp_buf);
+ ErtsTryImmDrvCallResult try_call_res;
+ ErtsTryImmDrvCallState try_call_state
+ = ERTS_INIT_TRY_IMM_DRV_CALL_STATE(
+ c_p,
+ prt,
+ ERTS_PORT_SFLGS_INVALID_LOOKUP,
+ 0,
+ 0,
+ am_call);
+
+ try_call_res = try_imm_drv_call(&try_call_state);
+ switch (try_call_res) {
+ case ERTS_TRY_IMM_DRV_CALL_OK: {
+ Eterm *hp, *hp_end;
+ Uint hsz;
+ unsigned ret_flags = 0U;
+ Eterm term;
+
+ res = call_driver_call(c_p->common.id,
+ prt,
+ command,
+ bufp,
+ size,
+ &resp_bufp,
+ &resp_size,
+ &ret_flags);
+
+ finalize_imm_drv_call(&try_call_state);
+ if (bufp != &input_buf[0])
+ erts_free(ERTS_ALC_T_TMP, bufp);
+ if (res == ERTS_PORT_OP_BADARG)
+ return ERTS_PORT_OP_BADARG;
+ hsz = erts_decode_ext_size((byte *) resp_bufp, resp_size);
+ if (hsz < 0)
+ return ERTS_PORT_OP_BADARG;
+ hsz += 3;
+ hp = HAlloc(c_p, hsz);
+ hp_end = hp + hsz;
+ endp = (byte *) resp_bufp;
+ term = erts_decode_ext(&hp, &MSO(c_p), &endp);
+ if (term == THE_NON_VALUE)
+ return ERTS_PORT_OP_BADARG;
+ *retvalp = TUPLE2(hp, am_ok, term);
+ hp += 3;
+ HRelease(c_p, hp_end, hp);
+ if (resp_buf != &resp_buf[0]
+ && !(ret_flags & DRIVER_CALL_KEEP_BUFFER))
+ driver_free(resp_buf);
+ return ERTS_PORT_OP_DONE;
}
- return ret;
- }
- else if (port_resp == NULL) {
- return NIL;
- }
- else { /* Binary result */
- ErlDrvBinary *dbin;
- ErlHeapBin *hbin;
- if (port_resp != port_result) {
- dbin = (ErlDrvBinary *) port_resp;
- if (dbin->orig_size > ERL_ONHEAP_BIN_LIMIT) {
- ProcBin* pb = (ProcBin *) HAlloc(p, PROC_BIN_SIZE);
- pb->thing_word = HEADER_PROC_BIN;
- pb->size = dbin->orig_size;
- pb->next = MSO(p).first;
- MSO(p).first = (struct erl_off_heap_header*)pb;
- pb->val = ErlDrvBinary2Binary(dbin);
- pb->bytes = (byte*) dbin->orig_bytes;
- pb->flags = 0;
- OH_OVERHEAD(&(MSO(p)), dbin->orig_size / sizeof(Eterm));
- return make_binary(pb);
- }
- port_resp = dbin->orig_bytes;
- n = dbin->orig_size;
- } else {
- dbin = NULL;
+ case ERTS_TRY_IMM_DRV_CALL_INVALID_PORT:
+ if (bufp != &input_buf[0])
+ erts_free(ERTS_ALC_T_TMP, bufp);
+ return ERTS_PORT_OP_BADARG;
+ default:
+ /* Schedule call() call instead... */
+ break;
}
- hbin = (ErlHeapBin*) HAlloc(p, heap_bin_size(n));
- ASSERT(n <= ERL_ONHEAP_BIN_LIMIT);
- hbin->thing_word = header_heap_bin(n);
- hbin->size = n;
- sys_memcpy(hbin->data, port_resp, n);
- if (dbin != NULL) {
- driver_free_binary(dbin);
+ }
+
+ /* Convert data into something that can be scheduled */
+
+ if (bufp == &input_buf[0] || try_call) {
+ char *new_bufp = erts_alloc(ERTS_ALC_T_DRV_CALL_DATA, size);
+ sys_memcpy(new_bufp, bufp, size);
+ if (bufp != &input_buf[0])
+ erts_free(ERTS_ALC_T_TMP, bufp);
+ bufp = new_bufp;
+ }
+
+ sigdp = erts_port_task_alloc_p2p_sig_data();
+ sigdp->flags = ERTS_P2P_SIG_TYPE_CALL;
+ sigdp->u.call.command = command;
+ sigdp->u.call.bufp = bufp;
+ sigdp->u.call.size = size;
+
+ res = erts_schedule_proc2port_signal(c_p,
+ prt,
+ c_p->common.id,
+ retvalp,
+ sigdp,
+ 0,
+ port_sig_call);
+ if (res != ERTS_PORT_OP_SCHEDULED) {
+ cleanup_scheduled_call(bufp);
+ return ERTS_PORT_OP_BADARG;
+ }
+ return res;
+}
+
+static Eterm
+make_port_info_term(Eterm **hpp_start,
+ Eterm **hpp,
+ Uint *hszp,
+ ErlHeapFragment **bpp,
+ Port *prt,
+ Eterm item)
+{
+ ErlOffHeap *ohp;
+
+ if (is_value(item)) {
+ if (erts_bld_port_info(NULL, NULL, hszp, prt, item) == am_false)
+ return THE_NON_VALUE;
+ if (*hszp) {
+ *bpp = new_message_buffer(*hszp);
+ *hpp_start = *hpp = (*bpp)->mem;
+ ohp = &(*bpp)->off_heap;
}
- return make_binary(hbin);
+ else {
+ *bpp = NULL;
+ *hpp_start = *hpp = NULL;
+ ohp = NULL;
+ }
+ return erts_bld_port_info(hpp, ohp, NULL, prt, item);
+ }
+ else {
+ int i;
+ int len;
+ int start;
+ static Eterm item[] = ERTS_PORT_INFO_1_ITEMS;
+ static Eterm value[sizeof(item)/sizeof(item[0])];
+
+ start = 0;
+ len = sizeof(item)/sizeof(item[0]);
+
+ for (i = start; i < sizeof(item)/sizeof(item[0]); i++) {
+ ASSERT(is_atom(item[i]));
+ value[i] = erts_bld_port_info(NULL, NULL, hszp, prt, item[i]);
+ }
+
+ if (value[0] == am_undefined) {
+ start++;
+ len--;
+ }
+
+ erts_bld_list(NULL, hszp, len, &value[start]);
+
+ *bpp = new_message_buffer(*hszp);
+ *hpp_start = *hpp = (*bpp)->mem;
+ ohp = &(*bpp)->off_heap;
+
+ for (i = start; i < sizeof(item)/sizeof(item[0]); i++)
+ value[i] = erts_bld_port_info(hpp, ohp, NULL, prt, item[i]);
+
+ return erts_bld_list(hpp, NULL, len, &value[start]);
+ }
+}
+
+static int
+port_sig_info(Port *prt,
+ erts_aint32_t state,
+ int op,
+ ErtsProc2PortSigData *sigdp)
+{
+ ASSERT(sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY);
+ if (op != ERTS_PROC2PORT_SIG_EXEC)
+ port_sched_op_reply(sigdp->caller, sigdp->ref, am_undefined);
+ else {
+ Eterm *hp, *hp_start;
+ Uint hsz;
+ ErlHeapFragment *bp;
+ Eterm value;
+ Process *rp;
+ ErtsProcLocks rp_locks = 0;
+
+ rp = erts_proc_lookup_raw(sigdp->caller);
+ if (!rp)
+ return ERTS_PORT_REDS_INFO;
+
+ hsz = ERTS_QUEUE_PORT_SCHED_OP_REPLY_SIZE;
+ value = make_port_info_term(&hp_start,
+ &hp,
+ &hsz,
+ &bp,
+ prt,
+ sigdp->u.info.item);
+ if (is_value(value)) {
+ queue_port_sched_op_reply(rp,
+ &rp_locks,
+ hp_start,
+ hp,
+ hsz,
+ bp,
+ sigdp->ref,
+ value);
+ }
+ if (rp_locks)
+ erts_smp_proc_unlock(rp, rp_locks);
+ }
+ return ERTS_PORT_REDS_INFO;
+}
+
+ErtsPortOpResult
+erts_port_info(Process* c_p,
+ Port *prt,
+ Eterm item,
+ Eterm *retvalp)
+{
+ ErtsProc2PortSigData *sigdp;
+ ErtsTryImmDrvCallResult try_call_res;
+ ErtsTryImmDrvCallState try_call_state
+ = ERTS_INIT_TRY_IMM_DRV_CALL_STATE(
+ c_p,
+ prt,
+ ERTS_PORT_SFLGS_INVALID_LOOKUP,
+ 0,
+ 0,
+ am_info);
+
+ try_call_res = try_imm_drv_call(&try_call_state);
+ switch (try_call_res) {
+ case ERTS_TRY_IMM_DRV_CALL_OK: {
+ Eterm *hp, *hp_start;
+ ErlHeapFragment *bp;
+ Uint hsz = 0;
+ Eterm value = make_port_info_term(&hp_start, &hp, &hsz, &bp, prt, item);
+ finalize_imm_drv_call(&try_call_state);
+ if (is_non_value(value))
+ return ERTS_PORT_OP_BADARG;
+ else if (is_immed(value))
+ *retvalp = value;
+ else {
+ Uint used_h_size = hp - hp_start;
+ hp = HAlloc(c_p, used_h_size);
+ *retvalp = copy_struct(value, used_h_size, &hp, &MSO(c_p));
+ free_message_buffer(bp);
+ }
+ return ERTS_PORT_OP_DONE;
+ }
+ case ERTS_TRY_IMM_DRV_CALL_INVALID_PORT:
+ return ERTS_PORT_OP_DROPPED;
+ case ERTS_TRY_IMM_DRV_CALL_INVALID_SCHED_FLAGS:
+ case ERTS_TRY_IMM_DRV_CALL_BUSY_LOCK:
+ /* Schedule call instead... */
+ break;
+ }
+
+ sigdp = erts_port_task_alloc_p2p_sig_data();
+ sigdp->flags = ERTS_P2P_SIG_TYPE_INFO;
+ sigdp->u.info.item = item;
+
+ return erts_schedule_proc2port_signal(c_p,
+ prt,
+ c_p->common.id,
+ retvalp,
+ sigdp,
+ 0,
+ port_sig_info);
+}
+
+static int
+port_sig_set_data(Port *prt,
+ erts_aint32_t state,
+ int op,
+ ErtsProc2PortSigData *sigdp)
+{
+ ASSERT(sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY);
+
+ if (op == ERTS_PROC2PORT_SIG_EXEC) {
+ if (prt->bp)
+ free_message_buffer(prt->bp);
+ prt->bp = sigdp->u.set_data.bp;
+ prt->data = sigdp->u.set_data.data;
+ port_sched_op_reply(sigdp->caller, sigdp->ref, am_true);
+ }
+ else {
+ if (sigdp->u.set_data.bp)
+ free_message_buffer(sigdp->u.set_data.bp);
+ port_sched_op_reply(sigdp->caller, sigdp->ref, am_badarg);
+ }
+ return ERTS_PORT_REDS_SET_DATA;
+}
+
+ErtsPortOpResult
+erts_port_set_data(Process* c_p,
+ Port *prt,
+ Eterm data,
+ Eterm *refp)
+{
+ ErtsPortOpResult res;
+ Eterm set_data;
+ ErlHeapFragment *bp;
+ ErtsProc2PortSigData *sigdp;
+ ErtsTryImmDrvCallResult try_call_res;
+ ErtsTryImmDrvCallState try_call_state
+ = ERTS_INIT_TRY_IMM_DRV_CALL_STATE(
+ c_p,
+ prt,
+ ERTS_PORT_SFLGS_INVALID_LOOKUP,
+ 0,
+ !refp,
+ am_set_data);
+
+ if (is_immed(data)) {
+ set_data = data;
+ bp = NULL;
+ }
+ else {
+ Eterm *hp;
+ Uint sz = size_object(data);
+ bp = new_message_buffer(sz);
+ hp = bp->mem;
+ set_data = copy_struct(data, sz, &hp, &bp->off_heap);
+ }
+
+ try_call_res = try_imm_drv_call(&try_call_state);
+ switch (try_call_res) {
+ case ERTS_TRY_IMM_DRV_CALL_OK:
+ if (prt->bp)
+ free_message_buffer(prt->bp);
+ prt->bp = bp;
+ prt->data = set_data;
+ finalize_imm_drv_call(&try_call_state);
+ return ERTS_PORT_OP_DONE;
+ case ERTS_TRY_IMM_DRV_CALL_INVALID_PORT:
+ return ERTS_PORT_OP_DROPPED;
+ case ERTS_TRY_IMM_DRV_CALL_INVALID_SCHED_FLAGS:
+ case ERTS_TRY_IMM_DRV_CALL_BUSY_LOCK:
+ /* Schedule call instead... */
+ break;
+ }
+
+ sigdp = erts_port_task_alloc_p2p_sig_data();
+ sigdp->flags = ERTS_P2P_SIG_TYPE_SET_DATA;
+ sigdp->u.set_data.data = set_data;
+ sigdp->u.set_data.bp = bp;
+
+ res = erts_schedule_proc2port_signal(c_p,
+ prt,
+ c_p->common.id,
+ refp,
+ sigdp,
+ 0,
+ port_sig_set_data);
+ if (res != ERTS_PORT_OP_SCHEDULED && bp)
+ free_message_buffer(bp);
+ return res;
+}
+
+static int
+port_sig_get_data(Port *prt,
+ erts_aint32_t state,
+ int op,
+ ErtsProc2PortSigData *sigdp)
+{
+ ASSERT(sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY);
+ if (op != ERTS_PROC2PORT_SIG_EXEC)
+ port_sched_op_reply(sigdp->caller, sigdp->ref, am_badarg);
+ else {
+ Process *rp;
+ ErtsProcLocks rp_locks = 0;
+
+ rp = erts_proc_lookup_raw(sigdp->caller);
+ if (rp) {
+ Uint hsz;
+ Eterm *hp, *hp_start;
+ Eterm data, msg;
+ ErlHeapFragment *bp;
+ ErlOffHeap *ohp;
+
+ hsz = ERTS_QUEUE_PORT_SCHED_OP_REPLY_SIZE;
+ hsz += 3;
+ if (prt->bp)
+ hsz += prt->bp->used_size;
+
+ hp_start = hp = erts_alloc_message_heap(hsz,
+ &bp,
+ &ohp,
+ rp,
+ &rp_locks);
+
+ if (is_immed(prt->data))
+ data = prt->data;
+ else
+ data = copy_struct(prt->data,
+ prt->bp->used_size,
+ &hp,
+ &bp->off_heap);
+
+
+
+ msg = TUPLE2(hp, am_ok, data);
+ hp += 3;
+
+ queue_port_sched_op_reply(rp,
+ &rp_locks,
+ hp_start,
+ hp,
+ hsz,
+ bp,
+ sigdp->ref,
+ msg);
+ if (rp_locks)
+ erts_smp_proc_unlock(rp, rp_locks);
+ }
+ }
+ return ERTS_PORT_REDS_GET_DATA;
+}
+
+ErtsPortOpResult
+erts_port_get_data(Process* c_p,
+ Port *prt,
+ Eterm *retvalp)
+{
+ ErtsProc2PortSigData *sigdp;
+ ErtsTryImmDrvCallResult try_call_res;
+ ErtsTryImmDrvCallState try_call_state
+ = ERTS_INIT_TRY_IMM_DRV_CALL_STATE(
+ c_p,
+ prt,
+ ERTS_PORT_SFLGS_INVALID_LOOKUP,
+ 0,
+ 0,
+ am_get_data);
+
+ try_call_res = try_imm_drv_call(&try_call_state);
+ switch (try_call_res) {
+ case ERTS_TRY_IMM_DRV_CALL_OK: {
+ Eterm *hp;
+ Eterm data;
+ ErlHeapFragment *bp;
+ Uint sz;
+ if (is_immed(prt->data)) {
+ bp = NULL;
+ data = prt->data;
+ }
+ else {
+ bp = new_message_buffer(prt->bp->used_size);
+ data = copy_struct(prt->data,
+ prt->bp->used_size,
+ &hp,
+ &bp->off_heap);
+ }
+ finalize_imm_drv_call(&try_call_state);
+ if (is_immed(data))
+ sz = 0;
+ else
+ sz = bp->used_size;
+
+ hp = HAlloc(c_p, sz + 3);
+ if (is_not_immed(data)) {
+ data = copy_struct(data, bp->used_size, &hp, &MSO(c_p));
+ free_message_buffer(bp);
+ }
+ *retvalp = TUPLE2(hp, am_ok, data);
+ return ERTS_PORT_OP_DONE;
+ }
+ case ERTS_TRY_IMM_DRV_CALL_INVALID_PORT:
+ return ERTS_PORT_OP_DROPPED;
+ case ERTS_TRY_IMM_DRV_CALL_INVALID_SCHED_FLAGS:
+ case ERTS_TRY_IMM_DRV_CALL_BUSY_LOCK:
+ /* Schedule call instead... */
+ break;
}
+
+ sigdp = erts_port_task_alloc_p2p_sig_data();
+ sigdp->flags = ERTS_P2P_SIG_TYPE_GET_DATA;
+
+ return erts_schedule_proc2port_signal(c_p,
+ prt,
+ c_p->common.id,
+ retvalp,
+ sigdp,
+ 0,
+ port_sig_get_data);
}
typedef struct {
@@ -2480,39 +4681,39 @@ static void prt_one_lnk(ErtsLink *lnk, void *vprtd)
}
void
-print_port_info(int to, void *arg, int i)
+print_port_info(Port *p, int to, void *arg)
{
- Port* p = &erts_port[i];
+ erts_aint32_t state = erts_atomic32_read_nob(&p->state);
- if (p->status & ERTS_PORT_SFLGS_DEAD)
+ if (state & ERTS_PORT_SFLGS_DEAD)
return;
- erts_print(to, arg, "=port:%T\n", p->id);
- erts_print(to, arg, "Slot: %d\n", i);
- if (p->status & ERTS_PORT_SFLG_CONNECTED) {
- erts_print(to, arg, "Connected: %T", p->connected);
+ erts_print(to, arg, "=port:%T\n", p->common.id);
+ erts_print(to, arg, "Slot: %d\n", internal_port_index(p->common.id));
+ if (state & ERTS_PORT_SFLG_CONNECTED) {
+ erts_print(to, arg, "Connected: %T", ERTS_PORT_GET_CONNECTED(p));
erts_print(to, arg, "\n");
}
- if (p->nlinks != NULL) {
+ if (ERTS_P_LINKS(p)) {
prt_one_lnk_data prtd;
prtd.to = to;
prtd.arg = arg;
erts_print(to, arg, "Links: ");
- erts_doforall_links(p->nlinks, &prt_one_lnk, &prtd);
+ erts_doforall_links(ERTS_P_LINKS(p), &prt_one_lnk, &prtd);
erts_print(to, arg, "\n");
}
- if (p->monitors != NULL) {
+ if (ERTS_P_MONITORS(p)) {
prt_one_lnk_data prtd;
prtd.to = to;
prtd.arg = arg;
erts_print(to, arg, "Monitors: ");
- erts_doforall_monitors(p->monitors, &prt_one_monitor, &prtd);
+ erts_doforall_monitors(ERTS_P_MONITORS(p), &prt_one_monitor, &prtd);
erts_print(to, arg, "\n");
}
- if (p->reg != NULL)
- erts_print(to, arg, "Registered as: %T\n", p->reg->name);
+ if (p->common.u.alive.reg != NULL)
+ erts_print(to, arg, "Registered as: %T\n", p->common.u.alive.reg->name);
if (p->drv_ptr == &fd_driver) {
erts_print(to, arg, "Port is UNIX fd not opened by emulator: %s\n", p->name);
@@ -2526,109 +4727,143 @@ print_port_info(int to, void *arg, int i)
}
void
-set_busy_port(ErlDrvPort port_num, int on)
+set_busy_port(ErlDrvPort dprt, int on)
{
+ Port *prt;
+ erts_aint32_t flags;
+
#ifdef USE_VM_PROBES
DTRACE_CHARBUF(port_str, 16);
#endif
ERTS_SMP_CHK_NO_PROC_LOCKS;
- ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(&erts_port[port_num]));
+ prt = erts_drvport2port_raw(dprt);
+ if (!prt)
+ return;
if (on) {
- erts_port_status_bor_set(&erts_port[port_num],
- ERTS_PORT_SFLG_PORT_BUSY);
+ flags = erts_smp_atomic32_read_bor_acqb(&prt->sched.flags,
+ ERTS_PTS_FLG_BUSY_PORT);
+ if (flags & ERTS_PTS_FLG_BUSY_PORT)
+ return; /* Already busy */
+
+ if (flags & ERTS_PTS_FLG_HAVE_NS_TASKS)
+ erts_port_task_abort_nosuspend_tasks(prt);
+
#ifdef USE_VM_PROBES
if (DTRACE_ENABLED(port_busy)) {
erts_snprintf(port_str, sizeof(port_str),
- "%T", erts_port[port_num].id);
+ "%T", prt->common.id);
DTRACE1(port_busy, port_str);
}
#endif
} else {
- ErtsProcList* plp = erts_port[port_num].suspended;
- erts_port_status_band_set(&erts_port[port_num],
- ~ERTS_PORT_SFLG_PORT_BUSY);
- erts_port[port_num].suspended = NULL;
+ flags = erts_smp_atomic32_read_band_acqb(&prt->sched.flags,
+ ~ERTS_PTS_FLG_BUSY_PORT);
+ if (!(flags & ERTS_PTS_FLG_BUSY_PORT))
+ return; /* Already non-busy */
#ifdef USE_VM_PROBES
if (DTRACE_ENABLED(port_not_busy)) {
erts_snprintf(port_str, sizeof(port_str),
- "%T", erts_port[port_num].id);
+ "%T", prt->common.id);
DTRACE1(port_not_busy, port_str);
}
#endif
- if (erts_port[port_num].dist_entry) {
+ if (prt->dist_entry) {
/*
* Processes suspended on distribution ports are
* normally queued on the dist entry.
*/
- erts_dist_port_not_busy(&erts_port[port_num]);
+ erts_dist_port_not_busy(prt);
}
- /*
- * Resume, in a round-robin fashion, all processes waiting on the port.
- *
- * This version submitted by Tony Rogvall. The earlier version used
- * to resume the processes in order, which caused starvation of all but
- * the first process.
- */
+ if (!(flags & ERTS_PTS_FLG_BUSY_PORT_Q))
+ erts_port_resume_procs(prt);
+ }
+}
+
+void
+erts_port_resume_procs(Port *prt)
+{
+ /*
+ * Resume, in a round-robin fashion, all processes waiting on the port.
+ *
+ * This version submitted by Tony Rogvall. The earlier version used
+ * to resume the processes in order, which caused starvation of all but
+ * the first process.
+ */
+ ErtsProcList *plp;
+
+ erts_port_task_sched_lock(&prt->sched);
+ plp = prt->suspended;
+ prt->suspended = NULL;
+ erts_port_task_sched_unlock(&prt->sched);
+
+ if (erts_proclist_fetch(&plp, NULL)) {
- if (plp) {
#ifdef USE_VM_PROBES
- /*
- * Hrm, for blocked dist ports, plp always seems to be NULL.
- * That's not so fun.
- * Well, another way to get the same info is using a D
- * script to correlate an earlier process-port_blocked+pid
- * event with a later process-scheduled event. That's
- * subject to the multi-CPU races with how events are
- * handled, but hey, that way works most of the time.
- */
- if (DTRACE_ENABLED(process_port_unblocked)) {
- DTRACE_CHARBUF(pid_str, 16);
- ErtsProcList* plp2 = plp;
-
- erts_snprintf(port_str, sizeof(port_str),
- "%T", erts_port[port_num]);
- while (plp2 != NULL) {
- erts_snprintf(pid_str, sizeof(pid_str), "%T", plp2->pid);
- DTRACE2(process_port_unblocked, pid_str, port_str);
- }
- }
-#endif
- /* First proc should be resumed last */
- if (plp->next) {
- erts_resume_processes(plp->next);
- plp->next = NULL;
+ /*
+ * Hrm, for blocked dist ports, plp always seems to be NULL.
+ * That's not so fun.
+ * Well, another way to get the same info is using a D
+ * script to correlate an earlier process-port_blocked+pid
+ * event with a later process-scheduled event. That's
+ * subject to the multi-CPU races with how events are
+ * handled, but hey, that way works most of the time.
+ */
+ if (DTRACE_ENABLED(process_port_unblocked)) {
+ DTRACE_CHARBUF(port_str, 16);
+ DTRACE_CHARBUF(pid_str, 16);
+ ErtsProcList* plp2 = plp;
+
+ erts_snprintf(port_str, sizeof(port_str), "%T", prt->common.id);
+ while (plp2 != NULL) {
+ erts_snprintf(pid_str, sizeof(pid_str), "%T", plp2->pid);
+ DTRACE2(process_port_unblocked, pid_str, port_str);
}
- erts_resume_processes(plp);
- }
+ }
+#endif
+
+ /* First proc should be resumed last */
+ if (plp->next) {
+ plp->next->prev = NULL;
+ erts_resume_processes(plp->next);
+ plp->next = NULL;
+ }
+ erts_resume_processes(plp);
}
}
void set_port_control_flags(ErlDrvPort port_num, int flags)
{
-
- ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(&erts_port[port_num]));
-
- erts_port[port_num].control_flags = flags;
+ Port *prt = erts_drvport2port_raw(port_num);
+ if (prt)
+ prt->control_flags = flags;
}
-int get_port_flags(ErlDrvPort ix) {
- Port* prt = erts_drvport2port(ix);
+int get_port_flags(ErlDrvPort ix)
+{
+ int flags;
+ Port *prt;
+ erts_aint32_t state;
+
+ prt = erts_drvport2port(ix, &state);
+ if (!prt)
+ return 0;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
- if (prt == NULL)
- return 0;
+ flags = 0;
+ if (state & ERTS_PORT_SFLG_BINARY_IO)
+ flags |= PORT_FLAG_BINARY;
+ if (state & ERTS_PORT_SFLG_LINEBUF_IO)
+ flags |= PORT_FLAG_LINE;
- return (prt->status & ERTS_PORT_SFLG_BINARY_IO ? PORT_FLAG_BINARY : 0)
- | (prt->status & ERTS_PORT_SFLG_LINEBUF_IO ? PORT_FLAG_LINE : 0);
+ return flags;
}
-
void erts_raw_port_command(Port* p, byte* buf, Uint len)
{
int fpe_was_unmasked;
@@ -2665,25 +4900,18 @@ int async_ready(Port *p, void* data)
if (p) {
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(p));
- ASSERT(!(p->status & ERTS_PORT_SFLGS_DEAD));
if (p->drv_ptr->ready_async != NULL) {
#ifdef USE_VM_PROBES
if (DTRACE_ENABLED(driver_ready_async)) {
- DTRACE_FORMAT_COMMON_PID_AND_PORT(p->connected, p)
+ DTRACE_FORMAT_COMMON_PID_AND_PORT(ERTS_PORT_GET_CONNECTED(p), p)
DTRACE3(driver_ready_async, process_str, port_str, p->name);
}
#endif
(*p->drv_ptr->ready_async)((ErlDrvData)p->drv_data, data);
need_free = 0;
-#ifdef ERTS_SMP
- if (p->xports)
- erts_smp_xports_unlock(p);
- ASSERT(!p->xports);
-#endif
- }
- if ((p->status & ERTS_PORT_SFLG_CLOSING) && is_port_ioq_empty(p)) {
- terminate_port(p);
+
}
+ erts_port_driver_callback_epilogue(p, NULL);
}
return need_free;
}
@@ -2691,12 +4919,12 @@ int async_ready(Port *p, void* data)
static void
report_missing_drv_callback(Port *p, char *drv_type, char *callback)
{
- ErtsPortNames *pnp = erts_get_port_names(p->id);
+ ErtsPortNames *pnp = erts_get_port_names(p->common.id);
char *unknown = "<unknown>";
char *drv_name = pnp->driver_name ? pnp->driver_name : unknown;
char *prt_name = pnp->name ? pnp->name : unknown;
erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
- erts_dsprintf(dsbufp, "%T: %s driver '%s' ", p->id, drv_type, drv_name);
+ erts_dsprintf(dsbufp, "%T: %s driver '%s' ", p->common.id, drv_type, drv_name);
if (sys_strcmp(drv_name, prt_name) != 0)
erts_dsprintf(dsbufp, "(%s) ", prt_name);
erts_dsprintf(dsbufp, "does not implement the %s callback!\n", callback);
@@ -2711,7 +4939,7 @@ erts_stale_drv_select(Eterm port,
int deselect)
{
char *type;
- ErlDrvPort drv_port = internal_port_index(port);
+ ErlDrvPort drv_port = (ErlDrvPort) erts_port_lookup_raw(port);
ErtsPortNames *pnp = erts_get_port_names(port);
erts_dsprintf_buf_t *dsbufp;
@@ -2751,16 +4979,16 @@ erts_stale_drv_select(Eterm port,
ErtsPortNames *
erts_get_port_names(Eterm id)
{
+ Port *prt = erts_port_lookup_raw(id);
ErtsPortNames *pnp;
ASSERT(is_nil(id) || is_internal_port(id));
-
- if (is_not_internal_port(id)) {
+
+ if (!prt) {
pnp = erts_alloc(ERTS_ALC_T_PORT_NAMES, sizeof(ErtsPortNames));
pnp->name = NULL;
pnp->driver_name = NULL;
}
else {
- Port* prt = &erts_port[internal_port_index(id)];
int do_realloc = 1;
int len = -1;
size_t pnp_len = sizeof(ErtsPortNames);
@@ -2776,17 +5004,10 @@ erts_get_port_names(Eterm id)
pnp_len = sizeof(ErtsPortNames) + len;
pnp = erts_alloc(ERTS_ALC_T_PORT_NAMES, pnp_len);
}
- erts_smp_port_state_lock(prt);
- if (id != prt->id) {
- len = nlen = 0;
- name = driver_name = NULL;
- }
- else {
- name = prt->name;
- len = nlen = name ? sys_strlen(name) + 1 : 0;
- driver_name = (prt->drv_ptr ? prt->drv_ptr->name : NULL);
- len += driver_name ? sys_strlen(driver_name) + 1 : 0;
- }
+ name = prt->name;
+ len = nlen = name ? sys_strlen(name) + 1 : 0;
+ driver_name = (prt->drv_ptr ? prt->drv_ptr->name : NULL);
+ len += driver_name ? sys_strlen(driver_name) + 1 : 0;
if (len <= pnp_len - sizeof(ErtsPortNames)) {
if (!name)
pnp->name = NULL;
@@ -2804,7 +5025,6 @@ erts_get_port_names(Eterm id)
}
do_realloc = 0;
}
- erts_smp_port_state_unlock(prt);
} while (do_realloc);
}
return pnp;
@@ -2829,11 +5049,9 @@ static void schedule_port_timeout(Port *p)
* /Rickard
*/
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(p));
- (void) erts_port_task_schedule(p->id,
- &p->timeout_task,
- ERTS_PORT_TASK_TIMEOUT,
- (ErlDrvEvent) -1,
- NULL);
+ erts_port_task_schedule(p->common.id,
+ &p->timeout_task,
+ ERTS_PORT_TASK_TIMEOUT);
}
ErlDrvTermData driver_mk_term_nil(void)
@@ -2841,9 +5059,9 @@ ErlDrvTermData driver_mk_term_nil(void)
return driver_term_nil;
}
-void driver_report_exit(int ix, int status)
+void driver_report_exit(ErlDrvPort ix, int status)
{
- Port* prt = erts_drvport2port(ix);
+ Port* prt = erts_drvport2port(ix, NULL);
Eterm* hp;
Eterm tuple;
Process *rp;
@@ -2856,7 +5074,7 @@ void driver_report_exit(int ix, int status)
ERTS_SMP_CHK_NO_PROC_LOCKS;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
- pid = prt->connected;
+ pid = ERTS_PORT_GET_CONNECTED(prt);
ASSERT(is_internal_pid(pid));
rp = (scheduler
@@ -2869,7 +5087,7 @@ void driver_report_exit(int ix, int status)
tuple = TUPLE2(hp, am_exit_status, make_small(status));
hp += 3;
- tuple = TUPLE2(hp, prt->id, tuple);
+ tuple = TUPLE2(hp, prt->common.id, tuple);
erts_queue_message(rp, &rp_locks, bp, tuple, am_undefined
#ifdef USE_VM_PROBES
@@ -2882,28 +5100,6 @@ void driver_report_exit(int ix, int status)
erts_smp_proc_dec_refc(rp);
}
-
-static ERTS_INLINE int
-deliver_term_check_port(ErlDrvPort drvport)
-{
- int res;
- int ix = (int) drvport;
- if (ix < 0 || erts_max_ports <= ix)
- res = -1; /* invalid */
- else {
- Port* prt = &erts_port[ix];
- erts_smp_port_state_lock(prt);
- if (!(prt->status & ERTS_PORT_SFLGS_INVALID_LOOKUP))
- res = 1; /* ok */
- else if (prt->status & ERTS_PORT_SFLG_CLOSING)
- res = 0; /* closing */
- else
- res = -1; /* invalid (dead) */
- erts_smp_port_state_unlock(prt);
- }
- return res;
-}
-
#define ERTS_B2T_STATES_DEF_STATES_SZ 5
#define ERTS_B2T_STATES_DEF_STATES_INC 100
@@ -2991,10 +5187,7 @@ cleanup_b2t_states(struct b2t_states__ *b2tsp)
*/
static int
-driver_deliver_term(ErlDrvPort port,
- Eterm to,
- ErlDrvTermData* data,
- int len)
+driver_deliver_term(Eterm to, ErlDrvTermData* data, int len)
{
#define ERTS_DDT_FAIL do { res = -1; goto done; } while (0)
Uint need = 0;
@@ -3196,11 +5389,8 @@ driver_deliver_term(ErlDrvPort port,
b2t.ix = 0;
/*
- * The term is OK. Go ahead and validate the port and process.
+ * The term is OK. Go ahead and validate the process.
*/
- res = deliver_term_check_port(port);
- if (res <= 0)
- goto done;
/*
* Increase refc on proc if done from a non-scheduler thread.
@@ -3470,25 +5660,115 @@ driver_deliver_term(ErlDrvPort port,
#undef ERTS_DDT_FAIL
}
+static ERTS_INLINE int
+deliver_term_check_port(ErlDrvTermData port_id, Eterm *connected_p)
+{
+#ifdef ERTS_SMP
+ ErtsThrPrgrDelayHandle dhndl = erts_thr_progress_unmanaged_delay();
+#endif
+ Port *prt = erts_port_lookup_raw((Eterm) port_id);
+ erts_aint32_t state = erts_atomic32_read_nob(&prt->state);
+ if (connected_p) {
+#ifdef ERTS_SMP
+ if (dhndl != ERTS_THR_PRGR_DHANDLE_MANAGED)
+ ETHR_MEMBAR(ETHR_LoadLoad);
+#endif
+ *connected_p = ERTS_PORT_GET_CONNECTED(prt);
+ }
+#ifdef ERTS_SMP
+ if (dhndl != ERTS_THR_PRGR_DHANDLE_MANAGED) {
+ erts_thr_progress_unmanaged_continue(dhndl);
+ ETHR_MEMBAR(ETHR_LoadLoad|ETHR_LoadStore);
+ }
+#endif
+ ERTS_SMP_LC_ASSERT(dhndl == ERTS_THR_PRGR_DHANDLE_MANAGED
+ ? erts_lc_is_port_locked(prt)
+ : !erts_lc_is_port_locked(prt));
+ return ((state & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP)
+ ? -1
+ : ((state & ERTS_PORT_SFLG_CLOSING) ? 0 : 1));
+}
+
+int erl_drv_output_term(ErlDrvTermData port_id, ErlDrvTermData* data, int len)
+{
+ /* May be called from arbitrary thread */
+ Eterm connected;
+ int res = deliver_term_check_port(port_id, &connected);
+ if (res <= 0)
+ return res;
+ return driver_deliver_term(connected, data, len);
+}
+/*
+ * driver_output_term() is deprecated, and has been scheduled for
+ * removal in OTP-R17. It is replaced by erl_drv_output_term()
+ * above.
+ */
int
-driver_output_term(ErlDrvPort ix, ErlDrvTermData* data, int len)
+driver_output_term(ErlDrvPort drvport, ErlDrvTermData* data, int len)
{
- Port* prt = erts_drvport2port(ix);
+ erts_aint32_t state;
+ Port* prt;
ERTS_SMP_CHK_NO_PROC_LOCKS;
+ /* NOTE! It *not* safe to access 'drvport' from unmanaged threads. */
+ prt = erts_drvport2port(drvport, &state);
+ if (!prt)
+ return -1; /* invalid (dead) */
+ ERTS_SMP_CHK_NO_PROC_LOCKS;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
-
- if (prt == NULL)
+ if (state & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP)
return -1;
- return driver_deliver_term(ix, prt->connected, data, len);
+ else if (state & ERTS_PORT_SFLG_CLOSING)
+ return 0;
+
+ return driver_deliver_term(ERTS_PORT_GET_CONNECTED(prt), data, len);
}
+int erl_drv_send_term(ErlDrvTermData port_id,
+ ErlDrvTermData to,
+ ErlDrvTermData* data,
+ int len)
+{
+ /* May be called from arbitrary thread */
+ int res = deliver_term_check_port(port_id, NULL);
+ if (res <= 0)
+ return res;
+ return driver_deliver_term(to, data, len);
+}
+/*
+ * driver_send_term() is deprecated, and has been scheduled for
+ * removal in OTP-R17. It is replaced by erl_drv_send_term() above.
+ */
int
-driver_send_term(ErlDrvPort ix, ErlDrvTermData to, ErlDrvTermData* data, int len)
+driver_send_term(ErlDrvPort drvport,
+ ErlDrvTermData to,
+ ErlDrvTermData* data,
+ int len)
{
- return driver_deliver_term(ix, to, data, len);
+ /*
+ * NOTE! It is *not* safe to access the 'drvport' parameter
+ * from unmanaged threads. Also note that it is impossible
+ * to make this access safe without using a less efficient
+ * internal data representation for ErlDrvPort.
+ */
+ ERTS_SMP_CHK_NO_PROC_LOCKS;
+#ifdef ERTS_SMP
+ if (erts_thr_progress_is_managed_thread())
+#endif
+ {
+ erts_aint32_t state;
+ Port* prt = erts_drvport2port(drvport, &state);
+ if (!prt)
+ return -1; /* invalid (dead) */
+ ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
+ if (state & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP)
+ return -1;
+ else if (state & ERTS_PORT_SFLG_CLOSING)
+ return 0;
+ }
+ return driver_deliver_term(to, data, len);
}
@@ -3500,26 +5780,27 @@ driver_send_term(ErlDrvPort ix, ErlDrvTermData to, ErlDrvTermData* data, int len
int driver_output_binary(ErlDrvPort ix, char* hbuf, ErlDrvSizeT hlen,
ErlDrvBinary* bin, ErlDrvSizeT offs, ErlDrvSizeT len)
{
- Port* prt = erts_drvport2port(ix);
+ erts_aint32_t state;
+ Port* prt = erts_drvport2port(ix, &state);
ERTS_SMP_CHK_NO_PROC_LOCKS;
if (prt == NULL)
return -1;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
- if (prt->status & ERTS_PORT_SFLG_CLOSING)
+ if (state & ERTS_PORT_SFLG_CLOSING)
return 0;
prt->bytes_in += (hlen + len);
erts_smp_atomic_add_nob(&erts_bytes_in, (erts_aint_t) (hlen + len));
- if (prt->status & ERTS_PORT_SFLG_DISTRIBUTION) {
+ if (state & ERTS_PORT_SFLG_DISTRIBUTION) {
return erts_net_message(prt,
prt->dist_entry,
(byte*) hbuf, hlen,
(byte*) (bin->orig_bytes+offs), len);
}
else
- deliver_bin_message(prt, prt->connected,
+ deliver_bin_message(prt, ERTS_PORT_GET_CONNECTED(prt),
hbuf, hlen, bin, offs, len);
return 0;
}
@@ -3534,7 +5815,8 @@ int driver_output_binary(ErlDrvPort ix, char* hbuf, ErlDrvSizeT hlen,
int driver_output2(ErlDrvPort ix, char* hbuf, ErlDrvSizeT hlen,
char* buf, ErlDrvSizeT len)
{
- Port* prt = erts_drvport2port(ix);
+ erts_aint32_t state;
+ Port* prt = erts_drvport2port(ix, &state);
ERTS_SMP_CHK_NO_PROC_LOCKS;
@@ -3543,12 +5825,12 @@ int driver_output2(ErlDrvPort ix, char* hbuf, ErlDrvSizeT hlen,
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
- if (prt->status & ERTS_PORT_SFLG_CLOSING)
+ if (state & ERTS_PORT_SFLG_CLOSING)
return 0;
prt->bytes_in += (hlen + len);
erts_smp_atomic_add_nob(&erts_bytes_in, (erts_aint_t) (hlen + len));
- if (prt->status & ERTS_PORT_SFLG_DISTRIBUTION) {
+ if (state & ERTS_PORT_SFLG_DISTRIBUTION) {
if (len == 0)
return erts_net_message(prt,
prt->dist_entry,
@@ -3560,10 +5842,12 @@ int driver_output2(ErlDrvPort ix, char* hbuf, ErlDrvSizeT hlen,
(byte*) hbuf, hlen,
(byte*) buf, len);
}
- else if(prt->status & ERTS_PORT_SFLG_LINEBUF_IO)
- deliver_linebuf_message(prt, prt->connected, hbuf, hlen, buf, len);
+ else if (state & ERTS_PORT_SFLG_LINEBUF_IO)
+ deliver_linebuf_message(prt, state, ERTS_PORT_GET_CONNECTED(prt),
+ hbuf, hlen, buf, len);
else
- deliver_read_message(prt, prt->connected, hbuf, hlen, buf, len, 0);
+ deliver_read_message(prt, state, ERTS_PORT_GET_CONNECTED(prt),
+ hbuf, hlen, buf, len, 0);
return 0;
}
@@ -3584,6 +5868,7 @@ int driver_outputv(ErlDrvPort ix, char* hbuf, ErlDrvSizeT hlen,
SysIOVec* iov;
ErlDrvBinary** binv;
Port* prt;
+ erts_aint32_t state;
ERTS_SMP_CHK_NO_PROC_LOCKS;
@@ -3596,13 +5881,13 @@ int driver_outputv(ErlDrvPort ix, char* hbuf, ErlDrvSizeT hlen,
if (hlen < 0)
hlen = 0;
- prt = erts_drvport2port(ix);
+ prt = erts_drvport2port(ix, &state);
if (prt == NULL)
return -1;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
- if (prt->status & ERTS_PORT_SFLG_CLOSING)
+ if (state & ERTS_PORT_SFLG_CLOSING)
return 0;
/* size > 0 ! */
@@ -3627,7 +5912,8 @@ int driver_outputv(ErlDrvPort ix, char* hbuf, ErlDrvSizeT hlen,
/* XXX handle distribution !!! */
prt->bytes_in += (hlen + size);
erts_smp_atomic_add_nob(&erts_bytes_in, (erts_aint_t) (hlen + size));
- deliver_vec_message(prt, prt->connected, hbuf, hlen, binv, iov, n, size);
+ deliver_vec_message(prt, ERTS_PORT_GET_CONNECTED(prt), hbuf, hlen,
+ binv, iov, n, size);
return 0;
}
@@ -3738,8 +6024,7 @@ ErlDrvBinary* driver_realloc_binary(ErlDrvBinary* bin, ErlDrvSizeT size)
}
-void driver_free_binary(dbin)
-ErlDrvBinary* dbin;
+void driver_free_binary(ErlDrvBinary* dbin)
{
Binary *bin;
if (!dbin) {
@@ -3835,6 +6120,7 @@ static ERTS_INLINE void pdl_destroy(ErlDrvPDL pdl)
{
ERTS_LC_ASSERT(driver_pdl_get_refc(pdl) == 0);
erts_mtx_destroy(&pdl->mtx);
+ erts_port_dec_refc(pdl->prt);
erts_free(ERTS_ALC_T_PORT_DATA_LOCK, pdl);
}
@@ -3872,16 +6158,18 @@ ErlDrvPDL
driver_pdl_create(ErlDrvPort dp)
{
ErlDrvPDL pdl;
- Port *pp = erts_drvport2port(dp);
+ Port *pp = erts_drvport2port(dp, NULL);
if (!pp || pp->port_data_lock)
return NULL;
pdl = erts_alloc(ERTS_ALC_T_PORT_DATA_LOCK,
sizeof(struct erl_drv_port_data_lock));
erts_mtx_init(&pdl->mtx, "port_data_lock");
pdl_init_refc(pdl);
+ erts_port_inc_refc(pp);
+ pdl->prt = pp;
pp->port_data_lock = pdl;
#ifdef HARDDEBUG
- erts_fprintf(stderr, "driver_pdl_create(%T) -> 0x%08X\r\n",pp->id,(unsigned) pdl);
+ erts_fprintf(stderr, "driver_pdl_create(%T) -> 0x%08X\r\n",pp->common.id,(unsigned) pdl);
#endif
return pdl;
}
@@ -4319,33 +6607,33 @@ static ERTS_INLINE void
drv_cancel_timer(Port *prt)
{
#ifdef ERTS_SMP
- erts_cancel_smp_ptimer(prt->ptimer);
+ erts_cancel_smp_ptimer(prt->common.u.alive.ptimer);
#else
- erts_cancel_timer(&prt->tm);
+ erts_cancel_timer(&prt->common.u.alive.tm);
#endif
if (erts_port_task_is_scheduled(&prt->timeout_task))
- erts_port_task_abort(prt->id, &prt->timeout_task);
+ erts_port_task_abort(&prt->timeout_task);
}
int driver_set_timer(ErlDrvPort ix, unsigned long t)
{
- Port* prt = erts_drvport2port(ix);
+ Port* prt = erts_drvport2port(ix, NULL);
ERTS_SMP_CHK_NO_PROC_LOCKS;
if (prt == NULL)
return -1;
- ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
+
if (prt->drv_ptr->timeout == NULL)
return -1;
drv_cancel_timer(prt);
#ifdef ERTS_SMP
- erts_create_smp_ptimer(&prt->ptimer,
- prt->id,
+ erts_create_smp_ptimer(&prt->common.u.alive.ptimer,
+ prt->common.id,
(ErlTimeoutProc) schedule_port_timeout,
t);
#else
- erts_set_timer(&prt->tm,
+ erts_set_timer(&prt->common.u.alive.tm,
(ErlTimeoutProc) schedule_port_timeout,
NULL,
prt,
@@ -4356,7 +6644,7 @@ int driver_set_timer(ErlDrvPort ix, unsigned long t)
int driver_cancel_timer(ErlDrvPort ix)
{
- Port* prt = erts_drvport2port(ix);
+ Port* prt = erts_drvport2port(ix, NULL);
if (prt == NULL)
return -1;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
@@ -4368,7 +6656,7 @@ int driver_cancel_timer(ErlDrvPort ix)
int
driver_read_timer(ErlDrvPort ix, unsigned long* t)
{
- Port* prt = erts_drvport2port(ix);
+ Port* prt = erts_drvport2port(ix, NULL);
ERTS_SMP_CHK_NO_PROC_LOCKS;
@@ -4376,9 +6664,11 @@ driver_read_timer(ErlDrvPort ix, unsigned long* t)
return -1;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
#ifdef ERTS_SMP
- *t = prt->ptimer ? erts_time_left(&prt->ptimer->timer.tm) : 0;
+ *t = (prt->common.u.alive.ptimer
+ ? erts_time_left(&prt->common.u.alive.ptimer->timer.tm)
+ : 0);
#else
- *t = erts_time_left(&prt->tm);
+ *t = erts_time_left(&prt->common.u.alive.tm);
#endif
return 0;
}
@@ -4429,8 +6719,8 @@ static int do_driver_monitor_process(Port *prt,
}
ref = erts_make_ref_in_buffer(buf);
- erts_add_monitor(&(prt->monitors), MON_ORIGIN, ref, rp->id, NIL);
- erts_add_monitor(&(rp->monitors), MON_TARGET, ref, prt->id, NIL);
+ erts_add_monitor(&ERTS_P_MONITORS(prt), MON_ORIGIN, ref, rp->common.id, NIL);
+ erts_add_monitor(&ERTS_P_MONITORS(rp), MON_TARGET, ref, prt->common.id, NIL);
erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_LINK);
ref_to_driver_monitor(ref,monitor);
@@ -4440,31 +6730,22 @@ static int do_driver_monitor_process(Port *prt,
/*
* This can be called from a non scheduler thread iff a port_data_lock exists
*/
-int driver_monitor_process(ErlDrvPort port,
+int driver_monitor_process(ErlDrvPort drvport,
ErlDrvTermData process,
ErlDrvMonitor *monitor)
{
Port *prt;
int ret;
- Uint32 status;
+ erts_aint32_t state;
+#if !HEAP_ON_C_STACK || (defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK))
ErtsSchedulerData *sched = erts_get_scheduler_data();
- int ix = (int) port;
- if (ix < 0 || erts_max_ports <= ix) {
- return -1;
- }
- prt = &erts_port[ix];
+#endif
- DRV_MONITOR_LOCK_PDL(prt);
+ prt = DRV_MONITOR_LOOKUP_PORT_LOCK_PDL(drvport);
- if (sched) {
- status = erts_port[ix].status;
- } else {
- erts_smp_port_state_lock(prt);
- status = erts_port[ix].status;
- erts_smp_port_state_unlock(prt);
- }
+ state = erts_atomic32_read_nob(&prt->state);
- if (status & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP) {
+ if (state & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP) {
DRV_MONITOR_UNLOCK_PDL(prt);
return -1;
}
@@ -4502,7 +6783,7 @@ static int do_driver_demonitor_process(Port *prt, Eterm *buf,
memcpy(buf,monitor,sizeof(Eterm)*REF_THING_SIZE);
ref = make_internal_ref(buf);
- mon = erts_lookup_monitor(prt->monitors, ref);
+ mon = erts_lookup_monitor(ERTS_P_MONITORS(prt), ref);
if (mon == NULL) {
return 1;
}
@@ -4514,13 +6795,13 @@ static int do_driver_demonitor_process(Port *prt, Eterm *buf,
to,
ERTS_PROC_LOCK_LINK,
ERTS_P2P_FLG_ALLOW_OTHER_X);
- mon = erts_remove_monitor(&(prt->monitors), ref);
+ mon = erts_remove_monitor(&ERTS_P_MONITORS(prt), ref);
if (mon) {
erts_destroy_monitor(mon);
}
if (rp) {
ErtsMonitor *rmon;
- rmon = erts_remove_monitor(&(rp->monitors), ref);
+ rmon = erts_remove_monitor(&ERTS_P_MONITORS(rp), ref);
erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_LINK);
if (rmon != NULL) {
erts_destroy_monitor(rmon);
@@ -4529,30 +6810,21 @@ static int do_driver_demonitor_process(Port *prt, Eterm *buf,
return 0;
}
-int driver_demonitor_process(ErlDrvPort port,
+int driver_demonitor_process(ErlDrvPort drvport,
const ErlDrvMonitor *monitor)
{
Port *prt;
int ret;
- Uint32 status;
+ erts_aint32_t state;
+#if !HEAP_ON_C_STACK || (defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK))
ErtsSchedulerData *sched = erts_get_scheduler_data();
- int ix = (int) port;
- if (ix < 0 || erts_max_ports <= ix) {
- return -1;
- }
- prt = &erts_port[ix];
+#endif
- DRV_MONITOR_LOCK_PDL(prt);
+ prt = DRV_MONITOR_LOOKUP_PORT_LOCK_PDL(drvport);
- if (sched) {
- status = erts_port[ix].status;
- } else {
- erts_smp_port_state_lock(prt);
- status = erts_port[ix].status;
- erts_smp_port_state_unlock(prt);
- }
+ state = erts_atomic32_read_nob(&prt->state);
- if (status & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP) {
+ if (state & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP) {
DRV_MONITOR_UNLOCK_PDL(prt);
return -1;
}
@@ -4588,7 +6860,7 @@ static ErlDrvTermData do_driver_get_monitored_process(Port *prt, Eterm *buf,
memcpy(buf,monitor,sizeof(Eterm)*REF_THING_SIZE);
ref = make_internal_ref(buf);
- mon = erts_lookup_monitor(prt->monitors, ref);
+ mon = erts_lookup_monitor(ERTS_P_MONITORS(prt), ref);
if (mon == NULL) {
return driver_term_nil;
}
@@ -4599,30 +6871,20 @@ static ErlDrvTermData do_driver_get_monitored_process(Port *prt, Eterm *buf,
}
-ErlDrvTermData driver_get_monitored_process(ErlDrvPort port,
+ErlDrvTermData driver_get_monitored_process(ErlDrvPort drvport,
const ErlDrvMonitor *monitor)
{
Port *prt;
ErlDrvTermData ret;
- Uint32 status;
+ erts_aint32_t state;
+#if !HEAP_ON_C_STACK || (defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK))
ErtsSchedulerData *sched = erts_get_scheduler_data();
- int ix = (int) port;
- if (ix < 0 || erts_max_ports <= ix) {
- return driver_term_nil;
- }
- prt = &erts_port[ix];
-
- DRV_MONITOR_LOCK_PDL(prt);
+#endif
- if (sched) {
- status = erts_port[ix].status;
- } else {
- erts_smp_port_state_lock(prt);
- status = erts_port[ix].status;
- erts_smp_port_state_unlock(prt);
- }
+ prt = DRV_MONITOR_LOOKUP_PORT_LOCK_PDL(drvport);
- if (status & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP) {
+ state = erts_atomic32_read_nob(&prt->state);
+ if (state & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP) {
DRV_MONITOR_UNLOCK_PDL(prt);
return driver_term_nil;
}
@@ -4667,7 +6929,7 @@ void erts_fire_port_monitor(Port *prt, Eterm ref)
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
ASSERT(prt->drv_ptr != NULL);
DRV_MONITOR_LOCK_PDL(prt);
- if (erts_lookup_monitor(prt->monitors,ref) == NULL) {
+ if (erts_lookup_monitor(ERTS_P_MONITORS(prt), ref) == NULL) {
DRV_MONITOR_UNLOCK_PDL(prt);
return;
}
@@ -4677,7 +6939,7 @@ void erts_fire_port_monitor(Port *prt, Eterm ref)
DRV_MONITOR_UNLOCK_PDL(prt);
#ifdef USE_VM_PROBES
if (DTRACE_ENABLED(driver_process_exit)) {
- DTRACE_FORMAT_COMMON_PID_AND_PORT(prt->connected, prt)
+ DTRACE_FORMAT_COMMON_PID_AND_PORT(ERTS_PORT_GET_CONNECTED(prt), prt)
DTRACE3(driver_process_exit, process_str, port_str, prt->name);
}
#endif
@@ -4686,7 +6948,7 @@ void erts_fire_port_monitor(Port *prt, Eterm ref)
erts_unblock_fpe(fpe_was_unmasked);
DRV_MONITOR_LOCK_PDL(prt);
/* remove monitor *after* callback */
- rmon = erts_remove_monitor(&(prt->monitors),ref);
+ rmon = erts_remove_monitor(&ERTS_P_MONITORS(prt), ref);
DRV_MONITOR_UNLOCK_PDL(prt);
if (rmon) {
erts_destroy_monitor(rmon);
@@ -4697,7 +6959,8 @@ void erts_fire_port_monitor(Port *prt, Eterm ref)
static int
driver_failure_term(ErlDrvPort ix, Eterm term, int eof)
{
- Port* prt = erts_drvport2port(ix);
+ erts_aint32_t state;
+ Port* prt = erts_drvport2port(ix, &state);
ERTS_SMP_CHK_NO_PROC_LOCKS;
@@ -4705,19 +6968,19 @@ driver_failure_term(ErlDrvPort ix, Eterm term, int eof)
return -1;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
if (eof)
- flush_linebuf_messages(prt);
- if (prt->status & ERTS_PORT_SFLG_CLOSING) {
+ flush_linebuf_messages(prt, state);
+ if (state & ERTS_PORT_SFLG_CLOSING) {
terminate_port(prt);
- } else if (eof && (prt->status & ERTS_PORT_SFLG_SOFT_EOF)) {
- deliver_result(prt->id, prt->connected, am_eof);
+ } else if (eof && (state & ERTS_PORT_SFLG_SOFT_EOF)) {
+ deliver_result(prt->common.id, ERTS_PORT_GET_CONNECTED(prt), am_eof);
} else {
- /* XXX UGLY WORK AROUND, Let do_exit_port terminate the port */
+ /* XXX UGLY WORK AROUND, Let erts_deliver_port_exit() terminate the port */
if (prt->port_data_lock)
driver_pdl_lock(prt->port_data_lock);
prt->ioq.size = 0;
if (prt->port_data_lock)
driver_pdl_unlock(prt->port_data_lock);
- erts_do_exit_port(prt, prt->id, eof ? am_normal : term);
+ erts_deliver_port_exit(prt, prt->common.id, eof ? am_normal : term, 0);
}
return 0;
}
@@ -4730,23 +6993,23 @@ driver_failure_term(ErlDrvPort ix, Eterm term, int eof)
*/
int driver_exit(ErlDrvPort ix, int err)
{
- Port* prt = erts_drvport2port(ix);
+ Port* prt = erts_drvport2port(ix, NULL);
Process* rp;
ErtsLink *lnk, *rlnk = NULL;
+ Eterm connected;
ERTS_SMP_CHK_NO_PROC_LOCKS;
if (prt == NULL)
return -1;
- ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
-
- rp = erts_pid2proc(NULL, 0, prt->connected, ERTS_PROC_LOCK_LINK);
+ connected = ERTS_PORT_GET_CONNECTED(prt);
+ rp = erts_pid2proc(NULL, 0, connected, ERTS_PROC_LOCK_LINK);
if (rp) {
- rlnk = erts_remove_link(&(rp->nlinks),prt->id);
+ rlnk = erts_remove_link(&ERTS_P_LINKS(rp),prt->common.id);
}
- lnk = erts_remove_link(&(prt->nlinks),prt->connected);
+ lnk = erts_remove_link(&ERTS_P_LINKS(prt), connected);
#ifdef ERTS_SMP
if (rp)
@@ -4803,24 +7066,24 @@ ErlDrvTermData driver_mk_atom(char* string)
ErlDrvTermData driver_mk_port(ErlDrvPort ix)
{
- Port* prt = erts_drvport2port(ix);
+ Port* prt = erts_drvport2port(ix, NULL);
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
- return (ErlDrvTermData) prt->id;
+ return (ErlDrvTermData) prt->common.id;
}
ErlDrvTermData driver_connected(ErlDrvPort ix)
{
- Port* prt = erts_drvport2port(ix);
+ Port* prt = erts_drvport2port(ix, NULL);
ERTS_SMP_CHK_NO_PROC_LOCKS;
if (prt == NULL)
return NIL;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
- return prt->connected;
+ return ERTS_PORT_GET_CONNECTED(prt);
}
ErlDrvTermData driver_caller(ErlDrvPort ix)
{
- Port* prt = erts_drvport2port(ix);
+ Port* prt = erts_drvport2port(ix, NULL);
ERTS_SMP_CHK_NO_PROC_LOCKS;
if (prt == NULL)
return NIL;
@@ -4830,25 +7093,25 @@ ErlDrvTermData driver_caller(ErlDrvPort ix)
int driver_lock_driver(ErlDrvPort ix)
{
- Port* prt = erts_drvport2port(ix);
+ Port* prt = erts_drvport2port(ix, NULL);
DE_Handle* dh;
ERTS_SMP_CHK_NO_PROC_LOCKS;
- erts_smp_mtx_lock(&erts_driver_list_lock);
+ erts_smp_rwmtx_rwlock(&erts_driver_list_lock);
if (prt == NULL) {
- erts_smp_mtx_unlock(&erts_driver_list_lock);
+ erts_smp_rwmtx_rwunlock(&erts_driver_list_lock);
return -1;
}
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
if ((dh = (DE_Handle*)prt->drv_ptr->handle ) == NULL) {
- erts_smp_mtx_unlock(&erts_driver_list_lock);
+ erts_smp_rwmtx_rwunlock(&erts_driver_list_lock);
return -1;
}
erts_ddll_lock_driver(dh, prt->drv_ptr->name);
- erts_smp_mtx_unlock(&erts_driver_list_lock);
+ erts_smp_rwmtx_rwunlock(&erts_driver_list_lock);
return 0;
}
@@ -4858,7 +7121,7 @@ static int maybe_lock_driver_list(void)
void *rec_lock;
rec_lock = erts_smp_tsd_get(driver_list_lock_status_key);
if (rec_lock == 0) {
- erts_smp_mtx_lock(&erts_driver_list_lock);
+ erts_smp_rwmtx_rwlock(&erts_driver_list_lock);
return 1;
}
return 0;
@@ -4866,7 +7129,7 @@ static int maybe_lock_driver_list(void)
static void maybe_unlock_driver_list(int doit)
{
if (doit) {
- erts_smp_mtx_unlock(&erts_driver_list_lock);
+ erts_smp_rwmtx_rwunlock(&erts_driver_list_lock);
}
}
/*
@@ -5035,7 +7298,7 @@ no_event_callback(ErlDrvData drv_data, ErlDrvEvent event, ErlDrvEventData event_
{
Port *prt = get_current_port();
report_missing_drv_callback(prt, "Event", "event()");
- driver_event((ErlDrvPort) internal_port_index(prt->id), event, NULL);
+ driver_event((ErlDrvPort) prt, event, NULL);
}
static void
@@ -5043,7 +7306,7 @@ no_ready_input_callback(ErlDrvData drv_data, ErlDrvEvent event)
{
Port *prt = get_current_port();
report_missing_drv_callback(prt, "Input", "ready_input()");
- driver_select((ErlDrvPort) internal_port_index(prt->id), event,
+ driver_select((ErlDrvPort) prt, event,
(ERL_DRV_READ | ERL_DRV_USE_NO_CALLBACK), 0);
}
@@ -5052,7 +7315,7 @@ no_ready_output_callback(ErlDrvData drv_data, ErlDrvEvent event)
{
Port *prt = get_current_port();
report_missing_drv_callback(prt, "Output", "ready_output()");
- driver_select((ErlDrvPort) internal_port_index(prt->id), event,
+ driver_select((ErlDrvPort) prt, event,
(ERL_DRV_WRITE | ERL_DRV_USE_NO_CALLBACK), 0);
}
@@ -5087,13 +7350,13 @@ init_driver(erts_driver_t *drv, ErlDrvEntry *de, DE_Handle *handle)
drv->lock = NULL;
else {
drv->lock = erts_alloc(ERTS_ALC_T_DRIVER_LOCK,
- sizeof(erts_smp_mtx_t));
- erts_smp_mtx_init_x(drv->lock,
- "driver_lock",
+ sizeof(erts_mtx_t));
+ erts_mtx_init_x(drv->lock,
+ "driver_lock",
#if defined(ERTS_ENABLE_LOCK_CHECK) || defined(ERTS_ENABLE_LOCK_COUNT)
- am_atom_put(drv->name, sys_strlen(drv->name))
+ am_atom_put(drv->name, sys_strlen(drv->name))
#else
- NIL
+ NIL
#endif
);
}
@@ -5165,7 +7428,7 @@ int erts_add_driver_entry(ErlDrvEntry *de, DE_Handle *handle, int driver_list_lo
int res;
if (!driver_list_locked) {
- erts_smp_mtx_lock(&erts_driver_list_lock);
+ erts_smp_rwmtx_rwlock(&erts_driver_list_lock);
}
dp->next = driver_list;
@@ -5194,7 +7457,7 @@ int erts_add_driver_entry(ErlDrvEntry *de, DE_Handle *handle, int driver_list_lo
if (!driver_list_locked) {
erts_smp_tsd_set(driver_list_lock_status_key, NULL);
- erts_smp_mtx_unlock(&erts_driver_list_lock);
+ erts_smp_rwmtx_rwunlock(&erts_driver_list_lock);
}
return res;
}
@@ -5207,7 +7470,7 @@ int remove_driver_entry(ErlDrvEntry *drv)
rec_lock = erts_smp_tsd_get(driver_list_lock_status_key);
if (rec_lock == NULL) {
- erts_smp_mtx_lock(&erts_driver_list_lock);
+ erts_smp_rwmtx_rwlock(&erts_driver_list_lock);
}
dp = driver_list;
while (dp && dp->entry != drv)
@@ -5215,7 +7478,7 @@ int remove_driver_entry(ErlDrvEntry *drv)
if (dp) {
if (dp->handle) {
if (rec_lock == NULL) {
- erts_smp_mtx_unlock(&erts_driver_list_lock);
+ erts_smp_rwmtx_rwunlock(&erts_driver_list_lock);
}
return -1;
}
@@ -5229,12 +7492,12 @@ int remove_driver_entry(ErlDrvEntry *drv)
}
erts_destroy_driver(dp);
if (rec_lock == NULL) {
- erts_smp_mtx_unlock(&erts_driver_list_lock);
+ erts_smp_rwmtx_rwunlock(&erts_driver_list_lock);
}
return 1;
}
if (rec_lock == NULL) {
- erts_smp_mtx_unlock(&erts_driver_list_lock);
+ erts_smp_rwmtx_rwunlock(&erts_driver_list_lock);
}
return 0;
}
@@ -5258,3 +7521,31 @@ erl_drv_getenv(char *key, char *value, size_t *value_size)
{
return erts_sys_getenv_raw(key, value, value_size);
}
+
+/* get heart_port
+ * used by erl_crash_dump
+ * - uses the fact that heart_port is registered when starting heart
+ */
+
+Port *erts_get_heart_port(void)
+{
+ int ix, max = erts_ptab_max(&erts_port);
+
+ for (ix = 0; ix < max; ix++) {
+ struct reg_proc *reg;
+ Port *port = erts_pix2port(ix);
+
+ if (!port)
+ continue;
+ /* only examine undead or alive ports */
+ if (erts_atomic32_read_nob(&port->state) & ERTS_PORT_SFLGS_DEAD)
+ continue;
+ /* immediate atom compare */
+ reg = port->common.u.alive.reg;
+ if (reg && reg->name == am_heart_port) {
+ return port;
+ }
+ }
+
+ return NULL;
+}
diff --git a/erts/emulator/beam/module.c b/erts/emulator/beam/module.c
index 1ef71cda79..01856007ee 100644
--- a/erts/emulator/beam/module.c
+++ b/erts/emulator/beam/module.c
@@ -144,7 +144,7 @@ erts_put_module(Eterm mod)
ASSERT(is_atom(mod));
ERTS_SMP_LC_ASSERT(erts_initialized == 0
- || erts_is_code_ix_locked());
+ || erts_has_code_write_permission());
mod_tab = &module_tables[erts_staging_code_ix()];
e.module = atom_val(mod);
diff --git a/erts/emulator/beam/register.c b/erts/emulator/beam/register.c
index c02872ef80..757e2800e6 100644
--- a/erts/emulator/beam/register.c
+++ b/erts/emulator/beam/register.c
@@ -175,14 +175,14 @@ int erts_register_name(Process *c_p, Eterm name, Eterm id)
if (is_not_atom(name) || name == am_undefined)
return res;
- if (c_p->id == id) /* A very common case I think... */
+ if (c_p->common.id == id) /* A very common case I think... */
proc = c_p;
else {
if (is_not_internal_pid(id) && is_not_internal_port(id))
return res;
erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN);
if (is_internal_port(id)) {
- port = erts_id2port(id, NULL, 0);
+ port = erts_id2port(id);
if (!port)
goto done;
}
@@ -204,7 +204,7 @@ int erts_register_name(Process *c_p, Eterm name, Eterm id)
r.p = proc;
if (!proc)
goto done;
- if (proc->reg)
+ if (proc->common.u.alive.reg)
goto done;
r.pt = NULL;
}
@@ -212,7 +212,7 @@ int erts_register_name(Process *c_p, Eterm name, Eterm id)
ASSERT(!INVALID_PORT(port, id));
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(port));
r.pt = port;
- if (r.pt->reg)
+ if (r.pt->common.u.alive.reg)
goto done;
r.p = NULL;
}
@@ -224,23 +224,24 @@ int erts_register_name(Process *c_p, Eterm name, Eterm id)
if (IS_TRACED_FL(proc, F_TRACE_PROCS)) {
trace_proc(c_p, proc, am_register, name);
}
- proc->reg = rp;
+ proc->common.u.alive.reg = rp;
}
else if (port && rp->pt == port) {
if (IS_TRACED_FL(port, F_TRACE_PORTS)) {
trace_port(port, am_register, name);
}
- port->reg = rp;
+ port->common.u.alive.reg = rp;
}
- if ((rp->p && rp->p->id == id) || (rp->pt && rp->pt->id == id)) {
+ if ((rp->p && rp->p->common.id == id)
+ || (rp->pt && rp->pt->common.id == id)) {
res = 1;
}
done:
reg_write_unlock();
if (port)
- erts_smp_port_unlock(port);
+ erts_port_release(port);
if (c_p != proc) {
if (proc)
erts_smp_proc_unlock(proc, ERTS_PROC_LOCK_MAIN);
@@ -291,9 +292,9 @@ erts_whereis_name_to_id(Process *c_p, Eterm name)
* is read only.
*/
if (rp->p)
- res = rp->p->id;
+ res = rp->p->common.id;
else if (rp->pt)
- res = rp->pt->id;
+ res = rp->pt->common.id;
break;
}
b = b->next;
@@ -396,28 +397,26 @@ erts_whereis_name(Process *c_p,
if (!rp || !rp->pt)
*port = NULL;
else {
-#ifndef ERTS_SMP
- erts_smp_atomic_inc_nob(&rp->pt->refc);
-#else
+#ifdef ERTS_SMP
if (pending_port == rp->pt)
pending_port = NULL;
else {
if (pending_port) {
/* Ahh! Registered port changed while reg lock
was unlocked... */
- erts_smp_port_unlock(pending_port);
+ erts_port_release(pending_port);
pending_port = NULL;
}
if (erts_smp_port_trylock(rp->pt) == EBUSY) {
- Eterm id = rp->pt->id; /* id read only... */
+ Eterm id = rp->pt->common.id; /* id read only... */
/* Unlock all locks, acquire port lock, and restart... */
if (current_c_p_locks) {
erts_smp_proc_unlock(c_p, current_c_p_locks);
current_c_p_locks = 0;
}
reg_read_unlock();
- pending_port = erts_id2port(id, NULL, 0);
+ pending_port = erts_id2port(id);
goto restart;
}
}
@@ -431,7 +430,7 @@ erts_whereis_name(Process *c_p,
if (c_p && !current_c_p_locks)
erts_smp_proc_lock(c_p, c_p_locks);
if (pending_port)
- erts_smp_port_unlock(pending_port);
+ erts_port_release(pending_port);
#endif
reg_read_unlock();
@@ -493,8 +492,8 @@ int erts_unregister_name(Process *c_p,
current_c_p_locks = c_p_locks;
}
#endif
- if (c_p->reg) {
- r.name = c_p->reg->name;
+ if (c_p->common.u.alive.reg) {
+ r.name = c_p->common.u.alive.reg->name;
} else {
/* Name got unregistered while main lock was released */
res = 0;
@@ -505,24 +504,22 @@ int erts_unregister_name(Process *c_p,
if ((rp = (RegProc*) hash_get(&process_reg, (void*) &r)) != NULL) {
if (rp->pt) {
if (port != rp->pt) {
-#ifndef ERTS_SMP
- erts_smp_atomic_inc_nob(&rp->pt->refc);
-#else
+#ifdef ERTS_SMP
if (port) {
ASSERT(port != c_prt);
- erts_smp_port_unlock(port);
+ erts_port_release(port);
port = NULL;
}
if (erts_smp_port_trylock(rp->pt) == EBUSY) {
- Eterm id = rp->pt->id; /* id read only... */
+ Eterm id = rp->pt->common.id; /* id read only... */
/* Unlock all locks, acquire port lock, and restart... */
if (current_c_p_locks) {
erts_smp_proc_unlock(c_p, current_c_p_locks);
current_c_p_locks = 0;
}
reg_write_unlock();
- port = erts_id2port(id, NULL, 0);
+ port = erts_id2port(id);
goto restart;
}
#endif
@@ -532,7 +529,7 @@ int erts_unregister_name(Process *c_p,
ASSERT(rp->pt == port);
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(port));
- rp->pt->reg = NULL;
+ rp->pt->common.u.alive.reg = NULL;
if (IS_TRACED_FL(port, F_TRACE_PORTS)) {
trace_port(port, am_unregister, r.name);
@@ -549,7 +546,7 @@ int erts_unregister_name(Process *c_p,
ERTS_PROC_LOCK_MAIN);
current_c_p_locks = c_p_locks;
#endif
- rp->p->reg = NULL;
+ rp->p->common.u.alive.reg = NULL;
if (IS_TRACED_FL(rp->p, F_TRACE_PROCS)) {
trace_proc(c_p, rp->p, am_unregister, r.name);
}
@@ -568,7 +565,7 @@ int erts_unregister_name(Process *c_p,
reg_write_unlock();
if (c_prt != port) {
if (port) {
- erts_smp_port_unlock(port);
+ erts_port_release(port);
}
if (c_prt) {
erts_smp_port_lock(c_prt);
diff --git a/erts/emulator/beam/register.h b/erts/emulator/beam/register.h
index 38e8cfbf28..7170463375 100644
--- a/erts/emulator/beam/register.h
+++ b/erts/emulator/beam/register.h
@@ -24,26 +24,19 @@
#ifndef __REGPROC_H__
#define __REGPROC_H__
-#ifndef __SYS_H__
#include "sys.h"
-#endif
-
-#ifndef __HASH_H__
#include "hash.h"
-#endif
-
-#ifndef __PROCESS_H__
#include "erl_process.h"
-#endif
-
-struct port;
+#define ERL_PORT_GET_PORT_TYPE_ONLY__
+#include "erl_port.h"
+#undef ERL_PORT_GET_PORT_TYPE_ONLY__
typedef struct reg_proc
{
HashBucket bucket; /* MUST BE LOCATED AT TOP OF STRUCT!!! */
Process *p; /* The process registered (only one of this and
'pt' is non-NULL */
- struct port *pt; /* The port registered */
+ Port *pt; /* The port registered */
Eterm name; /* Atom name */
} RegProc;
@@ -55,12 +48,12 @@ int erts_register_name(Process *, Eterm, Eterm);
Eterm erts_whereis_name_to_id(Process *, Eterm);
void erts_whereis_name(Process *, ErtsProcLocks,
Eterm, Process**, ErtsProcLocks, int,
- struct port**);
+ Port**);
Process *erts_whereis_process(Process *,
ErtsProcLocks,
Eterm,
ErtsProcLocks,
int);
-int erts_unregister_name(Process *, ErtsProcLocks, struct port *, Eterm);
+int erts_unregister_name(Process *, ErtsProcLocks, Port *, Eterm);
#endif
diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h
index 0e6bec352e..898a30b010 100644
--- a/erts/emulator/beam/sys.h
+++ b/erts/emulator/beam/sys.h
@@ -116,6 +116,16 @@ typedef ERTS_SYS_FD_TYPE ErtsSysFdType;
# define ERTS_DECLARE_DUMMY(X) X
#endif
+#if !defined(__func__)
+# if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L
+# if !defined(__GNUC__) || __GNUC__ < 2
+# define __func__ "[unknown_function]"
+# else
+# define __func__ __FUNCTION__
+# endif
+# endif
+#endif
+
#if defined(DEBUG) || defined(ERTS_ENABLE_LOCK_CHECK)
# undef ERTS_CAN_INLINE
# define ERTS_CAN_INLINE 0
@@ -231,9 +241,11 @@ void erl_assert_error(char* expr, char* file, int line);
#if SIZEOF_VOID_P == 8
#undef ARCH_32
#define ARCH_64
+#define ERTS_SIZEOF_TERM 8
#elif SIZEOF_VOID_P == 4
#define ARCH_32
#undef ARCH_64
+#define ERTS_SIZEOF_TERM 4
#else
#error Neither 32 nor 64 bit architecture
#endif
@@ -241,6 +253,8 @@ void erl_assert_error(char* expr, char* file, int line);
# define HALFWORD_HEAP 1
# define HALFWORD_ASSERT 0
# define ASSERT_HALFWORD(COND) ASSERT(COND)
+# undef ERTS_SIZEOF_TERM
+# define ERTS_SIZEOF_TERM 4
#else
# define HALFWORD_HEAP 0
# define HALFWORD_ASSERT 0
@@ -367,6 +381,27 @@ typedef unsigned char byte;
#error 64-bit architecture, but no appropriate type to use for Uint64 and Sint64 found
#endif
+#ifdef WORDS_BIGENDIAN
+# define ERTS_HUINT_HVAL_HIGH 0
+# define ERTS_HUINT_HVAL_LOW 1
+#else
+# define ERTS_HUINT_HVAL_HIGH 1
+# define ERTS_HUINT_HVAL_LOW 0
+#endif
+#if ERTS_SIZEOF_TERM == 8
+typedef union {
+ Uint val;
+ Uint32 hval[2];
+} HUint;
+#elif ERTS_SIZEOF_TERM == 4
+typedef union {
+ Uint val;
+ Uint16 hval[2];
+} HUint;
+#else
+#error "Unsupported size of term"
+#endif
+
# define ERTS_EXTRA_DATA_ALIGN_SZ(X) \
(((size_t) 8) - (((size_t) (X)) & ((size_t) 7)))
@@ -505,6 +540,10 @@ __decl_noreturn void __noreturn erl_exit(int n, char*, ...);
#define ERTS_ABORT_EXIT (INT_MIN + 1) /* no crash dump; only abort() */
#define ERTS_DUMP_EXIT (INT_MIN + 2) /* crash dump; then exit() */
+#define ERTS_INTERNAL_ERROR(What) \
+ erl_exit(ERTS_ABORT_EXIT, "%s:%d:%s(): Internal error: %s\n", \
+ __FILE__, __LINE__, __func__, What)
+
Eterm erts_check_io_info(void *p);
/* Size of misc memory allocated from system dependent code */
@@ -579,6 +618,7 @@ typedef struct _SysDriverOpts {
char *wd; /* Working directory. */
unsigned spawn_type; /* Bitfield of ERTS_SPAWN_DRIVER |
ERTS_SPAWN_EXTERNAL | both*/
+ int parallelism; /* Optimize for parallelism */
} SysDriverOpts;
extern char *erts_default_arg0;
@@ -618,7 +658,7 @@ typedef struct {
#define ERTS_SYS_DDLL_ERROR_INIT {NULL}
extern void erts_sys_ddll_free_error(ErtsSysDdllError*);
extern void erl_sys_ddll_init(void); /* to initialize mutexes etc */
-extern int erts_sys_ddll_open2(char *path, void **handle, ErtsSysDdllError*);
+extern int erts_sys_ddll_open2(const char *path, void **handle, ErtsSysDdllError*);
#define erts_sys_ddll_open(P,H) erts_sys_ddll_open2(P,H,NULL)
extern int erts_sys_ddll_open_noext(char *path, void **handle, ErtsSysDdllError*);
extern int erts_sys_ddll_load_driver_init(void *handle, void **function);
@@ -627,7 +667,7 @@ extern int erts_sys_ddll_close2(void *handle, ErtsSysDdllError*);
#define erts_sys_ddll_close(H) erts_sys_ddll_close2(H,NULL)
extern void *erts_sys_ddll_call_init(void *function);
extern void *erts_sys_ddll_call_nif_init(void *function);
-extern int erts_sys_ddll_sym2(void *handle, char *name, void **function, ErtsSysDdllError*);
+extern int erts_sys_ddll_sym2(void *handle, const char *name, void **function, ErtsSysDdllError*);
#define erts_sys_ddll_sym(H,N,F) erts_sys_ddll_sym2(H,N,F,NULL)
extern char *erts_sys_ddll_error(int code);
@@ -644,7 +684,7 @@ void erts_sys_schedule_interrupt_timed(int set, erts_short_time_t msec);
void erts_sys_main_thread(void);
#endif
-extern void erts_sys_prepare_crash_dump(void);
+extern int erts_sys_prepare_crash_dump(int secs);
extern void erts_sys_pre_init(void);
extern void erl_sys_init(void);
extern void erl_sys_args(int *argc, char **argv);
diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c
index 1969fc762c..5261effef9 100644
--- a/erts/emulator/beam/utils.c
+++ b/erts/emulator/beam/utils.c
@@ -46,6 +46,7 @@
#include "erl_thr_queue.h"
#include "erl_sched_spec_pre_alloc.h"
#include "beam_bp.h"
+#include "erl_ptab.h"
#undef M_TRIM_THRESHOLD
#undef M_TOP_PAD
@@ -3016,12 +3017,13 @@ buf_to_intlist(Eterm** hpp, char *buf, size_t len, Eterm tail)
** ;
**
** Return remaining bytes in buffer on success
-** -1 on overflow
-** -2 on type error (including that result would not be a whole number of bytes)
+** ERTS_IOLIST_TO_BUF_OVERFLOW on overflow
+** ERTS_IOLIST_TO_BUF_TYPE_ERROR on type error (including that result would not be a whole number of bytes)
*/
-int io_list_to_buf(Eterm obj, char* buf, int len)
+ErlDrvSizeT erts_iolist_to_buf(Eterm obj, char* buf, ErlDrvSizeT alloced_len)
{
+ ErlDrvSizeT len = (ErlDrvSizeT) alloced_len;
Eterm* objp;
DECLARE_ESTACK(s);
goto L_again;
@@ -3114,20 +3116,20 @@ int io_list_to_buf(Eterm obj, char* buf, int len)
L_type_error:
DESTROY_ESTACK(s);
- return -2;
+ return ERTS_IOLIST_TO_BUF_TYPE_ERROR;
L_overflow:
DESTROY_ESTACK(s);
- return -1;
+ return ERTS_IOLIST_TO_BUF_OVERFLOW;
}
/*
* Return 0 if successful, and non-zero if unsuccessful.
*/
-int erts_iolist_size(Eterm obj, Uint* sizep)
+int erts_iolist_size(Eterm obj, ErlDrvSizeT* sizep)
{
Eterm* objp;
- Uint size = 0;
+ Uint size = 0; /* Intentionally Uint due to halfword heap */
DECLARE_ESTACK(s);
goto L_again;
@@ -3179,7 +3181,7 @@ int erts_iolist_size(Eterm obj, Uint* sizep)
#undef SAFE_ADD
DESTROY_ESTACK(s);
- *sizep = size;
+ *sizep = (ErlDrvSizeT) size;
return ERTS_IOLIST_OK;
L_overflow_error:
diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c
index 912f5d3d8b..25b02db2c9 100644
--- a/erts/emulator/drivers/common/efile_drv.c
+++ b/erts/emulator/drivers/common/efile_drv.c
@@ -56,6 +56,7 @@
#define FILE_FDATASYNC 30
#define FILE_FADVISE 31
#define FILE_SENDFILE 32
+#define FILE_FALLOCATE 33
/* Return codes */
@@ -439,6 +440,7 @@ struct t_data
Efile_error errInfo;
int flags;
SWord fd;
+ int is_fd_unused;
/**/
Efile_info info;
EFILE_DIR_HANDLE dir_handle; /* Handle to open directory. */
@@ -503,6 +505,10 @@ struct t_data
Uint64 written;
} sendfile;
#endif /* HAVE_SENDFILE */
+ struct {
+ Sint64 offset;
+ Sint64 length;
+ } fallocate;
} c;
char b[1];
};
@@ -781,11 +787,6 @@ file_start(ErlDrvPort port, char* command)
return (ErlDrvData) desc;
}
-static void free_data(void *data)
-{
- EF_FREE(data);
-}
-
static void do_close(int flags, SWord fd) {
if (flags & EFILE_COMPRESSED) {
erts_gzclose((gzFile)(fd));
@@ -803,6 +804,17 @@ static void invoke_close(void *data)
DTRACE_INVOKE_RETURN(FILE_CLOSE);
}
+static void free_data(void *data)
+{
+ struct t_data *d = (struct t_data *) data;
+
+ if (d->command == FILE_OPEN && d->is_fd_unused && d->fd != FILE_FD_INVALID) {
+ do_close(d->flags, d->fd);
+ }
+
+ EF_FREE(data);
+}
+
/*********************************************************************
* Driver entry point -> stop
*/
@@ -1862,6 +1874,9 @@ static void invoke_open(void *data)
}
d->result_ok = status;
+ if (!status) {
+ d->fd = FILE_FD_INVALID;
+ }
DTRACE_INVOKE_RETURN(FILE_OPEN);
}
@@ -1953,6 +1968,17 @@ static int flush_sendfile(file_descriptor *desc,void *_) {
#endif /* HAVE_SENDFILE */
+static void invoke_fallocate(void *data)
+{
+ struct t_data *d = (struct t_data *) data;
+ int fd = (int) d->fd;
+ Sint64 offset = d->c.fallocate.offset;
+ Sint64 length = d->c.fallocate.length;
+
+ d->again = 0;
+ d->result_ok = efile_fallocate(&d->errInfo, fd, offset, length);
+}
+
static void free_readdir(void *data)
{
struct t_data *d = (struct t_data *) data;
@@ -2348,6 +2374,7 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data)
case FILE_RENAME:
case FILE_WRITE_INFO:
case FILE_FADVISE:
+ case FILE_FALLOCATE:
reply(desc, d->result_ok, &d->errInfo);
free_data(data);
break;
@@ -2373,8 +2400,10 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data)
if (!d->result_ok) {
reply_error(desc, &d->errInfo);
} else {
+ ASSERT(d->is_fd_unused);
desc->fd = d->fd;
desc->flags = d->flags;
+ d->is_fd_unused = 0;
reply_Uint(desc, d->fd);
}
free_data(data);
@@ -2745,6 +2774,7 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count)
d->invoke = invoke_open;
d->free = free_data;
d->level = 2;
+ d->is_fd_unused = 1;
goto done;
}
@@ -2958,6 +2988,20 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count)
goto done;
}
+ case FILE_FALLOCATE:
+ {
+ d = EF_SAFE_ALLOC(sizeof(struct t_data));
+
+ d->fd = fd;
+ d->command = command;
+ d->invoke = invoke_fallocate;
+ d->free = free_data;
+ d->level = 2;
+ d->c.fallocate.offset = get_int64((uchar*) buf);
+ d->c.fallocate.length = get_int64(((uchar*) buf) + sizeof(Sint64));
+ goto done;
+ }
+
}
/*
diff --git a/erts/emulator/drivers/common/erl_efile.h b/erts/emulator/drivers/common/erl_efile.h
index 69ad02633c..b29b4f971c 100644
--- a/erts/emulator/drivers/common/erl_efile.h
+++ b/erts/emulator/drivers/common/erl_efile.h
@@ -185,3 +185,4 @@ int efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset, Sint64 length,
int efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd,
off_t *offset, Uint64 *nbytes, struct t_sendfile_hdtl *hdtl);
#endif /* HAVE_SENDFILE */
+int efile_fallocate(Efile_error* errInfo, int fd, Sint64 offset, Sint64 length);
diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c
index dea910e89f..236b8710fb 100644
--- a/erts/emulator/drivers/common/inet_drv.c
+++ b/erts/emulator/drivers/common/inet_drv.c
@@ -660,6 +660,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
#define UDP_OPT_MULTICAST_LOOP 13 /* set/get IP multicast loopback */
#define UDP_OPT_ADD_MEMBERSHIP 14 /* add an IP group membership */
#define UDP_OPT_DROP_MEMBERSHIP 15 /* drop an IP group membership */
+#define INET_OPT_IPV6_V6ONLY 16 /* IPv6 only socket, no mapped v4 addrs */
/* LOPT is local options */
#define INET_LOPT_BUFFER 20 /* min buffer size hint */
#define INET_LOPT_HEADER 21 /* list header size */
@@ -677,6 +678,8 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
#define INET_LOPT_UDP_READ_PACKETS 33 /* Number of packets to read */
#define INET_OPT_RAW 34 /* Raw socket options */
#define INET_LOPT_TCP_SEND_TIMEOUT_CLOSE 35 /* auto-close on send timeout or not */
+#define INET_LOPT_TCP_MSGQ_HIWTRMRK 36 /* set local high watermark */
+#define INET_LOPT_TCP_MSGQ_LOWTRMRK 37 /* set local low watermark */
/* SCTP options: a separate range, from 100: */
#define SCTP_OPT_RTOINFO 100
#define SCTP_OPT_ASSOCINFO 101
@@ -787,6 +790,8 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
#define INET_HIGH_WATERMARK (1024*8) /* 8k pending high => busy */
#define INET_LOW_WATERMARK (1024*4) /* 4k pending => allow more */
+#define INET_HIGH_MSGQ_WATERMARK (1024*8) /* 8k pending high => busy */
+#define INET_LOW_MSGQ_WATERMARK (1024*4) /* 4k pending => allow more */
#define INET_INFINITY 0xffffffff /* infinity value */
@@ -878,7 +883,7 @@ typedef struct subs_list_ {
#define NO_PROCESS 0
#define NO_SUBSCRIBERS(SLP) ((SLP)->subscriber == NO_PROCESS)
-static void send_to_subscribers(ErlDrvPort, subs_list *, int,
+static void send_to_subscribers(ErlDrvTermData, subs_list *, int,
ErlDrvTermData [], int);
static void free_subscribers(subs_list*);
static int save_subscriber(subs_list *, ErlDrvTermData);
@@ -1167,6 +1172,7 @@ static ErlDrvTermData am_reuseaddr;
static ErlDrvTermData am_dontroute;
static ErlDrvTermData am_priority;
static ErlDrvTermData am_tos;
+static ErlDrvTermData am_ipv6_v6only;
#endif
/* speical errors for bad ports and sequences */
@@ -1871,8 +1877,7 @@ static int deq_async(inet_descriptor* desc, int* ap, ErlDrvTermData* cp, int* rp
** {inet_async, Port, Ref, ok}
*/
static int
-send_async_ok(ErlDrvPort port, ErlDrvTermData Port, int Ref,
- ErlDrvTermData recipient)
+send_async_ok(ErlDrvTermData Port, int Ref,ErlDrvTermData recipient)
{
ErlDrvTermData spec[2*LOAD_ATOM_CNT + LOAD_PORT_CNT +
LOAD_INT_CNT + LOAD_TUPLE_CNT];
@@ -1886,14 +1891,14 @@ send_async_ok(ErlDrvPort port, ErlDrvTermData Port, int Ref,
ASSERT(i == sizeof(spec)/sizeof(*spec));
- return driver_send_term(port, recipient, spec, i);
+ return erl_drv_send_term(Port, recipient, spec, i);
}
/* send message:
** {inet_async, Port, Ref, {ok,Port2}}
*/
static int
-send_async_ok_port(ErlDrvPort port, ErlDrvTermData Port, int Ref,
+send_async_ok_port(ErlDrvTermData Port, int Ref,
ErlDrvTermData recipient, ErlDrvTermData Port2)
{
ErlDrvTermData spec[2*LOAD_ATOM_CNT + 2*LOAD_PORT_CNT +
@@ -1912,14 +1917,14 @@ send_async_ok_port(ErlDrvPort port, ErlDrvTermData Port, int Ref,
ASSERT(i == sizeof(spec)/sizeof(*spec));
- return driver_send_term(port, recipient, spec, i);
+ return erl_drv_send_term(Port, recipient, spec, i);
}
/* send message:
** {inet_async, Port, Ref, {error,Reason}}
*/
static int
-send_async_error(ErlDrvPort port, ErlDrvTermData Port, int Ref,
+send_async_error(ErlDrvTermData Port, int Ref,
ErlDrvTermData recipient, ErlDrvTermData Reason)
{
ErlDrvTermData spec[3*LOAD_ATOM_CNT + LOAD_PORT_CNT +
@@ -1937,7 +1942,7 @@ send_async_error(ErlDrvPort port, ErlDrvTermData Port, int Ref,
i = LOAD_TUPLE(spec, i, 4);
ASSERT(i == sizeof(spec)/sizeof(*spec));
DEBUGF(("send_async_error %ld %ld\r\n", recipient, Reason));
- return driver_send_term(port, recipient, spec, i);
+ return erl_drv_send_term(Port, recipient, spec, i);
}
@@ -1949,7 +1954,7 @@ static int async_ok(inet_descriptor* desc)
if (deq_async(desc, &aid, &caller, &req) < 0)
return -1;
- return send_async_ok(desc->port, desc->dport, aid, caller);
+ return send_async_ok(desc->dport, aid, caller);
}
static int async_ok_port(inet_descriptor* desc, ErlDrvTermData Port2)
@@ -1960,7 +1965,7 @@ static int async_ok_port(inet_descriptor* desc, ErlDrvTermData Port2)
if (deq_async(desc, &aid, &caller, &req) < 0)
return -1;
- return send_async_ok_port(desc->port, desc->dport, aid, caller, Port2);
+ return send_async_ok_port(desc->dport, aid, caller, Port2);
}
static int async_error_am(inet_descriptor* desc, ErlDrvTermData reason)
@@ -1971,8 +1976,7 @@ static int async_error_am(inet_descriptor* desc, ErlDrvTermData reason)
if (deq_async(desc, &aid, &caller, &req) < 0)
return -1;
- return send_async_error(desc->port, desc->dport, aid, caller,
- reason);
+ return send_async_error(desc->dport, aid, caller, reason);
}
/* dequeue all operations */
@@ -1983,8 +1987,7 @@ static int async_error_am_all(inet_descriptor* desc, ErlDrvTermData reason)
ErlDrvTermData caller;
while (deq_async(desc, &aid, &caller, &req) == 0) {
- send_async_error(desc->port, desc->dport, aid, caller,
- reason);
+ send_async_error(desc->dport, aid, caller, reason);
}
return 0;
}
@@ -2012,7 +2015,7 @@ static int inet_reply_ok(inet_descriptor* desc)
ASSERT(i == sizeof(spec)/sizeof(*spec));
desc->caller = 0;
- return driver_send_term(desc->port, caller, spec, i);
+ return erl_drv_send_term(desc->dport, caller, spec, i);
}
#ifdef HAVE_SCTP
@@ -2031,7 +2034,7 @@ static int inet_reply_ok_port(inet_descriptor* desc, ErlDrvTermData dport)
ASSERT(i == sizeof(spec)/sizeof(*spec));
desc->caller = 0;
- return driver_send_term(desc->port, caller, spec, i);
+ return erl_drv_send_term(desc->dport, caller, spec, i);
}
#endif
@@ -2054,7 +2057,7 @@ static int inet_reply_error_am(inet_descriptor* desc, ErlDrvTermData reason)
desc->caller = 0;
DEBUGF(("inet_reply_error_am %ld %ld\r\n", caller, reason));
- return driver_send_term(desc->port, caller, spec, i);
+ return erl_drv_send_term(desc->dport, caller, spec, i);
}
/* send:
@@ -2163,12 +2166,12 @@ static int http_response_inetdrv(void *arg, int major, int minor,
i = LOAD_TUPLE(spec, i, 2);
i = LOAD_TUPLE(spec, i, 4);
ASSERT(i<=27);
- return driver_send_term(desc->inet.port, caller, spec, i);
+ return erl_drv_send_term(desc->inet.dport, caller, spec, i);
}
else {
i = LOAD_TUPLE(spec, i, 3);
ASSERT(i<=27);
- return driver_output_term(desc->inet.port, spec, i);
+ return erl_drv_output_term(desc->inet.dport, spec, i);
}
}
@@ -2260,12 +2263,12 @@ http_request_inetdrv(void* arg, const http_atom_t* meth, const char* meth_ptr,
i = LOAD_TUPLE(spec, i, 2);
i = LOAD_TUPLE(spec, i, 4);
ASSERT(i <= 43);
- return driver_send_term(desc->inet.port, caller, spec, i);
+ return erl_drv_send_term(desc->inet.dport, caller, spec, i);
}
else {
i = LOAD_TUPLE(spec, i, 3);
ASSERT(i <= 43);
- return driver_output_term(desc->inet.port, spec, i);
+ return erl_drv_output_term(desc->inet.dport, spec, i);
}
}
@@ -2314,12 +2317,12 @@ http_header_inetdrv(void* arg, const http_atom_t* name, const char* name_ptr,
i = LOAD_TUPLE(spec, i, 2);
i = LOAD_TUPLE(spec, i, 4);
ASSERT(i <= 26);
- return driver_send_term(desc->inet.port, caller, spec, i);
+ return erl_drv_send_term(desc->inet.dport, caller, spec, i);
}
else {
i = LOAD_TUPLE(spec, i, 3);
ASSERT(i <= 26);
- return driver_output_term(desc->inet.port, spec, i);
+ return erl_drv_output_term(desc->inet.dport, spec, i);
}
}
@@ -2345,7 +2348,7 @@ static int http_eoh_inetdrv(void* arg)
i = LOAD_TUPLE(spec, i, 2);
i = LOAD_TUPLE(spec, i, 4);
ASSERT(i <= 14);
- return driver_send_term(desc->inet.port, caller, spec, i);
+ return erl_drv_send_term(desc->inet.dport, caller, spec, i);
}
else {
/* {http, S, http_eoh} */
@@ -2354,7 +2357,7 @@ static int http_eoh_inetdrv(void* arg)
i = LOAD_ATOM(spec, i, am_http_eoh);
i = LOAD_TUPLE(spec, i, 3);
ASSERT(i <= 14);
- return driver_output_term(desc->inet.port, spec, i);
+ return erl_drv_output_term(desc->inet.dport, spec, i);
}
}
@@ -2382,7 +2385,7 @@ static int http_error_inetdrv(void* arg, const char* buf, int len)
i = LOAD_TUPLE(spec, i, 2);
i = LOAD_TUPLE(spec, i, 4);
ASSERT(i <= 19);
- return driver_send_term(desc->inet.port, caller, spec, i);
+ return erl_drv_send_term(desc->inet.dport, caller, spec, i);
}
else {
/* {http, S, {http_error,Line} */
@@ -2393,7 +2396,7 @@ static int http_error_inetdrv(void* arg, const char* buf, int len)
i = LOAD_TUPLE(spec, i, 2);
i = LOAD_TUPLE(spec, i, 3);
ASSERT(i <= 19);
- return driver_output_term(desc->inet.port, spec, i);
+ return erl_drv_output_term(desc->inet.dport, spec, i);
}
}
@@ -2446,11 +2449,11 @@ int ssl_tls_inetdrv(void* arg, unsigned type, unsigned major, unsigned minor,
i = LOAD_TUPLE(spec, i, 2);
i = LOAD_TUPLE(spec, i, 4);
ASSERT(i <= 28);
- ret = driver_send_term(desc->inet.port, caller, spec, i);
+ ret = erl_drv_send_term(desc->inet.dport, caller, spec, i);
}
else {
ASSERT(i <= 28);
- ret = driver_output_term(desc->inet.port, spec, i);
+ ret = erl_drv_output_term(desc->inet.dport, spec, i);
}
done:
driver_free_binary(bin);
@@ -2500,7 +2503,7 @@ static int inet_async_data(inet_descriptor* desc, const char* buf, int len)
i = LOAD_TUPLE(spec, i, 4);
ASSERT(i == 15);
desc->caller = 0;
- return driver_send_term(desc->port, caller, spec, i);
+ return erl_drv_send_term(desc->dport, caller, spec, i);
}
else {
/* INET_MODE_BINARY => [H1,H2,...HSz | Binary] */
@@ -2514,7 +2517,7 @@ static int inet_async_data(inet_descriptor* desc, const char* buf, int len)
i = LOAD_TUPLE(spec, i, 4);
ASSERT(i <= 20);
desc->caller = 0;
- code = driver_send_term(desc->port, caller, spec, i);
+ code = erl_drv_send_term(desc->dport, caller, spec, i);
return code;
}
}
@@ -3107,7 +3110,7 @@ inet_async_binary_data
ASSERT(i <= PACKET_ERL_DRV_TERM_DATA_LEN);
desc->caller = 0;
- return driver_send_term(desc->port, caller, spec, i);
+ return erl_drv_send_term(desc->dport, caller, spec, i);
}
/*
@@ -3130,7 +3133,7 @@ static int tcp_message(inet_descriptor* desc, const char* buf, int len)
i = LOAD_STRING(spec, i, buf, len); /* => [H1,H2,...Hn] */
i = LOAD_TUPLE(spec, i, 3);
ASSERT(i <= 20);
- return driver_output_term(desc->port, spec, i);
+ return erl_drv_output_term(desc->dport, spec, i);
}
else {
/* INET_MODE_BINARY => [H1,H2,...HSz | Binary] */
@@ -3142,7 +3145,7 @@ static int tcp_message(inet_descriptor* desc, const char* buf, int len)
i = LOAD_STRING_CONS(spec, i, buf, hsz);
i = LOAD_TUPLE(spec, i, 3);
ASSERT(i <= 20);
- code = driver_output_term(desc->port, spec, i);
+ code = erl_drv_output_term(desc->dport, spec, i);
return code;
}
}
@@ -3177,7 +3180,7 @@ tcp_binary_message(inet_descriptor* desc, ErlDrvBinary* bin, int offs, int len)
}
i = LOAD_TUPLE(spec, i, 3);
ASSERT(i <= 20);
- return driver_output_term(desc->port, spec, i);
+ return erl_drv_output_term(desc->dport, spec, i);
}
/*
@@ -3196,7 +3199,7 @@ static int tcp_closed_message(tcp_descriptor* desc)
i = LOAD_PORT(spec, i, desc->inet.dport);
i = LOAD_TUPLE(spec, i, 2);
ASSERT(i <= 6);
- return driver_output_term(desc->inet.port, spec, i);
+ return erl_drv_output_term(desc->inet.dport, spec, i);
}
return 0;
}
@@ -3217,7 +3220,7 @@ static int tcp_error_message(tcp_descriptor* desc, int err)
i = LOAD_ATOM(spec, i, am_err);
i = LOAD_TUPLE(spec, i, 3);
ASSERT(i <= 8);
- return driver_output_term(desc->inet.port, spec, i);
+ return erl_drv_output_term(desc->inet.dport, spec, i);
}
/*
@@ -3308,7 +3311,7 @@ static int packet_binary_message
/* Close up the outer 5-tuple: */
i = LOAD_TUPLE(spec, i, 5);
ASSERT(i <= PACKET_ERL_DRV_TERM_DATA_LEN);
- return driver_output_term(desc->port, spec, i);
+ return erl_drv_output_term(desc->dport, spec, i);
}
/*
@@ -3335,7 +3338,7 @@ static int packet_error_message(udp_descriptor* udesc, int err)
i = LOAD_ATOM(spec, i, am_err);
i = LOAD_TUPLE(spec, i, 3);
ASSERT(i == sizeof(spec)/sizeof(*spec));
- return driver_output_term(desc->port, spec, i);
+ return erl_drv_output_term(desc->dport, spec, i);
}
@@ -3486,6 +3489,7 @@ static void inet_init_sctp(void) {
INIT_ATOM(dontroute);
INIT_ATOM(priority);
INIT_ATOM(tos);
+ INIT_ATOM(ipv6_v6only);
/* Option names */
INIT_ATOM(sctp_rtoinfo);
@@ -5462,6 +5466,28 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len)
}
continue;
+ case INET_LOPT_TCP_MSGQ_HIWTRMRK:
+ if (desc->stype == SOCK_STREAM) {
+ ErlDrvSizeT high;
+ if (ival < ERL_DRV_BUSY_MSGQ_LIM_MIN
+ || ERL_DRV_BUSY_MSGQ_LIM_MAX < ival)
+ return -1;
+ high = (ErlDrvSizeT) ival;
+ erl_drv_busy_msgq_limits(desc->port, NULL, &high);
+ }
+ continue;
+
+ case INET_LOPT_TCP_MSGQ_LOWTRMRK:
+ if (desc->stype == SOCK_STREAM) {
+ ErlDrvSizeT low;
+ if (ival < ERL_DRV_BUSY_MSGQ_LIM_MIN
+ || ERL_DRV_BUSY_MSGQ_LIM_MAX < ival)
+ return -1;
+ low = (ErlDrvSizeT) ival;
+ erl_drv_busy_msgq_limits(desc->port, &low, NULL);
+ }
+ continue;
+
case INET_LOPT_TCP_SEND_TIMEOUT:
if (desc->stype == SOCK_STREAM) {
tcp_descriptor* tdesc = (tcp_descriptor*) desc;
@@ -5618,6 +5644,23 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len)
#endif /* HAVE_MULTICAST_SUPPORT */
+ case INET_OPT_IPV6_V6ONLY:
+#if HAVE_DECL_IPV6_V6ONLY
+ proto = IPPROTO_IPV6;
+ type = IPV6_V6ONLY;
+ propagate = 1;
+ DEBUGF(("inet_set_opts(%ld): s=%d, IPV6_V6ONLY=%d\r\n",
+ (long)desc->port, desc->s, ival));
+ break;
+#elif defined(__WIN32__) && defined(HAVE_IN6) && defined(AF_INET6)
+ /* Fake a'la OpenBSD; set to 'true' is fine but 'false' invalid. */
+ if (ival != 0) continue;
+ else return -1;
+ break;
+#else
+ continue;
+#endif
+
case INET_OPT_RAW:
if (len < 8) {
return -1;
@@ -5947,6 +5990,22 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len)
continue; /* Option not supported -- ignore it */
# endif
+ case INET_OPT_IPV6_V6ONLY:
+# if HAVE_DECL_IPV6_V6ONLY
+ {
+ arg.ival= get_int32 (curr); curr += 4;
+ proto = IPPROTO_IPV6;
+ type = IPV6_V6ONLY;
+ arg_ptr = (char*) (&arg.ival);
+ arg_sz = sizeof ( arg.ival);
+ break;
+ }
+# elif defined(__WIN32__) && defined(HAVE_IN6) && defined(AF_INET6)
+# error Here is a fix for Win IPv6 SCTP missing
+# else
+ continue; /* Option not supported -- ignore it */
+# endif
+
case SCTP_OPT_AUTOCLOSE:
{
arg.ival= get_int32 (curr); curr += 4;
@@ -6329,6 +6388,32 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc,
}
continue;
+ case INET_LOPT_TCP_MSGQ_HIWTRMRK:
+ if (desc->stype == SOCK_STREAM) {
+ ErlDrvSizeT high = ERL_DRV_BUSY_MSGQ_READ_ONLY;
+ *ptr++ = opt;
+ erl_drv_busy_msgq_limits(desc->port, NULL, &high);
+ ival = high > INT_MAX ? INT_MAX : (int) high;
+ put_int32(ival, ptr);
+ }
+ else {
+ TRUNCATE_TO(0,ptr);
+ }
+ continue;
+
+ case INET_LOPT_TCP_MSGQ_LOWTRMRK:
+ if (desc->stype == SOCK_STREAM) {
+ ErlDrvSizeT low = ERL_DRV_BUSY_MSGQ_READ_ONLY;
+ *ptr++ = opt;
+ erl_drv_busy_msgq_limits(desc->port, &low, NULL);
+ ival = low > INT_MAX ? INT_MAX : (int) low;
+ put_int32(ival, ptr);
+ }
+ else {
+ TRUNCATE_TO(0,ptr);
+ }
+ continue;
+
case INET_LOPT_TCP_SEND_TIMEOUT:
if (desc->stype == SOCK_STREAM) {
*ptr++ = opt;
@@ -6435,6 +6520,22 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc,
break;
#endif /* HAVE_MULTICAST_SUPPORT */
+ case INET_OPT_IPV6_V6ONLY:
+#if HAVE_DECL_IPV6_V6ONLY
+ proto = IPPROTO_IPV6;
+ type = IPV6_V6ONLY;
+ break;
+#elif defined(__WIN32__) && defined(HAVE_IN6) && defined(AF_INET6)
+ /* Fake reading 'true' */
+ *ptr++ = opt;
+ put_int32(1, ptr);
+ ptr += 4;
+ continue;
+#else
+ TRUNCATE_TO(0,ptr);
+ continue; /* skip - no result */
+#endif
+
case INET_OPT_RAW:
{
int data_provided;
@@ -6739,6 +6840,7 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc,
case INET_OPT_DONTROUTE:
case INET_OPT_PRIORITY :
case INET_OPT_TOS :
+ case INET_OPT_IPV6_V6ONLY:
case SCTP_OPT_AUTOCLOSE:
case SCTP_OPT_MAXSEG :
/* The following options return true or false: */
@@ -6811,6 +6913,20 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc,
continue;
# endif
}
+ case INET_OPT_IPV6_V6ONLY:
+# if HAVE_DECL_IPV6_V6ONLY
+ {
+ proto = IPPROTO_IPV6;
+ type = IPV6_V6ONLY;
+ tag = am_ipv6_v6only;
+ break;
+ }
+# elif defined(__WIN32__) && defined(HAVE_IN6) && defined(AF_INET6)
+# error Here is a fix for Win IPv6 SCTP needed
+# else
+ /* Not supported -- ignore */
+ continue;
+# endif
case SCTP_OPT_AUTOCLOSE:
{
proto = IPPROTO_SCTP;
@@ -7211,7 +7327,7 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc,
i = LOAD_TUPLE(spec, i, 3);
/* Now, convert "spec" into the returnable term: */
- driver_send_term(desc->port, driver_caller(desc->port), spec, i);
+ erl_drv_send_term(desc->dport, driver_caller(desc->port), spec, i);
FREE(spec);
(*dest)[0] = INET_REP;
@@ -7293,7 +7409,7 @@ send_empty_out_q_msgs(inet_descriptor* desc)
ASSERT(msg_len == sizeof(msg)/sizeof(*msg));
- send_to_subscribers(desc->port,
+ send_to_subscribers(desc->dport,
&desc->empty_out_q_subs,
1,
msg,
@@ -7940,6 +8056,7 @@ static int tcp_inet_init(void)
static ErlDrvData tcp_inet_start(ErlDrvPort port, char* args)
{
+ ErlDrvSizeT q_low, q_high;
tcp_descriptor* desc;
DEBUGF(("tcp_inet_start(%ld) {\r\n", (long)port));
@@ -7949,6 +8066,17 @@ static ErlDrvData tcp_inet_start(ErlDrvPort port, char* args)
return ERL_DRV_ERROR_ERRNO;
desc->high = INET_HIGH_WATERMARK;
desc->low = INET_LOW_WATERMARK;
+ q_high = INET_HIGH_MSGQ_WATERMARK;
+ q_low = INET_LOW_MSGQ_WATERMARK;
+ if (q_low < ERL_DRV_BUSY_MSGQ_LIM_MIN)
+ q_low = ERL_DRV_BUSY_MSGQ_LIM_MIN;
+ else if (q_low > ERL_DRV_BUSY_MSGQ_LIM_MAX)
+ q_low = ERL_DRV_BUSY_MSGQ_LIM_MAX;
+ if (q_high < ERL_DRV_BUSY_MSGQ_LIM_MIN)
+ q_high = ERL_DRV_BUSY_MSGQ_LIM_MIN;
+ else if (q_high > ERL_DRV_BUSY_MSGQ_LIM_MAX)
+ q_high = ERL_DRV_BUSY_MSGQ_LIM_MAX;
+ erl_drv_busy_msgq_limits(port, &q_low, &q_high);
desc->send_timeout = INET_INFINITY;
desc->send_timeout_close = 0;
desc->busy_on_send = 0;
@@ -7972,6 +8100,7 @@ static ErlDrvData tcp_inet_start(ErlDrvPort port, char* args)
static tcp_descriptor* tcp_inet_copy(tcp_descriptor* desc,SOCKET s,
ErlDrvTermData owner, int* err)
{
+ ErlDrvSizeT q_low, q_high;
ErlDrvPort port = desc->inet.port;
tcp_descriptor* copy_desc;
@@ -8009,6 +8138,13 @@ static tcp_descriptor* tcp_inet_copy(tcp_descriptor* desc,SOCKET s,
FREE(copy_desc);
return NULL;
}
+
+ /* Read busy msgq limits of parent */
+ q_low = q_high = ERL_DRV_BUSY_MSGQ_READ_ONLY;
+ erl_drv_busy_msgq_limits(desc->inet.port, &q_low, &q_high);
+ /* Write same busy msgq limits to child */
+ erl_drv_busy_msgq_limits(port, &q_low, &q_high);
+
copy_desc->inet.port = port;
copy_desc->inet.dport = driver_mk_port(port);
*err = 0;
@@ -8041,7 +8177,7 @@ static void tcp_close_check(tcp_descriptor* desc)
desc->inet.state = INET_STATE_LISTENING;
while (deq_multi_op(desc,&id,&req,&caller,NULL,&monitor) == 0) {
driver_demonitor_process(desc->inet.port, &monitor);
- send_async_error(desc->inet.port, desc->inet.dport, id, caller, am_closed);
+ send_async_error(desc->inet.dport, id, caller, am_closed);
}
clean_multi_timers(&(desc->mtd), desc->inet.port);
}
@@ -8465,7 +8601,7 @@ static void tcp_inet_multi_timeout(ErlDrvData e, ErlDrvTermData caller)
sock_select(INETP(desc),FD_ACCEPT,0);
desc->inet.state = INET_STATE_LISTENING; /* restore state */
}
- send_async_error(desc->inet.port, desc->inet.dport, id, caller, am_timeout);
+ send_async_error(desc->inet.dport, id, caller, am_timeout);
}
@@ -9206,7 +9342,7 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event)
if (s == INVALID_SOCKET) { /* Not ERRNO_BLOCK, that's handled right away */
- ret = send_async_error(desc->inet.port, desc->inet.dport,
+ ret = send_async_error(desc->inet.dport,
id, caller, error_atom(sock_errno()));
goto done;
}
@@ -9216,7 +9352,7 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event)
if ((accept_desc = tcp_inet_copy(desc,s,caller,&err)) == NULL) {
sock_close(s);
- ret = send_async_error(desc->inet.port, desc->inet.dport,
+ ret = send_async_error(desc->inet.dport,
id, caller, error_atom(err));
goto done;
}
@@ -9227,7 +9363,7 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event)
ERL_DRV_READ, 1);
#endif
accept_desc->inet.state = INET_STATE_CONNECTED;
- ret = send_async_ok_port(desc->inet.port, desc->inet.dport,
+ ret = send_async_ok_port(desc->inet.dport,
id, caller, accept_desc->inet.dport);
}
}
@@ -10095,6 +10231,7 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf,
}
new_udesc->inet.state = INET_STATE_CONNECTED;
new_udesc->inet.stype = SOCK_STREAM;
+ SET_NONBLOCKING(new_udesc->inet.s);
inet_reply_ok_port(desc, new_udesc->inet.dport);
(*rbuf)[0] = INET_REP;
@@ -10868,7 +11005,7 @@ subs_list *subs;
static void send_to_subscribers
(
- ErlDrvPort port,
+ ErlDrvTermData port,
subs_list *subs,
int free_subs,
ErlDrvTermData msg[],
@@ -10885,7 +11022,7 @@ static void send_to_subscribers
this = subs;
while(this) {
- (void) driver_send_term(port, this->subscriber, msg, msg_len);
+ (void) erl_drv_send_term(port, this->subscriber, msg, msg_len);
if(free_subs && !first) {
next = this->next;
diff --git a/erts/emulator/drivers/common/ram_file_drv.c b/erts/emulator/drivers/common/ram_file_drv.c
index a109e40333..7f7cd7cd91 100644
--- a/erts/emulator/drivers/common/ram_file_drv.c
+++ b/erts/emulator/drivers/common/ram_file_drv.c
@@ -48,6 +48,7 @@
#define RAM_FILE_SIZE 37 /* get file size */
#define RAM_FILE_ADVISE 38 /* predeclare the access
* pattern for file data */
+#define RAM_FILE_ALLOCATE 39 /* allocate space for a file */
/* possible new operations include:
DES_ENCRYPT
DES_DECRYPT
@@ -720,6 +721,13 @@ static void rfile_command(ErlDrvData e, char* buf, ErlDrvSizeT count)
else
reply(f, 1, 0);
break;
+
+ case RAM_FILE_ALLOCATE:
+ if (f->flags == 0)
+ error_reply(f, EBADF);
+ else
+ reply(f, 1, 0);
+ break;
}
/*
* Ignore anything else -- let the caller hang.
diff --git a/erts/emulator/drivers/unix/ttsl_drv.c b/erts/emulator/drivers/unix/ttsl_drv.c
index b29f80a8ba..ab2abb88d1 100644
--- a/erts/emulator/drivers/unix/ttsl_drv.c
+++ b/erts/emulator/drivers/unix/ttsl_drv.c
@@ -912,11 +912,15 @@ static int insert_buf(byte *s, int n)
lbuf[lpos++] = (CONTROL_TAG | ((Uint32) ch));
ch = 0;
} while (lpos % 8);
- } else if (ch == '\n' || ch == '\r') {
+ } else if (ch == '\e' || ch == '\n' || ch == '\r') {
write_buf(lbuf + buffpos, lpos - buffpos);
- outc('\r');
- if (ch == '\n')
- outc('\n');
+ if (ch == '\e') {
+ outc('\e');
+ } else {
+ outc('\r');
+ if (ch == '\n')
+ outc('\n');
+ }
if (llen > lpos) {
memcpy(lbuf, lbuf + lpos, llen - lpos);
}
diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c
index 2aa373aa7d..558651fff9 100644
--- a/erts/emulator/drivers/unix/unix_efile.c
+++ b/erts/emulator/drivers/unix/unix_efile.c
@@ -22,6 +22,12 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
+#if defined(HAVE_POSIX_FALLOCATE) && !defined(__sun) && !defined(__sun__)
+#define _XOPEN_SOURCE 600
+#endif
+#if !defined(_GNU_SOURCE) && defined(HAVE_LINUX_FALLOC_H)
+#define _GNU_SOURCE
+#endif
#include "sys.h"
#include "erl_driver.h"
#include "erl_efile.h"
@@ -41,9 +47,13 @@
#define DARWIN 1
#endif
-#ifdef DARWIN
+#if defined(DARWIN) || defined(HAVE_LINUX_FALLOC_H) || defined(HAVE_POSIX_FALLOCATE)
#include <fcntl.h>
-#endif /* DARWIN */
+#endif
+
+#ifdef HAVE_LINUX_FALLOC_H
+#include <linux/falloc.h>
+#endif
#ifdef SUNOS4
# define getcwd(buf, size) getwd(buf)
@@ -851,8 +861,8 @@ efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset,
}
#ifdef HAVE_SENDFILE
-// For some reason the maximum size_t cannot be used as the max size
-// 3GB seems to work on all platforms
+/* For some reason the maximum size_t cannot be used as the max size
+ 3GB seems to work on all platforms */
#define SENDFILE_CHUNK_SIZE ((1UL << 30) -1)
/*
@@ -889,7 +899,7 @@ efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd,
#if defined(__linux__)
ssize_t retval;
do {
- // check if *nbytes is 0 or greater than chunk size
+ /* check if *nbytes is 0 or greater than chunk size */
if (*nbytes == 0 || *nbytes > SENDFILE_CHUNK_SIZE)
retval = sendfile(out_fd, in_fd, offset, SENDFILE_CHUNK_SIZE);
else
@@ -900,7 +910,7 @@ efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd,
}
} while (retval == SENDFILE_CHUNK_SIZE);
if (written != 0) {
- // -1 is not returned by the linux API so we have to simulate it
+ /* -1 is not returned by the linux API so we have to simulate it */
retval = -1;
errno = EAGAIN;
}
@@ -913,23 +923,29 @@ efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd,
do {
fdrec.sfv_off = *offset;
len = 0;
- // check if *nbytes is 0 or greater than chunk size
+ /* check if *nbytes is 0 or greater than chunk size */
if (*nbytes == 0 || *nbytes > SENDFILE_CHUNK_SIZE)
fdrec.sfv_len = SENDFILE_CHUNK_SIZE;
else
fdrec.sfv_len = *nbytes;
retval = sendfilev(out_fd, &fdrec, 1, &len);
- if (retval != -1 || errno == EAGAIN || errno == EINTR) {
+
+ /* Sometimes sendfilev can return -1 and still send data.
+ When that happens we just pretend that no error happend. */
+ if (retval != -1 || errno == EAGAIN || errno == EINTR ||
+ len != 0) {
*offset += len;
*nbytes -= len;
written += len;
+ if (errno != EAGAIN && errno != EINTR && len != 0)
+ retval = len;
}
} while (len == SENDFILE_CHUNK_SIZE);
#elif defined(DARWIN)
int retval;
off_t len;
do {
- // check if *nbytes is 0 or greater than chunk size
+ /* check if *nbytes is 0 or greater than chunk size */
if(*nbytes > SENDFILE_CHUNK_SIZE)
len = SENDFILE_CHUNK_SIZE;
else
@@ -961,3 +977,81 @@ efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd,
return check_error(retval, errInfo);
}
#endif /* HAVE_SENDFILE */
+
+#ifdef HAVE_POSIX_FALLOCATE
+static int
+call_posix_fallocate(int fd, Sint64 offset, Sint64 length)
+{
+ int ret;
+
+ /*
+ * On Linux and Solaris for example, posix_fallocate() returns
+ * a positive error number on error and it does not set errno.
+ * On FreeBSD however (9.0 at least), it returns -1 on error
+ * and it sets errno.
+ */
+ do {
+ ret = posix_fallocate(fd, (off_t) offset, (off_t) length);
+ if (ret > 0) {
+ errno = ret;
+ ret = -1;
+ }
+ } while (ret != 0 && errno == EINTR);
+
+ return ret;
+}
+#endif /* HAVE_POSIX_FALLOCATE */
+
+int
+efile_fallocate(Efile_error* errInfo, int fd, Sint64 offset, Sint64 length)
+{
+#if defined HAVE_FALLOCATE
+ /* Linux specific, more efficient than posix_fallocate. */
+ int ret;
+
+ do {
+ ret = fallocate(fd, FALLOC_FL_KEEP_SIZE, (off_t) offset, (off_t) length);
+ } while (ret != 0 && errno == EINTR);
+
+#if defined HAVE_POSIX_FALLOCATE
+ /* Fallback to posix_fallocate if available. */
+ if (ret != 0) {
+ ret = call_posix_fallocate(fd, offset, length);
+ }
+#endif
+
+ return check_error(ret, errInfo);
+#elif defined F_PREALLOCATE
+ /* Mac OS X specific, equivalent to posix_fallocate. */
+ int ret;
+ fstore_t fs;
+
+ memset(&fs, 0, sizeof(fs));
+ fs.fst_flags = F_ALLOCATECONTIG;
+ fs.fst_posmode = F_VOLPOSMODE;
+ fs.fst_offset = (off_t) offset;
+ fs.fst_length = (off_t) length;
+
+ ret = fcntl(fd, F_PREALLOCATE, &fs);
+
+ if (-1 == ret) {
+ fs.fst_flags = F_ALLOCATEALL;
+ ret = fcntl(fd, F_PREALLOCATE, &fs);
+
+#if defined HAVE_POSIX_FALLOCATE
+ /* Fallback to posix_fallocate if available. */
+ if (-1 == ret) {
+ ret = call_posix_fallocate(fd, offset, length);
+ }
+#endif
+ }
+
+ return check_error(ret, errInfo);
+#elif defined HAVE_POSIX_FALLOCATE
+ /* Other Unixes, use posix_fallocate if available. */
+ return check_error(call_posix_fallocate(fd, offset, length), errInfo);
+#else
+ errno = ENOTSUP;
+ return check_error(-1, errInfo);
+#endif
+}
diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c
index dc7add01f7..f5011d11a5 100644
--- a/erts/emulator/drivers/win32/win_efile.c
+++ b/erts/emulator/drivers/win32/win_efile.c
@@ -1558,3 +1558,13 @@ efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset,
errno = ERROR_SUCCESS;
return check_error(0, errInfo);
}
+
+int
+efile_fallocate(Efile_error* errInfo, int fd, Sint64 offset, Sint64 length)
+{
+ /* No file preallocation method available in Windows. */
+ errno = errno_map(ERROR_NOT_SUPPORTED);
+ SetLastError(ERROR_NOT_SUPPORTED);
+
+ return check_error(-1, errInfo);
+}
diff --git a/erts/emulator/hipe/hipe_amd64_bifs.m4 b/erts/emulator/hipe/hipe_amd64_bifs.m4
index ec25c0b9b7..0de69a617f 100644
--- a/erts/emulator/hipe/hipe_amd64_bifs.m4
+++ b/erts/emulator/hipe/hipe_amd64_bifs.m4
@@ -2,7 +2,7 @@ changecom(`/*', `*/')dnl
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2004-2012. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -30,12 +30,12 @@ include(`hipe/hipe_amd64_asm.m4')
#define TEST_GOT_EXN cmpq $THE_NON_VALUE, %rax
#endif'
-define(TEST_GOT_MBUF,`movq P_MBUF(P), %rdx # `TEST_GOT_MBUF'
+define(TEST_GOT_MBUF,`movq P_MBUF(P), %rdx /* `TEST_GOT_MBUF' */
testq %rdx, %rdx
jnz 3f
2:')
define(HANDLE_GOT_MBUF,`
-3: call nbif_$1_gc_after_bif # `HANDLE_GOT_MBUF'
+3: call nbif_$1_gc_after_bif /* `HANDLE_GOT_MBUF' */
jmp 2b')
`#if defined(ERTS_ENABLE_LOCK_CHECK) && defined(ERTS_SMP)
diff --git a/erts/emulator/hipe/hipe_bif_list.m4 b/erts/emulator/hipe/hipe_bif_list.m4
index d9aa09b79e..764b8d180c 100644
--- a/erts/emulator/hipe/hipe_bif_list.m4
+++ b/erts/emulator/hipe/hipe_bif_list.m4
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2004-2012. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -145,6 +145,7 @@
* Zero-arity BIFs that can fail.
*/
standard_bif_interface_0(nbif_processes_0, processes_0)
+standard_bif_interface_0(nbif_ports_0, ports_0)
/*
* BIFs and primops that may do a GC (change heap limit and walk the native stack).
@@ -246,7 +247,7 @@ noproc_primop_interface_5(nbif_bs_put_big_integer, hipe_bs_put_big_integer)
gc_bif_interface_0(nbif_check_get_msg, hipe_check_get_msg)
-#ifdef NO_FPE_SIGNALS
+#`ifdef' NO_FPE_SIGNALS
nocons_nofail_primop_interface_0(nbif_emulate_fpe, hipe_emulate_fpe)
#endif
diff --git a/erts/emulator/hipe/hipe_debug.c b/erts/emulator/hipe/hipe_debug.c
index 37615bf718..f2e9d03607 100644
--- a/erts/emulator/hipe/hipe_debug.c
+++ b/erts/emulator/hipe/hipe_debug.c
@@ -189,11 +189,10 @@ void hipe_print_pcb(Process *p)
U("old_head ", old_heap);
U("min_heap_..", min_heap_size);
U("rcount ", rcount);
- U("id ", id);
- U("prio ", prio);
+ U("id ", common.id);
U("reds ", reds);
- U("tracer_pr..", tracer_proc);
- U("trace_fla..", trace_flags);
+ U("tracer_pr..", common.tracer_proc);
+ U("trace_fla..", common.trace_flags);
U("group_lea..", group_leader);
U("flags ", flags);
U("fvalue ", fvalue);
@@ -202,8 +201,8 @@ void hipe_print_pcb(Process *p)
/*XXX: ErlTimer tm; */
U("next ", next);
/*XXX: ErlOffHeap off_heap; */
- U("reg ", reg);
- U("nlinks ", nlinks);
+ U("reg ", common.u.alive.reg);
+ U("nlinks ", common.u.alive.links);
/*XXX: ErlMessageQueue msg; */
U("mbuf ", mbuf);
U("mbuf_sz ", mbuf_sz);
diff --git a/erts/emulator/hipe/hipe_mkliterals.c b/erts/emulator/hipe/hipe_mkliterals.c
index cbbf1db2e5..0e287908b1 100644
--- a/erts/emulator/hipe/hipe_mkliterals.c
+++ b/erts/emulator/hipe/hipe_mkliterals.c
@@ -262,47 +262,6 @@ static const struct literal {
const char *name;
int value;
} literals[] = {
- /* Field offsets in a process struct */
- { "P_HP", offsetof(struct process, htop) },
- { "P_HP_LIMIT", offsetof(struct process, stop) },
- { "P_OFF_HEAP_FIRST", offsetof(struct process, off_heap.first) },
- { "P_MBUF", offsetof(struct process, mbuf) },
- { "P_ID", offsetof(struct process, id) },
- { "P_FLAGS", offsetof(struct process, flags) },
- { "P_FVALUE", offsetof(struct process, fvalue) },
- { "P_FREASON", offsetof(struct process, freason) },
- { "P_FTRACE", offsetof(struct process, ftrace) },
- { "P_FCALLS", offsetof(struct process, fcalls) },
- { "P_BEAM_IP", offsetof(struct process, i) },
- { "P_ARITY", offsetof(struct process, arity) },
- { "P_ARG0", offsetof(struct process, def_arg_reg[0]) },
- { "P_ARG1", offsetof(struct process, def_arg_reg[1]) },
- { "P_ARG2", offsetof(struct process, def_arg_reg[2]) },
- { "P_ARG3", offsetof(struct process, def_arg_reg[3]) },
- { "P_ARG4", offsetof(struct process, def_arg_reg[4]) },
- { "P_ARG5", offsetof(struct process, def_arg_reg[5]) },
-#ifdef HIPE
- { "P_NSP", offsetof(struct process, hipe.nsp) },
- { "P_NCALLEE", offsetof(struct process, hipe.ncallee) },
- { "P_CLOSURE", offsetof(struct process, hipe.closure) },
-#if defined(__i386__) || defined(__x86_64__)
- { "P_NSP_LIMIT", offsetof(struct process, hipe.nstack) },
- { "P_CSP", offsetof(struct process, hipe.ncsp) },
-#elif defined(__sparc__) || defined(__powerpc__) || defined(__ppc__) || defined(__powerpc64__) || defined(__arm__)
- { "P_NSP_LIMIT", offsetof(struct process, hipe.nstack) },
- { "P_NRA", offsetof(struct process, hipe.nra) },
-#endif
- { "P_NARITY", offsetof(struct process, hipe.narity) },
- { "P_FLOAT_RESULT",
-# ifdef NO_FPE_SIGNALS
- offsetof(struct process, hipe.float_result)
-# endif
- },
-# if defined(ERTS_ENABLE_LOCK_CHECK) && defined(ERTS_SMP)
- { "P_BIF_CALLEE", offsetof(struct process, hipe.bif_callee) },
-# endif
-#endif /* HIPE */
-
/* process flags bits */
{ "F_TIMO", F_TIMO },
@@ -380,8 +339,6 @@ static const struct literal {
{ "MS_SAVEOFFSET_SIZE", field_sizeof(struct erl_bin_match_struct, save_offset)},
/* messages */
- { "P_MSG_FIRST", offsetof(struct process, msg.first) },
- { "P_MSG_SAVE", offsetof(struct process, msg.save) },
{ "MSG_NEXT", offsetof(struct erl_mesg, next) },
/* ARM */
@@ -460,12 +417,14 @@ static const struct atom_literal {
* These depend on configuration options such as heap architecture.
* The compiler accesses these through hipe_bifs:get_rts_param/1.
*/
-static const struct rts_param {
+struct rts_param {
unsigned int nr;
const char *name;
unsigned int is_defined;
int value;
-} rts_params[] = {
+};
+
+static const struct rts_param rts_params[] = {
{ 1, "P_OFF_HEAP_FUNS",
1, offsetof(struct process, off_heap.first)
},
@@ -518,7 +477,53 @@ static const struct rts_param {
{ 19, "MSG_MESSAGE",
1, offsetof(struct erl_mesg, m[0])
},
- /* highest entry ever used == 21 */
+
+ /* Field offsets in a process struct */
+ { 22, "P_HP", 1, offsetof(struct process, htop) },
+ { 23, "P_HP_LIMIT", 1, offsetof(struct process, stop) },
+ { 24, "P_OFF_HEAP_FIRST", 1, offsetof(struct process, off_heap.first) },
+ { 25, "P_MBUF", 1, offsetof(struct process, mbuf) },
+ { 26, "P_ID", 1, offsetof(struct process, common.id) },
+ { 27, "P_FLAGS", 1, offsetof(struct process, flags) },
+ { 28, "P_FVALUE", 1, offsetof(struct process, fvalue) },
+ { 29, "P_FREASON", 1, offsetof(struct process, freason) },
+ { 30, "P_FTRACE", 1, offsetof(struct process, ftrace) },
+ { 31, "P_FCALLS", 1, offsetof(struct process, fcalls) },
+ { 32, "P_BEAM_IP", 1, offsetof(struct process, i) },
+ { 33, "P_ARITY", 1, offsetof(struct process, arity) },
+ { 34, "P_ARG0", 1, offsetof(struct process, def_arg_reg[0]) },
+ { 35, "P_ARG1", 1, offsetof(struct process, def_arg_reg[1]) },
+ { 36, "P_ARG2", 1, offsetof(struct process, def_arg_reg[2]) },
+ { 37, "P_ARG3", 1, offsetof(struct process, def_arg_reg[3]) },
+ { 38, "P_ARG4", 1, offsetof(struct process, def_arg_reg[4]) },
+ { 39, "P_ARG5", 1, offsetof(struct process, def_arg_reg[5]) },
+ { 40, "P_NSP", 1, offsetof(struct process, hipe.nsp) },
+ { 41, "P_NCALLEE", 1, offsetof(struct process, hipe.ncallee) },
+ { 42, "P_CLOSURE", 1, offsetof(struct process, hipe.closure) },
+ { 43, "P_NSP_LIMIT", 1, offsetof(struct process, hipe.nstack) },
+ { 44, "P_CSP",
+#if defined(__i386__) || defined(__x86_64__)
+ 1, offsetof(struct process, hipe.ncsp)
+#endif
+ },
+ { 45, "P_NRA",
+#if defined(__sparc__) || defined(__powerpc__) || defined(__ppc__) || defined(__powerpc64__) || defined(__arm__)
+ 1, offsetof(struct process, hipe.nra)
+#endif
+ },
+ { 46, "P_NARITY", 1, offsetof(struct process, hipe.narity) },
+ { 47, "P_FLOAT_RESULT",
+#ifdef NO_FPE_SIGNALS
+ 1, offsetof(struct process, hipe.float_result)
+#endif
+ },
+ { 48, "P_BIF_CALLEE",
+#if defined(ERTS_ENABLE_LOCK_CHECK) && defined(ERTS_SMP)
+ 1, offsetof(struct process, hipe.bif_callee)
+#endif
+ },
+ { 49, "P_MSG_FIRST", 1, offsetof(struct process, msg.first) },
+ { 50, "P_MSG_SAVE", 1, offsetof(struct process, msg.save) },
};
#define NR_PARAMS ARRAY_SIZE(rts_params)
diff --git a/erts/emulator/hipe/hipe_x86.c b/erts/emulator/hipe/hipe_x86.c
index 24d232c968..4281730ae2 100644
--- a/erts/emulator/hipe/hipe_x86.c
+++ b/erts/emulator/hipe/hipe_x86.c
@@ -265,7 +265,7 @@ void *hipe_make_native_stub(void *beamAddress, unsigned int beamArity)
void hipe_arch_print_pcb(struct hipe_process_state *p)
{
#define U(n,x) \
- printf(" % 4d | %s | 0x%08x | |\r\n", offsetof(struct hipe_process_state,x), n, (unsigned)p->x)
+ printf(" % 4d | %s | 0x%08x | |\r\n", (int)offsetof(struct hipe_process_state,x), n, (unsigned)p->x)
U("ncsp ", ncsp);
U("narity ", narity);
#undef U
diff --git a/erts/emulator/hipe/hipe_x86_bifs.m4 b/erts/emulator/hipe/hipe_x86_bifs.m4
index 3cb7d67be0..dd6980f555 100644
--- a/erts/emulator/hipe/hipe_x86_bifs.m4
+++ b/erts/emulator/hipe/hipe_x86_bifs.m4
@@ -2,7 +2,7 @@ changecom(`/*', `*/')dnl
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2001-2012. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -35,12 +35,12 @@ include(`hipe/hipe_x86_asm.m4')
# define CALL_BIF(F) call CSYM(F)
#endif'
-define(TEST_GOT_MBUF,`movl P_MBUF(P), %edx # `TEST_GOT_MBUF'
+define(TEST_GOT_MBUF,`movl P_MBUF(P), %edx /* `TEST_GOT_MBUF' */
testl %edx, %edx
jnz 3f
2:')
define(HANDLE_GOT_MBUF,`
-3: call nbif_$1_gc_after_bif # `HANDLE_GOT_MBUF'
+3: call nbif_$1_gc_after_bif /* `HANDLE_GOT_MBUF' */
jmp 2b')
/*
@@ -70,7 +70,7 @@ ASYM($1):
NBIF_ARG_REG(0,P)
NBIF_ARG(2,1,0)
lea 8(%esp), %eax
- NBIF_ARG_REG(1,%eax) # BIF__ARGS
+ NBIF_ARG_REG(1,%eax) /* BIF__ARGS */
CALL_BIF($2)
TEST_GOT_MBUF
@@ -105,7 +105,7 @@ ASYM($1):
NBIF_ARG(2,2,0)
NBIF_ARG(3,2,1)
lea 8(%esp), %eax
- NBIF_ARG_REG(1,%eax) # BIF__ARGS
+ NBIF_ARG_REG(1,%eax) /* BIF__ARGS */
CALL_BIF($2)
TEST_GOT_MBUF
@@ -141,7 +141,7 @@ ASYM($1):
NBIF_ARG(3,3,1)
NBIF_ARG(4,3,2)
lea 8(%esp), %eax
- NBIF_ARG_REG(1,%eax) # BIF__ARGS
+ NBIF_ARG_REG(1,%eax) /* BIF__ARGS */
CALL_BIF($2)
TEST_GOT_MBUF
diff --git a/erts/emulator/pcre/pcre.mk b/erts/emulator/pcre/pcre.mk
index 352137b341..57bf5de2fb 100644
--- a/erts/emulator/pcre/pcre.mk
+++ b/erts/emulator/pcre/pcre.mk
@@ -49,18 +49,18 @@ PCRE_CFLAGS = $(filter-out -DDEBUG,$(CFLAGS)) -DERLANG_INTEGRATION
ifeq ($(TARGET), win32)
$(EPCRE_LIB): $(PCRE_OBJS)
- $(AR) -out:$@ $(PCRE_OBJS)
+ $(V_AR) -out:$@ $(PCRE_OBJS)
else
$(EPCRE_LIB): $(PCRE_OBJS)
- $(AR) $(ARFLAGS) $@ $(PCRE_OBJS)
+ $(V_AR) $(ARFLAGS) $@ $(PCRE_OBJS)
-@ ($(RANLIB) $@ || true) 2>/dev/null
endif
$(PCRE_OBJDIR)/%.o: pcre/%.c
- $(CC) -c $(PCRE_CFLAGS) -o $@ $<
+ $(V_CC) -c $(PCRE_CFLAGS) -o $@ $<
$(PCRE_GENINC): pcre/pcre_exec.c
- for x in `grep -n COST_CHK pcre/pcre_exec.c | grep -v 'COST_CHK(N)' | awk -F: '{print $$1}'`; \
+ $(gen_verbose)for x in `grep -n COST_CHK pcre/pcre_exec.c | grep -v 'COST_CHK(N)' | awk -F: '{print $$1}'`; \
do \
N=`expr $$x + 100`; \
echo "case $$N: goto L_LOOP_COUNT_$${x};"; \
diff --git a/erts/emulator/sys/common/erl_check_io.c b/erts/emulator/sys/common/erl_check_io.c
index ce014c19c2..474408ae7c 100644
--- a/erts/emulator/sys/common/erl_check_io.c
+++ b/erts/emulator/sys/common/erl_check_io.c
@@ -200,17 +200,6 @@ static void event_large_fd_error(ErlDrvPort, ErtsSysFdType, ErlDrvEventData);
#endif
static void steal_pending_stop_select(erts_dsprintf_buf_t*, ErlDrvPort,
ErtsDrvEventState*, int mode, int on);
-static ERTS_INLINE Eterm
-drvport2id(ErlDrvPort dp)
-{
- Port *pp = erts_drvport2port(dp);
- if (pp)
- return pp->id;
- else {
- ASSERT(0);
- return am_undefined;
- }
-}
#ifdef ERTS_SMP
ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(removed_fd, struct removed_fd, 64, ERTS_ALC_T_FD_LIST)
@@ -378,7 +367,7 @@ abort_task(Eterm id, ErtsPortTaskHandle *pthp, EventStateType type)
|| !erts_port_task_is_scheduled(pthp));
}
else if (erts_port_task_is_scheduled(pthp)) {
- erts_port_task_abort(id, pthp);
+ erts_port_task_abort(pthp);
ASSERT(erts_is_port_alive(id));
}
}
@@ -492,7 +481,7 @@ ERTS_CIO_EXPORT(driver_select)(ErlDrvPort ix,
int on)
{
void (*stop_select_fn)(ErlDrvEvent, void*) = NULL;
- Eterm id = drvport2id(ix);
+ Eterm id = erts_drvport2id(ix);
ErtsSysFdType fd = (ErtsSysFdType) e;
ErtsPollEvents ctl_events = (ErtsPollEvents) 0;
ErtsPollEvents new_events, old_events;
@@ -503,8 +492,8 @@ ERTS_CIO_EXPORT(driver_select)(ErlDrvPort ix,
DTRACE_CHARBUF(name, 64);
#endif
- ERTS_SMP_LC_ASSERT(erts_drvport2port(ix)
- && erts_lc_is_port_locked(erts_drvport2port(ix)));
+ ERTS_SMP_LC_ASSERT(erts_drvport2port(ix, NULL)
+ && erts_lc_is_port_locked(erts_drvport2port(ix, NULL)));
#ifdef ERTS_SYS_CONTINOUS_FD_NUMBERS
if ((unsigned)fd >= (unsigned)erts_smp_atomic_read_nob(&drv_ev_state_len)) {
@@ -530,9 +519,9 @@ ERTS_CIO_EXPORT(driver_select)(ErlDrvPort ix,
if (!on && (mode&ERL_DRV_USE_NO_CALLBACK) == ERL_DRV_USE) {
if (IS_FD_UNKNOWN(state)) {
/* fast track to stop_select callback */
- stop_select_fn = erts_drvport2port(ix)->drv_ptr->stop_select;
+ stop_select_fn = erts_drvport2port(ix, NULL)->drv_ptr->stop_select;
#ifdef USE_VM_PROBES
- strncpy(name, erts_drvport2port(ix)->drv_ptr->name, sizeof(name)-1);
+ strncpy(name, erts_drvport2port(ix, NULL)->drv_ptr->name, sizeof(name)-1);
name[sizeof(name)-1] = '\0';
#endif
ret = 0;
@@ -665,14 +654,14 @@ ERTS_CIO_EXPORT(driver_select)(ErlDrvPort ix,
}
}
if ((mode & ERL_DRV_USE_NO_CALLBACK) == ERL_DRV_USE) {
- erts_driver_t* drv_ptr = erts_drvport2port(ix)->drv_ptr;
+ erts_driver_t* drv_ptr = erts_drvport2port(ix, NULL)->drv_ptr;
ASSERT(new_events==0);
if (state->remove_cnt == 0 || !wake_poller) {
/* Safe to close fd now as it is not in pollset
or there was no need to eject fd (kernel poll) */
stop_select_fn = drv_ptr->stop_select;
#ifdef USE_VM_PROBES
- strncpy(name, erts_drvport2port(ix)->drv_ptr->name, sizeof(name)-1);
+ strncpy(name, erts_drvport2port(ix, NULL)->drv_ptr->name, sizeof(name)-1);
name[sizeof(name)-1] = '\0';
#endif
}
@@ -719,13 +708,13 @@ ERTS_CIO_EXPORT(driver_event)(ErlDrvPort ix,
ErtsPollEvents events;
ErtsPollEvents add_events;
ErtsPollEvents remove_events;
- Eterm id = drvport2id(ix);
+ Eterm id = erts_drvport2id(ix);
ErtsDrvEventState *state;
int do_wake = 0;
int ret;
- ERTS_SMP_LC_ASSERT(erts_drvport2port(ix)
- && erts_lc_is_port_locked(erts_drvport2port(ix)));
+ ERTS_SMP_LC_ASSERT(erts_drvport2port(ix, NULL)
+ && erts_lc_is_port_locked(erts_drvport2port(ix, NULL)));
#ifdef ERTS_SYS_CONTINOUS_FD_NUMBERS
if ((unsigned)fd >= (unsigned)erts_smp_atomic_read_nob(&drv_ev_state_len)) {
@@ -960,7 +949,7 @@ static void
print_select_op(erts_dsprintf_buf_t *dsbufp,
ErlDrvPort ix, ErtsSysFdType fd, int mode, int on)
{
- Port *pp = erts_drvport2port(ix);
+ Port *pp = erts_drvport2port(ix, NULL);
erts_dsprintf(dsbufp,
"driver_select(%p, %d,%s%s%s%s, %d) "
"by ",
@@ -971,8 +960,8 @@ print_select_op(erts_dsprintf_buf_t *dsbufp,
mode & ERL_DRV_USE ? " ERL_DRV_USE" : "",
mode & (ERL_DRV_USE_NO_CALLBACK & ~ERL_DRV_USE) ? "_NO_CALLBACK" : "",
on);
- print_driver_name(dsbufp, pp->id);
- erts_dsprintf(dsbufp, "driver %T ", pp ? pp->id : NIL);
+ print_driver_name(dsbufp, pp->common.id);
+ erts_dsprintf(dsbufp, "driver %T ", pp ? pp->common.id : NIL);
}
static void
@@ -1031,7 +1020,7 @@ steal_pending_stop_select(erts_dsprintf_buf_t *dsbufp, ErlDrvPort ix,
state->driver.drv_ptr = NULL;
}
else if ((mode & ERL_DRV_USE_NO_CALLBACK) == ERL_DRV_USE) {
- erts_driver_t* drv_ptr = erts_drvport2port(ix)->drv_ptr;
+ erts_driver_t* drv_ptr = erts_drvport2port(ix, NULL)->drv_ptr;
if (drv_ptr != state->driver.drv_ptr) {
/* Some other driver wants the stop_select callback */
if (state->driver.drv_ptr->handle) {
@@ -1053,7 +1042,7 @@ static void
print_event_op(erts_dsprintf_buf_t *dsbufp,
ErlDrvPort ix, ErtsSysFdType fd, ErlDrvEventData event_data)
{
- Port *pp = erts_drvport2port(ix);
+ Port *pp = erts_drvport2port(ix, NULL);
erts_dsprintf(dsbufp, "driver_event(%p, %d, ", ix, (int) fd);
if (!event_data)
erts_dsprintf(dsbufp, "NULL");
@@ -1062,8 +1051,8 @@ print_event_op(erts_dsprintf_buf_t *dsbufp,
(unsigned int) event_data->events,
(unsigned int) event_data->revents);
erts_dsprintf(dsbufp, ") by ");
- print_driver_name(dsbufp, pp->id);
- erts_dsprintf(dsbufp, "driver %T ", pp ? pp->id : NIL);
+ print_driver_name(dsbufp, pp->common.id);
+ erts_dsprintf(dsbufp, "driver %T ", pp ? pp->common.id : NIL);
}
static void
@@ -1100,8 +1089,7 @@ iready(Eterm id, ErtsDrvEventState *state)
if (erts_port_task_schedule(id,
&state->driver.select->intask,
ERTS_PORT_TASK_INPUT,
- (ErlDrvEvent) state->fd,
- NULL) != 0) {
+ (ErlDrvEvent) state->fd) != 0) {
stale_drv_select(id, state, ERL_DRV_READ);
}
}
@@ -1112,8 +1100,7 @@ oready(Eterm id, ErtsDrvEventState *state)
if (erts_port_task_schedule(id,
&state->driver.select->outtask,
ERTS_PORT_TASK_OUTPUT,
- (ErlDrvEvent) state->fd,
- NULL) != 0) {
+ (ErlDrvEvent) state->fd) != 0) {
stale_drv_select(id, state, ERL_DRV_WRITE);
}
}
diff --git a/erts/emulator/sys/common/erl_mseg.c b/erts/emulator/sys/common/erl_mseg.c
index db2854fa40..94f9f76a20 100644
--- a/erts/emulator/sys/common/erl_mseg.c
+++ b/erts/emulator/sys/common/erl_mseg.c
@@ -57,26 +57,48 @@
/* Implement some other way to get the real page size if needed! */
#endif
-#define MAX_CACHE_SIZE 30
-
#undef MIN
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
#undef MAX
#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
-#undef PAGE_MASK
-#define INV_PAGE_MASK ((Uint) (page_size - 1))
-#define PAGE_MASK (~INV_PAGE_MASK)
-#define PAGE_FLOOR(X) ((X) & PAGE_MASK)
-#define PAGE_CEILING(X) PAGE_FLOOR((X) + INV_PAGE_MASK)
-#define PAGES(X) ((X) >> page_shift)
+#define INV_ALIGNED_MASK ((UWord) ((MSEG_ALIGNED_SIZE) - 1))
+#define ALIGNED_MASK (~INV_ALIGNED_MASK)
+#define ALIGNED_FLOOR(X) (((UWord)(X)) & ALIGNED_MASK)
+#define ALIGNED_CEILING(X) ALIGNED_FLOOR((X) + INV_ALIGNED_MASK)
+#define MAP_IS_ALIGNED(X) (((UWord)(X) & (MSEG_ALIGNED_SIZE - 1)) == 0)
+
+#define IS_2POW(X) ((X) && !((X) & ((X) - 1)))
+static ERTS_INLINE Uint ceil_2pow(Uint x) {
+ int i = 1 << (4 + (sizeof(Uint) != 4 ? 1 : 0));
+ x--;
+ do { x |= x >> i; } while(i >>= 1);
+ return x + 1;
+}
+static const int debruijn[32] = {
+ 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
+ 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
+};
+
+#define LOG2(X) (debruijn[((Uint32)(((X) & -(X)) * 0x077CB531U)) >> 27])
+
+#define CACHE_AREAS (32 - MSEG_ALIGN_BITS)
+
+#define SIZE_TO_CACHE_AREA_IDX(S) (LOG2((S)) - MSEG_ALIGN_BITS)
+#define MAX_CACHE_SIZE (30)
+
+#define MSEG_FLG_IS_2POW(X) ((X) & ERTS_MSEG_FLG_2POW)
+
+#ifdef DEBUG
+#define DBG(F,...) fprintf(stderr, (F), __VA_ARGS__ )
+#else
+#define DBG(F,...) do{}while(0)
+#endif
static int atoms_initialized;
typedef struct mem_kind_t MemKind;
-static void mseg_clear_cache(MemKind*);
-
#if HALFWORD_HEAP
static int initialize_pmmap(void);
static void *pmmap(size_t size);
@@ -116,15 +138,6 @@ static int mmap_fd;
#error "Not supported"
#endif /* #if HAVE_MMAP */
-#if defined(ERTS_MSEG_FAKE_SEGMENTS) && HALFWORD_HEAP
-# warning "ERTS_MSEG_FAKE_SEGMENTS will only be used for high memory segments"
-#endif
-
-#if defined(ERTS_MSEG_FAKE_SEGMENTS)
-#undef CAN_PARTLY_DESTROY
-#define CAN_PARTLY_DESTROY 0
-#endif
-
const ErtsMsegOpt_t erts_mseg_default_opt = {
1, /* Use cache */
1, /* Preserv data */
@@ -137,26 +150,17 @@ const ErtsMsegOpt_t erts_mseg_default_opt = {
};
-typedef struct cache_desc_t_ {
- void *seg;
- Uint size;
- struct cache_desc_t_ *next;
- struct cache_desc_t_ *prev;
-} cache_desc_t;
-
typedef struct {
Uint32 giga_no;
Uint32 no;
} CallCounter;
-static Uint page_size;
-static Uint page_shift;
-
typedef struct {
CallCounter alloc;
CallCounter dealloc;
CallCounter realloc;
CallCounter create;
+ CallCounter create_resize;
CallCounter destroy;
#if HAVE_MSEG_RECREATE
CallCounter recreate;
@@ -165,17 +169,25 @@ typedef struct {
CallCounter check_cache;
} ErtsMsegCalls;
+typedef struct cache_t_ cache_t;
+
+struct cache_t_ {
+ Uint size;
+ void *seg;
+ cache_t *next;
+};
+
+
typedef struct ErtsMsegAllctr_t_ ErtsMsegAllctr_t;
struct mem_kind_t {
- cache_desc_t cache_descs[MAX_CACHE_SIZE];
- cache_desc_t *free_cache_descs;
- cache_desc_t *cache;
- cache_desc_t *cache_end;
-
- Uint cache_size;
- Uint min_cached_seg_size;
- Uint max_cached_seg_size;
+
+ cache_t cache[MAX_CACHE_SIZE];
+ cache_t *cache_unpowered;
+ cache_t *cache_area[CACHE_AREAS];
+ cache_t *cache_free;
+
+ Sint cache_size;
Uint cache_hits;
struct {
@@ -320,8 +332,7 @@ static erts_mtx_t init_atoms_mutex; /* Also needed when !USE_THREADS */
static ERTS_INLINE void
-schedule_cache_check(ErtsMsegAllctr_t *ma)
-{
+schedule_cache_check(ErtsMsegAllctr_t *ma) {
if (!ma->is_cache_check_scheduled && ma->is_init_done) {
erts_set_aux_work_timeout(ma->ix,
@@ -331,12 +342,45 @@ schedule_cache_check(ErtsMsegAllctr_t *ma)
}
}
+/* remove ErtsMsegAllctr_t from arguments?
+ * only used for statistics
+ */
+static ERTS_INLINE void *
+mmap_align(ErtsMsegAllctr_t *ma, void *addr, size_t length, int prot, int flags, int fd, off_t offset) {
+
+ void *p, *q;
+ UWord d;
+
+ p = mmap(addr, length, prot, flags, fd, offset);
+
+ if (MAP_IS_ALIGNED(p) || p == MAP_FAILED)
+ return p;
+
+ if (ma)
+ INC_CC(ma, create_resize);
+
+ munmap(p, length);
+
+ if ((p = mmap(addr, length + MSEG_ALIGNED_SIZE, prot, flags, fd, offset)) == MAP_FAILED)
+ return MAP_FAILED;
+
+ q = (void *)ALIGNED_CEILING(p);
+ d = q - p;
+
+ if (d > 0)
+ munmap(p, d);
+
+ if (MSEG_ALIGNED_SIZE - d > 0)
+ munmap((void *) (q + length), MSEG_ALIGNED_SIZE - d);
+
+ return q;
+}
+
static ERTS_INLINE void *
mseg_create(ErtsMsegAllctr_t *ma, MemKind* mk, Uint size)
{
void *seg;
-
- ASSERT(size % page_size == 0);
+ ASSERT(size % MSEG_ALIGNED_SIZE == 0);
#if HALFWORD_HEAP
if (mk == &ma->low_mem) {
@@ -345,18 +389,17 @@ mseg_create(ErtsMsegAllctr_t *ma, MemKind* mk, Uint size)
erts_fprintf(stderr,"Pointer mask failure (0x%08lx)\n",(unsigned long) seg);
return NULL;
}
- }
- else
+ } else
#endif
{
-#if defined(ERTS_MSEG_FAKE_SEGMENTS)
- seg = erts_sys_alloc(ERTS_ALC_N_INVALID, NULL, size);
-#elif HAVE_MMAP
+#if HAVE_MMAP
{
- seg = (void *) mmap((void *) 0, (size_t) size,
+ seg = (void *) mmap_align(ma, (void *) 0, (size_t) size,
MMAP_PROT, MMAP_FLAGS, MMAP_FD, 0);
if (seg == (void *) MAP_FAILED)
seg = NULL;
+
+ ASSERT(MAP_IS_ALIGNED(seg) || !seg);
}
#else
# error "Missing mseg_create() implementation"
@@ -369,38 +412,24 @@ mseg_create(ErtsMsegAllctr_t *ma, MemKind* mk, Uint size)
}
static ERTS_INLINE void
-mseg_destroy(ErtsMsegAllctr_t *ma, MemKind* mk, void *seg, Uint size)
-{
-#ifdef DEBUG
- int res;
-#endif
+mseg_destroy(ErtsMsegAllctr_t *ma, MemKind* mk, void *seg, Uint size) {
+ ERTS_DECLARE_DUMMY(int res);
#if HALFWORD_HEAP
if (mk == &ma->low_mem) {
-#ifdef DEBUG
- res =
-#endif
- pmunmap((void *) seg, size);
+ res = pmunmap((void *) seg, size);
}
else
#endif
{
-#ifdef ERTS_MSEG_FAKE_SEGMENTS
- erts_sys_free(ERTS_ALC_N_INVALID, NULL, seg);
-#ifdef DEBUG
- res = 0;
-#endif
-#elif HAVE_MMAP
-#ifdef DEBUG
- res =
-#endif
- munmap((void *) seg, size);
+#ifdef HAVE_MMAP
+ res = munmap((void *) seg, size);
#else
# error "Missing mseg_destroy() implementation"
#endif
}
- ASSERT(size % page_size == 0);
+ ASSERT(size % MSEG_ALIGNED_SIZE == 0);
ASSERT(res == 0);
INC_CC(ma, destroy);
@@ -408,14 +437,36 @@ mseg_destroy(ErtsMsegAllctr_t *ma, MemKind* mk, void *seg, Uint size)
}
#if HAVE_MSEG_RECREATE
+#if defined(__NetBsd__)
+#define MREMAP_FLAGS (0)
+#else
+#define MREMAP_FLAGS (MREMAP_MAYMOVE)
+#endif
+
+
+/* mseg_recreate
+ * May return *unaligned* segments as in address not aligned to MSEG_ALIGNMENT
+ * it is still page aligned
+ *
+ * This is fine for single block carriers as long as we don't cache misaligned
+ * segments (since multiblock carriers may use them)
+ *
+ * For multiblock carriers we *need* MSEG_ALIGNMENT but mbc's will never be
+ * reallocated.
+ *
+ * This should probably be fixed the following way:
+ * 1) Use an option to segment allocation - NEED_ALIGNMENT
+ * 2) Add mremap_align which takes care of aligning a new a mremaped area
+ * 3) Fix the cache to handle of aligned and unaligned segments
+ */
static ERTS_INLINE void *
mseg_recreate(ErtsMsegAllctr_t *ma, MemKind* mk, void *old_seg, Uint old_size, Uint new_size)
{
void *new_seg;
- ASSERT(old_size % page_size == 0);
- ASSERT(new_size % page_size == 0);
+ ASSERT(old_size % MSEG_ALIGNED_SIZE == 0);
+ ASSERT(new_size % MSEG_ALIGNED_SIZE == 0);
#if HALFWORD_HEAP
if (mk == &ma->low_mem) {
@@ -426,22 +477,12 @@ mseg_recreate(ErtsMsegAllctr_t *ma, MemKind* mk, void *old_seg, Uint old_size, U
else
#endif
{
-#if defined(ERTS_MSEG_FAKE_SEGMENTS)
- new_seg = erts_sys_realloc(ERTS_ALC_N_INVALID, NULL, old_seg, new_size);
-#elif HAVE_MREMAP
-
- #if defined(__NetBSD__)
- new_seg = (void *) mremap((void *) old_seg,
- (size_t) old_size,
- NULL,
- (size_t) new_size,
- 0);
- #else
- new_seg = (void *) mremap((void *) old_seg,
- (size_t) old_size,
- (size_t) new_size,
- MREMAP_MAYMOVE);
- #endif
+#if HAVE_MREMAP
+#if defined(__NetBSD__)
+ new_seg = mremap(old_seg, (size_t)old_size, NULL, new_size, MREMAP_FLAGS);
+#else
+ new_seg = mremap(old_seg, (size_t)old_size, (size_t)new_size, MREMAP_FLAGS);
+#endif
if (new_seg == (void *) MAP_FAILED)
new_seg = NULL;
#else
@@ -475,151 +516,265 @@ do { \
#define ERTS_DBG_MK_CHK_THR_ACCESS(MK)
#endif
-static ERTS_INLINE cache_desc_t *
-alloc_cd(MemKind* mk)
-{
- cache_desc_t *cd = mk->free_cache_descs;
+/* NEW CACHE interface */
+
+static ERTS_INLINE cache_t *mseg_cache_alloc_descriptor(MemKind *mk) {
+ cache_t *c = mk->cache_free;
+
ERTS_DBG_MK_CHK_THR_ACCESS(mk);
- if (cd)
- mk->free_cache_descs = cd->next;
- return cd;
+ if (c)
+ mk->cache_free = c->next;
+
+ return c;
}
-static ERTS_INLINE void
-free_cd(MemKind* mk, cache_desc_t *cd)
-{
+static ERTS_INLINE void mseg_cache_free_descriptor(MemKind *mk, cache_t *c) {
ERTS_DBG_MK_CHK_THR_ACCESS(mk);
- cd->next = mk->free_cache_descs;
- mk->free_cache_descs = cd;
+ ASSERT(c);
+
+ c->seg = NULL;
+ c->size = 0;
+ c->next = mk->cache_free;
+ mk->cache_free = c;
}
+static ERTS_INLINE int cache_bless_segment(MemKind *mk, void *seg, Uint size) {
-static ERTS_INLINE void
-link_cd(MemKind* mk, cache_desc_t *cd)
-{
+ cache_t *c;
ERTS_DBG_MK_CHK_THR_ACCESS(mk);
- if (mk->cache)
- mk->cache->prev = cd;
- cd->next = mk->cache;
- cd->prev = NULL;
- mk->cache = cd;
-
- if (!mk->cache_end) {
- ASSERT(!cd->next);
- mk->cache_end = cd;
+
+ if (mk->cache_free && MAP_IS_ALIGNED(seg)) {
+ if (IS_2POW(size)) {
+ int ix = SIZE_TO_CACHE_AREA_IDX(size);
+
+ ASSERT(ix < CACHE_AREAS);
+ ASSERT((1 << (ix + MSEG_ALIGN_BITS)) == size);
+
+ /* unlink from free cache list */
+ c = mseg_cache_alloc_descriptor(mk);
+
+ /* link to cache area */
+ c->seg = seg;
+ c->size = size;
+ c->next = mk->cache_area[ix];
+
+ mk->cache_area[ix] = c;
+ mk->cache_size++;
+
+ ASSERT(mk->cache_size <= mk->ma->max_cache_size);
+
+ return 1;
+ } else {
+ /* unlink from free cache list */
+ c = mseg_cache_alloc_descriptor(mk);
+
+ /* link to cache area */
+ c->seg = seg;
+ c->size = size;
+ c->next = mk->cache_unpowered;
+
+ mk->cache_unpowered = c;
+ mk->cache_size++;
+
+ ASSERT(mk->cache_size <= mk->ma->max_cache_size);
+
+ return 1;
+ }
}
- mk->cache_size++;
+ return 0;
}
-#if CAN_PARTLY_DESTROY
-static ERTS_INLINE void
-end_link_cd(MemKind* mk, cache_desc_t *cd)
-{
+static ERTS_INLINE void *cache_get_segment(MemKind *mk, Uint *size_p) {
+
+ Uint size = *size_p;
+
ERTS_DBG_MK_CHK_THR_ACCESS(mk);
- if (mk->cache_end)
- mk->cache_end->next = cd;
- cd->next = NULL;
- cd->prev = mk->cache_end;
- mk->cache_end = cd;
-
- if (!mk->cache) {
- ASSERT(!cd->prev);
- mk->cache = cd;
- }
+ if (IS_2POW(size)) {
+
+ int i, ix = SIZE_TO_CACHE_AREA_IDX(size);
+ void *seg;
+ cache_t *c;
+ Uint csize;
+
+ for( i = ix; i < CACHE_AREAS; i++) {
+
+ if ((c = mk->cache_area[i]) == NULL)
+ continue;
+
+ ASSERT(IS_2POW(c->size));
+
+ /* unlink from cache area */
+ csize = c->size;
+ seg = c->seg;
+ mk->cache_area[i] = c->next;
+ c->next = NULL;
+ mk->cache_size--;
+ mk->cache_hits++;
+
+ /* link to free cache list */
+ mseg_cache_free_descriptor(mk, c);
+
+ ASSERT(!(mk->cache_size < 0));
+
+ /* divvy up the cache - if needed */
+ while( i > ix) {
+ csize = csize >> 1;
+ /* try to cache half of it */
+ if (!cache_bless_segment(mk, (char *)seg + csize, csize)) {
+ /* wouldn't cache .. destroy it instead */
+ mseg_destroy(mk->ma, mk, (char *)seg + csize, csize);
+ }
+ i--;
+ }
+ ASSERT(csize == size);
+ return seg;
+ }
+ }
+ else if (mk->cache_unpowered) {
+ void *seg;
+ cache_t *c, *pc;
+ Uint csize;
+ Uint bad_max_abs = mk->ma->abs_max_cache_bad_fit;
+ Uint bad_max_rel = mk->ma->rel_max_cache_bad_fit;
+
+ c = mk->cache_unpowered;
+ pc = c;
+
+ while (c) {
+ csize = c->size;
+ if (csize >= size &&
+ ((csize - size)*100 < bad_max_rel*size) &&
+ (csize - size) < bad_max_abs ) {
+
+ /* unlink from cache area */
+ seg = c->seg;
+
+ if (pc == c) {
+ mk->cache_unpowered = c->next;
+ } else {
+ pc->next = c->next;
+ }
+
+ c->next = NULL;
+ mk->cache_size--;
+ mk->cache_hits++;
+
+ /* link to free cache list */
+ mseg_cache_free_descriptor(mk, c);
+ *size_p = csize;
+
+ return seg;
+ }
- mk->cache_size++;
+ pc = c;
+ c = c->next;
+ }
+ }
+ return NULL;
}
-#endif
-static ERTS_INLINE void
-unlink_cd(MemKind* mk, cache_desc_t *cd)
-{
- ERTS_DBG_MK_CHK_THR_ACCESS(mk);
- if (cd->next)
- cd->next->prev = cd->prev;
- else
- mk->cache_end = cd->prev;
-
- if (cd->prev)
- cd->prev->next = cd->next;
- else
- mk->cache = cd->next;
- ASSERT(mk->cache_size > 0);
+/* *_mseg_check_*_cache
+ * Slowly remove segments cached in the allocator by
+ * using callbacks from aux-work in the scheduler.
+ */
+
+static ERTS_INLINE Uint mseg_drop_one_memkind_cache_size(MemKind *mk, cache_t **head) {
+ cache_t *c = NULL;
+
+ c = *head;
+
+ ASSERT( c != NULL );
+
+ *head = c->next;
+
+ if (erts_mtrace_enabled)
+ erts_mtrace_crr_free(SEGTYPE, SEGTYPE, c->seg);
+
+ mseg_destroy(mk->ma, mk, c->seg, c->size);
+ mseg_cache_free_descriptor(mk, c);
+
+ mk->segments.current.watermark--;
mk->cache_size--;
-}
-static ERTS_INLINE void
-check_cache_limits(MemKind* mk)
-{
- cache_desc_t *cd;
- ERTS_DBG_MK_CHK_THR_ACCESS(mk);
- mk->max_cached_seg_size = 0;
- mk->min_cached_seg_size = ~((Uint) 0);
- for (cd = mk->cache; cd; cd = cd->next) {
- if (cd->size < mk->min_cached_seg_size)
- mk->min_cached_seg_size = cd->size;
- if (cd->size > mk->max_cached_seg_size)
- mk->max_cached_seg_size = cd->size;
- }
+ ASSERT( mk->cache_size >= 0 );
+
+ return mk->cache_size;
}
-static ERTS_INLINE void
-adjust_cache_size(MemKind* mk, int force_check_limits)
-{
- cache_desc_t *cd;
- int check_limits = force_check_limits;
- Sint max_cached = ((Sint) mk->segments.current.watermark
- - (Sint) mk->segments.current.no);
- ERTS_DBG_MK_CHK_THR_ACCESS(mk);
- while (((Sint) mk->cache_size) > max_cached && ((Sint) mk->cache_size) > 0) {
- ASSERT(mk->cache_end);
- cd = mk->cache_end;
- if (!check_limits &&
- !(mk->min_cached_seg_size < cd->size
- && cd->size < mk->max_cached_seg_size)) {
- check_limits = 1;
- }
+static ERTS_INLINE Uint mseg_drop_memkind_cache_size(MemKind *mk, cache_t **head) {
+ cache_t *c = NULL, *next = NULL;
+
+ c = *head;
+ ASSERT( c != NULL );
+
+ while (c) {
+
+ next = c->next;
+
if (erts_mtrace_enabled)
- erts_mtrace_crr_free(SEGTYPE, SEGTYPE, cd->seg);
- mseg_destroy(mk->ma, mk, cd->seg, cd->size);
- unlink_cd(mk,cd);
- free_cd(mk,cd);
- }
+ erts_mtrace_crr_free(SEGTYPE, SEGTYPE, c->seg);
- if (check_limits)
- check_cache_limits(mk);
-}
+ mseg_destroy(mk->ma, mk, c->seg, c->size);
+ mseg_cache_free_descriptor(mk, c);
-static Uint
-check_one_cache(MemKind* mk)
-{
- if (mk->segments.current.watermark > mk->segments.current.no)
mk->segments.current.watermark--;
- adjust_cache_size(mk, 0);
+ mk->cache_size--;
+
+ c = next;
+ }
+
+ *head = NULL;
+
+ ASSERT( mk->cache_size >= 0 );
- if (mk->cache_size)
- schedule_cache_check(mk->ma);
return mk->cache_size;
}
-static void do_cache_check(ErtsMsegAllctr_t *ma)
-{
- int empty_cache = 1;
+/* mseg_check_memkind_cache
+ * - Check if we can empty some cached segments in this
+ * MemKind.
+ */
+
+
+static Uint mseg_check_memkind_cache(MemKind *mk) {
+ int i;
+
+ ERTS_DBG_MK_CHK_THR_ACCESS(mk);
+
+ for (i = 0; i < CACHE_AREAS; i++) {
+ if (mk->cache_area[i] != NULL)
+ return mseg_drop_one_memkind_cache_size(mk, &(mk->cache_area[i]));
+ }
+
+ if (mk->cache_unpowered)
+ return mseg_drop_one_memkind_cache_size(mk, &(mk->cache_unpowered));
+
+ return 0;
+}
+
+/* mseg_cache_check
+ * - Check if we have some cache we can purge
+ * in any of the memkinds.
+ */
+
+static void mseg_cache_check(ErtsMsegAllctr_t *ma) {
MemKind* mk;
+ Uint empty_cache = 1;
ERTS_MSEG_LOCK(ma);
- for (mk=ma->mk_list; mk; mk=mk->next) {
- if (check_one_cache(mk))
+ for (mk = ma->mk_list; mk; mk = mk->next) {
+ if (mseg_check_memkind_cache(mk))
empty_cache = 0;
}
+ /* If all MemKinds caches are empty,
+ * remove aux-work callback
+ */
if (empty_cache) {
ma->is_cache_check_scheduled = 0;
- erts_set_aux_work_timeout(ma->ix,
- ERTS_SSI_AUX_WORK_MSEG_CACHE_CHECK,
- 0);
+ erts_set_aux_work_timeout(ma->ix, ERTS_SSI_AUX_WORK_MSEG_CACHE_CHECK, 0);
}
INC_CC(ma, check_cache);
@@ -627,27 +782,65 @@ static void do_cache_check(ErtsMsegAllctr_t *ma)
ERTS_MSEG_UNLOCK(ma);
}
-void erts_mseg_cache_check(void)
-{
- do_cache_check(ERTS_MSEG_ALLCTR_SS());
+/* erts_mseg_cache_check
+ * - This is a callback that is scheduled as aux-work from
+ * schedulers and is called at some interval if we have a cache
+ * on this mseg-allocator and memkind.
+ * - Purpose: Empty cache slowly so we don't collect mapped areas
+ * and bloat memory.
+ */
+
+void erts_mseg_cache_check(void) {
+ mseg_cache_check(ERTS_MSEG_ALLCTR_SS());
}
-static void
-mseg_clear_cache(MemKind* mk)
-{
- mk->segments.current.watermark = 0;
- adjust_cache_size(mk, 1);
+/* *_mseg_clear_*_cache
+ * Remove cached segments from the allocator completely
+ */
+
+static void mseg_clear_memkind_cache(MemKind *mk) {
+ int i;
+
+ /* drop pow2 caches */
+ for (i = 0; i < CACHE_AREAS; i++) {
+ if (mk->cache_area[i] == NULL)
+ continue;
+
+ mseg_drop_memkind_cache_size(mk, &(mk->cache_area[i]));
+ ASSERT(mk->cache_area[i] == NULL);
+ }
+ /* drop varied caches */
+ if(mk->cache_unpowered)
+ mseg_drop_memkind_cache_size(mk, &(mk->cache_unpowered));
+
+ ASSERT(mk->cache_unpowered == NULL);
+ ASSERT(mk->cache_size == 0);
+}
+
+static void mseg_clear_cache(ErtsMsegAllctr_t *ma) {
+ MemKind* mk;
+
+ ERTS_MSEG_LOCK(ma);
+ ERTS_DBG_MA_CHK_THR_ACCESS(ma);
+
- ASSERT(!mk->cache);
- ASSERT(!mk->cache_end);
- ASSERT(!mk->cache_size);
+ for (mk = ma->mk_list; mk; mk = mk->next) {
+ mseg_clear_memkind_cache(mk);
+ }
- mk->segments.current.watermark = mk->segments.current.no;
+ INC_CC(ma, clear_cache);
- INC_CC(mk->ma, clear_cache);
+ ERTS_MSEG_UNLOCK(ma);
}
+void erts_mseg_clear_cache(void) {
+ mseg_clear_cache(ERTS_MSEG_ALLCTR_SS());
+ mseg_clear_cache(ERTS_MSEG_ALLCTR_IX(0));
+}
+
+
+
static ERTS_INLINE MemKind* memkind(ErtsMsegAllctr_t *ma,
const ErtsMsegOpt_t *opt)
{
@@ -660,116 +853,40 @@ static ERTS_INLINE MemKind* memkind(ErtsMsegAllctr_t *ma,
static void *
mseg_alloc(ErtsMsegAllctr_t *ma, ErtsAlcType_t atype, Uint *size_p,
- const ErtsMsegOpt_t *opt)
+ Uint flags, const ErtsMsegOpt_t *opt)
{
- Uint max, min, diff_size, size;
- cache_desc_t *cd, *cand_cd;
+ Uint size;
void *seg;
MemKind* mk = memkind(ma, opt);
INC_CC(ma, alloc);
- size = PAGE_CEILING(*size_p);
+ /* Carrier align */
+ size = ALIGNED_CEILING(*size_p);
+
+ /* Cache optim (if applicable) */
+ if (MSEG_FLG_IS_2POW(flags) && !IS_2POW(size))
+ size = ceil_2pow(size);
#if CAN_PARTLY_DESTROY
if (size < ma->min_seg_size)
ma->min_seg_size = size;
#endif
+
+ if (opt->cache && mk->cache_size > 0 && (seg = cache_get_segment(mk, &size)) != NULL)
+ goto done;
- if (!opt->cache) {
- create_seg:
- adjust_cache_size(mk,0);
- seg = mseg_create(ma, mk, size);
- if (!seg) {
- mseg_clear_cache(mk);
- seg = mseg_create(ma, mk, size);
- if (!seg)
- size = 0;
- }
-
- *size_p = size;
- if (seg) {
- if (erts_mtrace_enabled)
- erts_mtrace_crr_alloc(seg, atype, ERTS_MTRACE_SEGMENT_ID, size);
- ERTS_MSEG_ALLOC_STAT(mk,size);
- }
- return seg;
- }
-
- if (size > mk->max_cached_seg_size)
- goto create_seg;
-
- if (size < mk->min_cached_seg_size) {
-
- diff_size = mk->min_cached_seg_size - size;
-
- if (diff_size > ma->abs_max_cache_bad_fit)
- goto create_seg;
-
- if (100*PAGES(diff_size) > ma->rel_max_cache_bad_fit*PAGES(size))
- goto create_seg;
-
- }
-
- max = 0;
- min = ~((Uint) 0);
- cand_cd = NULL;
-
- for (cd = mk->cache; cd; cd = cd->next) {
- if (cd->size >= size) {
- if (!cand_cd) {
- cand_cd = cd;
- continue;
- }
- else if (cd->size < cand_cd->size) {
- if (max < cand_cd->size)
- max = cand_cd->size;
- if (min > cand_cd->size)
- min = cand_cd->size;
- cand_cd = cd;
- continue;
- }
- }
- if (max < cd->size)
- max = cd->size;
- if (min > cd->size)
- min = cd->size;
- }
-
- mk->min_cached_seg_size = min;
- mk->max_cached_seg_size = max;
-
- if (!cand_cd)
- goto create_seg;
-
- diff_size = cand_cd->size - size;
-
- if (diff_size > ma->abs_max_cache_bad_fit
- || 100*PAGES(diff_size) > ma->rel_max_cache_bad_fit*PAGES(size)) {
- if (mk->max_cached_seg_size < cand_cd->size)
- mk->max_cached_seg_size = cand_cd->size;
- if (mk->min_cached_seg_size > cand_cd->size)
- mk->min_cached_seg_size = cand_cd->size;
- goto create_seg;
- }
-
- mk->cache_hits++;
-
- size = cand_cd->size;
- seg = cand_cd->seg;
-
- unlink_cd(mk,cand_cd);
- free_cd(mk,cand_cd);
+ if ((seg = mseg_create(ma, mk, size)) == NULL)
+ size = 0;
+done:
*size_p = size;
+ if (seg) {
+ if (erts_mtrace_enabled)
+ erts_mtrace_crr_alloc(seg, atype, ERTS_MTRACE_SEGMENT_ID, size);
- if (erts_mtrace_enabled) {
- erts_mtrace_crr_free(SEGTYPE, SEGTYPE, seg);
- erts_mtrace_crr_alloc(seg, atype, SEGTYPE, size);
- }
-
- if (seg)
ERTS_MSEG_ALLOC_STAT(mk,size);
+ }
return seg;
}
@@ -780,73 +897,42 @@ mseg_dealloc(ErtsMsegAllctr_t *ma, ErtsAlcType_t atype, void *seg, Uint size,
const ErtsMsegOpt_t *opt)
{
MemKind* mk = memkind(ma, opt);
- cache_desc_t *cd;
+
ERTS_MSEG_DEALLOC_STAT(mk,size);
- if (!opt->cache || ma->max_cache_size == 0) {
- if (erts_mtrace_enabled)
- erts_mtrace_crr_free(atype, SEGTYPE, seg);
- mseg_destroy(ma, mk, seg, size);
+ if (opt->cache && cache_bless_segment(mk, seg, size)) {
+ schedule_cache_check(ma);
+ goto done;
}
- else {
- int check_limits = 0;
-
- if (size < mk->min_cached_seg_size)
- mk->min_cached_seg_size = size;
- if (size > mk->max_cached_seg_size)
- mk->max_cached_seg_size = size;
-
- if (!mk->free_cache_descs) {
- cd = mk->cache_end;
- if (!(mk->min_cached_seg_size < cd->size
- && cd->size < mk->max_cached_seg_size)) {
- check_limits = 1;
- }
- if (erts_mtrace_enabled)
- erts_mtrace_crr_free(SEGTYPE, SEGTYPE, cd->seg);
- mseg_destroy(ma, mk, cd->seg, cd->size);
- unlink_cd(mk,cd);
- free_cd(mk,cd);
- }
- cd = alloc_cd(mk);
- ASSERT(cd);
- cd->seg = seg;
- cd->size = size;
- link_cd(mk,cd);
+ if (erts_mtrace_enabled)
+ erts_mtrace_crr_free(atype, SEGTYPE, seg);
- if (erts_mtrace_enabled) {
- erts_mtrace_crr_free(atype, SEGTYPE, seg);
- erts_mtrace_crr_alloc(seg, SEGTYPE, SEGTYPE, size);
- }
-
- /* ASSERT(segments.current.watermark >= segments.current.no + cache_size); */
-
- if (check_limits)
- check_cache_limits(mk);
+ mseg_destroy(ma, mk, seg, size);
- schedule_cache_check(ma);
-
- }
+done:
INC_CC(ma, dealloc);
}
static void *
mseg_realloc(ErtsMsegAllctr_t *ma, ErtsAlcType_t atype, void *seg,
- Uint old_size, Uint *new_size_p, const ErtsMsegOpt_t *opt)
+ Uint old_size, Uint *new_size_p, Uint flags, const ErtsMsegOpt_t *opt)
{
MemKind* mk;
void *new_seg;
Uint new_size;
+ /* Just allocate a new segment if we didn't have one before */
if (!seg || !old_size) {
- new_seg = mseg_alloc(ma, atype, new_size_p, opt);
+ new_seg = mseg_alloc(ma, atype, new_size_p, flags, opt);
DEC_CC(ma, alloc);
return new_seg;
}
+
+ /* Dealloc old segment if new segment is of size 0 */
if (!(*new_size_p)) {
mseg_dealloc(ma, atype, seg, old_size, opt);
DEC_CC(ma, dealloc);
@@ -855,7 +941,13 @@ mseg_realloc(ErtsMsegAllctr_t *ma, ErtsAlcType_t atype, void *seg,
mk = memkind(ma, opt);
new_seg = seg;
- new_size = PAGE_CEILING(*new_size_p);
+
+ /* Carrier align */
+ new_size = ALIGNED_CEILING(*new_size_p);
+
+ /* Cache optim (if applicable) */
+ if (MSEG_FLG_IS_2POW(flags) && !IS_2POW(new_size))
+ new_size = ceil_2pow(new_size);
if (new_size == old_size)
;
@@ -866,53 +958,27 @@ mseg_realloc(ErtsMsegAllctr_t *ma, ErtsAlcType_t atype, void *seg,
if (new_size < ma->min_seg_size)
ma->min_seg_size = new_size;
#endif
-
+ /* +M<S>rsbcst <ratio> */
if (shrink_sz < opt->abs_shrink_th
- && 100*PAGES(shrink_sz) < opt->rel_shrink_th*PAGES(old_size)) {
+ && 100*shrink_sz < opt->rel_shrink_th*old_size) {
new_size = old_size;
}
else {
#if CAN_PARTLY_DESTROY
- if (shrink_sz > ma->min_seg_size
- && mk->free_cache_descs
- && opt->cache) {
- cache_desc_t *cd;
-
- cd = alloc_cd(mk);
- ASSERT(cd);
- cd->seg = ((char *) seg) + new_size;
- cd->size = shrink_sz;
- end_link_cd(mk,cd);
-
- if (erts_mtrace_enabled) {
- erts_mtrace_crr_realloc(new_seg,
- atype,
- SEGTYPE,
- seg,
- new_size);
- erts_mtrace_crr_alloc(cd->seg, SEGTYPE, SEGTYPE, cd->size);
- }
- schedule_cache_check(ma);
- }
- else {
- if (erts_mtrace_enabled)
- erts_mtrace_crr_realloc(new_seg,
- atype,
- SEGTYPE,
- seg,
- new_size);
- mseg_destroy(ma, mk, ((char *) seg) + new_size, shrink_sz);
- }
+ if (erts_mtrace_enabled)
+ erts_mtrace_crr_realloc(new_seg, atype, SEGTYPE, seg, new_size);
-#elif HAVE_MSEG_RECREATE
+ mseg_destroy(ma, mk, ((char *) seg) + new_size, shrink_sz);
+#elif HAVE_MSEG_RECREATE
goto do_recreate;
-
#else
+ new_seg = mseg_alloc(ma, atype, &new_size, flags, opt);
+
+ ASSERT(MAP_IS_ALIGNED(new_seg) || !new_seg);
- new_seg = mseg_alloc(ma, atype, &new_size, opt);
if (!new_seg)
new_size = old_size;
else {
@@ -921,16 +987,15 @@ mseg_realloc(ErtsMsegAllctr_t *ma, ErtsAlcType_t atype, void *seg,
MIN(new_size, old_size));
mseg_dealloc(ma, atype, seg, old_size, opt);
}
-
#endif
-
}
}
else {
if (!opt->preserv) {
mseg_dealloc(ma, atype, seg, old_size, opt);
- new_seg = mseg_alloc(ma, atype, &new_size, opt);
+ new_seg = mseg_alloc(ma, atype, &new_size, flags, opt);
+ ASSERT(MAP_IS_ALIGNED(new_seg) || !new_seg);
}
else {
#if HAVE_MSEG_RECREATE
@@ -938,18 +1003,23 @@ mseg_realloc(ErtsMsegAllctr_t *ma, ErtsAlcType_t atype, void *seg,
do_recreate:
#endif
new_seg = mseg_recreate(ma, mk, (void *) seg, old_size, new_size);
+ /* ASSERT(MAP_IS_ALIGNED(new_seg) || !new_seg);
+ * will not always be aligned and it ok for now
+ */
+
if (erts_mtrace_enabled)
erts_mtrace_crr_realloc(new_seg, atype, SEGTYPE, seg, new_size);
if (!new_seg)
new_size = old_size;
#else
- new_seg = mseg_alloc(ma, atype, &new_size, opt);
+ new_seg = mseg_alloc(ma, atype, &new_size, flags, opt);
+
+ ASSERT(MAP_IS_ALIGNED(new_seg) || !new_seg);
+
if (!new_seg)
new_size = old_size;
else {
- sys_memcpy(((char *) new_seg),
- ((char *) seg),
- MIN(new_size, old_size));
+ sys_memcpy(((char *) new_seg), ((char *) seg), MIN(new_size, old_size));
mseg_dealloc(ma, atype, seg, old_size, opt);
}
#endif
@@ -958,6 +1028,7 @@ mseg_realloc(ErtsMsegAllctr_t *ma, ErtsAlcType_t atype, void *seg,
INC_CC(ma, realloc);
+ ASSERT(!MSEG_FLG_IS_2POW(flags) || IS_2POW(new_size));
*new_size_p = new_size;
ERTS_MSEG_REALLOC_STAT(mk, old_size, new_size);
@@ -990,6 +1061,7 @@ static struct {
Eterm mseg_dealloc;
Eterm mseg_realloc;
Eterm mseg_create;
+ Eterm mseg_create_resize;
Eterm mseg_destroy;
#if HAVE_MSEG_RECREATE
Eterm mseg_recreate;
@@ -1046,6 +1118,7 @@ init_atoms(ErtsMsegAllctr_t *ma)
AM_INIT(mseg_dealloc);
AM_INIT(mseg_realloc);
AM_INIT(mseg_create);
+ AM_INIT(mseg_create_resize);
AM_INIT(mseg_destroy);
#if HAVE_MSEG_RECREATE
AM_INIT(mseg_recreate);
@@ -1065,14 +1138,12 @@ init_atoms(ErtsMsegAllctr_t *ma)
erts_mtx_unlock(&init_atoms_mutex);
}
-
#define bld_uint erts_bld_uint
#define bld_cons erts_bld_cons
#define bld_tuple erts_bld_tuple
#define bld_string erts_bld_string
#define bld_2tup_list erts_bld_2tup_list
-
/*
* bld_unstable_uint() (instead of bld_uint()) is used when values may
* change between size check and actual build. This because a value
@@ -1116,6 +1187,7 @@ add_4tup(Uint **hpp, Uint *szp, Eterm *lp,
*lp = bld_cons(hpp, szp, bld_tuple(hpp, szp, 4, el1, el2, el3, el4), *lp);
}
+
static Eterm
info_options(ErtsMsegAllctr_t *ma,
char *prefix,
@@ -1176,6 +1248,7 @@ info_calls(ErtsMsegAllctr_t *ma, int *print_to_p, void *print_to_arg, Uint **hpp
PRINT_CC(to, arg, dealloc);
PRINT_CC(to, arg, realloc);
PRINT_CC(to, arg, create);
+ PRINT_CC(to, arg, create_resize);
PRINT_CC(to, arg, destroy);
#if HAVE_MSEG_RECREATE
PRINT_CC(to, arg, recreate);
@@ -1215,6 +1288,10 @@ info_calls(ErtsMsegAllctr_t *ma, int *print_to_p, void *print_to_arg, Uint **hpp
bld_unstable_uint(hpp, szp, ma->calls.create.giga_no),
bld_unstable_uint(hpp, szp, ma->calls.create.no));
+ add_3tup(hpp, szp, &res,
+ am.mseg_create_resize,
+ bld_unstable_uint(hpp, szp, ma->calls.create_resize.giga_no),
+ bld_unstable_uint(hpp, szp, ma->calls.create_resize.no));
add_3tup(hpp, szp, &res,
am.mseg_realloc,
@@ -1401,21 +1478,21 @@ erts_mseg_info(int ix,
}
void *
-erts_mseg_alloc_opt(ErtsAlcType_t atype, Uint *size_p, const ErtsMsegOpt_t *opt)
+erts_mseg_alloc_opt(ErtsAlcType_t atype, Uint *size_p, Uint flags, const ErtsMsegOpt_t *opt)
{
ErtsMsegAllctr_t *ma = ERTS_MSEG_ALLCTR_OPT(opt);
void *seg;
ERTS_MSEG_LOCK(ma);
ERTS_DBG_MA_CHK_THR_ACCESS(ma);
- seg = mseg_alloc(ma, atype, size_p, opt);
+ seg = mseg_alloc(ma, atype, size_p, flags, opt);
ERTS_MSEG_UNLOCK(ma);
return seg;
}
void *
-erts_mseg_alloc(ErtsAlcType_t atype, Uint *size_p)
+erts_mseg_alloc(ErtsAlcType_t atype, Uint *size_p, Uint flags)
{
- return erts_mseg_alloc_opt(atype, size_p, &erts_mseg_default_opt);
+ return erts_mseg_alloc_opt(atype, size_p, flags, &erts_mseg_default_opt);
}
void
@@ -1438,44 +1515,24 @@ erts_mseg_dealloc(ErtsAlcType_t atype, void *seg, Uint size)
void *
erts_mseg_realloc_opt(ErtsAlcType_t atype, void *seg,
Uint old_size, Uint *new_size_p,
+ Uint flags,
const ErtsMsegOpt_t *opt)
{
ErtsMsegAllctr_t *ma = ERTS_MSEG_ALLCTR_OPT(opt);
void *new_seg;
ERTS_MSEG_LOCK(ma);
ERTS_DBG_MA_CHK_THR_ACCESS(ma);
- new_seg = mseg_realloc(ma, atype, seg, old_size, new_size_p, opt);
+ new_seg = mseg_realloc(ma, atype, seg, old_size, new_size_p, flags, opt);
ERTS_MSEG_UNLOCK(ma);
return new_seg;
}
void *
erts_mseg_realloc(ErtsAlcType_t atype, void *seg,
- Uint old_size, Uint *new_size_p)
+ Uint old_size, Uint *new_size_p, Uint flags)
{
return erts_mseg_realloc_opt(atype, seg, old_size, new_size_p,
- &erts_mseg_default_opt);
-}
-
-void
-erts_mseg_clear_cache(void)
-{
- ErtsMsegAllctr_t *ma = ERTS_MSEG_ALLCTR_SS();
- MemKind* mk;
-
-start:
-
- ERTS_MSEG_LOCK(ma);
- ERTS_DBG_MA_CHK_THR_ACCESS(ma);
- for (mk=ma->mk_list; mk; mk=mk->next) {
- mseg_clear_cache(mk);
- }
- ERTS_MSEG_UNLOCK(ma);
-
- if (ma->ix != 0) {
- ma = ERTS_MSEG_ALLCTR_IX(0);
- goto start;
- }
+ flags, &erts_mseg_default_opt);
}
Uint
@@ -1496,28 +1553,32 @@ erts_mseg_no(const ErtsMsegOpt_t *opt)
Uint
erts_mseg_unit_size(void)
{
- return page_size;
+ return MSEG_ALIGNED_SIZE;
}
static void mem_kind_init(ErtsMsegAllctr_t *ma, MemKind* mk, const char* name)
{
- unsigned i;
+ int i;
- mk->cache = NULL;
- mk->cache_end = NULL;
- mk->max_cached_seg_size = 0;
- mk->min_cached_seg_size = ~((Uint) 0);
- mk->cache_size = 0;
- mk->cache_hits = 0;
+ for (i = 0; i < CACHE_AREAS; i++) {
+ mk->cache_area[i] = NULL;
+ }
+
+ mk->cache_free = NULL;
- if (ma->max_cache_size > 0) {
- for (i = 0; i < ma->max_cache_size - 1; i++)
- mk->cache_descs[i].next = &mk->cache_descs[i + 1];
- mk->cache_descs[ma->max_cache_size - 1].next = NULL;
- mk->free_cache_descs = &mk->cache_descs[0];
+ ASSERT(ma->max_cache_size <= MAX_CACHE_SIZE);
+
+ for (i = 0; i < ma->max_cache_size; i++) {
+ mk->cache[i].seg = NULL;
+ mk->cache[i].size = 0;
+ mk->cache[i].next = mk->cache_free;
+ mk->cache_free = &(mk->cache[i]);
}
- else
- mk->free_cache_descs = NULL;
+
+ mk->cache_unpowered = NULL;
+
+ mk->cache_size = 0;
+ mk->cache_hits = 0;
mk->segments.current.watermark = 0;
mk->segments.current.no = 0;
@@ -1570,15 +1631,10 @@ erts_mseg_init(ErtsMsegInit_t *init)
initialize_pmmap();
#endif
- page_size = GET_PAGE_SIZE;
+ if (!IS_2POW(GET_PAGE_SIZE))
+ erl_exit(ERTS_ABORT_EXIT, "erts_mseg: Unexpected page_size %beu\n", GET_PAGE_SIZE);
- page_shift = 1;
- while ((page_size >> page_shift) != 1) {
- if ((page_size & (1 << (page_shift - 1))) != 0)
- erl_exit(ERTS_ABORT_EXIT,
- "erts_mseg: Unexpected page_size %beu\n", page_size);
- page_shift++;
- }
+ ASSERT((MSEG_ALIGNED_SIZE % GET_PAGE_SIZE) == 0);
for (i = 0; i < no_mseg_allocators; i++) {
ErtsMsegAllctr_t *ma = ERTS_MSEG_ALLCTR_IX(i);
@@ -1663,7 +1719,7 @@ erts_mseg_test(unsigned long op,
case 0x400: /* Have erts_mseg */
return (unsigned long) 1;
case 0x401:
- return (unsigned long) erts_mseg_alloc(ERTS_ALC_A_INVALID, (Uint *) a1);
+ return (unsigned long) erts_mseg_alloc(ERTS_ALC_A_INVALID, (Uint *) a1, (Uint) 0);
case 0x402:
erts_mseg_dealloc(ERTS_ALC_A_INVALID, (void *) a1, (Uint) a2);
return (unsigned long) 0;
@@ -1671,7 +1727,8 @@ erts_mseg_test(unsigned long op,
return (unsigned long) erts_mseg_realloc(ERTS_ALC_A_INVALID,
(void *) a1,
(Uint) a2,
- (Uint *) a3);
+ (Uint *) a3,
+ (Uint) 0);
case 0x404:
erts_mseg_clear_cache();
return (unsigned long) 0;
@@ -1707,7 +1764,40 @@ erts_mseg_test(unsigned long op,
* mapping tricks.
*/
-/*#define HARDDEBUG 1*/
+/* #define HARDDEBUG 1 */
+
+#ifdef HARDDEBUG
+static void dump_freelist(void)
+{
+ FreeBlock *p = first;
+
+ while (p) {
+ fprintf(stderr, "p = %p\r\np->num = %ld\r\np->next = %p\r\n\r\n",
+ (void *) p, (unsigned long) p->num, (void *) p->next);
+ p = p->next;
+ }
+}
+
+#define HARDDEBUG_HW_INCOMPLETE_ALIGNMENT(PTR, SZ) \
+ fprintf(stderr,"Mapping of address %p with size %ld " \
+ "does not map complete pages (%s:%d)\r\n", \
+ (void *) (PTR), (unsigned long) (SZ),__FILE__, __LINE__)
+
+#define HARDDEBUG_HW_UNALIGNED_ALIGNMENT(PTR, SZ) \
+ fprintf(stderr,"Mapping of address %p with size %ld " \
+ "is not page aligned (%s:%d)\r\n", \
+ (void *) (PTR), (unsigned long) (SZ),__FILE__, __LINE__)
+
+#define HARDDEBUG_MAP_FAILED(PTR, SZ) \
+ fprintf(stderr, "Could not actually map memory " \
+ "at address %p with size %ld (%s:%d) ..\r\n", \
+ (void *) (PTR), (unsigned long) (SZ),__FILE__, __LINE__)
+#else
+#define HARDDEBUG_HW_INCOMPLETE_ALIGNMENT(PTR, SZ) do{}while(0)
+#define HARDDEBUG_HW_UNALIGNED_ALIGNMENT(PTR, SZ) do{}while(0)
+#define HARDDEBUG_MAP_FAILED(PTR, SZ) do{}while(0)
+#endif
+
#ifdef __APPLE__
#define MAP_ANONYMOUS MAP_ANON
@@ -1726,49 +1816,20 @@ typedef struct _free_block {
struct _free_block *next;
} FreeBlock;
-/* Assigned once and for all */
-static size_t pagsz;
-
/* Protect with lock */
static FreeBlock *first;
-static size_t round_up_to_pagesize(size_t size)
-{
- size_t x = size / pagsz;
-
- if ((size % pagsz)) {
- ++x;
- }
-
- return pagsz * x;
-}
-
-static size_t round_down_to_pagesize(size_t size)
-{
- size_t x = size / pagsz;
-
- return pagsz * x;
-}
-
static void *do_map(void *ptr, size_t sz)
{
void *res;
- if (round_up_to_pagesize(sz) != sz) {
-#ifdef HARDDEBUG
- fprintf(stderr,"Mapping of address %p with size %ld "
- "does not map complete pages\r\n",
- (void *) ptr, (unsigned long) sz);
-#endif
+ if (ALIGNED_CEILING(sz) != sz) {
+ HARDDEBUG_HW_INCOMPLETE_ALIGNMENT(ptr, sz);
return NULL;
}
- if (((unsigned long) ptr) % pagsz) {
-#ifdef HARDDEBUG
- fprintf(stderr,"Mapping of address %p with size %ld "
- "is not page aligned\r\n",
- (void *) ptr, (unsigned long) sz);
-#endif
+ if (((unsigned long) ptr) % MSEG_ALIGNED_SIZE) {
+ HARDDEBUG_HW_UNALIGNED_ALIGNMENT(ptr, sz);
return NULL;
}
@@ -1782,10 +1843,7 @@ static void *do_map(void *ptr, size_t sz)
#endif
if (res == MAP_FAILED) {
-#ifdef HARDDEBUG
- fprintf(stderr,"Mapping of address %p with size %ld failed!\r\n",
- (void *) ptr, (unsigned long) sz);
-#endif
+ HARDDEBUG_MAP_FAILED(ptr, sz);
return NULL;
}
@@ -1796,35 +1854,22 @@ static int do_unmap(void *ptr, size_t sz)
{
void *res;
- if (round_up_to_pagesize(sz) != sz) {
-#ifdef HARDDEBUG
- fprintf(stderr,"Mapping of address %p with size %ld "
- "does not map complete pages\r\n",
- (void *) ptr, (unsigned long) sz);
-#endif
+ if (ALIGNED_CEILING(sz) != sz) {
+ HARDDEBUG_HW_INCOMPLETE_ALIGNMENT(ptr, sz);
return 1;
}
- if (((unsigned long) ptr) % pagsz) {
-#ifdef HARDDEBUG
- fprintf(stderr,"Mapping of address %p with size %ld "
- "is not page aligned\r\n",
- (void *) ptr, (unsigned long) sz);
-#endif
+ if (((unsigned long) ptr) % MSEG_ALIGNED_SIZE) {
+ HARDDEBUG_HW_UNALIGNED_ALIGNMENT(ptr, sz);
return 1;
}
-
res = mmap(ptr, sz,
- PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE
- | MAP_FIXED,
+ PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_FIXED,
-1 , 0);
if (res == MAP_FAILED) {
-#ifdef HARDDEBUG
- fprintf(stderr,"Mapping of address %p with size %ld failed!\r\n",
- (void *) ptr, (unsigned long) sz);
-#endif
+ HARDDEBUG_MAP_FAILED(ptr, sz);
return 1;
}
@@ -1862,8 +1907,6 @@ static int initialize_pmmap(void)
size_t rsz;
FreeBlock *initial;
-
- pagsz = getpagesize();
SET_RANGE_MIN();
if (sizeof(void *) != 8) {
erl_exit(1,"Halfword emulator cannot be run in 32bit mode");
@@ -1872,15 +1915,15 @@ static int initialize_pmmap(void)
p = (char *) RANGE_MIN;
q = (char *) RANGE_MAX;
- rsz = round_down_to_pagesize(q - p);
+ rsz = ALIGNED_FLOOR(q - p);
- rptr = mmap((void *) p, rsz,
+ rptr = mmap_align(NULL, (void *) p, rsz,
PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS |
MAP_NORESERVE | EXTRA_MAP_FLAGS,
-1 , 0);
#ifdef HARDDEBUG
printf("p=%p, rsz = %ld, pages = %ld, got range = %p -> %p\r\n",
- p, (unsigned long) rsz, (unsigned long) (rsz / pagsz),
+ p, (unsigned long) rsz, (unsigned long) (rsz / MSEG_ALIGNED_SIZE),
(void *) rptr, (void*)(rptr + rsz));
#endif
if ((UWord)(rptr + rsz) > RANGE_MAX) {
@@ -1892,39 +1935,27 @@ static int initialize_pmmap(void)
munmap((void*)RANGE_MAX, rsz - rsz_trunc);
rsz = rsz_trunc;
}
- if (!do_map(rptr,pagsz)) {
+ if (!do_map(rptr, MSEG_ALIGNED_SIZE)) {
erl_exit(1,"Could not actually mmap first page for halfword emulator...\n");
}
initial = (FreeBlock *) rptr;
- initial->num = (rsz / pagsz);
+ initial->num = (rsz / MSEG_ALIGNED_SIZE);
initial->next = NULL;
first = initial;
INIT_LOCK();
return 0;
}
-#ifdef HARDDEBUG
-static void dump_freelist(void)
-{
- FreeBlock *p = first;
-
- while (p) {
- printf("p = %p\r\np->num = %ld\r\np->next = %p\r\n\r\n",
- (void *) p, (unsigned long) p->num, (void *) p->next);
- p = p->next;
- }
-}
-#endif
-
-
static void *pmmap(size_t size)
{
- size_t real_size = round_up_to_pagesize(size);
- size_t num_pages = real_size / pagsz;
+ size_t real_size = ALIGNED_CEILING(size);
+ size_t num_pages = real_size / MSEG_ALIGNED_SIZE;
FreeBlock **block;
FreeBlock *tail;
FreeBlock *res;
+
TAKE_LOCK();
+
for (block = &first;
*block != NULL && (*block)->num < num_pages;
block = &((*block)->next))
@@ -1935,29 +1966,25 @@ static void *pmmap(size_t size)
}
if ((*block)->num == num_pages) {
/* nice, perfect fit */
- res = *block;
+ res = *block;
*block = (*block)->next;
} else {
tail = (FreeBlock *) (((char *) ((void *) (*block))) + real_size);
- if (!do_map(tail,pagsz)) {
-#ifdef HARDDEBUG
- fprintf(stderr, "Could not actually allocate page at %p...\r\n",
- (void *) tail);
-#endif
+ if (!do_map(tail, MSEG_ALIGNED_SIZE)) {
+ HARDDEBUG_MAP_FAILED(tail, MSEG_ALIGNED_SIZE);
RELEASE_LOCK();
return NULL;
}
- tail->num = (*block)->num - num_pages;
+ tail->num = (*block)->num - num_pages;
tail->next = (*block)->next;
res = *block;
*block = tail;
}
+
RELEASE_LOCK();
- if (!do_map(res,real_size)) {
-#ifdef HARDDEBUG
- fprintf(stderr, "Could not actually allocate %ld at %p...\r\n",
- (unsigned long) real_size, (void *) res);
-#endif
+
+ if (!do_map(res, real_size)) {
+ HARDDEBUG_MAP_FAILED(res, real_size);
return NULL;
}
@@ -1966,15 +1993,17 @@ static void *pmmap(size_t size)
static int pmunmap(void *p, size_t size)
{
- size_t real_size = round_up_to_pagesize(size);
- size_t num_pages = real_size / pagsz;
+ size_t real_size = ALIGNED_CEILING(size);
+ size_t num_pages = real_size / MSEG_ALIGNED_SIZE;
+
FreeBlock *block;
FreeBlock *last;
FreeBlock *nb = (FreeBlock *) p;
ASSERT(((unsigned long)p & CHECK_POINTER_MASK)==0);
- if (real_size > pagsz) {
- if (do_unmap(((char *) p) + pagsz,real_size - pagsz)) {
+
+ if (real_size > MSEG_ALIGNED_SIZE) {
+ if (do_unmap(((char *) p) + MSEG_ALIGNED_SIZE, real_size - MSEG_ALIGNED_SIZE)) {
return 1;
}
}
@@ -1993,7 +2022,7 @@ static int pmunmap(void *p, size_t size)
/* Merge new free block with following */
nb->num = block->num + num_pages;
nb->next = block->next;
- if (do_unmap(block,pagsz)) {
+ if (do_unmap(block, MSEG_ALIGNED_SIZE)) {
RELEASE_LOCK();
return 1;
}
@@ -2003,11 +2032,11 @@ static int pmunmap(void *p, size_t size)
nb->next = block;
}
if (last != NULL) {
- if (p == ((void *) (((char *) last) + (last->num * pagsz)))) {
+ if (p == ((void *) (((char *) last) + (last->num * MSEG_ALIGNED_SIZE)))) {
/* Merge with previous */
last->num += nb->num;
last->next = nb->next;
- if (do_unmap(nb,pagsz)) {
+ if (do_unmap(nb, MSEG_ALIGNED_SIZE)) {
RELEASE_LOCK();
return 1;
}
@@ -2024,10 +2053,10 @@ static int pmunmap(void *p, size_t size)
static void *pmremap(void *old_address, size_t old_size,
size_t new_size)
{
- size_t new_real_size = round_up_to_pagesize(new_size);
- size_t new_num_pages = new_real_size / pagsz;
- size_t old_real_size = round_up_to_pagesize(old_size);
- size_t old_num_pages = old_real_size / pagsz;
+ size_t new_real_size = ALIGNED_CEILING(new_size);
+ size_t new_num_pages = new_real_size / MSEG_ALIGNED_SIZE;
+ size_t old_real_size = ALIGNED_CEILING(old_size);
+ size_t old_num_pages = old_real_size / MSEG_ALIGNED_SIZE;
if (new_num_pages == old_num_pages) {
return old_address;
} else if (new_num_pages < old_num_pages) { /* Shrink */
@@ -2045,8 +2074,8 @@ static void *pmremap(void *old_address, size_t old_size,
(*block) > ((FreeBlock *)(((char *) vnfb) + nfb_real_size))) {
/* Normal link in */
if (nfb_pages > 1) {
- if (do_unmap((void *)(((char *) vnfb) + pagsz),
- (nfb_pages - 1)*pagsz)) {
+ if (do_unmap((void *)(((char *) vnfb) + MSEG_ALIGNED_SIZE),
+ (nfb_pages - 1)*MSEG_ALIGNED_SIZE)) {
return NULL;
}
}
@@ -2058,8 +2087,8 @@ static void *pmremap(void *old_address, size_t old_size,
nfb->num = nfb_pages + (*block)->num;
/* unmap also the first page of the next freeblock */
(*block) = nfb;
- if (do_unmap((void *)(((char *) vnfb) + pagsz),
- nfb_pages*pagsz)) {
+ if (do_unmap((void *)(((char *) vnfb) + MSEG_ALIGNED_SIZE),
+ nfb_pages*MSEG_ALIGNED_SIZE)) {
return NULL;
}
}
@@ -2094,9 +2123,9 @@ static void *pmremap(void *old_address, size_t old_size,
size_t remaining_pages = (*block)->num -
(new_num_pages - old_num_pages);
if (!remaining_pages) {
- void *p = (void *) (((char *) (*block)) + pagsz);
+ void *p = (void *) (((char *) (*block)) + MSEG_ALIGNED_SIZE);
void *n = (*block)->next;
- size_t x = ((*block)->num - 1) * pagsz;
+ size_t x = ((*block)->num - 1) * MSEG_ALIGNED_SIZE;
if (x > 0) {
if (do_map(p,x) == NULL) {
RELEASE_LOCK();
@@ -2108,7 +2137,7 @@ static void *pmremap(void *old_address, size_t old_size,
FreeBlock *nfb = (FreeBlock *) ((void *)
(((char *) old_address) +
new_real_size));
- void *p = (void *) (((char *) (*block)) + pagsz);
+ void *p = (void *) (((char *) (*block)) + MSEG_ALIGNED_SIZE);
if (do_map(p,new_real_size - old_real_size) == NULL) {
RELEASE_LOCK();
return NULL;
@@ -2122,5 +2151,4 @@ static void *pmremap(void *old_address, size_t old_size,
}
}
}
-
#endif /* HALFWORD_HEAP */
diff --git a/erts/emulator/sys/common/erl_mseg.h b/erts/emulator/sys/common/erl_mseg.h
index 741080fb78..6f373f13f9 100644
--- a/erts/emulator/sys/common/erl_mseg.h
+++ b/erts/emulator/sys/common/erl_mseg.h
@@ -32,12 +32,35 @@
#if HAVE_MMAP
# define HAVE_ERTS_MSEG 1
+# define HAVE_SUPER_ALIGNED_MB_CARRIERS 1
#else
# define HAVE_ERTS_MSEG 0
+# define HAVE_SUPER_ALIGNED_MB_CARRIERS 0
+#endif
+
+#if HAVE_SUPER_ALIGNED_MB_CARRIERS
+# define MSEG_ALIGN_BITS (18)
+ /* Affects hard limits for sbct and lmbcs documented in erts_alloc.xml */
+#else
+/* If we don't use super aligned multiblock carriers
+ * we will mmap with page size alignment (and thus use corresponding
+ * align bits).
+ *
+ * Current implementation needs this to be a constant and
+ * only uses this for user dev testing so setting page size
+ * to 4096 (12 bits) is fine.
+ */
+# define MSEG_ALIGN_BITS (12)
#endif
#if HAVE_ERTS_MSEG
+#define MSEG_ALIGNED_SIZE (1 << MSEG_ALIGN_BITS)
+
+#define ERTS_MSEG_FLG_NONE ((Uint)(0))
+#define ERTS_MSEG_FLG_2POW ((Uint)(1 << 0))
+
+
#define ERTS_MSEG_VSN_STR "0.9"
typedef struct {
@@ -68,13 +91,13 @@ typedef struct {
extern const ErtsMsegOpt_t erts_mseg_default_opt;
-void *erts_mseg_alloc(ErtsAlcType_t, Uint *);
-void *erts_mseg_alloc_opt(ErtsAlcType_t, Uint *, const ErtsMsegOpt_t *);
+void *erts_mseg_alloc(ErtsAlcType_t, Uint *, Uint);
+void *erts_mseg_alloc_opt(ErtsAlcType_t, Uint *, Uint, const ErtsMsegOpt_t *);
void erts_mseg_dealloc(ErtsAlcType_t, void *, Uint);
void erts_mseg_dealloc_opt(ErtsAlcType_t, void *, Uint, const ErtsMsegOpt_t *);
-void *erts_mseg_realloc(ErtsAlcType_t, void *, Uint, Uint *);
+void *erts_mseg_realloc(ErtsAlcType_t, void *, Uint, Uint *, Uint);
void *erts_mseg_realloc_opt(ErtsAlcType_t, void *, Uint, Uint *,
- const ErtsMsegOpt_t *);
+ Uint, const ErtsMsegOpt_t *);
void erts_mseg_clear_cache(void);
void erts_mseg_cache_check(void);
Uint erts_mseg_no( const ErtsMsegOpt_t *);
diff --git a/erts/emulator/sys/unix/erl_unix_sys_ddll.c b/erts/emulator/sys/unix/erl_unix_sys_ddll.c
index 336d9586c4..a35aec560a 100644
--- a/erts/emulator/sys/unix/erl_unix_sys_ddll.c
+++ b/erts/emulator/sys/unix/erl_unix_sys_ddll.c
@@ -101,7 +101,7 @@ void erl_sys_ddll_init(void) {
/*
* Open a shared object
*/
-int erts_sys_ddll_open2(char *full_name, void **handle, ErtsSysDdllError* err)
+int erts_sys_ddll_open2(const char *full_name, void **handle, ErtsSysDdllError* err)
{
#if defined(HAVE_DLOPEN)
char* dlname;
@@ -153,7 +153,7 @@ int erts_sys_ddll_open_noext(char *dlname, void **handle, ErtsSysDdllError* err)
/*
* Find a symbol in the shared object
*/
-int erts_sys_ddll_sym2(void *handle, char *func_name, void **function,
+int erts_sys_ddll_sym2(void *handle, const char *func_name, void **function,
ErtsSysDdllError* err)
{
#if defined(HAVE_DLOPEN)
diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c
index 97756e8434..0b96eded76 100644
--- a/erts/emulator/sys/unix/sys.c
+++ b/erts/emulator/sys/unix/sys.c
@@ -58,7 +58,6 @@
#define __DARWIN__ 1
#endif
-
#ifdef USE_THREADS
#include "erl_threads.h"
#endif
@@ -71,7 +70,6 @@ static erts_smp_rwmtx_t environ_rwmtx;
#define MAX_VSIZE 16 /* Max number of entries allowed in an I/O
* vector sock_sendv().
*/
-
/*
* Don't need global.h, but bif_table.h (included by bif.h),
* won't compile otherwise
@@ -123,6 +121,16 @@ struct ErtsSysReportExit_ {
#endif
};
+/* This data is shared by these drivers - initialized by spawn_init() */
+static struct driver_data {
+ ErlDrvPort port_num;
+ int ofd, packet_bytes;
+ ErtsSysReportExit *report_exit;
+ int pid;
+ int alive;
+ int status;
+} *driver_data; /* indexed by fd */
+
static ErtsSysReportExit *report_exit_list;
#if CHLDWTHR && !defined(ERTS_SMP)
static ErtsSysReportExit *report_exit_transit_list;
@@ -679,18 +687,58 @@ static RETSIGTYPE break_handler(int sig)
}
#endif /* 0 */
-static ERTS_INLINE void
-prepare_crash_dump(void)
+static ERTS_INLINE int
+prepare_crash_dump(int secs)
{
+#define NUFBUF (3)
int i, max;
char env[21]; /* enough to hold any 64-bit integer */
size_t envsz;
+ DeclareTmpHeapNoproc(heap,NUFBUF);
+ Port *heart_port;
+ Eterm *hp = heap;
+ Eterm list = NIL;
+ int heart_fd[2] = {-1,-1};
+ int has_heart = 0;
+
+ UseTmpHeapNoproc(NUFBUF);
if (ERTS_PREPARED_CRASH_DUMP)
- return; /* We have already been called */
+ return 0; /* We have already been called */
+
+ heart_port = erts_get_heart_port();
+
+ /* Positive secs means an alarm must be set
+ * 0 or negative means no alarm
+ *
+ * Set alarm before we try to write to a port
+ * we don't want to hang on a port write with
+ * no alarm.
+ *
+ */
+
+ if (secs >= 0) {
+ alarm((unsigned int)secs);
+ }
+
+ if (heart_port) {
+ /* hearts input fd
+ * We "know" drv_data is the in_fd since the port is started with read|write
+ */
+ heart_fd[0] = (int)heart_port->drv_data;
+ heart_fd[1] = (int)driver_data[heart_fd[0]].ofd;
+ has_heart = 1;
+
+ list = CONS(hp, make_small(8), list); hp += 2;
+
+ /* send to heart port, CMD = 8, i.e. prepare crash dump =o */
+ erts_port_output(NULL, ERTS_PORT_SIG_FLG_FORCE_IMM_CALL, heart_port,
+ heart_port->common.id, list, NULL);
+ }
/* Make sure we unregister at epmd (unknown fd) and get at least
one free filedescriptor (for erl_crash.dump) */
+
max = max_files;
if (max < 1024)
max = 1024;
@@ -704,11 +752,15 @@ prepare_crash_dump(void)
if (i == async_fd[0] || i == async_fd[1])
continue;
#endif
+ /* We don't want to close our heart yet ... */
+ if (i == heart_fd[0] || i == heart_fd[1])
+ continue;
+
close(i);
}
envsz = sizeof(env);
- i = erts_sys_getenv_raw("ERL_CRASH_DUMP_NICE", env, &envsz);
+ i = erts_sys_getenv__("ERL_CRASH_DUMP_NICE", env, &envsz);
if (i >= 0) {
int nice_val;
nice_val = i != 0 ? 0 : atoi(env);
@@ -717,21 +769,15 @@ prepare_crash_dump(void)
}
erts_silence_warn_unused_result(nice(nice_val));
}
-
- envsz = sizeof(env);
- i = erts_sys_getenv_raw("ERL_CRASH_DUMP_SECONDS", env, &envsz);
- if (i >= 0) {
- unsigned sec;
- sec = (unsigned) i != 0 ? 0 : atoi(env);
- alarm(sec);
- }
+ UnUseTmpHeapNoproc(NUFBUF);
+#undef NUFBUF
+ return has_heart;
}
-void
-erts_sys_prepare_crash_dump(void)
+int erts_sys_prepare_crash_dump(int secs)
{
- prepare_crash_dump();
+ return prepare_crash_dump(secs);
}
static ERTS_INLINE void
@@ -768,12 +814,22 @@ static RETSIGTYPE request_break(int signum)
static ERTS_INLINE void
sigusr1_exit(void)
{
- /* We do this at interrupt level, since the main reason for
- wanting to generate a crash dump in this way is that the emulator
- is hung somewhere, so it won't be able to poll any flag we set here.
- */
+ char env[21]; /* enough to hold any 64-bit integer */
+ size_t envsz;
+ int i, secs = -1;
+
+ /* We do this at interrupt level, since the main reason for
+ * wanting to generate a crash dump in this way is that the emulator
+ * is hung somewhere, so it won't be able to poll any flag we set here.
+ */
ERTS_SET_GOT_SIGUSR1;
- prepare_crash_dump();
+
+ envsz = sizeof(env);
+ if ((i = erts_sys_getenv_raw("ERL_CRASH_DUMP_SECONDS", env, &envsz)) >= 0) {
+ secs = i != 0 ? 0 : atoi(env);
+ }
+
+ prepare_crash_dump(secs);
erl_exit(1, "Received SIGUSR1\n");
}
@@ -1021,15 +1077,6 @@ void fini_getenv_state(GETENV_STATE *state)
#define ERTS_SYS_READ_BUF_SZ (64*1024)
-/* This data is shared by these drivers - initialized by spawn_init() */
-static struct driver_data {
- int port_num, ofd, packet_bytes;
- ErtsSysReportExit *report_exit;
- int pid;
- int alive;
- int status;
-} *driver_data; /* indexed by fd */
-
/* Driver interfaces */
static ErlDrvData spawn_start(ErlDrvPort, char*, SysDriverOpts*);
static ErlDrvData fd_start(ErlDrvPort, char*, SysDriverOpts*);
@@ -1137,7 +1184,7 @@ static RETSIGTYPE onchld(int signum)
#endif
}
-static int set_driver_data(int port_num,
+static int set_driver_data(ErlDrvPort port_num,
int ifd,
int ofd,
int packet_bytes,
@@ -1145,6 +1192,7 @@ static int set_driver_data(int port_num,
int exit_status,
int pid)
{
+ Port *prt;
ErtsSysReportExit *report_exit;
if (!exit_status)
@@ -1153,7 +1201,7 @@ static int set_driver_data(int port_num,
report_exit = erts_alloc(ERTS_ALC_T_PRT_REP_EXIT,
sizeof(ErtsSysReportExit));
report_exit->next = report_exit_list;
- report_exit->port = erts_port[port_num].id;
+ report_exit->port = erts_drvport2id(port_num);
report_exit->pid = pid;
report_exit->ifd = read_write & DO_READ ? ifd : -1;
report_exit->ofd = read_write & DO_WRITE ? ofd : -1;
@@ -1163,7 +1211,9 @@ static int set_driver_data(int port_num,
report_exit_list = report_exit;
}
- erts_port[port_num].os_pid = pid;
+ prt = erts_drvport2port(port_num, NULL);
+ if (prt)
+ prt->os_pid = pid;
if (read_write & DO_READ) {
driver_data[ifd].packet_bytes = packet_bytes;
@@ -1236,7 +1286,7 @@ static void close_pipes(int ifd[2], int ofd[2], int read_write)
}
}
-static void init_fd_data(int fd, int prt)
+static void init_fd_data(int fd, ErlDrvPort port_num)
{
fd_data[fd].buf = NULL;
fd_data[fd].cpos = NULL;
@@ -1926,7 +1976,7 @@ static void clear_fd_data(int fd)
fd_data[fd].psz = 0;
}
-static void nbio_stop_fd(int prt, int fd)
+static void nbio_stop_fd(ErlDrvPort prt, int fd)
{
driver_select(prt,fd,DO_READ|DO_WRITE,0);
clear_fd_data(fd);
@@ -1974,7 +2024,8 @@ static ErlDrvData vanilla_start(ErlDrvPort port_num, char* name,
static void stop(ErlDrvData fd)
{
- int prt, ofd;
+ ErlDrvPort prt;
+ int ofd;
prt = driver_data[(int)(long)fd].port_num;
nbio_stop_fd(prt, (int)(long)fd);
@@ -1987,7 +2038,7 @@ static void stop(ErlDrvData fd)
CHLD_STAT_LOCK;
- /* Mark as unused. Maybe resetting the 'port_num' slot is better? */
+ /* Mark as unused. */
driver_data[(int)(long)fd].pid = -1;
CHLD_STAT_UNLOCK;
@@ -2003,7 +2054,7 @@ static void stop(ErlDrvData fd)
static void outputv(ErlDrvData e, ErlIOVec* ev)
{
int fd = (int)(long)e;
- int ix = driver_data[fd].port_num;
+ ErlDrvPort ix = driver_data[fd].port_num;
int pb = driver_data[fd].packet_bytes;
int ofd = driver_data[fd].ofd;
ssize_t n;
@@ -2053,7 +2104,7 @@ static void outputv(ErlDrvData e, ErlIOVec* ev)
static void output(ErlDrvData e, char* buf, ErlDrvSizeT len)
{
int fd = (int)(long)e;
- int ix = driver_data[fd].port_num;
+ ErlDrvPort ix = driver_data[fd].port_num;
int pb = driver_data[fd].packet_bytes;
int ofd = driver_data[fd].ofd;
ssize_t n;
@@ -2104,7 +2155,7 @@ static void output(ErlDrvData e, char* buf, ErlDrvSizeT len)
return; /* 0; */
}
-static int port_inp_failure(int port_num, int ready_fd, int res)
+static int port_inp_failure(ErlDrvPort port_num, int ready_fd, int res)
/* Result: 0 (eof) or -1 (error) */
{
int err = errno;
@@ -2154,7 +2205,7 @@ static int port_inp_failure(int port_num, int ready_fd, int res)
static void ready_input(ErlDrvData e, ErlDrvEvent ready_fd)
{
int fd = (int)(long)e;
- int port_num;
+ ErlDrvPort port_num;
int packet_bytes;
int res;
Uint h;
@@ -2277,7 +2328,7 @@ static void ready_input(ErlDrvData e, ErlDrvEvent ready_fd)
static void ready_output(ErlDrvData e, ErlDrvEvent ready_fd)
{
int fd = (int)(long)e;
- int ix = driver_data[fd].port_num;
+ ErlDrvPort ix = driver_data[fd].port_num;
int n;
struct iovec* iv;
int vsize;
@@ -2419,6 +2470,15 @@ erts_sys_getenv_raw(char *key, char *value, size_t *size) {
return erts_sys_getenv(key, value, size);
}
+/*
+ * erts_sys_getenv
+ * returns:
+ * -1, if environment key is not set with a value
+ * 0, if environment key is set and value fits into buffer size
+ * 1, if environment key is set but does not fit into buffer size
+ * size is set with the needed buffer size value
+ */
+
int
erts_sys_getenv(char *key, char *value, size_t *size)
{
@@ -2577,19 +2637,20 @@ report_exit_status(ErtsSysReportExit *rep, int status)
Port *pp;
#ifdef ERTS_SMP
CHLD_STAT_UNLOCK;
-#endif
+ pp = erts_thr_id2port_sflgs(rep->port,
+ ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP);
+ CHLD_STAT_LOCK;
+#else
pp = erts_id2port_sflgs(rep->port,
NULL,
0,
ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP);
-#ifdef ERTS_SMP
- CHLD_STAT_LOCK;
#endif
if (pp) {
if (rep->ifd >= 0) {
driver_data[rep->ifd].alive = 0;
driver_data[rep->ifd].status = status;
- (void) driver_select((ErlDrvPort) internal_port_index(pp->id),
+ (void) driver_select((ErlDrvPort) pp,
rep->ifd,
(ERL_DRV_READ|ERL_DRV_USE),
1);
@@ -2597,12 +2658,16 @@ report_exit_status(ErtsSysReportExit *rep, int status)
if (rep->ofd >= 0) {
driver_data[rep->ofd].alive = 0;
driver_data[rep->ofd].status = status;
- (void) driver_select((ErlDrvPort) internal_port_index(pp->id),
+ (void) driver_select((ErlDrvPort) pp,
rep->ofd,
(ERL_DRV_WRITE|ERL_DRV_USE),
1);
}
+#ifdef ERTS_SMP
+ erts_thr_port_release(pp);
+#else
erts_port_release(pp);
+#endif
}
erts_free(ERTS_ALC_T_PRT_REP_EXIT, rep);
}
diff --git a/erts/emulator/sys/win32/erl_win32_sys_ddll.c b/erts/emulator/sys/win32/erl_win32_sys_ddll.c
index d00eed932b..54991a610c 100644
--- a/erts/emulator/sys/win32/erl_win32_sys_ddll.c
+++ b/erts/emulator/sys/win32/erl_win32_sys_ddll.c
@@ -58,7 +58,7 @@ void erl_sys_ddll_init(void) {
/*
* Open a shared object
*/
-int erts_sys_ddll_open2(char *full_name, void **handle, ErtsSysDdllError* err)
+int erts_sys_ddll_open2(const char *full_name, void **handle, ErtsSysDdllError* err)
{
int len;
char dlname[MAXPATHLEN + 1];
@@ -92,7 +92,7 @@ int erts_sys_ddll_open_noext(char *dlname, void **handle, ErtsSysDdllError* err)
/*
* Find a symbol in the shared object
*/
-int erts_sys_ddll_sym2(void *handle, char *func_name, void **function,
+int erts_sys_ddll_sym2(void *handle, const char *func_name, void **function,
ErtsSysDdllError* err)
{
FARPROC proc;
diff --git a/erts/emulator/sys/win32/erl_win_dyn_driver.h b/erts/emulator/sys/win32/erl_win_dyn_driver.h
index ec5141838a..8b6be2b2f1 100644
--- a/erts/emulator/sys/win32/erl_win_dyn_driver.h
+++ b/erts/emulator/sys/win32/erl_win_dyn_driver.h
@@ -74,7 +74,9 @@ WDD_TYPEDEF(ErlDrvTermData, driver_mk_port,(ErlDrvPort));
WDD_TYPEDEF(ErlDrvTermData, driver_connected,(ErlDrvPort));
WDD_TYPEDEF(ErlDrvTermData, driver_caller,(ErlDrvPort));
WDD_TYPEDEF(ErlDrvTermData, driver_mk_term_nil,(void));
+WDD_TYPEDEF(int, erl_drv_output_term, (ErlDrvTermData, ErlDrvTermData*, int));
WDD_TYPEDEF(int, driver_output_term, (ErlDrvPort, ErlDrvTermData*, int));
+WDD_TYPEDEF(int, erl_drv_send_term, (ErlDrvTermData, ErlDrvTermData, ErlDrvTermData*, int));
WDD_TYPEDEF(int, driver_send_term, (ErlDrvPort, ErlDrvTermData, ErlDrvTermData*, int));
WDD_TYPEDEF(long, driver_async, (ErlDrvPort,unsigned int*,void (*)(void*),void*,void (*)(void*)));
WDD_TYPEDEF(int, driver_async_cancel, (unsigned int));
@@ -187,7 +189,9 @@ typedef struct {
WDD_FTYPE(driver_connected) *driver_connected;
WDD_FTYPE(driver_caller) *driver_caller;
WDD_FTYPE(driver_mk_term_nil) *driver_mk_term_nil;
+ WDD_FTYPE(erl_drv_output_term) *erl_drv_output_term;
WDD_FTYPE(driver_output_term) *driver_output_term;
+ WDD_FTYPE(erl_drv_send_term) *erl_drv_send_term;
WDD_FTYPE(driver_send_term) *driver_send_term;
WDD_FTYPE(driver_async) *driver_async;
WDD_FTYPE(driver_async_cancel) *driver_async_cancel;
@@ -294,7 +298,9 @@ extern TWinDynDriverCallbacks WinDynDriverCallbacks;
#define driver_connected (WinDynDriverCallbacks.driver_connected)
#define driver_caller (WinDynDriverCallbacks.driver_caller)
#define driver_mk_term_nil (WinDynDriverCallbacks.driver_mk_term_nil)
+#define erl_drv_output_term (WinDynDriverCallbacks.erl_drv_output_term)
#define driver_output_term (WinDynDriverCallbacks.driver_output_term)
+#define erl_drv_send_term (WinDynDriverCallbacks.erl_drv_send_term)
#define driver_send_term (WinDynDriverCallbacks.driver_send_term)
#define driver_async (WinDynDriverCallbacks.driver_async)
#define driver_async_cancel (WinDynDriverCallbacks.driver_async_cancel)
@@ -425,7 +431,9 @@ do { \
((W).driver_connected) = driver_connected; \
((W).driver_caller) = driver_caller; \
((W).driver_mk_term_nil) = driver_mk_term_nil; \
+((W).erl_drv_output_term) = erl_drv_output_term; \
((W).driver_output_term) = driver_output_term; \
+((W).erl_drv_send_term) = erl_drv_send_term; \
((W).driver_send_term) = driver_send_term; \
((W).driver_async) = driver_async; \
((W).driver_async_cancel) = driver_async_cancel; \
diff --git a/erts/emulator/sys/win32/sys.c b/erts/emulator/sys/win32/sys.c
index 6c69fecbf3..1cd9072cea 100755
--- a/erts/emulator/sys/win32/sys.c
+++ b/erts/emulator/sys/win32/sys.c
@@ -87,9 +87,6 @@ static erts_smp_tsd_key_t win32_errstr_key;
static erts_smp_atomic_t pipe_creation_counter;
-static erts_smp_mtx_t sys_driver_data_lock;
-
-
/* Results from application_type(_w) is one of */
#define APPL_NONE 0
#define APPL_DOS 1
@@ -97,7 +94,6 @@ static erts_smp_mtx_t sys_driver_data_lock;
#define APPL_WIN32 3
static int driver_write(long, HANDLE, byte*, int);
-static void common_stop(int);
static int create_file_thread(struct async_io* aio, int mode);
#ifdef ERTS_SMP
static void close_active_handle(ErlDrvPort, HANDLE handle);
@@ -115,9 +111,6 @@ BOOL WINAPI ctrl_handler(DWORD dwCtrlType);
#define PORT_BUFSIZ 4096
-#define PORT_FREE (-1)
-#define PORT_EXITING (-2)
-
#define DRV_BUF_ALLOC(SZ) \
erts_alloc_fnf(ERTS_ALC_T_DRV_DATA_BUF, (SZ))
#define DRV_BUF_REALLOC(P, SZ) \
@@ -255,11 +248,30 @@ void erl_sys_args(int* argc, char** argv)
#endif
}
-void
-erts_sys_prepare_crash_dump(void)
+int erts_sys_prepare_crash_dump(int secs)
{
+ Port *heart_port;
+ Eterm heap[3];
+ Eterm *hp = heap;
+ Eterm list = NIL;
+
+ heart_port = erts_get_heart_port();
+
+ if (heart_port) {
+
+ list = CONS(hp, make_small(8), list); hp += 2;
+
+ /* send to heart port, CMD = 8, i.e. prepare crash dump =o */
+ erts_port_output(NULL, ERTS_PORT_SIG_FLG_FORCE_IMM_CALL, heart_port,
+ heart_port->common.id, list, NULL);
+
+ return 1;
+ }
+
/* Windows - free file descriptors are hopefully available */
- return;
+ /* Alarm not used on windows */
+
+ return 0;
}
static void
@@ -456,7 +468,7 @@ typedef struct driver_data {
byte *inbuf; /* Buffer to use for overlapped read. */
int outBufSize; /* Size of output buffer. */
byte *outbuf; /* Buffer to use for overlapped write. */
- ErlDrvPort port_num; /* The port number. */
+ ErlDrvPort port_num; /* The port handle. */
int packet_bytes; /* 0: continous stream, 1, 2, or 4: the number
* of bytes in the packet header.
*/
@@ -466,8 +478,6 @@ typedef struct driver_data {
int report_exit; /* Do report exit status for the port */
} DriverData;
-static DriverData* driver_data; /* Pointer to array of driver data. */
-
/* Driver interfaces */
static ErlDrvData spawn_start(ErlDrvPort, char*, SysDriverOpts*);
static ErlDrvData fd_start(ErlDrvPort, char*, SysDriverOpts*);
@@ -579,67 +589,53 @@ struct erl_drv_entry vanilla_driver_entry = {
*/
static DriverData*
-new_driver_data(int port_num, int packet_bytes, int wait_objs_required, int use_threads)
+new_driver_data(ErlDrvPort port_num, int packet_bytes, int wait_objs_required, int use_threads)
{
DriverData* dp;
-
- erts_smp_mtx_lock(&sys_driver_data_lock);
- DEBUGF(("new_driver_data(port_num %d, pb %d)\n",
- port_num, packet_bytes));
+ DEBUGF(("new_driver_data(%p, pb %d)\n", port_num, packet_bytes));
+ dp = driver_alloc(sizeof(DriverData));
+ if (!dp)
+ return NULL;
/*
* We used to test first at all that there is enough room in the
* array used by WaitForMultipleObjects(), but that is not necessary
* any more, since driver_select() can't fail.
*/
- /*
- * Search for a free slot.
- */
+ dp->bytesInBuffer = 0;
+ dp->totalNeeded = packet_bytes;
+ dp->inBufSize = PORT_BUFSIZ;
+ dp->inbuf = DRV_BUF_ALLOC(dp->inBufSize);
+ if (dp->inbuf == NULL)
+ goto buf_alloc_error;
+ erts_smp_atomic_add_nob(&sys_misc_mem_sz, dp->inBufSize);
+ dp->outBufSize = 0;
+ dp->outbuf = NULL;
+ dp->port_num = port_num;
+ dp->packet_bytes = packet_bytes;
+ dp->port_pid = INVALID_HANDLE_VALUE;
+ if (init_async_io(&dp->in, use_threads) == -1)
+ goto async_io_error1;
+ if (init_async_io(&dp->out, use_threads) == -1)
+ goto async_io_error2;
- for (dp = driver_data; dp < driver_data+max_files; dp++) {
- if (dp->port_num == PORT_FREE) {
- dp->bytesInBuffer = 0;
- dp->totalNeeded = packet_bytes;
- dp->inBufSize = PORT_BUFSIZ;
- dp->inbuf = DRV_BUF_ALLOC(dp->inBufSize);
- if (dp->inbuf == NULL) {
- erts_smp_mtx_unlock(&sys_driver_data_lock);
- return NULL;
- }
- erts_smp_atomic_add_nob(&sys_misc_mem_sz, dp->inBufSize);
- dp->outBufSize = 0;
- dp->outbuf = NULL;
- dp->port_num = port_num;
- dp->packet_bytes = packet_bytes;
- dp->port_pid = INVALID_HANDLE_VALUE;
- if (init_async_io(&dp->in, use_threads) == -1)
- break;
- if (init_async_io(&dp->out, use_threads) == -1)
- break;
- erts_smp_mtx_unlock(&sys_driver_data_lock);
- return dp;
- }
- }
+ return dp;
- /*
- * Error or no free driver data.
- */
+async_io_error2:
+ release_async_io(&dp->in, dp->port_num);
+async_io_error1:
+ release_async_io(&dp->out, dp->port_num);
- if (dp < driver_data+max_files) {
- release_async_io(&dp->in, dp->port_num);
- release_async_io(&dp->out, dp->port_num);
- }
- erts_smp_mtx_unlock(&sys_driver_data_lock);
+buf_alloc_error:
+ driver_free(dp);
return NULL;
}
static void
release_driver_data(DriverData* dp)
{
- erts_smp_mtx_lock(&sys_driver_data_lock);
-
#ifdef ERTS_SMP
#ifdef USE_CANCELIOEX
if (fpCancelIoEx != NULL) {
@@ -723,8 +719,7 @@ release_driver_data(DriverData* dp)
* the exit thread.
*/
- dp->port_num = PORT_FREE;
- erts_smp_mtx_unlock(&sys_driver_data_lock);
+ driver_free(dp);
}
#ifdef ERTS_SMP
@@ -819,7 +814,6 @@ threaded_handle_closer(LPVOID param)
static ErlDrvData
set_driver_data(DriverData* dp, HANDLE ifd, HANDLE ofd, int read_write, int report_exit)
{
- int index = dp - driver_data;
int result;
dp->in.fd = ifd;
@@ -838,13 +832,12 @@ set_driver_data(DriverData* dp, HANDLE ifd, HANDLE ofd, int read_write, int repo
ERL_DRV_WRITE|ERL_DRV_USE, 1);
ASSERT(result != -1);
}
- return (ErlDrvData)index;
+ return (ErlDrvData) dp;
}
static ErlDrvData
reuse_driver_data(DriverData *dp, HANDLE ifd, HANDLE ofd, int read_write, ErlDrvPort port_num)
{
- int index = dp - driver_data;
int result;
dp->port_num = port_num;
@@ -863,7 +856,7 @@ reuse_driver_data(DriverData *dp, HANDLE ifd, HANDLE ofd, int read_write, ErlDrv
ERL_DRV_WRITE|ERL_DRV_USE, 1);
ASSERT(result != -1);
}
- return (ErlDrvData)index;
+ return (ErlDrvData) dp;
}
/*
@@ -1136,12 +1129,6 @@ spawn_init(void)
((module != NULL) ? GetProcAddress(module,"CancelIoEx") : NULL);
DEBUGF(("fpCancelIoEx = %p\r\n", fpCancelIoEx));
#endif
- driver_data = (struct driver_data *)
- erts_alloc(ERTS_ALC_T_DRV_TAB, max_files * sizeof(struct driver_data));
- erts_smp_atomic_add_nob(&sys_misc_mem_sz,
- max_files*sizeof(struct driver_data));
- for (i = 0; i < max_files; i++)
- driver_data[i].port_num = PORT_FREE;
return 0;
}
@@ -1272,9 +1259,12 @@ spawn_start(ErlDrvPort port_num, char* name, SysDriverOpts* opts)
#endif
retval = set_driver_data(dp, hFromChild, hToChild, opts->read_write,
opts->exit_status);
- if (retval != ERL_DRV_ERROR_GENERAL && retval != ERL_DRV_ERROR_ERRNO)
- /* We assume that this cannot generate a negative number */
- erts_port[port_num].os_pid = (SWord) pid;
+ if (retval != ERL_DRV_ERROR_GENERAL && retval != ERL_DRV_ERROR_ERRNO) {
+ Port *prt = erts_drvport2port_raw(port_num);
+ /* We assume that this cannot generate a negative number */
+ ASSERT(prt);
+ prt->os_pid = (SWord) pid;
+ }
}
if (retval != ERL_DRV_ERROR_GENERAL && retval != ERL_DRV_ERROR_ERRNO)
@@ -2263,12 +2253,10 @@ fd_start(ErlDrvPort port_num, char* name, SysDriverOpts* opts)
**/
if (!create_file_thread(&dp->in, DO_READ)) {
- dp->port_num = PORT_FREE;
return ERL_DRV_ERROR_GENERAL;
}
if (!create_file_thread(&dp->out, DO_WRITE)) {
- dp->port_num = PORT_FREE;
return ERL_DRV_ERROR_GENERAL;
}
@@ -2288,10 +2276,9 @@ fd_start(ErlDrvPort port_num, char* name, SysDriverOpts* opts)
}
}
-static void fd_stop(ErlDrvData d)
+static void fd_stop(ErlDrvData data)
{
- int fd = (int)d;
- DriverData* dp = driver_data+fd;
+ DriverData * dp = (DriverData *) data;
/*
* There's no way we can terminate an fd port in a consistent way.
* Instead we let it live until it's opened again (which it is,
@@ -2354,16 +2341,10 @@ vanilla_start(ErlDrvPort port_num, char* name, SysDriverOpts* opts)
}
static void
-stop(ErlDrvData index)
-{
- common_stop((int)index);
-}
-
-static void common_stop(int index)
+stop(ErlDrvData data)
{
- DriverData* dp = driver_data+index;
-
- DEBUGF(("common_stop(%d)\n", index));
+ DriverData *dp = (DriverData *) data;
+ DEBUGF(("stop(%p)\n", dp));
if (dp->in.ov.hEvent != NULL) {
(void) driver_select(dp->port_num,
@@ -2385,7 +2366,6 @@ static void common_stop(int index)
*/
HANDLE thread;
DWORD tid;
- dp->port_num = PORT_EXITING;
thread = (HANDLE *) _beginthreadex(NULL, 0, threaded_exiter, dp, 0, &tid);
CloseHandle(thread);
}
@@ -2510,22 +2490,17 @@ threaded_exiter(LPVOID param)
static void
output(ErlDrvData drv_data, char* buf, ErlDrvSizeT len)
-/* long drv_data; /* The slot to use in the driver data table.
+/* ErlDrvData drv_data; /* The slot to use in the driver data table.
* For Windows NT, this is *NOT* a file handle.
* The handle is found in the driver data.
*/
/* char *buf; /* Pointer to data to write to the port program. */
/* ErlDrvSizeT len; /* Number of bytes to write. */
{
- DriverData* dp;
+ DriverData* dp = (DriverData *) drv_data;
int pb; /* The header size for this port. */
- int port_num; /* The actual port number (for diagnostics). */
char* current;
- dp = driver_data + (int)drv_data;
- if ((port_num = dp->port_num) == -1)
- return ; /*-1;*/
-
pb = dp->packet_bytes;
if ((pb+len) == 0)
@@ -2536,7 +2511,7 @@ output(ErlDrvData drv_data, char* buf, ErlDrvSizeT len)
*/
if ((pb == 2 && len > 65535) || (pb == 1 && len > 255)) {
- driver_failure_posix(port_num, EINVAL);
+ driver_failure_posix(dp->port_num, EINVAL);
return ; /* -1; */
}
@@ -2550,7 +2525,7 @@ output(ErlDrvData drv_data, char* buf, ErlDrvSizeT len)
ASSERT(!dp->outbuf);
dp->outbuf = DRV_BUF_ALLOC(pb+len);
if (!dp->outbuf) {
- driver_failure_posix(port_num, ENOMEM);
+ driver_failure_posix(dp->port_num, ENOMEM);
return ; /* -1; */
}
@@ -2580,7 +2555,7 @@ output(ErlDrvData drv_data, char* buf, ErlDrvSizeT len)
memcpy(current, buf, len);
if (!async_write_file(&dp->out, dp->outbuf, pb+len)) {
- set_busy_port(port_num, 1);
+ set_busy_port(dp->port_num, 1);
} else {
dp->out.ov.Offset += pb+len; /* For vanilla driver. */
/* XXX OffsetHigh should be changed too. */
@@ -2615,10 +2590,9 @@ ready_input(ErlDrvData drv_data, ErlDrvEvent ready_event)
{
int error = 0; /* The error code (assume initially no errors). */
DWORD bytesRead; /* Number of bytes read. */
- DriverData* dp;
+ DriverData* dp = (DriverData *) drv_data;
int pb;
- dp = driver_data+(int)drv_data;
pb = dp->packet_bytes;
#ifdef ERTS_SMP
if(dp->in.thread == (HANDLE) -1) {
@@ -2786,7 +2760,7 @@ static void
ready_output(ErlDrvData drv_data, ErlDrvEvent ready_event)
{
DWORD bytesWritten;
- DriverData* dp = driver_data + (int)drv_data;
+ DriverData *dp = (DriverData *) drv_data;
int error;
#ifdef ERTS_SMP
@@ -2794,7 +2768,7 @@ ready_output(ErlDrvData drv_data, ErlDrvEvent ready_event)
dp->out.async_io_active = 0;
}
#endif
- DEBUGF(("ready_output(%d, 0x%x)\n", drv_data, ready_event));
+ DEBUGF(("ready_output(%p, 0x%x)\n", drv_data, ready_event));
set_busy_port(dp->port_num, 0);
if (!(dp->outbuf)) {
/* Happens because event sometimes get signalled during a successful
@@ -2849,7 +2823,7 @@ sys_init_io(void)
can change our view of the number of open files possible.
We estimate the number to twice the amount of ports.
We really dont know on windows, do we? */
- max_files = 2*erts_max_ports;
+ max_files = 2*erts_ptab_max(&erts_port);
}
#ifdef ERTS_SMP
@@ -3304,9 +3278,6 @@ void erl_sys_init(void)
noinherit_std_handle(STD_INPUT_HANDLE);
noinherit_std_handle(STD_ERROR_HANDLE);
-
- erts_smp_mtx_init(&sys_driver_data_lock, "sys_driver_data_lock");
-
#ifdef ERTS_SMP
erts_smp_tsd_key_create(&win32_errstr_key);
InitializeCriticalSection(&htbc_lock);
diff --git a/erts/emulator/test/alloc_SUITE_data/allocator_test.h b/erts/emulator/test/alloc_SUITE_data/allocator_test.h
index cd4a91d34a..c0396ddb61 100644
--- a/erts/emulator/test/alloc_SUITE_data/allocator_test.h
+++ b/erts/emulator/test/alloc_SUITE_data/allocator_test.h
@@ -60,9 +60,9 @@ typedef void* erts_cond;
#define IS_MMAP_C(C) ((Ulong) ALC_TEST1(0x00a, (C)))
#define C_SZ(C) ((Ulong) ALC_TEST1(0x00b, (C)))
#define SBC2BLK(A, C) ((Block_t *) ALC_TEST2(0x00c, (A), (C)))
-#define BLK2SBC(A, B) ((Carrier_t *) ALC_TEST2(0x00d, (A), (B)))
-#define MBC2FBLK(A, C) ((Block_t *) ALC_TEST2(0x00e, (A), (C)))
-#define FBLK2MBC(A, B) ((Carrier_t *) ALC_TEST2(0x00f, (A), (B)))
+#define BLK_TO_SBC(A, B) ((Carrier_t *) ALC_TEST2(0x00d, (A), (B)))
+#define MBC_TO_FIRST_BLK(A, C) ((Block_t *) ALC_TEST2(0x00e, (A), (C)))
+#define FIRST_BLK_TO_MBC(A, B) ((Carrier_t *) ALC_TEST2(0x00f, (A), (B)))
#define FIRST_MBC(A) ((Carrier_t *) ALC_TEST1(0x010, (A)))
#define LAST_MBC(A) ((Carrier_t *) ALC_TEST1(0x011, (A)))
#define FIRST_SBC(A) ((Carrier_t *) ALC_TEST1(0x012, (A)))
@@ -73,7 +73,7 @@ typedef void* erts_cond;
#define MIN_BLK_SZ(A) ((Ulong) ALC_TEST1(0x017, (A)))
#define NXT_BLK(B) ((Block_t *) ALC_TEST1(0x018, (B)))
#define PREV_BLK(B) ((Block_t *) ALC_TEST1(0x019, (B)))
-#define IS_FIRST_BLK(B) ((Ulong) ALC_TEST1(0x01a, (B)))
+#define IS_MBC_FIRST_BLK(A,B) ((Ulong) ALC_TEST2(0x01a, (A), (B)))
#define UNIT_SZ ((Ulong) ALC_TEST0(0x01b))
/* From erl_goodfit_alloc.c */
diff --git a/erts/emulator/test/alloc_SUITE_data/basic.c b/erts/emulator/test/alloc_SUITE_data/basic.c
index 4a5e888161..0c27665712 100644
--- a/erts/emulator/test/alloc_SUITE_data/basic.c
+++ b/erts/emulator/test/alloc_SUITE_data/basic.c
@@ -44,7 +44,7 @@ testcase_run(TestCaseState_t *tcs)
c = FIRST_MBC(a);
ASSERT(tcs, !NEXT_C(c));
- blk = MBC2FBLK(a, c);
+ blk = MBC_TO_FIRST_BLK(a, c);
ASSERT(tcs, IS_LAST_BLK(blk));
ASSERT(tcs, IS_FREE_BLK(blk));
diff --git a/erts/emulator/test/alloc_SUITE_data/bucket_mask.c b/erts/emulator/test/alloc_SUITE_data/bucket_mask.c
index 13af7d861a..34979cacf1 100644
--- a/erts/emulator/test/alloc_SUITE_data/bucket_mask.c
+++ b/erts/emulator/test/alloc_SUITE_data/bucket_mask.c
@@ -16,11 +16,19 @@
* $Id$
*/
+#include "erl_int_sizes_config.h"
+
#include "testcase_driver.h"
#include "allocator_test.h"
#include <stdio.h>
-#define SBCT (512*1024)
+#if defined(__WIN32__) && SIZEOF_VOID_P == 8
+/* Use larger threashold for win64 as block alignment
+ is 16 bytes and not 8 */
+#define SBCT ((1024*1024))
+#else
+#define SBCT ((512*1024))
+#endif
char *
testcase_name(void)
@@ -40,10 +48,16 @@ testcase_cleanup(TestCaseState_t *tcs)
void
testcase_run(TestCaseState_t *tcs)
{
- void *tmp;
- void **fence;
+ typedef struct linked_block {
+ struct linked_block* next;
+ }Linked;
+ Linked* link;
+ Linked* fence_list;
+ Linked* pad_list;
+ void* tmp;
void **blk;
Ulong sz;
+ Ulong residue;
Ulong smbcs;
int i;
int bi;
@@ -65,7 +79,7 @@ testcase_run(TestCaseState_t *tcs)
ASSERT(tcs, a);
min_blk_sz = MIN_BLK_SZ(a);
- smbcs = 2*(no_bkts*sizeof(void *) + min_blk_sz) + min_blk_sz;
+ smbcs = (no_bkts*sizeof(void *) + min_blk_sz) + min_blk_sz;
for (i = 0; i < no_bkts; i++) {
sz = BKT_MIN_SZ(a, i);
if (sz >= sbct)
@@ -90,26 +104,42 @@ testcase_run(TestCaseState_t *tcs)
tcs->extra = (void *) a;
ASSERT(tcs, a);
+
blk = (void **) ALLOC(a, no_bkts*sizeof(void *));
- fence = (void **) ALLOC(a, no_bkts*sizeof(void *));
- ASSERT(tcs, blk && fence);
+ ASSERT(tcs, blk);
+ fence_list = NULL;
testcase_printf(tcs, "Allocating blocks and fences\n");
for (i = 0; i < bi_tests; i++) {
sz = BKT_MIN_SZ(a, i);
blk[i] = ALLOC(a, sz - ablk_hdr_sz);
- fence[i] = ALLOC(a, 1);
- ASSERT(tcs, blk[i] && fence[i]);
+ link = (Linked*) ALLOC(a, sizeof(Linked));
+ ASSERT(tcs, blk[i] && link);
+ link->next = fence_list;
+ fence_list = link;
}
- tmp = (void *) UMEM2BLK(fence[bi_tests - 1]);
- tmp = (void *) NXT_BLK((Block_t *) tmp);
- ASSERT(tcs, IS_LAST_BLK(tmp));
- sz = BLK_SZ((Block_t *) tmp);
- testcase_printf(tcs, "Allocating leftover size = %lu\n", sz);
- tmp = ALLOC(a, sz - ablk_hdr_sz);
- ASSERT(tcs, tmp);
+ pad_list = 0;
+ do {
+ tmp = (void *) UMEM2BLK(link); /* last allocated */
+ tmp = (void *) NXT_BLK((Block_t *) tmp);
+ ASSERT(tcs, IS_LAST_BLK(tmp));
+ sz = BLK_SZ((Block_t *) tmp);
+ if (sz >= sbct) {
+ residue = sz;
+ sz = sbct - min_blk_sz;
+ residue -= sz;
+ }
+ else {
+ residue = 0;
+ }
+ testcase_printf(tcs, "Allocating leftover size = %lu, residue = %lu\n", sz, residue);
+ link = (Linked*) ALLOC(a, sz - ablk_hdr_sz);
+ ASSERT(tcs, link);
+ link->next = pad_list;
+ pad_list = link;
+ } while (residue);
bi = FIND_BKT(a, 0);
ASSERT(tcs, bi < 0);
@@ -127,16 +157,23 @@ testcase_run(TestCaseState_t *tcs)
for (i = 0; i < bi_tests; i++) {
FREE(a, blk[i]);
- FREE(a, fence[i]);
+ }
+ while (fence_list) {
+ link = fence_list;
+ fence_list = link->next;
+ FREE(a, link);
}
FREE(a, (void *) blk);
- FREE(a, (void *) fence);
bi = FIND_BKT(a, 0);
ASSERT(tcs, bi == no_bkts - 1);
- FREE(a, tmp);
+ while (pad_list) {
+ link = pad_list;
+ pad_list = link->next;
+ FREE(a, link);
+ }
bi = FIND_BKT(a, 0);
ASSERT(tcs, bi < 0);
diff --git a/erts/emulator/test/alloc_SUITE_data/coalesce.c b/erts/emulator/test/alloc_SUITE_data/coalesce.c
index 6f35d3279b..981fa6d43e 100644
--- a/erts/emulator/test/alloc_SUITE_data/coalesce.c
+++ b/erts/emulator/test/alloc_SUITE_data/coalesce.c
@@ -54,7 +54,7 @@ setup_sequence(TestCaseState_t *tcs, Allctr_t *a, Ulong bsz, int no,
no, bsz);
c = FIRST_MBC(a);
ASSERT(tcs, !NEXT_C(c));
- blk = MBC2FBLK(a, c);
+ blk = MBC_TO_FIRST_BLK(a, c);
ASSERT(tcs, IS_LAST_BLK(blk));
for (i = 0; i < no; i++)
@@ -266,7 +266,7 @@ testcase_name(void)
void
testcase_run(TestCaseState_t *tcs)
{
- char *argv_org[] = {"-tmmbcs1024", "-tsbct2048", "-trmbcmt100", "-tas", NULL, NULL};
+ char *argv_org[] = {"-tsmbcs511","-tmmbcs511", "-tsbct512", "-trmbcmt100", "-tas", NULL, NULL};
char *alg[] = {"af", "gf", "bf", "aobf", "aoff", NULL};
int i;
@@ -276,7 +276,7 @@ testcase_run(TestCaseState_t *tcs)
char *argv[sizeof(argv_org)/sizeof(argv_org[0])];
memcpy((void *) argv, (void *) argv_org, sizeof(argv_org));
- argv[4] = alg[i];
+ argv[5] = alg[i];
testcase_printf(tcs, " *** Starting \"%s\" allocator *** \n", alg[i]);
a = START_ALC("coalesce_", 0, argv);
ASSERT(tcs, a);
diff --git a/erts/emulator/test/alloc_SUITE_data/mseg_clear_cache.c b/erts/emulator/test/alloc_SUITE_data/mseg_clear_cache.c
index 0277616bd0..7d5608f890 100644
--- a/erts/emulator/test/alloc_SUITE_data/mseg_clear_cache.c
+++ b/erts/emulator/test/alloc_SUITE_data/mseg_clear_cache.c
@@ -52,10 +52,10 @@ testcase_run(TestCaseState_t *tcs)
tcs->extra = &seg[0];
for (i = 0; i < MAX_SEGS; i++) {
- seg[i].size = 1000;
+ seg[i].size = 1 << 18;
seg[i].ptr = MSEG_ALLOC(&seg[i].size);
ASSERT(tcs, seg[i].ptr);
- ASSERT(tcs, seg[i].size >= 1000);
+ ASSERT(tcs, seg[i].size >= (1 << 18));
}
n = MSEG_NO();
diff --git a/erts/emulator/test/beam_SUITE.erl b/erts/emulator/test/beam_SUITE.erl
index 02c6e19686..3197a4c137 100644
--- a/erts/emulator/test/beam_SUITE.erl
+++ b/erts/emulator/test/beam_SUITE.erl
@@ -54,7 +54,7 @@ end_per_group(_GroupName, Config) ->
%% Verify that apply(M, F, A) is really tail recursive.
apply_last(Config) when is_list(Config) ->
- Pid=spawn(?MODULE, applied, [self(), 10000]),
+ Pid = spawn(?MODULE, applied, [self(), 10000]),
Size =
receive
{Pid, finished} ->
@@ -94,32 +94,32 @@ apply_last_bif(Config) when is_list(Config) ->
%% Test three high register numbers in a put_list instruction
%% (to test whether packing works properly).
packed_registers(Config) when is_list(Config) ->
- ?line PrivDir = ?config(priv_dir, Config),
- ?line Mod = packed_regs,
- ?line Name = filename:join(PrivDir, atom_to_list(Mod) ++ ".erl"),
+ PrivDir = ?config(priv_dir, Config),
+ Mod = packed_regs,
+ Name = filename:join(PrivDir, atom_to_list(Mod) ++ ".erl"),
%% Generate a module which generates a list of tuples.
%% put_list(A) -> [{A, 600}, {A, 999}, ... {A, 0}].
- ?line Code = gen_packed_regs(600, ["-module("++atom_to_list(Mod)++").\n",
+ Code = gen_packed_regs(600, ["-module("++atom_to_list(Mod)++").\n",
"-export([put_list/1]).\n",
"put_list(A) ->\n["]),
- ?line ok = file:write_file(Name, Code),
+ ok = file:write_file(Name, Code),
%% Compile the module.
- ?line io:format("Compiling: ~s\n", [Name]),
- ?line CompRc = compile:file(Name, [{outdir, PrivDir}, report]),
- ?line io:format("Result: ~p\n",[CompRc]),
- ?line {ok, Mod} = CompRc,
+ io:format("Compiling: ~s\n", [Name]),
+ CompRc = compile:file(Name, [{outdir, PrivDir}, report]),
+ io:format("Result: ~p\n",[CompRc]),
+ {ok, Mod} = CompRc,
%% Load it.
- ?line io:format("Loading...\n",[]),
- ?line LoadRc = code:load_abs(filename:join(PrivDir, atom_to_list(Mod))),
- ?line {module,_Module} = LoadRc,
+ io:format("Loading...\n",[]),
+ LoadRc = code:load_abs(filename:join(PrivDir, atom_to_list(Mod))),
+ {module,_Module} = LoadRc,
%% Call it and verify result.
- ?line Term = {a, b},
- ?line L = Mod:put_list(Term),
- ?line verify_packed_regs(L, Term, 600),
+ Term = {a, b},
+ L = Mod:put_list(Term),
+ verify_packed_regs(L, Term, 600),
ok.
gen_packed_regs(0, Acc) ->
@@ -131,11 +131,11 @@ verify_packed_regs([], _, -1) -> ok;
verify_packed_regs([{Term, N}| T], Term, N) ->
verify_packed_regs(T, Term, N-1);
verify_packed_regs(L, Term, N) ->
- ?line ok = io:format("Expected [{~p, ~p}|T]; got\n~p\n", [Term, N, L]),
- ?line test_server:fail().
+ ok = io:format("Expected [{~p, ~p}|T]; got\n~p\n", [Term, N, L]),
+ test_server:fail().
buildo_mucho(Config) when is_list(Config) ->
- ?line buildo_mucho_1(),
+ buildo_mucho_1(),
ok.
buildo_mucho_1() ->
@@ -206,20 +206,27 @@ buildo_mucho_1() ->
{<<>>,1},{<<>>,1},{<<>>,1},{<<>>,1},{<<>>,1},{<<>>,1},{<<>>,1},{<<>>,1}].
heap_sizes(Config) when is_list(Config) ->
- ?line Sizes = erlang:system_info(heap_sizes),
- ?line io:format("~p heap sizes\n", [length(Sizes)]),
- ?line io:format("~p\n", [Sizes]),
+ Sizes = erlang:system_info(heap_sizes),
+ io:format("~p heap sizes\n", [length(Sizes)]),
+ io:format("~p\n", [Sizes]),
%% Verify that heap sizes increase monotonically.
- ?line Largest = lists:foldl(fun(E, P) when is_integer(P), E > P -> E;
+ Largest = lists:foldl(fun(E, P) when is_integer(P), E > P -> E;
(E, []) -> E
end, [], Sizes),
- %% Verify that the largest heap size consists of 31 or 63 bits.
- ?line
- case Largest bsr (erlang:system_info(wordsize)*8-2) of
- R when R > 0 -> ok
- end,
+ %% Verify that the largest heap size consists of
+ %% - 31 bits of bytes on 32 bits arch
+ %% - atleast 52 bits of bytes (48 is the maximum virtual address)
+ %% and at the most 63 bits on 64 bit archs
+ %% heap sizes are in words
+ case erlang:system_info(wordsize) of
+ 8 ->
+ 0 = (Largest*8) bsr 63,
+ true = (Largest*8) > (1 bsl 52);
+ 4 ->
+ 1 = (Largest*4) bsr 31
+ end,
ok.
%% Thanks to Igor Goryachev.
@@ -302,10 +309,10 @@ b() ->
end.
fconv(Config) when is_list(Config) ->
- ?line do_fconv(atom),
- ?line do_fconv(nil),
- ?line do_fconv(tuple_literal),
- ?line 3.0 = do_fconv(1.0, 2.0),
+ do_fconv(atom),
+ do_fconv(nil),
+ do_fconv(tuple_literal),
+ 3.0 = do_fconv(1.0, 2.0),
ok.
do_fconv(Type) ->
@@ -325,9 +332,9 @@ do_fconv(tuple_literal, Float) when is_float(Float) ->
Float + {a,b}.
select_val(Config) when is_list(Config) ->
- ?line zero = do_select_val(0),
- ?line big = do_select_val(1 bsl 64),
- ?line integer = do_select_val(42),
+ zero = do_select_val(0),
+ big = do_select_val(1 bsl 64),
+ integer = do_select_val(42),
ok.
do_select_val(X) ->
diff --git a/erts/emulator/test/binary_SUITE.erl b/erts/emulator/test/binary_SUITE.erl
index 58e0cb4096..babdb3363f 100644
--- a/erts/emulator/test/binary_SUITE.erl
+++ b/erts/emulator/test/binary_SUITE.erl
@@ -626,8 +626,32 @@ safe_binary_to_term2(Config) when is_list(Config) ->
bad_terms(suite) -> [];
bad_terms(Config) when is_list(Config) ->
?line test_terms(fun corrupter/1).
-
+
+corrupter(Term) when is_function(Term);
+ is_function(hd(Term));
+ is_function(element(2,element(2,element(2,Term)))) ->
+ %% Check if lists is native compiled. If it is, we do not try to
+ %% corrupt funs as this can create some very strange behaviour.
+ %% To show the error print `Byte` in the foreach fun in corrupter/2.
+ case erlang:system_info(hipe_architecture) of
+ undefined ->
+ corrupter0(Term);
+ Architecture ->
+ {lists, ListsBinary, _ListsFilename} = code:get_object_code(lists),
+ ChunkName = hipe_unified_loader:chunk_name(Architecture),
+ NativeChunk = beam_lib:chunks(ListsBinary, [ChunkName]),
+ case NativeChunk of
+ {ok,{_,[{_,Bin}]}} when is_binary(Bin) ->
+ S = io_lib:format("Skipping corruption of: ~P", [Term,12]),
+ io:put_chars(S);
+ {error, beam_lib, _} ->
+ corrupter0(Term)
+ end
+ end;
corrupter(Term) ->
+ corrupter0(Term).
+
+corrupter0(Term) ->
?line try
S = io_lib:format("About to corrupt: ~P", [Term,12]),
io:put_chars(S)
diff --git a/erts/emulator/test/bs_bit_binaries_SUITE.erl b/erts/emulator/test/bs_bit_binaries_SUITE.erl
index ff1088118d..7f2cd1e881 100644
--- a/erts/emulator/test/bs_bit_binaries_SUITE.erl
+++ b/erts/emulator/test/bs_bit_binaries_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -177,14 +177,55 @@ append(Config) when is_list(Config) ->
cs_init(),
?line <<(-1):256/signed-unit:8>> = cs(do_append(id(<<>>), 256*8)),
?line <<(-1):256/signed-unit:8>> = cs(do_append2(id(<<>>), 256*4)),
+ <<(-1):256/signed-unit:8>> = cs(do_append3(id(<<>>), 256*8)),
cs_end().
do_append(Bin, N) when N > 0 -> do_append(<<Bin/bits,1:1>>, N-1);
do_append(Bin, 0) -> Bin.
-do_append2(Bin, N) when N > 0 -> do_append2(<<Bin/bits,3:2>>, N-1);
+do_append2(Bin, N) when N > 0 -> do_append2(<<Bin/binary-unit:2,3:2>>, N-1);
do_append2(Bin, 0) -> Bin.
+do_append3(Bin, N) when N > 0 ->
+ Bits = bit_size(Bin),
+ if
+ Bits rem 2 =:= 0 ->
+ do_append3(<<Bin/binary-unit:2,1:1>>, N-1);
+ Bits rem 3 =:= 0 ->
+ do_append3(<<Bin/binary-unit:3,1:1>>, N-1);
+ Bits rem 4 =:= 0 ->
+ do_append3(<<Bin/binary-unit:4,1:1>>, N-1);
+ Bits rem 5 =:= 0 ->
+ do_append3(<<Bin/binary-unit:5,1:1>>, N-1);
+ Bits rem 6 =:= 0 ->
+ do_append3(<<Bin/binary-unit:6,1:1>>, N-1);
+ Bits rem 7 =:= 0 ->
+ do_append3(<<Bin/binary-unit:7,1:1>>, N-1);
+ Bits rem 8 =:= 0 ->
+ do_append3(<<Bin/binary-unit:8,1:1>>, N-1);
+ Bits rem 9 =:= 0 ->
+ do_append3(<<Bin/binary-unit:9,1:1>>, N-1);
+ Bits rem 10 =:= 0 ->
+ do_append3(<<Bin/binary-unit:10,1:1>>, N-1);
+ Bits rem 11 =:= 0 ->
+ do_append3(<<Bin/binary-unit:11,1:1>>, N-1);
+ Bits rem 12 =:= 0 ->
+ do_append3(<<Bin/binary-unit:12,1:1>>, N-1);
+ Bits rem 13 =:= 0 ->
+ do_append3(<<Bin/binary-unit:13,1:1>>, N-1);
+ Bits rem 14 =:= 0 ->
+ do_append3(<<Bin/binary-unit:14,1:1>>, N-1);
+ Bits rem 15 =:= 0 ->
+ do_append3(<<Bin/binary-unit:15,1:1>>, N-1);
+ Bits rem 16 =:= 0 ->
+ do_append3(<<Bin/binary-unit:16,1:1>>, N-1);
+ Bits rem 17 =:= 0 ->
+ do_append3(<<Bin/binary-unit:17,1:1>>, N-1);
+ true ->
+ do_append3(<<Bin/binary-unit:1,1:1>>, N-1)
+ end;
+do_append3(Bin, 0) -> Bin.
+
cs_init() ->
erts_debug:set_internal_state(available_internal_state, true),
ok.
diff --git a/erts/emulator/test/bs_construct_SUITE.erl b/erts/emulator/test/bs_construct_SUITE.erl
index 8b5c82d968..123952d01d 100644
--- a/erts/emulator/test/bs_construct_SUITE.erl
+++ b/erts/emulator/test/bs_construct_SUITE.erl
@@ -28,7 +28,7 @@
mem_leak/1, coerce_to_float/1, bjorn/1,
huge_float_field/1, huge_binary/1, system_limit/1, badarg/1,
copy_writable_binary/1, kostis/1, dynamic/1, bs_add/1,
- otp_7422/1, zero_width/1]).
+ otp_7422/1, zero_width/1, bad_append/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -38,7 +38,8 @@ all() ->
[test1, test2, test3, test4, test5, testf, not_used,
in_guard, mem_leak, coerce_to_float, bjorn,
huge_float_field, huge_binary, system_limit, badarg,
- copy_writable_binary, kostis, dynamic, bs_add, otp_7422, zero_width].
+ copy_writable_binary, kostis, dynamic, bs_add, otp_7422, zero_width,
+ bad_append].
groups() ->
[].
@@ -546,11 +547,47 @@ huge_float_check({'EXIT',{badarg,_}}) -> ok.
huge_binary(Config) when is_list(Config) ->
?line 16777216 = size(<<0:(id(1 bsl 26)),(-1):(id(1 bsl 26))>>),
?line garbage_collect(),
- ?line id(<<0:((1 bsl 32)-1)>>),
+ {Shift,Return} = case free_mem() of
+ undefined -> {32,ok};
+ Mb when Mb > 600 -> {32,ok};
+ Mb when Mb > 300 -> {31,"Limit huge binaries to 256 Mb"};
+ _ -> {30,"Limit huge binary to 128 Mb"}
+ end,
?line garbage_collect(),
- ?line id(<<0:(id((1 bsl 32)-1))>>),
+ ?line id(<<0:((1 bsl Shift)-1)>>),
?line garbage_collect(),
- ok.
+ ?line id(<<0:(id((1 bsl Shift)-1))>>),
+ ?line garbage_collect(),
+ case Return of
+ ok -> ok;
+ Comment -> {comment, Comment}
+ end.
+
+free_mem() ->
+ Cmd = "uname; free",
+ Output = string:tokens(os:cmd(Cmd), "\n"),
+ io:format("Output from command ~p\n~p\n",[Cmd,Output]),
+ case Output of
+ [OS, ColumnNames, Values | _] ->
+ case string:str(OS,"Linux") of
+ 0 ->
+ io:format("Unknown OS\n",[]),
+ undefined;
+ _ ->
+ case {string:tokens(ColumnNames, " \t"),
+ string:tokens(Values, " \t")} of
+ {[_,_,"free"|_],["Mem:",_,_,FreeKb|_]} ->
+ list_to_integer(FreeKb) div 1024;
+ _ ->
+ io:format("Failed to parse output from 'free':\n",[]),
+ undefined
+ end
+ end;
+ _ ->
+ io:format("Too few lines in output\n",[]),
+ undefined
+ end.
+
system_limit(Config) when is_list(Config) ->
WordSize = erlang:system_info(wordsize),
@@ -827,5 +864,49 @@ zero_width(Config) when is_list(Config) ->
?line {'EXIT',{badarg,_}} = (catch <<(id(not_a_number)):0>>),
ok.
+
+bad_append(_) ->
+ do_bad_append(<<127:1>>, fun append_unit_3/1),
+ do_bad_append(<<127:2>>, fun append_unit_3/1),
+ do_bad_append(<<127:17>>, fun append_unit_3/1),
+
+ do_bad_append(<<127:3>>, fun append_unit_4/1),
+ do_bad_append(<<127:5>>, fun append_unit_4/1),
+ do_bad_append(<<127:7>>, fun append_unit_4/1),
+ do_bad_append(<<127:199>>, fun append_unit_4/1),
+
+ do_bad_append(<<127:7>>, fun append_unit_8/1),
+ do_bad_append(<<127:9>>, fun append_unit_8/1),
+
+ do_bad_append(<<0:8>>, fun append_unit_16/1),
+ do_bad_append(<<0:15>>, fun append_unit_16/1),
+ do_bad_append(<<0:17>>, fun append_unit_16/1),
+ ok.
+
+do_bad_append(Bin0, Appender) ->
+ {'EXIT',{badarg,_}} = (catch Appender(Bin0)),
+
+ Bin1 = id(<<0:3,Bin0/bitstring>>),
+ <<_:3,Bin2/bitstring>> = Bin1,
+ {'EXIT',{badarg,_}} = (catch Appender(Bin2)),
+
+ %% Create a writable binary.
+ Empty = id(<<>>),
+ Bin3 = <<Empty/bitstring,Bin0/bitstring>>,
+ {'EXIT',{badarg,_}} = (catch Appender(Bin3)),
+ ok.
+
+append_unit_3(Bin) ->
+ <<Bin/binary-unit:3,0:1>>.
+
+append_unit_4(Bin) ->
+ <<Bin/binary-unit:4,0:1>>.
+
+append_unit_8(Bin) ->
+ <<Bin/binary,0:1>>.
+
+append_unit_16(Bin) ->
+ <<Bin/binary-unit:16,0:1>>.
+
id(I) -> I.
diff --git a/erts/emulator/test/busy_port_SUITE.erl b/erts/emulator/test/busy_port_SUITE.erl
index 3a29fd4d68..32e907ca69 100644
--- a/erts/emulator/test/busy_port_SUITE.erl
+++ b/erts/emulator/test/busy_port_SUITE.erl
@@ -148,9 +148,9 @@ message_order(Config) when is_list(Config) ->
send_to_busy_1(Parent) ->
{Owner, Slave} = get_slave(),
- Slave ! {Owner, {command, "set_me_busy"}},
- Slave ! {Owner, {command, "hello"}},
- Slave ! {Owner, {command, "hello again"}},
+ (catch port_command(Slave, "set_me_busy")),
+ (catch port_command(Slave, "hello")),
+ (catch port_command(Slave, "hello again")),
receive
Message ->
Parent ! {self(), Message}
@@ -193,10 +193,10 @@ system_monitor(Config) when is_list(Config) ->
?line Busy =
spawn_link(
fun() ->
- Slave ! {Owner,{command,"set busy"}},
+ (catch port_command(Slave, "set busy")),
receive {Parent,alpha} -> ok end,
- Slave ! {Owner,{command,"busy"}},
- Slave ! {Owner,{command,"free"}},
+ (catch port_command(Slave, "busy")),
+ (catch port_command(Slave, "free")),
Parent ! {self(),alpha},
command(lock),
receive {Parent,beta} -> ok end,
@@ -212,7 +212,7 @@ system_monitor(Config) when is_list(Config) ->
?line Void = rec(Void),
?line Busy ! {self(), beta},
?line {monitor,Owner,busy_port,Slave} = rec(Void),
- ?line Master ! {Owner, {command, "u"}},
+ ?line port_command(Master, "u"),
?line {Busy,beta} = rec(Void),
?line Void = rec(Void),
?line _NewMonitor = erlang:system_monitor(OldMonitor),
@@ -296,9 +296,9 @@ no_trap_exit_process(ResultTo, Link, Config) ->
linked -> ok;
unlink -> unlink(Slave)
end,
- ?line Slave ! {self(), {command, "lock port"}},
+ ?line (catch port_command(Slave, "lock port")),
?line ResultTo ! {self(), port_created, Slave},
- ?line Slave ! {self(), {command, "suspend me"}},
+ ?line (catch port_command(Slave, "suspend me")),
ok.
%% Assuming the following scenario,
@@ -339,9 +339,9 @@ busy_port_exit_process(ResultTo, Config) ->
?line load_busy_driver(Config),
?line _Master = open_port({spawn, "busy_drv master"}, [eof]),
?line Slave = open_port({spawn, "busy_drv slave"}, [eof]),
- ?line Slave ! {self(), {command, "lock port"}},
+ ?line (catch port_command(Slave, "lock port")),
?line ResultTo ! {self(), port_created, Slave},
- ?line Slave ! {self(), {command, "suspend me"}},
+ ?line (catch port_command(Slave, "suspend me")),
receive
{'EXIT', Slave, die} ->
ResultTo ! {self(), ok};
@@ -383,8 +383,8 @@ multiple_writers(Config) when is_list(Config) ->
quick_writer() ->
{Owner, Port} = get_slave(),
- Port ! {Owner, {command, "port to busy"}},
- Port ! {Owner, {command, "lock me"}},
+ (catch port_command(Port, "port to busy")),
+ (catch port_command(Port, "lock me")),
ok.
hard_busy_driver(Config) when is_list(Config) ->
@@ -644,11 +644,11 @@ loop(Master, Slave) ->
Pid ! {busy_drv_reply, {self(), Slave}},
loop(Master, Slave);
{Pid, unlock} ->
- Master ! {self(), {command, "u"}},
+ port_command(Master, "u"),
Pid ! {busy_drv_reply, ok},
loop(Master, Slave);
{Pid, lock} ->
- Master ! {self(), {command, "l"}},
+ port_command(Master, "l"),
Pid ! {busy_drv_reply, ok},
loop(Master, Slave);
{Pid, {port_command,Data}} ->
diff --git a/erts/emulator/test/ddll_SUITE.erl b/erts/emulator/test/ddll_SUITE.erl
index 6e15c228cd..4675cab15c 100644
--- a/erts/emulator/test/ddll_SUITE.erl
+++ b/erts/emulator/test/ddll_SUITE.erl
@@ -136,8 +136,8 @@ delayed_unload_with_ports(Config) when is_list(Config) ->
?line {ok,pending_driver,Ref} = erl_ddll:try_unload(echo_drv,[{monitor, pending_driver}]),
?line ok = receive _ -> false after 0 -> ok end,
?line Port ! {self(), close},
- ?line 1 = erl_ddll:info(echo_drv, port_count),
?line ok = receive {Port,closed} -> ok after 1000 -> false end,
+ ?line 1 = erl_ddll:info(echo_drv, port_count),
?line Port2 ! {self(), close},
?line ok = receive {Port2,closed} -> ok after 1000 -> false end,
?line ok = receive {'DOWN', Ref, driver, echo_drv, unloaded} -> ok after 1000 -> false end,
diff --git a/erts/emulator/test/driver_SUITE.erl b/erts/emulator/test/driver_SUITE.erl
index 643357263c..13f18b4563 100644
--- a/erts/emulator/test/driver_SUITE.erl
+++ b/erts/emulator/test/driver_SUITE.erl
@@ -77,7 +77,8 @@
thread_mseg_alloc_cache_clean/1,
otp_9302/1,
thr_free_drv/1,
- async_blast/1]).
+ async_blast/1,
+ thr_msg_blast/1]).
-export([bin_prefix/2]).
@@ -147,7 +148,8 @@ all() ->
thread_mseg_alloc_cache_clean,
otp_9302,
thr_free_drv,
- async_blast].
+ async_blast,
+ thr_msg_blast].
groups() ->
[{timer, [],
@@ -1136,7 +1138,9 @@ check_driver_system_info_result(Result) ->
{{1, 1}, _} ->
?line ExpNs = lists:sort(?EXPECTED_SYSTEM_INFO_NAMES
-- ?EXPECTED_SYSTEM_INFO_NAMES2),
- ?line ExpNs = lists:sort(Ns)
+ ?line ExpNs = lists:sort(Ns);
+ {{2, 0}, _} ->
+ ?line [] = Ns
end.
chk_sis(SIs, Ns) ->
@@ -2010,7 +2014,64 @@ async_blast(Config) when is_list(Config) ->
?line erlang:display({async_blast_time, AsyncBlastTime}),
?line ok.
+thr_msg_blast_receiver(_Port, N, N) ->
+ ok;
+thr_msg_blast_receiver(Port, N, Max) ->
+ receive
+ {Port, hi} ->
+ thr_msg_blast_receiver(Port, N+1, Max)
+ end.
+
+thr_msg_blast_receiver_proc(Port, Max, Parent, Done) ->
+ case port_control(Port, 0, "") of
+ "receiver" ->
+ spawn(fun () ->
+ thr_msg_blast_receiver_proc(Port, Max+1, Parent, Done)
+ end),
+ thr_msg_blast_receiver(Port, 0, Max);
+ "done" ->
+ Parent ! Done
+ end.
+thr_msg_blast(Config) when is_list(Config) ->
+ case erlang:system_info(smp_support) of
+ false ->
+ {skipped, "Non-SMP emulator; nothing to test..."};
+ true ->
+ Path = ?config(data_dir, Config),
+ erl_ddll:start(),
+ ok = load_driver(Path, thr_msg_blast_drv),
+ MemBefore = driver_alloc_size(),
+ Start = os:timestamp(),
+ Port = open_port({spawn, thr_msg_blast_drv}, []),
+ true = is_port(Port),
+ Done = make_ref(),
+ Me = self(),
+ spawn(fun () ->
+ thr_msg_blast_receiver_proc(Port, 1, Me, Done)
+ end),
+ receive
+ Done -> ok
+ end,
+ ok = thr_msg_blast_receiver(Port, 0, 32*10000),
+ port_close(Port),
+ End = os:timestamp(),
+ receive
+ Garbage ->
+ ?t:fail({received_garbage, Port, Garbage})
+ after 2000 ->
+ ok
+ end,
+ MemAfter = driver_alloc_size(),
+ io:format("MemBefore=~p, MemAfter=~p~n",
+ [MemBefore, MemAfter]),
+ ThrMsgBlastTime = timer:now_diff(End,Start)/1000000,
+ io:format("ThrMsgBlastTime=~p~n", [ThrMsgBlastTime]),
+ MemBefore = MemAfter,
+ Res = {thr_msg_blast_time, ThrMsgBlastTime},
+ erlang:display(Res),
+ Res
+ end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Utilities
diff --git a/erts/emulator/test/driver_SUITE_data/Makefile.src b/erts/emulator/test/driver_SUITE_data/Makefile.src
index 9cc107cc66..b667dff6b6 100644
--- a/erts/emulator/test/driver_SUITE_data/Makefile.src
+++ b/erts/emulator/test/driver_SUITE_data/Makefile.src
@@ -14,7 +14,8 @@ MISC_DRVS = outputv_drv@dll@ \
thr_alloc_drv@dll@ \
otp_9302_drv@dll@ \
thr_free_drv@dll@ \
- async_blast_drv@dll@
+ async_blast_drv@dll@ \
+ thr_msg_blast_drv@dll@
SYS_INFO_DRVS = sys_info_base_drv@dll@ \
sys_info_prev_drv@dll@ \
diff --git a/erts/emulator/test/driver_SUITE_data/thr_msg_blast_drv.c b/erts/emulator/test/driver_SUITE_data/thr_msg_blast_drv.c
new file mode 100644
index 0000000000..1070678d7b
--- /dev/null
+++ b/erts/emulator/test/driver_SUITE_data/thr_msg_blast_drv.c
@@ -0,0 +1,178 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2012. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "erl_driver.h"
+
+#define THR_MSG_BLAST_NO_PROCS 10
+#define THR_MSG_BLAST_NO_SENDS_PER_PROC 10000
+
+#define THR_MSG_BLAST_THREADS 32
+
+static void stop(ErlDrvData drv_data);
+static ErlDrvData start(ErlDrvPort port,
+ char *command);
+static ErlDrvSSizeT control(ErlDrvData drv_data,
+ unsigned int command,
+ char *buf, ErlDrvSizeT len,
+ char **rbuf, ErlDrvSizeT rlen);
+
+static ErlDrvEntry thr_msg_blast_drv_entry = {
+ NULL /* init */,
+ start,
+ stop,
+ NULL /* output */,
+ NULL /* ready_input */,
+ NULL /* ready_output */,
+ "thr_msg_blast_drv",
+ NULL /* finish */,
+ NULL /* handle */,
+ control,
+ NULL /* timeout */,
+ NULL /* outputv */,
+ NULL /* ready_async */,
+ NULL /* flush */,
+ NULL /* call */,
+ NULL /* event */,
+ ERL_DRV_EXTENDED_MARKER,
+ ERL_DRV_EXTENDED_MAJOR_VERSION,
+ ERL_DRV_EXTENDED_MINOR_VERSION,
+ ERL_DRV_FLAG_USE_PORT_LOCKING,
+ NULL /* handle2 */,
+ NULL /* handle_monitor */
+};
+
+typedef struct {
+ ErlDrvPort port;
+ ErlDrvTermData td_port;
+ ErlDrvTermData hi;
+ ErlDrvTid tid[THR_MSG_BLAST_THREADS];
+ int no_thrs;
+ ErlDrvTermData proc[THR_MSG_BLAST_NO_PROCS];
+ int no_procs;
+} thr_msg_blast_data_t;
+
+
+DRIVER_INIT(thr_msg_blast_drv)
+{
+ return &thr_msg_blast_drv_entry;
+}
+
+static void stop(ErlDrvData drv_data)
+{
+ int i;
+ thr_msg_blast_data_t *tmbd = (thr_msg_blast_data_t *) drv_data;
+ for (i = 0; i < tmbd->no_thrs; i++)
+ erl_drv_thread_join(tmbd->tid[i], NULL);
+ driver_free((void *) tmbd);
+}
+
+static ErlDrvData start(ErlDrvPort port,
+ char *command)
+{
+ thr_msg_blast_data_t *tmbd;
+
+ tmbd = driver_alloc(sizeof(thr_msg_blast_data_t));
+ if (!tmbd)
+ return ERL_DRV_ERROR_GENERAL;
+
+ tmbd->port = port;
+ tmbd->td_port = driver_mk_port(port);
+ tmbd->hi = driver_mk_atom("hi");
+ tmbd->no_thrs = 0;
+ tmbd->no_procs = 1;
+ tmbd->proc[0] = driver_caller(port);
+
+ return (ErlDrvData) tmbd;
+}
+
+static void *thread(void *);
+
+static ErlDrvSSizeT control(ErlDrvData drv_data,
+ unsigned int command,
+ char *buf, ErlDrvSizeT len,
+ char **rbuf, ErlDrvSizeT rlen)
+{
+ thr_msg_blast_data_t *tmbd = (thr_msg_blast_data_t *) drv_data;
+ char *res_str = "error";
+
+ if (tmbd->no_procs >= THR_MSG_BLAST_NO_PROCS) {
+ int i;
+ for (i = 0; i < tmbd->no_thrs; i++)
+ erl_drv_thread_join(tmbd->tid[i], NULL);
+ tmbd->no_thrs = 0;
+ res_str = "done";
+ }
+ else {
+
+ tmbd->proc[tmbd->no_procs++] = driver_caller(tmbd->port);
+
+ if (tmbd->no_procs == THR_MSG_BLAST_NO_PROCS) {
+ for (tmbd->no_thrs = 0;
+ tmbd->no_thrs < THR_MSG_BLAST_THREADS;
+ tmbd->no_thrs++) {
+ int res = erl_drv_thread_create("test",
+ &tmbd->tid[tmbd->no_thrs],
+ thread,
+ tmbd,
+ NULL);
+ if (res != 0) {
+ driver_failure_posix(tmbd->port, res);
+ goto done;
+ }
+ }
+ }
+
+ res_str = "receiver";
+ }
+
+ done: {
+ ErlDrvSSizeT res_len = strlen(res_str);
+ if (res_len > rlen) {
+ char *abuf = driver_alloc(sizeof(char)*res_len);
+ if (!abuf)
+ return 0;
+ *rbuf = abuf;
+ }
+
+ memcpy((void *) *rbuf, (void *) res_str, res_len);
+
+ return res_len;
+ }
+}
+
+static void *thread(void *varg)
+{
+ int s, p;
+ thr_msg_blast_data_t *tmbd = (thr_msg_blast_data_t *) varg;
+ ErlDrvTermData spec[] = {
+ ERL_DRV_PORT, tmbd->td_port,
+ ERL_DRV_ATOM, tmbd->hi,
+ ERL_DRV_TUPLE, 2
+ };
+
+ for (s = 0; s < THR_MSG_BLAST_NO_SENDS_PER_PROC; s++) {
+ for (p = 0; p < THR_MSG_BLAST_NO_PROCS; p++) {
+ int res = driver_send_term(tmbd->port, tmbd->proc[p],
+ spec, sizeof(spec)/sizeof(spec[0]));
+ if (p == 0 && res <= 0)
+ abort(); /* Could not send to creator */
+ }
+ }
+ return NULL;
+}
diff --git a/erts/emulator/test/fun_SUITE.erl b/erts/emulator/test/fun_SUITE.erl
index ef06845cf2..36ba4e0f48 100644
--- a/erts/emulator/test/fun_SUITE.erl
+++ b/erts/emulator/test/fun_SUITE.erl
@@ -726,8 +726,8 @@ t_arity(Config) when is_list(Config) ->
ok.
t_is_function2(Config) when is_list(Config) ->
- ?line true = is_function({a,b}, 0),
- ?line true = is_function({a,b}, 234343434333433433),
+ false = is_function(id({a,b}), 0),
+ false = is_function(id({a,b}), 234343434333433433),
?line true = is_function(fun() -> ok end, 0),
?line true = is_function(fun(_) -> ok end, 1),
?line false = is_function(fun(_) -> ok end, 0),
diff --git a/erts/emulator/test/match_spec_SUITE.erl b/erts/emulator/test/match_spec_SUITE.erl
index 461773114e..d5cb4ee1b7 100644
--- a/erts/emulator/test/match_spec_SUITE.erl
+++ b/erts/emulator/test/match_spec_SUITE.erl
@@ -28,7 +28,7 @@
unary_plus/1, unary_minus/1, moving_labels/1]).
-export([fpe/1]).
-export([otp_9422/1]).
-
+-export([faulty_seq_trace/1, do_faulty_seq_trace/0]).
-export([runner/2, loop_runner/3]).
-export([f1/1, f2/2, f3/2, fn/1, fn/2, fn/3]).
-export([do_boxed_and_small/0]).
@@ -59,6 +59,7 @@ all() ->
ms_trace3, boxed_and_small, destructive_in_test_bif,
guard_exceptions, unary_plus, unary_minus, fpe,
moving_labels,
+ faulty_seq_trace,
otp_9422];
true -> [not_run]
end.
@@ -726,6 +727,19 @@ do_boxed_and_small() ->
{ok, false, _, _} = erlang:match_spec_test({0,3},[{{make_ref(),'_'},[],['$_']}],table),
ok.
+faulty_seq_trace(doc) ->
+ ["Test that faulty seq_trace_call does not crash emulator"];
+faulty_seq_trace(suite) -> [];
+faulty_seq_trace(Config) when is_list(Config) ->
+ ?line {ok, Node} = start_node(match_spec_suite_other),
+ ?line ok = rpc:call(Node,?MODULE,do_faulty_seq_trace,[]),
+ ?line stop_node(Node),
+ ok.
+
+do_faulty_seq_trace() ->
+ {ok,'EXIT',_,_} = erlang:match_spec_test([],[{'_',[],[{message,{set_seq_token,yxa,true}}]}],trace),
+ ok.
+
errchk(Pat) ->
case catch erlang:trace_pattern({?MODULE, f2, 2}, Pat) of
{'EXIT', {badarg, _}} ->
diff --git a/erts/emulator/test/port_SUITE.erl b/erts/emulator/test/port_SUITE.erl
index 873601ddd1..13aa0f4c00 100644
--- a/erts/emulator/test/port_SUITE.erl
+++ b/erts/emulator/test/port_SUITE.erl
@@ -90,7 +90,7 @@
mix_up_ports/1, otp_5112/1, otp_5119/1, otp_6224/1,
exit_status_multi_scheduling_block/1, ports/1,
spawn_driver/1, spawn_executable/1, close_deaf_port/1,
- unregister_name/1]).
+ unregister_name/1, parallelism_option/1]).
-export([]).
@@ -114,7 +114,8 @@ all() ->
stderr_to_stdout, otp_3906, otp_4389, win_massive,
mix_up_ports, otp_5112, otp_5119,
exit_status_multi_scheduling_block, ports, spawn_driver,
- spawn_executable, close_deaf_port, unregister_name].
+ spawn_executable, close_deaf_port, unregister_name,
+ parallelism_option].
groups() ->
[{stream, [], [stream_small, stream_big]},
@@ -159,11 +160,11 @@ win_massive(Config) when is_list(Config) ->
do_win_massive() ->
Dog = test_server:timetrap(test_server:seconds(360)),
SuiteDir = filename:dirname(code:which(?MODULE)),
- Env = " -env ERL_MAX_PORTS 8192",
+ Ports = " +Q 8192",
{ok, Node} =
test_server:start_node(win_massive,
slave,
- [{args, " -pa " ++ SuiteDir ++ Env}]),
+ [{args, " -pa " ++ SuiteDir ++ Ports}]),
ok = rpc:call(Node,?MODULE,win_massive_client,[3000]),
test_server:stop_node(Node),
test_server:timetrap_cancel(Dog),
@@ -1298,6 +1299,43 @@ spawn_driver(Config) when is_list(Config) ->
test_server:timetrap_cancel(Dog),
ok.
+parallelism_option(suite) ->
+ [];
+parallelism_option(doc) ->
+ ["Test parallelism option of open_port"];
+parallelism_option(Config) when is_list(Config) ->
+ ?line Dog = test_server:timetrap(test_server:seconds(10)),
+ ?line Path = ?config(data_dir, Config),
+ ?line ok = load_driver(Path, "echo_drv"),
+ ?line Port = erlang:open_port({spawn_driver, "echo_drv"},
+ [{parallelism, true}]),
+ ?line {parallelism, true} = erlang:port_info(Port, parallelism),
+ ?line Port ! {self(), {command, "Hello port!"}},
+ ?line receive
+ {Port, {data, "Hello port!"}} = Msg1 ->
+ io:format("~p~n", [Msg1]),
+ ok;
+ Other ->
+ test_server:fail({unexpected, Other})
+ end,
+ ?line Port ! {self(), close},
+ ?line receive {Port, closed} -> ok end,
+
+ ?line Port2 = erlang:open_port({spawn_driver, "echo_drv -Hello port?"},
+ [{parallelism, false}]),
+ ?line {parallelism, false} = erlang:port_info(Port2, parallelism),
+ ?line receive
+ {Port2, {data, "Hello port?"}} = Msg2 ->
+ io:format("~p~n", [Msg2]),
+ ok;
+ Other2 ->
+ test_server:fail({unexpected2, Other2})
+ end,
+ ?line Port2 ! {self(), close},
+ ?line receive {Port2, closed} -> ok end,
+ ?line test_server:timetrap_cancel(Dog),
+ ok.
+
spawn_executable(suite) ->
[];
spawn_executable(doc) ->
@@ -1566,6 +1604,7 @@ otp_5112(Config) when is_list(Config) ->
?t:format("Links1: ~p~n",[Links1]),
true = lists:member(Port, Links1),
Port ! {self(), {command, ""}},
+ ?line wait_until(fun () -> lists:member(Port, erlang:ports()) == false end),
{links, Links2} = process_info(self(),links),
?t:format("Links2: ~p~n",[Links2]),
false = lists:member(Port, Links2), %% This used to fail
@@ -1636,38 +1675,8 @@ otp_5119_fill_empty_port_tab(Ports) ->
LastPort
end.
--define(DEF_MAX_PORTS, 1024).
-
-max_ports_env() ->
- case os:getenv("ERL_MAX_PORTS") of
- EMP when is_list(EMP) ->
- case catch list_to_integer(EMP) of
- Int when is_integer(Int) -> Int;
- _ -> false
- end;
- _ -> false
- end.
-
max_ports() ->
- PreMaxPorts
- = case max_ports_env() of
- Env when is_integer(Env) -> Env;
- _ ->
- case os:type() of
- {unix, _} ->
- UlimStr = string:strip(os:cmd("ulimit -n")
- -- "\n"),
- case catch list_to_integer(UlimStr) of
- Ulim when is_integer(Ulim) -> Ulim;
- _ -> ?DEF_MAX_PORTS
- end;
- _ -> ?DEF_MAX_PORTS
- end
- end,
- case PreMaxPorts > ?DEF_MAX_PORTS of
- true -> PreMaxPorts;
- false -> ?DEF_MAX_PORTS
- end.
+ erlang:system_info(port_limit).
port_ix(Port) when is_port(Port) ->
["#Port",_,PortIxStr] = string:tokens(erlang:port_to_list(Port),
@@ -2270,5 +2279,12 @@ close_deaf_port_1(N, Cmd) ->
_:eagain ->
{comment, "Could not spawn more than " ++ integer_to_list(N) ++ " OS processes."}
end.
-
+wait_until(Fun) ->
+ case catch Fun() of
+ true ->
+ ok;
+ _ ->
+ receive after 100 -> ok end,
+ wait_until(Fun)
+ end.
diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl
index 6509871a7d..11dd88413f 100644
--- a/erts/emulator/test/process_SUITE.erl
+++ b/erts/emulator/test/process_SUITE.erl
@@ -118,15 +118,15 @@ fun_spawn(Fun) ->
%% (unclear if this test case will actually prove anything on
%% a modern computer with lots of memory).
spawn_with_binaries(Config) when is_list(Config) ->
- ?line L = lists:duplicate(2048, 42),
- ?line TwoMeg = lists:duplicate(1024, L),
- ?line Fun = fun() -> spawn(?MODULE, binary_owner, [list_to_binary(TwoMeg)]),
+ L = lists:duplicate(2048, 42),
+ TwoMeg = lists:duplicate(1024, L),
+ Fun = fun() -> spawn(?MODULE, binary_owner, [list_to_binary(TwoMeg)]),
receive after 1 -> ok end end,
- ?line Iter = case test_server:purify_is_running() of
+ Iter = case test_server:purify_is_running() of
true -> 10;
false -> 150
end,
- ?line test_server:do_times(Iter, Fun),
+ test_server:do_times(Iter, Fun),
ok.
binary_owner(Bin) when is_binary(Bin) ->
@@ -134,87 +134,87 @@ binary_owner(Bin) when is_binary(Bin) ->
%% Tests exit/1 with a big message.
t_exit_1(Config) when is_list(Config) ->
- ?line start_spawner(),
- ?line Dog = test_server:timetrap(test_server:seconds(20)),
- ?line process_flag(trap_exit, true),
- ?line test_server:do_times(10, fun t_exit_1/0),
- ?line test_server:timetrap_cancel(Dog),
- ?line stop_spawner(),
+ start_spawner(),
+ Dog = test_server:timetrap(test_server:seconds(20)),
+ process_flag(trap_exit, true),
+ test_server:do_times(10, fun t_exit_1/0),
+ test_server:timetrap_cancel(Dog),
+ stop_spawner(),
ok.
t_exit_1() ->
- ?line Pid = fun_spawn(fun() -> exit(kb_128()) end),
- ?line Garbage = kb_128(),
- ?line receive
+ Pid = fun_spawn(fun() -> exit(kb_128()) end),
+ Garbage = kb_128(),
+ receive
{'EXIT', Pid, Garbage} -> ok
end.
%% Tests exit/2 with a lot of data in the exit message.
t_exit_2_other(Config) when is_list(Config) ->
- ?line start_spawner(),
- ?line Dog = test_server:timetrap(test_server:seconds(20)),
- ?line process_flag(trap_exit, true),
- ?line test_server:do_times(10, fun t_exit_2_other/0),
- ?line test_server:timetrap_cancel(Dog),
- ?line stop_spawner(),
+ start_spawner(),
+ Dog = test_server:timetrap(test_server:seconds(20)),
+ process_flag(trap_exit, true),
+ test_server:do_times(10, fun t_exit_2_other/0),
+ test_server:timetrap_cancel(Dog),
+ stop_spawner(),
ok.
t_exit_2_other() ->
- ?line Pid = fun_spawn(fun() -> receive x -> ok end end),
- ?line Garbage = kb_128(),
- ?line exit(Pid, Garbage),
- ?line receive
+ Pid = fun_spawn(fun() -> receive x -> ok end end),
+ Garbage = kb_128(),
+ exit(Pid, Garbage),
+ receive
{'EXIT', Pid, Garbage} -> ok
end.
%% Tests that exit(Pid, normal) does not kill another process.;
t_exit_2_other_normal(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(20)),
- ?line process_flag(trap_exit, true),
- ?line Pid = fun_spawn(fun() -> receive x -> ok end end),
- ?line exit(Pid, normal),
- ?line receive
+ Dog = test_server:timetrap(test_server:seconds(20)),
+ process_flag(trap_exit, true),
+ Pid = fun_spawn(fun() -> receive x -> ok end end),
+ exit(Pid, normal),
+ receive
{'EXIT', Pid, Reason} ->
- ?line test_server:fail({process_died, Reason})
+ test_server:fail({process_died, Reason})
after 1000 ->
ok
end,
- ?line case process_info(Pid) of
+ case process_info(Pid) of
undefined ->
test_server:fail(process_died_on_normal);
List when is_list(List) ->
ok
end,
exit(Pid, kill),
- ?line test_server:timetrap_cancel(Dog),
+ test_server:timetrap_cancel(Dog),
ok.
%% Tests that we can trap an exit message sent with exit/2 from
%% the same process.
self_exit(Config) when is_list(Config) ->
- ?line start_spawner(),
- ?line Dog = test_server:timetrap(test_server:seconds(10)),
- ?line process_flag(trap_exit, true),
- ?line test_server:do_times(200, fun self_exit/0),
- ?line test_server:timetrap_cancel(Dog),
- ?line stop_spawner(),
+ start_spawner(),
+ Dog = test_server:timetrap(test_server:seconds(10)),
+ process_flag(trap_exit, true),
+ test_server:do_times(200, fun self_exit/0),
+ test_server:timetrap_cancel(Dog),
+ stop_spawner(),
ok.
self_exit() ->
- ?line Garbage = eight_kb(),
- ?line P = self(),
- ?line true = exit(P, Garbage),
- ?line receive
+ Garbage = eight_kb(),
+ P = self(),
+ true = exit(P, Garbage),
+ receive
{'EXIT', P, Garbage} -> ok
end.
%% Tests exit(self(), normal) is equivalent to exit(normal) for a process
%% that doesn't trap exits.
normal_suicide_exit(Config) when is_list(Config) ->
- ?line process_flag(trap_exit, true),
- ?line Pid = fun_spawn(fun() -> exit(self(), normal) end),
- ?line receive
+ process_flag(trap_exit, true),
+ Pid = fun_spawn(fun() -> exit(self(), normal) end),
+ receive
{'EXIT', Pid, normal} -> ok;
Other -> test_server:fail({bad_message, Other})
end.
@@ -222,19 +222,19 @@ normal_suicide_exit(Config) when is_list(Config) ->
%% Tests exit(self(), Term) is equivalent to exit(Term) for a process
%% that doesn't trap exits.";
abnormal_suicide_exit(Config) when is_list(Config) ->
- ?line Garbage = eight_kb(),
- ?line process_flag(trap_exit, true),
- ?line Pid = fun_spawn(fun() -> exit(self(), Garbage) end),
- ?line receive
+ Garbage = eight_kb(),
+ process_flag(trap_exit, true),
+ Pid = fun_spawn(fun() -> exit(self(), Garbage) end),
+ receive
{'EXIT', Pid, Garbage} -> ok;
Other -> test_server:fail({bad_message, Other})
end.
%% Tests that exit(self(), die) cannot be catched.
t_exit_2_catch(Config) when is_list(Config) ->
- ?line process_flag(trap_exit, true),
- ?line Pid = fun_spawn(fun() -> catch exit(self(), die) end),
- ?line receive
+ process_flag(trap_exit, true),
+ Pid = fun_spawn(fun() -> catch exit(self(), die) end),
+ receive
{'EXIT', Pid, normal} ->
test_server:fail(catch_worked);
{'EXIT', Pid, die} ->
@@ -246,29 +246,29 @@ t_exit_2_catch(Config) when is_list(Config) ->
%% Tests trapping of an 'EXIT' message generated by a bad argument to
%% the abs/1 bif. The 'EXIT' message will intentionally be very big.
trap_exit_badarg(Config) when is_list(Config) ->
- ?line start_spawner(),
- ?line Dog = test_server:timetrap(test_server:seconds(10)),
- ?line process_flag(trap_exit, true),
- ?line test_server:do_times(10, fun trap_exit_badarg/0),
- ?line test_server:timetrap_cancel(Dog),
- ?line stop_spawner(),
+ start_spawner(),
+ Dog = test_server:timetrap(test_server:seconds(10)),
+ process_flag(trap_exit, true),
+ test_server:do_times(10, fun trap_exit_badarg/0),
+ test_server:timetrap_cancel(Dog),
+ stop_spawner(),
ok.
trap_exit_badarg() ->
- ?line Pid = fun_spawn(fun() -> bad_guy(kb_128()) end),
- ?line Garbage = kb_128(),
- ?line receive
+ Pid = fun_spawn(fun() -> bad_guy(kb_128()) end),
+ Garbage = kb_128(),
+ receive
{'EXIT',Pid,{badarg,[{erlang,abs,[Garbage],Loc1},
{?MODULE,bad_guy,1,Loc2}|_]}}
when is_list(Loc1), is_list(Loc2) ->
ok;
Other ->
- ?line ok = io:format("Bad EXIT message: ~P", [Other, 30]),
- ?line test_server:fail(bad_exit_message)
+ ok = io:format("Bad EXIT message: ~P", [Other, 30]),
+ test_server:fail(bad_exit_message)
end.
bad_guy(Arg) ->
- ?line abs(Arg).
+ abs(Arg).
kb_128() ->
@@ -281,11 +281,11 @@ kb_128() ->
eight_kb() ->
B64 = lists:seq(1, 64),
- ?line B512 = {<<1>>,B64,<<2,3>>,B64,make_unaligned_sub_binary(<<4,5,6,7,8,9>>),
+ B512 = {<<1>>,B64,<<2,3>>,B64,make_unaligned_sub_binary(<<4,5,6,7,8,9>>),
B64,make_sub_binary([1,2,3,4,5,6]),
B64,make_sub_binary(lists:seq(1, ?heap_binary_size+1)),
B64,B64,B64,B64,big_binary()},
- ?line lists:duplicate(8, {B512,B512}).
+ lists:duplicate(8, {B512,B512}).
big_binary() ->
big_binary(10, [42]).
@@ -296,19 +296,19 @@ big_binary(N, Acc) ->
%% Test receiving an EXIT message when spawning a BIF with bad arguments.
trap_exit_badarg_in_bif(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(10)),
- ?line process_flag(trap_exit, true),
- ?line test_server:do_times(10, fun trap_exit_badarg_bif/0),
- ?line test_server:timetrap_cancel(Dog),
+ Dog = test_server:timetrap(test_server:seconds(10)),
+ process_flag(trap_exit, true),
+ test_server:do_times(10, fun trap_exit_badarg_bif/0),
+ test_server:timetrap_cancel(Dog),
ok.
trap_exit_badarg_bif() ->
- ?line Pid = spawn_link(erlang, node, [1]),
- ?line receive
+ Pid = spawn_link(erlang, node, [1]),
+ receive
{'EXIT', Pid, {badarg, _}} ->
ok;
Other ->
- ?line test_server:fail({unexpected, Other})
+ test_server:fail({unexpected, Other})
end.
%% The following sequences of events have crasched Beam.
@@ -321,27 +321,27 @@ trap_exit_badarg_bif() ->
%% 3) The process will crash the next time it executes 'receive'.
exit_and_timeout(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(20)),
+ Dog = test_server:timetrap(test_server:seconds(20)),
- ?line process_flag(trap_exit, true),
- ?line Parent = self(),
- ?line Low = fun_spawn(fun() -> eat_low(Parent) end),
- ?line High = fun_spawn(fun() -> eat_high(Low) end),
- ?line eat_wait_for(Low, High),
+ process_flag(trap_exit, true),
+ Parent = self(),
+ Low = fun_spawn(fun() -> eat_low(Parent) end),
+ High = fun_spawn(fun() -> eat_high(Low) end),
+ eat_wait_for(Low, High),
- ?line test_server:timetrap_cancel(Dog),
+ test_server:timetrap_cancel(Dog),
ok.
eat_wait_for(Low, High) ->
- ?line receive
- {'EXIT', Low, {you, are, dead}} ->
- ok;
- {'EXIT', High, normal} ->
- eat_wait_for(Low, High);
- Other ->
- test_server:fail({bad_message, Other})
- end.
+ receive
+ {'EXIT', Low, {you, are, dead}} ->
+ ok;
+ {'EXIT', High, normal} ->
+ eat_wait_for(Low, High);
+ Other ->
+ test_server:fail({bad_message, Other})
+ end.
eat_low(_Parent) ->
receive
@@ -374,27 +374,27 @@ loop(_, _) ->
%% Tries to send two different exit messages to a process.
%% (The second one should be ignored.)
exit_twice(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(20)),
+ Dog = test_server:timetrap(test_server:seconds(20)),
- ?line process_flag(trap_exit, true),
- ?line Low = fun_spawn(fun etwice_low/0),
- ?line High = fun_spawn(fun() -> etwice_high(Low) end),
- ?line etwice_wait_for(Low, High),
+ process_flag(trap_exit, true),
+ Low = fun_spawn(fun etwice_low/0),
+ High = fun_spawn(fun() -> etwice_high(Low) end),
+ etwice_wait_for(Low, High),
- ?line test_server:timetrap_cancel(Dog),
+ test_server:timetrap_cancel(Dog),
ok.
etwice_wait_for(Low, High) ->
- ?line receive
- {'EXIT', Low, first} ->
- ok;
- {'EXIT', Low, Other} ->
- test_server:fail({wrong_exit_reason, Other});
- {'EXIT', High, normal} ->
- etwice_wait_for(Low, High);
- Other ->
- test_server:fail({bad_message, Other})
- end.
+ receive
+ {'EXIT', Low, first} ->
+ ok;
+ {'EXIT', Low, Other} ->
+ test_server:fail({wrong_exit_reason, Other});
+ {'EXIT', High, normal} ->
+ etwice_wait_for(Low, High);
+ Other ->
+ test_server:fail({bad_message, Other})
+ end.
etwice_low() ->
etwice_low().
@@ -406,15 +406,15 @@ etwice_high(Low) ->
%% Tests the process_info/2 BIF.
t_process_info(Config) when is_list(Config) ->
- ?line [] = process_info(self(), registered_name),
- ?line register(my_name, self()),
- ?line {registered_name, my_name} = process_info(self(), registered_name),
- ?line {status, running} = process_info(self(), status),
- ?line {min_heap_size, 233} = process_info(self(), min_heap_size),
- ?line {min_bin_vheap_size, 46368} = process_info(self(), min_bin_vheap_size),
- ?line {current_function,{?MODULE,t_process_info,1}} =
+ [] = process_info(self(), registered_name),
+ register(my_name, self()),
+ {registered_name, my_name} = process_info(self(), registered_name),
+ {status, running} = process_info(self(), status),
+ {min_heap_size, 233} = process_info(self(), min_heap_size),
+ {min_bin_vheap_size,46422} = process_info(self(), min_bin_vheap_size),
+ {current_function,{?MODULE,t_process_info,1}} =
process_info(self(), current_function),
- ?line {current_function,{?MODULE,t_process_info,1}} =
+ {current_function,{?MODULE,t_process_info,1}} =
apply(erlang, process_info, [self(),current_function]),
%% current_location and current_stacktrace
@@ -425,9 +425,9 @@ t_process_info(Config) when is_list(Config) ->
verify_loc(Line2, Res2),
pi_stacktrace([{?MODULE,t_process_info,1,?LINE}]),
- ?line Gleader = group_leader(),
- ?line {group_leader, Gleader} = process_info(self(), group_leader),
- ?line {'EXIT',{badarg,_Info}} = (catch process_info('not_a_pid')),
+ Gleader = group_leader(),
+ {group_leader, Gleader} = process_info(self(), group_leader),
+ {'EXIT',{badarg,_Info}} = (catch process_info('not_a_pid')),
ok.
pi_stacktrace(Expected0) ->
@@ -509,50 +509,50 @@ process_info_looper(Parent) ->
%% Tests the process_info/1 BIF on another process with messages.
process_info_other_msg(Config) when is_list(Config) ->
Self = self(),
- ?line Pid = spawn_link(fun() -> other_process(Self) end),
+ Pid = spawn_link(fun() -> other_process(Self) end),
receive
{go_ahead,Pid} -> ok
end,
- ?line Own = {my,own,message},
+ Own = {my,own,message},
- ?line {messages,[Own]} = process_info(Pid, messages),
+ {messages,[Own]} = process_info(Pid, messages),
- ?line Garbage = kb_128(),
- ?line MsgA = {a,Garbage},
- ?line MsgB = {b,Garbage},
- ?line MsgC = {c,Garbage},
- ?line MsgD = {d,Garbage},
- ?line MsgE = {e,Garbage},
-
- ?line Pid ! MsgA,
- ?line {messages,[Own,MsgA]} = process_info(Pid, messages),
- ?line Pid ! MsgB,
- ?line {messages,[Own,MsgA,MsgB]} = process_info(Pid, messages),
- ?line Pid ! MsgC,
- ?line {messages,[Own,MsgA,MsgB,MsgC]} = process_info(Pid, messages),
- ?line Pid ! MsgD,
- ?line {messages,[Own,MsgA,MsgB,MsgC,MsgD]} = process_info(Pid, messages),
- ?line Pid ! MsgE,
- ?line {messages,[Own,MsgA,MsgB,MsgC,MsgD,MsgE]=All} = process_info(Pid, messages),
- ?line {memory,BytesOther} = process_info(Pid, memory),
- ?line {memory,BytesSelf} = process_info(self(), memory),
+ Garbage = kb_128(),
+ MsgA = {a,Garbage},
+ MsgB = {b,Garbage},
+ MsgC = {c,Garbage},
+ MsgD = {d,Garbage},
+ MsgE = {e,Garbage},
+
+ Pid ! MsgA,
+ {messages,[Own,MsgA]} = process_info(Pid, messages),
+ Pid ! MsgB,
+ {messages,[Own,MsgA,MsgB]} = process_info(Pid, messages),
+ Pid ! MsgC,
+ {messages,[Own,MsgA,MsgB,MsgC]} = process_info(Pid, messages),
+ Pid ! MsgD,
+ {messages,[Own,MsgA,MsgB,MsgC,MsgD]} = process_info(Pid, messages),
+ Pid ! MsgE,
+ {messages,[Own,MsgA,MsgB,MsgC,MsgD,MsgE]=All} = process_info(Pid, messages),
+ {memory,BytesOther} = process_info(Pid, memory),
+ {memory,BytesSelf} = process_info(self(), memory),
io:format("Memory ~p: ~p\n", [Pid,BytesOther]),
io:format("Memory ~p (self): ~p\n", [self(),BytesSelf]),
[Own,MsgA,MsgB,MsgC,MsgD,MsgE] = All,
- ?line Pid ! {self(),empty},
- ?line receive
+ Pid ! {self(),empty},
+ receive
empty -> ok
end,
- ?line {messages,[]} = process_info(Pid, messages),
+ {messages,[]} = process_info(Pid, messages),
- ?line {min_heap_size, 233} = process_info(Pid, min_heap_size),
- ?line {min_bin_vheap_size, 46368} = process_info(Pid, min_bin_vheap_size),
+ {min_heap_size, 233} = process_info(Pid, min_heap_size),
+ {min_bin_vheap_size, 46422} = process_info(Pid, min_bin_vheap_size),
- ?line Pid ! stop,
+ Pid ! stop,
ok.
process_info_other_dist_msg(Config) when is_list(Config) ->
@@ -560,52 +560,51 @@ process_info_other_dist_msg(Config) when is_list(Config) ->
%% Check that process_info can handle messages that have not been
%% decoded yet.
%%
- ?line {ok, Node} = start_node(Config),
- ?line Self = self(),
- ?line Pid = spawn_link(fun() -> other_process(Self) end),
- ?line receive {go_ahead,Pid} -> ok end,
+ {ok, Node} = start_node(Config),
+ Self = self(),
+ Pid = spawn_link(fun() -> other_process(Self) end),
+ receive {go_ahead,Pid} -> ok end,
- ?line Own = {my,own,message},
+ Own = {my,own,message},
- ?line {messages,[Own]} = process_info(Pid, messages),
- ?line Garbage = kb_128(),
- ?line MsgA = {a,self(),Garbage},
- ?line MsgB = {b,self(),Garbage},
- ?line MsgC = {c,self(),Garbage},
- ?line MsgD = {d,self(),Garbage},
- ?line MsgE = {e,self(),Garbage},
+ {messages,[Own]} = process_info(Pid, messages),
+ Garbage = kb_128(),
+ MsgA = {a,self(),Garbage},
+ MsgB = {b,self(),Garbage},
+ MsgC = {c,self(),Garbage},
+ MsgD = {d,self(),Garbage},
+ MsgE = {e,self(),Garbage},
%% We don't want the other process to decode messages itself
%% therefore we suspend it.
- ?line true = erlang:suspend_process(Pid),
- ?line spawn_link(Node, fun () ->
- Pid ! MsgA,
- Pid ! MsgB,
- Pid ! MsgC,
- Self ! check_abc
- end),
- ?line receive check_abc -> ok end,
- ?line [{status,suspended},
- {messages,[Own,MsgA,MsgB,MsgC]},
- {status,suspended}]= process_info(Pid, [status,messages,status]),
- ?line spawn_link(Node, fun () ->
- Pid ! MsgD,
- Pid ! MsgE,
- Self ! check_de
- end),
- ?line receive check_de -> ok end,
- ?line {messages,[Own,MsgA,MsgB,MsgC,MsgD,MsgE]=All}
- = process_info(Pid, messages),
- ?line true = erlang:resume_process(Pid),
- ?line Pid ! {self(), get_all_messages},
- ?line receive
+ true = erlang:suspend_process(Pid),
+ spawn_link(Node, fun () ->
+ Pid ! MsgA,
+ Pid ! MsgB,
+ Pid ! MsgC,
+ Self ! check_abc
+ end),
+ receive check_abc -> ok end,
+ [{status,suspended},
+ {messages,[Own,MsgA,MsgB,MsgC]},
+ {status,suspended}]= process_info(Pid, [status,messages,status]),
+ spawn_link(Node, fun () ->
+ Pid ! MsgD,
+ Pid ! MsgE,
+ Self ! check_de
+ end),
+ receive check_de -> ok end,
+ {messages,[Own,MsgA,MsgB,MsgC,MsgD,MsgE]=All} = process_info(Pid, messages),
+ true = erlang:resume_process(Pid),
+ Pid ! {self(), get_all_messages},
+ receive
{all_messages, AllMsgs} ->
- ?line All = AllMsgs
+ All = AllMsgs
end,
- ?line {messages,[]} = process_info(Pid, messages),
- ?line Pid ! stop,
- ?line stop_node(Node),
- ?line ok.
+ {messages,[]} = process_info(Pid, messages),
+ Pid ! stop,
+ stop_node(Node),
+ ok.
other_process(Parent) ->
@@ -652,38 +651,36 @@ process_info_2_list(doc) ->
process_info_2_list(suite) ->
[];
process_info_2_list(Config) when is_list(Config) ->
- ?line Proc = spawn(fun () ->
- receive after infinity -> ok end end),
+ Proc = spawn(fun () -> receive after infinity -> ok end end),
register(process_SUITE_process_info_2_list1, self()),
register(process_SUITE_process_info_2_list2, Proc),
- ?line erts_debug:set_internal_state(available_internal_state,true),
- ?line AllArgs = erts_debug:get_internal_state(process_info_args),
- ?line A1 = lists:sort(AllArgs) ++ [status] ++ lists:reverse(AllArgs),
+ erts_debug:set_internal_state(available_internal_state,true),
+ AllArgs = erts_debug:get_internal_state(process_info_args),
+ A1 = lists:sort(AllArgs) ++ [status] ++ lists:reverse(AllArgs),
%% Verify that argument is accepted as single atom
- ?line lists:foreach(fun (A) ->
- ?line {A, _} = process_info(Proc, A),
- ?line {A, _} = process_info(self(), A)
- end,
- A1),
+ lists:foreach(fun (A) ->
+ {A, _} = process_info(Proc, A),
+ {A, _} = process_info(self(), A)
+ end, A1),
%% Verify that order is preserved
- ?line ok = chk_pi_order(process_info(self(), A1), A1),
- ?line ok = chk_pi_order(process_info(Proc, A1), A1),
+ ok = chk_pi_order(process_info(self(), A1), A1),
+ ok = chk_pi_order(process_info(Proc, A1), A1),
%% Small arg list
- ?line A2 = [status, stack_size, trap_exit, priority],
- ?line [{status, _}, {stack_size, _}, {trap_exit, _}, {priority, _}]
+ A2 = [status, stack_size, trap_exit, priority],
+ [{status, _}, {stack_size, _}, {trap_exit, _}, {priority, _}]
= process_info(Proc, A2),
- ?line [{status, _}, {stack_size, _}, {trap_exit, _}, {priority, _}]
+ [{status, _}, {stack_size, _}, {trap_exit, _}, {priority, _}]
= process_info(self(), A2),
%% Huge arg list (note values are shared)
- ?line A3 = lists:duplicate(5000,backtrace),
- ?line V3 = process_info(Proc, A3),
- ?line 5000 = length(V3),
- ?line lists:foreach(fun ({backtrace, _}) -> ok end, V3),
- ?line ok.
+ A3 = lists:duplicate(5000,backtrace),
+ V3 = process_info(Proc, A3),
+ 5000 = length(V3),
+ lists:foreach(fun ({backtrace, _}) -> ok end, V3),
+ ok.
process_info_lock_reschedule(doc) ->
[];
@@ -692,43 +689,37 @@ process_info_lock_reschedule(suite) ->
process_info_lock_reschedule(Config) when is_list(Config) ->
%% We need a process that is running and an item that requires
%% process_info to take the main process lock.
- ?line Target1 = spawn_link(fun tok_loop/0),
- ?line Name1 = process_info_lock_reschedule_running,
- ?line register(Name1, Target1),
- ?line Target2 = spawn_link(fun () -> receive after infinity -> ok end end),
- ?line Name2 = process_info_lock_reschedule_waiting,
- ?line register(Name2, Target2),
- ?line PI = fun(_) ->
- ?line erlang:yield(),
- ?line [{registered_name, Name1}]
- = process_info(Target1, [registered_name]),
- ?line [{registered_name, Name2}]
- = process_info(Target2, [registered_name]),
- ?line erlang:yield(),
- ?line {registered_name, Name1}
- = process_info(Target1, registered_name),
- ?line {registered_name, Name2}
- = process_info(Target2, registered_name),
- ?line erlang:yield(),
- ?line [{registered_name, Name1}| _]
- = process_info(Target1),
- ?line [{registered_name, Name2}| _]
- = process_info(Target2)
- end,
- ?line lists:foreach(PI, lists:seq(1,1000)),
+ Target1 = spawn_link(fun tok_loop/0),
+ Name1 = process_info_lock_reschedule_running,
+ register(Name1, Target1),
+ Target2 = spawn_link(fun () -> receive after infinity -> ok end end),
+ Name2 = process_info_lock_reschedule_waiting,
+ register(Name2, Target2),
+ PI = fun(_) ->
+ erlang:yield(),
+ [{registered_name, Name1}] = process_info(Target1, [registered_name]),
+ [{registered_name, Name2}] = process_info(Target2, [registered_name]),
+ erlang:yield(),
+ {registered_name, Name1} = process_info(Target1, registered_name),
+ {registered_name, Name2} = process_info(Target2, registered_name),
+ erlang:yield(),
+ [{registered_name, Name1}| _] = process_info(Target1),
+ [{registered_name, Name2}| _] = process_info(Target2)
+ end,
+ lists:foreach(PI, lists:seq(1,1000)),
%% Make sure Target1 still is willing to "tok loop"
- ?line case process_info(Target1, status) of
- {status, OkStatus} when OkStatus == runnable;
- OkStatus == running;
- OkStatus == garbage_collecting ->
- ?line unlink(Target1),
- ?line unlink(Target2),
- ?line exit(Target1, bang),
- ?line exit(Target2, bang),
- ?line OkStatus;
- {status, BadStatus} ->
- ?line ?t:fail(BadStatus)
- end.
+ case process_info(Target1, status) of
+ {status, OkStatus} when OkStatus == runnable;
+ OkStatus == running;
+ OkStatus == garbage_collecting ->
+ unlink(Target1),
+ unlink(Target2),
+ exit(Target1, bang),
+ exit(Target2, bang),
+ OkStatus;
+ {status, BadStatus} ->
+ ?t:fail(BadStatus)
+ end.
pi_loop(_Name, _Pid, 0) ->
ok;
@@ -741,50 +732,50 @@ process_info_lock_reschedule2(doc) ->
process_info_lock_reschedule2(suite) ->
[];
process_info_lock_reschedule2(Config) when is_list(Config) ->
- ?line Parent = self(),
- ?line Fun = fun () ->
- receive {go, Name, Pid} -> ok end,
- pi_loop(Name, Pid, 10000),
- Parent ! {done, self()},
- receive after infinity -> ok end
- end,
- ?line P1 = spawn_link(Fun),
- ?line N1 = process_info_lock_reschedule2_1,
- ?line true = register(N1, P1),
- ?line P2 = spawn_link(Fun),
- ?line N2 = process_info_lock_reschedule2_2,
- ?line true = register(N2, P2),
- ?line P3 = spawn_link(Fun),
- ?line N3 = process_info_lock_reschedule2_3,
- ?line true = register(N3, P3),
- ?line P4 = spawn_link(Fun),
- ?line N4 = process_info_lock_reschedule2_4,
- ?line true = register(N4, P4),
- ?line P5 = spawn_link(Fun),
- ?line N5 = process_info_lock_reschedule2_5,
- ?line true = register(N5, P5),
- ?line P6 = spawn_link(Fun),
- ?line N6 = process_info_lock_reschedule2_6,
- ?line true = register(N6, P6),
- ?line P1 ! {go, N2, P2},
- ?line P2 ! {go, N1, P1},
- ?line P3 ! {go, N1, P1},
- ?line P4 ! {go, N1, P1},
- ?line P5 ! {go, N6, P6},
- ?line P6 ! {go, N5, P5},
- ?line receive {done, P1} -> ok end,
- ?line receive {done, P2} -> ok end,
- ?line receive {done, P3} -> ok end,
- ?line receive {done, P4} -> ok end,
- ?line receive {done, P5} -> ok end,
- ?line receive {done, P6} -> ok end,
- ?line unlink(P1), exit(P1, bang),
- ?line unlink(P2), exit(P2, bang),
- ?line unlink(P3), exit(P3, bang),
- ?line unlink(P4), exit(P4, bang),
- ?line unlink(P5), exit(P5, bang),
- ?line unlink(P6), exit(P6, bang),
- ?line ok.
+ Parent = self(),
+ Fun = fun () ->
+ receive {go, Name, Pid} -> ok end,
+ pi_loop(Name, Pid, 10000),
+ Parent ! {done, self()},
+ receive after infinity -> ok end
+ end,
+ P1 = spawn_link(Fun),
+ N1 = process_info_lock_reschedule2_1,
+ true = register(N1, P1),
+ P2 = spawn_link(Fun),
+ N2 = process_info_lock_reschedule2_2,
+ true = register(N2, P2),
+ P3 = spawn_link(Fun),
+ N3 = process_info_lock_reschedule2_3,
+ true = register(N3, P3),
+ P4 = spawn_link(Fun),
+ N4 = process_info_lock_reschedule2_4,
+ true = register(N4, P4),
+ P5 = spawn_link(Fun),
+ N5 = process_info_lock_reschedule2_5,
+ true = register(N5, P5),
+ P6 = spawn_link(Fun),
+ N6 = process_info_lock_reschedule2_6,
+ true = register(N6, P6),
+ P1 ! {go, N2, P2},
+ P2 ! {go, N1, P1},
+ P3 ! {go, N1, P1},
+ P4 ! {go, N1, P1},
+ P5 ! {go, N6, P6},
+ P6 ! {go, N5, P5},
+ receive {done, P1} -> ok end,
+ receive {done, P2} -> ok end,
+ receive {done, P3} -> ok end,
+ receive {done, P4} -> ok end,
+ receive {done, P5} -> ok end,
+ receive {done, P6} -> ok end,
+ unlink(P1), exit(P1, bang),
+ unlink(P2), exit(P2, bang),
+ unlink(P3), exit(P3, bang),
+ unlink(P4), exit(P4, bang),
+ unlink(P5), exit(P5, bang),
+ unlink(P6), exit(P6, bang),
+ ok.
many_args(0,_B,_C,_D,_E,_F,_G,_H,_I,_J) ->
ok;
@@ -802,120 +793,115 @@ process_info_lock_reschedule3(suite) ->
process_info_lock_reschedule3(Config) when is_list(Config) ->
%% We need a process that is running and an item that requires
%% process_info to take the main process lock.
- ?line Target1 = spawn_link(fun tok_loop/0),
- ?line Name1 = process_info_lock_reschedule_running,
- ?line register(Name1, Target1),
- ?line Target2 = spawn_link(fun () -> receive after infinity -> ok end end),
- ?line Name2 = process_info_lock_reschedule_waiting,
- ?line register(Name2, Target2),
- ?line PI = fun(N) ->
- case N rem 10 of
- 0 -> erlang:yield();
- _ -> ok
- end,
- ?line do_pi_msg_len({proc, Target1},
- {arg, message_queue_len})
- end,
- ?line many_args(100000,1,2,3,4,5,6,7,8,9),
- ?line lists:foreach(PI, lists:seq(1,1000000)),
+ Target1 = spawn_link(fun tok_loop/0),
+ Name1 = process_info_lock_reschedule_running,
+ register(Name1, Target1),
+ Target2 = spawn_link(fun () -> receive after infinity -> ok end end),
+ Name2 = process_info_lock_reschedule_waiting,
+ register(Name2, Target2),
+ PI = fun(N) ->
+ case N rem 10 of
+ 0 -> erlang:yield();
+ _ -> ok
+ end,
+ do_pi_msg_len({proc, Target1},
+ {arg, message_queue_len})
+ end,
+ many_args(100000,1,2,3,4,5,6,7,8,9),
+ lists:foreach(PI, lists:seq(1,1000000)),
%% Make sure Target1 still is willing to "tok loop"
- ?line case process_info(Target1, status) of
+ case process_info(Target1, status) of
{status, OkStatus} when OkStatus == runnable;
OkStatus == running;
OkStatus == garbage_collecting ->
- ?line unlink(Target1),
- ?line unlink(Target2),
- ?line exit(Target1, bang),
- ?line exit(Target2, bang),
- ?line OkStatus;
+ unlink(Target1),
+ unlink(Target2),
+ exit(Target1, bang),
+ exit(Target2, bang),
+ OkStatus;
{status, BadStatus} ->
- ?line ?t:fail(BadStatus)
+ ?t:fail(BadStatus)
end.
process_status_exiting(Config) when is_list(Config) ->
%% Make sure that erts_debug:get_internal_state({process_status,P})
%% returns exiting if it is in status P_EXITING.
- ?line erts_debug:set_internal_state(available_internal_state,true),
- ?line Prio = process_flag(priority, max),
- ?line P = spawn_opt(fun () -> receive after infinity -> ok end end,
+ erts_debug:set_internal_state(available_internal_state,true),
+ Prio = process_flag(priority, max),
+ P = spawn_opt(fun () -> receive after infinity -> ok end end,
[{priority, normal}]),
- ?line erlang:yield(),
+ erlang:yield(),
%% The tok_loop processes are here to make it hard for the exiting
%% process to be scheduled in for exit...
- ?line TokLoops = lists:map(fun (_) ->
- spawn_opt(fun tok_loop/0,
- [link,{priority, high}])
- end,
- lists:seq(1, erlang:system_info(schedulers_online))),
- ?line exit(P, boom),
- ?line wait_until(
- fun () ->
- exiting =:= erts_debug:get_internal_state({process_status,P})
- end),
- ?line lists:foreach(fun (Tok) -> unlink(Tok), exit(Tok,bang) end, TokLoops),
- ?line process_flag(priority, Prio),
- ?line ok.
+ TokLoops = lists:map(fun (_) ->
+ spawn_opt(fun tok_loop/0,
+ [link,{priority, high}])
+ end, lists:seq(1, erlang:system_info(schedulers_online))),
+ exit(P, boom),
+ wait_until(fun() ->
+ exiting =:= erts_debug:get_internal_state({process_status,P})
+ end),
+ lists:foreach(fun (Tok) -> unlink(Tok), exit(Tok,bang) end, TokLoops),
+ process_flag(priority, Prio),
+ ok.
otp_4725(Config) when is_list(Config) ->
- ?line Tester = self(),
- ?line Ref1 = make_ref(),
- ?line Pid1 = spawn_opt(fun () ->
- Tester ! {Ref1, process_info(self())},
- receive
- Ref1 -> bye
- end
- end,
- [link,
- {priority, max},
- {fullsweep_after, 600}]),
- ?line receive
- {Ref1, ProcInfo1A} ->
- ?line ProcInfo1B = process_info(Pid1),
- ?line Pid1 ! Ref1,
- ?line check_proc_infos(ProcInfo1A, ProcInfo1B)
- end,
- ?line Ref2 = make_ref(),
- ?line Pid2 = spawn_opt(fun () ->
- Tester ! {Ref2, process_info(self())},
- receive
- Ref2 -> bye
- end
- end,
- []),
- ?line receive
- {Ref2, ProcInfo2A} ->
- ?line ProcInfo2B = process_info(Pid2),
- ?line Pid2 ! Ref2,
- ?line check_proc_infos(ProcInfo2A, ProcInfo2B)
- end,
- ?line ok.
+ Tester = self(),
+ Ref1 = make_ref(),
+ Pid1 = spawn_opt(fun () ->
+ Tester ! {Ref1, process_info(self())},
+ receive
+ Ref1 -> bye
+ end
+ end, [link, {priority, max}, {fullsweep_after, 600}]),
+ receive
+ {Ref1, ProcInfo1A} ->
+ ProcInfo1B = process_info(Pid1),
+ Pid1 ! Ref1,
+ check_proc_infos(ProcInfo1A, ProcInfo1B)
+ end,
+ Ref2 = make_ref(),
+ Pid2 = spawn_opt(fun () ->
+ Tester ! {Ref2, process_info(self())},
+ receive
+ Ref2 -> bye
+ end
+ end,
+ []),
+ receive
+ {Ref2, ProcInfo2A} ->
+ ProcInfo2B = process_info(Pid2),
+ Pid2 ! Ref2,
+ check_proc_infos(ProcInfo2A, ProcInfo2B)
+ end,
+ ok.
check_proc_infos(A, B) ->
- ?line IC = lists:keysearch(initial_call, 1, A),
- ?line IC = lists:keysearch(initial_call, 1, B),
+ IC = lists:keysearch(initial_call, 1, A),
+ IC = lists:keysearch(initial_call, 1, B),
- ?line L = lists:keysearch(links, 1, A),
- ?line L = lists:keysearch(links, 1, B),
+ L = lists:keysearch(links, 1, A),
+ L = lists:keysearch(links, 1, B),
- ?line D = lists:keysearch(dictionary, 1, A),
- ?line D = lists:keysearch(dictionary, 1, B),
+ D = lists:keysearch(dictionary, 1, A),
+ D = lists:keysearch(dictionary, 1, B),
- ?line TE = lists:keysearch(trap_exit, 1, A),
- ?line TE = lists:keysearch(trap_exit, 1, B),
+ TE = lists:keysearch(trap_exit, 1, A),
+ TE = lists:keysearch(trap_exit, 1, B),
- ?line EH = lists:keysearch(error_handler, 1, A),
- ?line EH = lists:keysearch(error_handler, 1, B),
+ EH = lists:keysearch(error_handler, 1, A),
+ EH = lists:keysearch(error_handler, 1, B),
- ?line P = lists:keysearch(priority, 1, A),
- ?line P = lists:keysearch(priority, 1, B),
+ P = lists:keysearch(priority, 1, A),
+ P = lists:keysearch(priority, 1, B),
- ?line GL = lists:keysearch(group_leader, 1, A),
- ?line GL = lists:keysearch(group_leader, 1, B),
+ GL = lists:keysearch(group_leader, 1, A),
+ GL = lists:keysearch(group_leader, 1, B),
- ?line GC = lists:keysearch(garbage_collection, 1, A),
- ?line GC = lists:keysearch(garbage_collection, 1, B),
+ GC = lists:keysearch(garbage_collection, 1, A),
+ GC = lists:keysearch(garbage_collection, 1, B),
- ?line ok.
+ ok.
%% Dummies.
@@ -928,18 +914,18 @@ stop_spawner() ->
%% Tests erlang:bump_reductions/1.
bump_reductions(Config) when is_list(Config) ->
- ?line erlang:garbage_collect(),
- ?line receive after 1 -> ok end, % Clear reductions.
- ?line {reductions,R1} = process_info(self(), reductions),
- ?line true = erlang:bump_reductions(100),
- ?line {reductions,R2} = process_info(self(), reductions),
- ?line case R2-R1 of
+ erlang:garbage_collect(),
+ receive after 1 -> ok end, % Clear reductions.
+ {reductions,R1} = process_info(self(), reductions),
+ true = erlang:bump_reductions(100),
+ {reductions,R2} = process_info(self(), reductions),
+ case R2-R1 of
Diff when Diff < 100 ->
- ?line ok = io:format("R1 = ~w, R2 = ~w", [R1, R2]),
- ?line test_server:fail({small_diff, Diff});
+ ok = io:format("R1 = ~w, R2 = ~w", [R1, R2]),
+ test_server:fail({small_diff, Diff});
Diff when Diff > 110 ->
- ?line ok = io:format("R1 = ~w, R2 = ~w", [R1, R2]),
- ?line test_server:fail({big_diff, Diff});
+ ok = io:format("R1 = ~w, R2 = ~w", [R1, R2]),
+ test_server:fail({big_diff, Diff});
Diff ->
io:format("~p\n", [Diff]),
ok
@@ -949,11 +935,11 @@ bump_reductions(Config) when is_list(Config) ->
bump_big(R2, 16#08000000).
bump_big(Prev, Limit) ->
- ?line true = erlang:bump_reductions(100000), %Limited to CONTEXT_REDUCTIONS.
- ?line case process_info(self(), reductions) of
+ true = erlang:bump_reductions(100000), %Limited to CONTEXT_REDUCTIONS.
+ case process_info(self(), reductions) of
{reductions,Big} when is_integer(Big), Big > Limit ->
- ?line erlang:garbage_collect(),
- ?line io:format("~p\n", [Big]);
+ erlang:garbage_collect(),
+ io:format("~p\n", [Big]);
{reductions,R} when is_integer(R), R > Prev ->
bump_big(R, Limit)
end,
@@ -964,34 +950,34 @@ bump_big(Prev, Limit) ->
low_prio(Config) when is_list(Config) ->
case erlang:system_info(schedulers_online) of
1 ->
- ?line ok = low_prio_test(Config);
+ ok = low_prio_test(Config);
_ ->
- ?line erlang:system_flag(multi_scheduling, block),
- ?line ok = low_prio_test(Config),
- ?line erlang:system_flag(multi_scheduling, unblock),
- ?line {comment,
+ erlang:system_flag(multi_scheduling, block),
+ ok = low_prio_test(Config),
+ erlang:system_flag(multi_scheduling, unblock),
+ {comment,
"Test not written for SMP runtime system. "
"Multi scheduling blocked during test."}
end.
low_prio_test(Config) when is_list(Config) ->
- ?line process_flag(trap_exit, true),
- ?line S = spawn_link(?MODULE, prio_server, [0, 0]),
- ?line PCs = spawn_prio_clients(S, erlang:system_info(schedulers_online)),
- ?line timer:sleep(2000),
- ?line lists:foreach(fun (P) -> exit(P, kill) end, PCs),
- ?line S ! exit,
- ?line receive {'EXIT', S, {A, B}} -> check_prio(A, B) end,
+ process_flag(trap_exit, true),
+ S = spawn_link(?MODULE, prio_server, [0, 0]),
+ PCs = spawn_prio_clients(S, erlang:system_info(schedulers_online)),
+ timer:sleep(2000),
+ lists:foreach(fun (P) -> exit(P, kill) end, PCs),
+ S ! exit,
+ receive {'EXIT', S, {A, B}} -> check_prio(A, B) end,
ok.
check_prio(A, B) ->
- ?line Prop = A/B,
- ?line ok = io:format("Low=~p, High=~p, Prop=~p\n", [A, B, Prop]),
+ Prop = A/B,
+ ok = io:format("Low=~p, High=~p, Prop=~p\n", [A, B, Prop]),
%% It isn't 1/8, it's more like 0.3, but let's check that
%% the low-prio processes get some little chance to run at all.
- ?line true = (Prop < 1.0),
- ?line true = (Prop > 1/32).
+ true = (Prop < 1.0),
+ true = (Prop > 1/32).
prio_server(A, B) ->
receive
@@ -1051,25 +1037,25 @@ yield(Config) when is_list(Config) ->
end.
yield_test() ->
- ?line erlang:garbage_collect(),
- ?line receive after 1 -> ok end, % Clear reductions.
- ?line SC = schedcnt(start),
- ?line {reductions, R1} = process_info(self(), reductions),
- ?line {ok, true} = call_yield(middle),
- ?line true = call_yield(final),
- ?line true = call_yield(),
- ?line true = apply(erlang, yield, []),
- ?line {reductions, R2} = process_info(self(), reductions),
- ?line Schedcnt = schedcnt(stop, SC),
- ?line case {R2-R1, Schedcnt} of
- {Diff, 4} when Diff < 30 ->
- ?line ok = io:format("R1 = ~w, R2 = ~w, Schedcnt = ~w",
- [R1, R2, Schedcnt]);
- {Diff, _} ->
- ?line ok = io:format("R1 = ~w, R2 = ~w, Schedcnt = ~w",
- [R1, R2, Schedcnt]),
- ?line test_server:fail({measurement_error, Diff, Schedcnt})
- end.
+ erlang:garbage_collect(),
+ receive after 1 -> ok end, % Clear reductions.
+ SC = schedcnt(start),
+ {reductions, R1} = process_info(self(), reductions),
+ {ok, true} = call_yield(middle),
+ true = call_yield(final),
+ true = call_yield(),
+ true = apply(erlang, yield, []),
+ {reductions, R2} = process_info(self(), reductions),
+ Schedcnt = schedcnt(stop, SC),
+ case {R2-R1, Schedcnt} of
+ {Diff, 4} when Diff < 30 ->
+ ok = io:format("R1 = ~w, R2 = ~w, Schedcnt = ~w",
+ [R1, R2, Schedcnt]);
+ {Diff, _} ->
+ ok = io:format("R1 = ~w, R2 = ~w, Schedcnt = ~w",
+ [R1, R2, Schedcnt]),
+ test_server:fail({measurement_error, Diff, Schedcnt})
+ end.
call_yield() ->
erlang:yield().
@@ -1108,61 +1094,61 @@ schedcnt(stop, {Ref, Pid}) when is_reference(Ref), is_pid(Pid) ->
yield2(doc) -> [];
yield2(suite) -> [];
yield2(Config) when is_list(Config) ->
- ?line Me = self(),
- ?line Go = make_ref(),
- ?line RedDiff = make_ref(),
- ?line Done = make_ref(),
- ?line P = spawn(fun () ->
- receive Go -> ok end,
- {reductions, R1} = process_info(self(), reductions),
- {ok, true} = call_yield(middle),
- true = call_yield(final),
- true = call_yield(),
- true = apply(erlang, yield, []),
- {reductions, R2} = process_info(self(), reductions),
- Me ! {RedDiff, R2 - R1},
- exit(Done)
- end),
- ?line erlang:yield(),
-
- ?line 1 = erlang:trace(P, true, [running, procs, {tracer, self()}]),
-
- ?line P ! Go,
+ Me = self(),
+ Go = make_ref(),
+ RedDiff = make_ref(),
+ Done = make_ref(),
+ P = spawn(fun () ->
+ receive Go -> ok end,
+ {reductions, R1} = process_info(self(), reductions),
+ {ok, true} = call_yield(middle),
+ true = call_yield(final),
+ true = call_yield(),
+ true = apply(erlang, yield, []),
+ {reductions, R2} = process_info(self(), reductions),
+ Me ! {RedDiff, R2 - R1},
+ exit(Done)
+ end),
+ erlang:yield(),
+
+ 1 = erlang:trace(P, true, [running, procs, {tracer, self()}]),
+
+ P ! Go,
%% receive Go -> ok end,
- ?line {trace, P, in, _} = next_tmsg(P),
+ {trace, P, in, _} = next_tmsg(P),
%% {ok, true} = call_yield(middle),
- ?line {trace, P, out, _} = next_tmsg(P),
- ?line {trace, P, in, _} = next_tmsg(P),
+ {trace, P, out, _} = next_tmsg(P),
+ {trace, P, in, _} = next_tmsg(P),
%% true = call_yield(final),
- ?line {trace, P, out, _} = next_tmsg(P),
- ?line {trace, P, in, _} = next_tmsg(P),
+ {trace, P, out, _} = next_tmsg(P),
+ {trace, P, in, _} = next_tmsg(P),
%% true = call_yield(),
- ?line {trace, P, out, _} = next_tmsg(P),
- ?line {trace, P, in, _} = next_tmsg(P),
+ {trace, P, out, _} = next_tmsg(P),
+ {trace, P, in, _} = next_tmsg(P),
%% true = apply(erlang, yield, []),
- ?line {trace, P, out, _} = next_tmsg(P),
- ?line {trace, P, in, _} = next_tmsg(P),
+ {trace, P, out, _} = next_tmsg(P),
+ {trace, P, in, _} = next_tmsg(P),
%% exit(Done)
- ?line {trace, P, exit, Done} = next_tmsg(P),
+ {trace, P, exit, Done} = next_tmsg(P),
- ?line receive
+ receive
{RedDiff, Reductions} when Reductions < 30, Reductions > 0 ->
io:format("Reductions = ~p~n", [Reductions]),
- ?line ok;
+ ok;
{RedDiff, Reductions} ->
- ?line ?t:fail({unexpected_reduction_count, Reductions})
+ ?t:fail({unexpected_reduction_count, Reductions})
end,
- ?line none = next_tmsg(P),
+ none = next_tmsg(P),
- ?line ok.
+ ok.
next_tmsg(Pid) ->
receive
@@ -1178,19 +1164,19 @@ next_tmsg(Pid) ->
bad_register(Config) when is_list(Config) ->
Name = a_long_and_unused_name,
- ?line {'EXIT',{badarg,_}} = (catch register({bad,name}, self())),
- ?line fail_register(undefined, self()),
- ?line fail_register([bad,name], self()),
+ {'EXIT',{badarg,_}} = (catch register({bad,name}, self())),
+ fail_register(undefined, self()),
+ fail_register([bad,name], self()),
- ?line {Dead,Mref} = spawn_monitor(fun() -> true end),
+ {Dead,Mref} = spawn_monitor(fun() -> true end),
receive
{'DOWN',Mref,process,Dead,_} -> ok
end,
- ?line fail_register(Name, Dead),
- ?line fail_register(Name, make_ref()),
- ?line fail_register(Name, []),
- ?line fail_register(Name, {bad,process}),
- ?line fail_register(Name, <<>>),
+ fail_register(Name, Dead),
+ fail_register(Name, make_ref()),
+ fail_register(Name, []),
+ fail_register(Name, {bad,process}),
+ fail_register(Name, <<>>),
ok.
fail_register(Name, Process) ->
@@ -1201,50 +1187,50 @@ fail_register(Name, Process) ->
garbage_collect(doc) -> [];
garbage_collect(suite) -> [];
garbage_collect(Config) when is_list(Config) ->
- ?line Prio = process_flag(priority, high),
- ?line true = erlang:garbage_collect(),
- ?line TokLoopers = lists:map(fun (_) ->
- spawn_opt(fun tok_loop/0,
- [{priority, low}, link])
- end,
- lists:seq(1, 10)),
- ?line lists:foreach(fun (Pid) ->
- ?line Mon = erlang:monitor(process, Pid),
- ?line DownBefore = receive
- {'DOWN', Mon, _, _, _} ->
- ?line true
- after 0 ->
- ?line false
- end,
- ?line GC = erlang:garbage_collect(Pid),
- ?line DownAfter = receive
- {'DOWN', Mon, _, _, _} ->
- ?line true
- after 0 ->
- ?line false
- end,
- ?line true = erlang:demonitor(Mon),
- ?line case {DownBefore, DownAfter} of
- {true, _} -> ?line false = GC;
- {false, false} -> ?line true = GC;
- _ -> ?line GC
- end
- end,
- processes()),
- ?line lists:foreach(fun (Pid) ->
- unlink(Pid),
- exit(Pid, bang)
- end, TokLoopers),
- ?line process_flag(priority, Prio),
- ?line ok.
+ Prio = process_flag(priority, high),
+ true = erlang:garbage_collect(),
+
+ TokLoopers = lists:map(fun (_) ->
+ spawn_opt(fun tok_loop/0, [{priority, low}, link])
+ end, lists:seq(1, 10)),
+
+ lists:foreach(fun (Pid) ->
+ Mon = erlang:monitor(process, Pid),
+ DownBefore = receive
+ {'DOWN', Mon, _, _, _} ->
+ true
+ after 0 ->
+ false
+ end,
+ GC = erlang:garbage_collect(Pid),
+ DownAfter = receive
+ {'DOWN', Mon, _, _, _} ->
+ true
+ after 0 ->
+ false
+ end,
+ true = erlang:demonitor(Mon),
+ case {DownBefore, DownAfter} of
+ {true, _} -> false = GC;
+ {false, false} -> true = GC;
+ _ -> GC
+ end
+ end, processes()),
+
+ lists:foreach(fun (Pid) ->
+ unlink(Pid),
+ exit(Pid, bang)
+ end, TokLoopers),
+ process_flag(priority, Prio),
+ ok.
process_info_messages(doc) ->
["This used to cause the nofrag emulator to dump core"];
process_info_messages(suite) ->
[];
process_info_messages(Config) when is_list(Config) ->
- ?line process_info_messages_test(),
- ?line ok.
+ process_info_messages_test(),
+ ok.
process_info_messages_loop(0) -> ok;
process_info_messages_loop(N) -> process_info_messages_loop(N-1).
@@ -1259,43 +1245,42 @@ process_info_messages_send_my_msgs_to(Rcvr) ->
end.
process_info_messages_test() ->
- ?line Go = make_ref(),
- ?line Done = make_ref(),
- ?line Rcvr = self(),
- ?line Rcvr2 = spawn_link(fun () ->
- receive {Go, Rcvr} -> ok end,
- garbage_collect(),
- Rcvr ! {Done, self()}
- end),
- ?line Sndrs = lists:map(
- fun (_) ->
- spawn_link(fun () ->
- Rcvr ! {Go, self()},
- receive {Go, Rcvr} -> ok end,
- BigData = lists:seq(1, 1000),
- Rcvr ! BigData,
- Rcvr ! BigData,
- Rcvr ! BigData,
- Rcvr ! {Done, self()}
- end)
- end,
- lists:seq(1, 10)),
- ?line lists:foreach(fun (Sndr) -> receive {Go, Sndr} -> ok end end,
+ Go = make_ref(),
+ Done = make_ref(),
+ Rcvr = self(),
+ Rcvr2 = spawn_link(fun () ->
+ receive {Go, Rcvr} -> ok end,
+ garbage_collect(),
+ Rcvr ! {Done, self()}
+ end),
+ Sndrs = lists:map(
+ fun (_) ->
+ spawn_link(fun () ->
+ Rcvr ! {Go, self()},
+ receive {Go, Rcvr} -> ok end,
+ BigData = lists:seq(1, 1000),
+ Rcvr ! BigData,
+ Rcvr ! BigData,
+ Rcvr ! BigData,
+ Rcvr ! {Done, self()}
+ end)
+ end, lists:seq(1, 10)),
+ lists:foreach(fun (Sndr) -> receive {Go, Sndr} -> ok end end,
Sndrs),
- ?line garbage_collect(),
- ?line erlang:yield(),
- ?line lists:foreach(fun (Sndr) -> Sndr ! {Go, self()} end, Sndrs),
- ?line process_info_messages_loop(100000000),
- ?line Msgs = process_info(self(), messages),
- ?line lists:foreach(fun (Sndr) -> receive {Done, Sndr} -> ok end end,
+ garbage_collect(),
+ erlang:yield(),
+ lists:foreach(fun (Sndr) -> Sndr ! {Go, self()} end, Sndrs),
+ process_info_messages_loop(100000000),
+ Msgs = process_info(self(), messages),
+ lists:foreach(fun (Sndr) -> receive {Done, Sndr} -> ok end end,
Sndrs),
- ?line garbage_collect(),
- ?line Rcvr2 ! Msgs,
- ?line process_info_messages_send_my_msgs_to(Rcvr2),
- ?line Rcvr2 ! {Go, self()},
- ?line garbage_collect(),
- ?line receive {Done, Rcvr2} -> ok end,
- ?line Msgs.
+ garbage_collect(),
+ Rcvr2 ! Msgs,
+ process_info_messages_send_my_msgs_to(Rcvr2),
+ Rcvr2 ! {Go, self()},
+ garbage_collect(),
+ receive {Done, Rcvr2} -> ok end,
+ Msgs.
chk_badarg(Fun) ->
try Fun(), exit(no_badarg) catch error:badarg -> ok end.
@@ -1305,76 +1290,72 @@ process_flag_badarg(doc) ->
process_flag_badarg(suite) ->
[];
process_flag_badarg(Config) when is_list(Config) ->
- ?line chk_badarg(fun () -> process_flag(gurka, banan) end),
- ?line chk_badarg(fun () -> process_flag(trap_exit, gurka) end),
- ?line chk_badarg(fun () -> process_flag(error_handler, 1) end),
- ?line chk_badarg(fun () -> process_flag(min_heap_size, gurka) end),
- ?line chk_badarg(fun () -> process_flag(min_bin_vheap_size, gurka) end),
- ?line chk_badarg(fun () -> process_flag(min_bin_vheap_size, -1) end),
- ?line chk_badarg(fun () -> process_flag(priority, 4711) end),
- ?line chk_badarg(fun () -> process_flag(save_calls, hmmm) end),
- ?line P= spawn_link(fun () -> receive die -> ok end end),
- ?line chk_badarg(fun () -> process_flag(P, save_calls, hmmm) end),
- ?line chk_badarg(fun () -> process_flag(gurka, save_calls, hmmm) end),
- ?line P ! die,
- ?line ok.
+ chk_badarg(fun () -> process_flag(gurka, banan) end),
+ chk_badarg(fun () -> process_flag(trap_exit, gurka) end),
+ chk_badarg(fun () -> process_flag(error_handler, 1) end),
+ chk_badarg(fun () -> process_flag(min_heap_size, gurka) end),
+ chk_badarg(fun () -> process_flag(min_bin_vheap_size, gurka) end),
+ chk_badarg(fun () -> process_flag(min_bin_vheap_size, -1) end),
+ chk_badarg(fun () -> process_flag(priority, 4711) end),
+ chk_badarg(fun () -> process_flag(save_calls, hmmm) end),
+ P= spawn_link(fun () -> receive die -> ok end end),
+ chk_badarg(fun () -> process_flag(P, save_calls, hmmm) end),
+ chk_badarg(fun () -> process_flag(gurka, save_calls, hmmm) end),
+ P ! die,
+ ok.
-include_lib("stdlib/include/ms_transform.hrl").
otp_6237(doc) -> [];
otp_6237(suite) -> [];
otp_6237(Config) when is_list(Config) ->
- ?line Slctrs = lists:map(fun (_) ->
- spawn_link(fun () ->
- otp_6237_select_loop()
- end)
- end,
- lists:seq(1,5)),
- ?line lists:foreach(fun (_) -> otp_6237_test() end, lists:seq(1, 100)),
- ?line lists:foreach(fun (S) -> unlink(S),exit(S, kill) end, Slctrs),
- ?line ok.
+ Slctrs = lists:map(fun (_) ->
+ spawn_link(fun () ->
+ otp_6237_select_loop()
+ end)
+ end,
+ lists:seq(1,5)),
+ lists:foreach(fun (_) -> otp_6237_test() end, lists:seq(1, 100)),
+ lists:foreach(fun (S) -> unlink(S),exit(S, kill) end, Slctrs),
+ ok.
otp_6237_test() ->
- ?line Parent = self(),
- ?line Inited = make_ref(),
- ?line Die = make_ref(),
- ?line Pid = spawn_link(fun () ->
- register(otp_6237,self()),
- otp_6237 = ets:new(otp_6237,
- [named_table,
- ordered_set]),
- ets:insert(otp_6237,
- [{I,I}
- || I <- lists:seq(1, 100)]),
- %% Inserting a lot of bif timers
- %% increase the possibility that
- %% the test will fail when the
- %% original cleanup order is used
- lists:foreach(
- fun (_) ->
- erlang:send_after(1000000,
- self(),
- {a,b,c})
- end,
- lists:seq(1,1000)),
- Parent ! Inited,
- receive Die -> bye end
- end),
- ?line receive
- Inited -> ?line ok
- end,
- ?line Pid ! Die,
+ Parent = self(),
+ Inited = make_ref(),
+ Die = make_ref(),
+ Pid = spawn_link(fun () ->
+ register(otp_6237,self()),
+ otp_6237 = ets:new(otp_6237,
+ [named_table,
+ ordered_set]),
+ ets:insert(otp_6237,
+ [{I,I}
+ || I <- lists:seq(1, 100)]),
+ %% Inserting a lot of bif timers
+ %% increase the possibility that
+ %% the test will fail when the
+ %% original cleanup order is used
+ lists:foreach( fun (_) ->
+ erlang:send_after(1000000, self(), {a,b,c})
+ end, lists:seq(1,1000)),
+ Parent ! Inited,
+ receive Die -> bye end
+ end),
+ receive
+ Inited -> ok
+ end,
+ Pid ! Die,
otp_6237_whereis_loop().
otp_6237_whereis_loop() ->
- ?line case whereis(otp_6237) of
+ case whereis(otp_6237) of
undefined ->
- ?line otp_6237 = ets:new(otp_6237,
+ otp_6237 = ets:new(otp_6237,
[named_table,ordered_set]),
- ?line ets:delete(otp_6237),
- ?line ok;
+ ets:delete(otp_6237),
+ ok;
_ ->
- ?line otp_6237_whereis_loop()
+ otp_6237_whereis_loop()
end.
otp_6237_select_loop() ->
@@ -1382,9 +1363,8 @@ otp_6237_select_loop() ->
otp_6237_select_loop().
-
-define(NoTestProcs, 10000).
--record(processes_bif_info, {min_start_reds,
+-record(ptab_list_bif_info, {min_start_reds,
tab_chunks,
tab_chunks_size,
tab_indices_per_red,
@@ -1399,89 +1379,86 @@ processes_large_tab(doc) ->
processes_large_tab(suite) ->
[];
processes_large_tab(Config) when is_list(Config) ->
- ?line enable_internal_state(),
- ?line MaxDbgLvl = 20,
- ?line MinProcTabSize = 2*(1 bsl 15),
- ?line ProcTabSize0 = 1000000,
- ?line ProcTabSize1 = case {erlang:system_info(schedulers_online),
- erlang:system_info(logical_processors)} of
- {Schdlrs, Cpus} when is_integer(Cpus),
- Schdlrs =< Cpus ->
- ProcTabSize0;
- _ ->
- ProcTabSize0 div 4
- end,
- ?line ProcTabSize2 = case erlang:system_info(debug_compiled) of
- true -> ProcTabSize1 - 500000;
- false -> ProcTabSize1
- end,
+ enable_internal_state(),
+ MaxDbgLvl = 20,
+ MinProcTabSize = 2*(1 bsl 15),
+ ProcTabSize0 = 1000000,
+ ProcTabSize1 = case {erlang:system_info(schedulers_online),
+ erlang:system_info(logical_processors)} of
+ {Schdlrs, Cpus} when is_integer(Cpus),
+ Schdlrs =< Cpus ->
+ ProcTabSize0;
+ _ ->
+ ProcTabSize0 div 4
+ end,
+ ProcTabSize2 = case erlang:system_info(debug_compiled) of
+ true -> ProcTabSize1 - 500000;
+ false -> ProcTabSize1
+ end,
%% With high debug levels this test takes so long time that
%% the connection times out; therefore, shrink the test on
%% high debug levels.
- ?line DbgLvl = case erts_debug:get_internal_state(processes_bif_info) of
- #processes_bif_info{debug_level = Lvl} when Lvl > MaxDbgLvl ->
+ DbgLvl = case erts_debug:get_internal_state(processes_bif_info) of
+ #ptab_list_bif_info{debug_level = Lvl} when Lvl > MaxDbgLvl ->
20;
- #processes_bif_info{debug_level = Lvl} when Lvl < 0 ->
- ?line ?t:fail({debug_level, Lvl});
- #processes_bif_info{debug_level = Lvl} ->
+ #ptab_list_bif_info{debug_level = Lvl} when Lvl < 0 ->
+ ?t:fail({debug_level, Lvl});
+ #ptab_list_bif_info{debug_level = Lvl} ->
Lvl
end,
- ?line ProcTabSize3 = ProcTabSize2 - (1300000 * DbgLvl div MaxDbgLvl),
- ?line ProcTabSize = case ProcTabSize3 < MinProcTabSize of
+ ProcTabSize3 = ProcTabSize2 - (1300000 * DbgLvl div MaxDbgLvl),
+ ProcTabSize = case ProcTabSize3 < MinProcTabSize of
true -> MinProcTabSize;
false -> ProcTabSize3
end,
- ?line {ok, LargeNode} = start_node(Config,
+ {ok, LargeNode} = start_node(Config,
"+P " ++ integer_to_list(ProcTabSize)),
- ?line Res = rpc:call(LargeNode, ?MODULE, processes_bif_test, []),
- ?line case rpc:call(LargeNode,
+ Res = rpc:call(LargeNode, ?MODULE, processes_bif_test, []),
+ case rpc:call(LargeNode,
erts_debug,
get_internal_state,
[processes_bif_info]) of
- #processes_bif_info{tab_chunks = Chunks} when is_integer(Chunks),
+ #ptab_list_bif_info{tab_chunks = Chunks} when is_integer(Chunks),
Chunks > 1 -> ok;
PBInfo -> ?t:fail(PBInfo)
end,
- ?line stop_node(LargeNode),
- ?line chk_processes_bif_test_res(Res).
+ stop_node(LargeNode),
+ chk_processes_bif_test_res(Res).
processes_default_tab(doc) ->
[];
processes_default_tab(suite) ->
[];
processes_default_tab(Config) when is_list(Config) ->
- ?line {ok, DefaultNode} = start_node(Config, ""),
- ?line Res = rpc:call(DefaultNode, ?MODULE, processes_bif_test, []),
- ?line stop_node(DefaultNode),
- ?line chk_processes_bif_test_res(Res).
+ {ok, DefaultNode} = start_node(Config, ""),
+ Res = rpc:call(DefaultNode, ?MODULE, processes_bif_test, []),
+ stop_node(DefaultNode),
+ chk_processes_bif_test_res(Res).
processes_small_tab(doc) ->
[];
processes_small_tab(suite) ->
[];
processes_small_tab(Config) when is_list(Config) ->
- ?line {ok, SmallNode} = start_node(Config, "+P 500"),
- ?line Res = rpc:call(SmallNode, ?MODULE, processes_bif_test, []),
- ?line PBInfo = rpc:call(SmallNode,
- erts_debug,
- get_internal_state,
- [processes_bif_info]),
- ?line stop_node(SmallNode),
- ?line 1 = PBInfo#processes_bif_info.tab_chunks,
- ?line chk_processes_bif_test_res(Res).
+ {ok, SmallNode} = start_node(Config, "+P 1024"),
+ Res = rpc:call(SmallNode, ?MODULE, processes_bif_test, []),
+ PBInfo = rpc:call(SmallNode, erts_debug, get_internal_state, [processes_bif_info]),
+ stop_node(SmallNode),
+ true = PBInfo#ptab_list_bif_info.tab_chunks < 10,
+ chk_processes_bif_test_res(Res).
processes_this_tab(doc) ->
[];
processes_this_tab(suite) ->
[];
processes_this_tab(Config) when is_list(Config) ->
- ?line chk_processes_bif_test_res(processes_bif_test()).
+ chk_processes_bif_test_res(processes_bif_test()).
chk_processes_bif_test_res(ok) -> ok;
chk_processes_bif_test_res({comment, _} = Comment) -> Comment;
chk_processes_bif_test_res(Failure) -> ?t:fail(Failure).
-print_processes_bif_info(#processes_bif_info{min_start_reds = MinStartReds,
+print_processes_bif_info(#ptab_list_bif_info{min_start_reds = MinStartReds,
tab_chunks = TabChunks,
tab_chunks_size = TabChunksSize,
tab_indices_per_red = TabIndPerRed,
@@ -1575,26 +1552,26 @@ do_processes(WantReds) ->
processes().
processes_bif_test() ->
- ?line Tester = self(),
- ?line enable_internal_state(),
- ?line PBInfo = erts_debug:get_internal_state(processes_bif_info),
- ?line print_processes_bif_info(PBInfo),
- ?line WantReds = PBInfo#processes_bif_info.min_start_reds + 10,
- ?line WillTrap = case PBInfo of
- #processes_bif_info{tab_chunks = 1} ->
- false;
- #processes_bif_info{tab_chunks = Chunks,
- tab_chunks_size = ChunksSize,
- tab_indices_per_red = IndiciesPerRed
- } ->
- Chunks*ChunksSize >= IndiciesPerRed*WantReds
- end,
- ?line Processes = fun () ->
- erts_debug:set_internal_state(reds_left,WantReds),
- processes()
- end,
+ Tester = self(),
+ enable_internal_state(),
+ PBInfo = erts_debug:get_internal_state(processes_bif_info),
+ print_processes_bif_info(PBInfo),
+ WantReds = PBInfo#ptab_list_bif_info.min_start_reds + 10,
+ WillTrap = case PBInfo of
+ #ptab_list_bif_info{tab_chunks = Chunks} when Chunks < 10 ->
+ false; %% Skip for small tables
+ #ptab_list_bif_info{tab_chunks = Chunks,
+ tab_chunks_size = ChunksSize,
+ tab_indices_per_red = IndiciesPerRed
+ } ->
+ Chunks*ChunksSize >= IndiciesPerRed*WantReds
+ end,
+ Processes = fun () ->
+ erts_debug:set_internal_state(reds_left,WantReds),
+ processes()
+ end,
- ?line ok = do_processes_bif_test(WantReds, WillTrap, Processes),
+ ok = do_processes_bif_test(WantReds, WillTrap, Processes),
case WillTrap of
false ->
@@ -1602,8 +1579,8 @@ processes_bif_test() ->
true ->
%% Do it again with a process suspended while
%% in the processes/0 bif.
- ?line erlang:system_flag(multi_scheduling, block),
- ?line Suspendee = spawn_link(fun () ->
+ erlang:system_flag(multi_scheduling, block),
+ Suspendee = spawn_link(fun () ->
Tester ! {suspend_me, self()},
Tester ! {self(),
done,
@@ -1613,179 +1590,160 @@ processes_bif_test() ->
ok
end
end),
- ?line receive {suspend_me, Suspendee} -> ok end,
- ?line erlang:suspend_process(Suspendee),
- ?line erlang:system_flag(multi_scheduling, unblock),
+ receive {suspend_me, Suspendee} -> ok end,
+ erlang:suspend_process(Suspendee),
+ erlang:system_flag(multi_scheduling, unblock),
- ?line [{status,suspended},
- {current_function,{erlang,processes_trap,2}}]
- = process_info(Suspendee, [status, current_function]),
+ [{status,suspended},{current_function,{erlang,ptab_list_continue,2}}] =
+ process_info(Suspendee, [status, current_function]),
- ?line ok = do_processes_bif_test(WantReds, WillTrap, Processes),
+ ok = do_processes_bif_test(WantReds, WillTrap, Processes),
- ?line erlang:resume_process(Suspendee),
- ?line receive {Suspendee, done, _} -> ok end,
- ?line unlink(Suspendee),
- ?line exit(Suspendee, bang)
+ erlang:resume_process(Suspendee),
+ receive {Suspendee, done, _} -> ok end,
+ unlink(Suspendee),
+ exit(Suspendee, bang)
end,
case get(processes_bif_testcase_comment) of
- undefined -> ?line ok;
- Comment -> ?line {comment, Comment}
+ undefined -> ok;
+ Comment -> {comment, Comment}
end.
do_processes_bif_test(WantReds, DieTest, Processes) ->
- ?line Tester = self(),
- ?line SpawnProcesses = fun (Prio) ->
- spawn_opt(?MODULE,
- do_processes,
- [WantReds],
- [link, {priority, Prio}])
- end,
- ?line Cleaner = spawn_link(fun () ->
- process_flag(trap_exit, true),
- Tester ! {cleaner_alive, self()},
- processes_bif_cleaner()
- end),
- ?line receive {cleaner_alive, Cleaner} -> ok end,
+ Tester = self(),
+ SpawnProcesses = fun (Prio) ->
+ spawn_opt(?MODULE, do_processes, [WantReds], [link, {priority, Prio}])
+ end,
+ Cleaner = spawn_link(fun () ->
+ process_flag(trap_exit, true),
+ Tester ! {cleaner_alive, self()},
+ processes_bif_cleaner()
+ end),
+ receive {cleaner_alive, Cleaner} -> ok end,
try
- ?line DoIt = make_ref(),
- ?line GetGoing = make_ref(),
- ?line {NoTestProcs, TestProcs} = spawn_initial_hangarounds(Cleaner),
- ?line ?t:format("Testing with ~p processes~n", [NoTestProcs]),
- ?line SpawnHangAround = fun () ->
- spawn(?MODULE,
- hangaround,
- [Cleaner, new_hangaround])
- end,
- ?line Killer = spawn_opt(fun () ->
- Splt = NoTestProcs div 10,
- {TP1, TP23} = lists:split(Splt,
- TestProcs),
- {TP2, TP3} = lists:split(Splt, TP23),
- erlang:system_flag(multi_scheduling,
- block),
- Tester ! DoIt,
- receive GetGoing -> ok end,
- erlang:system_flag(multi_scheduling,
- unblock),
- SpawnProcesses(high),
- lists:foreach(
- fun (P) ->
- SpawnHangAround(),
- exit(P, bang)
- end,
- TP1),
- SpawnProcesses(high),
- erlang:yield(),
- lists:foreach(
- fun (P) ->
- SpawnHangAround(),
- exit(P, bang)
- end,
- TP2),
- SpawnProcesses(high),
- lists:foreach(
- fun (P) ->
- SpawnHangAround(),
- exit(P, bang)
- end,
- TP3)
- end,
- [{priority, high}, link]),
- ?line receive DoIt -> ok end,
- ?line process_flag(priority, low),
- ?line SpawnProcesses(low),
- ?line erlang:yield(),
- ?line process_flag(priority, normal),
- ?line CorrectProcs0 = erts_debug:get_internal_state(processes),
- ?line Killer ! GetGoing,
- ?line erts_debug:set_internal_state(reds_left, WantReds),
- ?line Procs0 = processes(),
- ?line Procs = lists:sort(Procs0),
- ?line CorrectProcs = lists:sort(CorrectProcs0),
- ?line LengthCorrectProcs = length(CorrectProcs),
- ?line ?t:format("~p = length(CorrectProcs)~n", [LengthCorrectProcs]),
- ?line true = LengthCorrectProcs > NoTestProcs,
- ?line case CorrectProcs =:= Procs of
- true ->
- ?line ok;
- false ->
- ?line processes_unexpected_result(CorrectProcs, Procs)
- end,
- ?line unlink(Killer),
- ?line exit(Killer, bang)
+ DoIt = make_ref(),
+ GetGoing = make_ref(),
+ {NoTestProcs, TestProcs} = spawn_initial_hangarounds(Cleaner),
+ ?t:format("Testing with ~p processes~n", [NoTestProcs]),
+ SpawnHangAround = fun () ->
+ spawn(?MODULE, hangaround, [Cleaner, new_hangaround])
+ end,
+ Killer = spawn_opt(fun () ->
+ Splt = NoTestProcs div 10,
+ {TP1, TP23} = lists:split(Splt, TestProcs),
+ {TP2, TP3} = lists:split(Splt, TP23),
+ erlang:system_flag(multi_scheduling, block),
+ Tester ! DoIt,
+ receive GetGoing -> ok end,
+ erlang:system_flag(multi_scheduling, unblock),
+ SpawnProcesses(high),
+ lists:foreach( fun (P) ->
+ SpawnHangAround(),
+ exit(P, bang)
+ end, TP1),
+ SpawnProcesses(high),
+ erlang:yield(),
+ lists:foreach( fun (P) ->
+ SpawnHangAround(),
+ exit(P, bang)
+ end, TP2),
+ SpawnProcesses(high),
+ lists:foreach(
+ fun (P) ->
+ SpawnHangAround(),
+ exit(P, bang)
+ end, TP3)
+ end, [{priority, high}, link]),
+ receive DoIt -> ok end,
+ process_flag(priority, low),
+ SpawnProcesses(low),
+ erlang:yield(),
+ process_flag(priority, normal),
+ CorrectProcs0 = erts_debug:get_internal_state(processes),
+ Killer ! GetGoing,
+ erts_debug:set_internal_state(reds_left, WantReds),
+ Procs0 = processes(),
+ Procs = lists:sort(Procs0),
+ CorrectProcs = lists:sort(CorrectProcs0),
+ LengthCorrectProcs = length(CorrectProcs),
+ ?t:format("~p = length(CorrectProcs)~n", [LengthCorrectProcs]),
+ true = LengthCorrectProcs > NoTestProcs,
+ case CorrectProcs =:= Procs of
+ true ->
+ ok;
+ false ->
+ processes_unexpected_result(CorrectProcs, Procs)
+ end,
+ unlink(Killer),
+ exit(Killer, bang)
after
unlink(Cleaner),
exit(Cleaner, kill),
%% Wait for the system to recover to a normal state...
wait_until_system_recover()
end,
- ?line do_processes_bif_die_test(DieTest, Processes),
- ?line ok.
+ do_processes_bif_die_test(DieTest, Processes),
+ ok.
do_processes_bif_die_test(false, _Processes) ->
- ?line ?t:format("Skipping test killing process executing processes/0~n",[]),
- ?line ok;
+ ?t:format("Skipping test killing process executing processes/0~n",[]),
+ ok;
do_processes_bif_die_test(true, Processes) ->
- ?line do_processes_bif_die_test(5, Processes);
+ do_processes_bif_die_test(5, Processes);
do_processes_bif_die_test(N, Processes) ->
- ?line ?t:format("Doing test killing process executing processes/0~n",[]),
+ ?t:format("Doing test killing process executing processes/0~n",[]),
try
- ?line Tester = self(),
- ?line Oooh_Nooooooo = make_ref(),
- ?line {_, DieWhileDoingMon} = erlang:spawn_monitor(
- fun () ->
- Victim = self(),
- spawn_opt(
- fun () ->
- exit(Victim, got_him)
- end,
- [link,
- {priority, max}]),
- Tester ! {Oooh_Nooooooo,
- hd(Processes())},
- exit(ohhhh_nooooo)
- end),
- ?line receive
- {'DOWN', DieWhileDoingMon, _, _, Reason} ->
- case Reason of
- got_him -> ok;
- _ -> throw({kill_in_trap, Reason})
- end
- end,
- ?line receive
- {Oooh_Nooooooo, _} ->
- ?line throw({kill_in_trap, 'Oooh_Nooooooo'})
- after 0 ->
- ?line ok
- end,
- ?line PrcsCllrsSeqLen = 2*erlang:system_info(schedulers_online),
- ?line PrcsCllrsSeq = lists:seq(1, PrcsCllrsSeqLen),
- ?line ProcsCallers = lists:map(
- fun (_) ->
- spawn_link(
- fun () ->
- Tester ! hd(Processes())
- end)
- end,
- PrcsCllrsSeq),
- ?line erlang:yield(),
+ Tester = self(),
+ Oooh_Nooooooo = make_ref(),
+ {_, DieWhileDoingMon} = erlang:spawn_monitor( fun () ->
+ Victim = self(),
+ spawn_opt(
+ fun () ->
+ exit(Victim, got_him)
+ end,
+ [link, {priority, max}]),
+ Tester ! {Oooh_Nooooooo,
+ hd(Processes())},
+ exit(ohhhh_nooooo)
+ end),
+ receive
+ {'DOWN', DieWhileDoingMon, _, _, Reason} ->
+ case Reason of
+ got_him -> ok;
+ _ -> throw({kill_in_trap, Reason})
+ end
+ end,
+ receive
+ {Oooh_Nooooooo, _} ->
+ throw({kill_in_trap, 'Oooh_Nooooooo'})
+ after 0 ->
+ ok
+ end,
+ PrcsCllrsSeqLen = 2*erlang:system_info(schedulers_online),
+ PrcsCllrsSeq = lists:seq(1, PrcsCllrsSeqLen),
+ ProcsCallers = lists:map( fun (_) ->
+ spawn_link(
+ fun () ->
+ Tester ! hd(Processes())
+ end)
+ end, PrcsCllrsSeq),
+ erlang:yield(),
{ProcsCallers1, ProcsCallers2} = lists:split(PrcsCllrsSeqLen div 2,
ProcsCallers),
- ?line process_flag(priority, high),
- ?line lists:foreach(
+ process_flag(priority, high),
+ lists:foreach(
fun (P) ->
unlink(P),
exit(P, bang)
end,
lists:reverse(ProcsCallers2) ++ ProcsCallers1),
- ?line process_flag(priority, normal),
- ?line ok
+ process_flag(priority, normal),
+ ok
catch
throw:{kill_in_trap, R} when N > 0 ->
?t:format("Failed to kill in trap: ~p~n", [R]),
- ?t:format("Trying again~p~n", []),
+ ?t:format("Trying again~n", []),
do_processes_bif_die_test(N-1, Processes)
end.
@@ -1844,23 +1802,23 @@ processes_last_call_trap(doc) ->
processes_last_call_trap(suite) ->
[];
processes_last_call_trap(Config) when is_list(Config) ->
- ?line enable_internal_state(),
- ?line Processes = fun () -> processes() end,
- ?line PBInfo = erts_debug:get_internal_state(processes_bif_info),
- ?line print_processes_bif_info(PBInfo),
- ?line WantReds = case PBInfo#processes_bif_info.min_start_reds of
- R when R > 10 -> R - 1;
- _R -> 9
- end,
- ?line lists:foreach(fun (_) ->
- ?line erts_debug:set_internal_state(reds_left,
- WantReds),
- Processes(),
- ?line erts_debug:set_internal_state(reds_left,
- WantReds),
- my_processes()
- end,
- lists:seq(1,100)).
+ enable_internal_state(),
+ Processes = fun () -> processes() end,
+ PBInfo = erts_debug:get_internal_state(processes_bif_info),
+ print_processes_bif_info(PBInfo),
+ WantReds = case PBInfo#ptab_list_bif_info.min_start_reds of
+ R when R > 10 -> R - 1;
+ _R -> 9
+ end,
+ lists:foreach(fun (_) ->
+ erts_debug:set_internal_state(reds_left,
+ WantReds),
+ Processes(),
+ erts_debug:set_internal_state(reds_left,
+ WantReds),
+ my_processes()
+ end,
+ lists:seq(1,100)).
my_processes() ->
processes().
@@ -1870,108 +1828,106 @@ processes_apply_trap(doc) ->
processes_apply_trap(suite) ->
[];
processes_apply_trap(Config) when is_list(Config) ->
- ?line enable_internal_state(),
- ?line PBInfo = erts_debug:get_internal_state(processes_bif_info),
- ?line print_processes_bif_info(PBInfo),
- ?line WantReds = case PBInfo#processes_bif_info.min_start_reds of
- R when R > 10 -> R - 1;
- _R -> 9
- end,
- ?line lists:foreach(fun (_) ->
- ?line erts_debug:set_internal_state(reds_left,
- WantReds),
- ?line apply(erlang, processes, [])
- end,
- lists:seq(1,100)).
+ enable_internal_state(),
+ PBInfo = erts_debug:get_internal_state(processes_bif_info),
+ print_processes_bif_info(PBInfo),
+ WantReds = case PBInfo#ptab_list_bif_info.min_start_reds of
+ R when R > 10 -> R - 1;
+ _R -> 9
+ end,
+ lists:foreach(fun (_) ->
+ erts_debug:set_internal_state(reds_left,
+ WantReds),
+ apply(erlang, processes, [])
+ end, lists:seq(1,100)).
processes_gc_trap(doc) ->
[];
processes_gc_trap(suite) ->
[];
processes_gc_trap(Config) when is_list(Config) ->
- ?line Tester = self(),
- ?line enable_internal_state(),
- ?line PBInfo = erts_debug:get_internal_state(processes_bif_info),
- ?line print_processes_bif_info(PBInfo),
- ?line WantReds = PBInfo#processes_bif_info.min_start_reds + 10,
- ?line Processes = fun () ->
- erts_debug:set_internal_state(reds_left,WantReds),
- processes()
- end,
+ Tester = self(),
+ enable_internal_state(),
+ PBInfo = erts_debug:get_internal_state(processes_bif_info),
+ print_processes_bif_info(PBInfo),
+ WantReds = PBInfo#ptab_list_bif_info.min_start_reds + 10,
+ Processes = fun () ->
+ erts_debug:set_internal_state(reds_left,WantReds),
+ processes()
+ end,
- ?line erlang:system_flag(multi_scheduling, block),
- ?line Suspendee = spawn_link(fun () ->
+ erlang:system_flag(multi_scheduling, block),
+ Suspendee = spawn_link(fun () ->
Tester ! {suspend_me, self()},
Tester ! {self(),
done,
hd(Processes())},
receive after infinity -> ok end
end),
- ?line receive {suspend_me, Suspendee} -> ok end,
- ?line erlang:suspend_process(Suspendee),
- ?line erlang:system_flag(multi_scheduling, unblock),
+ receive {suspend_me, Suspendee} -> ok end,
+ erlang:suspend_process(Suspendee),
+ erlang:system_flag(multi_scheduling, unblock),
- ?line [{status,suspended}, {current_function,{erlang,processes_trap,2}}]
+ [{status,suspended}, {current_function,{erlang,ptab_list_continue,2}}]
= process_info(Suspendee, [status, current_function]),
- ?line erlang:garbage_collect(Suspendee),
- ?line erlang:garbage_collect(Suspendee),
+ erlang:garbage_collect(Suspendee),
+ erlang:garbage_collect(Suspendee),
- ?line erlang:resume_process(Suspendee),
- ?line receive {Suspendee, done, _} -> ok end,
- ?line erlang:garbage_collect(Suspendee),
- ?line erlang:garbage_collect(Suspendee),
+ erlang:resume_process(Suspendee),
+ receive {Suspendee, done, _} -> ok end,
+ erlang:garbage_collect(Suspendee),
+ erlang:garbage_collect(Suspendee),
- ?line unlink(Suspendee),
- ?line exit(Suspendee, bang),
- ?line ok.
+ unlink(Suspendee),
+ exit(Suspendee, bang),
+ ok.
process_flag_heap_size(doc) ->
[];
process_flag_heap_size(suite) ->
[];
process_flag_heap_size(Config) when is_list(Config) ->
- HSize = 2584, % must be gc fib number
- VHSize = 317811, % must be gc fib number
- ?line OldHmin = erlang:process_flag(min_heap_size, HSize),
- ?line {min_heap_size, HSize} = erlang:process_info(self(), min_heap_size),
- ?line OldVHmin = erlang:process_flag(min_bin_vheap_size, VHSize),
- ?line {min_bin_vheap_size, VHSize} = erlang:process_info(self(), min_bin_vheap_size),
- ?line HSize = erlang:process_flag(min_heap_size, OldHmin),
- ?line VHSize = erlang:process_flag(min_bin_vheap_size, OldVHmin),
- ?line ok.
+ HSize = 2586, % must be gc fib+ number
+ VHSize = 318187, % must be gc fib+ number
+ OldHmin = erlang:process_flag(min_heap_size, HSize),
+ {min_heap_size, HSize} = erlang:process_info(self(), min_heap_size),
+ OldVHmin = erlang:process_flag(min_bin_vheap_size, VHSize),
+ {min_bin_vheap_size, VHSize} = erlang:process_info(self(), min_bin_vheap_size),
+ HSize = erlang:process_flag(min_heap_size, OldHmin),
+ VHSize = erlang:process_flag(min_bin_vheap_size, OldVHmin),
+ ok.
spawn_opt_heap_size(doc) ->
[];
spawn_opt_heap_size(suite) ->
[];
spawn_opt_heap_size(Config) when is_list(Config) ->
- HSize = 987, % must be gc fib number
- VHSize = 46368, % must be gc fib number
- ?line Pid = spawn_opt(fun () -> receive stop -> ok end end,
+ HSize = 987, % must be gc fib+ number
+ VHSize = 46422, % must be gc fib+ number
+ Pid = spawn_opt(fun () -> receive stop -> ok end end,
[{min_heap_size, HSize},{ min_bin_vheap_size, VHSize}]),
- ?line {min_heap_size, HSize} = process_info(Pid, min_heap_size),
- ?line {min_bin_vheap_size, VHSize} = process_info(Pid, min_bin_vheap_size),
- ?line Pid ! stop,
- ?line ok.
+ {min_heap_size, HSize} = process_info(Pid, min_heap_size),
+ {min_bin_vheap_size, VHSize} = process_info(Pid, min_bin_vheap_size),
+ Pid ! stop,
+ ok.
processes_term_proc_list(doc) ->
[];
processes_term_proc_list(suite) ->
[];
processes_term_proc_list(Config) when is_list(Config) ->
- ?line Tester = self(),
- ?line as_expected = processes_term_proc_list_test(false),
- ?line {ok, Node} = start_node(Config, "+Mis true"),
- ?line RT = spawn_link(Node,
- fun () ->
- receive after 1000 -> ok end,
- processes_term_proc_list_test(false),
- Tester ! {it_worked, self()}
- end),
- ?line receive {it_worked, RT} -> ok end,
- ?line stop_node(Node),
- ?line ok.
+ Tester = self(),
+ as_expected = processes_term_proc_list_test(false),
+ {ok, Node} = start_node(Config, "+Mis true"),
+ RT = spawn_link(Node, fun () ->
+ receive after 1000 -> ok end,
+ processes_term_proc_list_test(false),
+ Tester ! {it_worked, self()}
+ end),
+ receive {it_worked, RT} -> ok end,
+ stop_node(Node),
+ ok.
-define(CHK_TERM_PROC_LIST(MC, XB),
chk_term_proc_list(?LINE, MC, XB)).
@@ -1982,8 +1938,8 @@ chk_term_proc_list(Line, MustChk, ExpectBlks) ->
not_enabled;
{_, MS} ->
{value,
- {processes_term_proc_el,
- DL}} = lists:keysearch(processes_term_proc_el, 1, MS),
+ {ptab_list_deleted_el,
+ DL}} = lists:keysearch(ptab_list_deleted_el, 1, MS),
case lists:keysearch(blocks, 1, DL) of
{value, {blocks, ExpectBlks, _, _}} ->
ok;
@@ -1997,35 +1953,34 @@ chk_term_proc_list(Line, MustChk, ExpectBlks) ->
ok.
processes_term_proc_list_test(MustChk) ->
- ?line Tester = self(),
- ?line enable_internal_state(),
- ?line PBInfo = erts_debug:get_internal_state(processes_bif_info),
- ?line print_processes_bif_info(PBInfo),
- ?line WantReds = PBInfo#processes_bif_info.min_start_reds + 10,
- ?line #processes_bif_info{tab_chunks = Chunks,
- tab_chunks_size = ChunksSize,
- tab_indices_per_red = IndiciesPerRed
- } = PBInfo,
- ?line true = Chunks > 1,
- ?line true = Chunks*ChunksSize >= IndiciesPerRed*WantReds,
- ?line Processes = fun () ->
- erts_debug:set_internal_state(reds_left,
- WantReds),
- processes()
- end,
- ?line Exit = fun (P) ->
- unlink(P),
- exit(P, bang),
- wait_until(
- fun () ->
- not lists:member(
- P,
- erts_debug:get_internal_state(
- processes))
- end)
- end,
- ?line SpawnSuspendProcessesProc
- = fun () ->
+ Tester = self(),
+ enable_internal_state(),
+ PBInfo = erts_debug:get_internal_state(processes_bif_info),
+ print_processes_bif_info(PBInfo),
+ WantReds = PBInfo#ptab_list_bif_info.min_start_reds + 10,
+ #ptab_list_bif_info{tab_chunks = Chunks,
+ tab_chunks_size = ChunksSize,
+ tab_indices_per_red = IndiciesPerRed
+ } = PBInfo,
+ true = Chunks > 1,
+ true = Chunks*ChunksSize >= IndiciesPerRed*WantReds,
+ Processes = fun () ->
+ erts_debug:set_internal_state(reds_left,
+ WantReds),
+ processes()
+ end,
+ Exit = fun (P) ->
+ unlink(P),
+ exit(P, bang),
+ wait_until(
+ fun () ->
+ not lists:member(
+ P,
+ erts_debug:get_internal_state(
+ processes))
+ end)
+ end,
+ SpawnSuspendProcessesProc = fun () ->
erlang:system_flag(multi_scheduling, block),
P = spawn_link(fun () ->
Tester ! {suspend_me, self()},
@@ -2038,76 +1993,76 @@ processes_term_proc_list_test(MustChk) ->
erlang:suspend_process(P),
erlang:system_flag(multi_scheduling, unblock),
[{status,suspended},
- {current_function,{erlang,processes_trap,2}}]
+ {current_function,{erlang,ptab_list_continue,2}}]
= process_info(P, [status, current_function]),
P
end,
- ?line ResumeProcessesProc = fun (P) ->
+ ResumeProcessesProc = fun (P) ->
erlang:resume_process(P),
receive {P, done, _} -> ok end
end,
- ?line ?CHK_TERM_PROC_LIST(MustChk, 0),
- ?line HangAround = fun () -> receive after infinity -> ok end end,
- ?line HA1 = spawn_link(HangAround),
- ?line HA2 = spawn_link(HangAround),
- ?line HA3 = spawn_link(HangAround),
- ?line S1 = SpawnSuspendProcessesProc(),
- ?line ?CHK_TERM_PROC_LIST(MustChk, 1),
- ?line Exit(HA1),
- ?line ?CHK_TERM_PROC_LIST(MustChk, 2),
- ?line S2 = SpawnSuspendProcessesProc(),
- ?line ?CHK_TERM_PROC_LIST(MustChk, 3),
- ?line S3 = SpawnSuspendProcessesProc(),
- ?line ?CHK_TERM_PROC_LIST(MustChk, 4),
- ?line Exit(HA2),
- ?line ?CHK_TERM_PROC_LIST(MustChk, 5),
- ?line S4 = SpawnSuspendProcessesProc(),
- ?line ?CHK_TERM_PROC_LIST(MustChk, 6),
- ?line Exit(HA3),
- ?line ?CHK_TERM_PROC_LIST(MustChk, 7),
- ?line ResumeProcessesProc(S1),
- ?line ?CHK_TERM_PROC_LIST(MustChk, 5),
- ?line ResumeProcessesProc(S3),
- ?line ?CHK_TERM_PROC_LIST(MustChk, 4),
- ?line ResumeProcessesProc(S4),
- ?line ?CHK_TERM_PROC_LIST(MustChk, 3),
- ?line ResumeProcessesProc(S2),
- ?line ?CHK_TERM_PROC_LIST(MustChk, 0),
- ?line Exit(S1),
- ?line Exit(S2),
- ?line Exit(S3),
- ?line Exit(S4),
-
-
- ?line HA4 = spawn_link(HangAround),
- ?line HA5 = spawn_link(HangAround),
- ?line HA6 = spawn_link(HangAround),
- ?line S5 = SpawnSuspendProcessesProc(),
- ?line ?CHK_TERM_PROC_LIST(MustChk, 1),
- ?line Exit(HA4),
- ?line ?CHK_TERM_PROC_LIST(MustChk, 2),
- ?line S6 = SpawnSuspendProcessesProc(),
- ?line ?CHK_TERM_PROC_LIST(MustChk, 3),
- ?line Exit(HA5),
- ?line ?CHK_TERM_PROC_LIST(MustChk, 4),
- ?line S7 = SpawnSuspendProcessesProc(),
- ?line ?CHK_TERM_PROC_LIST(MustChk, 5),
- ?line Exit(HA6),
- ?line ?CHK_TERM_PROC_LIST(MustChk, 6),
- ?line S8 = SpawnSuspendProcessesProc(),
- ?line ?CHK_TERM_PROC_LIST(MustChk, 7),
-
- ?line erlang:system_flag(multi_scheduling, block),
- ?line Exit(S8),
- ?line ?CHK_TERM_PROC_LIST(MustChk, 7),
- ?line Exit(S5),
- ?line ?CHK_TERM_PROC_LIST(MustChk, 6),
- ?line Exit(S7),
- ?line ?CHK_TERM_PROC_LIST(MustChk, 6),
- ?line Exit(S6),
- ?line ?CHK_TERM_PROC_LIST(MustChk, 0),
- ?line erlang:system_flag(multi_scheduling, unblock),
- ?line as_expected.
+ ?CHK_TERM_PROC_LIST(MustChk, 0),
+ HangAround = fun () -> receive after infinity -> ok end end,
+ HA1 = spawn_link(HangAround),
+ HA2 = spawn_link(HangAround),
+ HA3 = spawn_link(HangAround),
+ S1 = SpawnSuspendProcessesProc(),
+ ?CHK_TERM_PROC_LIST(MustChk, 1),
+ Exit(HA1),
+ ?CHK_TERM_PROC_LIST(MustChk, 2),
+ S2 = SpawnSuspendProcessesProc(),
+ ?CHK_TERM_PROC_LIST(MustChk, 3),
+ S3 = SpawnSuspendProcessesProc(),
+ ?CHK_TERM_PROC_LIST(MustChk, 4),
+ Exit(HA2),
+ ?CHK_TERM_PROC_LIST(MustChk, 5),
+ S4 = SpawnSuspendProcessesProc(),
+ ?CHK_TERM_PROC_LIST(MustChk, 6),
+ Exit(HA3),
+ ?CHK_TERM_PROC_LIST(MustChk, 7),
+ ResumeProcessesProc(S1),
+ ?CHK_TERM_PROC_LIST(MustChk, 5),
+ ResumeProcessesProc(S3),
+ ?CHK_TERM_PROC_LIST(MustChk, 4),
+ ResumeProcessesProc(S4),
+ ?CHK_TERM_PROC_LIST(MustChk, 3),
+ ResumeProcessesProc(S2),
+ ?CHK_TERM_PROC_LIST(MustChk, 0),
+ Exit(S1),
+ Exit(S2),
+ Exit(S3),
+ Exit(S4),
+
+
+ HA4 = spawn_link(HangAround),
+ HA5 = spawn_link(HangAround),
+ HA6 = spawn_link(HangAround),
+ S5 = SpawnSuspendProcessesProc(),
+ ?CHK_TERM_PROC_LIST(MustChk, 1),
+ Exit(HA4),
+ ?CHK_TERM_PROC_LIST(MustChk, 2),
+ S6 = SpawnSuspendProcessesProc(),
+ ?CHK_TERM_PROC_LIST(MustChk, 3),
+ Exit(HA5),
+ ?CHK_TERM_PROC_LIST(MustChk, 4),
+ S7 = SpawnSuspendProcessesProc(),
+ ?CHK_TERM_PROC_LIST(MustChk, 5),
+ Exit(HA6),
+ ?CHK_TERM_PROC_LIST(MustChk, 6),
+ S8 = SpawnSuspendProcessesProc(),
+ ?CHK_TERM_PROC_LIST(MustChk, 7),
+
+ erlang:system_flag(multi_scheduling, block),
+ Exit(S8),
+ ?CHK_TERM_PROC_LIST(MustChk, 7),
+ Exit(S5),
+ ?CHK_TERM_PROC_LIST(MustChk, 6),
+ Exit(S7),
+ ?CHK_TERM_PROC_LIST(MustChk, 6),
+ Exit(S6),
+ ?CHK_TERM_PROC_LIST(MustChk, 0),
+ erlang:system_flag(multi_scheduling, unblock),
+ as_expected.
otp_7738_waiting(doc) ->
@@ -2115,88 +2070,88 @@ otp_7738_waiting(doc) ->
otp_7738_waiting(suite) ->
[];
otp_7738_waiting(Config) when is_list(Config) ->
- ?line otp_7738_test(waiting).
+ otp_7738_test(waiting).
otp_7738_suspended(doc) ->
[];
otp_7738_suspended(suite) ->
[];
otp_7738_suspended(Config) when is_list(Config) ->
- ?line otp_7738_test(suspended).
+ otp_7738_test(suspended).
otp_7738_resume(doc) ->
[];
otp_7738_resume(suite) ->
[];
otp_7738_resume(Config) when is_list(Config) ->
- ?line otp_7738_test(resume).
+ otp_7738_test(resume).
otp_7738_test(Type) ->
- ?line T = self(),
- ?line S = spawn_link(fun () ->
- receive
- {suspend, Suspendee} ->
- erlang:suspend_process(Suspendee),
- T ! {suspended, Suspendee},
- receive
- after 10 ->
- erlang:resume_process(Suspendee),
- Suspendee ! wake_up
- end;
- {send, To, Msg} ->
- receive after 10 -> ok end,
- To ! Msg
- end
- end),
- ?line R = spawn_link(fun () ->
- X = lists:seq(1, 20000000),
- T ! {initialized, self()},
- ?line case Type of
- _ when Type == suspended;
- Type == waiting ->
- receive _ -> ok end;
- _ when Type == resume ->
- Receive = fun (F) ->
- receive
- _ ->
- ok
- after 0 ->
- F(F)
- end
- end,
- Receive(Receive)
- end,
- T ! {woke_up, self()},
- id(X)
- end),
- ?line receive {initialized, R} -> ok end,
- ?line receive after 10 -> ok end,
- ?line case Type of
+ T = self(),
+ S = spawn_link(fun () ->
+ receive
+ {suspend, Suspendee} ->
+ erlang:suspend_process(Suspendee),
+ T ! {suspended, Suspendee},
+ receive
+ after 10 ->
+ erlang:resume_process(Suspendee),
+ Suspendee ! wake_up
+ end;
+ {send, To, Msg} ->
+ receive after 10 -> ok end,
+ To ! Msg
+ end
+ end),
+ R = spawn_link(fun () ->
+ X = lists:seq(1, 20000000),
+ T ! {initialized, self()},
+ case Type of
+ _ when Type == suspended;
+ Type == waiting ->
+ receive _ -> ok end;
+ _ when Type == resume ->
+ Receive = fun (F) ->
+ receive
+ _ ->
+ ok
+ after 0 ->
+ F(F)
+ end
+ end,
+ Receive(Receive)
+ end,
+ T ! {woke_up, self()},
+ id(X)
+ end),
+ receive {initialized, R} -> ok end,
+ receive after 10 -> ok end,
+ case Type of
suspended ->
- ?line erlang:suspend_process(R),
- ?line S ! {send, R, wake_up};
+ erlang:suspend_process(R),
+ S ! {send, R, wake_up};
waiting ->
- ?line S ! {send, R, wake_up};
+ S ! {send, R, wake_up};
resume ->
- ?line S ! {suspend, R},
- ?line receive {suspended, R} -> ok end
+ S ! {suspend, R},
+ receive {suspended, R} -> ok end
end,
- ?line erlang:garbage_collect(R),
- ?line case Type of
+ erlang:garbage_collect(R),
+ case Type of
suspended ->
- ?line erlang:resume_process(R);
+ erlang:resume_process(R);
_ ->
- ?line ok
+ ok
end,
- ?line receive
+ receive
{woke_up, R} ->
- ?line ok
+ ok
after 2000 ->
- ?line I = process_info(R, [status, message_queue_len]),
- ?line ?t:format("~p~n", [I]),
- ?line ?t:fail(no_progress)
+ I = process_info(R, [status, message_queue_len]),
+ ?t:format("~p~n", [I]),
+ ?t:fail(no_progress)
end,
- ?line ok.
+ ok.
gor(Reds, Stop) ->
receive
@@ -2210,28 +2165,28 @@ gor(Reds, Stop) ->
end.
garb_other_running(Config) when is_list(Config) ->
- ?line Stop = make_ref(),
- ?line {Pid, Mon} = spawn_monitor(fun () -> gor(0, Stop) end),
- ?line Reds = lists:foldl(fun (_, OldReds) ->
- ?line erlang:garbage_collect(Pid),
- ?line receive after 1 -> ok end,
- ?line Pid ! {self(), reds},
- ?line receive
+ Stop = make_ref(),
+ {Pid, Mon} = spawn_monitor(fun () -> gor(0, Stop) end),
+ Reds = lists:foldl(fun (_, OldReds) ->
+ erlang:garbage_collect(Pid),
+ receive after 1 -> ok end,
+ Pid ! {self(), reds},
+ receive
{reds, NewReds, Pid} ->
- ?line true = (NewReds > OldReds),
- ?line NewReds
+ true = (NewReds > OldReds),
+ NewReds
end
end,
0,
lists:seq(1, 10000)),
- ?line receive after 1 -> ok end,
- ?line Pid ! {self(), Stop},
- ?line receive
+ receive after 1 -> ok end,
+ Pid ! {self(), Stop},
+ receive
{stopped, Stop, StopReds, Pid} ->
- ?line true = (StopReds > Reds)
+ true = (StopReds > Reds)
end,
- ?line receive {'DOWN', Mon, process, Pid, normal} -> ok end,
- ?line ok.
+ receive {'DOWN', Mon, process, Pid, normal} -> ok end,
+ ok.
%% Internal functions
@@ -2255,9 +2210,9 @@ start_node(Config) ->
start_node(Config, "").
start_node(Config, Args) when is_list(Config) ->
- ?line Pa = filename:dirname(code:which(?MODULE)),
- ?line {A, B, C} = now(),
- ?line Name = list_to_atom(atom_to_list(?MODULE)
+ Pa = filename:dirname(code:which(?MODULE)),
+ {A, B, C} = now(),
+ Name = list_to_atom(atom_to_list(?MODULE)
++ "-"
++ atom_to_list(?config(testcase, Config))
++ "-"
@@ -2266,7 +2221,7 @@ start_node(Config, Args) when is_list(Config) ->
++ integer_to_list(B)
++ "-"
++ integer_to_list(C)),
- ?line ?t:start_node(Name, slave, [{args, "-pa "++Pa++" "++Args}]).
+ ?t:start_node(Name, slave, [{args, "-pa "++Pa++" "++Args}]).
stop_node(Node) ->
?t:stop_node(Node).
diff --git a/erts/emulator/test/save_calls_SUITE.erl b/erts/emulator/test/save_calls_SUITE.erl
index 390b49b604..26ac4f2f7f 100644
--- a/erts/emulator/test/save_calls_SUITE.erl
+++ b/erts/emulator/test/save_calls_SUITE.erl
@@ -21,8 +21,10 @@
-include_lib("test_server/include/test_server.hrl").
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2]).
+-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([save_calls_1/1,dont_break_reductions/1]).
@@ -48,6 +50,27 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
+init_per_testcase(dont_break_reductions,Config) ->
+ %% Skip on --enable-native-libs as hipe rescedules after each
+ %% function call.
+ case erlang:system_info(hipe_architecture) of
+ undefined ->
+ Config;
+ Architecture ->
+ {lists, ListsBinary, _ListsFilename} = code:get_object_code(lists),
+ ChunkName = hipe_unified_loader:chunk_name(Architecture),
+ NativeChunk = beam_lib:chunks(ListsBinary, [ChunkName]),
+ case NativeChunk of
+ {ok,{_,[{_,Bin}]}} when is_binary(Bin) ->
+ {skip,"Does not work for --enable-native-libs"};
+ {error, beam_lib, _} -> Config
+ end
+ end;
+init_per_testcase(_,Config) ->
+ Config.
+
+end_per_testcase(_,_Config) ->
+ ok.
dont_break_reductions(suite) ->
[];
diff --git a/erts/emulator/test/smoke_test_SUITE.erl b/erts/emulator/test/smoke_test_SUITE.erl
index 98f1cf1ad5..6f5c2080c0 100644
--- a/erts/emulator/test/smoke_test_SUITE.erl
+++ b/erts/emulator/test/smoke_test_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -51,7 +51,17 @@ end_per_group(_GroupName, Config) ->
Config.
+init_per_testcase(boot_combo = Case, Config) when is_list(Config) ->
+ case erlang:system_info(build_type) of
+ opt ->
+ init_per_tc(Case, Config);
+ _ ->
+ {skip,"Cannot test boot_combo in special builds since beam.* may not exist"}
+ end;
init_per_testcase(Case, Config) when is_list(Config) ->
+ init_per_tc(Case, Config).
+
+init_per_tc(Case, Config) ->
Dog = ?t:timetrap(?DEFAULT_TIMEOUT),
[{testcase, Case},{watchdog, Dog}|Config].
@@ -121,18 +131,19 @@ start_node(Config) ->
start_node(Config, "").
start_node(Config, Args) when is_list(Config) ->
- ?line Pa = filename:dirname(code:which(?MODULE)),
- ?line {A, B, C} = now(),
- ?line Name = list_to_atom(atom_to_list(?MODULE)
- ++ "-"
- ++ atom_to_list(?config(testcase, Config))
- ++ "-"
- ++ integer_to_list(A)
- ++ "-"
- ++ integer_to_list(B)
- ++ "-"
- ++ integer_to_list(C)),
- ?line ?t:start_node(Name, slave, [{args, "-pa "++Pa++" "++Args}]).
+ Pa = filename:dirname(code:which(?MODULE)),
+ {A, B, C} = now(),
+ Name = list_to_atom(atom_to_list(?MODULE)
+ ++ "-"
+ ++ atom_to_list(?config(testcase, Config))
+ ++ "-"
+ ++ integer_to_list(A)
+ ++ "-"
+ ++ integer_to_list(B)
+ ++ "-"
+ ++ integer_to_list(C)),
+ Opts = [{args, "-pa "++Pa++" "++Args}],
+ ?t:start_node(Name, slave, Opts).
stop_node(Node) ->
?t:stop_node(Node).
diff --git a/erts/emulator/test/trace_local_SUITE.erl b/erts/emulator/test/trace_local_SUITE.erl
index 1e0705fabe..b89a8c4a0e 100644
--- a/erts/emulator/test/trace_local_SUITE.erl
+++ b/erts/emulator/test/trace_local_SUITE.erl
@@ -874,7 +874,7 @@ exception_test(Opts, Func0, Args0) ->
%% wrap them in wrappers...
?line {Func1,Args1} =
case Function of
- true -> {fun exc/2,[Func0,Args0]};
+ true -> {fun (F, As) -> exc(F, As) end,[Func0,Args0]};
false -> {Func0,Args0}
end,
diff --git a/erts/emulator/test/tuple_SUITE.erl b/erts/emulator/test/tuple_SUITE.erl
index bfc3910742..a3b2764a5d 100644
--- a/erts/emulator/test/tuple_SUITE.erl
+++ b/erts/emulator/test/tuple_SUITE.erl
@@ -20,6 +20,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
t_size/1, t_tuple_size/1, t_element/1, t_setelement/1,
+ t_insert_element/1, t_delete_element/1,
t_list_to_tuple/1, t_tuple_to_list/1,
t_make_tuple_2/1, t_make_tuple_3/1, t_append_element/1,
build_and_match/1, tuple_with_case/1, tuple_in_guard/1]).
@@ -41,6 +42,7 @@ all() ->
[build_and_match, t_size, t_tuple_size, t_list_to_tuple,
t_tuple_to_list, t_element, t_setelement,
t_make_tuple_2, t_make_tuple_3, t_append_element,
+ t_insert_element, t_delete_element,
tuple_with_case, tuple_in_guard].
groups() ->
@@ -60,40 +62,40 @@ end_per_group(_GroupName, Config) ->
build_and_match(Config) when is_list(Config) ->
- ?line {} = id({}),
- ?line {1} = id({1}),
- ?line {1, 2} = id({1, 2}),
- ?line {1, 2, 3} = id({1, 2, 3}),
- ?line {1, 2, 3, 4} = id({1, 2, 3, 4}),
- ?line {1, 2, 3, 4, 5} = id({1, 2, 3, 4, 5}),
- ?line {1, 2, 3, 4, 5, 6} = id({1, 2, 3, 4, 5, 6}),
- ?line {1, 2, 3, 4, 5, 6} = id({1, 2, 3, 4, 5, 6}),
- ?line {1, 2, 3, 4, 5, 6, 7} = id({1, 2, 3, 4, 5, 6, 7}),
- ?line {1, 2, 3, 4, 5, 6, 7, 8} = id({1, 2, 3, 4, 5, 6, 7, 8}),
+ {} = id({}),
+ {1} = id({1}),
+ {1, 2} = id({1, 2}),
+ {1, 2, 3} = id({1, 2, 3}),
+ {1, 2, 3, 4} = id({1, 2, 3, 4}),
+ {1, 2, 3, 4, 5} = id({1, 2, 3, 4, 5}),
+ {1, 2, 3, 4, 5, 6} = id({1, 2, 3, 4, 5, 6}),
+ {1, 2, 3, 4, 5, 6} = id({1, 2, 3, 4, 5, 6}),
+ {1, 2, 3, 4, 5, 6, 7} = id({1, 2, 3, 4, 5, 6, 7}),
+ {1, 2, 3, 4, 5, 6, 7, 8} = id({1, 2, 3, 4, 5, 6, 7, 8}),
ok.
%% Tests size(Tuple).
t_size(Config) when is_list(Config) ->
- ?line 0 = size({}),
- ?line 1 = size({a}),
- ?line 1 = size({{a}}),
- ?line 2 = size({{a}, {b}}),
- ?line 3 = size({1, 2, 3}),
+ 0 = size({}),
+ 1 = size({a}),
+ 1 = size({{a}}),
+ 2 = size({{a}, {b}}),
+ 3 = size({1, 2, 3}),
ok.
t_tuple_size(Config) when is_list(Config) ->
- ?line 0 = tuple_size(id({})),
- ?line 1 = tuple_size(id({a})),
- ?line 1 = tuple_size(id({{a}})),
- ?line 2 = tuple_size(id({{a},{b}})),
- ?line 3 = tuple_size(id({1,2,3})),
+ 0 = tuple_size(id({})),
+ 1 = tuple_size(id({a})),
+ 1 = tuple_size(id({{a}})),
+ 2 = tuple_size(id({{a},{b}})),
+ 3 = tuple_size(id({1,2,3})),
%% Error cases.
- ?line {'EXIT',{badarg,_}} = (catch tuple_size([])),
- ?line {'EXIT',{badarg,_}} = (catch tuple_size(<<1,2,3>>)),
- ?line error = ludicrous_tuple_size({a,b,c}),
- ?line error = ludicrous_tuple_size([a,b,c]),
+ {'EXIT',{badarg,_}} = (catch tuple_size([])),
+ {'EXIT',{badarg,_}} = (catch tuple_size(<<1,2,3>>)),
+ error = ludicrous_tuple_size({a,b,c}),
+ error = ludicrous_tuple_size([a,b,c]),
ok.
@@ -104,44 +106,44 @@ ludicrous_tuple_size(_) -> error.
%% Tests element/2.
t_element(Config) when is_list(Config) ->
- ?line a = element(1, {a}),
- ?line a = element(1, {a, b}),
+ a = element(1, {a}),
+ a = element(1, {a, b}),
- ?line List = lists:seq(1, 4096),
- ?line Tuple = list_to_tuple(lists:seq(1, 4096)),
- ?line get_elements(List, Tuple, 1),
+ List = lists:seq(1, 4096),
+ Tuple = list_to_tuple(lists:seq(1, 4096)),
+ get_elements(List, Tuple, 1),
- ?line {'EXIT', {badarg, _}} = (catch element(0, id({a,b}))),
- ?line {'EXIT', {badarg, _}} = (catch element(3, id({a,b}))),
- ?line {'EXIT', {badarg, _}} = (catch element(1, id({}))),
- ?line {'EXIT', {badarg, _}} = (catch element(1, id([a,b]))),
- ?line {'EXIT', {badarg, _}} = (catch element(1, id(42))),
- ?line {'EXIT', {badarg, _}} = (catch element(id(1.5), id({a,b}))),
+ {'EXIT', {badarg, _}} = (catch element(0, id({a,b}))),
+ {'EXIT', {badarg, _}} = (catch element(3, id({a,b}))),
+ {'EXIT', {badarg, _}} = (catch element(1, id({}))),
+ {'EXIT', {badarg, _}} = (catch element(1, id([a,b]))),
+ {'EXIT', {badarg, _}} = (catch element(1, id(42))),
+ {'EXIT', {badarg, _}} = (catch element(id(1.5), id({a,b}))),
ok.
get_elements([Element|Rest], Tuple, Pos) ->
- ?line Element = element(Pos, Tuple),
- ?line get_elements(Rest, Tuple, Pos+1);
+ Element = element(Pos, Tuple),
+ get_elements(Rest, Tuple, Pos+1);
get_elements([], _Tuple, _Pos) ->
ok.
%% Tests set_element/3.
t_setelement(Config) when is_list(Config) ->
- ?line {x} = setelement(1, id({1}), x),
- ?line {x,2} = setelement(1, id({1,2}), x),
- ?line {1,x} = setelement(2, id({1,2}), x),
+ {x} = setelement(1, id({1}), x),
+ {x,2} = setelement(1, id({1,2}), x),
+ {1,x} = setelement(2, id({1,2}), x),
- ?line Tuple = list_to_tuple(lists:duplicate(2048, x)),
- ?line NewTuple = set_all_elements(Tuple, 1),
- ?line NewTuple = list_to_tuple(lists:seq(1+7, 2048+7)),
+ Tuple = list_to_tuple(lists:duplicate(2048, x)),
+ NewTuple = set_all_elements(Tuple, 1),
+ NewTuple = list_to_tuple(lists:seq(1+7, 2048+7)),
- ?line {'EXIT', {badarg, _}} = (catch setelement(0, {a, b}, x)),
- ?line {'EXIT', {badarg, _}} = (catch setelement(3, {a, b}, x)),
- ?line {'EXIT', {badarg, _}} = (catch setelement(1, {}, x)),
- ?line {'EXIT', {badarg, _}} = (catch setelement(1, [a, b], x)),
- ?line {'EXIT', {badarg, _}} = (catch setelement(1.5, {a, b}, x)),
+ {'EXIT', {badarg, _}} = (catch setelement(0, {a, b}, x)),
+ {'EXIT', {badarg, _}} = (catch setelement(3, {a, b}, x)),
+ {'EXIT', {badarg, _}} = (catch setelement(1, {}, x)),
+ {'EXIT', {badarg, _}} = (catch setelement(1, [a, b], x)),
+ {'EXIT', {badarg, _}} = (catch setelement(1.5, {a, b}, x)),
%% Nested setelement with literals.
AnotherTuple = id({0,0,a,b,c}),
@@ -159,52 +161,68 @@ set_all_elements(Tuple, Pos) when Pos > size(Tuple) ->
%% Tests list_to_tuple/1.
t_list_to_tuple(Config) when is_list(Config) ->
- ?line {} = list_to_tuple([]),
- ?line {a} = list_to_tuple([a]),
- ?line {a, b} = list_to_tuple([a, b]),
- ?line {a, b, c} = list_to_tuple([a, b, c]),
- ?line {a, b, c, d} = list_to_tuple([a, b, c, d]),
- ?line {a, b, c, d, e} = list_to_tuple([a, b, c, d, e]),
-
- ?line Size = 4096,
- ?line Tuple = list_to_tuple(lists:seq(1, Size)),
- ?line Size = size(Tuple),
-
- ?line {'EXIT', {badarg, _}} = (catch list_to_tuple(id({a,b}))),
- ?line {'EXIT', {badarg, _}} = (catch list_to_tuple(id([a|b]))),
- ?line {'EXIT', {badarg, _}} = (catch list_to_tuple(id([a|b]))),
-
+ {} = list_to_tuple([]),
+ {a} = list_to_tuple([a]),
+ {a, b} = list_to_tuple([a, b]),
+ {a, b, c} = list_to_tuple([a, b, c]),
+ {a, b, c, d} = list_to_tuple([a, b, c, d]),
+ {a, b, c, d, e} = list_to_tuple([a, b, c, d, e]),
+
+ Size = 4096,
+ Tuple = list_to_tuple(lists:seq(1, Size)),
+ Size = size(Tuple),
+
+ {'EXIT', {badarg, _}} = (catch list_to_tuple(id({a,b}))),
+ {'EXIT', {badarg, _}} = (catch list_to_tuple(id([a|b]))),
+ {'EXIT', {badarg, _}} = (catch list_to_tuple(id([a|b]))),
+
+ % test upper boundry, 16777215 elements
+ MaxSize = 1 bsl 24 - 1,
+ MaxTuple = list_to_tuple(lists:seq(1, MaxSize)),
+ MaxSize = size(MaxTuple),
+
+ {'EXIT', {badarg,_}} = (catch list_to_tuple(lists:seq(1, 1 bsl 24))),
ok.
%% Tests tuple_to_list/1.
t_tuple_to_list(Config) when is_list(Config) ->
- ?line [] = tuple_to_list({}),
- ?line [a] = tuple_to_list({a}),
- ?line [a, b] = tuple_to_list({a, b}),
- ?line [a, b, c] = tuple_to_list({a, b, c}),
- ?line [a, b, c, d] = tuple_to_list({a, b, c, d}),
- ?line [a, b, c, d] = tuple_to_list({a, b, c, d}),
-
- ?line Size = 4096,
- ?line List = lists:seq(1, Size),
- ?line Tuple = list_to_tuple(List),
- ?line Size = size(Tuple),
- ?line List = tuple_to_list(Tuple),
-
- ?line {'EXIT', {badarg,_}} = (catch tuple_to_list(id(a))),
- ?line {'EXIT', {badarg,_}} = (catch tuple_to_list(id(42))),
+ [] = tuple_to_list({}),
+ [a] = tuple_to_list({a}),
+ [a, b] = tuple_to_list({a, b}),
+ [a, b, c] = tuple_to_list({a, b, c}),
+ [a, b, c, d] = tuple_to_list({a, b, c, d}),
+ [a, b, c, d] = tuple_to_list({a, b, c, d}),
+
+ Size = 4096,
+ List = lists:seq(1, Size),
+ Tuple = list_to_tuple(List),
+ Size = size(Tuple),
+ List = tuple_to_list(Tuple),
+
+ {'EXIT', {badarg,_}} = (catch tuple_to_list(id(a))),
+ {'EXIT', {badarg,_}} = (catch tuple_to_list(id(42))),
ok.
%% Tests the make_tuple/2 BIF.
t_make_tuple_2(Config) when is_list(Config) ->
- ?line t_make_tuple1([]),
- ?line t_make_tuple1(42),
- ?line t_make_tuple1(a),
- ?line t_make_tuple1({}),
- ?line t_make_tuple1({a}),
- ?line t_make_tuple1(erlang:make_tuple(400, [])),
+ t_make_tuple1([]),
+ t_make_tuple1(42),
+ t_make_tuple1(a),
+ t_make_tuple1({}),
+ t_make_tuple1({a}),
+ t_make_tuple1(erlang:make_tuple(400, [])),
+
+ % test upper boundry, 16777215 elements
+ t_make_tuple(1 bsl 24 - 1, a),
+ {'EXIT', {badarg,_}} = (catch erlang:make_tuple(1 bsl 24, a)),
+
+ {'EXIT', {badarg,_}} = (catch erlang:make_tuple(-1, a)),
+ % 26 bits is the total header arity room (for now)
+ {'EXIT', {badarg,_}} = (catch erlang:make_tuple(1 bsl 26 + 3, a)),
+ % bignum
+ {'EXIT', {badarg,_}} = (catch erlang:make_tuple(1 bsl 65 + 3, a)),
ok.
t_make_tuple1(Element) ->
@@ -222,29 +240,82 @@ t_make_tuple(Size, Element) ->
%% Tests the erlang:make_tuple/3 BIF.
t_make_tuple_3(Config) when is_list(Config) ->
- ?line {} = erlang:make_tuple(0, def, []),
- ?line {def} = erlang:make_tuple(1, def, []),
- ?line {a} = erlang:make_tuple(1, def, [{1,a}]),
- ?line {a,def,c,def,e} = erlang:make_tuple(5, def, [{5,e},{1,a},{3,c}]),
- ?line {a,def,c,def,e} = erlang:make_tuple(5, def,
- [{1,blurf},{5,e},{3,blurf},
- {1,a},{3,c}]),
+ {} = erlang:make_tuple(0, def, []),
+ {def} = erlang:make_tuple(1, def, []),
+ {a} = erlang:make_tuple(1, def, [{1,a}]),
+
+ {a,def,c,def,e} = erlang:make_tuple(5, def, [{5,e},{1,a},{3,c}]),
+ {a,def,c,def,e} = erlang:make_tuple(5, def, [{1,blurf},{5,e},{3,blurf},{1,a},{3,c}]),
+ MaxSize = 1 bsl 16 - 1,
+ MaxTuple = erlang:make_tuple(MaxSize, def, [{1,blurf},{5,e},{3,blurf},{1,a},{3,c}]),
+ MaxSize = size(MaxTuple),
+
+ %% Error cases.
+ {'EXIT',{badarg,_}} = (catch erlang:make_tuple(0, def, [{1,a}])),
+ {'EXIT',{badarg,_}} = (catch erlang:make_tuple(5, def, [{-1,a}])),
+ {'EXIT',{badarg,_}} = (catch erlang:make_tuple(5, def, [{0,a}])),
+ {'EXIT',{badarg,_}} = (catch erlang:make_tuple(5, def, [{6,z}])),
+ {'EXIT',{badarg,_}} = (catch erlang:make_tuple(a, def, [{6,z}])),
+ {'EXIT',{badarg,_}} = (catch erlang:make_tuple(5, def, [{1,a}|b])),
+ {'EXIT',{badarg,_}} = (catch erlang:make_tuple(5, def, [42])),
+ {'EXIT',{badarg,_}} = (catch erlang:make_tuple(5, def, [[a,b,c]])),
+ {'EXIT',{badarg,_}} = (catch erlang:make_tuple(5, def, non_list)),
+ {'EXIT',{badarg,_}} = (catch erlang:make_tuple(1 bsl 24, def, [{5,e},{1,a},{3,c}])),
+
+ ok.
+
+%% Tests the erlang:insert_element/3 BIF.
+t_insert_element(Config) when is_list(Config) ->
+ {a} = erlang:insert_element(1, {}, a),
+ {{b,b},a} = erlang:insert_element(1, {a}, {b,b}),
+ {a,b} = erlang:insert_element(2, {a}, b),
+ [b,def|_] = tuple_to_list(erlang:insert_element(1, erlang:make_tuple(1 bsl 20, def), b)),
+ [def,b|_] = tuple_to_list(erlang:insert_element(2, erlang:make_tuple(1 bsl 20, def), b)),
+ [def,b|_] = lists:reverse(tuple_to_list(erlang:insert_element(1 bsl 20, erlang:make_tuple(1 bsl 20, def), b))),
+ [b,def|_] = lists:reverse(tuple_to_list(erlang:insert_element((1 bsl 20) + 1, erlang:make_tuple(1 bsl 20, def), b))),
+
+ %% Error cases.
+ {'EXIT',{badarg,_}} = (catch erlang:insert_element(1, [], a)),
+ {'EXIT',{badarg,_}} = (catch erlang:insert_element(1, a, a)),
+ {'EXIT',{badarg,_}} = (catch erlang:insert_element(0, {}, a)),
+ {'EXIT',{badarg,_}} = (catch erlang:insert_element(0, {b,b,b,b,b}, a)),
+ {'EXIT',{badarg,_}} = (catch erlang:insert_element(-1, {}, a)),
+ {'EXIT',{badarg,_}} = (catch erlang:insert_element(2, {}, a)),
+ {'EXIT',{badarg,_}} = (catch erlang:insert_element(6, {b,b,b,b}, a)),
+ {'EXIT',{badarg,_}} = (catch erlang:insert_element(1 bsl 20, {b,b,b,b}, a)),
+ ok.
+
+%% Tests the erlang:delete_element/3 BIF.
+t_delete_element(Config) when is_list(Config) ->
+ {} = erlang:delete_element(1, {a}),
+ {{b,b},c} = erlang:delete_element(1, {a,{b,b},c}),
+ {a,b} = erlang:delete_element(2, {a,c,b}),
+ [2,3|_] = tuple_to_list(erlang:delete_element(1, list_to_tuple(lists:seq(1, 1 bsl 20)))),
+ [1,3|_] = tuple_to_list(erlang:delete_element(2, list_to_tuple(lists:seq(1, 1 bsl 20)))),
+ [(1 bsl 20) - 1, (1 bsl 20) - 2 |_] = lists:reverse(tuple_to_list(erlang:delete_element(1 bsl 20, list_to_tuple(lists:seq(1, 1 bsl 20))))),
+ [(1 bsl 20), (1 bsl 20) - 2 |_] = lists:reverse(tuple_to_list(erlang:delete_element((1 bsl 20) - 1, list_to_tuple(lists:seq(1, 1 bsl 20))))),
%% Error cases.
- ?line {'EXIT',{badarg,_}} = (catch erlang:make_tuple(0, def, [{1,a}])),
- ?line {'EXIT',{badarg,_}} = (catch erlang:make_tuple(5, def, [{-1,a}])),
- ?line {'EXIT',{badarg,_}} = (catch erlang:make_tuple(5, def, [{0,a}])),
- ?line {'EXIT',{badarg,_}} = (catch erlang:make_tuple(5, def, [{6,z}])),
- ?line {'EXIT',{badarg,_}} = (catch erlang:make_tuple(a, def, [{6,z}])),
- ?line {'EXIT',{badarg,_}} = (catch erlang:make_tuple(5, def, [{1,a}|b])),
- ?line {'EXIT',{badarg,_}} = (catch erlang:make_tuple(5, def, [42])),
- ?line {'EXIT',{badarg,_}} = (catch erlang:make_tuple(5, def, [[a,b,c]])),
- ?line {'EXIT',{badarg,_}} = (catch erlang:make_tuple(5, def, non_list)),
+ {'EXIT',{badarg,_}} = (catch erlang:delete_element(1, [])),
+ {'EXIT',{badarg,_}} = (catch erlang:delete_element(1, a)),
+ {'EXIT',{badarg,_}} = (catch erlang:delete_element(0, {})),
+ {'EXIT',{badarg,_}} = (catch erlang:delete_element(-1, {})),
+ {'EXIT',{badarg,_}} = (catch erlang:delete_element(1, {})),
+ {'EXIT',{badarg,_}} = (catch erlang:delete_element(0, {b,b,b,b,b})),
+ {'EXIT',{badarg,_}} = (catch erlang:delete_element(5, {b,b,b,b})),
+ {'EXIT',{badarg,_}} = (catch erlang:delete_element(1 bsl 20, {b,c,b,b,b})),
ok.
+
%% Tests the append_element/2 BIF.
t_append_element(Config) when is_list(Config) ->
- t_append_element({}, 2048, 2048).
+ ok = t_append_element({}, 2048, 2048),
+
+ % test upper boundry, 16777215 elements
+ MaxSize = 1 bsl 24 - 1,
+ MaxTuple = list_to_tuple(lists:seq(1, MaxSize)),
+ {'EXIT',{badarg,_}} = (catch erlang:append_element(MaxTuple, a)),
+ ok.
t_append_element(_Tuple, 0, _High) -> ok;
t_append_element(Tuple, N, High) ->
@@ -261,7 +332,7 @@ verify_seq([High|T], High, Lower) ->
%% (This is known to crash earlier versions of BEAM.)
tuple_with_case(Config) when is_list(Config) ->
- ?line {reply, true} = tuple_with_case(),
+ {reply, true} = tuple_with_case(),
ok.
tuple_with_case() ->
@@ -280,21 +351,21 @@ foo() -> ignored.
%% Test to build a tuple in a guard.
tuple_in_guard(Config) when is_list(Config) ->
- ?line Tuple1 = id({a,b}),
- ?line Tuple2 = id({a,b,c}),
- ?line if
- Tuple1 == {element(1, Tuple2),element(2, Tuple2)} ->
- ok;
- true ->
- ?line test_server:fail()
- end,
- ?line if
- Tuple2 == {element(1, Tuple2),element(2, Tuple2),
- element(3, Tuple2)} ->
- ok;
- true ->
- ?line test_server:fail()
- end,
+ Tuple1 = id({a,b}),
+ Tuple2 = id({a,b,c}),
+ if
+ Tuple1 == {element(1, Tuple2),element(2, Tuple2)} ->
+ ok;
+ true ->
+ test_server:fail()
+ end,
+ if
+ Tuple2 == {element(1, Tuple2),element(2, Tuple2),
+ element(3, Tuple2)} ->
+ ok;
+ true ->
+ test_server:fail()
+ end,
ok.
%% Use this function to avoid compile-time evaluation of an expression.
diff --git a/erts/emulator/utils/beam_makeops b/erts/emulator/utils/beam_makeops
index 8fe2402ca8..16a949c2a6 100755
--- a/erts/emulator/utils/beam_makeops
+++ b/erts/emulator/utils/beam_makeops
@@ -1,4 +1,4 @@
-#!/usr/bin/env perl
+#!/usr/bin/env perl -W
#
# %CopyrightBegin%
#
@@ -362,7 +362,7 @@ while (<>) {
$gen_to_spec{"$name/$arity"} = undef;
$num_specific{"$name/$arity"} = 0;
$min_window{"$name/$arity"} = 255;
- $obsolete[$op_num] = $obsolete eq '-';
+ $obsolete[$op_num] = defined $obsolete;
} else { # Unnumbered generic operation.
push(@unnumbered_generic, [$name, $arity]);
$unnumbered{$name,$arity} = 1;
@@ -379,7 +379,7 @@ while (<>) {
if @args > $max_spec_operands;
&syntax_check($name, @args);
my $arity = @args;
- if ($obsolete[$gen_opnum{$name,$arity}]) {
+ if (defined $gen_opnum{$name,$arity} and $obsolete[$gen_opnum{$name,$arity}]) {
error("specific instructions may not be specified for obsolete instructions");
}
push(@{$specific_op{"$name/$arity"}}, [$name, $hot, @args]);
@@ -810,8 +810,8 @@ sub compiler_output {
#
# Generate .hrl file.
#
- my($name) = "$outdir/${module}.hrl";
- open(STDOUT, ">$name") || die "Failed to open $name for writing: $!\n";
+ my($hrl_name) = "$outdir/${module}.hrl";
+ open(STDOUT, ">$hrl_name") || die "Failed to open $hrl_name for writing: $!\n";
&comment('erlang');
for ($i = 0; $i < @tag_type && $i < 8; $i++) {
@@ -1251,8 +1251,8 @@ sub compile_transform {
$arity++ unless $list[1] eq '*';
$_ = [ @list ];
}
-
- if ($obsolete[$gen_opnum{$name,$arity}]) {
+
+ if (defined $gen_opnum{$name,$arity} && $obsolete[$gen_opnum{$name,$arity}]) {
error("obsolete function must not be used in transformations");
}
@@ -1704,14 +1704,15 @@ sub tr_gen_to {
#
my($first_ref) = shift(@code);
my($size, $first, $key) = @$first_ref;
- my($dummy, $op, $arity) = @$first;
+ my($dummy, $arity);
+ ($dummy, $op, $arity) = @$first;
my($comment) = "\n/*\n * Line $line:\n * $orig_transform\n */\n\n";
$min_window{$key} = $min_window
if $min_window{$key} > $min_window;
my $prev_last;
$prev_last = pop(@{$gen_transform{$key}})
- if defined @{$gen_transform{$key}}; # Fail
+ if defined $gen_transform{$key}; # Fail
if ($prev_last && !is_instr($prev_last, 'fail')) {
error("Line $line: A previous transformation shadows '$orig_transform'");
@@ -1719,7 +1720,7 @@ sub tr_gen_to {
unless ($cannot_fail) {
unshift(@code, make_op('', 'try_me_else',
tr_code_len(@code)));
- push(@code, make_op(""), make_op("$key", 'fail'));
+ push(@code, make_op("$key", 'fail'));
}
unshift(@code, make_op($comment));
push(@{$gen_transform{$key}}, @code),
diff --git a/erts/emulator/valgrind/suppress.halfword b/erts/emulator/valgrind/suppress.halfword
new file mode 100644
index 0000000000..8fe448d897
--- /dev/null
+++ b/erts/emulator/valgrind/suppress.halfword
@@ -0,0 +1,56 @@
+# Extra suppressions specific for the halfword emulator.
+
+# --- Suppress all offheap binaries ---
+# Valgrinds leak check does not recognize pointers that are stored
+# at unaligned addresses. In halfword emulator we store 64-bit pointers
+# to offheap data on 32-bit aligned heaps.
+# We solve this by suppressing allocation of all offheap structures
+# that are not referenced by other tables (ie binaries).
+
+{
+Halfword erts_bin_nrml_alloc
+Memcheck:Leak
+...
+fun:erts_bin_nrml_alloc
+...
+}
+
+{
+Halfword erts_bin_realloc
+Memcheck:Leak
+...
+fun:erts_bin_realloc
+...
+}
+
+{
+Halfword erts_bin_realloc_fnf
+Memcheck:Leak
+...
+fun:erts_bin_realloc_fnf
+...
+}
+
+{
+Halfword erts_bin_drv_alloc
+Memcheck:Leak
+...
+fun:erts_bin_drv_alloc
+...
+}
+
+{
+Halfword erts_bin_drv_alloc_fnf
+Memcheck:Leak
+...
+fun:erts_bin_drv_alloc_fnf
+...
+}
+
+{
+Halfword erts_create_magic_binary
+Memcheck:Leak
+...
+fun:erts_create_magic_binary
+...
+}
diff --git a/erts/emulator/valgrind/suppress.patched.3.6.0 b/erts/emulator/valgrind/suppress.patched.3.6.0
index 62ba032520..b3507bdba7 100644
--- a/erts/emulator/valgrind/suppress.patched.3.6.0
+++ b/erts/emulator/valgrind/suppress.patched.3.6.0
@@ -133,26 +133,18 @@ fun:pthread_create@@GLIBC_2.2.5
{
zlib; ok according to zlib developers
Memcheck:Cond
-fun:longest_match
+...
fun:deflate_slow
fun:deflate
}
{
zlib; ok according to zlib developers
Memcheck:Cond
-fun:longest_match
+...
fun:deflate_fast
fun:deflate
}
{
-zlib; ok accordnig to zlib (this one popped up with valgrind-3.6.0)
-Memcheck:Cond
-fun:deflate_slow
-fun:deflate
-fun:zlib_deflate
-fun:zlib_ctl
-}
-{
No leak; pointer into block
Memcheck:Leak
fun:malloc
@@ -275,6 +267,14 @@ obj:*/ssleay.*
}
{
+ Harmless assembler bug in openssl
+ Memcheck:Addr8
+ ...
+ fun:AES_cbc_encrypt
+ ...
+}
+
+{
erts_bits_init_state; Why is this needed?
Memcheck:Leak
PossiblyLost
diff --git a/erts/emulator/valgrind/suppress.standard b/erts/emulator/valgrind/suppress.standard
index 5a129bfd10..beecf1a7b5 100644
--- a/erts/emulator/valgrind/suppress.standard
+++ b/erts/emulator/valgrind/suppress.standard
@@ -120,14 +120,14 @@ fun:pthread_create@@GLIBC_2.2.5
{
zlib; ok according to zlib developers
Memcheck:Cond
-fun:longest_match
+...
fun:deflate_slow
fun:deflate
}
{
zlib; ok according to zlib developers
Memcheck:Cond
-fun:longest_match
+...
fun:deflate_fast
fun:deflate
}
@@ -252,6 +252,14 @@ obj:*/ssleay.*
}
{
+ Harmless assembler bug in openssl
+ Memcheck:Addr8
+ ...
+ fun:AES_cbc_encrypt
+ ...
+}
+
+{
Prebuilt constant terms in os_info_init (PossiblyLost)
Memcheck:Leak
fun:malloc
diff --git a/erts/emulator/zlib/zlib.mk b/erts/emulator/zlib/zlib.mk
index fa1f159fae..ff5ffa5328 100644
--- a/erts/emulator/zlib/zlib.mk
+++ b/erts/emulator/zlib/zlib.mk
@@ -63,12 +63,12 @@ endif # gcov
ifeq ($(TARGET), win32)
$(ZLIB_LIBRARY): $(ZLIB_OBJS)
- $(AR) -out:$@ $(ZLIB_OBJS)
+ $(V_AR) -out:$@ $(ZLIB_OBJS)
else
$(ZLIB_LIBRARY): $(ZLIB_OBJS)
- $(AR) $(ARFLAGS) $@ $(ZLIB_OBJS)
+ $(V_AR) $(ARFLAGS) $@ $(ZLIB_OBJS)
-@ ($(RANLIB) $@ || true) 2>/dev/null
endif
$(ZLIB_OBJDIR)/%.o: zlib/%.c
- $(CC) -c $(ZLIB_CFLAGS) -o $@ $<
+ $(V_CC) -c $(ZLIB_CFLAGS) -o $@ $<
diff --git a/erts/epmd/src/Makefile.in b/erts/epmd/src/Makefile.in
index 577fc77c13..e94674e6f4 100644
--- a/erts/epmd/src/Makefile.in
+++ b/erts/epmd/src/Makefile.in
@@ -128,13 +128,13 @@ clean:
#
$(BINDIR)/$(EPMD): $(EPMD_OBJS) $(ERTS_LIB)
- $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(EPMD_OBJS) $(LIBS)
+ $(ld_verbose)$(PURIFY) $(LD) $(LDFLAGS) -o $@ $(EPMD_OBJS) $(LIBS)
$(OBJDIR)/%.o: %.c epmd.h epmd_int.h
- $(CC) $(CFLAGS) $(EPMD_FLAGS) -o $@ -c $<
+ $(V_CC) $(CFLAGS) $(EPMD_FLAGS) -o $@ -c $<
$(ERTS_LIB):
- cd $(ERL_TOP)/erts/lib_src && $(MAKE) $(TYPE)
+ $(make_verbose)cd $(ERL_TOP)/erts/lib_src && $(MAKE) $(TYPE)
include $(ERL_TOP)/make/otp_release_targets.mk
diff --git a/erts/etc/common/Makefile.in b/erts/etc/common/Makefile.in
index ea70946346..5c1ce51644 100644
--- a/erts/etc/common/Makefile.in
+++ b/erts/etc/common/Makefile.in
@@ -17,6 +17,7 @@
# %CopyrightEnd%
#
+include $(ERL_TOP)/make/output.mk
include $(ERL_TOP)/make/target.mk
ERTS_LIB_TYPEMARKER=.$(TYPE)
@@ -191,7 +192,7 @@ etc: $(ENTRY_OBJ) $(INSTALL_PROGS) $(INSTALL_LIBS) $(TEXTFILES) $(INSTALL_TOP_BI
# erlexec needs the erts_internal library...
$(ERTS_LIB):
- cd $(ERL_TOP)/erts/lib_src && $(MAKE) $(TYPE)
+ $(V_at)cd $(ERL_TOP)/erts/lib_src && $(MAKE) $(TYPE)
.PHONY: docs
docs:
@@ -249,23 +250,23 @@ endif
ifeq ($(TARGET),win32)
$(BINDIR)/$(ERLEXEC): $(OBJDIR)/erlexec.o $(OBJDIR)/win_erlexec.o $(OBJDIR)/init_file.o $(OBJDIR)/$(ERLRES_OBJ) $(ERTS_LIB)
- $(LD) -dll $(LDFLAGS) -o $@ $(OBJDIR)/erlexec.o $(OBJDIR)/win_erlexec.o $(OBJDIR)/init_file.o $(OBJDIR)/$(ERLRES_OBJ) $(ERTS_INTERNAL_LIBS)
+ $(V_LD) -dll $(LDFLAGS) -o $@ $(OBJDIR)/erlexec.o $(OBJDIR)/win_erlexec.o $(OBJDIR)/init_file.o $(OBJDIR)/$(ERLRES_OBJ) $(ERTS_INTERNAL_LIBS)
$(BINDIR)/erl@EXEEXT@: $(OBJDIR)/erl.o $(OBJDIR)/init_file.o $(OBJDIR)/$(ERLRES_OBJ)
- $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/erl.o $(OBJDIR)/init_file.o $(OBJDIR)/$(ERLRES_OBJ)
+ $(V_LD) $(LDFLAGS) -o $@ $(OBJDIR)/erl.o $(OBJDIR)/init_file.o $(OBJDIR)/$(ERLRES_OBJ)
$(BINDIR)/werl@EXEEXT@: $(OBJDIR)/werl.o $(OBJDIR)/init_file.o $(OBJDIR)/$(ERLRES_OBJ)
- $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/werl.o $(OBJDIR)/init_file.o $(OBJDIR)/$(ERLRES_OBJ)
+ $(V_LD) $(LDFLAGS) -o $@ $(OBJDIR)/werl.o $(OBJDIR)/init_file.o $(OBJDIR)/$(ERLRES_OBJ)
$(BINDIR)/start_erl@EXEEXT@: $(OBJDIR)/start_erl.o
- $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/start_erl.o
+ $(V_LD) $(LDFLAGS) -o $@ $(OBJDIR)/start_erl.o
$(BINDIR)/Install@EXEEXT@: $(OBJDIR)/Install.o $(OBJDIR)/init_file.o
- $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/Install.o $(OBJDIR)/init_file.o
+ $(V_LD) $(LDFLAGS) -o $@ $(OBJDIR)/Install.o $(OBJDIR)/init_file.o
# The service expects to be compiled with $(MT_FLAG) flag.
$(BINDIR)/erlsrv@EXEEXT@: $(ERLSRV_OBJECTS)
- $(LD) $(LDFLAGS) $(MT_FLAG) -o $@ $(ERLSRV_OBJECTS)
+ $(V_LD) $(LDFLAGS) $(MT_FLAG) -o $@ $(ERLSRV_OBJECTS)
# To fix a spooky parallel make build problem on Windows there are some
# false dependencies on the $(MC), $(RC) and .o rules. The theory behind
@@ -280,62 +281,62 @@ $(BINDIR)/erlsrv@EXEEXT@: $(ERLSRV_OBJECTS)
LOGMESS_GENERATED = $(OBJDIR)/LOGMESS-GENERATED
$(MC_OUTPUTS): $(LOGMESS_GENERATED)
$(LOGMESS_GENERATED): $(WINETC)/erlsrv/erlsrv_logmess.mc
- $(MC) -o $(OBJDIR) $(WINETC)/erlsrv/erlsrv_logmess.mc && \
+ $(V_MC) -o $(OBJDIR) $(WINETC)/erlsrv/erlsrv_logmess.mc && \
echo $? >$(LOGMESS_GENERATED)
$(OBJDIR)/$(ERLRES_OBJ): $(WINETC)/erl.rc $(WINETC)/erlang.ico \
$(WINETC)/erl_icon.ico $(WINETC)/hrl_icon.ico \
$(WINETC)/beam_icon.ico $(LOGMESS_GENERATED)
- $(RC) -o $@ -I$(WINETC) $(WINETC)/erl.rc
+ $(V_RC) -o $@ -I$(WINETC) $(WINETC)/erl.rc
ifeq ($(USING_VC), yes)
RC_GENERATED = $(OBJDIR)/erlsrv_logmess.res
$(RC_GENERATED): $(OBJDIR)/erlsrv_logmess.rc $(OBJDIR)/$(ERLRES_OBJ)
- $(RC) -o $(OBJDIR)/erlsrv_logmess.res -I$(OBJDIR) $(OBJDIR)/erlsrv_logmess.rc
+ $(V_RC) -o $(OBJDIR)/erlsrv_logmess.res -I$(OBJDIR) $(OBJDIR)/erlsrv_logmess.rc
else
RC_GENERATED = $(OBJDIR)/erlsrv_logmess.o
$(RC_GENERATED): $(OBJDIR)/erlsrv_logmess.res $(OBJDIR)/$(ERLRES_OBJ)
- $(RC) -o $(OBJDIR)/erlsrv_logmess.o -I$(OBJDIR) $(OBJDIR)/erlsrv_logmess.res
+ $(V_RC) -o $(OBJDIR)/erlsrv_logmess.o -I$(OBJDIR) $(OBJDIR)/erlsrv_logmess.res
endif
# The service expects to be compiled with $(MT_FLAG) flag.
$(OBJDIR)/%.o: $(WINETC)/erlsrv/%.c $(ERLSRV_HEADERS) $(RC_GENERATED)
- $(CC) $(CFLAGS) $(MT_FLAG) -o $@ -c $<
+ $(V_CC) $(CFLAGS) $(MT_FLAG) -o $@ -c $<
$(OBJDIR)/erlsrv_util.o: $(WINETC)/erlsrv/erlsrv_util.c $(ERLSRV_HEADERS) \
$(OBJDIR)/erlsrv_logmess.h $(RC_GENERATED)
- $(CC) $(CFLAGS) -I$(OBJDIR) $(MT_FLAG) -o $@ -c $<
+ $(V_CC) $(CFLAGS) -I$(OBJDIR) $(MT_FLAG) -o $@ -c $<
$(OBJDIR)/werl.o: $(WINETC)/erl.c $(WINETC)/init_file.h $(RC_GENERATED)
- $(CC) $(CFLAGS) -DBUILD_TYPE=\"-$(TYPE)\" -DERL_RUN_SHARED_LIB=1 \
+ $(V_CC) $(CFLAGS) -DBUILD_TYPE=\"-$(TYPE)\" -DERL_RUN_SHARED_LIB=1 \
-DWIN32_WERL -o $@ -c $(WINETC)/erl.c
$(OBJDIR)/erl.o: $(WINETC)/erl.c $(WINETC)/init_file.h $(RC_GENERATED)
- $(CC) $(CFLAGS) -DBUILD_TYPE=\"-$(TYPE)\" -DERL_RUN_SHARED_LIB=1 \
+ $(V_CC) $(CFLAGS) -DBUILD_TYPE=\"-$(TYPE)\" -DERL_RUN_SHARED_LIB=1 \
-o $@ -c $(WINETC)/erl.c
$(OBJDIR)/erlexec.o: $(ERLEXECDIR)/erlexec.c $(RC_GENERATED)
- $(CC) $(CFLAGS) -DBUILD_TYPE=\"-$(TYPE)\" -DERL_RUN_SHARED_LIB=1 \
+ $(V_CC) $(CFLAGS) -DBUILD_TYPE=\"-$(TYPE)\" -DERL_RUN_SHARED_LIB=1 \
-o $@ -c $(ERLEXECDIR)/erlexec.c
$(OBJDIR)/win_erlexec.o: $(WINETC)/win_erlexec.c $(RC_GENERATED)
- $(CC) $(CFLAGS) -DBUILD_TYPE=\"-$(TYPE)\" -DERL_RUN_SHARED_LIB=1 \
+ $(V_CC) $(CFLAGS) -DBUILD_TYPE=\"-$(TYPE)\" -DERL_RUN_SHARED_LIB=1 \
-o $@ -c $(WINETC)/win_erlexec.c
$(OBJDIR)/init_file.o: $(WINETC)/init_file.c $(WINETC)/init_file.h $(RC_GENERATED)
- $(CC) $(CFLAGS) -o $@ -c $(WINETC)/init_file.c
+ $(V_CC) $(CFLAGS) -o $@ -c $(WINETC)/init_file.c
$(OBJDIR)/Install.o: $(WINETC)/Install.c $(WINETC)/init_file.h $(RC_GENERATED)
- $(CC) $(CFLAGS) -o $@ -c $(WINETC)/Install.c
+ $(V_CC) $(CFLAGS) -o $@ -c $(WINETC)/Install.c
$(OBJDIR)/start_erl.o: $(WINETC)/start_erl.c $(RC_GENERATED)
- $(CC) $(CFLAGS) -o $@ -c $(WINETC)/start_erl.c
+ $(V_CC) $(CFLAGS) -o $@ -c $(WINETC)/start_erl.c
$(ENTRY_OBJ): $(ENTRY_SRC) $(RC_GENERATED)
- $(CC) $(CFLAGS) -o $@ -c $(ENTRY_SRC)
+ $(V_CC) $(CFLAGS) -o $@ -c $(ENTRY_SRC)
Install.ini: ../$(TARGET)/Install.src ../../vsn.mk $(TARGET)/Makefile
- sed -e 's;%I_VSN%;$(VSN);' \
+ $(vsn_verbose)sed -e 's;%I_VSN%;$(VSN);' \
-e 's;%I_SYSTEM_VSN%;$(SYSTEM_VSN);' \
../$(TARGET)/Install.src > Install.ini
@@ -348,99 +349,99 @@ endif
#---------------------------------------------------------
$(BINDIR)/heart@EXEEXT@: $(OBJDIR)/heart.o $(ENTRY_OBJ)
- $(LD) $(LDFLAGS) $(ENTRY_LDFLAGS) -o $@ $(OBJDIR)/heart.o \
+ $(V_LD) $(LDFLAGS) $(ENTRY_LDFLAGS) -o $@ $(OBJDIR)/heart.o \
$(RTLIBS) $(ENTRY_OBJ) $(WINDSOCK)
$(OBJDIR)/heart.o: heart.c $(RC_GENERATED)
- $(CC) $(CFLAGS) -o $@ -c heart.c
+ $(V_CC) $(CFLAGS) -o $@ -c heart.c
#
# Objects & executables
#
#$(OBJDIR)/%.o: %.c
-# $(CC) $(CFLAGS) -o $@ -c $<
+# $(V_CC) $(CFLAGS) -o $@ -c $<
#
#$(OBJDIR)/%.o: ../unix/%.c
-# $(CC) $(CFLAGS) -o $@ -c $<
+# $(V_CC) $(CFLAGS) -o $@ -c $<
#
#$(BINDIR)/%: $(OBJDIR)/%.o
-# $(PURIFY) $(LD) $(LDFLAGS) -o $@ $< $(LIBS)
+# $(ld_verbose)$(PURIFY) $(LD) $(LDFLAGS) -o $@ $< $(LIBS)
$(OBJDIR)/inet_gethost.o: inet_gethost.c $(RC_GENERATED)
- $(CC) $(CFLAGS) -o $@ -c inet_gethost.c
+ $(V_CC) $(CFLAGS) -o $@ -c inet_gethost.c
$(BINDIR)/inet_gethost@EXEEXT@: $(OBJDIR)/inet_gethost.o $(ENTRY_OBJ) $(ERTS_LIB)
- $(PURIFY) $(LD) $(LDFLAGS) $(ENTRY_LDFLAGS) -o $@ $(OBJDIR)/inet_gethost.o $(ENTRY_OBJ) $(LIBS) $(ERTS_INTERNAL_LIBS)
+ $(ld_verbose)$(PURIFY) $(LD) $(LDFLAGS) $(ENTRY_LDFLAGS) -o $@ $(OBJDIR)/inet_gethost.o $(ENTRY_OBJ) $(LIBS) $(ERTS_INTERNAL_LIBS)
$(BINDIR)/run_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/run_erl.o
- $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/safe_string.o $(OBJDIR)/run_erl.o $(LIBS)
+ $(V_LD) $(LDFLAGS) -o $@ $(OBJDIR)/safe_string.o $(OBJDIR)/run_erl.o $(LIBS)
$(OBJDIR)/run_erl.o: ../unix/run_erl.c $(RC_GENERATED)
- $(CC) $(CFLAGS) -o $@ -c ../unix/run_erl.c
+ $(V_CC) $(CFLAGS) -o $@ -c ../unix/run_erl.c
$(BINDIR)/to_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/to_erl.o
- $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/safe_string.o $(OBJDIR)/to_erl.o
+ $(V_LD) $(LDFLAGS) -o $@ $(OBJDIR)/safe_string.o $(OBJDIR)/to_erl.o
$(OBJDIR)/to_erl.o: ../unix/to_erl.c $(RC_GENERATED)
- $(CC) $(CFLAGS) -o $@ -c ../unix/to_erl.c
+ $(V_CC) $(CFLAGS) -o $@ -c ../unix/to_erl.c
$(BINDIR)/dyn_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/dyn_erl.o
- $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/safe_string.o $(OBJDIR)/dyn_erl.o
+ $(V_LD) $(LDFLAGS) -o $@ $(OBJDIR)/safe_string.o $(OBJDIR)/dyn_erl.o
$(OBJDIR)/dyn_erl.o: ../unix/dyn_erl.c $(RC_GENERATED)
- $(CC) $(CFLAGS) -o $@ -c ../unix/dyn_erl.c
+ $(V_CC) $(CFLAGS) -o $@ -c ../unix/dyn_erl.c
$(OBJDIR)/safe_string.o: ../unix/safe_string.c $(RC_GENERATED)
- $(CC) $(CFLAGS) -o $@ -c ../unix/safe_string.c
+ $(V_CC) $(CFLAGS) -o $@ -c ../unix/safe_string.c
ifneq ($(TARGET),win32)
$(BINDIR)/$(ERLEXEC): $(OBJDIR)/$(ERLEXEC).o $(ERTS_LIB)
- $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/$(ERLEXEC).o $(ERTS_INTERNAL_LIBS)
+ $(ld_verbose)$(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/$(ERLEXEC).o $(ERTS_INTERNAL_LIBS)
$(OBJDIR)/$(ERLEXEC).o: $(ERLEXECDIR)/$(ERLEXEC).c $(RC_GENERATED)
- $(CC) -I$(EMUDIR) $(CFLAGS) -o $@ -c $(ERLEXECDIR)/$(ERLEXEC).c
+ $(V_CC) -I$(EMUDIR) $(CFLAGS) -o $@ -c $(ERLEXECDIR)/$(ERLEXEC).c
endif
$(BINDIR)/erlc@EXEEXT@: $(OBJDIR)/erlc.o $(ERTS_LIB)
- $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/erlc.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS)
+ $(ld_verbose)$(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/erlc.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS)
$(OBJDIR)/erlc.o: erlc.c $(RC_GENERATED)
- $(CC) $(CFLAGS) -o $@ -c erlc.c
+ $(V_CC) $(CFLAGS) -o $@ -c erlc.c
$(BINDIR)/dialyzer@EXEEXT@: $(OBJDIR)/dialyzer.o $(ERTS_LIB)
- $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/dialyzer.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS)
+ $(ld_verbose)$(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/dialyzer.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS)
$(OBJDIR)/dialyzer.o: dialyzer.c $(RC_GENERATED)
- $(CC) $(CFLAGS) -o $@ -c dialyzer.c
+ $(V_CC) $(CFLAGS) -o $@ -c dialyzer.c
$(BINDIR)/typer@EXEEXT@: $(OBJDIR)/typer.o $(ERTS_LIB)
- $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/typer.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS)
+ $(ld_verbose)$(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/typer.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS)
$(OBJDIR)/typer.o: typer.c $(RC_GENERATED)
- $(CC) $(CFLAGS) -o $@ -c typer.c
+ $(V_CC) $(CFLAGS) -o $@ -c typer.c
$(BINDIR)/escript@EXEEXT@: $(OBJDIR)/escript.o $(ERTS_LIB)
- $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/escript.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS)
+ $(ld_verbose)$(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/escript.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS)
$(OBJDIR)/escript.o: escript.c $(RC_GENERATED)
- $(CC) $(CFLAGS) -o $@ -c escript.c
+ $(V_CC) $(CFLAGS) -o $@ -c escript.c
$(BINDIR)/ct_run@EXEEXT@: $(OBJDIR)/ct_run.o $(ERTS_LIB)
- $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/ct_run.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS)
+ $(ld_verbose)$(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/ct_run.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS)
$(OBJDIR)/ct_run.o: ct_run.c $(RC_GENERATED)
- $(CC) $(CFLAGS) -o $@ -c ct_run.c
+ $(V_CC) $(CFLAGS) -o $@ -c ct_run.c
Install: ../unix/Install.src ../../vsn.mk $(TARGET)/Makefile
- sed -e 's;%I_VSN%;$(VSN);' \
+ $(vsn_verbose)sed -e 's;%I_VSN%;$(VSN);' \
-e 's;%EMULATOR%;$(EMULATOR);' \
-e 's;%EMULATOR_NUMBER%;$(EMULATOR_NUMBER);' \
-e 's;%I_SYSTEM_VSN%;$(SYSTEM_VSN);' \
../unix/Install.src > Install
erl.src: ../unix/erl.src.src ../../vsn.mk $(TARGET)/Makefile
- sed -e 's;%EMULATOR%;$(EMULATOR);' \
+ $(vsn_verbose)sed -e 's;%EMULATOR%;$(EMULATOR);' \
-e 's;%EMULATOR_NUMBER%;$(EMULATOR_NUMBER);' \
-e 's;%VSN%;$(VSN);' \
../unix/erl.src.src > erl.src
diff --git a/erts/etc/common/erlexec.c b/erts/etc/common/erlexec.c
index 52add1c1ba..50c61f50eb 100644
--- a/erts/etc/common/erlexec.c
+++ b/erts/etc/common/erlexec.c
@@ -127,6 +127,7 @@ static char *pluss_val_switches[] = {
"wt",
"ws",
"ss",
+ "pp",
NULL
};
/* +h arguments with values */
@@ -799,7 +800,9 @@ int main(int argc, char **argv)
case 'A':
case 'b':
case 'i':
+ case 'n':
case 'P':
+ case 'Q':
case 'S':
case 't':
case 'T':
@@ -989,8 +992,7 @@ int main(int argc, char **argv)
if (print_args_exit) {
for (i = 1; i < EargsCnt; i++)
- printf("%s ", Eargsp[i]);
- printf("\n");
+ printf("%s\n", Eargsp[i]);
exit(0);
}
@@ -1104,7 +1106,8 @@ usage_aux(void)
"[-make] [-man [manopts] MANPAGE] [-x] [-emu_args] "
"[-args_file FILENAME] [+A THREADS] [+a SIZE] [+B[c|d|i]] [+c] "
"[+h HEAP_SIZE_OPTION] [+K BOOLEAN] "
- "[+l] [+M<SUBSWITCH> <ARGUMENT>] [+P MAX_PROCS] [+R COMPAT_REL] "
+ "[+l] [+M<SUBSWITCH> <ARGUMENT>] [+P MAX_PROCS] [+Q MAX_PORTS] "
+ "[+R COMPAT_REL] "
"[+r] [+rg READER_GROUPS_LIMIT] [+s SCHEDULER_OPTION] "
"[+S NO_SCHEDULERS:NO_SCHEDULERS_ONLINE] [+T LEVEL] [+V] [+v] "
"[+W<i|w>] [+z MISC_OPTION] [args ...]\n");
diff --git a/erts/etc/common/escript.c b/erts/etc/common/escript.c
index 9e80ec6656..3566406bf3 100644
--- a/erts/etc/common/escript.c
+++ b/erts/etc/common/escript.c
@@ -264,7 +264,7 @@ append_shebang_args(char* scriptname)
static char linebuf[LINEBUFSZ];
char* ptr = fgets(linebuf, LINEBUFSZ, fd);
- if (ptr != NULL && linebuf[0] == '#' && linebuf[1] == '!') {
+ if (ptr != NULL) {
/* Try to find args on second or third line */
ptr = fgets(linebuf, LINEBUFSZ, fd);
if (ptr != NULL && linebuf[0] == '%' && linebuf[1] == '%' && linebuf[2] == '!') {
diff --git a/erts/etc/common/heart.c b/erts/etc/common/heart.c
index 7b78cc489d..81d797dc7e 100644
--- a/erts/etc/common/heart.c
+++ b/erts/etc/common/heart.c
@@ -115,7 +115,8 @@
# endif
#endif
-#define HEART_COMMAND_ENV "HEART_COMMAND"
+#define HEART_COMMAND_ENV "HEART_COMMAND"
+#define ERL_CRASH_DUMP_SECONDS_ENV "ERL_CRASH_DUMP_SECONDS"
#define MSG_HDR_SIZE 2
#define MSG_HDR_PLUS_OP_SIZE 3
@@ -131,13 +132,14 @@ struct msg {
};
/* operations */
-#define HEART_ACK 1
-#define HEART_BEAT 2
-#define SHUT_DOWN 3
-#define SET_CMD 4
-#define CLEAR_CMD 5
-#define GET_CMD 6
-#define HEART_CMD 7
+#define HEART_ACK (1)
+#define HEART_BEAT (2)
+#define SHUT_DOWN (3)
+#define SET_CMD (4)
+#define CLEAR_CMD (5)
+#define GET_CMD (6)
+#define HEART_CMD (7)
+#define PREPARING_CRASH (8)
/* Maybe interesting to change */
@@ -165,10 +167,11 @@ unsigned long heart_beat_kill_pid = 0;
#define SOL_WD_TIMEOUT (heart_beat_timeout+heart_beat_boot_delay)
/* reasons for reboot */
-#define R_TIMEOUT 1
-#define R_CLOSED 2
-#define R_ERROR 3
-#define R_SHUT_DOWN 4
+#define R_TIMEOUT (1)
+#define R_CLOSED (2)
+#define R_ERROR (3)
+#define R_SHUT_DOWN (4)
+#define R_CRASHING (5) /* Doing a crash dump and we will wait for it */
/* macros */
@@ -178,8 +181,8 @@ unsigned long heart_beat_kill_pid = 0;
/* prototypes */
-static int message_loop(int,int);
-static void do_terminate(int);
+static int message_loop(int, int);
+static void do_terminate(int, int);
static int notify_ack(int);
static int heart_cmd_reply(int, char *);
static int write_message(int, struct msg *);
@@ -190,6 +193,7 @@ static void print_error(const char *,...);
static void debugf(const char *,...);
static void init_timestamp(void);
static time_t timestamp(time_t *);
+static int wait_until_close_write_or_env_tmo(int);
#ifdef __WIN32__
static BOOL enable_privilege(void);
@@ -328,12 +332,14 @@ static void get_arguments(int argc, char** argv) {
debugf("arguments -ht %d -wt %d -pid %lu\n",h,w,p);
}
-int
-main(int argc, char **argv)
-{
+int main(int argc, char **argv) {
+
+ if (is_env_set("HEART_DEBUG")) {
+ fprintf(stderr, "heart: debug is ON!\r\n");
+ debug_on = 1;
+ }
+
get_arguments(argc,argv);
- if (is_env_set("HEART_DEBUG"))
- debug_on=1;
#ifdef __WIN32__
if (debug_on) {
if(!is_env_set("ERLSRV_SERVICE_NAME")) {
@@ -354,7 +360,7 @@ main(int argc, char **argv)
program_name[sizeof(program_name)-1] = '\0';
notify_ack(erlout_fd);
cmd[0] = '\0';
- do_terminate(message_loop(erlin_fd,erlout_fd));
+ do_terminate(erlin_fd,message_loop(erlin_fd,erlout_fd));
return 0;
}
@@ -388,6 +394,7 @@ message_loop(erlin_fd, erlout_fd)
#endif
while (1) {
+ /* REFACTOR: below to select/tmo function */
#ifdef __WIN32__
wresult = WaitForSingleObject(hevent_dataready,SELECT_TIMEOUT*1000+ 2);
if (wresult == WAIT_FAILED) {
@@ -482,6 +489,10 @@ message_loop(erlin_fd, erlout_fd)
free_env_val(env);
}
break;
+ case PREPARING_CRASH:
+ /* Erlang has reached a crushdump point (is crashing for sure) */
+ print_error("Erlang is crashing .. (waiting for crash dump file)");
+ return R_CRASHING;
default:
/* ignore all other messages */
break;
@@ -612,72 +623,130 @@ void win_system(char *command)
* do_terminate
*/
static void
-do_terminate(reason)
- int reason;
-{
+do_terminate(int erlin_fd, int reason) {
/*
When we get here, we have HEART_BEAT_BOOT_DELAY secs to finish
(plus heart_beat_report_delay if under VxWorks), so we don't need
to call wd_reset().
*/
-
+ int ret = 0, tmo=0;
+ char *tmo_env;
+
switch (reason) {
case R_SHUT_DOWN:
break;
+ case R_CRASHING:
+ if (is_env_set(ERL_CRASH_DUMP_SECONDS_ENV)) {
+ tmo_env = get_env(ERL_CRASH_DUMP_SECONDS_ENV);
+ tmo = atoi(tmo_env);
+ print_error("Waiting for dump - timeout set to %d seconds.", tmo);
+ wait_until_close_write_or_env_tmo(tmo);
+ free_env_val(tmo_env);
+ }
+ /* fall through */
case R_TIMEOUT:
- case R_ERROR:
case R_CLOSED:
+ case R_ERROR:
default:
-#if defined(__WIN32__)
{
- if(!cmd[0]) {
- char *command = get_env(HEART_COMMAND_ENV);
- if(!command)
- print_error("Would reboot. Terminating.");
- else {
- kill_old_erlang();
- /* High prio combined with system() works badly indeed... */
- SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
- win_system(command);
- print_error("Executed \"%s\". Terminating.",command);
+#if defined(__WIN32__) /* Not VxWorks */
+ if(!cmd[0]) {
+ char *command = get_env(HEART_COMMAND_ENV);
+ if(!command)
+ print_error("Would reboot. Terminating.");
+ else {
+ kill_old_erlang();
+ /* High prio combined with system() works badly indeed... */
+ SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
+ win_system(command);
+ print_error("Executed \"%s\". Terminating.",command);
+ }
+ free_env_val(command);
+ } else {
+ kill_old_erlang();
+ /* High prio combined with system() works badly indeed... */
+ SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
+ win_system(&cmd[0]);
+ print_error("Executed \"%s\". Terminating.",cmd);
}
- free_env_val(command);
- }
- else {
- kill_old_erlang();
- /* High prio combined with system() works badly indeed... */
- SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
- win_system(&cmd[0]);
- print_error("Executed \"%s\". Terminating.",cmd);
- }
- }
-
#else
- {
- if(!cmd[0]) {
- char *command = get_env(HEART_COMMAND_ENV);
- if(!command)
- print_error("Would reboot. Terminating.");
- else {
- kill_old_erlang();
- /* suppress gcc warning with 'if' */
- if(system(command));
- print_error("Executed \"%s\". Terminating.",command);
+ if(!cmd[0]) {
+ char *command = get_env(HEART_COMMAND_ENV);
+ if(!command)
+ print_error("Would reboot. Terminating.");
+ else {
+ kill_old_erlang();
+ /* suppress gcc warning with 'if' */
+ ret = system(command);
+ print_error("Executed \"%s\" -> %d. Terminating.",command, ret);
+ }
+ free_env_val(command);
+ } else {
+ kill_old_erlang();
+ /* suppress gcc warning with 'if' */
+ ret = system((char*)&cmd[0]);
+ print_error("Executed \"%s\" -> %d. Terminating.",cmd, ret);
}
- free_env_val(command);
- }
- else {
- kill_old_erlang();
- /* suppress gcc warning with 'if' */
- if(system((char*)&cmd[0]));
- print_error("Executed \"%s\". Terminating.",cmd);
- }
+#endif
}
break;
-#endif
} /* switch(reason) */
}
+
+/* Waits until something happens on socket or handle
+ *
+ * Uses global variables erlin_fd or hevent_dataready
+ */
+int wait_until_close_write_or_env_tmo(int tmo) {
+ int i = 0;
+
+#ifdef __WIN32__
+ DWORD wresult;
+ DWORD wtmo = INFINITE;
+
+ if (tmo >= 0) {
+ wtmo = tmo*1000 + 2;
+ }
+
+ wresult = WaitForSingleObject(hevent_dataready, wtmo);
+ if (wresult == WAIT_FAILED) {
+ print_last_error();
+ return -1;
+ }
+
+ if (wresult == WAIT_TIMEOUT) {
+ debugf("wait timed out\n");
+ i = 0;
+ } else {
+ debugf("wait ok\n");
+ i = 1;
+ }
+#else
+ fd_set read_fds;
+ int max_fd;
+ struct timeval timeout;
+ struct timeval *tptr = NULL;
+
+ max_fd = erlin_fd; /* global */
+
+ if (tmo >= 0) {
+ timeout.tv_sec = tmo; /* On Linux timeout is modified by select */
+ timeout.tv_usec = 0;
+ tptr = &timeout;
+ }
+
+ FD_ZERO(&read_fds);
+ FD_SET(erlin_fd, &read_fds);
+ if ((i = select(max_fd + 1, &read_fds, NULLFDS, NULLFDS, tptr)) < 0) {
+ print_error("error in select.");
+ return -1;
+ }
+#endif
+ return i;
+}
+
+
/*
* notify_ack
*
@@ -868,12 +937,13 @@ debugf(const char *format,...)
{
va_list args;
- if (!debug_on) return;
- va_start(args, format);
- fprintf(stderr, "Heart: ");
- vfprintf(stderr, format, args);
- va_end(args);
- fprintf(stderr, "\r\n");
+ if (debug_on) {
+ va_start(args, format);
+ fprintf(stderr, "Heart: ");
+ vfprintf(stderr, format, args);
+ va_end(args);
+ fprintf(stderr, "\r\n");
+ }
}
#ifdef __WIN32__
diff --git a/erts/etc/unix/cerl.src b/erts/etc/unix/cerl.src
index e0d7404de7..cc7d77fd9a 100644
--- a/erts/etc/unix/cerl.src
+++ b/erts/etc/unix/cerl.src
@@ -267,11 +267,16 @@ if [ "x$GDB" = "x" ]; then
valgrind_misc_flags="$VALGRIND_MISC_FLAGS"
fi
beam_args=`$EXEC -emu_args_exit ${1+"$@"}`
- # Ahhhh... Need to quote $PROGNAME...
- early_beam_args=`echo $beam_args | sed "s|^\(.*-progname\).*$|\1|g"`
- late_beam_args=`echo $beam_args | sed "s|^$pre_beam_args.*\(-- -home.*\)$|\1|g"`
-
- exec valgrind $valgrind_xml $valgrind_log $valgrind_misc_flags $BINDIR/$EMU_NAME $emu_xargs $early_beam_args "$PROGNAME" $late_beam_args -pz $PRELOADED
+
+ # Time for some argument passing voodoo:
+ # $beam_args is a list of command line arguments separated by newlines.
+ # Make "$@" represent those arguments verbatim (including spaces and quotes).
+ SAVE_IFS="$IFS"
+ IFS='
+'
+ set -- $beam_args
+ IFS="$SAVE_IFS"
+ exec valgrind $valgrind_xml $valgrind_log $valgrind_misc_flags $BINDIR/$EMU_NAME $emu_xargs "$@" -pz $PRELOADED
else
exec $EXEC $eeargs $xargs ${1+"$@"}
fi
@@ -299,10 +304,17 @@ else
;;
esac
- # Set annotation level for gdb in emacs 22 and higher.
- emacs_major=`$EMACS --version | head -1 | sed 's,^[^0-9]*\([0-9]*\).*,\1,g'`
- if [ '!' -z "$emacs_major" -a $emacs_major -gt 21 ]; then
- GDBARGS="--annotate=1 "
+ if [ "$EMACS_ANNOTATE_LEVEL" != "" ]; then
+ GDBARGS="--annotate=$EMACS_ANNOTATE_LEVEL"
+ else
+ # Set annotation level for gdb in emacs 22 and higher. Seems to
+ # be working with level 1 for emacs 22 and level 3 for emacs 23...
+ emacs_major=`$EMACS --version | head -1 | sed 's,^[^0-9]*\([0-9]*\).*,\1,g'`
+ if [ '!' -z "$emacs_major" -a $emacs_major -gt 22 ]; then
+ GDBARGS="--annotate=3 "
+ elif [ '!' -z "$emacs_major" -a $emacs_major -gt 21 ]; then
+ GDBARGS="--annotate=1 "
+ fi
fi
gdbcmd="$gdbcmd $GDBBP \
(insert-string \"source $ROOTDIR/erts/etc/unix/etp-commands\") \
diff --git a/erts/etc/unix/etp-commands b/erts/etc/unix/etp-commands
index d98505c0ff..f059662271 100644
--- a/erts/etc/unix/etp-commands
+++ b/erts/etc/unix/etp-commands
@@ -705,8 +705,6 @@ define etp-ct-name-1
end
end
-
-
define etp-pid-1
# Args: Eterm pid
#
@@ -714,9 +712,17 @@ define etp-pid-1
#
set $etp_pid_1 = (Eterm)($arg0)
if ($etp_pid_1 & 0xF) == 0x3
+ if (etp_arch_bits == 64 && etp_halfword == 0)
+ if (etp_big_endian)
+ set $etp_pid_data = (unsigned) ((((Uint64) $etp_pid_1) >> 36) & 0x0fffffff)
+ else
+ set $etp_pid_data = (unsigned) ((((Uint64) $etp_pid_1) >> 4) & 0x0fffffff)
+ end
+ else
+ set $etp_pid_data = (unsigned) (((((Uint32) $etp_pid_1) >> 4) & ~erts_proc.r.o.pix_mask) | ((((Uint32) $etp_pid_1) >> (erts_proc.r.o.pix_cl_shift + 4)) & erts_proc.r.o.pix_cl_mask) | (((((Uint32) $etp_pid_1) >> 4) & erts_proc.r.o.pix_cli_mask) << erts_proc.r.o.pix_cli_shift))
+ end
# Internal pid
- printf "<0.%u.%u>", (unsigned) ($etp_pid_1>>4)&0x7fff, \
- (unsigned) ($etp_pid_1>>19)&0x1fff
+ printf "<0.%u.%u>", $etp_pid_data & 0x7fff, ($etp_pid_data >> 15) & 0x1fff
else
printf "#NotPid<%#x>", ($arg0)
end
@@ -759,7 +765,6 @@ define etp-extpid-1
end
-
define etp-port-1
# Args: Eterm port
#
@@ -767,8 +772,17 @@ define etp-port-1
#
set $etp_port_1 = (Eterm)($arg0)
if ($etp_port_1 & 0xF) == 0x7
+ if (etp_arch_bits == 64 && etp_halfword == 0)
+ if (etp_big_endian)
+ set $etp_port_data = (unsigned) ((((Uint64) $etp_port_1) >> 36) & 0x0fffffff)
+ else
+ set $etp_port_data = (unsigned) ((((Uint64) $etp_port_1) >> 4) & 0x0fffffff)
+ end
+ else
+ set $etp_port_data = (unsigned) (((((Uint32) $etp_port_1) >> 4) & ~erts_port.r.o.pix_mask) | ((((Uint32) $etp_port_1) >> (erts_port.r.o.pix_cl_shift + 4)) & erts_port.r.o.pix_cl_mask) | (((((Uint32) $etp_port_1) >> 4) & erts_port.r.o.pix_cli_mask) << erts_port.r.o.pix_cli_shift))
+ end
# Internal port
- printf "#Port<0.%u>", (unsigned) ($etp_port_1>>4)&0x3ffff
+ printf "#Port<0.%u>", $etp_port_data
else
printf "#NotPort<%#x>", ($arg0)
end
@@ -1264,23 +1278,32 @@ document etpf-stackdump
%---------------------------------------------------------------------------
end
+define etp-pid2pix-1
+# Args: Eterm
+#
+ if (etp_arch_bits == 64 && etp_halfword == 0)
+ if (etp_big_endian)
+ set $etp_pix = (int) (((Uint64) $arg0) & 0x0fffffff)
+ else
+ set $etp_pix = (int) ((((Uint64) $arg0) >> 32) & 0x0fffffff)
+ end
+ else
+ set $etp_pix = (int) ((((Uint32) $arg0) >> 4) & erts_proc.r.o.pix_mask)
+ end
+end
+
define etp-pix2proc
# Args: Eterm
#
- set $proc = (Process *) *((UWord *) &erts_proc.tab[((int) $arg0)])
+ set $proc = (Process *) *((UWord *) &erts_proc.r.o.tab[((int) $arg0)])
printf "(Process *) %p\n", $proc
end
define etp-pid2proc-1
# Args: Eterm
#
- set $pix = (int) ($arg0 >> 4)
-
- if (erts_proc.pix_cl_mask != 0)
- set $proc = (Process *) *((UWord *) &erts_proc.tab[(((($pix) & erts_proc.pix_cl_mask) << erts_proc.pix_cl_shift) + ((($pix) >> erts_proc.pix_cli_shift) & erts_proc.pix_cli_mask))])
- else
- set $proc =(Process *) *((UWord *) &erts_proc.tab[((($pix) % erts_proc.max) % erts_proc.tab_cache_lines + (($pix) % erts_proc.max) / erts_proc.tab_cache_lines)])
- end
+ etp-pid2pix-1 $arg0
+ set $proc = (Process *) *((UWord *) &erts_proc.r.o.tab[$etp_pix])
end
define etp-pid2proc
@@ -1369,13 +1392,15 @@ define etp-process-info
# Args: Process*
#
printf " Pid: "
- etp-1 $arg0->id
+ etp-1 $arg0->common.id
printf "\n State: "
etp-proc-state $arg0
- if ($arg0->reg)
- printf " Registered name: "
- etp-1 $arg0->reg->name
- printf "\n"
+ if (*(((Uint32 *) &(((Process *) $arg0)->state))) & 0x4) == 0
+ if ($arg0->common.u.alive.reg)
+ printf " Registered name: "
+ etp-1 $arg0->common.u.alive.reg->name
+ printf "\n"
+ end
end
if ($arg0->current)
printf " Current function: "
@@ -1400,7 +1425,7 @@ define etp-process-info
end
printf " Mbuf size: %ld\n", $arg0->mbuf_sz
if (etp_smp_compiled)
- printf " Msgq len: %ld (inner=%ld, outer=%ld)\n", ($arg0->msg.len + $arg0->u.alive.msg_inq.len), $arg0->msg.len, $arg0->u.alive.msg_inq.len
+ printf " Msgq len: %ld (inner=%ld, outer=%ld)\n", ($arg0->msg.len + $arg0->msg_inq.len), $arg0->msg.len, $arg0->msg_inq.len
else
printf " Msgq len: %d\n", $arg0->msg.len
end
@@ -1422,9 +1447,9 @@ define etp-processes
printf "No processes, since system isn't initialized!\n"
else
set $proc_ix = 0
- while $proc_ix < erts_proc.max
- set $proc = (Process *) *((UWord *) &erts_proc.tab[$proc_ix])
- if ($proc != (Process *) 0)
+ while $proc_ix < erts_proc.r.o.max
+ set $proc = (Process *) *((UWord *) &erts_proc.r.o.tab[$proc_ix])
+ if ($proc != ((Process *) 0) && $proc != &erts_invalid_process)
printf "---\n"
printf " Pix: %d\n", $proc_ix
etp-process-info $proc
@@ -1443,8 +1468,108 @@ document etp-processes
%---------------------------------------------------------------------------
end
+define etp-port-id2pix-1
+# Args: Eterm
+#
+ if (etp_arch_bits == 64 && etp_halfword == 0)
+ if (etp_big_endian)
+ set $etp_pix = (int) (((Uint64) $arg0) & 0x0fffffff)
+ elser
+ set $etp_pix = (int) ((((Uint64) $arg0) >> 32) & 0x0fffffff)
+ end
+ else
+ set $etp_pix = (int) ((((Uint32) $arg0) >> 4) & erts_port.r.o.pix_mask)
+ end
+end
+
+define etp-pix2port
+# Args: Eterm
+#
+ set $port = (Port *) *((UWord *) &erts_port.r.o.tab[((int) $arg0)])
+ printf "(Port *) %p\n", $port
+end
-define etp-port-status-int
+define etp-id2port-1
+# Args: Eterm
+#
+ etp-port-id2pix-1 $arg0
+ set $port = (Port *) *((UWord *) &erts_port.r.o.tab[((int) $etp_pix)])
+end
+
+define etp-id2port
+# Args: Eterm
+#
+ etp-id2port-1 $arg0
+ printf "(Port *) %p\n", $port
+end
+
+define etp-port-sched-flags-int
+# Args: int
+#
+ if ($arg0 & 0x1)
+ printf " in-run-queue"
+ end
+ if ($arg0 & 0x2)
+ printf " executing"
+ end
+ if ($arg0 & 0x4)
+ printf " have-tasks"
+ end
+ if ($arg0 & 0x8)
+ printf " exited"
+ end
+ if ($arg0 & 0x10)
+ printf " busy-port"
+ end
+ if ($arg0 & 0x20)
+ printf " busy-port-q"
+ end
+ if ($arg0 & 0x40)
+ printf " chk-unset-busy-port-q"
+ end
+ if ($arg0 & 0x80)
+ printf " have-busy-tasks"
+ end
+ if ($arg0 & 0x100)
+ printf " have-nosuspend-tasks"
+ end
+ if ($arg0 & 0x200)
+ printf " parallelism"
+ end
+ if ($arg0 & 0x400)
+ printf " force-sched"
+ end
+ if ($arg0 & 0xfffff800)
+ printf " GARBAGE"
+ end
+ printf "\n"
+end
+
+document etp-port-sched-flags-int
+%---------------------------------------------------------------------------
+% etp-proc-sched-flags-int int
+%
+% Print port sched-flags
+%---------------------------------------------------------------------------
+end
+
+
+define etp-port-sched-flags
+# Args: Port*
+#
+ set $sched_flags_int = *(((Uint32 *) &(((Port *) $arg0)->sched.flags)))
+ etp-port-sched-flags-int $sched_flags_int
+end
+
+document etp-port-sched-flags
+%---------------------------------------------------------------------------
+% etp-proc-sched-flags-int Port *
+%
+% Print port sched-flags
+%---------------------------------------------------------------------------
+end
+
+define etp-port-state-int
# Args: int
#
if ($arg0 & 0x1)
@@ -1463,68 +1588,62 @@ define etp-port-status-int
printf " soft-eof"
end
if ($arg0 & 0x20)
- printf " port-busy"
+ printf " closing"
end
if ($arg0 & 0x40)
- printf " closing"
+ printf " send-closed"
end
if ($arg0 & 0x80)
- printf " send-closed"
+ printf " linebuf-io"
end
if ($arg0 & 0x100)
- printf " linebuf-io"
+ printf " free"
end
if ($arg0 & 0x200)
- printf " immortal"
+ printf " initializing"
end
if ($arg0 & 0x400)
- printf " free"
+ printf " port-specific-lock"
end
if ($arg0 & 0x800)
- printf " free-scheduled"
+ printf " invalid"
end
if ($arg0 & 0x1000)
- printf " initializing"
- end
- if ($arg0 & 0x2000)
- printf " port-specific-lock"
- end
- if ($arg0 & 0x4000)
- printf " invalid"
+ printf " halt"
end
if (etp_debug_compiled)
- if ($arg0 & 0x7fff8000)
+ if ($arg0 & 0x7fffe000)
printf " GARBAGE"
end
else
- if ($arg0 & 0xffff8000)
+ if ($arg0 & 0xffffe000)
printf " GARBAGE"
end
end
printf "\n"
end
-document etp-port-status-int
+document etp-port-state-int
%---------------------------------------------------------------------------
% etp-proc-state-int int
%
-% Print port status
+% Print port state
%---------------------------------------------------------------------------
end
-define etp-port-status
+define etp-port-state
# Args: Port*
#
- set $status_int = *(((Uint32 *) &(((Port *) $arg0)->status)))
- etp-port-status-int $status_int
+ set $state_int = *(((Uint32 *) &(((Port *) $arg0)->state)))
+ etp-port-state-int $state_int
end
-document etp-port-status
+document etp-port-state
%---------------------------------------------------------------------------
% etp-proc-state-int Port *
%
-% Print port status
+% Print port state
%---------------------------------------------------------------------------
end
@@ -1532,17 +1651,22 @@ define etp-port-info
# Args: Port*
#
printf " Port: "
- etp-1 $arg0->id
+ etp-1 $arg0->common.id
printf "\n Name: %s\n", $arg0->name
- printf " Status:"
- etp-port-status $arg0
- if ($arg0->reg)
- printf " Registered name: "
- etp-1 $arg0->reg->name
- printf "\n"
+ printf " State:"
+ etp-port-state $arg0
+ printf " Scheduler flags:"
+ etp-port-sched-flags $arg0
+ if (*(((Uint32 *) &(((Port *) $arg0)->state))) & 0x5C00) == 0
+ if ($arg0->common.u.alive.reg)
+ printf " Registered name: "
+ etp-1 $arg0->common.u.alive.reg->name
+ printf "\n"
+ end
end
printf " Connected: "
- etp-1 $arg0->connected
+ set $connected = *(((Eterm *) &(((Port *) $arg0)->connected)))
+ etp-1 $connected
printf "\n Pointer: (Port *) %p\n", $arg0
end
@@ -1560,13 +1684,15 @@ define etp-ports
printf "No ports, since system isn't initialized!\n"
else
set $port_ix = 0
- while $port_ix < erts_max_ports
- set $port = &erts_port[$port_ix]
- if ($port->status & 0x400) == 0
- # I.e, not free
- printf "---\n"
- printf " Pix: %d\n", $port_ix
- etp-port-info $port
+ while $port_ix < erts_port.r.o.max
+ set $port = (Port *) *((UWord *) &erts_port.r.o.tab[$port_ix])
+ if ($port != ((Port *) 0) && $port != &erts_invalid_port)
+ if (*(((Uint32 *) &(((Port *) $port)->state))) & 0x100) == 0
+ # I.e, not free
+ printf "---\n"
+ printf " Pix: %d\n", $port_ix
+ etp-port-info $port
+ end
end
set $port_ix++
end
@@ -1866,6 +1992,12 @@ define etp-system-info
printf "ERTS version: %s\n", etp_erts_version
printf "Compile date: %s\n", etp_compile_date
printf "Arch: %s\n", etp_arch
+ printf "Endianess: "
+ if (etp_big_endian)
+ printf "Big\n"
+ else
+ printf "Little\n"
+ end
printf "Word size: %d-bit\n", etp_arch_bits
printf "Halfword: "
if (etp_halfword)
@@ -2113,8 +2245,8 @@ define etp-search-heaps-1
end
set $etp_search_heaps_i = 0
set $etp_search_heaps_found = 0
- while $etp_search_heaps_i < erts_proc.max
- set $proc = (Process *) *((UWord *) &erts_proc.tab[$proc_ix])
+ while $etp_search_heaps_i < erts_proc.r.o.max
+ set $proc = (Process *) *((UWord *) &erts_proc.r.o.tab[$proc_ix])
if $proc
if ($proc->heap <= ($arg0)) && \
(($arg0) < $proc->hend)
diff --git a/erts/etc/win32/nsis/Makefile b/erts/etc/win32/nsis/Makefile
index f377a68c69..7bcecaa264 100644
--- a/erts/etc/win32/nsis/Makefile
+++ b/erts/etc/win32/nsis/Makefile
@@ -62,9 +62,15 @@ else
endif
REDIST_FILE=$(shell (sh ./find_redist.sh || echo ""))
+ifeq ($(MSYSTEM),MINGW32)
+ NICEREDISTFILE=$(shell (msys2win_path.sh -m "$(REDIST_FILE)" 2>/dev/null || echo ""))
+else
+ NICEREDISTFILE=$(shell (cygpath -d -m "$(REDIST_FILE)" 2>/dev/null || echo ""))
+endif
+
REDIST_TARGET=$(shell (sh ./find_redist.sh -n || echo ""))
-REDIST_DLL_VERSION=$(shell (sh ./dll_version_helper.sh || echo ""))
-REDIST_DLL_NAME=$(shell (sh ./dll_version_helper.sh -n || echo ""))
+REDIST_DLL_VERSION=$(shell (sh ./dll_version_helper.sh $(NICEREDISTFILE) || echo ""))
+REDIST_DLL_NAME=$(shell (sh ./dll_version_helper.sh -n $(NICEREDISTFILE) || echo ""))
release_spec:
@NSIS_VER=`makensis /hdrinfo | head -1 | awk '{print $$2}'`; \
@@ -91,7 +97,7 @@ release_spec:
fi;\
if [ '!' -z "$(REDIST_FILE)" -a '!' -z "$(REDIST_DLL_VERSION)" ];\
then \
- cp $(REDIST_FILE) "$(RELEASE_PATH)/$(REDIST_TARGET);"\
+ cp $(REDIST_FILE) "$(RELEASE_PATH)/$(REDIST_TARGET)";\
echo '!define HAVE_REDIST_FILE 1' >> $(VERSION_HEADER); \
echo '!define REDIST_DLL_VERSION "$(REDIST_DLL_VERSION)"' >> $(VERSION_HEADER);\
echo '!define REDIST_DLL_NAME "$(REDIST_DLL_NAME)"' >> $(VERSION_HEADER);\
diff --git a/erts/etc/win32/nsis/dll_version_helper.sh b/erts/etc/win32/nsis/dll_version_helper.sh
index 96e4532b7a..0d9ba4248d 100755
--- a/erts/etc/win32/nsis/dll_version_helper.sh
+++ b/erts/etc/win32/nsis/dll_version_helper.sh
@@ -25,6 +25,13 @@
# echo "8.0.50727.763"
# exit 0
+if [ "$1" = "-n" ]; then
+ SWITCH=$1
+ shift
+else
+ SWITCH=""
+fi
+
cat > hello.c <<EOF
#include <windows.h>
#include <stdio.h>
@@ -42,11 +49,16 @@ if [ '!' -f hello.exe.manifest ]; then
# need another way of getting the version
DLLNAME=`dumpbin.exe -imports hello.exe | egrep MSVCR.*dll`
DLLNAME=`echo $DLLNAME`
+ if [ '!' -z "$1" ]; then
+ FILETOLOOKIN=$1
+ else
+ FILETOLOOKIN=$DLLNAME
+ fi
cat > helper.c <<EOF
#include <windows.h>
#include <stdio.h>
-#define REQ_MODULE "$DLLNAME"
+#define REQ_MODULE "$FILETOLOOKIN"
int main(void)
{
@@ -100,7 +112,7 @@ else
NAME=`grep '<assemblyIdentity' hello.exe.manifest | sed 's,.*name=.[A-Za-z\.]*\([0-9]*\).*,msvcr\1.dll,g' | grep -v '<'`
fi
#rm -f hello.c hello.obj hello.exe hello.exe.manifest helper.c helper.obj helper.exe helper.exe.manifest
-if [ "$1" = "-n" ]; then
+if [ "$SWITCH" = "-n" ]; then
ASKEDFOR=$NAME
else
ASKEDFOR=$VERSION
diff --git a/erts/etc/win32/nsis/erlang20.nsi b/erts/etc/win32/nsis/erlang20.nsi
index c5ada9e3b3..3333c4a9aa 100644
--- a/erts/etc/win32/nsis/erlang20.nsi
+++ b/erts/etc/win32/nsis/erlang20.nsi
@@ -35,6 +35,7 @@
!include "MUI.nsh"
!include "WordFunc.nsh"
+ !include "WinVer.nsh"
;--------------------------------
;Configuration
@@ -341,6 +342,9 @@ FunctionEnd
Function .onInit
Var /GLOBAL archprefix
Var /GLOBAL sysnativedir
+ Var /GLOBAL winvermajor
+ Var /GLOBAL winverminor
+
SectionGetFlags 0 $MYTEMP
StrCmpS ${WINTYPE} "win64" +1 +4
StrCpy $archprefix "amd64"
@@ -348,9 +352,16 @@ Function .onInit
Goto +3
StrCpy $archprefix "x86"
StrCpy $sysnativedir $SYSDIR
- ;MessageBox MB_YESNO "Found $sysnativedir\${REDIST_DLL_NAME}" IDYES FoundLbl
+ ${WinVerGetMajor} $0
+ ${WinVerGetMinor} $1
+ StrCpy $winvermajor $0
+ StrCpy $winverminor $1
IfFileExists $sysnativedir\${REDIST_DLL_NAME} MaybeFoundInSystemLbl
SearchSxSLbl:
+ IntCmp $winvermajor 6 WVCheckMinorLbl WVCheckDoneLbl NotFoundLbl
+ WVCheckMinorLbl:
+ IntCmp $winverminor 1 WVCheckDoneLbl WVCheckDoneLbl NotFoundLbl
+ WVCheckDoneLbl:
FindFirst $0 $1 $WINDIR\WinSxS\$archprefix*
LoopLbl:
StrCmp $1 "" NotFoundLbl
diff --git a/erts/include/internal/ethread.h b/erts/include/internal/ethread.h
index e1885c627a..aef31e282a 100644
--- a/erts/include/internal/ethread.h
+++ b/erts/include/internal/ethread.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2004-2012. All Rights Reserved.
*
* The 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/erts/lib_src/Makefile.in b/erts/lib_src/Makefile.in
index aed889eaef..88083bfe7d 100644
--- a/erts/lib_src/Makefile.in
+++ b/erts/lib_src/Makefile.in
@@ -17,6 +17,7 @@
# %CopyrightEnd%
#
+include $(ERL_TOP)/make/output.mk
include $(ERL_TOP)/make/target.mk
include ../include/internal/$(TARGET)/ethread.mk
@@ -326,6 +327,7 @@ _create_dirs := $(shell mkdir -p $(CREATE_DIRS))
all: $(OBJ_DIR)/MADE
$(OBJ_DIR)/MADE: $(ETHREAD_LIB) $(ERTS_LIBS) $(ERTS_INTERNAL_LIBS)
+ $(gen_verbose)
ifeq ($(OMIT_OMIT_FP),yes)
@echo '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *'
@echo '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *'
@@ -335,7 +337,7 @@ ifeq ($(OMIT_OMIT_FP),yes)
@echo '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *'
@echo '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *'
endif
- echo $? > $(OBJ_DIR)/MADE
+ $(V_at)echo $? > $(OBJ_DIR)/MADE
#
# The libs ...
@@ -345,93 +347,97 @@ AR_OUT=-out:
AR_FLAGS=
else
AR_OUT=
+ifeq ($(V),0)
+AR_FLAGS=rc
+else
AR_FLAGS=rcv
endif
+endif
ifndef RANLIB
RANLIB=true
endif
$(ETHREAD_LIB): $(ETHREAD_LIB_OBJS)
- $(AR) $(AR_FLAGS) $(AR_OUT)$@ $(ETHREAD_LIB_OBJS)
- $(RANLIB) $@
+ $(V_AR) $(AR_FLAGS) $(AR_OUT)$@ $(ETHREAD_LIB_OBJS)
+ $(V_RANLIB) $@
$(ERTS_INTERNAL_LIB): $(ERTS_INTERNAL_LIB_OBJS)
- $(AR) $(AR_FLAGS) $(AR_OUT)$@ $(ERTS_INTERNAL_LIB_OBJS)
- $(RANLIB) $@
+ $(V_AR) $(AR_FLAGS) $(AR_OUT)$@ $(ERTS_INTERNAL_LIB_OBJS)
+ $(V_RANLIB) $@
$(ERTS_INTERNAL_r_LIB): $(ERTS_INTERNAL_r_LIB_OBJS)
- $(AR) $(AR_FLAGS) $(AR_OUT)$@ $(ERTS_INTERNAL_r_LIB_OBJS)
- $(RANLIB) $@
+ $(V_AR) $(AR_FLAGS) $(AR_OUT)$@ $(ERTS_INTERNAL_r_LIB_OBJS)
+ $(V_RANLIB) $@
$(ERTS_MD_LIB): $(ERTS_MD_LIB_OBJS)
- $(AR) $(AR_FLAGS) $(AR_OUT)$@ $(ERTS_MD_LIB_OBJS)
- $(RANLIB) $@
+ $(V_AR) $(AR_FLAGS) $(AR_OUT)$@ $(ERTS_MD_LIB_OBJS)
+ $(V_RANLIB) $@
$(ERTS_MDd_LIB): $(ERTS_MDd_LIB_OBJS)
- $(AR) $(AR_FLAGS) $(AR_OUT)$@ $(ERTS_MDd_LIB_OBJS)
- $(RANLIB) $@
+ $(V_AR) $(AR_FLAGS) $(AR_OUT)$@ $(ERTS_MDd_LIB_OBJS)
+ $(V_RANLIB) $@
$(ERTS_MT_LIB): $(ERTS_MT_LIB_OBJS)
- $(AR) $(AR_FLAGS) $(AR_OUT)$@ $(ERTS_MT_LIB_OBJS)
- $(RANLIB) $@
+ $(V_AR) $(AR_FLAGS) $(AR_OUT)$@ $(ERTS_MT_LIB_OBJS)
+ $(V_RANLIB) $@
$(ERTS_MTd_LIB): $(ERTS_MTd_LIB_OBJS)
- $(AR) $(AR_FLAGS) $(AR_OUT)$@ $(ERTS_MTd_LIB_OBJS)
- $(RANLIB) $@
+ $(V_AR) $(AR_FLAGS) $(AR_OUT)$@ $(ERTS_MTd_LIB_OBJS)
+ $(V_RANLIB) $@
$(ERTS_r_LIB): $(ERTS_r_LIB_OBJS)
- $(AR) $(AR_FLAGS) $(AR_OUT)$@ $(ERTS_r_LIB_OBJS)
- $(RANLIB) $@
+ $(V_AR) $(AR_FLAGS) $(AR_OUT)$@ $(ERTS_r_LIB_OBJS)
+ $(V_RANLIB) $@
$(ERTS_LIB): $(ERTS_LIB_OBJS)
- $(AR) $(AR_FLAGS) $(AR_OUT)$@ $(ERTS_LIB_OBJS)
- $(RANLIB) $@
+ $(V_AR) $(AR_FLAGS) $(AR_OUT)$@ $(ERTS_LIB_OBJS)
+ $(V_RANLIB) $@
#
# Object files
#
$(r_OBJ_DIR)/ethr_x86_sse2_asm.o: pthread/ethr_x86_sse2_asm.c
- $(CC) -msse2 $(THR_DEFS) $(CFLAGS) $(INCLUDES) -c $< -o $@
+ $(V_CC) -msse2 $(THR_DEFS) $(CFLAGS) $(INCLUDES) -c $< -o $@
$(r_OBJ_DIR)/%.o: common/%.c
- $(CC) $(THR_DEFS) $(CFLAGS) $(INCLUDES) -c $< -o $@
+ $(V_CC) $(THR_DEFS) $(CFLAGS) $(INCLUDES) -c $< -o $@
$(r_OBJ_DIR)/%.o: $(ETHR_THR_LIB_BASE_DIR)/%.c
- $(CC) $(THR_DEFS) $(CFLAGS) $(INCLUDES) -c $< -o $@
+ $(V_CC) $(THR_DEFS) $(CFLAGS) $(INCLUDES) -c $< -o $@
$(OBJ_DIR)/%.o: common/%.c
- $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
+ $(V_CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
$(OBJ_DIR)/%.o: $(ETHR_THR_LIB_BASE_DIR)/%.c
- $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
+ $(V_CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
# Win32 specific
$(MD_OBJ_DIR)/%.o: common/%.c
- $(CC) $(THR_DEFS) $(CFLAGS) -MD $(INCLUDES) -c $< -o $@
+ $(V_CC) $(THR_DEFS) $(CFLAGS) -MD $(INCLUDES) -c $< -o $@
$(MD_OBJ_DIR)/%.o: $(ETHR_THR_LIB_BASE_DIR)/%.c
- $(CC) $(THR_DEFS) $(CFLAGS) -MD $(INCLUDES) -c $< -o $@
+ $(V_CC) $(THR_DEFS) $(CFLAGS) -MD $(INCLUDES) -c $< -o $@
$(MDd_OBJ_DIR)/%.o: common/%.c
- $(CC) $(THR_DEFS) $(CFLAGS) -MDd $(INCLUDES) -c $< -o $@
+ $(V_CC) $(THR_DEFS) $(CFLAGS) -MDd $(INCLUDES) -c $< -o $@
$(MDd_OBJ_DIR)/%.o: $(ETHR_THR_LIB_BASE_DIR)/%.c
- $(CC) $(THR_DEFS) $(CFLAGS) -MDd $(INCLUDES) -c $< -o $@
+ $(V_CC) $(THR_DEFS) $(CFLAGS) -MDd $(INCLUDES) -c $< -o $@
$(MT_OBJ_DIR)/%.o: common/%.c
- $(CC) $(THR_DEFS) $(CFLAGS) -MT $(INCLUDES) -c $< -o $@
+ $(V_CC) $(THR_DEFS) $(CFLAGS) -MT $(INCLUDES) -c $< -o $@
$(MT_OBJ_DIR)/%.o: $(ETHR_THR_LIB_BASE_DIR)/%.c
- $(CC) $(THR_DEFS) $(CFLAGS) -MT $(INCLUDES) -c $< -o $@
+ $(V_CC) $(THR_DEFS) $(CFLAGS) -MT $(INCLUDES) -c $< -o $@
$(MTd_OBJ_DIR)/%.o: common/%.c
- $(CC) $(THR_DEFS) $(CFLAGS) -MTd $(INCLUDES) -c $< -o $@
+ $(V_CC) $(THR_DEFS) $(CFLAGS) -MTd $(INCLUDES) -c $< -o $@
$(MTd_OBJ_DIR)/%.o: $(ETHR_THR_LIB_BASE_DIR)/%.c
- $(CC) $(THR_DEFS) $(CFLAGS) -MTd $(INCLUDES) -c $< -o $@
+ $(V_CC) $(THR_DEFS) $(CFLAGS) -MTd $(INCLUDES) -c $< -o $@
#
# Install
@@ -560,73 +566,74 @@ DEPEND_MK=$(OBJ_DIR)/depend.mk
.PHONY: depend
depend: $(DEPEND_MK)
$(DEPEND_MK):
- @echo "Generating dependency file $(DEPEND_MK)..."
+ $(gen_verbose)
+ $(V_colon)@echo "Generating dependency file $(DEPEND_MK)..."
@echo "# Generated dependency rules" > $(DEPEND_MK);
@echo "# " >> $(DEPEND_MK);
ifneq ($(strip $(ETHREAD_LIB_SRC)),)
@echo "# ethread lib objects..." >> $(DEPEND_MK);
ifeq ($(USING_VC),yes)
- $(DEP_CC) -MM $(THR_DEFS) $(DEP_FLAGS) $(ETHREAD_LIB_SRC) \
+ $(V_at)$(DEP_CC) -MM $(THR_DEFS) $(DEP_FLAGS) $(ETHREAD_LIB_SRC) \
| $(SED_MD_DEPEND) >> $(DEPEND_MK)
- $(DEP_CC) -MM $(THR_DEFS) $(DEP_FLAGS) $(ETHREAD_LIB_SRC) \
+ $(V_at)$(DEP_CC) -MM $(THR_DEFS) $(DEP_FLAGS) $(ETHREAD_LIB_SRC) \
| $(SED_MDd_DEPEND) >> $(DEPEND_MK)
else
- $(DEP_CC) -MM $(THR_DEFS) $(DEP_FLAGS) $(ETHREAD_LIB_SRC) \
- | $(SED_r_DEPEND) >> $(DEPEND_MK)
+ $(V_at)$(DEP_CC) -MM $(THR_DEFS) $(DEP_FLAGS) $(ETHREAD_LIB_SRC) \
+ | $(SED_r_DEPEND) >$(V_at)> $(DEPEND_MK)
endif
endif
ifneq ($(strip $(ERTS_INTERNAL_LIB_SRCS)),)
ifneq ($(strip $(ETHREAD_LIB_SRC)),)
@echo "# erts_internal_r lib objects..." >> $(DEPEND_MK);
ifeq ($(USING_VC),yes)
- $(DEP_CC) -MM $(THR_DEFS) $(DEP_FLAGS) $(ERTS_INTERNAL_LIB_SRCS) \
+ $(V_at)$(DEP_CC) -MM $(THR_DEFS) $(DEP_FLAGS) $(ERTS_INTERNAL_LIB_SRCS) \
| $(SED_MD_DEPEND) >> $(DEPEND_MK)
- $(DEP_CC) -MM $(THR_DEFS) $(DEP_FLAGS) $(ERTS_INTERNAL_LIB_SRCS) \
+ $(V_at)$(DEP_CC) -MM $(THR_DEFS) $(DEP_FLAGS) $(ERTS_INTERNAL_LIB_SRCS) \
| $(SED_MDd_DEPEND) >> $(DEPEND_MK)
else
- $(DEP_CC) -MM $(THR_DEFS) $(DEP_FLAGS) $(ERTS_INTERNAL_LIB_SRCS) \
+ $(V_at)$(DEP_CC) -MM $(THR_DEFS) $(DEP_FLAGS) $(ERTS_INTERNAL_LIB_SRCS) \
| $(SED_r_DEPEND) >> $(DEPEND_MK)
endif
endif
@echo "# erts_internal lib objects..." >> $(DEPEND_MK);
ifeq ($(USING_VC),yes)
- $(DEP_CC) -MM $(DEP_FLAGS) $(ERTS_INTERNAL_LIB_SRCS) \
+ $(V_at)$(DEP_CC) -MM $(DEP_FLAGS) $(ERTS_INTERNAL_LIB_SRCS) \
| $(SED_MD_DEPEND) >> $(DEPEND_MK)
- $(DEP_CC) -MM $(DEP_FLAGS) $(ERTS_INTERNAL_LIB_SRCS) \
+ $(V_at)$(DEP_CC) -MM $(DEP_FLAGS) $(ERTS_INTERNAL_LIB_SRCS) \
| $(SED_MDd_DEPEND) >> $(DEPEND_MK)
else
- $(DEP_CC) -MM $(DEP_FLAGS) $(ERTS_INTERNAL_LIB_SRCS) \
+ $(V_at)$(DEP_CC) -MM $(DEP_FLAGS) $(ERTS_INTERNAL_LIB_SRCS) \
| $(SED_DEPEND) >> $(DEPEND_MK)
endif
endif
ifneq ($(strip $(ERTS_LIB_SRCS)),)
ifeq ($(USING_VC),yes)
@echo "# erts_MD lib objects..." >> $(DEPEND_MK);
- $(DEP_CC) -MM $(THR_DEFS) $(DEP_FLAGS) $(ERTS_LIB_SRCS) \
+ $(V_at)$(DEP_CC) -MM $(THR_DEFS) $(DEP_FLAGS) $(ERTS_LIB_SRCS) \
| $(SED_MD_DEPEND) >> $(DEPEND_MK)
@echo "# erts_MDd lib objects..." >> $(DEPEND_MK);
- $(DEP_CC) -MM $(THR_DEFS) $(DEP_FLAGS) $(ERTS_LIB_SRCS) \
+ $(V_at)$(DEP_CC) -MM $(THR_DEFS) $(DEP_FLAGS) $(ERTS_LIB_SRCS) \
| $(SED_MDd_DEPEND) >> $(DEPEND_MK)
@echo "# erts_MT lib objects..." >> $(DEPEND_MK);
- $(DEP_CC) -MM $(THR_DEFS) $(DEP_FLAGS) $(ERTS_LIB_SRCS) \
+ $(V_at)$(DEP_CC) -MM $(THR_DEFS) $(DEP_FLAGS) $(ERTS_LIB_SRCS) \
| $(SED_MT_DEPEND) >> $(DEPEND_MK)
@echo "# erts_MTd lib objects..." >> $(DEPEND_MK);
- $(DEP_CC) -MM $(THR_DEFS) $(DEP_FLAGS) $(ERTS_LIB_SRCS) \
+ $(V_at)$(DEP_CC) -MM $(THR_DEFS) $(DEP_FLAGS) $(ERTS_LIB_SRCS) \
| $(SED_MTd_DEPEND) >> $(DEPEND_MK)
@echo "# erts_internal_r lib objects..." >> $(DEPEND_MK);
- $(DEP_CC) -MM $(THR_DEFS) $(DEP_FLAGS) $(ERTS_INTERNAL_LIB_SRCS) \
+ $(V_at)$(DEP_CC) -MM $(THR_DEFS) $(DEP_FLAGS) $(ERTS_INTERNAL_LIB_SRCS) \
| $(SED_MD_DEPEND) >> $(DEPEND_MK)
@echo "# erts_internal_r.debug lib objects..." >> $(DEPEND_MK);
- $(DEP_CC) -MM $(THR_DEFS) $(DEP_FLAGS) $(ERTS_INTERNAL_LIB_SRCS) \
+ $(V_at)$(DEP_CC) -MM $(THR_DEFS) $(DEP_FLAGS) $(ERTS_INTERNAL_LIB_SRCS) \
| $(SED_MDd_DEPEND) >> $(DEPEND_MK)
else
ifneq ($(strip $(ETHREAD_LIB_SRC)),)
@echo "# erts_r lib objects..." >> $(DEPEND_MK);
- $(DEP_CC) -MM $(THR_DEFS) $(DEP_FLAGS) $(ERTS_LIB_SRCS) \
+ $(V_at)$(DEP_CC) -MM $(THR_DEFS) $(DEP_FLAGS) $(ERTS_LIB_SRCS) \
| $(SED_r_DEPEND) >> $(DEPEND_MK)
endif
@echo "# erts lib objects..." >> $(DEPEND_MK);
- $(DEP_CC) -MM $(DEP_FLAGS) $(ERTS_LIB_SRCS) \
+ $(V_at)$(DEP_CC) -MM $(DEP_FLAGS) $(ERTS_LIB_SRCS) \
| $(SED_DEPEND) >> $(DEPEND_MK)
endif
endif
diff --git a/erts/lib_src/common/erl_misc_utils.c b/erts/lib_src/common/erl_misc_utils.c
index 3b123063fa..1b49f69581 100644
--- a/erts/lib_src/common/erl_misc_utils.c
+++ b/erts/lib_src/common/erl_misc_utils.c
@@ -28,8 +28,6 @@
#include "erl_misc_utils.h"
#if defined(__WIN32__)
-#elif defined(VXWORKS)
-# include <selectLib.h>
#else /* UNIX */
# include <stdio.h>
# include <sys/types.h>
@@ -124,6 +122,12 @@
#include <sys/sysctl.h>
#endif
+/* Simplify include for static functions */
+
+#if defined(__linux__) || defined(HAVE_KSTAT) || defined(__WIN32__) || defined(__FreeBSD__)
+# define ERTS_CPU_TOPOLOGY_ENABLED (1)
+#endif
+
static int read_topology(erts_cpu_info_t *cpuinfo);
#if defined(ERTS_HAVE_MISC_UTIL_AFFINITY_MASK__)
@@ -669,6 +673,7 @@ erts_unbind_from_cpu_str(char *str)
}
+#if defined(ERTS_CPU_TOPOLOGY_ENABLED)
static int
pn_cmp(const void *vx, const void *vy)
{
@@ -759,6 +764,7 @@ adjust_processor_nodes(erts_cpu_info_t *cpuinfo, int no_nodes)
}
}
}
+#endif
#ifdef __linux__
diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam
index e46795e2b1..344fa3ecc0 100644
--- a/erts/preloaded/ebin/erl_prim_loader.beam
+++ b/erts/preloaded/ebin/erl_prim_loader.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam
index 66b7a011d6..bea586b11c 100644
--- a/erts/preloaded/ebin/erlang.beam
+++ b/erts/preloaded/ebin/erlang.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam
new file mode 100644
index 0000000000..af06c2a1cb
--- /dev/null
+++ b/erts/preloaded/ebin/erts_internal.beam
Binary files differ
diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam
index 1a250932da..9710204552 100644
--- a/erts/preloaded/ebin/init.beam
+++ b/erts/preloaded/ebin/init.beam
Binary files differ
diff --git a/erts/preloaded/ebin/otp_ring0.beam b/erts/preloaded/ebin/otp_ring0.beam
index 2fa007f683..0ba1cb8f73 100644
--- a/erts/preloaded/ebin/otp_ring0.beam
+++ b/erts/preloaded/ebin/otp_ring0.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam
index 19cf856754..b8f71b0c1e 100644
--- a/erts/preloaded/ebin/prim_file.beam
+++ b/erts/preloaded/ebin/prim_file.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam
index 5409cf2dfc..a1aca09d1d 100644
--- a/erts/preloaded/ebin/prim_inet.beam
+++ b/erts/preloaded/ebin/prim_inet.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam
index 55697cfe11..bec1f2cc21 100644
--- a/erts/preloaded/ebin/prim_zip.beam
+++ b/erts/preloaded/ebin/prim_zip.beam
Binary files differ
diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam
index d2f30fd9cd..1ac89dd42a 100644
--- a/erts/preloaded/ebin/zlib.beam
+++ b/erts/preloaded/ebin/zlib.beam
Binary files differ
diff --git a/erts/preloaded/src/Makefile b/erts/preloaded/src/Makefile
index 5bcc2eb6e4..a224b6a5d4 100644
--- a/erts/preloaded/src/Makefile
+++ b/erts/preloaded/src/Makefile
@@ -40,7 +40,8 @@ PRE_LOADED_MODULES = \
zlib \
prim_zip \
otp_ring0 \
- erlang
+ erlang \
+ erts_internal
RELSYSDIR = $(RELEASE_PATH)/lib/erts-$(VSN)
# not $(RELEASE_PATH)/erts-$(VSN)/preloaded
diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl
index 646acf5798..061db72dd8 100644
--- a/erts/preloaded/src/erlang.erl
+++ b/erts/preloaded/src/erlang.erl
@@ -79,6 +79,7 @@
-export([bump_reductions/1, byte_size/1, call_on_load_function/1]).
-export([cancel_timer/1, check_old_code/1, check_process_code/2, crc32/1]).
-export([crc32/2, crc32_combine/3, date/0, decode_packet/3]).
+-export([delete_element/2]).
-export([delete_module/1, demonitor/1, demonitor/2, display/1]).
-export([display_nl/0, display_string/1, dist_exit/3, erase/0, erase/1]).
-export([error/1, error/2, exit/1, exit/2, external_size/1]).
@@ -88,6 +89,7 @@
-export([garbage_collect_message_area/0, get/0, get/1, get_keys/1]).
-export([get_module_info/1, get_stacktrace/0, group_leader/0]).
-export([group_leader/2, halt/0, halt/1, halt/2, hash/2, hibernate/3]).
+-export([insert_element/3]).
-export([integer_to_list/1, iolist_size/1, iolist_to_binary/1]).
-export([is_alive/0, is_builtin/3, is_process_alive/1, length/1, link/1]).
-export([list_to_atom/1, list_to_binary/1, list_to_bitstr/1]).
@@ -529,6 +531,14 @@ date() ->
decode_packet(_Type, _Bin, _Options) ->
erlang:nif_error(undefined).
+%% delete_element/2
+-spec erlang:delete_element(Index, Tuple1) -> Tuple2 when
+ Index :: pos_integer(),
+ Tuple1 :: tuple(),
+ Tuple2 :: tuple().
+delete_element(_Index, _Tuple1) ->
+ erlang:nif_error(undefined).
+
%% delete_module/1
-spec delete_module(Module) -> true | undefined when
Module :: module().
@@ -820,6 +830,15 @@ hash(_Term, _Range) ->
hibernate(_Module, _Function, _Args) ->
erlang:nif_error(undefined).
+%% insert_element/3
+-spec erlang:insert_element(Index, Tuple1, Term) -> Tuple2 when
+ Index :: pos_integer(),
+ Tuple1 :: tuple(),
+ Tuple2 :: tuple(),
+ Term :: term().
+insert_element(_Index, _Tuple1, _Term) ->
+ erlang:nif_error(undefined).
+
%% integer_to_list/1
-spec integer_to_list(Integer) -> string() when
Integer :: integer().
@@ -1075,57 +1094,6 @@ phash2(_Term, _Range) ->
pid_to_list(_Pid) ->
erlang:nif_error(undefined).
-%% port_close/1
--spec port_close(Port) -> true when
- Port :: port() | atom().
-port_close(_Port) ->
- erlang:nif_error(undefined).
-
-%% port_command/2
--spec port_command(Port, Data) -> true when
- Port :: port() | atom(),
- Data :: iodata().
-port_command(_Port, _Data) ->
- erlang:nif_error(undefined).
-
-%% port_command/3
--spec port_command(Port, Data, OptionList) -> boolean() when
- Port :: port() | atom(),
- Data :: iodata(),
- OptionList :: [Option],
- Option :: force | nosuspend.
-port_command(_Port, _Data, _OptionList) ->
- erlang:nif_error(undefined).
-
-%% port_connect/2
--spec port_connect(Port, Pid) -> true when
- Port :: port() | atom(),
- Pid :: pid().
-port_connect(_Port, _Pid) ->
- erlang:nif_error(undefined).
-
-%% port_control/3
--spec port_control(Port, Operation, Data) -> Res when
- Port :: port() | atom(),
- Operation :: integer(),
- Data :: iodata(),
- Res :: string() | binary().
-port_control(_Port, _Operation, _Data) ->
- erlang:nif_error(undefined).
-
-%% port_get_data/1
--spec erlang:port_get_data(P1) -> term() when
- P1 :: port() | atom().
-port_get_data(_P1) ->
- erlang:nif_error(undefined).
-
-%% port_set_data/2
--spec erlang:port_set_data(P1, P2) -> true when
- P1 :: port() | atom(),
- P2 :: term().
-port_set_data(_P1, _P2) ->
- erlang:nif_error(undefined).
-
%% port_to_list/1
-spec erlang:port_to_list(Port) -> string() when
Port :: port().
@@ -1699,60 +1667,12 @@ nodes(_Arg) ->
| in
| out
| binary
- | eof.
+ | eof
+ | {parallelism, Boolean :: boolean()}
+ | hide.
open_port(_PortName,_PortSettings) ->
erlang:nif_error(undefined).
-%% Shadowed by erl_bif_types: erlang:port_call/2
--spec erlang:port_call(Port, Data) -> term() when
- Port :: port() | atom(),
- Data :: term().
-port_call(_Port, _Data) ->
- erlang:nif_error(undefined).
-
-%% Shadowed by erl_bif_types: erlang:port_call/3
--spec erlang:port_call(Port, Operation, Data) -> term() when
- Port :: port() | atom(),
- Operation :: integer(),
- Data :: term().
-port_call(_Port, _Operation, _Data) ->
- erlang:nif_error(undefined).
-
--type port_info_item() ::
- registered_name |
- id |
- connected |
- links |
- name |
- input |
- output |
- os_pid.
-
--type port_info_result_item() ::
- {registered_name, RegName :: atom()} |
- {id, Index :: non_neg_integer()} |
- {connected, Pid :: pid()} |
- {links, Pids :: [pid()]} |
- {name, String :: string()} |
- {input, Bytes :: non_neg_integer()} |
- {output, Bytes :: non_neg_integer()} |
- {os_pid, OsPid :: non_neg_integer() | 'undefined'}.
-
-%% Shadowed by erl_bif_types: erlang:port_info/1
--spec erlang:port_info(Port) -> Result when
- Port :: port() | atom(),
- Result :: [port_info_result_item()] | undefined.
-port_info(_Result) ->
- erlang:nif_error(undefined).
-
-%% Shadowed by erl_bif_types: erlang:port_info/2
--spec erlang:port_info(Port, Item) -> Result when
- Port :: port() | atom(),
- Item :: port_info_item(),
- Result :: port_info_result_item() | undefined.
-port_info(_Result, _Item) ->
- erlang:nif_error(undefined).
-
-type priority_level() ::
low | normal | high | max.
@@ -1836,7 +1756,7 @@ process_flag(_Flag, _Value) ->
{group_leader, GroupLeader :: pid()} |
{heap_size, Size :: non_neg_integer()} |
{initial_call, mfa()} |
- {links, Pids :: [pid()]} |
+ {links, PidsAndPorts :: [pid() | port()]} |
{last_calls, false | (Calls :: [mfa()])} |
{memory, Size :: non_neg_integer()} |
{message_que_len, MessageQueueLen :: non_neg_integer()} |
@@ -2530,6 +2450,216 @@ suspend_process(P) ->
end.
%%
+%% Port BIFs
+%%
+%% Currently all port BIFs calls the corresponding
+%% erts_internal:port_*() native function which perform
+%% most of the actual work. These native functions should
+%% *never* be called directly by other functionality. The
+%% native functions may be changed, or removed without any
+%% notice whatsoever!
+%%
+%% IMPORTANT NOTE:
+%% When the erts_internal:port_*() native functions return
+%% a reference, they have also internally prepared the
+%% message queue of the caller for a receive that will
+%% unconditionally wait for a message containing this
+%% reference. If the erlang code calling these native
+%% functions do not do this, subsequent receives will not
+%% work as expected! That is, it is of *vital importance*
+%% that the receive is performed as described above!
+%%
+
+-spec port_command(Port, Data) -> 'true' when
+ Port :: port() | atom(),
+ Data :: iodata().
+
+port_command(Port, Data) ->
+ case case erts_internal:port_command(Port, Data, []) of
+ Ref when erlang:is_reference(Ref) -> receive {Ref, Res} -> Res end;
+ Res -> Res
+ end of
+ true -> true;
+ Error -> erlang:error(Error, [Port, Data])
+ end.
+
+-spec port_command(Port, Data, OptionList) -> boolean() when
+ Port :: port() | atom(),
+ Data :: iodata(),
+ Option :: force | nosuspend,
+ OptionList :: [Option].
+
+port_command(Port, Data, Flags) ->
+ case case erts_internal:port_command(Port, Data, Flags) of
+ Ref when erlang:is_reference(Ref) -> receive {Ref, Res} -> Res end;
+ Res -> Res
+ end of
+ Bool when Bool == true; Bool == false -> Bool;
+ Error -> erlang:error(Error, [Port, Data, Flags])
+ end.
+
+-spec port_connect(Port, Pid) -> 'true' when
+ Port :: port() | atom(),
+ Pid :: pid().
+
+port_connect(Port, Pid) ->
+ case case erts_internal:port_connect(Port, Pid) of
+ Ref when erlang:is_reference(Ref) -> receive {Ref, Res} -> Res end;
+ Res -> Res
+ end of
+ true -> true;
+ Error -> erlang:error(Error, [Port, Pid])
+ end.
+
+-spec port_close(Port) -> 'true' when
+ Port :: port() | atom().
+
+port_close(Port) ->
+ case case erts_internal:port_close(Port) of
+ Ref when erlang:is_reference(Ref) -> receive {Ref, Res} -> Res end;
+ Res -> Res
+ end of
+ true -> true;
+ Error -> erlang:error(Error, [Port])
+ end.
+
+-spec port_control(Port, Operation, Data) -> iodata() | binary() when
+ Port :: port() | atom(),
+ Operation :: integer(),
+ Data :: iodata().
+
+port_control(Port, Operation, Data) ->
+ case case erts_internal:port_control(Port, Operation, Data) of
+ Ref when erlang:is_reference(Ref) -> receive {Ref, Res} -> Res end;
+ Res -> Res
+ end of
+ badarg -> erlang:error(badarg, [Port, Operation, Data]);
+ Result -> Result
+ end.
+
+-spec erlang:port_call(Port, Data) -> term() when
+ Port :: port() | atom(),
+ Data :: term().
+
+port_call(Port, Data) ->
+ case case erts_internal:port_call(Port, 0, Data) of
+ Ref when erlang:is_reference(Ref) -> receive {Ref, Res} -> Res end;
+ Res -> Res
+ end of
+ {ok, Result} -> Result;
+ Error -> erlang:error(Error, [Port, Data])
+ end.
+
+-spec erlang:port_call(Port, Operation, Data) -> term() when
+ Port :: port() | atom(),
+ Operation :: integer(),
+ Data :: term().
+
+port_call(Port, Operation, Data) ->
+ case case erts_internal:port_call(Port, Operation, Data) of
+ Ref when erlang:is_reference(Ref) -> receive {Ref, Res} -> Res end;
+ Res -> Res
+ end of
+ {ok, Result} -> Result;
+ Error -> erlang:error(Error, [Port, Operation, Data])
+ end.
+
+-spec erlang:port_info(Port) -> Result when
+ Port :: port() | atom(),
+ ResultItem :: {registered_name, RegisteredName :: atom()}
+ | {id, Index :: non_neg_integer()}
+ | {connected, Pid :: pid()}
+ | {links, Pids :: [pid()]}
+ | {name, String :: string()}
+ | {input, Bytes :: non_neg_integer()}
+ | {output, Bytes :: non_neg_integer()}
+ | {os_pid, OsPid :: non_neg_integer() | 'undefined'},
+ Result :: [ResultItem] | 'undefined'.
+
+port_info(Port) ->
+ case case erts_internal:port_info(Port) of
+ Ref when erlang:is_reference(Ref) -> receive {Ref, Res} -> Res end;
+ Res -> Res
+ end of
+ badarg -> erlang:error(badarg, [Port]);
+ Result -> Result
+ end.
+
+-spec erlang:port_info(Port, connected) -> {connected, Pid} | 'undefined' when
+ Port :: port() | atom(),
+ Pid :: pid();
+ (Port, id) -> {id, Index} | 'undefined' when
+ Port :: port() | atom(),
+ Index :: non_neg_integer();
+ (Port, input) -> {input, Bytes} | 'undefined' when
+ Port :: port() | atom(),
+ Bytes :: non_neg_integer();
+ (Port, links) -> {links, Pids} | 'undefined' when
+ Port :: port() | atom(),
+ Pids :: [pid()];
+ (Port, locking) -> {locking, Locking} | 'undefined' when
+ Port :: port() | atom(),
+ Locking :: 'false' | 'port_level' | 'driver_level';
+ (Port, memory) -> {memory, Bytes} | 'undefined' when
+ Port :: port() | atom(),
+ Bytes :: non_neg_integer();
+ (Port, monitors) -> {monitors, Monitors} | 'undefined' when
+ Port :: port() | atom(),
+ Monitors :: [{process, pid()}];
+ (Port, name) -> {name, Name} | 'undefined' when
+ Port :: port() | atom(),
+ Name :: string();
+ (Port, os_pid) -> {os_pid, OsPid} | 'undefined' when
+ Port :: port() | atom(),
+ OsPid :: non_neg_integer() | 'undefined';
+ (Port, output) -> {output, Bytes} | 'undefined' when
+ Port :: port() | atom(),
+ Bytes :: non_neg_integer();
+ (Port, parallelism) -> {parallelism, Boolean} | 'undefined' when
+ Port :: port() | atom(),
+ Boolean :: boolean();
+ (Port, queue_size) -> {queue_size, Bytes} | 'undefined' when
+ Port :: port() | atom(),
+ Bytes :: non_neg_integer();
+ (Port, registered_name) -> {registered_name, RegisteredName} | [] | 'undefined' when
+ Port :: port() | atom(),
+ RegisteredName :: atom().
+
+port_info(Port, Item) ->
+ case case erts_internal:port_info(Port, Item) of
+ Ref when erlang:is_reference(Ref) -> receive {Ref, Res} -> Res end;
+ Res -> Res
+ end of
+ badarg -> erlang:error(badarg, [Port, Item]);
+ Result -> Result
+ end.
+
+-spec erlang:port_set_data(Port, Data) -> 'true' when
+ Port :: port() | atom(),
+ Data :: term().
+
+port_set_data(Port, Data) ->
+ case case erts_internal:port_set_data(Port, Data) of
+ Ref when erlang:is_reference(Ref) -> receive {Ref, Res} -> Res end;
+ Res -> Res
+ end of
+ badarg -> erlang:error(badarg, [Port, Data]);
+ Result -> Result
+ end.
+
+-spec erlang:port_get_data(Port) -> term() when
+ Port :: port() | atom().
+
+port_get_data(Port) ->
+ case case erts_internal:port_get_data(Port) of
+ Ref when erlang:is_reference(Ref) -> receive {Ref, Res} -> Res end;
+ Res -> Res
+ end of
+ {ok, Data} -> Data;
+ Error -> erlang:error(Error, [Port])
+ end.
+
+%%
%% If the emulator wants to perform a distributed command and
%% a connection is not established to the actual node the following
%% functions are called in order to set up the connection and then
diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl
new file mode 100644
index 0000000000..f1c83f4518
--- /dev/null
+++ b/erts/preloaded/src/erts_internal.erl
@@ -0,0 +1,155 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012. All Rights Reserved.
+%%
+%% The 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%
+%%
+
+%%
+%% As the module name imply, this module is here for ERTS internal
+%% functionality. As an application programmer you should *never*
+%% call anything in this module directly. Functions exported by
+%% this module may change behaviour or be removed at any time
+%% without any notice whatsoever. Everything in this module is
+%% intentionally left undocumented, and should remain so.
+%%
+
+-module(erts_internal).
+
+-export([await_port_send_result/3]).
+
+-export([port_command/3, port_connect/2, port_close/1,
+ port_control/3, port_call/3, port_set_data/2, port_get_data/1,
+ port_info/1, port_info/2]).
+
+%%
+%% Await result of send to port
+%%
+
+await_port_send_result(Ref, Busy, Ok) ->
+ receive
+ {Ref, false} -> Busy;
+ {Ref, _} -> Ok
+ end.
+
+%%
+%% Statically linked port NIFs
+%%
+
+-spec erts_internal:port_command(Port, Data, OptionList) -> Result when
+ Port :: port() | atom(),
+ Data :: iodata(),
+ OptionList :: [Option],
+ Option :: force | nosuspend,
+ Result :: boolean() | reference() | badarg | notsup.
+port_command(_Port, _Data, _OptionList) ->
+ erlang:nif_error(undefined).
+
+-spec erts_internal:port_connect(Port, Pid) -> Result when
+ Port :: port() | atom(),
+ Pid :: pid(),
+ Result :: true | reference() | badarg.
+port_connect(_Port, _Pid) ->
+ erlang:nif_error(undefined).
+
+-spec erts_internal:port_close(Port) -> Result when
+ Port :: port() | atom(),
+ Result :: true | reference() | badarg.
+port_close(_Port) ->
+ erlang:nif_error(undefined).
+
+-spec erts_internal:port_control(Port, Operation, Data) -> Result when
+ Port :: port() | atom(),
+ Operation :: integer(),
+ Data :: iodata(),
+ Result :: string() | binary() | reference() | badarg.
+port_control(_Port, _Operation, _Data) ->
+ erlang:nif_error(undefined).
+
+-spec erts_internal:port_call(Port, Operation, Data) -> Result when
+ Port :: port() | atom(),
+ Operation :: integer(),
+ Data :: term(),
+ Result :: {ok, term()} | reference() | badarg.
+port_call(_Port, _Operation, _Data) ->
+ erlang:nif_error(undefined).
+
+-spec erts_internal:port_get_data(P1) -> Result when
+ P1 :: port() | atom(),
+ Result :: {ok, term()} | reference() | badarg.
+port_get_data(_P1) ->
+ erlang:nif_error(undefined).
+
+-spec erts_internal:port_set_data(P1, P2) -> Result when
+ P1 :: port() | atom(),
+ P2 :: term(),
+ Result :: true | reference() | badarg.
+port_set_data(_P1, _P2) ->
+ erlang:nif_error(undefined).
+
+-type port_info_1_result_item() ::
+ {registered_name, RegName :: atom()} |
+ {id, Index :: non_neg_integer()} |
+ {connected, Pid :: pid()} |
+ {links, Pids :: [pid()]} |
+ {name, String :: string()} |
+ {input, Bytes :: non_neg_integer()} |
+ {output, Bytes :: non_neg_integer()} |
+ {os_pid, OsPid :: non_neg_integer() | 'undefined'}.
+
+-spec erts_internal:port_info(Port) -> Result when
+ Port :: port() | atom(),
+ Result :: [port_info_1_result_item()] | undefined | reference() | badarg | [].
+port_info(_Result) ->
+ erlang:nif_error(undefined).
+
+-type port_info_2_item() ::
+ registered_name |
+ id |
+ connected |
+ links |
+ name |
+ input |
+ output |
+ os_pid |
+ monitors |
+ memory |
+ parallelism |
+ queue_size |
+ locking.
+
+-type port_info_2_result_item() ::
+ {registered_name, RegName :: atom()} |
+ [] | % No registered name
+ {id, Index :: non_neg_integer()} |
+ {connected, Pid :: pid()} |
+ {links, Pids :: [pid()]} |
+ {name, String :: string()} |
+ {input, Bytes :: non_neg_integer()} |
+ {output, Bytes :: non_neg_integer()} |
+ {os_pid, OsPid :: non_neg_integer() | 'undefined'} |
+ {monitors, Monitors :: [{process, pid()}]} |
+ {memory, MemSz :: non_neg_integer()} |
+ {parallelism, Boolean :: boolean()} |
+ {queue_size, QSz :: non_neg_integer()} |
+ {locking, Locking :: 'false' | 'port_level' | 'driver_level'}.
+
+-spec erts_internal:port_info(Port, Item) -> Result when
+ Port :: port() | atom(),
+ Item :: port_info_2_item(),
+ Result :: port_info_2_result_item() | undefined | reference() | badarg.
+
+port_info(_Result, _Item) ->
+ erlang:nif_error(undefined).
diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl
index eafab1bae4..c412b7faf2 100644
--- a/erts/preloaded/src/prim_file.erl
+++ b/erts/preloaded/src/prim_file.erl
@@ -27,7 +27,7 @@
%% Generic file contents operations
-export([open/2, close/1, datasync/1, sync/1, advise/4, position/2, truncate/1,
write/2, pwrite/2, pwrite/3, read/2, read_line/1, pread/2, pread/3,
- copy/3, sendfile/10]).
+ copy/3, sendfile/10, allocate/3]).
%% Specialized file operations
-export([open/1, open/3]).
@@ -100,6 +100,7 @@
-define(FILE_FDATASYNC, 30).
-define(FILE_ADVISE, 31).
-define(FILE_SENDFILE, 32).
+-define(FILE_ALLOCATE, 33).
%% Driver responses
-define(FILE_RESP_OK, 0).
@@ -293,6 +294,11 @@ advise(#file_descriptor{module = ?MODULE, data = {Port, _}},
end.
%% Returns {error, Reason} | ok.
+allocate(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offset, Length) ->
+ Cmd = <<?FILE_ALLOCATE, Offset:64/signed, Length:64/signed>>,
+ drv_command(Port, Cmd).
+
+%% Returns {error, Reason} | ok.
write(#file_descriptor{module = ?MODULE, data = {Port, _}}, Bytes) ->
case drv_command_nt(Port, [?FILE_WRITE,erlang:dt_prepend_vm_tag_data(Bytes)],undefined) of
{ok, _Size} ->
diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl
index b639b1efdd..21d23159f0 100644
--- a/erts/preloaded/src/prim_inet.erl
+++ b/erts/preloaded/src/prim_inet.erl
@@ -1062,6 +1062,7 @@ enc_opt(multicast_ttl) -> ?UDP_OPT_MULTICAST_TTL;
enc_opt(multicast_loop) -> ?UDP_OPT_MULTICAST_LOOP;
enc_opt(add_membership) -> ?UDP_OPT_ADD_MEMBERSHIP;
enc_opt(drop_membership) -> ?UDP_OPT_DROP_MEMBERSHIP;
+enc_opt(ipv6_v6only) -> ?INET_OPT_IPV6_V6ONLY;
enc_opt(buffer) -> ?INET_LOPT_BUFFER;
enc_opt(header) -> ?INET_LOPT_HEADER;
enc_opt(active) -> ?INET_LOPT_ACTIVE;
@@ -1071,6 +1072,8 @@ enc_opt(deliver) -> ?INET_LOPT_DELIVER;
enc_opt(exit_on_close) -> ?INET_LOPT_EXITONCLOSE;
enc_opt(high_watermark) -> ?INET_LOPT_TCP_HIWTRMRK;
enc_opt(low_watermark) -> ?INET_LOPT_TCP_LOWTRMRK;
+enc_opt(high_msgq_watermark) -> ?INET_LOPT_TCP_MSGQ_HIWTRMRK;
+enc_opt(low_msgq_watermark) -> ?INET_LOPT_TCP_MSGQ_LOWTRMRK;
enc_opt(send_timeout) -> ?INET_LOPT_TCP_SEND_TIMEOUT;
enc_opt(send_timeout_close) -> ?INET_LOPT_TCP_SEND_TIMEOUT_CLOSE;
enc_opt(delay_send) -> ?INET_LOPT_TCP_DELAY_SEND;
@@ -1115,6 +1118,7 @@ dec_opt(?UDP_OPT_MULTICAST_TTL) -> multicast_ttl;
dec_opt(?UDP_OPT_MULTICAST_LOOP) -> multicast_loop;
dec_opt(?UDP_OPT_ADD_MEMBERSHIP) -> add_membership;
dec_opt(?UDP_OPT_DROP_MEMBERSHIP) -> drop_membership;
+dec_opt(?INET_OPT_IPV6_V6ONLY) -> ipv6_v6only;
dec_opt(?INET_LOPT_BUFFER) -> buffer;
dec_opt(?INET_LOPT_HEADER) -> header;
dec_opt(?INET_LOPT_ACTIVE) -> active;
@@ -1124,6 +1128,8 @@ dec_opt(?INET_LOPT_DELIVER) -> deliver;
dec_opt(?INET_LOPT_EXITONCLOSE) -> exit_on_close;
dec_opt(?INET_LOPT_TCP_HIWTRMRK) -> high_watermark;
dec_opt(?INET_LOPT_TCP_LOWTRMRK) -> low_watermark;
+dec_opt(?INET_LOPT_TCP_MSGQ_HIWTRMRK) -> high_msgq_watermark;
+dec_opt(?INET_LOPT_TCP_MSGQ_LOWTRMRK) -> low_msgq_watermark;
dec_opt(?INET_LOPT_TCP_SEND_TIMEOUT) -> send_timeout;
dec_opt(?INET_LOPT_TCP_SEND_TIMEOUT_CLOSE) -> send_timeout_close;
dec_opt(?INET_LOPT_TCP_DELAY_SEND) -> delay_send;
@@ -1178,6 +1184,7 @@ type_opt_1(recbuf) -> int;
type_opt_1(priority) -> int;
type_opt_1(tos) -> int;
type_opt_1(nodelay) -> bool;
+type_opt_1(ipv6_v6only) -> bool;
%% multicast
type_opt_1(multicast_ttl) -> int;
type_opt_1(multicast_loop) -> bool;
@@ -1218,6 +1225,8 @@ type_opt_1(deliver) ->
type_opt_1(exit_on_close) -> bool;
type_opt_1(low_watermark) -> int;
type_opt_1(high_watermark) -> int;
+type_opt_1(low_msgq_watermark) -> int;
+type_opt_1(high_msgq_watermark) -> int;
type_opt_1(send_timeout) -> time;
type_opt_1(send_timeout_close) -> bool;
type_opt_1(delay_send) -> bool;
diff --git a/erts/start_scripts/Makefile b/erts/start_scripts/Makefile
index 608679b016..3bf233cbb6 100644
--- a/erts/start_scripts/Makefile
+++ b/erts/start_scripts/Makefile
@@ -65,28 +65,28 @@ debug opt script: rel $(INSTALL_SCRIPTS) $(RELEASES_SRC)
rel: $(REL_SCRIPTS)
RELEASES.src:
- $(INSTALL_DIR) $(SS_TMP)
- ( cd $(SS_TMP) && \
+ $(gen_verbose)$(INSTALL_DIR) $(SS_TMP)
+ $(V_at)( cd $(SS_TMP) && \
$(ERL) -noinput +B -eval 'release_handler:create_RELEASES("%ERL_ROOT%", "$(SS_ROOT)", "$(SS_ROOT)/start_sasl.rel", []), halt()')
- mv RELEASES RELEASES.src
+ $(V_at)mv RELEASES RELEASES.src
$(SS_ROOT)/start_clean.script \
$(SS_ROOT)/start_clean.boot: $(SS_ROOT)/start_clean.rel
- $(INSTALL_DIR) $(SS_TMP)
- ( cd $(SS_TMP) && \
+ $(gen_verbose)$(INSTALL_DIR) $(SS_TMP)
+ $(V_at)( cd $(SS_TMP) && \
$(ERLC) $(SASL_FLAGS) $(SCRIPT_PATH) +no_warn_sasl -o $(SS_ROOT) $< )
$(SS_ROOT)/start_sasl.script \
$(SS_ROOT)/start_sasl.boot: $(SS_ROOT)/start_sasl.rel
- $(INSTALL_DIR) $(SS_TMP)
- ( cd $(SS_TMP) && \
+ $(gen_verbose)$(INSTALL_DIR) $(SS_TMP)
+ $(V_at)( cd $(SS_TMP) && \
$(ERLC) $(SASL_FLAGS) $(SCRIPT_PATH) -o $(SS_ROOT) $< )
$(SS_ROOT)/start_clean.rel: $(SS_ROOT)/start_clean.rel.src \
../vsn.mk \
$(LIBPATH)/kernel/vsn.mk \
$(LIBPATH)/stdlib/vsn.mk
- sed -e 's;%SYS_VSN%;$(SYSTEM_VSN);' \
+ $(gen_verbose)sed -e 's;%SYS_VSN%;$(SYSTEM_VSN);' \
-e 's;%ERTS_VSN%;$(VSN);' \
-e 's;%KERNEL_VSN%;$(KERNEL_VSN);' \
-e 's;%STDLIB_VSN%;$(STDLIB_VSN);' \
@@ -97,7 +97,7 @@ $(SS_ROOT)/start_sasl.rel: $(SS_ROOT)/start_sasl.rel.src \
$(LIBPATH)/kernel/vsn.mk \
$(LIBPATH)/stdlib/vsn.mk \
$(LIBPATH)/sasl/vsn.mk
- sed -e 's;%SYS_VSN%;$(SYSTEM_VSN);' \
+ $(gen_verbose)sed -e 's;%SYS_VSN%;$(SYSTEM_VSN);' \
-e 's;%ERTS_VSN%;$(VSN);' \
-e 's;%KERNEL_VSN%;$(KERNEL_VSN);' \
-e 's;%STDLIB_VSN%;$(STDLIB_VSN);' \
@@ -113,7 +113,7 @@ $(SS_ROOT)/start_all_example.rel: $(SS_ROOT)/start_all_example.rel.src \
$(LIBPATH)/mnesia/vsn.mk \
$(LIBPATH)/snmp/vsn.mk \
$(LIBPATH)/inets/vsn.mk
- sed -e 's;%SYS_VSN%;$(SYSTEM_VSN);' \
+ $(gen_verbose)sed -e 's;%SYS_VSN%;$(SYSTEM_VSN);' \
-e 's;%ERTS_VSN%;$(VSN);' \
-e 's;%KERNEL_VSN%;$(KERNEL_VSN);' \
-e 's;%STDLIB_VSN%;$(STDLIB_VSN);' \
@@ -126,33 +126,33 @@ $(SS_ROOT)/start_all_example.rel: $(SS_ROOT)/start_all_example.rel.src \
## Special target used from $(ERL_TOP)/erts/Makefile.
$(ERL_TOP)/bin/start.script:
- $(INSTALL_DIR) $(SS_TMP)
- ( cd $(SS_TMP) && \
+ $(gen_verbose)$(INSTALL_DIR) $(SS_TMP)
+ $(V_at)( cd $(SS_TMP) && \
$(ERLC) $(SCRIPT_PATH) +no_warn_sasl +otp_build -o $@ $(SS_ROOT)/start_clean.rel )
$(ERL_TOP)/bin/start_sasl.script:
- $(INSTALL_DIR) $(SS_TMP)
- ( cd $(SS_TMP) && \
+ $(gen_verbose)$(INSTALL_DIR) $(SS_TMP)
+ $(V_at)( cd $(SS_TMP) && \
$(ERLC) $(SCRIPT_PATH) +otp_build -o $@ $(SS_ROOT)/start_sasl.rel )
$(ERL_TOP)/bin/start_clean.script:
- $(INSTALL_DIR) $(SS_TMP)
- ( cd $(SS_TMP) && \
+ $(gen_verbose)$(INSTALL_DIR) $(SS_TMP)
+ $(V_at)( cd $(SS_TMP) && \
$(ERLC) $(SCRIPT_PATH) +no_warn_sasl +otp_build -o $@ $(SS_ROOT)/start_clean.rel )
## Special target used from system/build/Makefile for source code release bootstrap.
bootstrap_scripts: $(SS_ROOT)/start_clean.rel
- $(INSTALL_DIR) $(TESTROOT)/bin
- $(INSTALL_DIR) $(SS_TMP)
- ( cd $(SS_TMP) && \
+ $(V_at)$(INSTALL_DIR) $(TESTROOT)/bin
+ $(V_at)$(INSTALL_DIR) $(SS_TMP)
+ $(V_at)( cd $(SS_TMP) && \
$(ERLC) $(BOOTSTRAP_SCRIPT_PATH) +otp_build +no_module_tests \
-o $(TESTROOT)/bin/start.script $(SS_ROOT)/start_clean.rel )
- ( cd $(SS_TMP) && \
+ $(V_at)( cd $(SS_TMP) && \
$(ERLC) $(BOOTSTRAP_SCRIPT_PATH) +otp_build +no_module_tests \
-o $(TESTROOT)/bin/start_clean.script $(SS_ROOT)/start_clean.rel )
clean:
- $(RM) $(REL_SCRIPTS) $(INSTALL_SCRIPTS)
+ $(V_at)$(RM) $(REL_SCRIPTS) $(INSTALL_SCRIPTS)
docs:
@@ -163,14 +163,14 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: script
- $(INSTALL_DIR) "$(RELEASE_PATH)/releases/$(SYSTEM_VSN)"
+ $(V_at)$(INSTALL_DIR) "$(RELEASE_PATH)/releases/$(SYSTEM_VSN)"
ifneq ($(findstring win32,$(TARGET)),win32)
- $(INSTALL_DATA) RELEASES.src "$(RELEASE_PATH)/releases"
+ $(V_at)$(INSTALL_DATA) RELEASES.src "$(RELEASE_PATH)/releases"
endif
- $(INSTALL_DATA) $(INSTALL_SCRIPTS) $(REL_SCRIPTS) \
+ $(V_at)$(INSTALL_DATA) $(INSTALL_SCRIPTS) $(REL_SCRIPTS) \
"$(RELEASE_PATH)/releases/$(SYSTEM_VSN)"
- $(INSTALL_DATA) start_clean.script "$(RELEASE_PATH)/releases/$(SYSTEM_VSN)/start.script"
- $(INSTALL_DATA) start_clean.boot "$(RELEASE_PATH)/releases/$(SYSTEM_VSN)/start.boot"
+ $(V_at)$(INSTALL_DATA) start_clean.script "$(RELEASE_PATH)/releases/$(SYSTEM_VSN)/start.script"
+ $(V_at)$(INSTALL_DATA) start_clean.boot "$(RELEASE_PATH)/releases/$(SYSTEM_VSN)/start.boot"
release_docs_spec:
diff --git a/erts/test/otp_SUITE.erl b/erts/test/otp_SUITE.erl
index b7ceb0a3fd..51f07b5432 100644
--- a/erts/test/otp_SUITE.erl
+++ b/erts/test/otp_SUITE.erl
@@ -151,8 +151,8 @@ is_hipe_module(Mod) ->
end.
ssl_crypto_filter(Undef) ->
- case {code:lib_dir(crypto),code:lib_dir(ssl)} of
- {{error,bad_name},{error,bad_name}} ->
+ case {app_exists(crypto),app_exists(ssl)} of
+ {false,false} ->
filter(fun({_,{ssl,_,_}}) -> false;
({_,{crypto,_,_}}) -> false;
({_,{ssh,_,_}}) -> false;
@@ -176,8 +176,8 @@ eunit_filter(Undef) ->
end, Undef).
dialyzer_filter(Undef) ->
- case code:lib_dir(dialyzer) of
- {error,bad_name} ->
+ case app_exists(dialyzer) of
+ false ->
filter(fun({_,{dialyzer_callgraph,_,_}}) -> false;
({_,{dialyzer_codeserver,_,_}}) -> false;
({_,{dialyzer_contracts,_,_}}) -> false;
@@ -192,8 +192,8 @@ dialyzer_filter(Undef) ->
end.
wx_filter(Undef) ->
- case code:lib_dir(wx) of
- {error,bad_name} ->
+ case app_exists(wx) of
+ false ->
filter(fun({_,{MaybeWxModule,_,_}}) ->
case atom_to_list(MaybeWxModule) of
"wx"++_ -> false;
@@ -349,3 +349,16 @@ open_log(Config, Name) ->
close_log(Fd) ->
ok = file:close(Fd).
+
+app_exists(AppAtom) ->
+ case code:lib_dir(AppAtom) of
+ {error,bad_name} ->
+ false;
+ Path ->
+ case file:read_file_info(filename:join(Path,"ebin")) of
+ {ok,_} ->
+ true;
+ _ ->
+ false
+ end
+ end.
diff --git a/lib/appmon/src/Makefile b/lib/appmon/src/Makefile
index 06e61b7cc8..c42ce068b4 100644
--- a/lib/appmon/src/Makefile
+++ b/lib/appmon/src/Makefile
@@ -37,13 +37,15 @@ MODULES= \
appmon \
appmon_a \
appmon_dg \
- appmon_info \
appmon_place \
appmon_txt \
appmon_lb \
process_info \
appmon_web
+# appmon_info \ Moved to runtime tools where it belongs
+
+
HRL_FILES= appmon_dg.hrl
ERL_FILES= $(MODULES:%=%.erl)
@@ -81,10 +83,10 @@ docs:
# ----------------------------------------------------
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
# ----------------------------------------------------
# Release Target
diff --git a/lib/appmon/src/appmon.app.src b/lib/appmon/src/appmon.app.src
index 2e1aa3ef3b..aa6a08772e 100644
--- a/lib/appmon/src/appmon.app.src
+++ b/lib/appmon/src/appmon.app.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -18,7 +18,7 @@
{application, appmon,
[{description, "DEVTOOLS CXC 138 16"},
{vsn, "%VSN%"},
- {modules, [appmon, appmon_a, appmon_dg, appmon_info,
+ {modules, [appmon, appmon_a, appmon_dg, %% appmon_info, moved to runtime tools
appmon_lb, appmon_place, appmon_txt,process_info,appmon_web]},
{registered,[appmon, appmon_info, appmon_txt,webappmon_server,proc_info]},
{applications, [kernel, stdlib]}]}.
diff --git a/lib/asn1/c_src/Makefile b/lib/asn1/c_src/Makefile
index dc926947af..70238335c4 100644
--- a/lib/asn1/c_src/Makefile
+++ b/lib/asn1/c_src/Makefile
@@ -94,10 +94,10 @@ docs:
$(OBJDIR)/%.o: %.c
- $(CC) -c $(CFLAGS) -O3 -o $@ $<
+ $(V_CC) -c $(CFLAGS) -O3 -o $@ $<
$(NIF_SHARED_OBJ_FILE): $(NIF_OBJ_FILES)
- $(LD) $(LDFLAGS) -o $(NIF_SHARED_OBJ_FILE) $(NIF_OBJ_FILES) $(CLIB_FLAGS) $(LIBS)
+ $(V_LD) $(LDFLAGS) -o $(NIF_SHARED_OBJ_FILE) $(NIF_OBJ_FILES) $(CLIB_FLAGS) $(LIBS)
# ----------------------------------------------------
# Release Target
diff --git a/lib/asn1/doc/src/asn1_ug.xml b/lib/asn1/doc/src/asn1_ug.xml
index 1b399fb641..6cb251c3e2 100644
--- a/lib/asn1/doc/src/asn1_ug.xml
+++ b/lib/asn1/doc/src/asn1_ug.xml
@@ -186,13 +186,21 @@ END </pre>
The following shows how the compiler
can be called from the Erlang shell:</p>
<pre>
-1><input>asn1ct:compile("People",[ber_bin]).</input>
+1><input>asn1ct:compile("People", [ber]).</input>
+ok
+2> </pre>
+
+ <p>The <c>verbose</c> option can be given to have information
+ about the generated files printed:</p>
+ <pre>
+2><input>asn1ct:compile("People", [ber,verbose]).</input>
Erlang ASN.1 compiling "People.asn"
--{generated,"People.asn1db"}--
--{generated,"People.hrl"}--
--{generated,"People.erl"}--
ok
-2> </pre>
+3> </pre>
+
<p>The ASN.1 module People is now accepted and the abstract syntax tree
is saved in the <c>People.asn1db</c> file, the
generated Erlang code is compiled using the Erlang compiler and
@@ -229,7 +237,7 @@ receive
constructed and encoded using
<c>'People':encode('Person',Answer)</c> which takes an
instance of a defined ASN.1 type and transforms it to a
- (possibly) nested list of bytes according to the BER or PER
+ binary according to the BER or PER
encoding-rules.
<br></br>
The encoder and the decoder can also be run from
@@ -239,24 +247,12 @@ The encoder and the decoder can also be run from
<pre>
2> <input>Rockstar = {'Person',"Some Name",roving,50}.</input>
{'Person',"Some Name",roving,50}
-3> <input>{ok,Bytes} = asn1rt:encode('People','Person',Rockstar).</input>
-{ok,[&lt;&lt;243&gt;&gt;,
- [17],
- [19,9,"Some Name"],
- [2,1,[2]],
- [2,1,"2"]]}
-4> <input>Bin = list_to_binary(Bytes).</input>
-&lt;&lt;243,17,19,9,83,111,109,101,32,78,97,109,101,2,1,2,2,1,50&gt;&gt;
-5> <input>{ok,Person} = asn1rt:decode('People','Person',Bin).</input>
+3> <input>{ok,Bin} = asn1rt:encode('People','Person',Rockstar).</input>
+{ok,&lt;&lt;243,17,19,9,83,111,109,101,32,78,97,109,101,2,1,2,
+ 2,1,50&gt;&gt;}
+4> <input>{ok,Person} = asn1rt:decode('People','Person',Bin).</input>
{ok,{'Person',"Some Name",roving,50}}
-6> </pre>
- <p>Notice that the result from <c>encode</c> is a nested list which
- must be turned into a binary before the call to <c>decode</c>. A
- binary is necessary as input to decode since the module was compiled
- with the <c>ber_bin</c> option
- The reason for returning a nested list is that it is faster to produce
- and the <c>list_to_binary</c> operation is
- performed automatically when the list is sent via the Erlang port mechanism.</p>
+5> </pre>
</section>
<section>
@@ -305,17 +301,15 @@ The encoder and the decoder can also be run from
ASN.1 compiler:</p>
<pre>
erlc Person.asn
-erlc -bper_bin Person.asn
-erlc -bber_bin +optimize ../Example.asn
+erlc -bper Person.asn
+erlc -bber ../Example.asn
erlc -o ../asnfiles -I ../asnfiles -I /usr/local/standards/asn1 Person.asn </pre>
<p>The useful options for the ASN.1 compiler are:</p>
<taglist>
- <tag><c>-b[ber | per | ber_bin | per_bin | uper_bin]</c></tag>
+ <tag><c>-b[ber | per | uper]</c></tag>
<item>
<p>Choice of encoding rules, if omitted <c>ber</c> is the
- default. The <c>ber_bin</c> and <c>per_bin</c> options
- allows for optimizations and are therefore recommended
- instead of the <c>ber</c> and <c>per</c> options.</p>
+ default.</p>
</item>
<tag><c>-o OutDirectory</c></tag>
<item>
@@ -339,42 +333,12 @@ erlc -o ../asnfiles -I ../asnfiles -I /usr/local/standards/asn1 Person.asn
</item>
<tag><c>+der</c></tag>
<item>
- <p>DER encoding rule. Only when using <c>-ber</c> or
- <c>-ber_bin</c> option.</p>
- </item>
- <tag><c>+optimize</c></tag>
- <item>
- <p>This flag has effect only when used together with one of
- <c>per_bin</c> or <c>ber_bin</c> flags. It gives time optimized
- code in the generated modules and it uses another runtime module.
- In the <c>per_bin</c> case a nif is used. The
- result from an encode is a binary.</p>
- <p><em>When this flag is used you cannot use the old format</em><c>{TypeName,Value}</c> when you encode values. Since it is
- an unnecessary construct it has been removed in favor of
- performance. It
- is neither admitted to construct SEQUENCE or SET component values
- with the format <c>{ComponentName,Value}</c> since it also is
- unnecessary. The only case were it is necessary is in a CHOICE,
- were you have to pass values to the right component by specifying
- <c>{ComponentName,Value}</c>. See also about
- <seealso marker="#TypeNameValue">{Typename,Value}</seealso> below
- and in the sections for each type.</p>
- </item>
- <tag><c>+driver</c></tag>
- <item>
- <p>As of R15B this means the same as the <c>nif</c> option. Kept for
- backwards compatability reasons.</p>
- </item>
- <tag><c>+nif</c></tag>
- <item>
- <p>Together with the flags <c>ber_bin</c>
- and <c>optimize</c> you choose to use a nif for considerable
- faster encode and decode. </p>
+ <p>DER encoding rule. Only when using <c>-ber</c> option.</p>
</item>
<tag><c>+asn1config</c></tag>
<item>
<p>This functionality works together with the flags
- <c>ber_bin</c> and <c>optimize</c>. You enables the
+ <c>ber</c>. It enables the
specialized decodes, see the <seealso marker="asn1_spec">Specialized Decode</seealso> chapter.
</p>
</item>
@@ -413,7 +377,6 @@ erlc -o ../asnfiles -I ../asnfiles -I /usr/local/standards/asn1 Person.asn
</item>
</taglist>
<p>For a complete description of <c>erlc</c> see Erts Reference Manual.</p>
- <p>For preferred option use see <seealso marker="#preferred option use">Preferred Option Use</seealso> section.</p>
<p>The compiler and other compile-time functions can also be invoked from
the Erlang shell. Below follows a brief
description of the primary functions, for a
@@ -429,9 +392,9 @@ asn1ct:compile("H323-MESSAGES.asn1"). </pre>
<p>which equals:</p>
<pre>
asn1ct:compile("H323-MESSAGES.asn1",[ber]). </pre>
- <p>If one wants PER encoding with optimizations:</p>
+ <p>If one wants PER encoding:</p>
<pre>
-asn1ct:compile("H323-MESSAGES.asn1",[per_bin,optimize]). </pre>
+asn1ct:compile("H323-MESSAGES.asn1",[per]). </pre>
<p>The generic encode and decode functions can be invoked like this:</p>
<pre>
asn1ct:encode('H323-MESSAGES','SomeChoiceType',{call,"octetstring"}).
@@ -443,269 +406,6 @@ asn1ct:decode('H323-MESSAGES','SomeChoiceType',Bytes). </pre>
</section>
<section>
- <marker id="preferred option use"></marker>
- <title>Preferred Option Use</title>
- <p>
- It may not be obvious which compile options best fit a
- situation. This section describes the format of the result of
- encode and decode. It also gives some performance statistics
- when using certain options. Finally there is a recommendation
- which option combinations should be used.
- </p>
- <p>
- The default option is <c>ber</c>. It is the same backend as
- <c>ber_bin</c> except that the result of encode is transformed
- to a flat list. Below is a table that gives the different
- formats of input and output of encode and decode using the
- <em>allowed combinations</em> of coding and optimization
- options: (EAVF stands for how ASN1 values are represented in
- Erlang which is described in the <seealso
- marker="#ASN1Types">ASN1 Types chapter</seealso>)
- </p>
- <table>
- <row>
- <cell align="left" valign="middle"><em>Encoding Rule</em></cell>
- <cell align="left" valign="middle"><em>Compile options, allowed combinations</em></cell>
- <cell align="left" valign="middle"><em>encode input</em></cell>
- <cell align="left" valign="middle"><em>encode output</em></cell>
- <cell align="left" valign="middle"><em>decode input</em></cell>
- <cell align="left" valign="middle"><em>decode output</em></cell>
- </row>
- <row>
- <cell align="left" valign="middle">BER</cell>
- <cell align="left" valign="middle">[ber] (default)</cell>
- <cell align="left" valign="middle">EAVF</cell>
- <cell align="left" valign="middle">flat list</cell>
- <cell align="left" valign="middle">flat list / binary</cell>
- <cell align="left" valign="middle">EAVF</cell>
- </row>
- <row>
- <cell align="left" valign="middle">BER</cell>
- <cell align="left" valign="middle">[ber_bin]</cell>
- <cell align="left" valign="middle">EAVF</cell>
- <cell align="left" valign="middle">iolist</cell>
- <cell align="left" valign="middle">binary</cell>
- <cell align="left" valign="middle">EAVF</cell>
- </row>
- <row>
- <cell align="left" valign="middle">BER</cell>
- <cell align="left" valign="middle"><em>[ber_bin, optimize]</em></cell>
- <cell align="left" valign="middle">EAVF</cell>
- <cell align="left" valign="middle">iolist</cell>
- <cell align="left" valign="middle">binary</cell>
- <cell align="left" valign="middle">EAVF</cell>
- </row>
- <row>
- <cell align="left" valign="middle">BER</cell>
- <cell align="left" valign="middle"><em>[ber_bin, optimize, nif]</em></cell>
- <cell align="left" valign="middle">EAVF</cell>
- <cell align="left" valign="middle">iolist</cell>
- <cell align="left" valign="middle">iolist / binary</cell>
- <cell align="left" valign="middle">EAVF</cell>
- </row>
- <row>
- <cell align="left" valign="middle">PER aligned variant</cell>
- <cell align="left" valign="middle">[per]</cell>
- <cell align="left" valign="middle">EAVF</cell>
- <cell align="left" valign="middle">flat list</cell>
- <cell align="left" valign="middle">flat list</cell>
- <cell align="left" valign="middle">EAVF</cell>
- </row>
- <row>
- <cell align="left" valign="middle">PER aligned variant</cell>
- <cell align="left" valign="middle"><em>[per_bin]</em></cell>
- <cell align="left" valign="middle">EAVF</cell>
- <cell align="left" valign="middle">iolist / binary</cell>
- <cell align="left" valign="middle">binary</cell>
- <cell align="left" valign="middle">EAVF</cell>
- </row>
- <row>
- <cell align="left" valign="middle">PER aligned variant</cell>
- <cell align="left" valign="middle"><em>[per_bin, optimize]</em></cell>
- <cell align="left" valign="middle">EAVF</cell>
- <cell align="left" valign="middle">binary</cell>
- <cell align="left" valign="middle">binary</cell>
- <cell align="left" valign="middle">EAVF</cell>
- </row>
- <row>
- <cell align="left" valign="middle">PER unaligned variant</cell>
- <cell align="left" valign="middle"><em>[uper_bin]</em></cell>
- <cell align="left" valign="middle">EAVF</cell>
- <cell align="left" valign="middle">binary</cell>
- <cell align="left" valign="middle">binary</cell>
- <cell align="left" valign="middle">EAVF</cell>
- </row>
-
- <row>
- <cell align="left" valign="middle">DER</cell>
- <cell align="left" valign="middle">[(ber), der]</cell>
- <cell align="left" valign="middle">EAVF</cell>
- <cell align="left" valign="middle">flat list</cell>
- <cell align="left" valign="middle">flat list / binary</cell>
- <cell align="left" valign="middle">EAVF</cell>
- </row>
- <row>
- <cell align="left" valign="middle">DER</cell>
- <cell align="left" valign="middle">[ber_bin, der]</cell>
- <cell align="left" valign="middle">EAVF</cell>
- <cell align="left" valign="middle">iolist</cell>
- <cell align="left" valign="middle">binary</cell>
- <cell align="left" valign="middle">EAVF</cell>
- </row>
- <row>
- <cell align="left" valign="middle">DER</cell>
- <cell align="left" valign="middle"><em>[ber_bin, optimize, der]</em></cell>
- <cell align="left" valign="middle">EAVF</cell>
- <cell align="left" valign="middle">iolist</cell>
- <cell align="left" valign="middle">binary</cell>
- <cell align="left" valign="middle">EAVF</cell>
- </row>
- <row>
- <cell align="left" valign="middle">DER</cell>
- <cell align="left" valign="middle"><em>[ber_bin, optimize, nif, der]</em></cell>
- <cell align="left" valign="middle">EAVF</cell>
- <cell align="left" valign="middle">iolist</cell>
- <cell align="left" valign="middle">binary</cell>
- <cell align="left" valign="middle">EAVF</cell>
- </row>
-
-
- <tcaption>The output / input formats for different combinations of compile options.</tcaption>
- </table>
- <p>
- Encode / decode speed comparison in one user case for the above
- alternatives (except <c>DER</c>) is showed in the table below. The
- <c>DER</c> alternatives are slower than their corresponding
- <c>BER</c> alternative.
- </p>
-
- <table>
- <row>
- <cell align="left" valign="middle"><em>compile options</em></cell>
- <cell align="left" valign="middle"><em>encode time</em></cell>
- <cell align="left" valign="middle"><em>decode time</em></cell>
- </row>
- <row>
- <cell align="left" valign="middle">[ber]</cell>
- <cell align="left" valign="middle">120</cell>
- <cell align="left" valign="middle">162</cell>
- </row>
- <row>
- <cell align="left" valign="middle">[ber_bin]</cell>
- <cell align="left" valign="middle">124</cell>
- <cell align="left" valign="middle">154</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><em>[ber_bin, optimize]</em></cell>
- <cell align="left" valign="middle">50</cell>
- <cell align="left" valign="middle">78</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><em>[ber_bin, optimize, driver]</em></cell>
- <cell align="left" valign="middle">50</cell>
- <cell align="left" valign="middle">62</cell>
- </row>
- <row>
- <cell align="left" valign="middle">[per]</cell>
- <cell align="left" valign="middle">141</cell>
- <cell align="left" valign="middle">133</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><em>[per_bin]</em></cell>
- <cell align="left" valign="middle">125</cell>
- <cell align="left" valign="middle">123</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><em>[per_bin, optimize]</em></cell>
- <cell align="left" valign="middle">77</cell>
- <cell align="left" valign="middle">72</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><em>[uper_bin]</em></cell>
- <cell align="left" valign="middle">97</cell>
- <cell align="left" valign="middle">104</cell>
- </row>
- <tcaption>
- One example of difference in speed for the compile option alternatives.
- </tcaption>
- </table>
-
- <p>
- The compile options <c>ber</c>, <c>per</c> and
- <c>driver</c> are kept for backwards compatibility and should not be
- used in new code. The nif implementation which replaces the linked-in
- driver has been shown to be about 5-15% faster.
- </p>
- <p>
- You are strongly recommended to use the appropriate alternative
- of the bold typed options. The <c>optimize</c> and
- <c>nif</c> options does not affect the encode or decode
- result, just the time spent in run-time. When <c>ber_bin</c> and
- <c>nif</c> or <c>per_bin</c> and <c>optimize</c> is
- combined the C-code nif is used in chosen parts of encode /
- decode procedure.
- </p>
- <table>
- <row>
- <cell align="left" valign="middle"><em>Compile options, allowed combinations</em></cell>
- <cell align="left" valign="middle"><em>use of nif</em></cell>
- </row>
- <row>
- <cell align="left" valign="middle">[ber]</cell>
- <cell align="left" valign="middle">no</cell>
- </row>
- <row>
- <cell align="left" valign="middle">[ber_bin]</cell>
- <cell align="left" valign="middle">no</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><em>[ber_bin, optimize]</em></cell>
- <cell align="left" valign="middle">no</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><em>[ber_bin, optimize, nif]</em></cell>
- <cell align="left" valign="middle">yes</cell>
- </row>
- <row>
- <cell align="left" valign="middle">[per]</cell>
- <cell align="left" valign="middle">no</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><em>[per_bin]</em></cell>
- <cell align="left" valign="middle">no</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><em>[per_bin, optimize]</em></cell>
- <cell align="left" valign="middle">yes</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><em>[uper_bin]</em></cell>
- <cell align="left" valign="middle">no</cell>
- </row>
-
- <row>
- <cell align="left" valign="middle">[(ber), der]</cell>
- <cell align="left" valign="middle">no</cell>
- </row>
- <row>
- <cell align="left" valign="middle">[ber_bin, der]</cell>
- <cell align="left" valign="middle">no</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><em>[ber_bin, optimize, der]</em></cell>
- <cell align="left" valign="middle">no</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><em>[ber_bin, optimize, nif, der]</em></cell>
- <cell align="left" valign="middle">yes</cell>
- </row>
-
-
- <tcaption>When the ASN1 nif is used.</tcaption>
- </table>
-
- </section>
- <section>
<title>Run-time Functions</title>
<p>A brief description of the major functions is given here. For a
complete description of each function see
@@ -719,9 +419,9 @@ asn1rt:decode('H323-MESSAGES','SomeChoiceType',Bytes). </pre>
'H323-MESSAGES':encode('SomeChoiceType',{call,"octetstring"}).
'H323-MESSAGES':decode('SomeChoiceType',Bytes). </pre>
<p>The asn1 nif is enabled in two occasions: encoding of
- asn1 values when the asn1 spec is compiled with <c>per_bin</c> and
- <c>optimize</c> or decode of encoded asn1 values when the asn1 spec is
- compiled with <c>ber_bin</c>, <c>optimize</c> and <c>nif</c>. In
+ asn1 values when the asn1 spec is compiled with <c>per</c> and
+ or decode of encoded asn1 values when the asn1 spec is
+ compiled with <c>ber</c>. In
those cases the nif will be loaded automatically at the first call
to <c>encode</c>/<c>decode</c>. If one doesn't want the performance
overhead of the nif being loaded at the first call it is possible
@@ -868,26 +568,6 @@ Operational ::= BOOLEAN --ASN.1 definition </pre>
<pre>
Val = true,
{ok,Bytes}=asn1rt:encode(MyModule,'Operational',Val), </pre>
- <p>For historical reasons it is also possible to assign ASN.1 values
- in Erlang using a tuple notation
- with type and value as this</p>
- <pre>
-Val = {'Operational',true} </pre>
- <warning>
- <marker id="warning"></marker>
- <p>The tuple notation, <c>{Typename, Value}</c> is only kept
- because of backward compatibility and may be withdrawn in a
- future release. If the notation is used the <c>Typename</c>
- element must be spelled correctly, otherwise a run-time error
- will occur.
- </p>
- <p>If the ASN.1 module is compiled with the flags
- <c>per_bin</c> or <c>ber_bin</c> and <c>optimize</c> it is not
- allowed to use the tuple notation. That possibility has been
- removed due to performance reasons. Neither is it allowed to
- use the <c>{ComponentName,Value}</c> notation in case of a
- SEQUENCE or SET type.</p>
- </warning>
<p>Below follows a description of how
values of each type can be represented in Erlang.
</p>
@@ -1149,7 +829,7 @@ TextFileVal2 = [88,76,55,44,99,121 .......... a lot of characters here ....]
The following example shows how it works:</p>
<p>In a file <c>PrimStrings.asn1</c> the type <c>BMP</c> is defined as
<br></br>
-<c>BMP ::= BMPString</c> then using BER encoding (<c>ber_bin</c>
+<c>BMP ::= BMPString</c> then using BER encoding (<c>ber</c>
option)the input/output format will be:</p>
<pre>
1> <input>{ok,Bytes1} = asn1rt:encode('PrimStrings','BMP',[{0,0,53,53},{0,0,45,56}]).</input>
@@ -1174,9 +854,9 @@ TextFileVal2 = [88,76,55,44,99,121 .......... a lot of characters here ....]
<c>utf8_list_to_binary</c>, are in the <c>asn1rt</c> module. In
the example below we assume an asn1 definition <c>UTF ::= UTF8String</c> in a module <c>UTF.asn</c>:</p>
<pre>
-1> <input>asn1ct:compile('UTF',[ber_bin]).</input>
+1> <input>asn1ct:compile('UTF',[ber]).</input>
Erlang ASN.1 version "1.4.3.3" compiling "UTF.asn"
-Compiler Options: [ber_bin]
+Compiler Options: [ber]
--{generated,"UTF.asn1db"}--
--{generated,"UTF.erl"}--
ok
@@ -1287,14 +967,6 @@ Pdu ::= SEQUENCE {
<p>Values can be assigned in Erlang as shown below:</p>
<pre>
MyPdu = #'Pdu'{a=22,b=77.99,c={0,1,2,3,4},d='NULL'}. </pre>
-<note>
- <p>
- In very early versions of the asn1 compiler it was also possible to
- specify the values of the components in
- a SEQUENCE or a SET as a list of tuples <c>{ComponentName,Value}</c>.
- This is no longer supported.
- </p>
-</note>
<p>The decode functions will return a record as result when decoding
a <c>SEQUENCE</c> or a <c>SET</c>.
<marker id="DEFAULT"></marker>
@@ -1739,12 +1411,9 @@ SS ::= SET {
1> <input>Val = 'Values':tt().</input>
{'TT',77,["kalle","kula"]}
2> <input>{ok,Bytes} = 'Values':encode('TT',Val).</input>
-{ok,["0",
- [18],
- [[[128],[1],"M"],["\\241","\\r",[[[4],[5],"kalle"],[[4],[4],"kula"]]]]]}
-3> <input>FlatBytes = lists:flatten(Bytes).</input>
-[48,18,128,1,77,161,13,4,5,107,97,108,108,101,4,4,107,117,108,97]
-4> <input>'Values':decode('TT',FlatBytes).</input>
+{ok,&lt;&lt;48,18,128,1,77,161,13,4,5,107,97,108,108,101,4,4,
+ 107,117,108,97&gt;&gt;}
+4> <input>'Values':decode('TT',Bytes).</input>
{ok,{'TT',77,["kalle","kula"]}}
5>
</pre>
diff --git a/lib/asn1/doc/src/asn1ct.xml b/lib/asn1/doc/src/asn1ct.xml
index 3be58cbc8e..bb3c6a4f0f 100644
--- a/lib/asn1/doc/src/asn1ct.xml
+++ b/lib/asn1/doc/src/asn1ct.xml
@@ -41,6 +41,19 @@
encode/decode functions. There are also some generic functions which
can be used in during development of applications which handles ASN.1
data (encoded as BER or PER).</p>
+ <note>
+ <p>In R16, the options have been simplified. The back-end is chosen
+ using one of the options <c>ber</c>, <c>per</c>, or <c>uper</c>.
+ The options <c>optimize</c>, <c>nif</c>, and <c>driver</c> options
+ are no longer necessary (and the ASN.1 compiler will print a
+ warning if they are used). The options <c>ber_bin</c>, <c>per_bin</c>,
+ and <c>uper_bin</c> options will still work, but will print a warning.
+ </p>
+ <p>Another change in R16 is that the generated <c>encode/2</c>
+ function (and <c>asn1rt:encode/3</c>) always returns a binary.
+ The <c>encode/2</c> function for the BER back-end used to return
+ an iolist.</p>
+ </note>
</description>
<funcs>
<func>
@@ -50,9 +63,9 @@
<type>
<v>Asn1module = atom() | string()</v>
<v>Options = [Option| OldOption]</v>
- <v>Option = ber_bin | per_bin | uper_bin | der | compact_bit_string |
- noobj | {n2n, EnumTypeName} |{outdir, Dir} | {i, IncludeDir} | optimize |
- nif | asn1config | undec_rest | {inline, OutputName} | inline |
+ <v>Option = ber | per | uper | der | compact_bit_string |
+ noobj | {n2n, EnumTypeName} |{outdir, Dir} | {i, IncludeDir} |
+ asn1config | undec_rest | {inline, OutputName} | inline |
{macro_name_prefix, Prefix} | {record_name_prefix, Prefix} | verbose | warnings_as_errors</v>
<v>OldOption = ber | per</v>
<v>Reason = term()</v>
@@ -107,12 +120,10 @@ File3.asn </pre>
<c>Options</c> is a list with options specific for the asn1
compiler and options that are applied to the Erlang compiler.
The latter are those that not is recognized as asn1 specific.
- For <em>preferred option use</em> see <seealso
- marker="asn1_ug#preferred option use">Preferred Option Use
- section in users guide</seealso>. Available options are:
+ Available options are:
</p>
<taglist>
- <tag><c>ber | ber_bin | per | per_bin | uper_bin</c></tag>
+ <tag><c>ber | per | uper</c></tag>
<item>
<p>
The encoding rule to be used. The supported encoding rules
@@ -120,23 +131,12 @@ File3.asn </pre>
PER aligned (Packed Encoding Rules) and PER unaligned.
If the encoding rule option is omitted <c>ber</c>
is the default.
- The <c>per_bin</c> option means the aligned
- variant. To use the unaligned variant the <c>uper_bin</c>
- option has to be used.
</p>
<p>
The generated Erlang module always gets the same name
as the ASN.1 module and as a consequence of this only one
encoding rule per ASN.1 module can be used at runtime.
</p>
- <p>
- The <c>ber_bin</c> and <c>per_bin</c> options are
- equivalent with the <c>OldOptions</c> <c>ber</c> and <c>per</c>
- with the difference that the generated encoding/decoding
- functions take advantage of the bit syntax, which in most
- cases increases the performance considerably. The result
- from encoding is a binary or an iolist.
- </p>
</item>
<tag><c>der</c></tag>
<item>
@@ -144,7 +144,7 @@ File3.asn </pre>
By this option the Distinguished Encoding Rules (DER) is chosen.
DER is regarded as a specialized variant of the BER encoding
rule, therefore the <c>der</c> option only makes sense together
- with the <c>ber</c> or <c>ber_bin</c> option.
+ with the <c>ber</c> option.
This option
sometimes adds sorting and value checks when encoding, which
implies a slower encoding. The decoding routines are the same
@@ -206,28 +206,6 @@ Binary = binary()
shall be placed. If omitted the files are placed in the
current directory.</p>
</item>
- <tag><c>optimize</c></tag>
- <item>
- <p>This option is only valid together with one of the
- <c>per_bin</c>
- or <c>ber_bin</c> option. It gives time optimized code
- generated and it uses another runtime module and
- in the <c>per_bin</c> case a nif. The result
- in the <c>per_bin</c> case from an encode when compiled
- with this option will be a binary.</p>
- </item>
- <tag><c>driver</c></tag>
- <item>
- <p>As of R15B this means the same as the <c>nif</c> option. Kept for
- backwards compatability reasons.</p>
- </item>
- <tag><c>nif</c></tag>
- <item>
- <p>Option valid together with <c>ber_bin</c> and <c>optimize</c>
- options. It enables the use of several nifs that gives faster
- encode and decode. Nifs are only enabled by the explicit use of
- the option <c>nif</c></p>
- </item>
<tag><c>asn1config</c></tag>
<item>
<p>When one of the specialized decodes, exclusive or
@@ -270,10 +248,6 @@ Binary = binary()
<c>{export, [atom()]}</c> or <c>{export_all, true}</c> option
are provided. The list of atoms are names of chosen asn1
specs from the <c>.set.asn</c> file. </p>
- <p>When used together with <c>nif</c> for <c>ber_bin</c>, the
- asn1 nifs will be used if the <c>asn1rt_nif</c> module is
- available. If it is not available, a slower erlang fallback
- will be used.</p>
</item>
<tag><c>inline</c></tag>
<item>
@@ -327,13 +301,12 @@ Binary = binary()
<type>
<v>Module = Type = atom()</v>
<v>Value = term()</v>
- <v>Bytes = [Int] when integer(Int), Int >= 0, Int =&lt; 255</v>
+ <v>Bytes = binary()</v>
<v>Reason = term()</v>
</type>
<desc>
<p>Encodes <c>Value</c> of <c>Type</c> defined in the ASN.1 module
- <c>Module</c>. Returns a list of bytes if successful. To get as fast execution as
- possible the
+ <c>Module</c>. To get as fast execution as possible the
encode function only performs rudimentary tests that the input
<c>Value</c>
is a correct instance of <c>Type</c>. The length of strings is for example
@@ -348,10 +321,10 @@ Binary = binary()
<type>
<v>Module = Type = atom()</v>
<v>Value = Reason = term()</v>
- <v>Bytes = [Int] when integer(Int), Int >= 0, Int =&lt; 255</v>
+ <v>Bytes = binary()</v>
</type>
<desc>
- <p>Decodes <c>Type</c> from <c>Module</c> from the list of bytes
+ <p>Decodes <c>Type</c> from <c>Module</c> from the binary
<c>Bytes</c>. Returns <c>{ok, Value}</c> if successful.</p>
</desc>
</func>
diff --git a/lib/asn1/doc/src/asn1rt.xml b/lib/asn1/doc/src/asn1rt.xml
index 0c3c257189..f2cac0c9e7 100644
--- a/lib/asn1/doc/src/asn1rt.xml
+++ b/lib/asn1/doc/src/asn1rt.xml
@@ -47,35 +47,34 @@
<type>
<v>Module = Type = atom()</v>
<v>Value = Reason = term()</v>
- <v>Bytes = binary | [Int] when integer(Int), Int >= 0, Int =&lt; 255 | binary</v>
+ <v>Bytes = binary</v>
</type>
<desc>
- <p>Decodes <c>Type</c> from <c>Module</c> from the list of bytes or
- binary <c>Bytes</c>. If the module is compiled with <c>ber_bin</c>
- or <c>per_bin</c> option <c>Bytes</c> must be a binary.
+ <p>Decodes <c>Type</c> from <c>Module</c> from the binary <c>Bytes</c>.
Returns <c>{ok,Value}</c> if successful.</p>
</desc>
</func>
<func>
- <name>encode(Module,Type,Value)-> {ok,BinOrList} | {error,Reason}</name>
+ <name>encode(Module,Type,Value)-> {ok,Bytes} | {error,Reason}</name>
<fsummary>Encode an ASN.1 value.</fsummary>
<type>
<v>Module = Type = atom()</v>
<v>Value = term()</v>
- <v>BinOrList = Bytes | binary()</v>
- <v>Bytes = [Int|binary|Bytes] when integer(Int), Int >= 0, Int =&lt; 255</v>
+ <v>Bytes = binary</v>
<v>Reason = term()</v>
</type>
<desc>
<p>Encodes <c>Value</c> of <c>Type</c> defined in the ASN.1 module
<c>Module</c>. Returns a possibly nested list of bytes and or binaries
- if successful. If <c>Module</c> was compiled with the options <c>per_bin</c> and <c>optimize</c> the result is a binary. To get as
- fast execution as possible the
+ if successful. To get as fast execution as possible the
encode function only performs rudimentary tests that the input
<c>Value</c>
is a correct instance of <c>Type</c>. The length of strings is for example
not always checked. </p>
+ <note>
+ <p>Starting in R16, <c>Bytes</c> is always a binary.</p>
+ </note>
</desc>
</func>
@@ -95,28 +94,6 @@
</func>
<func>
- <name>load_driver() -> ok | {error,Reason}</name>
- <fsummary>Loads the linked-in driver. (deprecated)</fsummary>
- <type>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>This function is obsolete and will be removed in R16A</p>
- </desc>
- </func>
-
- <func>
- <name>unload_driver() -> ok | {error,Reason}</name>
- <fsummary>Unloads the linked-in driver. (deprecated)</fsummary>
- <type>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>This function is obsolete and will be removed in R16A</p>
- </desc>
- </func>
-
- <func>
<name>utf8_binary_to_list(UTF8Binary) -> {ok,UnicodeList} | {error,Reason}</name>
<fsummary>Transforms an utf8 encoded binary to a unicode list.</fsummary>
<type>
diff --git a/lib/asn1/doc/src/notes.xml b/lib/asn1/doc/src/notes.xml
index 5ca86130a1..72b496caf7 100644
--- a/lib/asn1/doc/src/notes.xml
+++ b/lib/asn1/doc/src/notes.xml
@@ -483,7 +483,7 @@
ENUMERATION type, the compilation will be terminated with an
error code.<br/>
Below follows an example on how to use the option from the command line with <c>erlc</c>:<br/>
- <c>erlc -bper_bin +optimize +driver +"{n2n,'CauseMisc'}" +"{n2n,'CausePcl'}" MyModyle.asn</c>
+ <c>erlc -bper+"{n2n,'CauseMisc'}" +"{n2n,'CausePcl'}" MyModyle.asn</c>
</p>
<p>
Own Id: OTP-8136 Aux Id: seq11347 </p>
diff --git a/lib/asn1/src/Makefile b/lib/asn1/src/Makefile
index 4bd49aa93b..03e18c565b 100644
--- a/lib/asn1/src/Makefile
+++ b/lib/asn1/src/Makefile
@@ -52,10 +52,9 @@ CT_MODULES= \
asn1ct_gen_per_rt2ct \
asn1ct_name \
asn1ct_constructed_per \
- asn1ct_constructed_ber \
- asn1ct_gen_ber \
asn1ct_constructed_ber_bin_v2 \
asn1ct_gen_ber_bin_v2 \
+ asn1ct_imm \
asn1ct_value \
asn1ct_tok \
asn1ct_parser2 \
@@ -63,7 +62,6 @@ CT_MODULES= \
RT_MODULES= \
asn1rt \
- asn1rt_per_bin \
asn1rt_ber_bin \
asn1rt_ber_bin_v2 \
asn1rt_per_bin_rt2ct \
@@ -138,13 +136,13 @@ info:
# ----------------------------------------------------
$(EBIN)/asn1ct.$(EMULATOR):asn1ct.erl
- $(ERLC) -b$(EMULATOR) -o$(EBIN) $(ERL_COMPILE_FLAGS) -Dvsn=\"$(VSN)\" $<
+ $(V_ERLC) -b$(EMULATOR) -o$(EBIN) $(ERL_COMPILE_FLAGS) -Dvsn=\"$(VSN)\" $<
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
# ----------------------------------------------------
@@ -166,11 +164,32 @@ release_spec: opt
release_docs_spec:
+#
+# Dependencies
+#
-
-
-
-
-
-
-
+$(EBIN)/asn1_app.beam: asn1_app.erl
+$(EBIN)/asn1_db.beam: asn1_db.erl
+$(EBIN)/asn1ct.beam: asn1ct.erl asn1_records.hrl
+$(EBIN)/asn1ct_check.beam: asn1ct_check.erl asn1_records.hrl
+$(EBIN)/asn1ct_constructed_ber_bin_v2.beam: asn1ct_constructed_ber_bin_v2.erl \
+ asn1_records.hrl
+$(EBIN)/asn1ct_constructed_per.beam: asn1ct_constructed_per.erl asn1_records.hrl
+$(EBIN)/asn1ct_gen.beam: asn1ct_gen.erl asn1_records.hrl
+$(EBIN)/asn1ct_gen_ber_bin_v2.beam: asn1ct_gen_ber_bin_v2.erl asn1_records.hrl
+$(EBIN)/asn1ct_gen_per.beam: asn1ct_gen_per.erl asn1_records.hrl
+$(EBIN)/asn1ct_gen_per_rt2ct.beam: asn1ct_gen_per_rt2ct.erl asn1_records.hrl
+$(EBIN)/asn1ct_imm.beam: asn1ct_imm.erl
+$(EBIN)/asn1ct_name.beam: asn1ct_name.erl
+$(EBIN)/asn1ct_parser2.beam: asn1ct_parser2.erl asn1_records.hrl
+$(EBIN)/asn1ct_pretty_format.beam: asn1ct_pretty_format.erl
+$(EBIN)/asn1ct_table.beam: asn1ct_table.erl
+$(EBIN)/asn1ct_tok.beam: asn1ct_tok.erl
+$(EBIN)/asn1ct_value.beam: asn1ct_value.erl asn1_records.hrl
+$(EBIN)/asn1rt.beam: asn1rt.erl
+$(EBIN)/asn1rt_ber_bin.beam: asn1rt_ber_bin.erl asn1_records.hrl
+$(EBIN)/asn1rt_ber_bin_v2.beam: asn1rt_ber_bin_v2.erl
+$(EBIN)/asn1rt_check.beam: asn1rt_check.erl
+$(EBIN)/asn1rt_nif.beam: asn1rt_nif.erl
+$(EBIN)/asn1rt_per_bin_rt2ct.beam: asn1rt_per_bin_rt2ct.erl asn1_records.hrl
+$(EBIN)/asn1rt_uper_bin.beam: asn1rt_uper_bin.erl asn1_records.hrl
diff --git a/lib/asn1/src/asn1.app.src b/lib/asn1/src/asn1.app.src
index 09144ba2f7..64b33a8a30 100644
--- a/lib/asn1/src/asn1.app.src
+++ b/lib/asn1/src/asn1.app.src
@@ -3,7 +3,6 @@
{vsn, "%VSN%"},
{modules, [
asn1rt,
- asn1rt_per_bin,
asn1rt_per_bin_rt2ct,
asn1rt_uper_bin,
asn1rt_ber_bin,
diff --git a/lib/asn1/src/asn1ct.erl b/lib/asn1/src/asn1ct.erl
index 8e971a1c76..98877320a0 100644
--- a/lib/asn1/src/asn1ct.erl
+++ b/lib/asn1/src/asn1ct.erl
@@ -85,14 +85,8 @@
compile(File) ->
compile(File,[]).
-compile(File,Options) when is_list(Options) ->
- case lists:member(driver, Options) of %% remove me in R16A!
- true ->
- io:format("Warning: driver option is obsolete and will be removed in R16A, use nif instead!");
- false ->
- ok
- end,
- Options1 = optimize_ber_bin(Options),
+compile(File, Options0) when is_list(Options0) ->
+ Options1 = translate_options(Options0),
Options2 = includes(File,Options1),
Includes = strip_includes(Options2),
in_process(fun() -> compile_proc(File, Includes, Options2) end).
@@ -852,8 +846,8 @@ generate({true,{M,_Module,GenTOrV}},OutFile,EncodingRule,Options) ->
debug_off(Options),
put(compact_bit_string,false),
erase(encoding_options),
- erase(tlv_format), % used in ber_bin, optimize
- erase(class_default_type),% used in ber_bin, optimize
+ erase(tlv_format), % used in ber
+ erase(class_default_type),% used in ber
asn1ct_table:delete(check_functions),
case Result of
{error,_} ->
@@ -876,14 +870,13 @@ parse_and_save(Module,S) ->
Options = S#state.options,
SourceDir = S#state.sourcedir,
Includes = [I || {i,I} <-Options],
- Options1 = optimize_ber_bin(Options),
-
+
case get_input_file(Module,[SourceDir|Includes]) of
%% search for asn1 source
{file,SuffixedASN1source} ->
- case dbfile_uptodate(SuffixedASN1source,Options1) of
+ case dbfile_uptodate(SuffixedASN1source,Options) of
false ->
- parse_and_save1(S,SuffixedASN1source,Options1,Includes);
+ parse_and_save1(S,SuffixedASN1source,Options,Includes);
_ -> ok
end;
Err ->
@@ -1065,9 +1058,9 @@ get_file_list1(Stream,Dir,Includes,Acc) ->
end.
get_rule(Options) ->
- case [Rule ||Rule <-[per,ber,ber_bin,ber_bin_v2,per_bin,uper_bin],
- Opt <- Options,
- Rule==Opt] of
+ case [Rule || Rule <- [ber,per,uper],
+ Opt <- Options,
+ Rule =:= Opt] of
[Rule] ->
Rule;
[Rule|_] ->
@@ -1079,19 +1072,34 @@ get_rule(Options) ->
get_runtime_mod(Options) ->
RtMod1=
case get_rule(Options) of
- per -> ["asn1rt_per_bin.erl"];
- ber -> ["asn1rt_ber_bin.erl"];
- per_bin ->
- case lists:member(optimize,Options) of
- true -> ["asn1rt_per_bin_rt2ct.erl"];
- _ -> ["asn1rt_per_bin.erl"]
- end;
- ber_bin -> ["asn1rt_ber_bin.erl"];
- ber_bin_v2 -> ["asn1rt_ber_bin_v2.erl"];
- uper_bin -> ["asn1rt_uper_bin.erl"]
+ per -> "asn1rt_per_bin_rt2ct.erl";
+ ber -> ["asn1rt_ber_bin_v2.erl"];
+ uper -> ["asn1rt_uper_bin.erl"]
end,
RtMod1++["asn1rt_check.erl","asn1rt.erl"].
-
+
+%% translate_options(NewOptions) -> OldOptions
+%% Translate the new option names to the old option name.
+%% FIXME. We should rewrite all code to handle the new option names.
+
+translate_options([ber_bin|T]) ->
+ io:format("Warning: The option 'ber_bin' is now called 'ber'.\n"),
+ [ber|translate_options(T)];
+translate_options([per_bin|T]) ->
+ io:format("Warning: The option 'per_bin' is now called 'per'.\n"),
+ [per|translate_options(T)];
+translate_options([uper_bin|T]) ->
+ io:format("Warning: The option 'uper_bin' is now called 'uper'.\n"),
+ translate_options([uper|T]);
+translate_options([nif|T]) ->
+ io:format("Warning: The option 'nif' is no longer needed.\n"),
+ translate_options(T);
+translate_options([optimize|T]) ->
+ io:format("Warning: The option 'optimize' is no longer needed.\n"),
+ translate_options(T);
+translate_options([H|T]) ->
+ [H|translate_options(T)];
+translate_options([]) -> [].
erl_compile(OutFile,Options) ->
% io:format("Options:~n~p~n",[Options]),
@@ -1115,7 +1123,6 @@ remove_asn_flags(Options) ->
X /= optimize,
X /= compact_bit_string,
X /= debug,
- X /= keyed_list,
X /= asn1config,
X /= record_name_prefix].
@@ -1125,12 +1132,6 @@ debug_on(Options) ->
put(asndebug,true);
_ ->
true
- end,
- case lists:member(keyed_list,Options) of
- true ->
- put(asn_keyed_list,true);
- _ ->
- true
end.
igorify_options(Options) ->
@@ -1151,8 +1152,7 @@ generated_file(Name,Options) ->
end.
debug_off(_Options) ->
- erase(asndebug),
- erase(asn_keyed_list).
+ erase(asndebug).
outfile(Base, Ext, Opts) ->
@@ -1168,13 +1168,6 @@ outfile(Base, Ext, Opts) ->
lists:concat([Obase,".",Ext])
end.
-optimize_ber_bin(Options) ->
- case {lists:member(optimize,Options),lists:member(ber_bin,Options)} of
- {true,true} ->
- [ber_bin_v2|Options--[ber_bin]];
- _ -> Options
- end.
-
includes(File,Options) ->
Options2 = include_append(".", Options),
Options3 = include_append(filename:dirname(File), Options2),
@@ -1284,12 +1277,7 @@ make_erl_options(Opts) ->
Defines) ++
case OutputType of
undefined -> [ber]; % temporary default (ber when it's ready)
- ber -> [ber];
- ber_bin -> [ber_bin];
- ber_bin_v2 -> [ber_bin_v2];
- per -> [per];
- per_bin -> [per_bin];
- uper_bin -> [uper_bin]
+ _ -> [OutputType] % pass through
end,
Options++[errors, {cwd, Cwd}, {outdir, Outdir}|
@@ -1300,35 +1288,35 @@ pretty2(Module,AbsFile) ->
{ok,F} = file:open(AbsFile,[write]),
M = asn1_db:dbget(Module,'MODULE'),
io:format(F,"%%%%%%%%%%%%%%%%%%% ~p %%%%%%%%%%%%%%%%%%%~n",[Module]),
- io:format(F,"~s\n",[asn1ct_pretty_format:term(M#module.defid)]),
- io:format(F,"~s\n",[asn1ct_pretty_format:term(M#module.tagdefault)]),
- io:format(F,"~s\n",[asn1ct_pretty_format:term(M#module.exports)]),
- io:format(F,"~s\n",[asn1ct_pretty_format:term(M#module.imports)]),
- io:format(F,"~s\n\n",[asn1ct_pretty_format:term(M#module.extensiondefault)]),
+ io:format(F,"~s.\n",[asn1ct_pretty_format:term(M#module.defid)]),
+ io:format(F,"~s.\n",[asn1ct_pretty_format:term(M#module.tagdefault)]),
+ io:format(F,"~s.\n",[asn1ct_pretty_format:term(M#module.exports)]),
+ io:format(F,"~s.\n",[asn1ct_pretty_format:term(M#module.imports)]),
+ io:format(F,"~s.\n\n",[asn1ct_pretty_format:term(M#module.extensiondefault)]),
{Types,Values,ParameterizedTypes,Classes,Objects,ObjectSets} = M#module.typeorval,
io:format(F,"%%%%%%%%%%%%%%%%%%% TYPES in ~p %%%%%%%%%%%%%%%%%%%~n",[Module]),
- lists:foreach(fun(T)-> io:format(F,"~s\n",
+ lists:foreach(fun(T)-> io:format(F,"~s.\n",
[asn1ct_pretty_format:term(asn1_db:dbget(Module,T))])
end,Types),
io:format(F,"%%%%%%%%%%%%%%%%%%% VALUES in ~p %%%%%%%%%%%%%%%%%%%~n",[Module]),
- lists:foreach(fun(T)-> io:format(F,"~s\n",
+ lists:foreach(fun(T)-> io:format(F,"~s.\n",
[asn1ct_pretty_format:term(asn1_db:dbget(Module,T))])
end,Values),
io:format(F,"%%%%%%%%%%%%%%%%%%% Parameterized Types in ~p %%%%%%%%%%%%%%%%%%%~n",[Module]),
- lists:foreach(fun(T)-> io:format(F,"~s\n",
+ lists:foreach(fun(T)-> io:format(F,"~s.\n",
[asn1ct_pretty_format:term(asn1_db:dbget(Module,T))])
end,ParameterizedTypes),
io:format(F,"%%%%%%%%%%%%%%%%%%% Classes in ~p %%%%%%%%%%%%%%%%%%%~n",[Module]),
- lists:foreach(fun(T)-> io:format(F,"~s\n",
+ lists:foreach(fun(T)-> io:format(F,"~s.\n",
[asn1ct_pretty_format:term(asn1_db:dbget(Module,T))])
end,Classes),
io:format(F,"%%%%%%%%%%%%%%%%%%% Objects in ~p %%%%%%%%%%%%%%%%%%%~n",[Module]),
- lists:foreach(fun(T)-> io:format(F,"~s\n",
+ lists:foreach(fun(T)-> io:format(F,"~s.\n",
[asn1ct_pretty_format:term(asn1_db:dbget(Module,T))])
end,Objects),
io:format(F,"%%%%%%%%%%%%%%%%%%% Object Sets in ~p %%%%%%%%%%%%%%%%%%%~n",[Module]),
- lists:foreach(fun(T)-> io:format(F,"~s\n",
+ lists:foreach(fun(T)-> io:format(F,"~s.\n",
[asn1ct_pretty_format:term(asn1_db:dbget(Module,T))])
end,ObjectSets).
start() ->
@@ -1400,8 +1388,7 @@ test_value(Module, Type, Value) ->
in_process(fun() ->
case catch encode(Module, Type, Value) of
{ok, Bytes} ->
- M = to_atom(Module),
- NewBytes = prepare_bytes(M:encoding_rule(), Bytes),
+ NewBytes = prepare_bytes(Bytes),
case decode(Module, Type, NewBytes) of
{ok, Value} ->
{ok, {Module, Type, Value}};
@@ -1452,18 +1439,8 @@ check(Module, Includes) ->
end
end.
-to_atom(Term) when is_list(Term) -> list_to_atom(Term);
-to_atom(Term) when is_atom(Term) -> Term.
-
-prepare_bytes(ber, Bytes) -> lists:flatten(Bytes);
-prepare_bytes(ber_bin, Bytes) when is_binary(Bytes) -> Bytes;
-prepare_bytes(ber_bin, Bytes) -> list_to_binary(Bytes);
-prepare_bytes(ber_bin_v2, Bytes) when is_binary(Bytes) -> Bytes;
-prepare_bytes(ber_bin_v2, Bytes) -> list_to_binary(Bytes);
-prepare_bytes(per, Bytes) -> lists:flatten(Bytes);
-prepare_bytes(per_bin, Bytes) when is_binary(Bytes) -> Bytes;
-prepare_bytes(per_bin, Bytes) -> list_to_binary(Bytes);
-prepare_bytes(uper_bin, Bytes) -> Bytes.
+prepare_bytes(Bytes) when is_binary(Bytes) -> Bytes;
+prepare_bytes(Bytes) -> list_to_binary(Bytes).
vsn() ->
?vsn.
@@ -1504,7 +1481,7 @@ specialized_decode_prepare(Erule,M,TsAndVs,Options) ->
end.
%% Reads the configuration file if it exists and stores information
%% about partial decode and incomplete decode
-partial_decode_prepare(ber_bin_v2,M,TsAndVs,Options) when is_tuple(TsAndVs) ->
+partial_decode_prepare(ber,M,TsAndVs,Options) when is_tuple(TsAndVs) ->
%% read configure file
ModName =
diff --git a/lib/asn1/src/asn1ct_check.erl b/lib/asn1/src/asn1ct_check.erl
index 59e82b7a57..dd77085c39 100644
--- a/lib/asn1/src/asn1ct_check.erl
+++ b/lib/asn1/src/asn1ct_check.erl
@@ -61,13 +61,13 @@
-define(TAG_PRIMITIVE(Num),
case S#state.erule of
- ber_bin_v2 ->
+ ber ->
#tag{class='UNIVERSAL',number=Num,type='IMPLICIT',form=0};
_ -> []
end).
-define(TAG_CONSTRUCTED(Num),
case S#state.erule of
- ber_bin_v2 ->
+ ber ->
#tag{class='UNIVERSAL',number=Num,type='IMPLICIT',form=32};
_ -> []
end).
@@ -3262,7 +3262,7 @@ check_type(S=#state{recordtopname=TopName},Type,Ts) when is_record(Ts,type) ->
inlined=IsInlined},
TestFun =
fun(Tref) ->
- {_,MaybeChoice} = get_referenced_type(S,Tref),
+ MaybeChoice = get_non_typedef(S, Tref),
case catch((MaybeChoice#typedef.typespec)#type.def) of
{'CHOICE',_} ->
maybe_illicit_implicit_tag(choice,Tag);
@@ -3347,7 +3347,7 @@ check_type(S=#state{recordtopname=TopName},Type,Ts) when is_record(Ts,type) ->
TempNewDef#newt{
type = check_externaltypereference(S,NewExt),
tag = case S#state.erule of
- ber_bin_v2 ->
+ ber ->
merge_tags(Ct,RefType#type.tag);
_ ->
Ct
@@ -3617,6 +3617,14 @@ check_type(S=#state{recordtopname=TopName},Type,Ts) when is_record(Ts,type) ->
check_type(_S,Type,Ts) ->
exit({error,{asn1,internal_error,Type,Ts}}).
+get_non_typedef(S, Tref0) ->
+ case get_referenced_type(S, Tref0) of
+ {_,#typedef{typespec=#type{def=#'Externaltypereference'{}=Tref}}} ->
+ get_non_typedef(S, Tref);
+ {_,Type} ->
+ Type
+ end.
+
%% tablecinf_choose. A SEQUENCE or SET may be inserted in another
%% SEQUENCE or SET by the COMPONENTS OF directive. If this inserted
%% type is a referenced type that already has been checked it already
@@ -4332,11 +4340,33 @@ permitted_alphabet_merge([C1|Rest],UorI,Acc) ->
%% there will be no extension if the last constraint is without extension.
%% The rootset of all constraints are considered in the "outermoust
%% intersection". See section 13.1.2 in Dubuisson.
-constraint_merge(_S,C=[H])when is_tuple(H) ->
+constraint_merge(St, Cs0) ->
+ Cs = constraint_merge_1(St, Cs0),
+ normalize_cs(Cs).
+
+normalize_cs([{'SingleValue',[V]}|Cs]) ->
+ [{'SingleValue',V}|normalize_cs(Cs)];
+normalize_cs([{'SingleValue',[_|_]=L0}|Cs]) ->
+ [H|T] = L = lists:usort(L0),
+ [case is_range(H, T) of
+ false -> {'SingleValue',L};
+ true -> {'ValueRange',{H,lists:last(T)}}
+ end|normalize_cs(Cs)];
+normalize_cs([{'ValueRange',{Sv,Sv}}|Cs]) ->
+ [{'SingleValue',Sv}|normalize_cs(Cs)];
+normalize_cs([{'ValueRange',{'MIN','MAX'}}|Cs]) ->
+ normalize_cs(Cs);
+normalize_cs(Other) -> Other.
+
+is_range(Prev, [H|T]) when Prev =:= H - 1 -> is_range(H, T);
+is_range(_, [_|_]) -> false;
+is_range(_, []) -> true.
+
+constraint_merge_1(_S, [H]=C) when is_tuple(H) ->
C;
-constraint_merge(_S,[]) ->
+constraint_merge_1(_S, []) ->
[];
-constraint_merge(S,C) ->
+constraint_merge_1(S, C) ->
%% skip all extension but the last extension
C1 = filter_extensions(C),
%% perform all internal level intersections, intersections first
@@ -4359,17 +4389,16 @@ constraint_merge(S,C) ->
%% get the least common size constraint
SZs = get_constraints(C3,'SizeConstraint'),
CombSZ = intersection_of_size(S,SZs),
- CminusSVs=ordsets:subtract(ordsets:from_list(C3),ordsets:from_list(SVs)),
- % CminusSVsVRs = ordsets:subtract(ordsets:from_list(CminusSVs),
-% ordsets:from_list(VRs)),
- RestC = ordsets:subtract(ordsets:from_list(CminusSVs),
- ordsets:from_list(SZs)),
+ RestC = ordsets:subtract(ordsets:from_list(C3),
+ ordsets:from_list(SZs ++ VRs ++ SVs)),
%% get the least common combined constraint. That is the union of each
- %% deep costraint and merge of single value and value range constraints
- NewCs = combine_constraints(S,CombSV,CombVR,CombSZ++RestC),
- [X||X <- lists:flatten(NewCs),
- X /= intersection,
- X /= union].
+ %% deep constraint and merge of single value and value range constraints.
+ %% FIXME: Removing 'intersection' from the flattened list essentially
+ %% means that intersections are converted to unions!
+ Cs = combine_constraints(S, CombSV, CombVR, CombSZ++RestC),
+ [X || X <- lists:flatten(Cs),
+ X =/= intersection,
+ X =/= union].
%% constraint_union(S,C) takes a list of constraints as input and
%% merge them to a union. Unions are performed when two
@@ -4399,16 +4428,16 @@ constraint_union(_S,C) ->
constraint_union1(S,[A={'ValueRange',_},union,B={'ValueRange',_}|Rest],Acc) ->
AunionB = constraint_union_vr([A,B]),
- constraint_union1(S,Rest,Acc ++ AunionB);
+ constraint_union1(S, AunionB++Rest, Acc);
constraint_union1(S,[A={'SingleValue',_},union,B={'SingleValue',_}|Rest],Acc) ->
AunionB = constraint_union_sv(S,[A,B]),
constraint_union1(S,Rest,Acc ++ AunionB);
constraint_union1(S,[A={'SingleValue',_},union,B={'ValueRange',_}|Rest],Acc) ->
AunionB = union_sv_vr(S,A,B),
- constraint_union1(S,Rest,Acc ++ AunionB);
+ constraint_union1(S, AunionB++Rest, Acc);
constraint_union1(S,[A={'ValueRange',_},union,B={'SingleValue',_}|Rest],Acc) ->
AunionB = union_sv_vr(S,B,A),
- constraint_union1(S,Rest,Acc ++ AunionB);
+ constraint_union1(S, AunionB++Rest, Acc);
constraint_union1(S,[union|Rest],Acc) -> %skip when unsupported constraints
constraint_union1(S,Rest,Acc);
constraint_union1(S,[A|Rest],Acc) ->
@@ -4441,15 +4470,8 @@ constraint_union_vr(VR) ->
({_,{A1,_B1}},{_,{A2,_B2}}) when is_integer(A1),is_integer(A2),A1<A2 -> true;
({_,{A,B1}},{_,{A,B2}}) when B1=<B2->true;
(_,_)->false end,
- % sort and remove duplicates
- SortedVR = lists:sort(Fun,VR),
- RemoveDup = fun([],_) ->[];
- ([H],_) -> [H];
- ([H,H|T],F) -> F([H|T],F);
- ([H|T],F) -> [H|F(T,F)]
- end,
-
- constraint_union_vr(RemoveDup(SortedVR,RemoveDup),[]).
+ SortedVR = lists:usort(Fun,VR),
+ constraint_union_vr(SortedVR, []).
constraint_union_vr([],Acc) ->
lists:reverse(Acc);
@@ -4459,8 +4481,8 @@ constraint_union_vr([{_,{Lb,Ub2}}|Rest],[{_,{Lb,_Ub1}}|Acc]) -> %Ub2 > Ub1
constraint_union_vr(Rest,[{'ValueRange',{Lb,Ub2}}|Acc]);
constraint_union_vr([{_,{_,Ub}}|Rest],A=[{_,{_,Ub}}|_Acc]) ->
constraint_union_vr(Rest,A);
-constraint_union_vr([{_,{Lb2,Ub2}}|Rest],[{_,{Lb1,Ub1}}|Acc]) when Lb2=<Ub1,
- Ub2>Ub1->
+constraint_union_vr([{_,{Lb2,Ub2}}|Rest], [{_,{Lb1,Ub1}}|Acc])
+ when Ub1 =< Lb2, Ub1 < Ub2 ->
constraint_union_vr(Rest,[{'ValueRange',{Lb1,Ub2}}|Acc]);
constraint_union_vr([{_,{_,Ub2}}|Rest],A=[{_,{_,Ub1}}|_Acc]) when Ub2=<Ub1->
constraint_union_vr(Rest,A);
@@ -4581,9 +4603,11 @@ constraint_intersection(_S,C) ->
constraint_intersection1(S,[A,intersection,B|Rest],Acc) ->
AisecB = c_intersect(S,A,B),
- constraint_intersection1(S,Rest,AisecB++Acc);
+ constraint_intersection1(S, AisecB++Rest, Acc);
constraint_intersection1(S,[A|Rest],Acc) ->
constraint_intersection1(S,Rest,[A|Acc]);
+constraint_intersection1(_, [], [C]) ->
+ C;
constraint_intersection1(_,[],Acc) ->
lists:reverse(Acc).
@@ -5289,7 +5313,7 @@ iof_associated_type(S,[]) ->
AssociateSeq = iof_associated_type1(S,[]),
Tag =
case S#state.erule of
- ber_bin_v2 ->
+ ber ->
[?TAG_CONSTRUCTED(?N_INSTANCE_OF)];
_ -> []
end,
@@ -5320,7 +5344,7 @@ iof_associated_type1(S,C) ->
end,
{ObjIdTag,C1TypeTag}=
case S#state.erule of
- ber_bin_v2 ->
+ ber ->
{[{'UNIVERSAL',8}],
[#tag{class='UNIVERSAL',
number=6,
@@ -5551,8 +5575,9 @@ complist_as_tuple(_Per,[],Acc,Ext,_Acc2,ext) ->
complist_as_tuple(_Per,[],Acc,Ext,Acc2,root2) ->
{lists:reverse(Acc),lists:reverse(Ext),lists:reverse(Acc2)}.
-is_erule_per(Erule) ->
- lists:member(Erule,[per,per_bin,uper_bin]).
+is_erule_per(per) -> true;
+is_erule_per(uper) -> true;
+is_erule_per(ber) -> false.
expand_components(S, [{'COMPONENTS OF',Type}|T]) ->
CompList = expand_components2(S,get_referenced_type(S,Type#type.def)),
@@ -5641,7 +5666,7 @@ check_set(S,Type,Components) ->
{true,_} ->
{Sorted,SortedComponents} = sort_components(der,S,NewComponents),
{Sorted,TableCInf,SortedComponents};
- {_,PER} when PER =:= per; PER =:= per_bin; PER =:= uper_bin ->
+ {_,PER} when PER =:= per; PER =:= uper ->
{Sorted,SortedComponents} = sort_components(per,S,NewComponents),
{Sorted,TableCInf,SortedComponents};
_ ->
@@ -5765,7 +5790,7 @@ sort_universal_type(Components) ->
decode_type(I) when is_integer(I) ->
I;
decode_type(T) ->
- asn1ct_gen_ber:decode_type(T).
+ asn1ct_gen_ber_bin_v2:decode_type(T).
untagged_choice(_S,[#'ComponentType'{typespec=#type{tag=[],def={'CHOICE',_}}}|_Rest]) ->
true;
@@ -6884,16 +6909,16 @@ get_taglist(S,{ObjCl,FieldNameList}) when is_record(ObjCl,objectclass),
{TypeFieldName,_} when is_atom(TypeFieldName) -> []%should check if allowed
end;
get_taglist(S,Def) ->
- case lists:member(S#state.erule,[ber_bin_v2]) of
- false ->
+ case S#state.erule of
+ ber ->
+ [];
+ _ ->
case Def of
'ASN1_OPEN_TYPE' -> % open_type has no UNIVERSAL tag as such
[];
_ ->
[asn1ct_gen:def_to_tag(Def)]
- end;
- _ ->
- []
+ end
end.
get_taglist1(S,[#'ComponentType'{name=_Cname,tags=TagL}|Rest]) when is_list(TagL) ->
diff --git a/lib/asn1/src/asn1ct_constructed_ber.erl b/lib/asn1/src/asn1ct_constructed_ber.erl
deleted file mode 100644
index 360de77663..0000000000
--- a/lib/asn1/src/asn1ct_constructed_ber.erl
+++ /dev/null
@@ -1,1596 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% 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(asn1ct_constructed_ber).
-
--export([gen_encode_sequence/3]).
--export([gen_decode_sequence/3]).
--export([gen_encode_set/3]).
--export([gen_decode_set/3]).
--export([gen_encode_sof/4]).
--export([gen_decode_sof/4]).
--export([gen_encode_choice/3]).
--export([gen_decode_choice/3]).
-
-%%%% Application internal exports
--export([match_tag/2]).
-
--include("asn1_records.hrl").
-
--import(asn1ct_gen, [emit/1,demit/1,get_record_name_prefix/0]).
-
-% the encoding of class of tag bits 8 and 7
--define(UNIVERSAL, 0).
--define(APPLICATION, 16#40).
--define(CONTEXT, 16#80).
--define(PRIVATE, 16#C0).
-
-% primitive or constructed encoding % bit 6
--define(PRIMITIVE, 0).
--define(CONSTRUCTED, 2#00100000).
-
-
-
-
-%%===============================================================================
-%%===============================================================================
-%%===============================================================================
-%% Encode/decode SEQUENCE
-%%===============================================================================
-%%===============================================================================
-%%===============================================================================
-
-gen_encode_sequence(Erules,Typename,D) when is_record(D,type) ->
- asn1ct_name:start(),
- asn1ct_name:new(term),
- asn1ct_name:new(bytes),
-
- %% if EXTERNAL type the input value must be transformed to
- %% ASN1 1990 format
- case Typename of
- ['EXTERNAL'] ->
- emit([" NewVal = asn1rt_check:transform_to_EXTERNAL1990(Val),",
- nl]);
- _ ->
- ok
- end,
-
- {SeqOrSet,TableConsInfo,CompList0} =
- case D#type.def of
- #'SEQUENCE'{tablecinf=TCI,components=CL} ->
- {'SEQUENCE',TCI,CL};
- #'SET'{tablecinf=TCI,components=CL} ->
- {'SET',TCI,CL}
- end,
- %% filter away extensionAdditiongroup markers
- CompList = filter_complist(CompList0),
- Ext = extensible(CompList),
- CompList1 = case CompList of
- {Rl1,El,Rl2} -> Rl1 ++ El ++ Rl2;
- {Rl,El} -> Rl ++ El;
- _ -> CompList
- end,
- EncObj =
- case TableConsInfo of
- #simpletableattributes{usedclassfield=Used,
- uniqueclassfield=Unique} when Used /= Unique ->
- false;
- %% ObjectSetRef, name of the object set in constraints
- %%
- %%{ObjectSetRef,AttrN,N,UniqueFieldName}
- #simpletableattributes{objectsetname=ObjectSetRef,
- c_name=AttrN,
- c_index=N,
- usedclassfield=UniqueFieldName,
- uniqueclassfield=UniqueFieldName,
- valueindex=ValueIndex
- } ->
- OSDef =
- case ObjectSetRef of
- {Module,OSName} ->
- asn1_db:dbget(Module,OSName);
- OSName ->
- asn1_db:dbget(get(currmod),OSName)
- end,
-% io:format("currmod: ~p~nOSName: ~p~nAttrN: ~p~nN: ~p~nUniqueFieldName: ~p~n",
-% [get(currmod),OSName,AttrN,N,UniqueFieldName]),
- case (OSDef#typedef.typespec)#'ObjectSet'.gen of
- true ->
-% Val = lists:concat(["?RT_BER:cindex(",
-% N+1,",Val,"]),
- ObjectEncode =
- asn1ct_gen:un_hyphen_var(lists:concat(['Obj',
- AttrN])),
- emit({ObjectEncode," = ",nl}),
- {ObjSetMod,ObjSetName} =
- case ObjectSetRef of
- {M,O} ->
- {{asis,M},O};
- O ->
- {"?MODULE",O}
- end,
- emit({" ",ObjSetMod,":'getenc_",ObjSetName,"'(",{asis,UniqueFieldName},
- ", ",nl}),
-% emit({indent(35),"?RT_BER:cindex(",N+1,", Val,",
-% {asis,AttrN},")),",nl}),
- Length = fun(X,_LFun) when is_atom(X) ->
- length(atom_to_list(X));
- (X,_LFun) when is_list(X) ->
- length(X);
- ({X1,X2},LFun) ->
- LFun(X1,LFun) + LFun(X2,LFun)
- end,
- emit([indent(10+Length(ObjectSetRef,Length)),
- "value_match(",{asis,ValueIndex},",",
- "?RT_BER:cindex(",N+1,",Val,",
- {asis,AttrN},"))),",nl]),
- notice_value_match(),
- {AttrN,ObjectEncode};
- _ ->
- false
- end;
- _ ->
- case D#type.tablecinf of
- [{objfun,_}|_] ->
- %% when the simpletableattributes was at an
- %% outer level and the objfun has been passed
- %% through the function call
- {"got objfun through args","ObjFun"};
- _ ->
- false
- end
- end,
-
- gen_enc_sequence_call(Erules,Typename,CompList1,1,Ext,EncObj),
-
- MyTag = [X#tag{class=asn1ct_gen_ber:decode_class(X#tag.class)}|| X <- D#type.tag]
- ++
- [#tag{class = asn1ct_gen_ber:decode_class('UNIVERSAL'),
- number = asn1ct_gen_ber:decode_type(SeqOrSet),
- form = ?CONSTRUCTED,
- type = 'IMPLICIT'}],
- emit([nl," BytesSoFar = "]),
- case SeqOrSet of
- 'SET' when (D#type.def)#'SET'.sorted == dynamic ->
- emit("asn1rt_check:dynamicsort_SET_components(["),
- mkvlist(asn1ct_name:all(encBytes)),
- emit(["]),",nl]);
- _ ->
- emit("["),
- mkvlist(asn1ct_name:all(encBytes)),
- emit(["],",nl])
- end,
- emit(" LenSoFar = "),
- case asn1ct_name:all(encLen) of
- [] -> emit("0");
- AllLengths ->
- mkvplus(AllLengths)
- end,
- emit([",",nl]),
-% emit(["{TagBytes,Len} = ?RT_BER:encode_tags(TagIn ++ ",
- emit([" ?RT_BER:encode_tags(TagIn ++ ",
- {asis,MyTag},", BytesSoFar, LenSoFar).",nl]).
-
-
-gen_decode_sequence(Erules,Typename,D) when is_record(D,type) ->
- asn1ct_name:start(),
- asn1ct_name:new(tag),
- #'SEQUENCE'{tablecinf=TableConsInfo,components=CList0} = D#type.def,
-
- %% filter away extensionAdditiongroup markers
- CList = filter_complist(CList0),
-
- Ext = extensible(CList),
- {CompList,CompList2} = case CList of
- {Rl1,El,Rl2} -> {Rl1 ++ El ++ Rl2,CList};
- {Rl,El} -> {Rl ++ El, Rl ++ El};
- _ -> {CList,CList}
- end,
-
- emit([" %%-------------------------------------------------",nl]),
- emit([" %% decode tag and length ",nl]),
- emit([" %%-------------------------------------------------",nl]),
-
- asn1ct_name:new(rb),
- MyTag = [X#tag{class=asn1ct_gen_ber:decode_class(X#tag.class)}|| X <- D#type.tag]
- ++
- [#tag{class = asn1ct_gen_ber:decode_class('UNIVERSAL'),
- number = asn1ct_gen_ber:decode_type('SEQUENCE'),
- form = ?CONSTRUCTED,
- type = 'IMPLICIT'}],
- emit([" {{_,",asn1ct_gen_ber:unused_var("Len",D#type.def),"},",{next,bytes},",",{curr,rb},
- "} = ?RT_BER:check_tags(TagIn ++ ",{asis,MyTag},", ",
- {curr,bytes},", OptOrMand), ",nl]),
- asn1ct_name:new(bytes),
- asn1ct_name:new(len),
-
- case CompList of
- [] -> true;
- _ ->
- emit({"{",{next,bytes},
- ",RemBytes} = ?RT_BER:split_list(",
- {curr,bytes},
- ",", {prev,len},"),",nl}),
- asn1ct_name:new(bytes)
- end,
-
- {DecObjInf,UniqueFName,ValueIndex} =
- case TableConsInfo of
- #simpletableattributes{objectsetname=ObjectSet,
- c_name=AttrN,
- usedclassfield=UniqueFieldName,
- uniqueclassfield=UniqueFieldName,
- valueindex=ValIndex
- } ->
- F = fun(#'ComponentType'{typespec=CT})->
- case {asn1ct_gen:get_constraint(CT#type.constraint,componentrelation),CT#type.tablecinf} of
-% case {CT#type.constraint,CT#type.tablecinf} of
- {no,[{objfun,_}|_R]} -> true;
- _ -> false
- end
- end,
- case lists:any(F,CompList) of
- %%AttributeName = asn1ct_gen:un_hyphen_var(AttrN),
- true -> % when component relation constraint establish
- %% relation from a component to another components
- %% subtype component
- {{AttrN,{deep,ObjectSet,UniqueFieldName,
- ValIndex}},
- UniqueFieldName,ValIndex};
- false ->
- {{AttrN,ObjectSet},UniqueFieldName,ValIndex}
- end;
- _ ->
- {false,false,false}
- end,
- RecordName = lists:concat([get_record_name_prefix(),asn1ct_gen:list2rname(Typename)]),
- case gen_dec_sequence_call(Erules,Typename,CompList2,Ext,DecObjInf) of
- no_terms -> % an empty sequence
- emit([nl,nl]),
- demit({"Result = "}), %dbg
- %% return value as record
- asn1ct_name:new(rb),
- emit([" {{'",RecordName,"'}, ",{curr,bytes},",",nl," "]),
- asn1ct_gen_ber:add_removed_bytes(),
- emit(["}.",nl]);
- {LeadingAttrTerm,PostponedDecArgs} ->
- emit([com,nl,nl]),
- case {LeadingAttrTerm,PostponedDecArgs} of
- {[],[]} ->
- ok;
- {_,[]} ->
- ok;
- {[{ObjSet,LeadingAttr,Term}],PostponedDecArgs} ->
- DecObj = asn1ct_gen:un_hyphen_var(lists:concat(['DecObj',LeadingAttr,Term])),
- ValueMatch = value_match(ValueIndex,Term),
- {ObjSetMod,ObjSetName} =
- case ObjSet of
- {M,O} ->
- {{asis,M},O};
- _ ->
- {"?MODULE",ObjSet}
- end,
- emit([DecObj," =",nl," ",ObjSetMod,":'getdec_",ObjSetName,"'(",
-% {asis,UniqueFName},", ",Term,"),",nl}),
- {asis,UniqueFName},", ",ValueMatch,"),",nl]),
- gen_dec_postponed_decs(DecObj,PostponedDecArgs)
- end,
- demit({"Result = "}), %dbg
- %% return value as record
- asn1ct_name:new(rb),
- asn1ct_name:new(bytes),
- ExtStatus = case Ext of
- {ext,_,_} -> ext;
- _ -> noext % noext | extensible
- end,
- emit([" {",{next,bytes},",",{curr,rb},"} = ?RT_BER:restbytes2(RemBytes, ",
- {curr,bytes},",",ExtStatus,"),",nl]),
- asn1ct_name:new(rb),
- case Typename of
- ['EXTERNAL'] ->
- emit([" OldFormat={'",RecordName,
- "', "]),
- mkvlist(asn1ct_name:all(term)),
- emit(["},",nl]),
- emit([" ASN11994Format =",nl,
- " asn1rt_check:transform_to_EXTERNAL1994",
- "(OldFormat),",nl]),
- emit([" {ASN11994Format,",{next,bytes},", "]);
- _ ->
- emit([" {{'",RecordName,"', "]),
- mkvlist(asn1ct_name:all(term)),
- emit(["}, ",{next,bytes},", "])
- end,
- asn1ct_gen_ber:add_removed_bytes(),
- emit(["}.",nl])
- end.
-
-gen_dec_postponed_decs(_,[]) ->
- emit(nl);
-gen_dec_postponed_decs(DecObj,[{_Cname,{FirstPFN,PFNList},Term,TmpTerm,_Tag,OptOrMand}|Rest]) ->
-% asn1ct_name:new(term),
- asn1ct_name:new(tmpterm),
- asn1ct_name:new(reason),
-
- emit({"{",Term,", _, _} = ",nl}),
- N = case OptOrMand of
- mandatory -> 0;
- 'OPTIONAL' ->
- emit_opt_or_mand_check(asn1_NOVALUE,TmpTerm),
- 6;
- {'DEFAULT',Val} ->
- emit_opt_or_mand_check(Val,TmpTerm),
- 6
- end,
- emit({indent(N+3),"case (catch ",DecObj,"(",{asis,FirstPFN},
-% ", ",TmpTerm,", ", {asis,Tag},", ",{asis,PFNList},")) of",nl}),
- ", ",TmpTerm,", [], ",{asis,PFNList},")) of",nl}),
- emit({indent(N+6),"{'EXIT', ",{curr,reason},"} ->",nl}),
- emit({indent(N+9),"exit({'Type not compatible with table constraint',",
- {curr,reason},"});",nl}),
- emit({indent(N+6),{curr,tmpterm}," ->",nl}),
- emit({indent(N+9),{curr,tmpterm},nl}),
-
- case OptOrMand of
- mandatory -> emit([indent(N+3),"end,",nl]);
- _ ->
- emit([indent(N+3),"end",nl,
- indent(3),"end,",nl])
- end,
-% emit({indent(3),"end,",nl}),
- gen_dec_postponed_decs(DecObj,Rest).
-
-
-emit_opt_or_mand_check(Value,TmpTerm) ->
- emit([indent(3),"case ",TmpTerm," of",nl,
- indent(6),{asis,Value}," -> {",{asis,Value},",[],[]};",nl,
- indent(6),"_ ->",nl]).
-
-%%============================================================================
-%% Encode/decode SET
-%%
-%%============================================================================
-
-gen_encode_set(Erules,Typename,D) when is_record(D,type) ->
- gen_encode_sequence(Erules,Typename,D).
-
-gen_decode_set(Erules,Typename,D) when is_record(D,type) ->
- asn1ct_name:start(),
- asn1ct_name:clear(),
- asn1ct_name:new(term),
- asn1ct_name:new(tag),
- #'SET'{components=TCompList0} = D#type.def,
-
- %% filter away extensionAdditiongroup markers
- TCompList = filter_complist(TCompList0),
- Ext = extensible(TCompList),
- ToOptional = fun(mandatory) ->
- 'OPTIONAL';
- (X) -> X
- end,
- CompList = case TCompList of
- {Rl1,El,Rl2} ->
- Rl1 ++ [X#'ComponentType'{prop=ToOptional(Y)}||X = #'ComponentType'{prop=Y}<-El] ++ Rl2;
- {Rl,El} -> Rl ++ El;
- _ -> TCompList
- end,
-
- emit([" %%-------------------------------------------------",nl]),
- emit([" %% decode tag and length ",nl]),
- emit([" %%-------------------------------------------------",nl]),
-
- asn1ct_name:new(rb),
- MyTag = [X#tag{class=asn1ct_gen_ber:decode_class(X#tag.class)}|| X <- D#type.tag]
- ++
- [#tag{class = asn1ct_gen_ber:decode_class('UNIVERSAL'),
- number = asn1ct_gen_ber:decode_type('SET'),
- form = ?CONSTRUCTED,
- type = 'IMPLICIT'}],
- emit([" {{_,Len},",{next,bytes},",",{curr,rb},
- "} = ?RT_BER:check_tags(TagIn ++ ",{asis,MyTag},", ",
- {curr,bytes},", OptOrMand), ",nl]),
- asn1ct_name:new(bytes),
- asn1ct_name:new(len),
- asn1ct_name:new(rb),
-
- emit([" {SetTerm, SetBytes, ",{curr,rb},"} = ?RT_BER:decode_set(0, Len, ",
- {curr,bytes},", OptOrMand, ",
- "fun 'dec_",asn1ct_gen:list2name(Typename),"_fun'/2, []),",nl]),
-
- asn1ct_name:new(rb),
- {ExtFlatten1,ExtFlatten2} =
- case Ext of
- noext -> {"",""};
- _ -> {"lists:flatten(",")"}
- end,
- emit([" 'dec_",asn1ct_gen:list2name(Typename),
- "__result__'(lists:sort(",ExtFlatten1,"SetTerm",ExtFlatten2,"), SetBytes, "]),
- asn1ct_gen_ber:add_removed_bytes(),
- emit([").",nl,nl,nl]),
-
- emit({"%%-------------------------------------------------",nl}),
- emit({"%% Set loop fun for ",asn1ct_gen:list2name(Typename),nl}),
- emit({"%%-------------------------------------------------",nl}),
-
- asn1ct_name:clear(),
- asn1ct_name:new(term),
- emit(["'dec_",asn1ct_gen:list2name(Typename),"_fun'(",{curr,bytes},
- ", OptOrMand) ->",nl]),
-
- asn1ct_name:new(bytes),
- gen_dec_set(Erules,Typename,CompList,1,Ext),
-
- emit([" %% tag not found, if extensionmark we should skip bytes here",nl]),
- emit([indent(6),"_ -> ",nl]),
- case Ext of
- noext ->
- emit([indent(9),"{[], Bytes,0}",nl]);
- _ ->
- asn1ct_name:new(rbCho),
- emit([indent(9),"{RestBytes, ",{curr,rbCho},
- "} = ?RT_BER:skipvalue(Bytes),",nl,
- indent(9),"{[], RestBytes, ",{curr,rbCho},"}",nl])
- end,
- emit([indent(3),"end.",nl,nl,nl]),
-
-
- emit({"%%-------------------------------------------------",nl}),
- emit({"%% Result ",asn1ct_gen:list2name(Typename),nl}),
- emit({"%%-------------------------------------------------",nl}),
-
- asn1ct_name:clear(),
- emit({"'dec_",asn1ct_gen:list2name(Typename),"__result__'(",
- asn1ct_gen_ber:unused_var("TermList",D#type.def),", Bytes, Rb) ->",nl}),
- RecordName = lists:concat([get_record_name_prefix(),
- asn1ct_gen:list2rname(Typename)]),
- case gen_dec_set_result(Erules,Typename,CompList) of
- no_terms ->
- %% return value as record
- asn1ct_name:new(rb),
- emit({" {{'",RecordName,"'}, Bytes, Rb}.",nl});
- _ ->
- emit({nl," case ",{curr,termList}," of",nl}),
- emit({" [] -> {{'",RecordName,"', "}),
- mkvlist(asn1ct_name:all(term)),
- emit({"}, Bytes, Rb};",nl}),
- emit({" ExtraAtt -> exit({error,{asn1,{too_many_attributes, ExtraAtt}}})",nl}),
- emit({" end.",nl}),
- emit({nl,nl,nl})
- end.
-
-
-%%===============================================================================
-%%===============================================================================
-%%===============================================================================
-%% Encode/decode SEQUENCE OF and SET OF
-%%===============================================================================
-%%===============================================================================
-%%===============================================================================
-
-gen_encode_sof(Erules,Typename,_InnerTypename,D) when is_record(D,type) ->
- asn1ct_name:start(),
- {SeqOrSetOf, Cont} = D#type.def,
-
- Objfun = case D#type.tablecinf of
- [{objfun,_}|_R] ->
- ", ObjFun";
- _ ->
- ""
- end,
-
- emit({" {EncBytes,EncLen} = 'enc_",asn1ct_gen:list2name(Typename),
- "_components'(Val",Objfun,",[],0),",nl}),
-
- MyTag = [X#tag{class=asn1ct_gen_ber:decode_class(X#tag.class)}|| X <- D#type.tag]
- ++
- [#tag{class = asn1ct_gen_ber:decode_class('UNIVERSAL'),
- number = asn1ct_gen_ber:decode_type(SeqOrSetOf),
- form = ?CONSTRUCTED,
- type = 'IMPLICIT'}],
-% gen_encode_tags(Erules,MyTag,"EncLen","EncBytes"),
- emit([" ?RT_BER:encode_tags(TagIn ++ ",
- {asis,MyTag},", EncBytes, EncLen).",nl,nl]),
-
- gen_encode_sof_components(Erules,Typename,SeqOrSetOf,Cont).
-% gen_enc_line(Erules,Typename,TypeNameSuffix,Cont,"H",0,
-% mandatory,"{EncBytes,EncLen} = "),
-
-
-gen_decode_sof(Erules,Typename,_InnerTypename,D) when is_record(D,type) ->
- asn1ct_name:start(),
- asn1ct_name:clear(),
- {SeqOrSetOf, TypeTag, Cont} =
- case D#type.def of
- {'SET OF',_Cont} -> {'SET OF','SET',_Cont};
- {'SEQUENCE OF',_Cont} -> {'SEQUENCE OF','SEQUENCE',_Cont}
- end,
- TypeNameSuffix = asn1ct_gen:constructed_suffix(SeqOrSetOf,Cont#type.def),
-
- emit({" %%-------------------------------------------------",nl}),
- emit({" %% decode tag and length ",nl}),
- emit({" %%-------------------------------------------------",nl}),
-
- asn1ct_name:new(rb),
- MyTag = [X#tag{class=asn1ct_gen_ber:decode_class(X#tag.class)}|| X <- D#type.tag]
- ++
- [#tag{class = asn1ct_gen_ber:decode_class('UNIVERSAL'),
- number = asn1ct_gen_ber:decode_type(TypeTag),
- form = ?CONSTRUCTED,
- type = 'IMPLICIT'}],
- emit([" {{_,Len},",{next,bytes},",",{curr,rb},
- "} = ?RT_BER:check_tags(TagIn ++ ",{asis,MyTag},", ",
- {curr,bytes},", OptOrMand), ",nl]),
-
- emit([" ?RT_BER:decode_components(",{curr,rb}]),
- InnerType = asn1ct_gen:get_inner(Cont#type.def),
- ContName = case asn1ct_gen:type(InnerType) of
- Atom when is_atom(Atom) -> Atom;
- _ -> TypeNameSuffix
- end,
- emit([", Len, ",{next,bytes},", "]),
-% NewCont =
-% case Cont#type.def of
-% {'ENUMERATED',_,Components}->
-% Cont#type{def={'ENUMERATED',Components}};
-% _ -> Cont
-% end,
- ObjFun =
- case D#type.tablecinf of
- [{objfun,_}|_R] ->
- ", ObjFun";
- _ ->
- []
- end,
- gen_dec_line_sof(Erules,Typename,ContName,Cont,ObjFun),
- emit([", []).",nl,nl,nl]).
-
-
-gen_encode_sof_components(Erules,Typename,SeqOrSetOf,Cont)
- when is_record(Cont,type)->
-
- {Objfun,ObjFun_novar,EncObj} =
- case Cont#type.tablecinf of
- [{objfun,_}|_R] ->
- {", ObjFun",", _",{no_attr,"ObjFun"}};
- _ ->
- {"","",false}
- end,
- emit(["'enc_",asn1ct_gen:list2name(Typename),
- "_components'([]",ObjFun_novar,", AccBytes, AccLen) -> ",nl]),
-
- case catch lists:member(der,get(encoding_options)) of
- true when SeqOrSetOf=='SET OF' ->
- emit([indent(3),
- "{asn1rt_check:dynamicsort_SETOF(AccBytes),AccLen};",nl,nl]);
- _ ->
- emit([indent(3),"{lists:reverse(AccBytes),AccLen};",nl,nl])
- end,
- emit(["'enc_",asn1ct_gen:list2name(Typename),
- "_components'([H|T]",Objfun,",AccBytes, AccLen) ->",nl]),
- TypeNameSuffix = asn1ct_gen:constructed_suffix(SeqOrSetOf,Cont#type.def),
- gen_enc_line(Erules,Typename,TypeNameSuffix,Cont,"H",3,
-% mandatory,"{EncBytes,EncLen} = ",EncObj),
- mandatory,EncObj),
- emit([",",nl]),
- emit([indent(3),"'enc_",asn1ct_gen:list2name(Typename),
- "_components'(T",Objfun,","]),
- emit(["[EncBytes|AccBytes], AccLen + EncLen).",nl,nl]).
-
-%%============================================================================
-%% Encode/decode CHOICE
-%%
-%%============================================================================
-
-gen_encode_choice(Erules,Typename,D) when is_record(D,type) ->
- ChoiceTag = D#type.tag,
- {'CHOICE',CompList} = D#type.def,
- Ext = extensible(CompList),
- CompList1 = case CompList of
- {Rl1,El,Rl2} -> Rl1 ++ El ++ Rl2;
- {Rl,El} -> Rl ++ El;
- _ -> CompList
- end,
- gen_enc_choice(Erules,Typename,ChoiceTag,CompList1,Ext),
- emit({nl,nl}).
-
-gen_decode_choice(Erules,Typename,D) when is_record(D,type) ->
- asn1ct_name:start(),
- asn1ct_name:new(bytes),
- ChoiceTag = D#type.tag,
- {'CHOICE',CompList} = D#type.def,
- Ext = extensible(CompList),
- CompList1 = case CompList of
- {Rl1,El,Rl2} -> Rl1 ++ El ++Rl2;
- {Rl,El} -> Rl ++ El;
- _ -> CompList
- end,
- gen_dec_choice(Erules,Typename,ChoiceTag,CompList1,Ext),
- emit({".",nl}).
-
-
-%%============================================================================
-%% Encode SEQUENCE
-%%
-%%============================================================================
-
-gen_enc_sequence_call(Erules,TopType,[#'ComponentType'{name=Cname,typespec=Type,prop=Prop,textual_order=Order}|Rest],Pos,Ext,EncObj) ->
- asn1ct_name:new(encBytes),
- asn1ct_name:new(encLen),
- CindexPos =
- case Order of
- undefined ->
- Pos;
- _ -> Order % der
- end,
- Element =
- case TopType of
- ['EXTERNAL'] ->
- io_lib:format("?RT_BER:cindex(~w,NewVal,~w)",[CindexPos+1,Cname]);
- _ ->
- io_lib:format("?RT_BER:cindex(~w,Val,~w)",[CindexPos+1,Cname])
- end,
- InnerType = asn1ct_gen:get_inner(Type#type.def),
- print_attribute_comment(InnerType,Pos,Prop),
- gen_enc_line(Erules,TopType,Cname,Type,Element,3,Prop,EncObj),
- case Rest of
- [] ->
- emit({com,nl});
- _ ->
- emit({com,nl}),
- gen_enc_sequence_call(Erules,TopType,Rest,Pos+1,Ext,EncObj)
- end;
-
-gen_enc_sequence_call(_Erules,_TopType,[],_Num,_,_) ->
- true.
-
-%%============================================================================
-%% Decode SEQUENCE
-%%
-%%============================================================================
-
-gen_dec_sequence_call(Erules,TopType,CompList,Ext,DecObjInf)
- when is_list(CompList) ->
- gen_dec_sequence_call1(Erules,TopType, CompList, 1, Ext,DecObjInf,[],[]);
-gen_dec_sequence_call(Erules,TopType,CList,Ext,DecObjInf) ->
- gen_dec_sequence_call2(Erules,TopType,CList,Ext,DecObjInf).
-
-gen_dec_sequence_call1(Erules,TopType,[#'ComponentType'{name=Cname,typespec=Type,prop=Prop,tags=Tags}|Rest],Num,Ext,DecObjInf,LeadingAttrAcc,ArgsAcc) ->
- {LA,PostponedDec} =
- gen_dec_component(Erules,TopType,Cname,Tags,Type,Num,Prop,
- Ext,DecObjInf),
- case Rest of
- [] ->
- {LA ++ LeadingAttrAcc,PostponedDec ++ ArgsAcc};
- _ ->
- emit({com,nl}),
-% asn1ct_name:new(term),
- asn1ct_name:new(bytes),
- gen_dec_sequence_call1(Erules,TopType,Rest,Num+1,Ext,DecObjInf,
- LA++LeadingAttrAcc,PostponedDec++ArgsAcc)
- end;
-
-gen_dec_sequence_call1(_Erules,_TopType,[],1,_,_,_,_) ->
- no_terms.
-
-gen_dec_sequence_call2(_Erules,_TopType,{[],[],[]},_Ext,_DecObjInf) ->
- no_terms;
-gen_dec_sequence_call2(Erules,TopType,{Root1,EList,Root2},_Ext,DecObjInf) ->
- {LA,ArgsAcc} =
- case gen_dec_sequence_call1(Erules,TopType,Root1++EList,1,
- extensible({Root1,EList}),DecObjInf,[],[]) of
- no_terms ->
- {[],[]};
- Res -> Res
- end,
- %% TagList is the tags of Root2 elements from the first up to and
- %% including the first mandatory element.
- TagList = get_root2_taglist(Root2,[]),
- emit({com,nl}),
- asn1ct_name:new(bytes),
- emit([" {",{next,bytes},", ",{next,rb},
- "} = ?RT_BER:skip_ExtensionAdditions(",
- {curr,bytes},", ",{asis,TagList},"),",nl]),
- asn1ct_name:new(rb),
- asn1ct_name:new(bytes),
- gen_dec_sequence_call1(Erules,TopType,Root2,
- length(Root1)+length(EList),noext,
- DecObjInf,LA,ArgsAcc).
-
-%% returns a list of tags of the elements in the component (second
-%% root) list up to and including the first mandatory tag. See 24.6 in
-%% X.680 (7/2002)
-get_root2_taglist([],Acc) ->
- lists:reverse(Acc);
-get_root2_taglist([#'ComponentType'{prop=Prop,typespec=Type}|Rest],Acc) ->
- FirstTag = fun([])->[];
- ([H|_T])->H#tag{class=asn1ct_gen_ber:decode_class(H#tag.class)}
- end(Type#type.tag),
- case Prop of
- mandatory ->
- %% match_tags/ may be used
- %% this is the last tag of interest -> return
- lists:reverse([FirstTag|Acc]);
- _ ->
- get_root2_taglist(Rest,[FirstTag|Acc])
- end.
-
-
-%%----------------------------
-%%SEQUENCE mandatory
-%%----------------------------
-
-gen_dec_component(Erules,TopType,Cname,CTags,Type,Pos,Prop,Ext,DecObjInf) ->
- InnerType =
- case Type#type.def of
- #'ObjectClassFieldType'{type=OCFTType} -> OCFTType;
- _ -> asn1ct_gen:get_inner(Type#type.def)
- end,
-
- Prop1 = case {Prop,Ext} of
- {_,{ext,Epos,_Root2pos}} when Pos < Epos ->
- Prop;
- {mandatory,{ext,Epos,_}} when Pos >= Epos ->
- 'OPTIONAL';
- _ ->
- Prop
- end,
- print_attribute_comment(InnerType,Pos,Prop1),
- emit(" "),
-
- case {InnerType,DecObjInf} of
- {{typefield,_},NotFalse} when NotFalse /= false ->
- asn1ct_name:new(term),
- asn1ct_name:new(tmpterm),
- emit({"{",{curr,tmpterm},", ",{next,bytes},",",{next,rb},"} = "});
- {{objectfield,_,_},_} ->
- asn1ct_name:new(term),
- asn1ct_name:new(tmpterm),
- emit({"{",{curr,tmpterm},", ",{next,bytes},",",{next,rb},"} = "});
- _ ->
- asn1ct_name:new(term),
- emit({"{",{curr,term},",",{next,bytes},",",{next,rb},"} = "})
- end,
- asn1ct_name:new(rb),
- PostponedDec =
- gen_dec_line(Erules,TopType,Cname,CTags,Type,Prop1,DecObjInf),
- asn1ct_name:new(form),
- PostponedDec.
-
-
-%%-------------------------------------
-%% Decode SET
-%%-------------------------------------
-
-gen_dec_set(Erules,TopType,CompList,Pos,Ext) ->
- ExtCatch = case Ext of
- noext ->"";
- _ -> " catch"
- end,
- TagList = get_all_choice_tags(CompList),
- emit({indent(3),
- {curr,tagList}," = ",{asis,TagList},",",nl}),
- emit({indent(3),
- "case",ExtCatch," ?RT_BER:check_if_valid_tag(Bytes, ",
- {curr,tagList},", OptOrMand) of",nl}),
- asn1ct_name:new(tagList),
- asn1ct_name:new(rbCho),
- asn1ct_name:new(choTags),
- gen_dec_set_cases(Erules,TopType,CompList,TagList,Pos),
- asn1ct_name:new(tag),
- asn1ct_name:new(bytes).
-
-
-
-gen_dec_set_cases(_,_,[],_,_) ->
- ok;
-gen_dec_set_cases(Erules,TopType,[H|T],List,Pos) ->
- Name = H#'ComponentType'.name,
- Type = H#'ComponentType'.typespec,
-
- emit({indent(6),"'",Name,"' ->",nl}),
- case Type#type.def of
- {'CHOICE',_NewCompList} ->
- gen_dec_set_cases_choice(Erules,TopType,H,Pos);
- _ ->
- gen_dec_set_cases_type(Erules,TopType,H,Pos)
- end,
- gen_dec_set_cases(Erules,TopType,T,List,Pos+1).
-
-
-
-gen_dec_set_cases_choice(_Erules,TopType,H,Pos) ->
- Cname = H#'ComponentType'.name,
- Tag = [X#tag{class=asn1ct_gen_ber:decode_class(X#tag.class)}
- || X <- (H#'ComponentType'.typespec)#type.tag],
- asn1ct_name:new(rbCho),
- emit({indent(9),"{Dec, Rest, ",{curr,rbCho},"} = "}),
- emit({"'dec_",asn1ct_gen:list2name([Cname|TopType]),
- "'(Bytes,OptOrMand,",{asis,Tag},"),",nl}),
- emit([" {{",Pos,",Dec}, Rest, ",{curr,rbCho},"}"]),
- emit([";",nl,nl]).
-
-
-gen_dec_set_cases_type(Erules,TopType,H,Pos) ->
- Cname = H#'ComponentType'.name,
- Type = H#'ComponentType'.typespec,
- %% always use Prop = mandatory here Prop = H#'ComponentType'.prop,
-
- asn1ct_name:new(rbCho),
- emit({indent(9),"{Dec, Rest, ",{curr,rbCho},"} = "}),
- asn1ct_name:delete(bytes),
- %% we have already seen the tag so now we must find the value
- %% that why we always use 'mandatory' here
- gen_dec_line(Erules,TopType,Cname,[],Type,mandatory,decObjInf),
- asn1ct_name:new(bytes),
-
- emit([",",nl]),
- emit(["{{",Pos,",Dec}, Rest, ",{curr,rbCho},"}"]),
- emit([";",nl,nl]).
-
-
-%%---------------------------------
-%% Decode SET result
-%%---------------------------------
-
-gen_dec_set_result(Erules,TopType,CompList) ->
- gen_dec_set_result1(Erules,TopType, CompList, 1).
-
-gen_dec_set_result1(Erules,TopType,
- [#'ComponentType'{name=Cname,
- typespec=Type,
- prop=Prop}|Rest],Num) ->
- gen_dec_set_component(Erules,TopType,Cname,Type,Num,Prop),
- case Rest of
- [] ->
- true;
- _ ->
- gen_dec_set_result1(Erules,TopType,Rest,Num+1)
- end;
-
-gen_dec_set_result1(_Erules,_TopType,[],1) ->
- no_terms;
-gen_dec_set_result1(_Erules,_TopType,[],_Num) ->
- true.
-
-
-gen_dec_set_component(_Erules,_TopType,_Cname,Type,Pos,Prop) ->
- InnerType = asn1ct_gen:get_inner(Type#type.def),
- print_attribute_comment(InnerType,Pos,Prop),
- emit({" {",{next,term},com,{next,termList},"} =",nl}),
- emit({" case ",{curr,termList}," of",nl}),
- emit({" [{",Pos,com,{curr,termTmp},"}|",
- {curr,rest},"] -> "}),
- emit({"{",{curr,termTmp},com,
- {curr,rest},"};",nl}),
- case Prop of
- 'OPTIONAL' ->
- emit([indent(10),"_ -> {asn1_NOVALUE, ",{curr,termList},"}",nl]);
- {'DEFAULT', DefVal} ->
- emit([indent(10),
- "_ -> {",{asis,DefVal},", ",{curr,termList},"}",nl]);
- mandatory ->
- emit([indent(10),
- "_ -> exit({error,{asn1,{mandatory_attribute_no, ",
- Pos,", missing}}})",nl])
- end,
- emit([indent(6),"end,",nl]),
- asn1ct_name:new(rest),
- asn1ct_name:new(term),
- asn1ct_name:new(termList),
- asn1ct_name:new(termTmp).
-
-
-%%---------------------------------------------
-%% Encode CHOICE
-%%---------------------------------------------
-%% for BER we currently do care (a little) if the choice has an EXTENSIONMARKER
-
-
-gen_enc_choice(Erules,TopType,Tag,CompList,_Ext) ->
- gen_enc_choice1(Erules,TopType,Tag,CompList,_Ext).
-
-gen_enc_choice1(Erules,TopType,Tag,CompList,_Ext) ->
- asn1ct_name:clear(),
- emit({" {EncBytes,EncLen} = case element(1,Val) of",nl}),
- gen_enc_choice2(Erules,TopType,CompList),
- emit([nl," end,",nl,nl]),
- NewTag = [X#tag{class=asn1ct_gen_ber:decode_class(X#tag.class)}|| X <- Tag],
-% gen_encode_tags(Erules,NewTag,"EncLen","EncBytes").
- emit(["?RT_BER:encode_tags(TagIn ++",{asis,NewTag},", EncBytes, EncLen).",nl]).
-
-
-
-gen_enc_choice2(Erules,TopType,[H1|T]) when is_record(H1,'ComponentType') ->
- Cname = H1#'ComponentType'.name,
- Type = H1#'ComponentType'.typespec,
- emit({" ",{asis,Cname}," ->",nl}),
- {Encobj,Assign} =
-% case asn1ct_gen:get_constraint(Type#type.constraint,
-% tableconstraint_info) of
- case {Type#type.def,asn1ct_gen:get_constraint(Type#type.constraint,
- componentrelation)} of
- {#'ObjectClassFieldType'{},{componentrelation,_,_}} ->
- asn1ct_name:new(tmpBytes),
- asn1ct_name:new(encBytes),
- asn1ct_name:new(encLen),
- Emit = ["{",{curr,tmpBytes},", _} = "],
- {{no_attr,"ObjFun"},Emit};
- _ ->
- case Type#type.tablecinf of
- [{objfun,_}] -> {{no_attr,"ObjFun"},[]};
- _-> {false,[]}
- end
- end,
- gen_enc_line(Erules,TopType,Cname,Type,"element(2,Val)",9,
- mandatory,Assign,Encobj),
- case {Type#type.def,Encobj} of
- {#'ObjectClassFieldType'{},{no_attr,"ObjFun"}} ->
- emit({",",nl,indent(9),"{",{curr,encBytes},", ",
- {curr,encLen},"}"});
- _ -> ok
- end,
- emit({";",nl}),
- case T of
- [] ->
- emit([indent(6), "Else -> ",nl,
- indent(9),"exit({error,{asn1,{invalid_choice_type,Else}}})"]);
- _ ->
- true
- end,
- gen_enc_choice2(Erules,TopType,T);
-
-gen_enc_choice2(_,_,[]) ->
- true.
-
-
-
-
-%%--------------------------------------------
-%% Decode CHOICE
-%%--------------------------------------------
-
-gen_dec_choice(Erules,TopType, ChTag, CompList, Ext) ->
- asn1ct_name:delete(bytes),
- Tags = [X#tag{class=asn1ct_gen_ber:decode_class(X#tag.class)}|| X <- ChTag],
-
- emit([" {{_,Len},",{next,bytes},
- ", RbExp} = ?RT_BER:check_tags(TagIn++",
- {asis,Tags},", ",
- {curr,bytes},", OptOrMand),",nl]),
- asn1ct_name:new(bytes),
- asn1ct_name:new(len),
- gen_dec_choice_indef_funs(Erules),
- case Erules of
- ber_bin ->
- emit([indent(3),"case ",{curr,bytes}," of",nl]);
- ber ->
- emit([indent(3),
- "case (catch ?RT_BER:peek_tag(",{curr,bytes},")) of",nl])
- end,
- asn1ct_name:new(tagList),
- asn1ct_name:new(choTags),
- gen_dec_choice_cases(Erules,TopType,CompList),
- case Ext of
- noext ->
- emit([indent(6), {curr,else}," -> ",nl]),
- emit([indent(9),"case OptOrMand of",nl,
- indent(12),"mandatory ->","exit({error,{asn1,",
- "{invalid_choice_tag,",{curr,else},"}}});",nl,
- indent(12),"_ ->","exit({error,{asn1,{no_optional_tag,",
- {curr,else},"}}})",nl,
- indent(9),"end",nl]);
- _ ->
- emit([indent(6),"_ -> ",nl]),
- emit([indent(9),"{{asn1_ExtAlt,",{curr,bytes},"},",
- empty_lb(Erules),", RbExp}",nl])
- end,
- emit([indent(3),"end"]),
- asn1ct_name:new(tag),
- asn1ct_name:new(else).
-
-gen_dec_choice_indef_funs(Erules) ->
- emit({indent(3),"IndefEndBytes = fun(indefinite,",indefend_match(Erules,used_var),
- ")-> R; (_,B)-> B end,",nl}),
- emit({indent(3),"IndefEndRb = fun(indefinite,",indefend_match(Erules,unused_var),
- ")-> 2; (_,_)-> 0 end,",nl}).
-
-
-gen_dec_choice_cases(_,_, []) ->
- ok;
-gen_dec_choice_cases(Erules,TopType, [H|T]) ->
- asn1ct_name:push(rbCho),
- Name = H#'ComponentType'.name,
- emit([nl,"%% '",Name,"'",nl]),
- Fcases = fun([T1,T2|Tail],Fun) ->
- emit([indent(6),match_tag(Erules,T1)," ->",nl]),
- gen_dec_choice_cases_type(Erules,TopType, H),
- Fun([T2|Tail],Fun);
- ([T1],_) ->
- emit([indent(6),match_tag(Erules,T1)," ->",nl]),
- gen_dec_choice_cases_type(Erules,TopType, H)
- end,
- Fcases(H#'ComponentType'.tags,Fcases),
- asn1ct_name:pop(rbCho),
- gen_dec_choice_cases(Erules,TopType, T).
-
-
-
-gen_dec_choice_cases_type(Erules,TopType,H) ->
- Cname = H#'ComponentType'.name,
- Type = H#'ComponentType'.typespec,
- Prop = H#'ComponentType'.prop,
- emit({indent(9),"{Dec, Rest, ",{curr,rbCho},"} = "}),
- gen_dec_line(Erules,TopType,Cname,[],Type,Prop,false),
- emit([",",nl,indent(9),"{{",{asis,Cname},
- ", Dec}, IndefEndBytes(Len,Rest), RbExp + ",
- {curr,rbCho}," + IndefEndRb(Len,Rest)};",nl,nl]).
-
-encode_tag_val(Erules,{Class,TagNo}) when is_integer(TagNo) ->
- Rtmod = rtmod(Erules),
- Rtmod:encode_tag_val({asn1ct_gen_ber:decode_class(Class),
- 0,TagNo});
-encode_tag_val(Erules,{Class,TypeName}) ->
- Rtmod = rtmod(Erules),
- Rtmod:encode_tag_val({asn1ct_gen_ber:decode_class(Class),
- 0,asn1ct_gen_ber:decode_type(TypeName)}).
-
-
-match_tag(ber_bin,Arg) ->
- match_tag_with_bitsyntax(Arg);
-match_tag(Erules,Arg) ->
- io_lib:format("~p",[encode_tag_val(Erules,Arg)]).
-
-match_tag_with_bitsyntax({Class,TagNo}) when is_integer(TagNo) ->
- match_tag_with_bitsyntax1({asn1ct_gen_ber:decode_class(Class),
- 0,TagNo});
-match_tag_with_bitsyntax({Class,TypeName}) ->
- match_tag_with_bitsyntax1({asn1ct_gen_ber:decode_class(Class),
- 0,asn1ct_gen_ber:decode_type(TypeName)}).
-
-match_tag_with_bitsyntax1({Class, _Form, TagNo}) when (TagNo =< 30) ->
- io_lib:format("<<~p:2,_:1,~p:5,_/binary>>",[Class bsr 6,TagNo]);
-
-match_tag_with_bitsyntax1({Class, _Form, TagNo}) ->
- {Octets,Len} = mk_object_val(TagNo),
- OctForm = case Len of
- 1 -> "~p";
- 2 -> "~p,~p";
- 3 -> "~p,~p,~p";
- 4 -> "~p,~p,~p,~p"
- end,
- io_lib:format("<<~p:2,_:1,31:5," ++ OctForm ++ ",_/binary>>",
- [Class bsr 6] ++ Octets).
-
-%%%%%%%%%%%
-%% mk_object_val(Value) -> {OctetList, Len}
-%% returns a Val as a list of octets, the 8 bit is allways set to one except
-%% for the last octet, where its 0
-%%
-
-
-mk_object_val(Val) when Val =< 127 ->
- {[255 band Val], 1};
-mk_object_val(Val) ->
- mk_object_val(Val bsr 7, [Val band 127], 1).
-mk_object_val(0, Ack, Len) ->
- {Ack, Len};
-mk_object_val(Val, Ack, Len) ->
- mk_object_val(Val bsr 7, [((Val band 127) bor 128) | Ack], Len + 1).
-
-
-get_all_choice_tags(ComponentTypeList) ->
- get_all_choice_tags(ComponentTypeList,[]).
-
-get_all_choice_tags([],TagList) ->
- TagList;
-get_all_choice_tags([H|T],TagList) ->
- Tags = H#'ComponentType'.tags,
- get_all_choice_tags(T, TagList ++ [{H#'ComponentType'.name, Tags}]).
-
-
-
-%%---------------------------------------
-%% Generate the encode/decode code
-%%---------------------------------------
-
-gen_enc_line(Erules,TopType,Cname,
- Type=#type{constraint=C,
- def=#'ObjectClassFieldType'{type={typefield,_}}},
- Element,Indent,OptOrMand=mandatory,EncObj)
- when is_list(Element) ->
- case asn1ct_gen:get_constraint(C,componentrelation) of
- {componentrelation,_,_} ->
- asn1ct_name:new(tmpBytes),
- gen_enc_line(Erules,TopType,Cname,Type,Element,Indent,OptOrMand,
- ["{",{curr,tmpBytes},",_} = "],EncObj);
- _ ->
- gen_enc_line(Erules,TopType,Cname,Type,Element,Indent,OptOrMand,
- ["{",{curr,encBytes},",",{curr,encLen},"} = "],
- EncObj)
- end;
- gen_enc_line(Erules,TopType,Cname,Type,Element,Indent,OptOrMand,EncObj)
- when is_list(Element) ->
- gen_enc_line(Erules,TopType,Cname,Type,Element,Indent,OptOrMand,
- ["{",{curr,encBytes},",",{curr,encLen},"} = "],EncObj).
-
-gen_enc_line(Erules,TopType,Cname,Type,Element,Indent,OptOrMand,Assign,EncObj)
- when is_list(Element) ->
- IndDeep = indent(Indent),
-
- Tag = [X#tag{class=asn1ct_gen_ber:decode_class(X#tag.class)}
- || X <- Type#type.tag],
- InnerType = asn1ct_gen:get_inner(Type#type.def),
- WhatKind = asn1ct_gen:type(InnerType),
- emit(IndDeep),
- emit(Assign),
- gen_optormand_case(OptOrMand,Erules,TopType,Cname,Type,InnerType,WhatKind,
- Element),
- case {Type,asn1ct_gen:get_constraint(Type#type.constraint,
- componentrelation)} of
- {#type{def=#'ObjectClassFieldType'{type={typefield,_},
- fieldname=RefedFieldName}},
- {componentrelation,_,_}} ->
- {_LeadingAttrName,Fun} = EncObj,
- case RefedFieldName of
- {Name,RestFieldNames} when is_atom(Name),Name =/= notype ->
- case OptOrMand of
- mandatory -> ok;
- _ ->
- emit(["{",{curr,tmpBytes},", _} = "])
- end,
- emit({Fun,"(",{asis,Name},", ",Element,", [], ",
- {asis,RestFieldNames},"),",nl}),
- emit(IndDeep),
- case OptOrMand of
- mandatory ->
- emit({"{",{curr,encBytes},", ",{curr,encLen},"} = "}),
- emit({"?RT_BER:encode_open_type(",{curr,tmpBytes},
- ",",{asis,Tag},")"});
- _ ->
- emit({"{",{next,tmpBytes},", ",{curr,tmpLen},
- "} = "}),
- emit({"?RT_BER:encode_open_type(",{curr,tmpBytes},
- ",",{asis,Tag},"),",nl}),
- emit(IndDeep),
- emit({"{",{next,tmpBytes},", ",{curr,tmpLen},"}"})
- end;
- Err ->
- throw({asn1,{'internal error',Err}})
- end;
- _ ->
- case WhatKind of
- {primitive,bif} ->
- EncType =
- case Type#type.def of
- #'ObjectClassFieldType'{
- type={fixedtypevaluefield,
- _,Btype}} ->
- Btype;
- _ ->
- Type
- end,
- asn1ct_gen_ber:gen_encode_prim(ber,EncType,{asis,Tag},
- Element);
- 'ASN1_OPEN_TYPE' ->
- asn1ct_gen_ber:gen_encode_prim(ber,Type#type{def='ASN1_OPEN_TYPE'},{asis,Tag},Element);
- _ ->
- {EncFunName, _, _} =
- mkfuncname(TopType,Cname,WhatKind,enc),
- case {WhatKind,Type#type.tablecinf,EncObj} of
- {{constructed,bif},[{objfun,_}|_R],{_,Fun}} ->
- emit([EncFunName,"(",Element,", ",{asis,Tag},
- ", ",Fun,")"]);
- _ ->
- emit([EncFunName,"(",Element,", ",{asis,Tag},")"])
- end
- end
- end,
- case OptOrMand of
- mandatory -> true;
- _ ->
- emit({nl,indent(7),"end"})
- end.
-
-
-
-gen_optormand_case(mandatory,_,_,_,_,_,_, _) ->
- ok;
-gen_optormand_case('OPTIONAL',Erules,_,_,_,_,_,Element) ->
- emit({" case ",Element," of",nl}),
- emit({indent(9),"asn1_NOVALUE -> {",
- empty_lb(Erules),",0};",nl}),
- emit({indent(9),"_ ->",nl,indent(12)});
-gen_optormand_case({'DEFAULT',DefaultValue},Erules,TopType,Cname,Type,
- InnerType,WhatKind,Element) ->
- CurrMod = get(currmod),
- case catch lists:member(der,get(encoding_options)) of
- true ->
- emit(" case catch "),
- asn1ct_gen:gen_check_call(TopType,Cname,Type,InnerType,
- WhatKind,{asis,DefaultValue},
- Element),
- emit({" of",nl}),
- emit({indent(12),"true -> {[],0};",nl});
- _ ->
- emit({" case ",Element," of",nl}),
- emit({indent(9),"asn1_DEFAULT -> {",
- empty_lb(Erules),
- ",0};",nl}),
- case DefaultValue of
- #'Externalvaluereference'{module=CurrMod,
- value=V} ->
- emit({indent(9),"?",{asis,V}," -> {",
- empty_lb(Erules),",0};",nl});
- _ ->
- emit({indent(9),{asis,
- DefaultValue}," -> {",
- empty_lb(Erules),",0};",nl})
- end
- end,
- emit({indent(9),"_ ->",nl,indent(12)}).
-
-
-
-
-gen_dec_line_sof(Erules,TopType,Cname,Type,ObjFun) ->
-
- Tag = [X#tag{class=asn1ct_gen_ber:decode_class(X#tag.class)}
- || X <- Type#type.tag],
- InnerType = asn1ct_gen:get_inner(Type#type.def),
- WhatKind = asn1ct_gen:type(InnerType),
- case WhatKind of
- {primitive,bif} ->
- asn1ct_name:delete(len),
-
- asn1ct_name:new(len),
- emit(["fun(FBytes,_,_)->",nl]),
- EncType = case Type#type.def of
- #'ObjectClassFieldType'{
- type={fixedtypevaluefield,
- _,Btype}} ->
- Btype;
- _ ->
- Type
- end,
- asn1ct_gen_ber:gen_dec_prim(ber,EncType,"FBytes",Tag,
- [],no_length,?PRIMITIVE,
- mandatory),
- emit([nl,"end, []"]);
- _ ->
- case ObjFun of
- [] ->
- {DecFunName, _, _} =
- mkfunname(Erules,TopType,Cname,WhatKind,dec,3),
- emit([DecFunName,", ",{asis,Tag}]);
- _ ->
- {DecFunName, _, _} =
- mkfunname(Erules,TopType,Cname,WhatKind,dec,4),
- emit([DecFunName,", ",{asis,Tag},", ObjFun"])
- end
- end.
-
-
-gen_dec_line(Erules,TopType,Cname,CTags,Type,OptOrMand,DecObjInf) ->
- BytesVar = asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
- Tag = [X#tag{class=asn1ct_gen_ber:decode_class(X#tag.class)}
- || X <- Type#type.tag],
- InnerType =
- case Type#type.def of
- #'ObjectClassFieldType'{type=OCFTType} ->
- OCFTType;
- _ ->
- asn1ct_gen:get_inner(Type#type.def)
- end,
- PostpDec =
- case OptOrMand of
- mandatory ->
- gen_dec_call(InnerType,Erules,TopType,Cname,Type,
- BytesVar,Tag,mandatory,", mandatory, ",
- DecObjInf,OptOrMand);
- _ -> %optional or default
- case {CTags,Erules} of
- {[CTag],ber_bin} when CTag =/= [] -> % R9C-0.patch-34
- emit(["case ",{curr,bytes}," of",nl]),
- emit([match_tag(Erules,CTag)," ->",nl]),
- PostponedDec =
- gen_dec_call(InnerType,Erules,TopType,Cname,Type,
- BytesVar,Tag,mandatory,
- ", opt_or_default, ",DecObjInf,
- OptOrMand),
- emit([";",nl]),
- emit(["_ ->",nl]),
- case OptOrMand of
- {'DEFAULT', Def} ->
- emit(["{",{asis,Def},",",
- BytesVar,", 0 }",nl]);
- 'OPTIONAL' ->
- emit(["{ asn1_NOVALUE, ",
- BytesVar,", 0 }",nl])
- end,
- emit("end"),
- PostponedDec;
- _ ->
- emit("case (catch "),
- PostponedDec =
- gen_dec_call(InnerType,Erules,TopType,Cname,Type,
- BytesVar,Tag,OptOrMand,
- ", opt_or_default, ",DecObjInf,
- OptOrMand),
- emit([") of",nl]),
- case OptOrMand of
- {'DEFAULT', Def} ->
- emit(["{'EXIT',{error,{asn1,{no_optional_tag,_}}}}",
- " -> {",{asis,Def},",",
- BytesVar,", 0 };",nl]);
- 'OPTIONAL' ->
- emit(["{'EXIT',{error,{asn1,{no_optional_tag,_}}}}",
- " -> { asn1_NOVALUE, ",
- BytesVar,", 0 };",nl])
- end,
- asn1ct_name:new(casetmp),
- emit([{curr,casetmp},"-> ",{curr,casetmp},nl,"end"]),
- PostponedDec
- end
- end,
- case DecObjInf of
- {Cname,ObjSet} -> % this must be the component were an object is
- %% choosen from the object set according to the table
- %% constraint.
- ObjSetName = case ObjSet of
- {deep,OSName,_,_} ->
- OSName;
- _ -> ObjSet
- end,
- {[{ObjSetName,Cname,asn1ct_gen:mk_var(asn1ct_name:curr(term))}],
- PostpDec};
- _ -> {[],PostpDec}
- end.
-
-
-gen_dec_call({typefield,_},Erules,_,_,Type,_,Tag,_,_,false,_) ->
- %% this in case of a choice with typefield components
- asn1ct_name:new(reason),
- {FirstPFName,RestPFName} =
-% asn1ct_gen:get_constraint(Type#type.constraint,
-% tableconstraint_info),
- (Type#type.def)#'ObjectClassFieldType'.fieldname,
- emit([nl,indent(6),"begin",nl]),
- emit([indent(9),"{OpenDec,TmpRest,TmpRbCho} =",nl,indent(12),
- "?RT_BER:decode_open_type(",Erules,",",{curr,bytes},",",
- {asis,Tag},"),",nl]),
- emit([indent(9),"case (catch ObjFun(",{asis,FirstPFName},
- ", OpenDec, [], ",{asis,RestPFName},
- ")) of", nl]),%% ??? What about Tag
- emit([indent(12),"{'EXIT',",{curr,reason},"} ->",nl]),
-%% emit({indent(15),"throw({runtime_error,{'Type not ",
-%% "compatible with tableconstraint', OpenDec}});",nl}),
- emit([indent(15),"exit({'Type not ",
- "compatible with table constraint', ",{curr,reason},"});",nl]),
- emit([indent(12),"{TmpDec,_ ,_} ->",nl]),
- emit([indent(15),"{TmpDec, TmpRest, TmpRbCho}",nl]),
- emit([indent(9),"end",nl,indent(6),"end",nl]),
- [];
-gen_dec_call({typefield,_},_Erules,_,Cname,Type,_BytesVar,Tag,_,_,
- _DecObjInf,OptOrMandComp) ->
- emit(["?RT_BER:decode_open_type(",{curr,bytes},",",{asis,Tag},")"]),
- RefedFieldName =
- (Type#type.def)#'ObjectClassFieldType'.fieldname,
-% asn1ct_gen:get_constraint(Type#type.constraint,
-% tableconstraint_info),
- [{Cname,RefedFieldName,
- asn1ct_gen:mk_var(asn1ct_name:curr(term)),
-% asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),[],OptOrMandComp}];
- asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),Tag,OptOrMandComp}];
-gen_dec_call({objectfield,PrimFieldName,PFNList},_Erules,_,Cname,_,_,Tag,_,_,_,
- OptOrMandComp) ->
- emit(["?RT_BER:decode_open_type(",{curr,bytes},",",{asis,Tag},")"]),
- [{Cname,{PrimFieldName,PFNList},
- asn1ct_gen:mk_var(asn1ct_name:curr(term)),
-% asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),[],OptOrMandComp}];
- asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),Tag,OptOrMandComp}];
-gen_dec_call(InnerType,Erules,TopType,Cname,Type,BytesVar,Tag,PrimOptOrMand,
- OptOrMand,DecObjInf,_) ->
- WhatKind = asn1ct_gen:type(InnerType),
- gen_dec_call1(WhatKind,InnerType,Erules,TopType,Cname,Type,BytesVar,Tag,
- PrimOptOrMand,OptOrMand),
- case DecObjInf of
- {Cname,{_,OSet,UniqueFName,ValIndex}} ->
- Term = asn1ct_gen:mk_var(asn1ct_name:curr(term)),
- ValueMatch = value_match(ValIndex,Term),
- {ObjSetMod,ObjSetName} =
- case OSet of
- {M,O} ->
- {{asis,M},O};
- _ ->
- {"?MODULE",OSet}
- end,
- emit({",",nl,"ObjFun = ",ObjSetMod,":'getdec_",ObjSetName,"'(",
- {asis,UniqueFName},", ",ValueMatch,")"});
- _ ->
- ok
- end,
- [].
-gen_dec_call1({primitive,bif},InnerType,Erules,_,_,Type,BytesVar,
- Tag,OptOrMand,_) ->
- case InnerType of
- {fixedtypevaluefield,_,Btype} ->
- asn1ct_gen_ber:gen_dec_prim(Erules,Btype,BytesVar,Tag,[],no_length,
- ?PRIMITIVE,OptOrMand);
- _ ->
- asn1ct_gen_ber:gen_dec_prim(Erules,Type,BytesVar,Tag,[],no_length,
- ?PRIMITIVE,OptOrMand)
- end;
-gen_dec_call1('ASN1_OPEN_TYPE',_InnerType,Erules,_,_,Type,BytesVar,
- Tag,OptOrMand,_) ->
- asn1ct_gen_ber:gen_dec_prim(Erules,Type#type{def='ASN1_OPEN_TYPE'},
- BytesVar,Tag,[],no_length,
- ?PRIMITIVE,OptOrMand);
-gen_dec_call1(WhatKind,_,_Erules,TopType,Cname,Type,_,Tag,_,OptOrMand) ->
- {DecFunName,_,_} =
- mkfuncname(TopType,Cname,WhatKind,dec),
- case {WhatKind,Type#type.tablecinf} of
- {{constructed,bif},[{objfun,_}|_R]} ->
- emit({DecFunName,"(",{curr,bytes},OptOrMand,{asis,Tag},", ObjFun)"});
- _ ->
- emit({DecFunName,"(",{curr,bytes},OptOrMand,{asis,Tag},")"})
- end.
-
-
-%%------------------------------------------------------
-%% General and special help functions (not exported)
-%%------------------------------------------------------
-
-
-indent(N) ->
- lists:duplicate(N,32). % 32 = space
-
-
-mkvlist([H,T1|T], Sep) -> % Sep is a string e.g ", " or "+ "
- emit([{var,H},Sep]),
- mkvlist([T1|T], Sep);
-mkvlist([H|T], Sep) ->
- emit([{var,H}]),
- mkvlist(T, Sep);
-mkvlist([], _) ->
- true.
-
-mkvlist(L) ->
- mkvlist(L,", ").
-
-mkvplus(L) ->
- mkvlist(L," + ").
-
-extensible(CompList) when is_list(CompList) ->
- noext;
-extensible({RootList,ExtList}) ->
- {ext,length(RootList)+1,length(ExtList)};
-extensible({_Rl1,_ExtL,_Rl2}) ->
- extensible.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% filter away ExtensionAdditionGroup start and end marks since these
-%% have no significance for the BER encoding
-%%
-filter_complist(CompList) when is_list(CompList) ->
- lists:filter(fun(#'ExtensionAdditionGroup'{}) ->
- false;
- ('ExtensionAdditionGroupEnd') ->
- false;
- (_) ->
- true
- end, CompList);
-filter_complist({Root,Ext}) ->
- {Root,filter_complist(Ext)};
-filter_complist({Root1,Ext,Root2}) ->
- {Root1,filter_complist(Ext),Root2}.
-
-print_attribute_comment(InnerType,Pos,Prop) ->
- CommentLine = "%%-------------------------------------------------",
- emit([nl,CommentLine]),
- case InnerType of
- {typereference,_,Name} ->
- emit([nl,"%% attribute number ",Pos," with type ",Name]);
- {'Externaltypereference',_,XModule,Name} ->
- emit([nl,"%% attribute number ",Pos," External ",XModule,":",Name]);
- _ ->
- emit([nl,"%% attribute number ",Pos," with type ",InnerType])
- end,
- case Prop of
- mandatory ->
- continue;
- {'DEFAULT', Def} ->
- emit([" DEFAULT = ",{asis,Def}]);
- 'OPTIONAL' ->
- emit([" OPTIONAL"])
- end,
- emit([nl,CommentLine,nl]).
-
-
-mkfuncname(TopType,Cname,WhatKind,DecOrEnc) ->
- CurrMod = get(currmod),
- case WhatKind of
- #'Externaltypereference'{module=CurrMod,type=EType} ->
- F = lists:concat(["'",DecOrEnc,"_",EType,"'"]),
- {F, "?MODULE", F};
- #'Externaltypereference'{module=Mod,type=EType} ->
- {lists:concat(["'",Mod,"':'",DecOrEnc,"_",EType,"'"]),Mod,
- lists:concat(["'",DecOrEnc,"_",EType,"'"])};
- {constructed,bif} ->
- F = lists:concat(["'",DecOrEnc,"_",asn1ct_gen:list2name([Cname|TopType]),"'"]),
- {F, "?MODULE", F}
- end.
-
-mkfunname(Erule,TopType,Cname,WhatKind,DecOrEnc,Arity) ->
- CurrMod = get(currmod),
- case WhatKind of
- #'Externaltypereference'{module=CurrMod,type=EType} ->
- F = lists:concat(["fun '",DecOrEnc,"_",EType,"'/",Arity]),
- {F, "?MODULE", F};
- #'Externaltypereference'{module=Mod,type=EType} ->
- {lists:concat(["fun '",Mod,"':'",DecOrEnc,"_",EType,"'/",Arity]),Mod,
- lists:concat(["'",DecOrEnc,"_",EType,"'"])};
- {constructed,bif} ->
- F =
- lists:concat(["fun '",DecOrEnc,"_",
- asn1ct_gen:list2name([Cname|TopType]),"'/",
- Arity]),
- {F, "?MODULE", F};
- 'ASN1_OPEN_TYPE' ->
- case Arity of
- 3 ->
- F = lists:concat(["fun(A,_,C) -> ?RT_BER:decode_open_type(",Erule,",A,C) end"]),
- {F, "?MODULE", F};
- 4 ->
- F = lists:concat(["fun(A,_,C,_) -> ?RT_BER:decode_open_type(",Erule,",A,C) end"]),
- {F, "?MODULE", F}
- end
- end.
-
-empty_lb(ber) ->
- "[]";
-empty_lb(ber_bin) ->
- "<<>>".
-
-rtmod(ber) ->
- list_to_atom(?RT_BER_BIN);
-rtmod(ber_bin) ->
- list_to_atom(?RT_BER_BIN).
-
-indefend_match(ber,used_var) ->
- "[0,0|R]";
-indefend_match(ber,unused_var) ->
- "[0,0|_R]";
-indefend_match(ber_bin,used_var) ->
- "<<0,0,R/binary>>";
-indefend_match(ber_bin,unused_var) ->
- "<<0,0,_R/binary>>".
-
-notice_value_match() ->
- Module = get(currmod),
- put(value_match,{true,Module}).
-
-value_match(Index,Value) when is_atom(Value) ->
- value_match(Index,atom_to_list(Value));
-value_match([],Value) ->
- Value;
-value_match([{VI,_Cname}|VIs],Value) ->
- value_match1(Value,VIs,lists:concat(["element(",VI,","]),1).
-value_match1(Value,[],Acc,Depth) ->
- Acc ++ Value ++ lists:concat(lists:duplicate(Depth,")"));
-value_match1(Value,[{VI,_Cname}|VIs],Acc,Depth) ->
- value_match1(Value,VIs,Acc++lists:concat(["element(",VI,","]),Depth+1).
diff --git a/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl b/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl
index 2c4b44996d..78cb9297d8 100644
--- a/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl
+++ b/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl
@@ -32,7 +32,6 @@
-include("asn1_records.hrl").
-import(asn1ct_gen, [emit/1,demit/1,get_record_name_prefix/0]).
--import(asn1ct_constructed_ber,[match_tag/2]).
-define(ASN1CT_GEN_BER,asn1ct_gen_ber_bin_v2).
@@ -913,7 +912,7 @@ gen_dec_choice_cases(Erules,TopType, [H|T]) ->
[DecTag],Type}),
asn1ct:update_gen_state(namelist,Names),
emit([indent(4),{curr,res}," = ",
- match_tag(ber_bin,{FirstT#tag.class,FirstT#tag.number}),
+ match_tag(FirstT#tag.class, FirstT#tag.number),
" -> ",nl]),
emit([indent(8),"{",{asis,Cname},", {'",
asn1ct_gen:list2name([Cname|TopType]),"',",
@@ -928,7 +927,25 @@ gen_dec_choice_cases(Erules,TopType, [H|T]) ->
end,
gen_dec_choice_cases(Erules,TopType, T).
+match_tag(Class, TagNo) when is_integer(TagNo) ->
+ match_tag1(asn1ct_gen_ber_bin_v2:decode_class(Class), TagNo).
+match_tag1(Class, TagNo) when TagNo =< 30 ->
+ io_lib:format("<<~p:2,_:1,~p:5,_/binary>>", [Class bsr 6,TagNo]);
+match_tag1(Class, TagNo) ->
+ Octets = mk_object_val(TagNo),
+ io_lib:format("<<~p:2,_:1,31:5,~s,_/binary>>", [Class bsr 6,Octets]).
+
+mk_object_val(Val) when Val < 16#80 ->
+ integer_to_list(Val);
+mk_object_val(Val) ->
+ mk_object_val(Val bsr 7, [integer_to_list(Val band 16#7F)]).
+
+mk_object_val(0, Acc) ->
+ Acc;
+mk_object_val(Val, Acc) ->
+ I = integer_to_list((Val band 16#7F) bor 16#80),
+ mk_object_val(Val bsr 7, [I,","|Acc]).
%%---------------------------------------
%% Generate the encode/decode code
@@ -1493,10 +1510,6 @@ mkfuncname(TopType,Cname,WhatKind,Prefix,Suffix) ->
end.
empty_lb(ber) ->
- "[]";
-empty_lb(ber_bin) ->
- "<<>>";
-empty_lb(ber_bin_v2) ->
"<<>>".
value_match(Index,Value) when is_atom(Value) ->
diff --git a/lib/asn1/src/asn1ct_constructed_per.erl b/lib/asn1/src/asn1ct_constructed_per.erl
index 8de41a4dd4..27070be966 100644
--- a/lib/asn1/src/asn1ct_constructed_per.erl
+++ b/lib/asn1/src/asn1ct_constructed_per.erl
@@ -76,13 +76,9 @@ gen_encode_constructed(Erule,Typename,D) when is_record(D,type) ->
case {Optionals = optionals(to_textual_order(CompList)),CompList,
is_optimized(Erule)} of
{[],EmptyCL,_} when EmptyCL == {[],[],[]};EmptyCL == {[],[]};EmptyCL == [] ->
- emit(["%%Variable setting just to eliminate ",
- "compiler warning for unused vars!",nl,
- "_Val = ",{curr,val},",",nl]);
+ ok;
{[],_,_} ->
- emit([{next,val}," = ?RT_PER:list_to_record("]),
- emit(["'",asn1ct_gen:list2rname(Typename),"'"]),
- emit([", ",{curr,val},"),",nl]);
+ emit([{next,val}," = ",{curr,val},",",nl]);
{_,_,true} ->
gen_fixoptionals(Optionals),
FixOpts = param_map(fun(Var) ->
@@ -112,7 +108,10 @@ gen_encode_constructed(Erule,Typename,D) when is_record(D,type) ->
emit([
{next,val}," = case [X || X <- [",Elements,
"],X =/= asn1_NOVALUE] of",nl,
- "[] -> ",{curr,val},";",nl,
+ "[] -> setelement(",
+ {asis,ExtActualGroupPos+1},",",
+ {curr,val},",",
+ "asn1_NOVALUE);",nl,
"_ -> setelement(",{asis,ExtActualGroupPos+1},",",
{curr,val},",",
"{extaddgroup,", Elements,"})",nl,
@@ -155,7 +154,7 @@ gen_encode_constructed(Erule,Typename,D) when is_record(D,type) ->
emit([ObjectEncode," = ",nl]),
emit([" ",ObjSetMod,":'getenc_",ObjSetName,"'(",
{asis,UniqueFieldName},", ",nl]),
- El = make_element(N+1,asn1ct_gen:mk_var(asn1ct_name:curr(val)),AttrN),
+ El = make_element(N+1,asn1ct_gen:mk_var(asn1ct_name:curr(val))),
Length = fun(X,_LFun) when is_atom(X) ->
length(atom_to_list(X));
@@ -221,9 +220,74 @@ gen_decode_set(Erules,Typename,D) ->
gen_decode_sequence(Erules,Typename,D) ->
gen_decode_constructed(Erules,Typename,D).
-gen_decode_constructed(Erules,Typename,D) when is_record(D,type) ->
+gen_decode_constructed(Erule, Typename, #type{}=D) ->
+ Imm0 = gen_dec_constructed_imm(Erule, Typename, #type{}=D),
+ Imm = opt_imm(Imm0),
asn1ct_name:start(),
asn1ct_name:clear(),
+ emit_gen_dec_imm(Imm),
+ emit([".",nl,nl]).
+
+opt_imm(Imm0) ->
+ {Imm,_} = opt_imm_1(Imm0, unknown, []),
+ Imm.
+
+opt_imm_1([{imm,Imm0,F}|T], Al0, Acc) ->
+ {Imm,Al} = asn1ct_imm:optimize_alignment(Imm0, Al0),
+ opt_imm_1(T, Al, [{imm,Imm,F}|Acc]);
+opt_imm_1([ignore|T], Al, Acc) ->
+ opt_imm_1(T, Al, Acc);
+opt_imm_1([{ignore,_}=H|T], Al, Acc) ->
+ opt_imm_1(T, Al, [H|Acc]);
+opt_imm_1([{safe,ignore}|T], Al, Acc) ->
+ opt_imm_1(T, Al, Acc);
+opt_imm_1([{safe,_}=H|T], Al, Acc) ->
+ opt_imm_1(T, Al, [H|Acc]);
+opt_imm_1([{group,G0}|T], Al0, Acc) ->
+ {G,Al} = opt_imm_1(G0, Al0, []),
+ opt_imm_1(T, Al, [{group,G}|Acc]);
+opt_imm_1([Emit|T], _, Acc) when is_function(Emit, 1) ->
+ opt_imm_1(T, unknown, [Emit|Acc]);
+opt_imm_1([], Al, Acc) ->
+ {lists:reverse(Acc),Al}.
+
+emit_gen_dec_imm(L) ->
+ emit_gen_dec_imm(L, "", []).
+
+emit_gen_dec_imm([{ignore,Fun}|T], Sep, St0) ->
+ St = Fun(St0),
+ emit_gen_dec_imm(T, Sep, St);
+emit_gen_dec_imm([{group,L}|T], Sep, St0) ->
+ emit(Sep),
+ St = emit_gen_dec_imm_group(L, St0),
+ emit_gen_dec_imm(T, [com,nl], St);
+emit_gen_dec_imm([{imm,Imm,Emit}|T], Sep, St0) ->
+ emit(Sep),
+ St = Emit(Imm, St0),
+ emit_gen_dec_imm(T, [com,nl], St);
+emit_gen_dec_imm([{safe,Item}|T], Sep, St) ->
+ emit_gen_dec_imm([Item|T], Sep, St);
+emit_gen_dec_imm([Emit|T], Sep, St0) ->
+ emit(Sep),
+ St = Emit(St0),
+ emit_gen_dec_imm(T, [com,nl], St);
+emit_gen_dec_imm([], _, _) -> ok.
+
+emit_gen_dec_imm_group([H|T], St0) ->
+ St = emit_gen_dec_group_item(H, St0),
+ emit_gen_dec_imm_group(T, St);
+emit_gen_dec_imm_group([], St) -> St.
+
+emit_gen_dec_group_item({ignore,Fun}, St) ->
+ Fun(St);
+emit_gen_dec_group_item({imm,Imm,Fun}, St) ->
+ Fun(Imm, St);
+emit_gen_dec_group_item({safe,Item}, St) ->
+ emit_gen_dec_group_item(Item, St);
+emit_gen_dec_group_item(Emit, St) ->
+ Emit(St).
+
+gen_dec_constructed_imm(Erule, Typename, #type{}=D) ->
{CompList,TableConsInfo} =
case D#type.def of
#'SEQUENCE'{tablecinf=TCI,components=CL} ->
@@ -233,27 +297,19 @@ gen_decode_constructed(Erules,Typename,D) when is_record(D,type) ->
{CL,TCI} % the textual order is already taken care of
end,
Ext = extensible_dec(CompList),
- MaybeComma1 = case Ext of
- {ext,_Pos,_NumExt} ->
- gen_dec_extension_value("Bytes"),
- {",",nl};
- _ ->
- ""
- end,
+ EmitExt = case Ext of
+ {ext,_Pos,_NumExt} ->
+ gen_dec_extension_value();
+ _ -> ignore
+ end,
Optionals = optionals(CompList),
- MaybeComma2 = case Optionals of
- [] -> MaybeComma1;
- _ ->
- Bcurr = asn1ct_name:curr(bytes),
- Bnext = asn1ct_name:next(bytes),
- emit(MaybeComma1),
- GetoptCall = "} = ?RT_PER:getoptionals2(",
- emit({"{Opt,",{var,Bnext},GetoptCall,
- {var,Bcurr},",",{asis,length(Optionals)},")"}),
- asn1ct_name:new(bytes),
- ", "
- end,
- {DecObjInf,UniqueFName,ValueIndex} =
+ EmitOpt = case Optionals of
+ [] ->
+ ignore;
+ [_|_] ->
+ gen_dec_optionals(Optionals)
+ end,
+ ObjSetInfo =
case TableConsInfo of
%% {ObjectSet,AttrN,N,UniqueFieldName} ->%% N is index of attribute that determines constraint
#simpletableattributes{objectsetname=ObjectSet,
@@ -285,13 +341,19 @@ gen_decode_constructed(Erules,Typename,D) when is_record(D,type) ->
{false,false,false}
end
end,
-%% NewCompList = wrap_compList(CompList),
- {AccTerm,AccBytes} =
- gen_dec_components_call(Erules,Typename,CompList,MaybeComma2,DecObjInf,Ext,length(Optionals)),
- case asn1ct_name:all(term) of
- [] -> emit(MaybeComma2); % no components at all
- _ -> emit({com,nl})
- end,
+ {DecObjInf,_,_} = ObjSetInfo,
+ EmitComp = gen_dec_components_call(Erule, Typename, CompList,
+ DecObjInf, Ext, length(Optionals)),
+ EmitRest = fun({AccTerm,AccBytes}) ->
+ gen_dec_constructed_imm_2(Typename, CompList,
+ ObjSetInfo,
+ AccTerm, AccBytes)
+ end,
+ [EmitExt,EmitOpt|EmitComp++[{safe,EmitRest}]].
+
+gen_dec_constructed_imm_2(Typename, CompList,
+ ObjSetInfo, AccTerm, AccBytes) ->
+ {_,UniqueFName,ValueIndex} = ObjSetInfo,
case {AccTerm,AccBytes} of
{[],[]} ->
ok;
@@ -333,8 +395,7 @@ gen_decode_constructed(Erules,Typename,D) when is_record(D,type) ->
mkvlist(textual_order(to_encoding_order(CompList),asn1ct_name:all(term))),
emit("},")
end,
- emit({{curr,bytes},"}"}),
- emit({".",nl,nl}).
+ emit({{curr,bytes},"}"}).
textual_order([#'ComponentType'{textual_order=undefined}|_],TermList) ->
TermList;
@@ -516,10 +577,10 @@ gen_decode_sof(Erules,Typename,SeqOrSetOf,D) when is_record(D,type) ->
_ ->
""
end,
- gen_decode_length(SizeConstraint,
- is_optimized(Erules)),
- emit({"'dec_",asn1ct_gen:list2name(Typename),
- "_components'(Num, Bytes1, telltype",ObjFun,", []).",nl}),
+ {Num,Buf} = gen_decode_length(SizeConstraint, Erules),
+ emit([",",nl,
+ "'dec_",asn1ct_gen:list2name(Typename),
+ "_components'(",Num,", ",Buf,ObjFun,", []).",nl,nl]),
NewComponentType =
case ComponentType#type.def of
{'ENUMERATED',_,Component}->
@@ -528,40 +589,13 @@ gen_decode_sof(Erules,Typename,SeqOrSetOf,D) when is_record(D,type) ->
end,
gen_decode_sof_components(Erules,Typename,SeqOrSetOf,NewComponentType).
-%% Logic copied from asn1_per_bin_rt2ct:decode_constrained_number
-gen_decode_length({Lb,Ub},true) when Ub =< 65535, Lb >= 0 ->
- Range = Ub - Lb + 1,
- Call = if
- Range == 1 ->
- "{0,Bytes}";
- Range == 2 ->
- "?RT_PER:getbits(Bytes,1)";
- Range =< 4 ->
- "?RT_PER:getbits(Bytes,2)";
- Range =< 8 ->
- "?RT_PER:getbits(Bytes,3)";
- Range =< 16 ->
- "?RT_PER:getbits(Bytes,4)";
- Range =< 32 ->
- "?RT_PER:getbits(Bytes,5)";
- Range =< 64 ->
- "?RT_PER:getbits(Bytes,6)";
- Range =< 128 ->
- "?RT_PER:getbits(Bytes,7)";
- Range =< 255 ->
- "?RT_PER:getbits(Bytes,8)";
- Range =< 256 ->
- "?RT_PER:getoctets(Bytes,1)";
- Range =< 65536 ->
- "?RT_PER:getoctets(Bytes,2)";
- true ->
- ["exit({not_supported,{integer_range,",Range,"}}"]
- end,
- emit({nl,"{Val,Remain} = ",Call,",",nl}),
- emit({nl,"{Num,Bytes1} = {Val+",Lb,",Remain},",nl});
-gen_decode_length(SizeConstraint,_) ->
- emit({nl,"{Num,Bytes1} = ?RT_PER:decode_length(Bytes,",
- {asis,SizeConstraint},"),",nl}).
+is_aligned(per) -> true;
+is_aligned(uper) -> false.
+
+gen_decode_length(Constraint, Erule) ->
+ emit(["%% Length with constraint ",{asis,Constraint},nl]),
+ Imm = asn1ct_imm:per_dec_length(Constraint, true, is_aligned(Erule)),
+ asn1ct_imm:dec_slim_cg(Imm, "Bytes").
gen_encode_sof_components(Erule,Typename,SeqOrSetOf,Cont) ->
{ObjFun,ObjFun_Var} =
@@ -583,8 +617,7 @@ gen_encode_sof_components(Erule,Typename,SeqOrSetOf,Cont) ->
Conttype = asn1ct_gen:get_inner(Cont#type.def),
Currmod = get(currmod),
- Ctgenmod = list_to_atom(lists:concat(["asn1ct_gen_",per,
- asn1ct_gen:rt2ct_suffix()])),
+ Ctgenmod = asn1ct_gen:ct_gen_module(Erule),
case asn1ct_gen:type(Conttype) of
{primitive,bif} ->
gen_encode_prim_wrapper(Ctgenmod,Erule,Cont,false,"H");
@@ -614,16 +647,15 @@ gen_decode_sof_components(Erule,Typename,SeqOrSetOf,Cont) ->
{"",""}
end,
emit({"'dec_",asn1ct_gen:list2name(Typename),
- "_components'(0, Bytes, _",ObjFun_Var,", Acc) ->",nl,
+ "_components'(0, Bytes",ObjFun_Var,", Acc) ->",nl,
indent(3),"{lists:reverse(Acc), Bytes};",nl}),
emit({"'dec_",asn1ct_gen:list2name(Typename),
- "_components'(Num, Bytes, _",ObjFun,", Acc) ->",nl}),
+ "_components'(Num, Bytes",ObjFun,", Acc) ->",nl}),
emit({indent(3),"{Term,Remain} = "}),
Constructed_Suffix = asn1ct_gen:constructed_suffix(SeqOrSetOf,
Cont#type.def),
Conttype = asn1ct_gen:get_inner(Cont#type.def),
- Ctgenmod = list_to_atom(lists:concat(["asn1ct_gen_",per,
- asn1ct_gen:rt2ct_suffix()])),
+ Ctgenmod = asn1ct_gen:ct_gen_module(Erule),
CurrMod = get(currmod),
case asn1ct_gen:type(Conttype) of
{primitive,bif} ->
@@ -647,7 +679,7 @@ gen_decode_sof_components(Erule,Typename,SeqOrSetOf,Cont) ->
emit({"'dec_",Conttype,"'(Bytes,telltype),",nl})
end,
emit({indent(3),"'dec_",asn1ct_gen:list2name(Typename),
- "_components'(Num-1, Remain, telltype",ObjFun,", [Term|Acc]).",nl}).
+ "_components'(Num-1, Remain",ObjFun,", [Term|Acc]).",nl}).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -718,10 +750,25 @@ extgrouppos([_|T],ActualPos,VirtualPos,Len,Acc) ->
extgrouppos(T,ActualPos,VirtualPos,Len+1,Acc).
-
-gen_dec_extension_value(_) ->
- emit({"{Ext,",{next,bytes},"} = ?RT_PER:getext(",{curr,bytes},")"}),
- asn1ct_name:new(bytes).
+gen_dec_extension_value() ->
+ Imm0 = {get_bits,1,[1]},
+ E = fun(Imm, _) ->
+ emit(["{Ext,",{next,bytes},"} = "]),
+ BytesVar = asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
+ asn1ct_imm:dec_code_gen(Imm, BytesVar),
+ asn1ct_name:new(bytes)
+ end,
+ {imm,Imm0,E}.
+
+gen_dec_optionals(Optionals) ->
+ Imm0 = {get_bits,length(Optionals),[1]},
+ E = fun(Imm, _) ->
+ BytesVar = asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
+ emit(["{Opt,",{next,bytes},"} = "]),
+ asn1ct_imm:dec_code_gen(Imm, BytesVar),
+ asn1ct_name:new(bytes)
+ end,
+ {imm,Imm0,E}.
gen_fixoptionals([{Pos,Def}|R]) ->
asn1ct_name:new(fixopt),
@@ -889,7 +936,7 @@ gen_enc_components_call1(_Erule,_TopType,[],Pos,_,_,_) ->
Pos.
gen_enc_component_default(Erule,TopType,Cname,Type,Pos,DynamicEnc,Ext,DefaultVal) ->
- Element = make_element(Pos+1,asn1ct_gen:mk_var(asn1ct_name:curr(val)),Cname),
+ Element = make_element(Pos+1,asn1ct_gen:mk_var(asn1ct_name:curr(val))),
emit({"case ",Element," of",nl}),
% emit({"asn1_DEFAULT -> [];",nl}),
emit({"DFLT when DFLT == asn1_DEFAULT; DFLT == ",{asis,DefaultVal}," -> [];",nl}),
@@ -909,7 +956,7 @@ gen_enc_component_optional(Erule,TopType,Cname,
components=_ExtGroupCompList}},
Pos,DynamicEnc,Ext) when is_integer(Number) ->
- Element = make_element(Pos+1,asn1ct_gen:mk_var(asn1ct_name:curr(val)),Cname),
+ Element = make_element(Pos+1,asn1ct_gen:mk_var(asn1ct_name:curr(val))),
emit({"case ",Element," of",nl}),
emit({"asn1_NOVALUE -> [];",nl}),
@@ -922,7 +969,7 @@ gen_enc_component_optional(Erule,TopType,Cname,
gen_enc_line(Erule,TopType,Cname,Type,NextElement, Pos,DynamicEnc,Ext),
emit({nl,"end"});
gen_enc_component_optional(Erule,TopType,Cname,Type,Pos,DynamicEnc,Ext) ->
- Element = make_element(Pos+1,asn1ct_gen:mk_var(asn1ct_name:curr(val)),Cname),
+ Element = make_element(Pos+1,asn1ct_gen:mk_var(asn1ct_name:curr(val))),
emit({"case ",Element," of",nl}),
emit({"asn1_NOVALUE -> [];",nl}),
@@ -942,11 +989,10 @@ gen_enc_component_mandatory(Erule,TopType,Cname,Type,Pos,DynamicEnc,Ext) ->
gen_enc_line(Erule,TopType,Cname,Type,[],Pos,DynamicEnc,Ext).
gen_enc_line(Erule,TopType, Cname, Type, [], Pos,DynamicEnc,Ext) ->
- Element = make_element(Pos+1,asn1ct_gen:mk_var(asn1ct_name:curr(val)),Cname),
+ Element = make_element(Pos+1,asn1ct_gen:mk_var(asn1ct_name:curr(val))),
gen_enc_line(Erule,TopType,Cname,Type,Element, Pos,DynamicEnc,Ext);
gen_enc_line(Erule,TopType,Cname,Type,Element, _Pos,DynamicEnc,Ext) ->
- Ctgenmod = list_to_atom(lists:concat(["asn1ct_gen_",per,
- asn1ct_gen:rt2ct_suffix()])),
+ Ctgenmod = asn1ct_gen:ct_gen_module(Erule),
Atype =
case Type of
#type{def=#'ObjectClassFieldType'{type=InnerType}} ->
@@ -1036,53 +1082,80 @@ gen_enc_line(Erule,TopType,Cname,Type,Element, _Pos,DynamicEnc,Ext) ->
emit("))");
_ -> true
end.
-gen_dec_components_call(Erule,TopType,{Root,ExtList},MaybeComma,
+
+gen_dec_components_call(Erule, TopType, {Root,ExtList},
+ DecInfObj, Ext, NumberOfOptionals) ->
+ gen_dec_components_call(Erule,TopType,{Root,ExtList,[]},
+ DecInfObj,Ext,NumberOfOptionals);
+gen_dec_components_call(Erule,TopType,CL={Root1,ExtList,Root2},
DecInfObj,Ext,NumberOfOptionals) ->
- gen_dec_components_call(Erule,TopType,{Root,ExtList,[]},MaybeComma,DecInfObj,Ext,NumberOfOptionals);
-gen_dec_components_call(Erule,TopType,CL={Root1,ExtList,Root2},MaybeComma,DecInfObj,Ext,NumberOfOptionals) ->
%% The type has extensionmarker
-
OptTable = create_optionality_table(Root1++Root2),
- {Rpos,AccTerm,AccBytes} =
- gen_dec_components_call1(Erule,TopType, Root1++Root2, 1, OptTable,
- MaybeComma,DecInfObj,noext,[],[],
- NumberOfOptionals),
- emit([",",nl,"{Extensions,",{next,bytes},"} = "]),
- emit(["?RT_PER:getextension(Ext,",{curr,bytes},"),",nl]),
- asn1ct_name:new(bytes),
+ Init = {ignore,fun(_) -> {[],[]} end},
+ {EmitRoot,Tpos} =
+ gen_dec_comp_calls(Root1++Root2, Erule, TopType, OptTable,
+ DecInfObj, noext, NumberOfOptionals,
+ 1, []),
+ EmitGetExt = gen_dec_get_extension(Erule),
{extgrouppos,ExtGroupPosLen} = extgroup_pos_and_length(CL),
- NewExtList = wrap_extensionAdditionGroups(ExtList,ExtGroupPosLen),
- {_Epos,AccTermE,AccBytesE} =
- gen_dec_components_call1(Erule,TopType,NewExtList,Rpos, OptTable,
- "",DecInfObj,Ext,[],[],NumberOfOptionals),
- case ExtList of
- [] -> true;
- _ -> emit([",",nl])
- end,
- emit([{next,bytes},"= ?RT_PER:skipextensions(",{curr,bytes},",",
- length(ExtList)+1,",Extensions)",nl]),
- asn1ct_name:new(bytes),
- {AccTerm++AccTermE,AccBytes++AccBytesE};
-
-gen_dec_components_call(Erule,TopType,CompList,MaybeComma,DecInfObj,
- Ext,NumberOfOptionals) ->
+ NewExtList = wrap_extensionAdditionGroups(ExtList, ExtGroupPosLen),
+ {EmitExts,_} = gen_dec_comp_calls(NewExtList, Erule, TopType, OptTable,
+ DecInfObj, Ext, NumberOfOptionals,
+ Tpos, []),
+ NumExtsToSkip = ext_length(ExtList),
+ Finish =
+ fun(St) ->
+ emit([{next,bytes},"= ?RT_PER:skipextensions(",{curr,bytes},",",
+ NumExtsToSkip+1,",Extensions)"]),
+ asn1ct_name:new(bytes),
+ St
+ end,
+ [Init] ++ EmitRoot ++ [EmitGetExt|EmitExts] ++ [Finish];
+gen_dec_components_call(Erule, TopType, CompList, DecInfObj,
+ Ext, NumberOfOptionals) ->
%% The type has no extensionmarker
OptTable = create_optionality_table(CompList),
- {_,AccTerm,AccBytes} =
- gen_dec_components_call1(Erule,TopType, CompList, 1, OptTable,
- MaybeComma,DecInfObj,Ext,[],[],
- NumberOfOptionals),
- {AccTerm,AccBytes}.
-
-
-gen_dec_components_call1(Erule,TopType,
- [C=#'ComponentType'{name=Cname,typespec=Type,prop=Prop,textual_order=TextPos}|Rest],
- Tpos,OptTable,MaybeComma,DecInfObj,Ext,AccTerm,AccBytes,NumberOfOptionals) ->
+ Init = {ignore,fun(_) -> {[],[]} end},
+ {Cs,_} = gen_dec_comp_calls(CompList, Erule, TopType, OptTable,
+ DecInfObj, Ext, NumberOfOptionals,
+ 1, []),
+ [Init|Cs].
+
+gen_dec_get_extension(Erule) ->
+ Imm0 = asn1ct_imm:per_dec_extension_map(is_aligned(Erule)),
+ E = fun(Imm, St) ->
+ emit([nl,"%% Extensions",
+ nl,
+ "{Extensions,",{next,bytes},"} = ",
+ "case Ext of",nl,
+ "0 -> {<<>>,",{curr,bytes},"};",nl,
+ "1 ->",nl]),
+ BytesVar = asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
+ {Dst,DstBuf} = asn1ct_imm:dec_slim_cg(Imm, BytesVar),
+ emit([com,nl,
+ "{",Dst,",",DstBuf,"}",nl,
+ "end"]),
+ asn1ct_name:new(bytes),
+ St
+ end,
+ {imm,Imm0,E}.
+
+gen_dec_comp_calls([C|Cs], Erule, TopType, OptTable, DecInfObj,
+ Ext, NumberOfOptionals, Tpos, Acc) ->
+ L = gen_dec_comp_call(C, Erule, TopType, Tpos, OptTable, DecInfObj,
+ Ext, NumberOfOptionals),
+ gen_dec_comp_calls(Cs, Erule, TopType, OptTable, DecInfObj,
+ Ext, NumberOfOptionals, Tpos+1, [L|Acc]);
+gen_dec_comp_calls([], _, _, _, _, _, _, Tpos, Acc) ->
+ {lists:append(lists:reverse(Acc)),Tpos}.
+
+gen_dec_comp_call(Comp, Erule, TopType, Tpos, OptTable, DecInfObj,
+ Ext, NumberOfOptionals) ->
+ #'ComponentType'{typespec=Type,prop=Prop,textual_order=TextPos} = Comp,
Pos = case Ext of
noext -> Tpos;
{ext,Epos,_Enum} -> Tpos - Epos + 1
end,
- emit(MaybeComma),
InnerType =
case Type#type.def of
#'ObjectClassFieldType'{type=InType} ->
@@ -1091,109 +1164,128 @@ gen_dec_components_call1(Erule,TopType,
asn1ct_gen:get_inner(Def)
end,
- case InnerType of
- #'Externaltypereference'{type=T} ->
- emit({nl,"%% attribute number ",TextPos," with type ",
- T,nl});
- IT when is_tuple(IT) ->
- emit({nl,"%% attribute number ",TextPos," with type ",
- element(2,IT),nl});
- _ ->
- emit({nl,"%% attribute number ",TextPos," with type ",
- InnerType,nl})
- end,
-
- IsMandatoryAndPredefinedTableC =
- fun(noext,mandatory,{"got objfun through args","ObjFun"}) ->
- true;
- (_,_,{"got objfun through args","ObjFun"}) ->
- false;
- (_,_,_) ->
- true
- end,
- case {InnerType,IsMandatoryAndPredefinedTableC(Ext,Prop,DecInfObj)} of
-%% {typefield,_} when Ext == noext, Prop == mandatory ->
- {{typefield,_},true} ->
- %% DecInfObj /= {"got objfun through args","ObjFun"} |
- %% (DecInfObj == {"got objfun through args","ObjFun"} &
- %% Ext == noext & Prop == mandatory)
- asn1ct_name:new(term),
- asn1ct_name:new(tmpterm),
- emit({"{",{curr,tmpterm},", ",{next,bytes},"} = "});
+ DispType = case InnerType of
+ #'Externaltypereference'{type=T} -> T;
+ IT when is_tuple(IT) -> element(2,IT);
+ _ -> InnerType
+ end,
+ Comment = fun(St) ->
+ emit([nl,"%% attribute number ",TextPos,
+ " with type ",DispType,nl]),
+ St
+ end,
+
+ Preamble =
+ case {InnerType,is_mandatory_predef_tab_c(Ext, Prop, DecInfObj)} of
+ {{typefield,_},true} ->
+ %% DecInfObj /= {"got objfun through args","ObjFun"} |
+ %% (DecInfObj == {"got objfun through args","ObjFun"} &
+ %% Ext == noext & Prop == mandatory)
+ fun(St) ->
+ asn1ct_name:new(term),
+ asn1ct_name:new(tmpterm),
+ emit(["{",{curr,tmpterm},", ",{next,bytes},"} = "]),
+ St
+ end;
%%{objectfield,_,_} when Ext == noext, Prop == mandatory ->
- {{objectfield,_,_},true} ->
- asn1ct_name:new(term),
- asn1ct_name:new(tmpterm),
- emit({"{",{curr,tmpterm},", ",{next,bytes},"} = "});
+ {{objectfield,_,_},true} ->
+ fun(St) ->
+ asn1ct_name:new(term),
+ asn1ct_name:new(tmpterm),
+ emit(["{",{curr,tmpterm},", ",{next,bytes},"} = "]),
+ St
+ end;
_ ->
case Type of
#type{def=#'SEQUENCE'{
extaddgroup=Number1,
components=ExtGroupCompList1}} when is_integer(Number1)->
- emit({"{{_,"}),
- emit_extaddgroupTerms(term,ExtGroupCompList1),
- emit({"}"});
- _ ->
- asn1ct_name:new(term),
- emit({"{",{curr,term}})
- end,
- emit({",",{next,bytes},"} = "})
- end,
-
- case {Ext,Prop,is_optimized(Erule)} of
- {noext,mandatory,_} -> ok; % generate nothing
- {noext,_,_} -> %% OPTIONAL or DEFAULT
- OptPos = get_optionality_pos(TextPos,OptTable),
- Element = io_lib:format("Opt band (1 bsl ~w)",[NumberOfOptionals - OptPos]),
- emit(["case ",Element," of",nl]),
- emit([" _Opt",TextPos," when _Opt",TextPos," > 0 ->"]);
- {_,_,false} -> %% extension element, not bitstring
- emit(["case Extensions of",nl]),
- emit([" _ when size(Extensions) >= ",Pos,",element(",Pos,",Extensions) == 1 ->",nl]);
- _ ->
- emit(["case Extensions of",nl]),
- emit([" <<_:",Pos-1,",1:1,_/bitstring>> when bit_size(Extensions) >= ",Pos," ->",nl])
- end,
- put(component_type,{true,C}),
- {TermVar,BytesVar} = gen_dec_line(Erule,TopType,Cname,Type,Tpos,DecInfObj,Ext,Prop),
- erase(component_type),
- case {Ext,Prop} of
- {noext,mandatory} -> true; % generate nothing
- {noext,_} ->
- emit([";",nl,"0 ->"]),
- emit(["{"]),
- gen_dec_component_no_val(Ext,Prop),
- emit({",",{curr,bytes},"}",nl}),
- emit([nl,"end"]);
- _ ->
- emit([";",nl,"_ ->",nl]),
- emit(["{"]),
- case Type of
- #type{def=#'SEQUENCE'{
- extaddgroup=Number2,
- components=ExtGroupCompList2}} when is_integer(Number2)->
- emit({"{extAddGroup,"}),
- gen_dec_extaddGroup_no_val(Ext,ExtGroupCompList2),
- emit({"}"});
+ fun(St) ->
+ emit(["{{_,"]),
+ emit_extaddgroupTerms(term,ExtGroupCompList1),
+ emit(["}"]),
+ emit([",",{next,bytes},"} = "]),
+ St
+ end;
_ ->
- gen_dec_component_no_val(Ext,Prop)
- end,
- emit({",",{curr,bytes},"}",nl}),
- emit([nl,"end"])
- end,
- asn1ct_name:new(bytes),
- case Rest of
- [] ->
- {Tpos+1,AccTerm++TermVar,AccBytes++BytesVar};
- _ ->
- emit({com,nl}),
- gen_dec_components_call1(Erule,TopType,Rest,Tpos+1,OptTable,
- "",DecInfObj,Ext, AccTerm++TermVar,
- AccBytes++BytesVar,NumberOfOptionals)
- end;
+ fun(St) ->
+ asn1ct_name:new(term),
+ emit(["{",{curr,term}]),
+ emit([",",{next,bytes},"} = "]),
+ St
+ end
+ end
+ end,
-gen_dec_components_call1(_,_TopType,[],Pos,_OptTable,_,_,_,AccTerm,AccBytes,_NumberOfOptionals) ->
- {Pos,AccTerm,AccBytes}.
+ OptOrDef =
+ case {Ext,Prop} of
+ {noext,mandatory} ->
+ ignore;
+ {noext,_} -> %% OPTIONAL or DEFAULT
+ OptPos = get_optionality_pos(TextPos, OptTable),
+ Element = io_lib:format("Opt band (1 bsl ~w)",
+ [NumberOfOptionals - OptPos]),
+ fun(St) ->
+ emit(["case ",Element," of",nl]),
+ emit([" _Opt",TextPos," when _Opt",TextPos," > 0 ->"]),
+ St
+ end;
+ {{ext,_,_},_} -> %Extension
+ fun(St) ->
+ emit(["case Extensions of",nl,
+ " <<_:",Pos-1,",1:1,_/bitstring>> ->",nl]),
+ St
+ end
+ end,
+ Lines = gen_dec_line_imm(Erule, TopType, Comp, Tpos, DecInfObj, Ext),
+ Postamble =
+ case {Ext,Prop} of
+ {noext,mandatory} ->
+ ignore;
+ {noext,_} ->
+ fun(St) ->
+ emit([";",nl,"0 ->"]),
+ emit(["{"]),
+ gen_dec_component_no_val(Ext,Prop),
+ emit({",",{curr,bytes},"}",nl}),
+ emit([nl,"end"]),
+ St
+ end;
+ _ ->
+ fun(St) ->
+ emit([";",nl,"_ ->",nl]),
+ emit(["{"]),
+ case Type of
+ #type{def=#'SEQUENCE'{
+ extaddgroup=Number2,
+ components=ExtGroupCompList2}}
+ when is_integer(Number2)->
+ emit({"{extAddGroup,"}),
+ gen_dec_extaddGroup_no_val(Ext,ExtGroupCompList2),
+ emit({"}"});
+ _ ->
+ gen_dec_component_no_val(Ext, Prop)
+ end,
+ emit({",",{curr,bytes},"}",nl}),
+ emit([nl,"end"]),
+ St
+ end
+ end,
+ AdvBuffer = {ignore,fun(St) ->
+ asn1ct_name:new(bytes),
+ St
+ end},
+ [{group,[{safe,Comment},{safe,Preamble},
+ {safe,OptOrDef}|Lines]++
+ [{safe,Postamble},{safe,AdvBuffer}]}].
+
+is_mandatory_predef_tab_c(noext, mandatory,
+ {"got objfun through args","ObjFun"}) ->
+ true;
+is_mandatory_predef_tab_c(_, _, {"got objfun through args","ObjFun"}) ->
+ false;
+is_mandatory_predef_tab_c(_,_,_) ->
+ true.
gen_dec_extaddGroup_no_val(Ext,[#'ComponentType'{prop=Prop}])->
gen_dec_component_no_val(Ext,Prop),
@@ -1213,9 +1305,14 @@ gen_dec_component_no_val({ext,_,_},mandatory) ->
emit({"asn1_NOVALUE"}).
-gen_dec_line(Erule,TopType,Cname,Type,Pos,DecInfObj,Ext,Prop) ->
- Ctgenmod = list_to_atom(lists:concat(["asn1ct_gen_",per,
- asn1ct_gen:rt2ct_suffix()])),
+gen_dec_line(Erule, TopType, Comp, Pos, DecInfObj, Ext) ->
+ Imm0 = gen_dec_line_imm(Erule, TopType, Comp, Pos, DecInfObj, Ext),
+ Init = {ignore,fun(_) -> {[],[]} end},
+ Imm = [{group,[Init|Imm0]}],
+ emit_gen_dec_imm(Imm).
+
+gen_dec_line_imm(Erule, TopType, Comp, Pos, DecInfObj, Ext) ->
+ #'ComponentType'{name=Cname,typespec=Type} = Comp,
Atype =
case Type of
#type{def=#'ObjectClassFieldType'{type=InnerType}} ->
@@ -1224,175 +1321,241 @@ gen_dec_line(Erule,TopType,Cname,Type,Pos,DecInfObj,Ext,Prop) ->
asn1ct_gen:get_inner(Type#type.def)
end,
- BytesVar0 = asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
- BytesVar = case Ext of
- {ext,Ep,_} when Pos >= Ep ->
- emit(["begin",nl,"{TmpVal",Pos,",Trem",Pos,
- "}=?RT_PER:decode_open_type(",
- {curr,bytes},",[]),",nl,
- "{TmpValx",Pos,",_}="]),
- io_lib:format("TmpVal~p",[Pos]);
- _ -> BytesVar0
- end,
- SaveBytes =
- case Atype of
- {typefield,_} ->
- case DecInfObj of
- false -> % This is in a choice with typefield components
- {Name,RestFieldNames} =
- (Type#type.def)#'ObjectClassFieldType'.fieldname,
-
- asn1ct_name:new(tmpterm),
- asn1ct_name:new(reason),
- emit([indent(2),"{",{curr,tmpterm},", ",{next,bytes},
- "} = ?RT_PER:decode_open_type(",{curr,bytes},
- ", []),",nl]),
- emit([indent(2),"case (catch ObjFun(",
- {asis,Name},",",{curr,tmpterm},",telltype,",
- {asis,RestFieldNames},")) of", nl]),
- emit([indent(4),"{'EXIT',",{curr,reason},"} ->",nl]),
- emit([indent(6),"exit({'Type not ",
- "compatible with table constraint', ",
- {curr,reason},"});",nl]),
- asn1ct_name:new(tmpterm),
- emit([indent(4),"{",{curr,tmpterm},", _} ->",nl]),
- emit([indent(6),"{",{asis,Cname},", {",{curr,tmpterm},", ",
- {next,bytes},"}}",nl]),
- emit([indent(2),"end"]),
- [];
- {"got objfun through args","ObjFun"} ->
- %% this is when the generated code gots the
- %% objfun though arguments on function
- %% invocation.
- if
- Ext == noext andalso Prop == mandatory ->
- ok;
- true ->
- asn1ct_name:new(tmpterm),
- asn1ct_name:new(tmpbytes),
- emit([nl," {",{curr,tmpterm},", ",{curr,tmpbytes},"} ="])
- end,
- {Name,RestFieldNames} =
- (Type#type.def)#'ObjectClassFieldType'.fieldname,
- emit(["?RT_PER:decode_open_type(",{curr,bytes},
- ", []),",nl]),
- if
- Ext == noext andalso Prop == mandatory ->
- emit([{curr,term}," =",nl," "]);
- true ->
- emit([" {"])
- end,
- emit(["case (catch ObjFun(",{asis,Name},",",
- {curr,tmpterm},",telltype,",
- {asis,RestFieldNames},")) of", nl]),
- emit([" {'EXIT',",{curr,reason},"} ->",nl]),
- emit([indent(6),"exit({'Type not ",
- "compatible with table constraint', ",
- {curr,reason},"});",nl]),
- asn1ct_name:new(tmpterm),
- emit([indent(4),"{",{curr,tmpterm},", _} ->",nl]),
- emit([indent(6),{curr,tmpterm},nl]),
- emit([indent(2),"end"]),
- if
- Ext == noext andalso Prop == mandatory ->
- ok;
- true ->
- emit([",",nl,{curr,tmpbytes},"}"])
- end,
- [];
- _ ->
- emit(["?RT_PER:decode_open_type(",{curr,bytes},
- ", [])"]),
- RefedFieldName =
- (Type#type.def)#'ObjectClassFieldType'.fieldname,
-
- [{Cname,RefedFieldName,
- asn1ct_gen:mk_var(asn1ct_name:curr(term)),
- asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),
- get_components_prop()}]
- end;
- {objectfield,PrimFieldName1,PFNList} ->
- emit(["?RT_PER:decode_open_type(",{curr,bytes},", [])"]),
- [{Cname,{PrimFieldName1,PFNList},
- asn1ct_gen:mk_var(asn1ct_name:curr(term)),
- asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),
- get_components_prop()}];
- _ ->
- CurrMod = get(currmod),
- case asn1ct_gen:type(Atype) of
- #'Externaltypereference'{module=CurrMod,type=EType} ->
- emit({"'dec_",EType,"'(",BytesVar,",telltype)"});
- #'Externaltypereference'{module=Mod,type=EType} ->
- emit({"'",Mod,"':'dec_",EType,"'(",BytesVar,
- ",telltype)"});
- {primitive,bif} ->
- case Atype of
- {fixedtypevaluefield,_,Btype} ->
- Ctgenmod:gen_dec_prim(Erule,Btype,
- BytesVar);
- _ ->
- Ctgenmod:gen_dec_prim(Erule,Type,
- BytesVar)
- end;
- 'ASN1_OPEN_TYPE' ->
- case Type#type.def of
- #'ObjectClassFieldType'{type=OpenType} ->
- Ctgenmod:gen_dec_prim(Erule,#type{def=OpenType},
- BytesVar);
- _ ->
- Ctgenmod:gen_dec_prim(Erule,Type,
- BytesVar)
- end;
- #typereference{val=Dname} ->
- emit({"'dec_",Dname,"'(",BytesVar,",telltype)"});
- {notype,_} ->
- emit({"'dec_",Atype,"'(",BytesVar,",telltype)"});
- {constructed,bif} ->
- NewTypename = [Cname|TopType],
- case Type#type.tablecinf of
- [{objfun,_}|_R] ->
- emit({"'dec_",asn1ct_gen:list2name(NewTypename),
- "'(",BytesVar,", telltype, ObjFun)"});
- _ ->
- emit({"'dec_",asn1ct_gen:list2name(NewTypename),
- "'(",BytesVar,", telltype)"})
- end
- end,
+ Pre = gen_dec_line_open_type(Erule, Ext, Pos),
+ Decode = gen_dec_line_special(Erule, Atype, TopType, Comp, DecInfObj, Ext),
+ Post =
+ fun({SaveBytes,Finish}) ->
+ {AccTerm,AccBytes} = Finish(),
+ #'ComponentType'{name=Cname} = Comp,
case DecInfObj of
- {Cname,{_,OSet,UniqueFName,ValIndex}} ->
- Term = asn1ct_gen:mk_var(asn1ct_name:curr(term)),
- ValueMatch = value_match(ValIndex,Term),
- {ObjSetMod,ObjSetName} =
- case OSet of
- {M,O} -> {{asis,M},O};
- _ -> {"?MODULE",OSet}
+ {Cname,ObjSet} ->
+ ObjSetRef =
+ case ObjSet of
+ {deep,OSName,_,_} ->
+ OSName;
+ _ -> ObjSet
end,
- emit({",",nl,"ObjFun = ",ObjSetMod,
- ":'getdec_",ObjSetName,"'(",
- {asis,UniqueFName},", ",ValueMatch,")"});
+ {AccTerm++[{ObjSetRef,Cname,
+ asn1ct_gen:mk_var(asn1ct_name:curr(term))}],
+ AccBytes++SaveBytes};
_ ->
- ok
- end,
- []
+ {AccTerm,AccBytes++SaveBytes}
+ end
end,
- case Ext of
- {ext,Ep2,_} when Pos >= Ep2 ->
- emit([", {TmpValx",Pos,",Trem",Pos,"}",nl,"end"]);
- _ -> true
- end,
- %% Prepare return value
+ [Pre,Decode,{safe,Post}].
+
+gen_dec_line_open_type(Erule, {ext,Ep,_}, Pos) when Pos >= Ep ->
+ Imm = asn1ct_imm:per_dec_open_type(is_aligned(Erule)),
+ {safe,fun(St) ->
+ emit(["begin",nl]),
+ BytesVar = asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
+ {Dst,DstBuf} = asn1ct_imm:dec_slim_cg(Imm, BytesVar),
+ emit([",",nl,"{TmpValx",Pos,",_} = "]),
+ {Dst,
+ fun() ->
+ emit([",",nl,
+ "{TmpValx",Pos,",",DstBuf,"}",nl,
+ "end"]),
+ St
+ end}
+ end};
+gen_dec_line_open_type(_, _, _) ->
+ {safe,fun(St) ->
+ {asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
+ fun() -> St end}
+ end}.
+
+gen_dec_line_special(Erule, {typefield,_}, _TopType, Comp,
+ DecInfObj, Ext) ->
+ #'ComponentType'{name=Cname,typespec=Type,prop=Prop} = Comp,
+ fun({_BytesVar,PrevSt}) ->
+ case DecInfObj of
+ false -> % This is in a choice with typefield components
+ {Name,RestFieldNames} =
+ (Type#type.def)#'ObjectClassFieldType'.fieldname,
+
+ asn1ct_name:new(reason),
+ Imm = asn1ct_imm:per_dec_open_type(is_aligned(Erule)),
+ BytesVar = asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
+ {TmpTerm,TempBuf} = asn1ct_imm:dec_slim_cg(Imm, BytesVar),
+ emit([com,nl,
+ {next,bytes}," = ",TempBuf,com,nl,
+ indent(2),"case (catch ObjFun(",
+ {asis,Name},",",TmpTerm,",telltype,",
+ {asis,RestFieldNames},")) of", nl]),
+ emit([indent(4),"{'EXIT',",{curr,reason},"} ->",nl]),
+ emit([indent(6),"exit({'Type not ",
+ "compatible with table constraint', ",
+ {curr,reason},"});",nl]),
+ asn1ct_name:new(tmpterm),
+ emit([indent(4),"{",{curr,tmpterm},", _} ->",nl]),
+ emit([indent(6),"{",{asis,Cname},", {",{curr,tmpterm},", ",
+ {next,bytes},"}}",nl]),
+ emit([indent(2),"end"]),
+ {[],PrevSt};
+ {"got objfun through args","ObjFun"} ->
+ %% this is when the generated code gots the
+ %% objfun though arguments on function
+ %% invocation.
+ if
+ Ext == noext andalso Prop == mandatory ->
+ ok;
+ true ->
+ asn1ct_name:new(tmpterm),
+ asn1ct_name:new(tmpbytes),
+ emit([nl," {",{curr,tmpterm},", ",{curr,tmpbytes},"} ="])
+ end,
+ {Name,RestFieldNames} =
+ (Type#type.def)#'ObjectClassFieldType'.fieldname,
+ Imm = asn1ct_imm:per_dec_open_type(is_aligned(Erule)),
+ BytesVar = asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
+ asn1ct_imm:dec_code_gen(Imm, BytesVar),
+ emit([com,nl]),
+ if
+ Ext == noext andalso Prop == mandatory ->
+ emit([{curr,term}," =",nl," "]);
+ true ->
+ emit([" {"])
+ end,
+ emit(["case (catch ObjFun(",{asis,Name},",",
+ {curr,tmpterm},",telltype,",
+ {asis,RestFieldNames},")) of", nl]),
+ emit([" {'EXIT',",{curr,reason},"} ->",nl]),
+ emit([indent(6),"exit({'Type not ",
+ "compatible with table constraint', ",
+ {curr,reason},"});",nl]),
+ asn1ct_name:new(tmpterm),
+ emit([indent(4),"{",{curr,tmpterm},", _} ->",nl]),
+ emit([indent(6),{curr,tmpterm},nl]),
+ emit([indent(2),"end"]),
+ if
+ Ext == noext andalso Prop == mandatory ->
+ ok;
+ true ->
+ emit([",",nl,{curr,tmpbytes},"}"])
+ end,
+ {[],PrevSt};
+ _ ->
+ Imm = asn1ct_imm:per_dec_open_type(is_aligned(Erule)),
+ BytesVar = asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
+ asn1ct_imm:dec_code_gen(Imm, BytesVar),
+ RefedFieldName =
+ (Type#type.def)#'ObjectClassFieldType'.fieldname,
+
+ {[{Cname,RefedFieldName,
+ asn1ct_gen:mk_var(asn1ct_name:curr(term)),
+ asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),
+ Prop}],PrevSt}
+ end
+ end;
+gen_dec_line_special(Erule, {objectfield,PrimFieldName1,PFNList}, _TopType,
+ Comp, _DecInfObj, _Ext) ->
+ fun({_BytesVar,PrevSt}) ->
+ Imm = asn1ct_imm:per_dec_open_type(is_aligned(Erule)),
+ BytesVar = asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
+ asn1ct_imm:dec_code_gen(Imm, BytesVar),
+ #'ComponentType'{name=Cname,prop=Prop} = Comp,
+ SaveBytes = [{Cname,{PrimFieldName1,PFNList},
+ asn1ct_gen:mk_var(asn1ct_name:curr(term)),
+ asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),
+ Prop}],
+ {SaveBytes,PrevSt}
+ end;
+gen_dec_line_special(Erule, Atype, TopType, Comp, DecInfObj, _Ext) ->
+ case gen_dec_line_other(Erule, Atype, TopType, Comp) of
+ Fun when is_function(Fun, 1) ->
+ fun({BytesVar,PrevSt}) ->
+ Fun(BytesVar),
+ gen_dec_line_dec_inf(Comp, DecInfObj),
+ {[],PrevSt}
+ end;
+ Imm0 ->
+ {imm,Imm0,
+ fun(Imm, {BytesVar,PrevSt}) ->
+ asn1ct_imm:dec_code_gen(Imm, BytesVar),
+ gen_dec_line_dec_inf(Comp, DecInfObj),
+ {[],PrevSt}
+ end}
+ end.
+
+gen_dec_line_dec_inf(Comp, DecInfObj) ->
+ #'ComponentType'{name=Cname} = Comp,
case DecInfObj of
- {Cname,ObjSet} ->
- ObjSetRef =
- case ObjSet of
- {deep,OSName,_,_} ->
- OSName;
- _ -> ObjSet
+ {Cname,{_,OSet,UniqueFName,ValIndex}} ->
+ Term = asn1ct_gen:mk_var(asn1ct_name:curr(term)),
+ ValueMatch = value_match(ValIndex,Term),
+ {ObjSetMod,ObjSetName} =
+ case OSet of
+ {M,O} -> {{asis,M},O};
+ _ -> {"?MODULE",OSet}
end,
- {[{ObjSetRef,Cname,asn1ct_gen:mk_var(asn1ct_name:curr(term))}],
- SaveBytes};
+ emit({",",nl,"ObjFun = ",ObjSetMod,
+ ":'getdec_",ObjSetName,"'(",
+ {asis,UniqueFName},", ",ValueMatch,")"});
_ ->
- {[],SaveBytes}
+ ok
+ end.
+
+gen_dec_line_other(Erule, Atype, TopType, Comp) ->
+ #'ComponentType'{name=Cname,typespec=Type} = Comp,
+ CurrMod = get(currmod),
+ Ctgenmod = asn1ct_gen:ct_gen_module(Erule),
+ case asn1ct_gen:type(Atype) of
+ #'Externaltypereference'{module=CurrMod,type=EType} ->
+ fun(BytesVar) ->
+ emit({"'dec_",EType,"'(",BytesVar,",telltype)"})
+ end;
+ #'Externaltypereference'{module=Mod,type=EType} ->
+ fun(BytesVar) ->
+ emit({"'",Mod,"':'dec_",EType,"'(",BytesVar,
+ ",telltype)"})
+ end;
+ {primitive,bif} ->
+ case Atype of
+ {fixedtypevaluefield,_,Btype} ->
+ gen_dec_prim(Ctgenmod, Erule, Btype);
+ _ ->
+ gen_dec_prim(Ctgenmod, Erule, Type)
+ end;
+ 'ASN1_OPEN_TYPE' ->
+ case Type#type.def of
+ #'ObjectClassFieldType'{type=OpenType} ->
+ gen_dec_prim(Ctgenmod, Erule, #type{def=OpenType});
+ _ ->
+ gen_dec_prim(Ctgenmod, Erule, Type)
+ end;
+ #typereference{val=Dname} ->
+ fun(BytesVar) ->
+ emit({"'dec_",Dname,"'(",BytesVar,",telltype)"})
+ end;
+ {notype,_} ->
+ fun(BytesVar) ->
+ emit({"'dec_",Atype,"'(",BytesVar,",telltype)"})
+ end;
+ {constructed,bif} ->
+ NewTypename = [Cname|TopType],
+ case Type#type.tablecinf of
+ [{objfun,_}|_R] ->
+ fun(BytesVar) ->
+ emit({"'dec_",asn1ct_gen:list2name(NewTypename),
+ "'(",BytesVar,", telltype, ObjFun)"})
+ end;
+ _ ->
+ fun(BytesVar) ->
+ emit({"'dec_",asn1ct_gen:list2name(NewTypename),
+ "'(",BytesVar,", telltype)"})
+ end
+ end
+ end.
+
+gen_dec_prim(Ctgenmod, Erule, Type) ->
+ case asn1ct_gen_per:gen_dec_imm(Erule, Type) of
+ no ->
+ fun(BytesVar) ->
+ Ctgenmod:gen_dec_prim(Erule, Type, BytesVar)
+ end;
+ Imm ->
+ Imm
end.
gen_enc_choice(Erule,TopType,CompList,Ext) ->
@@ -1513,20 +1676,15 @@ gen_dec_choice1(Erule,TopType,CompList,{ext,ExtPos,ExtNum}) ->
length(CompList)-ExtNum,",Ext ),",nl}),
emit({"{Cname,{Val,NewBytes}} = case Choice + Ext*",ExtPos-1," of",nl}),
gen_dec_choice2(Erule,TopType,CompList,{ext,ExtPos,ExtNum}),
- case Erule of
- per ->
- emit([";",nl,"_ -> {asn1_ExtAlt,",nl,
- " fun() -> ",nl,
- " {XTerm,XBytes} = ?RT_PER:decode_open_type(",
- {curr,bytes},",[]),",nl,
- " {binary_to_list(XTerm),XBytes}",nl,
- " end()}"]);
- _ ->
- emit([";",nl,"_ -> {asn1_ExtAlt, ?RT_PER:decode_open_type(",
- {curr,bytes},",[])}"])
- end,
- emit({nl,"end,",nl}),
- emit({nl,"{{Cname,Val},NewBytes}"}).
+ Imm = asn1ct_imm:per_dec_open_type(is_aligned(Erule)),
+ BytesVar = asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
+ emit([";",nl,
+ "_ ->",nl]),
+ {TmpTerm,TmpBuf} = asn1ct_imm:dec_slim_cg(Imm, BytesVar),
+ emit([com,nl,
+ "{asn1_ExtAlt,{",TmpTerm,com,TmpBuf,"}}",nl,
+ "end,",nl,nl,
+ "{{Cname,Val},NewBytes}"]).
gen_dec_choice2(Erule,TopType,L,Ext) ->
@@ -1578,22 +1736,17 @@ gen_encode_prim_wrapper(CtgenMod,Erule,Cont,DoTag,Value) ->
make_elements(I,Val,ExtCnames) ->
make_elements(I,Val,ExtCnames,[]).
-make_elements(I,Val,[ExtCname],Acc)-> % the last one, no comma needed
- Element = make_element(I,Val,ExtCname),
+make_elements(I,Val,[_ExtCname],Acc)-> % the last one, no comma needed
+ Element = make_element(I, Val),
make_elements(I+1,Val,[],[Element|Acc]);
-make_elements(I,Val,[ExtCname|Rest],Acc)->
- Element = make_element(I,Val,ExtCname),
+make_elements(I,Val,[_ExtCname|Rest],Acc)->
+ Element = make_element(I, Val),
make_elements(I+1,Val,Rest,[", ",Element|Acc]);
make_elements(_I,_,[],Acc) ->
lists:reverse(Acc).
-make_element(I,Val,Cname) ->
- case tuple_notation_allowed() of
- true ->
- io_lib:format("?RT_PER:cindex(~w,~s,~w)",[I,Val,Cname]);
- _ ->
- io_lib:format("element(~w,~s)",[I,Val])
- end.
+make_element(I, Val) ->
+ io_lib:format("element(~w,~s)", [I,Val]).
emit_extaddgroupTerms(VarSeries,[_]) ->
asn1ct_name:new(VarSeries),
@@ -1651,22 +1804,12 @@ wrap_extensionAdditionGroups([],_,Acc,_,_) ->
lists:reverse(Acc).
-tuple_notation_allowed() ->
- Options = get(encoding_options),
- not (lists:member(optimize,Options) orelse lists:member(uper_bin,Options)).
-
-wrap_gen_dec_line(Erule,C,TopType,Cname,Type,Pos,DIO,Ext) ->
+wrap_gen_dec_line(Erule,C,TopType,_Cname,_Type,Pos,DIO,Ext) ->
put(component_type,{true,C}),
- gen_dec_line(Erule,TopType,Cname,Type,Pos,DIO,Ext,mandatory),
+ gen_dec_line(Erule, TopType, C#'ComponentType'{prop=mandatory},
+ Pos, DIO, Ext),
erase(component_type).
-get_components_prop() ->
- case get(component_type) of
- undefined ->
- mandatory;
- {true,#'ComponentType'{prop=Prop}} -> Prop
- end.
-
value_match(Index,Value) when is_atom(Value) ->
value_match(Index,atom_to_list(Value));
@@ -1683,7 +1826,5 @@ notice_value_match() ->
Module = get(currmod),
put(value_match,{true,Module}).
-is_optimized(per_bin) ->
- lists:member(optimize,get(encoding_options));
-is_optimized(_Erule) ->
- false.
+is_optimized(per) -> true;
+is_optimized(uper) -> false.
diff --git a/lib/asn1/src/asn1ct_gen.erl b/lib/asn1/src/asn1ct_gen.erl
index 64a3555f62..57b12ce186 100644
--- a/lib/asn1/src/asn1ct_gen.erl
+++ b/lib/asn1/src/asn1ct_gen.erl
@@ -37,8 +37,7 @@
gen_check_call/7,
get_constraint/2,
insert_once/2,
- rt2ct_suffix/1,
- rt2ct_suffix/0,
+ ct_gen_module/1,
index2suffix/1,
get_record_name_prefix/0]).
-export([pgen/5,
@@ -52,7 +51,7 @@
%% pgen(Outfile, Erules, Module, TypeOrVal, Options)
%% Generate Erlang module (.erl) and (.hrl) file corresponding to an ASN.1 module
%% .hrl file is only generated if necessary
-%% Erules = per | ber | ber_bin | per_bin
+%% Erules = per | ber
%% Module = atom()
%% TypeOrVal = {TypeList,ValueList}
%% TypeList = ValueList = [atom()]
@@ -83,7 +82,7 @@ pgen_module(OutFile,Erules,Module,
pgen_exports(Erules,Module,TypeOrVal),
pgen_dispatcher(Erules,Module,TypeOrVal),
pgen_info(),
- pgen_typeorval(wrap_ber(Erules),Module,N2nConvEnums,TypeOrVal),
+ pgen_typeorval(Erules,Module,N2nConvEnums,TypeOrVal),
pgen_partial_incomplete_decode(Erules),
% gen_vars(asn1_db:mod_to_vars(Module)),
% gen_tag_table(AllTypes),
@@ -92,8 +91,7 @@ pgen_module(OutFile,Erules,Module,
pgen_typeorval(Erules,Module,N2nConvEnums,{Types,Values,_Ptypes,_Classes,Objects,ObjectSets}) ->
- Rtmod = list_to_atom(lists:concat(["asn1ct_gen_",erule(Erules),
- rt2ct_suffix(Erules)])),
+ Rtmod = ct_gen_module(Erules),
pgen_types(Rtmod,Erules,N2nConvEnums,Module,Types),
pgen_values(Erules,Module,Values),
pgen_objects(Rtmod,Erules,Module,Objects),
@@ -196,7 +194,7 @@ pgen_check_defaultval(Erules,Module) ->
end,
gen_check_defaultval(Erules,Module,CheckObjects).
-pgen_partial_decode(Rtmod,Erule,Module) when Erule == ber_bin_v2 ->
+pgen_partial_decode(Rtmod,Erule,Module) when Erule == ber ->
pgen_partial_inc_dec(Rtmod,Erule,Module),
pgen_partial_dec(Rtmod,Erule,Module);
pgen_partial_decode(_,_,_) ->
@@ -240,7 +238,7 @@ pgen_partial_inc_dec1(Rtmod,Erules,Module,[P|Ps]) ->
pgen_partial_inc_dec1(_,_,_,[]) ->
ok.
-gen_partial_inc_dec_refed_funcs(Rtmod,Erule) when Erule == ber_bin_v2 ->
+gen_partial_inc_dec_refed_funcs(Rtmod,Erule) when Erule == ber ->
case asn1ct:next_refed_func() of
[] ->
ok;
@@ -296,8 +294,7 @@ pgen_partial_types1(_,undefined) ->
%% TypeList a decode function will be generated.
traverse_type_structure(Erules,Type,[],FuncName,TopTypeName) ->
%% this is the selected type
- Ctmod = list_to_atom(lists:concat(["asn1ct_gen_",erule(Erules),
- rt2ct_suffix(Erules)])),
+ Ctmod = ct_gen_module(Erules),
TypeDef =
case Type of
#type{} ->
@@ -457,7 +454,7 @@ pgen_partial_incomplete_decode(Erule) ->
_ ->
ok
end.
-pgen_partial_incomplete_decode1(ber_bin_v2) ->
+pgen_partial_incomplete_decode1(ber) ->
case asn1ct:read_config_data(partial_incomplete_decode) of
undefined ->
ok;
@@ -552,20 +549,17 @@ gen_part_decode_funcs(WhatKind,_TypeName,{_,Directive,_,_}) ->
gen_types(Erules,Tname,{RootL1,ExtList,RootL2})
when is_list(RootL1), is_list(RootL2) ->
gen_types(Erules,Tname,RootL1),
- Rtmod = list_to_atom(lists:concat(["asn1ct_gen_",erule(Erules),
- rt2ct_suffix(Erules)])),
+ Rtmod = ct_gen_module(Erules),
gen_types(Erules,Tname,Rtmod:extaddgroup2sequence(ExtList)),
gen_types(Erules,Tname,RootL2);
gen_types(Erules,Tname,{RootList,ExtList}) when is_list(RootList) ->
gen_types(Erules,Tname,RootList),
- Rtmod = list_to_atom(lists:concat(["asn1ct_gen_",erule(Erules),
- rt2ct_suffix(Erules)])),
+ Rtmod = ct_gen_module(Erules),
gen_types(Erules,Tname,Rtmod:extaddgroup2sequence(ExtList));
gen_types(Erules,Tname,[{'EXTENSIONMARK',_,_}|Rest]) ->
gen_types(Erules,Tname,Rest);
gen_types(Erules,Tname,[ComponentType|Rest]) ->
- Rtmod = list_to_atom(lists:concat(["asn1ct_gen_",erule(Erules),
- rt2ct_suffix(Erules)])),
+ Rtmod = ct_gen_module(Erules),
asn1ct_name:clear(),
Rtmod:gen_encode(Erules,Tname,ComponentType),
asn1ct_name:clear(),
@@ -574,8 +568,7 @@ gen_types(Erules,Tname,[ComponentType|Rest]) ->
gen_types(_,_,[]) ->
true;
gen_types(Erules,Tname,Type) when is_record(Type,type) ->
- Rtmod = list_to_atom(lists:concat(["asn1ct_gen_",erule(Erules),
- rt2ct_suffix(Erules)])),
+ Rtmod = ct_gen_module(Erules),
asn1ct_name:clear(),
Rtmod:gen_encode(Erules,Tname,Type),
asn1ct_name:clear(),
@@ -754,8 +747,7 @@ gen_value(Value) when is_record(Value,valuedef) ->
emit([{asis,V},".",nl,nl]).
gen_encode_constructed(Erules,Typename,InnerType,D) when is_record(D,type) ->
-
- Rtmod = list_to_atom(lists:concat(["asn1ct_constructed_",erule(Erules)])),
+ Rtmod = ct_constructed_module(Erules),
case InnerType of
'SET' ->
Rtmod:gen_encode_set(Erules,Typename,D),
@@ -787,7 +779,7 @@ gen_encode_constructed(Erules,Typename,InnerType,D)
gen_encode_constructed(Erules,Typename,InnerType,D#typedef.typespec).
gen_decode_constructed(Erules,Typename,InnerType,D) when is_record(D,type) ->
- Rtmod = list_to_atom(lists:concat(["asn1ct_constructed_",erule(Erules)])),
+ Rtmod = ct_constructed_module(Erules),
asn1ct:step_in_constructed(), %% updates namelist for exclusive decode
case InnerType of
'SET' ->
@@ -818,27 +810,11 @@ pgen_exports(Erules,_Module,{Types,Values,_,_,Objects,ObjectSets}) ->
case Erules of
ber ->
gen_exports1(Types,"enc_",2);
- ber_bin ->
- gen_exports1(Types,"enc_",2);
- ber_bin_v2 ->
- gen_exports1(Types,"enc_",2);
_ ->
gen_exports1(Types,"enc_",1)
end,
emit({"-export([",nl}),
- gen_exports1(Types,"dec_",2),
- case Erules of
- ber ->
- emit({"-export([",nl}),
- gen_exports1(Types,"dec_",3);
- ber_bin ->
- emit({"-export([",nl}),
- gen_exports1(Types,"dec_",3);
-% ber_bin_v2 ->
-% emit({"-export([",nl}),
-% gen_exports1(Types,"dec_",2);
- _ -> ok
- end
+ gen_exports1(Types,"dec_",2)
end,
case [X || {n2n,X} <- get(encoding_options)] of
[] -> ok;
@@ -863,16 +839,11 @@ pgen_exports(Erules,_Module,{Types,Values,_,_,Objects,ObjectSets}) ->
gen_exports1(Objects,"enc_",3),
emit({"-export([",nl}),
gen_exports1(Objects,"dec_",4);
- ber_bin_v2 ->
+ ber ->
emit({"-export([",nl}),
gen_exports1(Objects,"enc_",3),
emit({"-export([",nl}),
- gen_exports1(Objects,"dec_",3);
- _ ->
- emit({"-export([",nl}),
- gen_exports1(Objects,"enc_",4),
- emit({"-export([",nl}),
- gen_exports1(Objects,"dec_",4)
+ gen_exports1(Objects,"dec_",3)
end
end,
case ObjectSets of
@@ -948,20 +919,17 @@ pgen_dispatcher(Erules,_Module,{Types,_Values,_,_,_Objects,_ObjectSets}) ->
emit(["encoding_rule() ->",nl]),
emit([" ",{asis,Erules},".",nl,nl]),
NoFinalPadding = lists:member(no_final_padding,get(encoding_options)),
- Call = case Erules of
- per -> "?RT_PER:complete(encode_disp(Type,Data))";
- per_bin -> ["?RT_PER:complete(encode_disp(Type,Data))"];
- ber -> "encode_disp(Type,Data)";
- ber_bin -> "encode_disp(Type,Data)";
- ber_bin_v2 -> "encode_disp(Type,Data)";
- uper_bin when NoFinalPadding == true ->
- "?RT_PER:complete_NFP(encode_disp(Type,Data))";
- uper_bin -> ["?RT_PER:complete(encode_disp(Type,Data))"]
- end,
- EncWrap = case Erules of
- ber -> "wrap_encode(Bytes)";
- _ -> "Bytes"
- end,
+ {Call,BytesAsBinary} =
+ case Erules of
+ per ->
+ {["?RT_PER:complete(encode_disp(Type,Data))"],"Bytes"};
+ ber ->
+ {"encode_disp(Type,Data)","iolist_to_binary(Bytes)"};
+ uper when NoFinalPadding == true ->
+ {"?RT_PER:complete_NFP(encode_disp(Type,Data))","Bytes"};
+ uper ->
+ {["?RT_PER:complete(encode_disp(Type,Data))"],"Bytes"}
+ end,
emit(["encode(Type,Data) ->",nl,
"case catch ",Call," of",nl,
" {'EXIT',{error,Reason}} ->",nl,
@@ -969,42 +937,25 @@ pgen_dispatcher(Erules,_Module,{Types,_Values,_,_,_Objects,_ObjectSets}) ->
" {'EXIT',Reason} ->",nl,
" {error,{asn1,Reason}};",nl,
" {Bytes,_Len} ->",nl,
- " {ok,",EncWrap,"};",nl]),
- case Erules of
- per ->
- emit([" Bytes when is_binary(Bytes) ->",nl,
- " {ok,binary_to_list(Bytes)};",nl,
- " Bytes ->",nl,
- " {ok,binary_to_list(list_to_binary(Bytes))}",nl,
- " end.",nl,nl]);
- _ ->
- emit([" Bytes ->",nl,
- " {ok,",EncWrap,"}",nl,
- "end.",nl,nl])
- end,
-
-% case Erules of
-% ber_bin_v2 ->
-% emit(["decode(Type,Data0) ->",nl]),
-% emit(["{Data,_RestBin} = ?RT_BER:decode(Data0",nif_parameter(),"),",nl]);
-% _ ->
-% emit(["decode(Type,Data) ->",nl])
-% end,
+ " {ok,",BytesAsBinary,"};",nl,
+ " Bytes ->",nl,
+ " {ok,",BytesAsBinary,"}",nl,
+ "end.",nl,nl]),
Return_rest = lists:member(undec_rest,get(encoding_options)),
Data = case {Erules,Return_rest} of
- {ber_bin_v2,true} -> "Data0";
+ {ber,true} -> "Data0";
_ -> "Data"
end,
emit(["decode(Type,",Data,") ->",nl]),
DecAnonymous =
case {Erules,Return_rest} of
- {ber_bin_v2,false} ->
+ {ber,false} ->
io_lib:format("~s~s~s~n",
["element(1,?RT_BER:decode(Data",
nif_parameter(),"))"]);
- {ber_bin_v2,true} ->
+ {ber,true} ->
emit(["{Data,Rest} = ?RT_BER:decode(Data0",
nif_parameter(),"),",nl]),
"Data";
@@ -1012,10 +963,8 @@ pgen_dispatcher(Erules,_Module,{Types,_Values,_,_,_Objects,_ObjectSets}) ->
"Data"
end,
DecWrap = case Erules of
- ber -> "wrap_decode(Data)";
- ber_bin_v2 ->
+ ber ->
DecAnonymous;
- per -> "list_to_binary(Data)";
_ -> "Data"
end,
@@ -1025,32 +974,18 @@ pgen_dispatcher(Erules,_Module,{Types,_Values,_,_,_Objects,_ObjectSets}) ->
" {'EXIT',Reason} ->",nl,
" {error,{asn1,Reason}};",nl]),
case {Erules,Return_rest} of
- {ber_bin_v2,false} ->
+ {ber,false} ->
emit([" Result ->",nl,
" {ok,Result}",nl]);
- {ber_bin_v2,true} ->
+ {ber,true} ->
emit([" Result ->",nl,
" {ok,Result,Rest}",nl]);
- {per,false} ->
- emit([" {X,_Rest} ->",nl,
- " {ok,if_binary2list(X)};",nl,
- " {X,_Rest,_Len} ->",nl,
- " {ok,if_binary2list(X)}",nl]);
{_,false} ->
emit([" {X,_Rest} ->",nl,
" {ok,X};",nl,
" {X,_Rest,_Len} ->",nl,
" {ok,X}",nl]);
- {per,true} ->
- emit([" {X,{_,Rest}} ->",nl,
- " {ok,if_binary2list(X),Rest};",nl,
- " {X,{_,Rest},_Len} ->",nl,
- " {ok,if_binary2list(X),Rest};",nl,
- " {X,Rest} ->",nl,
- " {ok,if_binary2list(X),Rest};",nl,
- " {X,Rest,_Len} ->",nl,
- " {ok,if_binary2list(X),Rest}",nl]);
- {per_bin,true} ->
+ {per,true} ->
emit([" {X,{_,Rest}} ->",nl,
" {ok,X,Rest};",nl,
" {X,{_,Rest},_Len} ->",nl,
@@ -1059,7 +994,7 @@ pgen_dispatcher(Erules,_Module,{Types,_Values,_,_,_Objects,_ObjectSets}) ->
" {ok,X,Rest};",nl,
" {X,Rest,_Len} ->",nl,
" {ok,X,Rest}",nl]);
- {uper_bin,true} ->
+ {uper,true} ->
emit([" {X,{_,Rest}} ->",nl,
" {ok,X,Rest};",nl,
" {X,{_,Rest},_Len} ->",nl,
@@ -1067,34 +1002,14 @@ pgen_dispatcher(Erules,_Module,{Types,_Values,_,_,_Objects,_ObjectSets}) ->
" {X,Rest} ->",nl,
" {ok,X,Rest};",nl,
" {X,Rest,_Len} ->",nl,
- " {ok,X,Rest}",nl]);
- _ ->
- emit([" {X,Rest} ->",nl,
- " {ok,X,Rest};",nl,
- " {X,Rest,_Len} ->",nl,
" {ok,X,Rest}",nl])
end,
emit(["end.",nl,nl]),
- case Erules of
- per ->
- emit(["if_binary2list(B) when is_binary(B) ->",nl,
- " binary_to_list(B);",nl,
- "if_binary2list(L) -> L.",nl,nl]);
- _ ->
- ok
- end,
-
gen_decode_partial_incomplete(Erules),
case Erules of
ber ->
- gen_dispatcher(Types,"encode_disp","enc_",",[]"),
- gen_dispatcher(Types,"decode_disp","dec_",",mandatory");
- ber_bin ->
- gen_dispatcher(Types,"encode_disp","enc_",",[]"),
- gen_dispatcher(Types,"decode_disp","dec_",",mandatory");
- ber_bin_v2 ->
gen_dispatcher(Types,"encode_disp","enc_",""),
gen_dispatcher(Types,"decode_disp","dec_",""),
gen_partial_inc_dispatcher();
@@ -1103,17 +1018,10 @@ pgen_dispatcher(Erules,_Module,{Types,_Values,_,_,_Objects,_ObjectSets}) ->
gen_dispatcher(Types,"decode_disp","dec_",",mandatory")
end,
emit([nl]),
-
- case Erules of
- ber ->
- gen_wrapper();
- _ -> ok
- end,
emit({nl,nl}).
-gen_decode_partial_incomplete(Erule) when Erule == ber;Erule==ber_bin;
- Erule==ber_bin_v2 ->
+gen_decode_partial_incomplete(ber) ->
case {asn1ct:read_config_data(partial_incomplete_decode),
asn1ct:get_gen_state_field(inc_type_pattern)} of
{undefined,_} ->
@@ -1121,34 +1029,35 @@ gen_decode_partial_incomplete(Erule) when Erule == ber;Erule==ber_bin;
{_,undefined} ->
ok;
_ ->
- case Erule of
- ber_bin_v2 ->
- EmitCaseClauses =
- fun() ->
- emit([" {'EXIT',{error,Reason}} ->",nl,
- " {error,Reason};",nl,
- " {'EXIT',Reason} ->",nl,
- " {error,{asn1,Reason}};",nl,
- " Result ->",nl,
- " {ok,Result}",nl,
- " end.",nl,nl])
- end,
- emit(["decode_partial_incomplete(Type,Data0,",
- "Pattern) ->",nl]),
- emit([" {Data,_RestBin} =",nl,
- " ?RT_BER:decode_primitive_",
- "incomplete(Pattern,Data0),",nl,
- " case catch decode_partial_inc_disp(Type,",
- "Data) of",nl]),
- EmitCaseClauses(),
- emit(["decode_part(Type,Data0) ->",nl]),
- emit([" case catch decode_inc_disp(Type,element(1,"
- "?RT_BER:decode(Data0",nif_parameter(),"))) of",nl]),
-% " {Data,_RestBin} = ?RT_BER:decode(Data0),",nl,
-% " case catch decode_inc_disp(Type,Data) of",nl]),
- EmitCaseClauses();
- _ -> ok % add later
- end
+ EmitCaseClauses =
+ fun() ->
+ emit([" {'EXIT',{error,Reason}} ->",nl,
+ " {error,Reason};",nl,
+ " {'EXIT',Reason} ->",nl,
+ " {error,{asn1,Reason}};",nl,
+ " Result ->",nl,
+ " {ok,Result}",nl,
+ " end"])
+ end,
+ emit(["decode_partial_incomplete(Type,Data0,",
+ "Pattern) ->",nl]),
+ emit([" {Data,_RestBin} =",nl,
+ " ?RT_BER:decode_primitive_",
+ "incomplete(Pattern,Data0),",nl,
+ " case catch decode_partial_inc_disp(Type,",
+ "Data) of",nl]),
+ EmitCaseClauses(),
+ emit([".",nl,nl]),
+ emit(["decode_part(Type, Data0) "
+ "when is_binary(Data0) ->",nl]),
+ emit([" case catch decode_inc_disp(Type,element(1,"
+ "?RT_BER:decode(Data0",nif_parameter(),"))) of",nl]),
+ EmitCaseClauses(),
+ emit([";",nl]),
+ emit(["decode_part(Type, Data0) ->",nl]),
+ emit([" case catch decode_inc_disp(Type, Data0) of",nl]),
+ EmitCaseClauses(),
+ emit([".",nl,nl])
end;
gen_decode_partial_incomplete(_Erule) ->
ok.
@@ -1187,23 +1096,8 @@ gen_partial_inc_dispatcher([],_) ->
" exit({error,{asn1,{undefined_type,Type}}}).",nl]).
nif_parameter() ->
- Options = get(encoding_options),
- case {lists:member(driver,Options),lists:member(nif,Options)} of
- {true,_} -> ",nif";
- {_,true} -> ",nif";
- _ -> ""
- end.
+ ",nif".
-gen_wrapper() ->
- emit(["wrap_encode(Bytes) when is_list(Bytes) ->",nl,
- " binary_to_list(list_to_binary(Bytes));",nl,
- "wrap_encode(Bytes) when is_binary(Bytes) ->",nl,
- " binary_to_list(Bytes);",nl,
- "wrap_encode(Bytes) -> Bytes.",nl,nl]),
- emit(["wrap_decode(Bytes) when is_list(Bytes) ->",nl,
- " list_to_binary(Bytes);",nl,
- "wrap_decode(Bytes) -> Bytes.",nl]).
-
gen_dispatcher([F1,F2|T],FuncName,Prefix,ExtraArg) ->
emit([FuncName,"('",F1,"',Data) -> '",Prefix,F1,"'(Data",ExtraArg,")",";",nl]),
gen_dispatcher([F2|T],FuncName,Prefix,ExtraArg);
@@ -1213,19 +1107,16 @@ gen_dispatcher([Flast|_T],FuncName,Prefix,ExtraArg) ->
pgen_info() ->
emit(["info() ->",nl,
- " case ?MODULE:module_info() of",nl,
- " MI when is_list(MI) ->",nl,
- " case lists:keysearch(attributes,1,MI) of",nl,
- " {value,{_,Attributes}} when is_list(Attributes) ->",nl,
- " case lists:keysearch(asn1_info,1,Attributes) of",nl,
- " {value,{_,Info}} when is_list(Info) ->",nl,
- " Info;",nl,
- " _ ->",nl,
- " []",nl,
- " end;",nl,
- " _ ->",nl,
- " []",nl,
- " end",nl,
+ " case ?MODULE:module_info(attributes) of",nl,
+ " Attributes when is_list(Attributes) ->",nl,
+ " case lists:keyfind(asn1_info, 1, Attributes) of",nl,
+ " {_,Info} when is_list(Info) ->",nl,
+ " Info;",nl,
+ " _ ->",nl,
+ " []",nl,
+ " end;",nl,
+ " _ ->",nl,
+ " []",nl,
" end.",nl]).
open_hrl(OutFile,Module) ->
@@ -1496,32 +1387,15 @@ gen_head(Erules,Mod,Hrl) ->
{Rtmac,Rtmod} = case Erules of
per ->
emit({"%% Generated by the Erlang ASN.1 PER-"
- "compiler version:",asn1ct:vsn(),nl}),
- {"RT_PER",?RT_PER_BIN};
- ber ->
- emit({"%% Generated by the Erlang ASN.1 BER-"
- "compiler version:",asn1ct:vsn(),nl}),
- {"RT_BER",?RT_BER_BIN};
- per_bin ->
- emit({"%% Generated by the Erlang ASN.1 BER-"
- "compiler version, utilizing bit-syntax:",
- asn1ct:vsn(),nl}),
- %% temporary code to enable rt2ct optimization
- case lists:member(optimize,Options) of
- true -> {"RT_PER","asn1rt_per_bin_rt2ct"};
- _ -> {"RT_PER",?RT_PER_BIN}
- end;
- ber_bin ->
- emit({"%% Generated by the Erlang ASN.1 BER-"
"compiler version, utilizing bit-syntax:",
asn1ct:vsn(),nl}),
- {"RT_BER",?RT_BER_BIN};
- ber_bin_v2 ->
+ {"RT_PER","asn1rt_per_bin_rt2ct"};
+ ber ->
emit({"%% Generated by the Erlang ASN.1 BER_V2-"
"compiler version, utilizing bit-syntax:",
asn1ct:vsn(),nl}),
{"RT_BER","asn1rt_ber_bin_v2"};
- uper_bin ->
+ uper ->
emit(["%% Generated by the Erlang ASN.1 UNALIGNED"
" PER-compiler version, utilizing"
" bit-syntax:",
@@ -1531,7 +1405,7 @@ gen_head(Erules,Mod,Hrl) ->
emit({"%% Purpose: encoder and decoder to the types in mod ",Mod,nl,nl}),
emit({"-module('",Mod,"').",nl}),
put(currmod,Mod),
- %emit({"-compile(export_all).",nl}),
+ emit({"-compile(nowarn_unused_vars).",nl}),
case {Hrl,lists:member(inline,get(encoding_options))} of
{0,_} -> true;
{_,true} -> true;
@@ -1541,7 +1415,7 @@ gen_head(Erules,Mod,Hrl) ->
emit(["-define('",Rtmac,"',",Rtmod,").",nl]),
emit(["-asn1_info([{vsn,'",asn1ct:vsn(),"'},",nl,
" {module,'",Mod,"'},",nl,
- " {options,",io_lib:format("~w",[Options]),"}]).",nl,nl]).
+ " {options,",io_lib:format("~p",[Options]),"}]).",nl,nl]).
gen_hrlhead(Mod) ->
@@ -2019,43 +1893,29 @@ constructed_suffix('SEQUENCE OF',_) ->
constructed_suffix('SET OF',_) ->
'SETOF'.
-erule(ber) ->
- ber;
-erule(ber_bin) ->
- ber;
-erule(ber_bin_v2) ->
- ber_bin_v2;
-erule(per) ->
- per;
-erule(per_bin) ->
- per;
-erule(uper_bin) ->
- per.
-
-wrap_ber(ber) ->
- ber_bin;
-wrap_ber(Erule) ->
- Erule.
-
-rt2ct_suffix() ->
- Options = get(encoding_options),
- case {lists:member(optimize,Options),lists:member(per_bin,Options)} of
- {true,true} -> "_rt2ct";
- _ -> ""
- end.
-rt2ct_suffix(per_bin) ->
- Options = get(encoding_options),
- case lists:member(optimize,Options) of
- true -> "_rt2ct";
- _ -> ""
- end;
-rt2ct_suffix(_) -> "".
+erule(ber) -> ber;
+erule(per) -> per;
+erule(uper) -> per.
index2suffix(0) ->
"";
index2suffix(N) ->
lists:concat(["_",N]).
+ct_gen_module(ber) ->
+ asn1ct_gen_ber_bin_v2;
+ct_gen_module(per) ->
+ asn1ct_gen_per_rt2ct;
+ct_gen_module(uper) ->
+ asn1ct_gen_per.
+
+ct_constructed_module(ber) ->
+ asn1ct_constructed_ber_bin_v2;
+ct_constructed_module(per) ->
+ asn1ct_constructed_per;
+ct_constructed_module(uper) ->
+ asn1ct_constructed_per.
+
get_constraint(C,Key) ->
case lists:keysearch(Key,1,C) of
false ->
diff --git a/lib/asn1/src/asn1ct_gen_ber.erl b/lib/asn1/src/asn1ct_gen_ber.erl
deleted file mode 100644
index 491ebcb8fd..0000000000
--- a/lib/asn1/src/asn1ct_gen_ber.erl
+++ /dev/null
@@ -1,1749 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(asn1ct_gen_ber).
-
-%% Generate erlang module which handles (PER) encode and decode for
-%% all types in an ASN.1 module
-
--include("asn1_records.hrl").
-
--export([pgen/4]).
--export([decode_class/1, decode_type/1]).
--export([add_removed_bytes/0]).
--export([gen_encode/2,gen_encode/3,gen_decode/2,gen_decode/3]).
--export([gen_encode_prim/4]).
--export([gen_dec_prim/8]).
--export([gen_objectset_code/2, gen_obj_code/3]).
--export([re_wrap_erule/1]).
--export([unused_var/2]).
--export([extaddgroup2sequence/1]).
-
--import(asn1ct_gen, [emit/1,demit/1]).
-
- % the encoding of class of tag bits 8 and 7
--define(UNIVERSAL, 0).
--define(APPLICATION, 16#40).
--define(CONTEXT, 16#80).
--define(PRIVATE, 16#C0).
-
- % primitive or constructed encoding % bit 6
--define(PRIMITIVE, 0).
--define(CONSTRUCTED, 2#00100000).
-
-
--define(T_ObjectDescriptor, ?UNIVERSAL bor ?PRIMITIVE bor 7).
- % restricted character string types
--define(T_NumericString, ?UNIVERSAL bor ?PRIMITIVE bor 18). %can be constructed
--define(T_PrintableString, ?UNIVERSAL bor ?PRIMITIVE bor 19). %can be constructed
--define(T_TeletexString, ?UNIVERSAL bor ?PRIMITIVE bor 20). %can be constructed
--define(T_VideotexString, ?UNIVERSAL bor ?PRIMITIVE bor 21). %can be constructed
--define(T_IA5String, ?UNIVERSAL bor ?PRIMITIVE bor 22). %can be constructed
--define(T_GraphicString, ?UNIVERSAL bor ?PRIMITIVE bor 25). %can be constructed
--define(T_VisibleString, ?UNIVERSAL bor ?PRIMITIVE bor 26). %can be constructed
--define(T_GeneralString, ?UNIVERSAL bor ?PRIMITIVE bor 27). %can be constructed
-
-%% pgen(Erules, Module, TypeOrVal)
-%% Generate Erlang module (.erl) and (.hrl) file corresponding to an ASN.1 module
-%% .hrl file is only generated if necessary
-%% Erules = per | ber
-%% Module = atom()
-%% TypeOrVal = {TypeList,ValueList,PTypeList}
-%% TypeList = ValueList = [atom()]
-
-pgen(OutFile,Erules,Module,TypeOrVal) ->
- asn1ct_gen:pgen_module(OutFile,Erules,Module,TypeOrVal,[],true).
-
-
-%%===============================================================================
-%%===============================================================================
-%%===============================================================================
-%% Generate ENCODING
-%%===============================================================================
-%%===============================================================================
-%%===============================================================================
-
-%%===============================================================================
-%% encode #{typedef, {pos, name, typespec}}
-%%===============================================================================
-
-gen_encode(Erules,Type) when is_record(Type,typedef) ->
- gen_encode_user(Erules,Type).
-
-%%===============================================================================
-%% encode #{type, {tag, def, constraint}}
-%%===============================================================================
-
-gen_encode(Erules,Typename,Type) when is_record(Type,type) ->
- InnerType = asn1ct_gen:get_inner(Type#type.def),
- ObjFun =
- case lists:keysearch(objfun,1,Type#type.tablecinf) of
- {value,{_,_Name}} ->
- ", ObjFun";
- false ->
- ""
- end,
- case asn1ct_gen:type(InnerType) of
- {constructed,bif} ->
- emit([nl,nl,nl,"%%================================"]),
- emit([nl,"%% ",asn1ct_gen:list2name(Typename)]),
- emit([nl,"%%================================",nl]),
- case lists:member(InnerType,['SET','SEQUENCE']) of
- true ->
- case get(asn_keyed_list) of
- true ->
- CompList =
- case Type#type.def of
- #'SEQUENCE'{components=Cl} -> Cl;
- #'SET'{components=Cl} -> Cl
- end,
- emit([nl,"'enc_",asn1ct_gen:list2name(Typename),
- "'(Val, TagIn",ObjFun,
- ") when is_list(Val) ->",nl]),
- emit([" 'enc_",asn1ct_gen:list2name(Typename),
- "'(?RT_BER:fixoptionals(",
- {asis,optionals(CompList)},
- ",Val), TagIn",ObjFun,");",nl,nl]);
- _ -> true
- end;
- _ ->
- emit([nl,"'enc_",asn1ct_gen:list2name(Typename),
- "'({'",asn1ct_gen:list2name(Typename),
- "',Val}, TagIn",ObjFun,") ->",nl]),
- emit([" 'enc_",asn1ct_gen:list2name(Typename),
- "'(Val, TagIn",ObjFun,");",nl,nl])
- end,
- emit(["'enc_",asn1ct_gen:list2name(Typename),
- "'(Val, TagIn",ObjFun,") ->",nl," "]),
- asn1ct_gen:gen_encode_constructed(Erules,Typename,InnerType,Type);
- _ ->
- true
- end;
-
-%%===============================================================================
-%% encode ComponentType
-%%===============================================================================
-
-gen_encode(Erules,Tname,#'ComponentType'{name=Cname,typespec=Type}) ->
- NewTname = [Cname|Tname],
- %% The tag is set to [] to avoid that it is
- %% taken into account twice, both as a component/alternative (passed as
- %% argument to the encode decode function and within the encode decode
- %% function it self.
- NewType = Type#type{tag=[]},
- gen_encode(Erules,NewTname,NewType).
-
-gen_encode_user(Erules,D) when is_record(D,typedef) ->
- Typename = [D#typedef.name],
- Type = D#typedef.typespec,
- InnerType = asn1ct_gen:get_inner(Type#type.def),
- OTag = Type#type.tag,
- Tag = [X#tag{class=decode_class(X#tag.class)}|| X <- OTag],
- emit([nl,nl,"%%================================"]),
- emit([nl,"%% ",Typename]),
- emit([nl,"%%================================",nl]),
- case lists:member(InnerType,['SET','SEQUENCE']) of
- true ->
- case get(asn_keyed_list) of
- true ->
- CompList =
- case Type#type.def of
- #'SEQUENCE'{components=Cl} -> Cl;
- #'SET'{components=Cl} -> Cl
- end,
-
- emit([nl,"'enc_",asn1ct_gen:list2name(Typename),
- "'(Val, TagIn) when is_list(Val) ->",nl]),
- emit([" 'enc_",asn1ct_gen:list2name(Typename),
- "'(?RT_BER:fixoptionals(",
- {asis,optionals(CompList)},
- ",Val), TagIn);",nl,nl]);
- _ -> true
- end;
- _ ->
- emit({nl,"'enc_",asn1ct_gen:list2name(Typename),
- "'({'",asn1ct_gen:list2name(Typename),"',Val}, TagIn) ->",nl}),
- emit({" 'enc_",asn1ct_gen:list2name(Typename),"'(Val, TagIn);",nl,nl})
- end,
- emit({"'enc_",asn1ct_gen:list2name(Typename),"'(",
- unused_var("Val",Type#type.def),", TagIn) ->",nl}),
- CurrentMod = get(currmod),
- case asn1ct_gen:type(InnerType) of
- {constructed,bif} ->
- asn1ct_gen:gen_encode_constructed(Erules,Typename,InnerType,D);
- {primitive,bif} ->
- asn1ct_gen_ber:gen_encode_prim(ber,Type,["TagIn ++ ",
- {asis,Tag}],"Val"),
- emit([".",nl]);
- #typereference{val=Ename} ->
- emit([" 'enc_",Ename,"'(Val, TagIn ++ ",{asis,Tag},").",nl]);
- #'Externaltypereference'{module=CurrentMod,type=Etype} ->
- emit([" 'enc_",Etype,"'(Val, TagIn ++ ",
- {asis,Tag},").",nl]);
- #'Externaltypereference'{module=Emod,type=Etype} ->
- emit([" '",Emod,"':'enc_",Etype,"'(Val, TagIn ++ ",
- {asis,Tag},").",nl]);
- 'ASN1_OPEN_TYPE' ->
- emit(["%% OPEN TYPE",nl]),
- asn1ct_gen_ber:gen_encode_prim(ber,
- Type#type{def='ASN1_OPEN_TYPE'},
- ["TagIn ++ ",
- {asis,Tag}],"Val"),
- emit([".",nl])
- end.
-
-unused_var(Var,#'SEQUENCE'{components=Cl}) ->
- unused_var1(Var,Cl);
-unused_var(Var,#'SET'{components=Cl}) ->
- unused_var1(Var,Cl);
-unused_var(Var,_) ->
- Var.
-unused_var1(Var,Cs) when Cs == []; Cs == {[],[]} ->
- lists:concat(["_",Var]);
-unused_var1(Var,_) ->
- Var.
-
-unused_optormand_var(Var,Def) ->
- case asn1ct_gen:type(asn1ct_gen:get_inner(Def)) of
- 'ASN1_OPEN_TYPE' ->
- lists:concat(["_",Var]);
- _ ->
- Var
- end.
-
-
-gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) ->
-
-%%% Currently not used for BER (except for BitString) and therefore replaced
-%%% with [] as a placeholder
- BitStringConstraint = D#type.constraint,
- Constraint = [],
- asn1ct_name:new(enumval),
- case D#type.def of
- 'BOOLEAN' ->
- emit_encode_func('boolean',Value,DoTag);
- 'INTEGER' ->
- emit_encode_func('integer',Constraint,Value,DoTag);
- {'INTEGER',NamedNumberList} ->
- emit_encode_func('integer',Constraint,Value,
- NamedNumberList,DoTag);
- {'ENUMERATED',NamedNumberList={_,_}} ->
-
- emit(["case (case ",Value," of {_,",{curr,enumval},"}->",
- {curr,enumval},";_->", Value," end) of",nl]),
- asn1ct_name:new(enumval),
- emit_enc_enumerated_cases(NamedNumberList,DoTag);
- {'ENUMERATED',NamedNumberList} ->
-
- emit(["case (case ",Value," of {_,",{curr,enumval},"}->",
- {curr,enumval},";_->", Value," end) of",nl]),
- asn1ct_name:new(enumval),
- emit_enc_enumerated_cases(NamedNumberList,DoTag);
-
- 'REAL' ->
- emit_encode_func('real',Constraint,Value,DoTag);
-
- {'BIT STRING',NamedNumberList} ->
- emit_encode_func('bit_string',BitStringConstraint,Value,
- NamedNumberList,DoTag);
- 'ANY' ->
- emit_encode_func('open_type', Value,DoTag);
- 'NULL' ->
- emit_encode_func('null',Value,DoTag);
- 'OBJECT IDENTIFIER' ->
- emit_encode_func("object_identifier",Value,DoTag);
- 'RELATIVE-OID' ->
- emit_encode_func("relative_oid",Value,DoTag);
- 'ObjectDescriptor' ->
- emit_encode_func('restricted_string',Constraint,Value,
- ?T_ObjectDescriptor,DoTag);
- 'OCTET STRING' ->
- emit_encode_func('octet_string',Constraint,Value,DoTag);
- 'NumericString' ->
- emit_encode_func('restricted_string',Constraint,Value,
- ?T_NumericString,DoTag);
- TString when TString == 'TeletexString';
- TString == 'T61String' ->
- emit_encode_func('restricted_string',Constraint,Value,
- ?T_TeletexString,DoTag);
- 'VideotexString' ->
- emit_encode_func('restricted_string',Constraint,Value,
- ?T_VideotexString,DoTag);
- 'GraphicString' ->
- emit_encode_func('restricted_string',Constraint,Value,
- ?T_GraphicString,DoTag);
- 'VisibleString' ->
- emit_encode_func('restricted_string',Constraint,Value,
- ?T_VisibleString,DoTag);
- 'GeneralString' ->
- emit_encode_func('restricted_string',Constraint,Value,
- ?T_GeneralString,DoTag);
- 'PrintableString' ->
- emit_encode_func('restricted_string',Constraint,Value,
- ?T_PrintableString,DoTag);
- 'IA5String' ->
- emit_encode_func('restricted_string',Constraint,Value,
- ?T_IA5String,DoTag);
- 'UniversalString' ->
- emit_encode_func('universal_string',Constraint,Value,DoTag);
- 'UTF8String' ->
- emit_encode_func('UTF8_string',Constraint,Value,DoTag);
- 'BMPString' ->
- emit_encode_func('BMP_string',Constraint,Value,DoTag);
- 'UTCTime' ->
- emit_encode_func('utc_time',Constraint,Value,DoTag);
- 'GeneralizedTime' ->
- emit_encode_func('generalized_time',Constraint,Value,DoTag);
- 'ASN1_OPEN_TYPE' ->
- emit_encode_func('open_type', Value,DoTag);
- #'ObjectClassFieldType'{} ->
- case asn1ct_gen:get_inner(D#type.def) of
- {fixedtypevaluefield,_,InnerType} ->
- gen_encode_prim(Erules,InnerType,DoTag,Value);
- 'ASN1_OPEN_TYPE' ->
- emit_encode_func('open_type', Value,DoTag);
- XX ->
- exit({'can not encode' ,XX})
- end;
- XX ->
- exit({'can not encode' ,XX})
- end.
-
-
-emit_encode_func(Name,Value,Tags) when is_atom(Name) ->
- emit_encode_func(atom_to_list(Name),Value,Tags);
-emit_encode_func(Name,Value,Tags) ->
- Fname = "?RT_BER:encode_" ++ Name,
- emit([Fname,"(",Value,", ",Tags,")"]).
-
-emit_encode_func(Name,Constraint,Value,Tags) when is_atom(Name) ->
- emit_encode_func(atom_to_list(Name),Constraint,Value,Tags);
-emit_encode_func(Name,Constraint,Value,Tags) ->
- Fname = "?RT_BER:encode_" ++ Name,
- emit([Fname,"(",{asis,Constraint},", ",Value,", ",Tags,")"]).
-
-emit_encode_func(Name,Constraint,Value,Asis,Tags) when is_atom(Name) ->
- emit_encode_func(atom_to_list(Name),Constraint,Value,Asis,Tags);
-emit_encode_func(Name,Constraint,Value,Asis,Tags) ->
- Fname = "?RT_BER:encode_" ++ Name,
- emit([Fname,"(",{asis,Constraint},", ",Value,
- ", ",{asis,Asis},
- ", ",Tags,")"]).
-
-emit_enc_enumerated_cases({L1,L2}, Tags) ->
- emit_enc_enumerated_cases(L1++L2, Tags, ext);
-emit_enc_enumerated_cases(L, Tags) ->
- emit_enc_enumerated_cases(L, Tags, noext).
-
-emit_enc_enumerated_cases([{EnumName,EnumVal},H2|T], Tags, Ext) ->
- emit([{asis,EnumName}," -> ?RT_BER:encode_enumerated(",EnumVal,",",Tags,");",nl]),
-%% emit(["'",{asis,EnumName},"' -> ?RT_BER:encode_enumerated(",EnumVal,",",Tags,");",nl]),
- emit_enc_enumerated_cases([H2|T], Tags, Ext);
-emit_enc_enumerated_cases([{EnumName,EnumVal}], Tags, Ext) ->
- emit([{asis,EnumName}," -> ?RT_BER:encode_enumerated(",EnumVal,",",Tags,")"]),
-%% emit(["'",{asis,EnumName},"' -> ?RT_BER:encode_enumerated(",EnumVal,",",Tags,")"]),
- case Ext of
- noext -> emit([";",nl]);
- ext ->
-%% emit([";",nl,"{asn1_enum,",{curr,enumval},"} -> ",
-%% "?RT_BER:encode_enumerated(",{curr,enumval},",",Tags,");",nl]),
-%% asn1ct_name:new(enumval)
- emit([";",nl])
- end,
- emit([{curr,enumval}," -> exit({error,{asn1, {enumerated_not_in_range,",{curr, enumval},"}}})"]),
- emit([nl,"end"]).
-
-
-%%===============================================================================
-%%===============================================================================
-%%===============================================================================
-%% Generate DECODING
-%%===============================================================================
-%%===============================================================================
-%%===============================================================================
-
-%%===============================================================================
-%% decode #{typedef, {pos, name, typespec}}
-%%===============================================================================
-
-gen_decode(Erules,Type) when is_record(Type,typedef) ->
- D = Type,
- emit({nl,nl}),
- emit({"'dec_",Type#typedef.name,"'(Bytes, OptOrMand) ->",nl}),
- emit({" 'dec_",Type#typedef.name,"'(Bytes, OptOrMand, []).",nl,nl}),
- emit({"'dec_",Type#typedef.name,"'(Bytes, ",
- unused_optormand_var("OptOrMand",(Type#typedef.typespec)#type.def),", TagIn) ->",nl}),
- dbdec(Type#typedef.name),
- gen_decode_user(Erules,D).
-
-
-%%===============================================================================
-%% decode #{type, {tag, def, constraint}}
-%%===============================================================================
-
-gen_decode(Erules,Tname,Type) when is_record(Type,type) ->
- Typename = Tname,
- InnerType = asn1ct_gen:get_inner(Type#type.def),
- case asn1ct_gen:type(InnerType) of
- {constructed,bif} ->
- ObjFun =
- case Type#type.tablecinf of
- [{objfun,_}|_R] ->
- ", ObjFun";
- _ ->
- ""
- end,
- emit({"'dec_",asn1ct_gen:list2name(Typename),"'(Bytes, OptOrMand, TagIn",ObjFun,") ->",nl}),
- dbdec(Typename),
- asn1ct_gen:gen_decode_constructed(Erules,Typename,InnerType,Type);
- _ ->
- true
- end;
-
-
-%%===============================================================================
-%% decode ComponentType
-%%===============================================================================
-
-gen_decode(Erules,Tname,#'ComponentType'{name=Cname,typespec=Type}) ->
- NewTname = [Cname|Tname],
- %% The tag is set to [] to avoid that it is
- %% taken into account twice, both as a component/alternative (passed as
- %% argument to the encode decode function and within the encode decode
- %% function it self.
- NewType = Type#type{tag=[]},
- gen_decode(Erules,NewTname,NewType).
-
-
-gen_decode_user(Erules,D) when is_record(D,typedef) ->
- Typename = [D#typedef.name],
- Def = D#typedef.typespec,
- InnerType = asn1ct_gen:get_inner(Def#type.def),
- InnerTag = Def#type.tag ,
- Tag = [X#tag{class=decode_class(X#tag.class)}|| X <- InnerTag],
- case asn1ct_gen:type(InnerType) of
- 'ASN1_OPEN_TYPE' ->
- BytesVar = asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
- asn1ct_name:new(len),
- gen_dec_prim(Erules, Def#type{def='ASN1_OPEN_TYPE'},
- BytesVar, Tag, "TagIn",no_length,
- ?PRIMITIVE,"OptOrMand"),
- emit({".",nl,nl});
- {primitive,bif} ->
- BytesVar = asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
- asn1ct_name:new(len),
- gen_dec_prim(Erules, Def, BytesVar, Tag, "TagIn",no_length,
- ?PRIMITIVE,"OptOrMand"),
- emit({".",nl,nl});
- {constructed,bif} ->
- asn1ct_gen:gen_decode_constructed(Erules,Typename,InnerType,D);
- TheType ->
- DecFunName = mkfuncname(TheType,dec),
- emit({DecFunName,"(",{curr,bytes},
- ", OptOrMand, TagIn++",{asis,Tag},")"}),
- emit({".",nl,nl})
- end.
-
-
-gen_dec_prim(Erules,Att,BytesVar,DoTag,TagIn,Length,Form,OptOrMand) ->
- Typename = Att#type.def,
-%% Currently not used for BER replaced with [] as place holder
-%% Constraint = Att#type.constraint,
-%% Constraint = [],
- Constraint =
- case get_constraint(Att#type.constraint,'SizeConstraint') of
- no -> [];
- Tc -> Tc
- end,
- ValueRange =
- case get_constraint(Att#type.constraint,'ValueRange') of
- no -> [];
- Tv -> Tv
- end,
- SingleValue =
- case get_constraint(Att#type.constraint,'SingleValue') of
- no -> [];
- Sv -> Sv
- end,
- AsBin = case get(binary_strings) of
- true -> "_as_bin";
- _ -> ""
- end,
- NewTypeName = case Typename of
- 'ANY' -> 'ASN1_OPEN_TYPE';
- _ -> Typename
- end,
- DoLength =
- case NewTypeName of
- 'BOOLEAN'->
- emit({"?RT_BER:decode_boolean(",BytesVar,","}),
- false;
- 'INTEGER' ->
- emit({"?RT_BER:decode_integer(",BytesVar,",",
- {asis,int_constr(SingleValue,ValueRange)},","}),
- false;
- {'INTEGER',NamedNumberList} ->
- emit({"?RT_BER:decode_integer(",BytesVar,",",
- {asis,int_constr(SingleValue,ValueRange)},",",
- {asis,NamedNumberList},","}),
- false;
- {'ENUMERATED',NamedNumberList} ->
- emit({"?RT_BER:decode_enumerated(",BytesVar,",",
- {asis,Constraint},",",
- {asis,NamedNumberList},","}),
- false;
- 'REAL' ->
- emit({"?RT_BER:decode_real(",BytesVar,",",
- {asis,Constraint},","}),
- false;
- {'BIT STRING',NamedNumberList} ->
- case get(compact_bit_string) of
- true ->
- emit({"?RT_BER:decode_compact_bit_string(",
- BytesVar,",",{asis,Constraint},",",
- {asis,NamedNumberList},","});
- _ ->
- emit({"?RT_BER:decode_bit_string(",BytesVar,",",
- {asis,Constraint},",",
- {asis,NamedNumberList},","})
- end,
- true;
- 'NULL' ->
- emit({"?RT_BER:decode_null(",BytesVar,","}),
- false;
- 'OBJECT IDENTIFIER' ->
- emit({"?RT_BER:decode_object_identifier(",BytesVar,","}),
- false;
- 'RELATIVE-OID' ->
- emit({"?RT_BER:decode_relative_oid(",BytesVar,","}),
- false;
- 'ObjectDescriptor' ->
- emit({"?RT_BER:decode_restricted_string(",
- BytesVar,",",{asis,Constraint},",",{asis,?T_ObjectDescriptor},","}),
- true;
- 'OCTET STRING' ->
- emit({"?RT_BER:decode_octet_string",AsBin,"(",BytesVar,",",{asis,Constraint},","}),
- true;
- 'NumericString' ->
- emit({"?RT_BER:decode_restricted_string",AsBin,"(",
- BytesVar,",",{asis,Constraint},",",{asis,?T_NumericString},","}),true;
- TString when TString == 'TeletexString';
- TString == 'T61String' ->
- emit({"?RT_BER:decode_restricted_string",AsBin,"(",
- BytesVar,",",{asis,Constraint},",",{asis,?T_TeletexString},","}),
- true;
- 'VideotexString' ->
- emit({"?RT_BER:decode_restricted_string",AsBin,"(",
- BytesVar,",",{asis,Constraint},",",{asis,?T_VideotexString},","}),
- true;
- 'GraphicString' ->
- emit({"?RT_BER:decode_restricted_string",AsBin,"(",
- BytesVar,",",{asis,Constraint},",",{asis,?T_GraphicString},","})
- ,true;
- 'VisibleString' ->
- emit({"?RT_BER:decode_restricted_string",AsBin,"(",
- BytesVar,",",{asis,Constraint},",",{asis,?T_VisibleString},","}),
- true;
- 'GeneralString' ->
- emit({"?RT_BER:decode_restricted_string",AsBin,"(",
- BytesVar,",",{asis,Constraint},",",{asis,?T_GeneralString},","}),
- true;
- 'PrintableString' ->
- emit({"?RT_BER:decode_restricted_string",AsBin,"(",
- BytesVar,",",{asis,Constraint},",",{asis,?T_PrintableString},","}),
- true;
- 'IA5String' ->
- emit({"?RT_BER:decode_restricted_string",AsBin,"(",
- BytesVar,",",{asis,Constraint},",",{asis,?T_IA5String},","}),
- true;
- 'UniversalString' ->
- emit({"?RT_BER:decode_universal_string",AsBin,"(",
- BytesVar,",",{asis,Constraint},","}),
- true;
- 'UTF8String' ->
- emit({"?RT_BER:decode_UTF8_string",AsBin,"(",
- BytesVar,","}),
- false;
- 'BMPString' ->
- emit({"?RT_BER:decode_BMP_string",AsBin,"(",
- BytesVar,",",{asis,Constraint},","}),
- true;
- 'UTCTime' ->
- emit({"?RT_BER:decode_utc_time",AsBin,"(",
- BytesVar,",",{asis,Constraint},","}),
- true;
- 'GeneralizedTime' ->
- emit({"?RT_BER:decode_generalized_time",AsBin,"(",
- BytesVar,",",{asis,Constraint},","}),
- true;
- 'ASN1_OPEN_TYPE' ->
- emit(["?RT_BER:decode_open_type(",re_wrap_erule(Erules),",",
- BytesVar,","]),
- false;
- #'ObjectClassFieldType'{} ->
- case asn1ct_gen:get_inner(Att#type.def) of
- {fixedtypevaluefield,_,InnerType} ->
- gen_dec_prim(Erules,InnerType,BytesVar,DoTag,TagIn,Length,Form,OptOrMand),
- false;
- 'ASN1_OPEN_TYPE' ->
- emit(["?RT_BER:decode_open_type(",
- re_wrap_erule(Erules),",",
- BytesVar,","]),
- false;
- XX ->
- exit({'can not decode' ,XX})
- end;
- Other ->
- exit({'can not decode' ,Other})
- end,
-
- NewLength = case DoLength of
- true -> [", ", Length];
- false -> ""
- end,
- NewOptOrMand = case OptOrMand of
- _ when is_list(OptOrMand) -> OptOrMand;
- mandatory -> {asis,mandatory};
- _ -> {asis,opt_or_default}
- end,
- case {TagIn,NewTypeName} of
- {_,#'ObjectClassFieldType'{}} ->
- case asn1ct_gen:get_inner(Att#type.def) of
- 'ASN1_OPEN_TYPE' ->
- emit([{asis,DoTag},")"]);
- _ -> ok
- end;
- {[],'ASN1_OPEN_TYPE'} ->
- emit([{asis,DoTag},")"]);
- {_,'ASN1_OPEN_TYPE'} ->
- emit([TagIn,"++",{asis,DoTag},")"]);
- {[],_} ->
- emit([{asis,DoTag},NewLength,", ",NewOptOrMand,")"]);
- _ when is_list(TagIn) ->
- emit([TagIn,"++",{asis,DoTag},NewLength,", ",NewOptOrMand,")"])
- end.
-
-
-int_constr([],[]) ->
- [];
-int_constr([],ValueRange) ->
- ValueRange;
-int_constr(SingleValue,[]) ->
- SingleValue;
-int_constr(SV,VR) ->
- [SV,VR].
-
-%% Object code generating for encoding and decoding
-%% ------------------------------------------------
-
-gen_obj_code(Erules,_Module,Obj) when is_record(Obj,typedef) ->
- ObjName = Obj#typedef.name,
- Def = Obj#typedef.typespec,
- #'Externaltypereference'{module=M,type=ClName} = Def#'Object'.classname,
- Class = asn1_db:dbget(M,ClName),
-
- {object,_,Fields} = Def#'Object'.def,
- emit({nl,nl,nl,"%%================================"}),
- emit({nl,"%% ",ObjName}),
- emit({nl,"%%================================",nl}),
- EncConstructed =
- gen_encode_objectfields(ClName,get_class_fields(Class),
- ObjName,Fields,[]),
- emit(nl),
- gen_encode_constr_type(Erules,EncConstructed),
- emit(nl),
- DecConstructed =
- gen_decode_objectfields(ClName,get_class_fields(Class),
- ObjName,Fields,[]),
- emit(nl),
- gen_decode_constr_type(Erules,DecConstructed);
-gen_obj_code(_Erules,_Module,Obj) when is_record(Obj,pobjectdef) ->
- ok.
-
-
-gen_encode_objectfields(ClassName,[{typefield,Name,OptOrMand}|Rest],
- ObjName,ObjectFields,ConstrAcc) ->
- EmitFuncClause =
- fun(Args) ->
- emit(["'enc_",ObjName,"'(",{asis,Name},
- ", ",Args,", _RestPrimFieldName) ->",nl])
- end,
-% emit(["'enc_",ObjName,"'(",{asis,Name},
-% ", Val, TagIn, _RestPrimFieldName) ->",nl]),
- MaybeConstr=
- case {get_object_field(Name,ObjectFields),OptOrMand} of
- {false,'MANDATORY'} -> %% this case is illegal
- exit({error,{asn1,{"missing mandatory field in object",
- ObjName}}});
- {false,'OPTIONAL'} -> %% OPTIONAL field in class
- EmitFuncClause("Val, _"), %% Value must be anything
- %% already encoded
- emit([" {Val,0}"]),
- [];
- {false,{'DEFAULT',DefaultType}} ->
- EmitFuncClause("Val, TagIn"),
- gen_encode_default_call(ClassName,Name,DefaultType);
- {{Name,TypeSpec},_} ->
- %% A specified field owerwrites any 'DEFAULT' or
- %% 'OPTIONAL' field in the class
- EmitFuncClause("Val, TagIn"),
- gen_encode_field_call(ObjName,Name,TypeSpec)
- end,
- case more_genfields(Rest) of
- true ->
- emit([";",nl]);
- false ->
- emit([".",nl])
- end,
- gen_encode_objectfields(ClassName,Rest,ObjName,ObjectFields,
- MaybeConstr++ConstrAcc);
-gen_encode_objectfields(ClassName,[{objectfield,Name,_,_,OptOrMand}|Rest],
- ObjName,ObjectFields,ConstrAcc) ->
- CurrentMod = get(currmod),
- EmitFuncClause =
- fun(Args) ->
- emit(["'enc_",ObjName,"'(",{asis,Name},
- ", ",Args,") ->",nl])
- end,
-% emit(["'enc_",ObjName,"'(",{asis,Name},
-% ", Val, TagIn, [H|T]) ->",nl]),
- case {get_object_field(Name,ObjectFields),OptOrMand} of
- {false,'MANDATORY'} ->
- exit({error,{asn1,{"missing mandatory field in object",
- ObjName}}});
- {false,'OPTIONAL'} ->
- EmitFuncClause("_,_,_"),
- emit([" exit({error,{'use of missing field in object', ",{asis,Name},
- "}})"]);
- {false,{'DEFAULT',_DefaultObject}} ->
- exit({error,{asn1,{"not implemented yet",Name}}});
- {{Name,#'Externalvaluereference'{module=CurrentMod,
- value=TypeName}},_} ->
- EmitFuncClause(" Val, TagIn, [H|T]"),
- emit({indent(3),"'enc_",TypeName,"'(H, Val, TagIn, T)"});
- {{Name,#'Externalvaluereference'{module=M,value=TypeName}},_} ->
- EmitFuncClause(" Val, TagIn, [H|T]"),
- emit({indent(3),"'",M,"':'enc_",TypeName,"'(H, Val, TagIn, T)"});
- {{Name,TypeSpec},_} ->
- EmitFuncClause(" Val, TagIn, [H|T]"),
- case TypeSpec#typedef.name of
- {ExtMod,TypeName} ->
- emit({indent(3),"'",ExtMod,"':'enc_",TypeName,
- "'(H, Val, TagIn, T)"});
- TypeName ->
- emit({indent(3),"'enc_",TypeName,"'(H, Val, TagIn, T)"})
- end
- end,
- case more_genfields(Rest) of
- true ->
- emit([";",nl]);
- false ->
- emit([".",nl])
- end,
- gen_encode_objectfields(ClassName,Rest,ObjName,ObjectFields,ConstrAcc);
-gen_encode_objectfields(ClassName,[_|Cs],O,OF,Acc) ->
- gen_encode_objectfields(ClassName,Cs,O,OF,Acc);
-gen_encode_objectfields(_,[],_,_,Acc) ->
- Acc.
-
-
-% gen_encode_objectfields(Class,ObjName,[{FieldName,Type}|Rest],ConstrAcc) ->
-% Fields = Class#objectclass.fields,
-% MaybeConstr=
-% case is_typefield(Fields,FieldName) of
-% true ->
-% Def = Type#typedef.typespec,
-% OTag = Def#type.tag,
-% Tag = [X#tag{class=decode_class(X#tag.class)}|| X <- OTag],
-% emit({"'enc_",ObjName,"'(",{asis,FieldName},
-% ", Val, TagIn, RestPrimFieldName) ->",nl}),
-% CAcc=
-% case Type#typedef.name of
-% {primitive,bif} ->
-% gen_encode_prim(ber,Def,["TagIn ++ ",{asis,Tag}],
-% "Val"),
-% [];
-% {constructed,bif} ->
-% %%InnerType = asn1ct_gen:get_inner(Def#type.def),
-% %%asn1ct_gen:gen_encode_constructed(ber,[ObjName],
-% %% InnerType,Def);
-% emit({" 'enc_",ObjName,'_',FieldName,
-% "'(Val, TagIn ++ ",{asis,Tag},")"}),
-% [{['enc_',ObjName,'_',FieldName],Def}];
-% {ExtMod,TypeName} ->
-% emit({" '",ExtMod,"':'enc_",TypeName,
-% "'(Val, TagIn ++ ",{asis,Tag},")"}),
-% [];
-% TypeName ->
-% emit({" 'enc_",TypeName,"'(Val, TagIn ++ ",
-% {asis,Tag},")"}),
-% []
-% end,
-% case more_genfields(Fields,Rest) of
-% true ->
-% emit({";",nl});
-% false ->
-% emit({".",nl})
-% end,
-% CAcc;
-% {false,objectfield} ->
-% emit({"'enc_",ObjName,"'(",{asis,FieldName},
-% ", Val, TagIn, [H|T]) ->",nl}),
-% case Type#typedef.name of
-% {ExtMod,TypeName} ->
-% emit({indent(3),"'",ExtMod,"':'enc_",TypeName,
-% "'(H, Val, TagIn, T)"});
-% TypeName ->
-% emit({indent(3),"'enc_",TypeName,"'(H, Val, TagIn, T)"})
-% end,
-% case more_genfields(Fields,Rest) of
-% true ->
-% emit({";",nl});
-% false ->
-% emit({".",nl})
-% end,
-% [];
-% {false,_} -> []
-% end,
-% gen_encode_objectfields(Class,ObjName,Rest,MaybeConstr ++ ConstrAcc);
-% gen_encode_objectfields(C,O,[H|T],Acc) ->
-% gen_encode_objectfields(C,O,T,Acc);
-% gen_encode_objectfields(_,_,[],Acc) ->
-% Acc.
-
-% gen_encode_constr_type([{Name,Def}|Rest]) ->
-% emit({Name,"(Val,TagIn) ->",nl}),
-% InnerType = asn1ct_gen:get_inner(Def#type.def),
-% asn1ct_gen:gen_encode_constructed(ber,Name,InnerType,Def),
-% gen_encode_constr_type(Rest);
-gen_encode_constr_type(Erules,[TypeDef|Rest]) when is_record(TypeDef,typedef) ->
- case is_already_generated(enc,TypeDef#typedef.name) of
- true -> ok;
- _ -> gen_encode_user(Erules,TypeDef)
- end,
- gen_encode_constr_type(Erules,Rest);
-gen_encode_constr_type(_,[]) ->
- ok.
-
-gen_encode_field_call(_ObjName,_FieldName,
- #'Externaltypereference'{module=M,type=T}) ->
- CurrentMod = get(currmod),
- TDef = asn1_db:dbget(M,T),
- Def = TDef#typedef.typespec,
- OTag = Def#type.tag,
- Tag = [X#tag{class=decode_class(X#tag.class)}|| X <- OTag],
- if
- M == CurrentMod ->
- emit({" 'enc_",T,"'(Val, TagIn ++ ",{asis,Tag},")"}),
- [];
- true ->
- emit({" '",M,"':'enc_",T,"'(Val, TagIn ++ ",{asis,Tag},")"}),
- []
- end;
-gen_encode_field_call(ObjName,FieldName,Type) ->
- Def = Type#typedef.typespec,
- OTag = Def#type.tag,
- Tag = [X#tag{class=decode_class(X#tag.class)}|| X <- OTag],
- case Type#typedef.name of
- {primitive,bif} -> %%tag should be the primitive tag
- gen_encode_prim(ber,Def,["TagIn ++ ",{asis,Tag}],
- "Val"),
- [];
- {constructed,bif} ->
- emit({" 'enc_",ObjName,'_',FieldName,
- "'(Val, TagIn ++",{asis,Tag},")"}),
- [Type#typedef{name=list_to_atom(lists:concat([ObjName,'_',FieldName]))}];
- {ExtMod,TypeName} ->
- emit({" '",ExtMod,"':'enc_",TypeName,
- "'(Val, TagIn ++ ",{asis,Tag},")"}),
- [];
- TypeName ->
- emit({" 'enc_",TypeName,"'(Val, TagIn ++ ",{asis,Tag},")"}),
- []
- end.
-
-gen_encode_default_call(ClassName,FieldName,Type) ->
- CurrentMod = get(currmod),
- InnerType = asn1ct_gen:get_inner(Type#type.def),
- OTag = Type#type.tag,
- Tag = [X#tag{class=decode_class(X#tag.class)}|| X <- OTag],
- case asn1ct_gen:type(InnerType) of
- {constructed,bif} ->
-%% asn1ct_gen:gen_encode_constructed(Erules,Typename,InnerType,Type);
- emit([" 'enc_",ClassName,'_',FieldName,"'(Bytes, TagIn ++ ",
- {asis,Tag},")"]),
- [#typedef{name=list_to_atom(lists:concat([ClassName,'_',FieldName])),
- typespec=Type}];
- {primitive,bif} ->
- gen_encode_prim(ber,Type,["TagIn ++ ",{asis,Tag}],"Val"),
- [];
- #'Externaltypereference'{module=CurrentMod,type=Etype} ->
- emit([" 'enc_",Etype,"'(Val, TagIn ++ ",{asis,Tag},")",nl]),
- [];
- #'Externaltypereference'{module=Emod,type=Etype} ->
- emit([" '",Emod,"':'enc_",Etype,"'(Val, TagIn ++ ",{asis,Tag},")",nl]),
- []
- end.
-
-
-
-gen_decode_objectfields(ClassName,[{typefield,Name,OptOrMand}|Rest],
- ObjName,ObjectFields,ConstrAcc) ->
- EmitFuncClause =
- fun(Args) ->
- emit(["'dec_",ObjName,"'(",{asis,Name},
- ", ",Args,"_) ->",nl])
- end,
-% emit(["'dec_",ObjName,"'(",{asis,Name},
-% ", Bytes, TagIn, RestPrimFieldName) ->",nl]),
- MaybeConstr=
- case {get_object_field(Name,ObjectFields),OptOrMand} of
- {false,'MANDATORY'} -> %% this case is illegal
- exit({error,{asn1,{"missing mandatory field in object",
- ObjName}}});
- {false,'OPTIONAL'} ->
- EmitFuncClause("Bytes, _,"),
-% emit([" asn1_NOVALUE"]),
- emit([" {Bytes,[],0}"]),
- [];
- {false,{'DEFAULT',DefaultType}} ->
- EmitFuncClause("Bytes, TagIn,"),
- gen_decode_default_call(ClassName,Name,"Bytes",DefaultType);
- {{Name,TypeSpec},_} ->
- %% A specified field owerwrites any 'DEFAULT' or
- %% 'OPTIONAL' field in the class
- EmitFuncClause("Bytes, TagIn,"),
- gen_decode_field_call(ObjName,Name,"Bytes",TypeSpec)
- end,
- case more_genfields(Rest) of
- true ->
- emit([";",nl]);
- false ->
- emit([".",nl])
- end,
- gen_decode_objectfields(ClassName,Rest,ObjName,ObjectFields,MaybeConstr++ConstrAcc);
-gen_decode_objectfields(ClassName,[{objectfield,Name,_,_,OptOrMand}|Rest],
- ObjName,ObjectFields,ConstrAcc) ->
- CurrentMod = get(currmod),
- EmitFuncClause =
- fun(Args) ->
- emit(["'dec_",ObjName,"'(",{asis,Name},
- ", ",Args,") ->",nl])
- end,
-% emit(["'dec_",ObjName,"'(",{asis,Name},
-% ", Bytes,TagIn,[H|T]) ->",nl]),
- case {get_object_field(Name,ObjectFields),OptOrMand} of
- {false,'MANDATORY'} ->
- exit({error,{asn1,{"missing mandatory field in object",
- ObjName}}});
- {false,'OPTIONAL'} ->
- EmitFuncClause("_,_,_"),
- emit([" exit({error,{'illegal use of missing field in object', ",{asis,Name},
- "}})"]);
- {false,{'DEFAULT',_DefaultObject}} ->
- exit({error,{asn1,{"not implemented yet",Name}}});
- {{Name,#'Externalvaluereference'{module=CurrentMod,
- value=TypeName}},_} ->
- EmitFuncClause("Bytes,TagIn,[H|T]"),
- emit({indent(3),"'dec_",TypeName,"'(H, Bytes, TagIn, T)"});
- {{Name,#'Externalvaluereference'{module=M,value=TypeName}},_} ->
- EmitFuncClause("Bytes,TagIn,[H|T]"),
- emit({indent(3),"'",M,"':'dec_",TypeName,
- "'(H, Bytes, TagIn, T)"});
- {{Name,TypeSpec},_} ->
- EmitFuncClause("Bytes,TagIn,[H|T]"),
- case TypeSpec#typedef.name of
- {ExtMod,TypeName} ->
- emit({indent(3),"'",ExtMod,"':'dec_",TypeName,
- "'(H, Bytes, TagIn, T)"});
- TypeName ->
- emit({indent(3),"'dec_",TypeName,"'(H, Bytes, TagIn, T)"})
- end
- end,
- case more_genfields(Rest) of
- true ->
- emit([";",nl]);
- false ->
- emit([".",nl])
- end,
- gen_decode_objectfields(ClassName,Rest,ObjName,ObjectFields,ConstrAcc);
-gen_decode_objectfields(CN,[_|Cs],O,OF,CAcc) ->
- gen_decode_objectfields(CN,Cs,O,OF,CAcc);
-gen_decode_objectfields(_,[],_,_,CAcc) ->
- CAcc.
-
-
-gen_decode_constr_type(Erules,[TypeDef|Rest]) when is_record(TypeDef,typedef) ->
- case is_already_generated(dec,TypeDef#typedef.name) of
- true -> ok;
- _ ->
- gen_decode(Erules,TypeDef)
- end,
- gen_decode_constr_type(Erules,Rest);
-gen_decode_constr_type(_,[]) ->
- ok.
-
-gen_decode_field_call(_ObjName,_FieldName,Bytes,
- #'Externaltypereference'{module=M,type=T}) ->
- CurrentMod = get(currmod),
- TDef = asn1_db:dbget(M,T),
- Def = TDef#typedef.typespec,
- OTag = Def#type.tag,
- Tag = [X#tag{class=decode_class(X#tag.class)}|| X <- OTag],
- if
- M == CurrentMod ->
- emit({" 'dec_",T,"'(",Bytes,
- ", opt_or_default,TagIn ++ ",{asis,Tag},")"}),
- [];
- true ->
- emit({" '",M,"':'dec_",T,
- "'(",Bytes,", opt_or_default,TagIn ++ ",{asis,Tag},")"}),
- []
- end;
-gen_decode_field_call(ObjName,FieldName,Bytes,Type) ->
- Def = Type#typedef.typespec,
- OTag = Def#type.tag,
- Tag = [X#tag{class=decode_class(X#tag.class)}|| X <- OTag],
- case Type#typedef.name of
- {primitive,bif} -> %%tag should be the primitive tag
- gen_dec_prim(ber,Def,Bytes,Tag,"TagIn",no_length,
- ?PRIMITIVE,opt_or_default),
- [];
- {constructed,bif} ->
- emit({" 'dec_",ObjName,'_',FieldName,
- "'(",Bytes,",opt_or_default, TagIn ++ ",{asis,Tag},")"}),
- [Type#typedef{name=list_to_atom(lists:concat([ObjName,'_',FieldName]))}];
- {ExtMod,TypeName} ->
- emit({" '",ExtMod,"':'dec_",TypeName,
- "'(",Bytes,", opt_or_default,TagIn ++ ",{asis,Tag},")"}),
- [];
- TypeName ->
- emit({" 'dec_",TypeName,"'(",Bytes,
- ", opt_or_default,TagIn ++ ",{asis,Tag},")"}),
- []
- end.
-
-gen_decode_default_call(ClassName,FieldName,Bytes,Type) ->
- CurrentMod = get(currmod),
- InnerType = asn1ct_gen:get_inner(Type#type.def),
- OTag = Type#type.tag,
- Tag = [X#tag{class=decode_class(X#tag.class)}|| X <- OTag],
- case asn1ct_gen:type(InnerType) of
- {constructed,bif} ->
- emit([" 'dec_",ClassName,'_',FieldName,"'(",Bytes,
- ",opt_or_default, TagIn ++ ",{asis,Tag},")"]),
- [#typedef{name=list_to_atom(lists:concat([ClassName,'_',FieldName])),
- typespec=Type}];
- {primitive,bif} ->
- gen_dec_prim(ber,Type,Bytes,Tag,"TagIn",no_length,
- ?PRIMITIVE,opt_or_default),
- [];
- #'Externaltypereference'{module=CurrentMod,type=Etype} ->
- emit([" 'dec_",Etype,"'(",Bytes,
- " ,opt_or_default, TagIn ++ ",{asis,Tag},")",nl]),
- [];
- #'Externaltypereference'{module=Emod,type=Etype} ->
- emit([" '",Emod,"':'dec_",Etype,"'(",Bytes,
- ", opt_or_defualt, TagIn ++ ",{asis,Tag},")",nl]),
- []
- end.
-
-
-more_genfields([]) ->
- false;
-more_genfields([Field|Fields]) ->
- case element(1,Field) of
- typefield ->
- true;
- objectfield ->
- true;
- _ ->
- more_genfields(Fields)
- end.
-
-
-
-%% Object Set code generating for encoding and decoding
-%% ----------------------------------------------------
-gen_objectset_code(Erules,ObjSet) ->
- ObjSetName = ObjSet#typedef.name,
- Def = ObjSet#typedef.typespec,
-% {ClassName,ClassDef} = Def#'ObjectSet'.class,
- #'Externaltypereference'{module=ClassModule,
- type=ClassName} = Def#'ObjectSet'.class,
- ClassDef = asn1_db:dbget(ClassModule,ClassName),
- UniqueFName = Def#'ObjectSet'.uniquefname,
- Set = Def#'ObjectSet'.set,
- emit({nl,nl,nl,"%%================================"}),
- emit({nl,"%% ",ObjSetName}),
- emit({nl,"%%================================",nl}),
- case ClassName of
- {_Module,ExtClassName} ->
- gen_objset_code(Erules,ObjSetName,UniqueFName,Set,
- ExtClassName,ClassDef);
- _ ->
- gen_objset_code(Erules,ObjSetName,UniqueFName,Set,
- ClassName,ClassDef)
- end,
- emit(nl).
-
-gen_objset_code(Erules,ObjSetName,UniqueFName,Set,ClassName,ClassDef)->
- ClassFields = (ClassDef#classdef.typespec)#objectclass.fields,
- InternalFuncs=gen_objset_enc(ObjSetName,UniqueFName,Set,ClassName,ClassFields,1,[]),
- gen_objset_dec(Erules,ObjSetName,UniqueFName,Set,ClassName,ClassFields,1),
- gen_internal_funcs(Erules,InternalFuncs).
-
-
-%% gen_objset_enc iterates over the objects of the object set
-gen_objset_enc(_,{unique,undefined},_,_,_,_,_) ->
- %% There is no unique field in the class of this object set
- %% don't bother about the constraint
- [];
-gen_objset_enc(ObjSName,UniqueName,[{_,no_unique_value,_},T|Rest],
- ClName,ClFields,NthObj,Acc) ->
- %% No need to check that this class has property OPTIONAL for the
- %% unique field, it was detected in the previous phase
- gen_objset_enc(ObjSName,UniqueName,[T|Rest],ClName,ClFields,NthObj,Acc);
-gen_objset_enc(ObjSetName,UniqueName,[{_,no_unique_value,_}],
- _ClName,_ClFields,_NthObj,Acc) ->
- %% No need to check that this class has property OPTIONAL for the
- %% unique field, it was detected in the previous phase
- emit_default_getenc(ObjSetName,UniqueName),
- emit({".",nl,nl}),
- Acc;
-gen_objset_enc(ObjSName,UniqueName,
- [{ObjName,Val,Fields},T|Rest],ClName,ClFields,NthObj,Acc)->
- emit({"'getenc_",ObjSName,"'(",{asis,UniqueName},",",{asis,Val},") ->",nl}),
- CurrMod = get(currmod),
- {InternalFunc,NewNthObj}=
- case ObjName of
- {no_mod,no_name} ->
- gen_inlined_enc_funs(Fields,ClFields,ObjSName,NthObj);
- {CurrMod,Name} ->
- emit({" fun 'enc_",Name,"'/4"}),
- {[],NthObj};
- {ModuleName,Name} ->
- emit_ext_fun(enc,ModuleName,Name),
-% emit([" {'",ModuleName,"', 'enc_",Name,"'}"]),
- {[],NthObj};
- _Other ->
- emit({" fun 'enc_",ObjName,"'/4"}),
- {[],NthObj}
- end,
- emit({";",nl}),
- gen_objset_enc(ObjSName,UniqueName,[T|Rest],ClName,ClFields,
- NewNthObj,InternalFunc ++ Acc);
-gen_objset_enc(ObjSetName,UniqueName,
- [{ObjName,Val,Fields}],_ClName,ClFields,NthObj,Acc) ->
- emit({"'getenc_",ObjSetName,"'(",{asis,UniqueName},",",{asis,Val},") ->",nl}),
- CurrMod = get(currmod),
- {InternalFunc,_}=
- case ObjName of
- {no_mod,no_name} ->
- gen_inlined_enc_funs(Fields,ClFields,ObjSetName,NthObj);
- {CurrMod,Name} ->
- emit({" fun 'enc_",Name,"'/4"}),
- {[],NthObj};
- {ModuleName,Name} ->
- emit_ext_fun(enc,ModuleName,Name),
-% emit([" {'",ModuleName,"', 'enc_",Name,"'}"]),
- {[],NthObj};
- _Other ->
- emit({" fun 'enc_",ObjName,"'/4"}),
- {[],NthObj}
- end,
- emit([";",nl]),
- emit_default_getenc(ObjSetName,UniqueName),
- emit({".",nl,nl}),
- InternalFunc ++ Acc;
-%% See X.681 Annex E for the following case
-gen_objset_enc(ObjSetName,_UniqueName,['EXTENSIONMARK'],
- _ClName,_ClFields,_NthObj,Acc) ->
- emit({"'getenc_",ObjSetName,"'(_, _) ->",nl}),
- emit({indent(3),"fun(_Attr, Val, _TagIn, _RestPrimFieldName) ->",nl}),
- emit({indent(6),"Len = case Val of",nl,indent(9),
- "Bin when is_binary(Bin) -> size(Bin);",nl,indent(9),
- "_ -> length(Val)",nl,indent(6),"end,"}),
- emit({indent(6),"{Val,Len}",nl}),
- emit({indent(3),"end.",nl,nl}),
- Acc;
-gen_objset_enc(ObjSetName,UniqueName,['EXTENSIONMARK','EXTENSIONMARK'|Rest],
- ClName,ClFields,NthObj,Acc) ->
- gen_objset_enc(ObjSetName,UniqueName,['EXTENSIONMARK'|Rest],
- ClName,ClFields,NthObj,Acc);
-gen_objset_enc(ObjSetName,UniqueName,['EXTENSIONMARK'|Rest],
- ClName,ClFields,NthObj,Acc) ->
- gen_objset_enc(ObjSetName,UniqueName,Rest++['EXTENSIONMARK'],
- ClName,ClFields,NthObj,Acc);
-gen_objset_enc(_,_,[],_,_,_,Acc) ->
- Acc.
-
-emit_ext_fun(EncDec,ModuleName,Name) ->
- emit([indent(3),"fun(T,V,_O1,_O2) -> '",ModuleName,"':'",EncDec,"_",
- Name,"'(T,V,_O1,_O2) end"]).
-
-emit_default_getenc(ObjSetName,UniqueName) ->
- emit(["'getenc_",ObjSetName,"'(",{asis,UniqueName},", ErrV) ->",nl]),
- emit([indent(3),"fun(C,V,_,_) -> exit({'Type not compatible with table constraint',{component,C},{value,V}, {unique_name_and_value,",{asis,UniqueName},", ErrV}}) end"]).
-
-%% gen_inlined_enc_funs for each object iterates over all fields of a
-%% class, and for each typefield it checks if the object has that
-%% field and emits the proper code.
-gen_inlined_enc_funs(Fields,[{typefield,Name,_}|Rest],ObjSetName,
- NthObj) ->
- CurrMod = get(currmod),
- InternalDefFunName = asn1ct_gen:list2name([NthObj,Name,ObjSetName]),
- case lists:keysearch(Name,1,Fields) of
- {value,{_,Type}} when is_record(Type,type) ->
- emit({indent(3),"fun(Type, Val, TagIn, _RestPrimFieldName) ->",nl,
- indent(6),"case Type of",nl}),
- {Ret,N} = emit_inner_of_fun(Type,InternalDefFunName),
- gen_inlined_enc_funs1(Fields,Rest,ObjSetName,NthObj+N,Ret);
- {value,{_,Type}} when is_record(Type,typedef) ->
- emit({indent(3),"fun(Type, Val, TagIn, _RestPrimFieldName) ->",nl,
- indent(6),"case Type of",nl}),
- emit({indent(9),{asis,Name}," ->",nl}),
- {Ret,N} = emit_inner_of_fun(Type,InternalDefFunName),
- gen_inlined_enc_funs1(Fields,Rest,ObjSetName,NthObj+N,Ret);
- {value,{_,#'Externaltypereference'{module=M,type=T}}} ->
- #typedef{typespec=Type} = asn1_db:dbget(M,T),
- OTag = Type#type.tag,
- Tag = [X#tag{class=decode_class(X#tag.class)}|| X <- OTag],
- emit([indent(3),"fun(Type, Val, TagIn, _RestPrimFieldName) ->",nl,
- indent(6),"case Type of",nl]),
- emit([indent(9),{asis,Name}," ->",nl]),
- if
- M == CurrMod ->
- emit([indent(12),"'enc_",T,"'(Val, TagIn ++ ",
- {asis,Tag},")"]);
- true ->
- emit([indent(12),"'",M,"':'enc_",T,"'(Val,TagIn ++",
- {asis,Tag},")"])
- end,
- gen_inlined_enc_funs1(Fields,Rest,ObjSetName,NthObj,[]);
- false ->
- %% This field was not present in the object thus there were no
- %% type in the table and we therefore generate code that returns
- %% the input for application treatment.
- emit([indent(3),"fun(Type, Val, TagIn, _RestPrimFieldName) ->",nl,
- indent(6),"case Type of",nl]),
- emit([indent(9),{asis,Name}," ->",nl]),
- emit([indent(12),"Len = case Val of",nl,
- indent(15),"Bin when is_binary(Bin) -> size(Bin);",nl,
- indent(15),"_ -> length(Val)",nl,indent(12),"end,",nl,
- indent(12),"{Val,Len}"]),
- gen_inlined_enc_funs1(Fields,Rest,ObjSetName,NthObj,[])
- end;
-gen_inlined_enc_funs(Fields,[_H|Rest],ObjSetName,NthObj) ->
- gen_inlined_enc_funs(Fields,Rest,ObjSetName,NthObj);
-gen_inlined_enc_funs(_,[],_,NthObj) ->
- {[],NthObj}.
-
-gen_inlined_enc_funs1(Fields,[{typefield,Name,_}|Rest],ObjSetName,
- NthObj,Acc) ->
- CurrMod = get(currmod),
- InternalDefFunName = asn1ct_gen:list2name([NthObj,Name,ObjSetName]),
- {Acc2,NAdd}=
- case lists:keysearch(Name,1,Fields) of
- {value,{_,Type}} when is_record(Type,type) ->
- emit({";",nl}),
- {Ret,N}=emit_inner_of_fun(Type,InternalDefFunName),
- {Ret++Acc,N};
- {value,{_,Type}} when is_record(Type,typedef) ->
- emit({";",nl,indent(9),{asis,Name}," ->",nl}),
- {Ret,N}=emit_inner_of_fun(Type,InternalDefFunName),
- {Ret++Acc,N};
- {value,{_,#'Externaltypereference'{module=M,type=T}}} ->
- #typedef{typespec=Type} = asn1_db:dbget(M,T),
- OTag = Type#type.tag,
- Tag = [X#tag{class=decode_class(X#tag.class)}|| X <- OTag],
- emit({";",nl,indent(9),{asis,Name}," ->",nl}),
- if
- M == CurrMod ->
- emit([indent(12),"'enc_",T,"'(Val, TagIn ++ ",
- {asis,Tag},")"]);
- true ->
- emit([indent(12),"'",M,"':'enc_",T,"'(Val,TagIn ++",
- {asis,Tag},")"])
- end,
- {Acc,0};
- false ->
- %% This field was not present in the object thus there were no
- %% type in the table and we therefore generate code that returns
- %% the input for application treatment.
- emit([";",nl,indent(9),{asis,Name}," ->",nl]),
- emit([indent(12),"Len = case Val of",nl,
- indent(15),"Bin when is_binary(Bin) -> size(Bin);",nl,
- indent(15),"_ -> length(Val)",nl,indent(12),"end,",nl,
- indent(12),"{Val,Len}"]),
- {Acc,0}
- end,
- gen_inlined_enc_funs1(Fields,Rest,ObjSetName,NthObj+NAdd,Acc2);
-gen_inlined_enc_funs1(Fields,[_H|Rest],ObjSetName,NthObj,Acc)->
- gen_inlined_enc_funs1(Fields,Rest,ObjSetName,NthObj,Acc);
-gen_inlined_enc_funs1(_,[],_,NthObj,Acc) ->
- emit({nl,indent(6),"end",nl}),
- emit({indent(3),"end"}),
- {Acc,NthObj}.
-
-
-emit_inner_of_fun(TDef = #typedef{name={ExtMod,Name},typespec=Type},
- InternalDefFunName) ->
- OTag = Type#type.tag,
- Tag = [X#tag{class=decode_class(X#tag.class)}|| X <- OTag],
- case {ExtMod,Name} of
- {primitive,bif} ->
- emit(indent(12)),
- gen_encode_prim(ber,Type,["TagIn ++ ",{asis,Tag}],"Val"),
- {[],0};
- {constructed,bif} ->
- emit([indent(12),"'enc_",
- InternalDefFunName,"'(Val,TagIn ++ ",
- {asis,Tag},")"]),
- {[TDef#typedef{name=InternalDefFunName}],1};
- _ ->
- emit({indent(12),"'",ExtMod,"':'enc_",Name,"'(Val, TagIn ++ ",
- {asis,Tag},")"}),
- {[],0}
- end;
-emit_inner_of_fun(#typedef{name=Name,typespec=Type},_) ->
- OTag = Type#type.tag,
- Tag = [X#tag{class=decode_class(X#tag.class)}|| X <- OTag],
- emit({indent(12),"'enc_",Name,"'(Val, TagIn ++ ",{asis,Tag},")"}),
- {[],0};
-emit_inner_of_fun(Type,_) when is_record(Type,type) ->
- CurrMod = get(currmod),
- OTag = Type#type.tag,
- Tag = [X#tag{class=decode_class(X#tag.class)}|| X <- OTag],
- case Type#type.def of
- Def when is_atom(Def) ->
- emit({indent(9),Def," ->",nl,indent(12)}),
- gen_encode_prim(ber,Type,["TagIn ++ ",{asis,Tag}],"Val");
- TRef when is_record(TRef,typereference) ->
- T = TRef#typereference.val,
- emit({indent(9),T," ->",nl,indent(12),"'enc_",T,
- "'(Val, TagIn ++ ",{asis,Tag},")"});
- #'Externaltypereference'{module=CurrMod,type=T} ->
- emit({indent(9),T," ->",nl,indent(12),"'enc_",T,
- "'(Val, TagIn ++ ",{asis,Tag},")"});
- #'Externaltypereference'{module=ExtMod,type=T} ->
- emit({indent(9),T," ->",nl,indent(12),ExtMod,":'enc_",
- T,"'(Val, TagIn ++ ",{asis,Tag},")"})
- end,
- {[],0}.
-
-indent(N) ->
- lists:duplicate(N,32). % 32 = space
-
-
-gen_objset_dec(_,_,{unique,undefined},_,_,_,_) ->
- %% There is no unique field in the class of this object set
- %% don't bother about the constraint
- ok;
-gen_objset_dec(Erules,ObjSName,UniqueName,[{_,no_unique_value,_},T|Rest],
- ClName,ClFields,NthObj)->
- gen_objset_dec(Erules,ObjSName,UniqueName,[T|Rest],ClName,ClFields,
- NthObj);
-gen_objset_dec(_Erules,ObjSetName,UniqueName,[{_,no_unique_value,_}],
- _ClName,_ClFields,_NthObj)->
- emit_default_getdec(ObjSetName,UniqueName),
- emit({".",nl,nl});
-gen_objset_dec(Erules,ObjSName,UniqueName,[{ObjName,Val,Fields},T|Rest],
- ClName,ClFields,NthObj)->
- emit({"'getdec_",ObjSName,"'(",{asis,UniqueName},",",{asis,Val},
- ") ->",nl}),
- CurrMod = get(currmod),
- NewNthObj=
- case ObjName of
- {no_mod,no_name} ->
- gen_inlined_dec_funs(Erules,Fields,ClFields,ObjSName,
- NthObj);
- {CurrMod,Name} ->
- emit({" fun 'dec_",Name,"'/4"}),
- NthObj;
- {ModName,Name} ->
- emit_ext_fun(dec,ModName,Name),
-% emit([" {'",ModName,"', 'dec_",Name,"'}"]),
- NthObj;
- _Other ->
- emit({" fun 'dec_",ObjName,"'/4"}),
- NthObj
- end,
- emit({";",nl}),
- gen_objset_dec(Erules,ObjSName,UniqueName,[T|Rest],ClName,ClFields,
- NewNthObj);
-gen_objset_dec(Erules,ObjSetName,UniqueName,[{ObjName,Val,Fields}],_ClName,
- ClFields,NthObj) ->
- emit({"'getdec_",ObjSetName,"'(",{asis,UniqueName},",",{asis,Val},") ->",nl}),
- CurrMod = get(currmod),
- case ObjName of
- {no_mod,no_name} ->
- gen_inlined_dec_funs(Erules,Fields,ClFields,ObjSetName,
- NthObj);
- {CurrMod,Name} ->
- emit({" fun 'dec_",Name,"'/4"});
- {ModName,Name} ->
- emit_ext_fun(dec,ModName,Name);
-% emit([" {'",ModName,"', 'dec_",Name,"'}"]);
- _Other ->
- emit({" fun 'dec_",ObjName,"'/4"})
- end,
- emit({";",nl}),
- emit_default_getdec(ObjSetName,UniqueName),
- emit({".",nl,nl});
-gen_objset_dec(_,ObjSetName,_UniqueName,['EXTENSIONMARK'],_ClName,_ClFields,
- _NthObj) ->
- emit({"'getdec_",ObjSetName,"'(_, _) ->",nl}),
- emit({indent(3),"fun(_, Bytes, _, _) ->",nl}),
- emit({indent(6),"Len = case Bytes of",nl,indent(9),
- "Bin when is_binary(Bin) -> size(Bin);",nl,indent(9),
- "_ -> length(Bytes)",nl,indent(6),"end,"}),
- emit({indent(6),"{Bytes,[],Len}",nl}),
- emit({indent(3),"end.",nl,nl}),
- ok;
-gen_objset_dec(Erule,ObjSetName,UniqueName,
- ['EXTENSIONMARK','EXTENSIONMARK'|Rest],
- ClName,ClFields,NthObj) ->
- gen_objset_dec(Erule,ObjSetName,UniqueName,['EXTENSIONMARK'|Rest],
- ClName,ClFields,NthObj);
-gen_objset_dec(Erule,ObjSetName,UniqueName,['EXTENSIONMARK'|Rest],
- ClName,ClFields,NthObj) ->
- gen_objset_dec(Erule,ObjSetName,UniqueName,Rest++['EXTENSIONMARK'],
- ClName,ClFields,NthObj);
-gen_objset_dec(_,_,_,[],_,_,_) ->
- ok.
-
-emit_default_getdec(ObjSetName,UniqueName) ->
- emit(["'getdec_",ObjSetName,"'(",{asis,UniqueName},", ErrV) ->",nl]),
- emit([indent(3),"fun(C,V,_,_) -> exit({{component,C},{value,V}, {unique_name_and_value,",{asis,UniqueName},", ErrV}}) end"]).
-
-gen_inlined_dec_funs(Erules,Fields,[{typefield,Name,Prop}|Rest],
- ObjSetName,NthObj) ->
- DecProp = case Prop of
- 'OPTIONAL' -> opt_or_default;
- {'DEFAULT',_} -> opt_or_default;
- _ -> mandatory
- end,
- CurrMod = get(currmod),
- InternalDefFunName = [NthObj,Name,ObjSetName],
- case lists:keysearch(Name,1,Fields) of
- {value,{_,Type}} when is_record(Type,type) ->
- emit({indent(3),"fun(Type, Bytes, TagIn, _RestPrimFieldName) ->",
- nl,indent(6),"case Type of",nl}),
- N=emit_inner_of_decfun(Erules,Type,DecProp,InternalDefFunName),
- gen_inlined_dec_funs1(Erules,Fields,Rest,ObjSetName,NthObj+N);
- {value,{_,Type}} when is_record(Type,typedef) ->
- emit({indent(3),"fun(Type, Bytes, TagIn, _RestPrimFieldName) ->",
- nl,indent(6),"case Type of",nl}),
- emit({indent(9),{asis,Name}," ->",nl}),
- N=emit_inner_of_decfun(Erules,Type,DecProp,InternalDefFunName),
- gen_inlined_dec_funs1(Erules,Fields,Rest,ObjSetName,NthObj+N);
- {value,{_,#'Externaltypereference'{module=M,type=T}}} ->
- #typedef{typespec=Type} = asn1_db:dbget(M,T),
- OTag = Type#type.tag,
- Tag = [X#tag{class=decode_class(X#tag.class)}|| X <- OTag],
- emit({indent(3),"fun(Type, Bytes, TagIn, _RestPrimFieldName) ->",
- nl,indent(6),"case Type of",nl}),
- emit({indent(9),{asis,Name}," ->",nl}),
- if
- M == CurrMod ->
- emit([indent(12),"'dec_",T,"'(Bytes, ",DecProp,
- ", TagIn ++ ",{asis,Tag},")"]);
- true ->
- emit([indent(12),"'",M,"':'dec_",T,"'(Bytes, ",
- DecProp,", TagIn ++ ",{asis,Tag},")"])
- end,
- gen_inlined_dec_funs1(Erules,Fields,Rest,ObjSetName,NthObj);
- false ->
- emit([indent(3),"fun(Type, Bytes, TagIn, _RestPrimFieldName) ->",
- nl,indent(6),"case Type of",nl,
- indent(9),{asis,Name}," ->",nl,
- indent(12),"Len = case Bytes of",nl,
- indent(15),"B when is_binary(B) -> size(B);",nl,
- indent(15),"_ -> length(Bytes)",nl,
- indent(12),"end,",nl,
- indent(12),"{Bytes,[],Len}"]),
- gen_inlined_dec_funs1(Erules,Fields,Rest,ObjSetName,NthObj)
- end;
-gen_inlined_dec_funs(Erules,Fields,[_H|Rest],ObjSetName,NthObj) ->
- gen_inlined_dec_funs(Erules,Fields,Rest,ObjSetName,NthObj);
-gen_inlined_dec_funs(_,_,[],_,NthObj) ->
- NthObj.
-
-gen_inlined_dec_funs1(Erules,Fields,[{typefield,Name,Prop}|Rest],
- ObjSetName,NthObj) ->
- DecProp = case Prop of
- 'OPTIONAL' -> opt_or_default;
- {'DEFAULT',_} -> opt_or_default;
- _ -> mandatory
- end,
- CurrMod = get(currmod),
- InternalDefFunName = [NthObj,Name,ObjSetName],
- N=
- case lists:keysearch(Name,1,Fields) of
- {value,{_,Type}} when is_record(Type,type) ->
- emit({";",nl}),
- emit_inner_of_decfun(Erules,Type,DecProp,InternalDefFunName);
- {value,{_,Type}} when is_record(Type,typedef) ->
- emit({";",nl,indent(9),{asis,Name}," ->",nl}),
- emit_inner_of_decfun(Erules,Type,DecProp,InternalDefFunName);
- {value,{_,#'Externaltypereference'{module=M,type=T}}} ->
- #typedef{typespec=Type} = asn1_db:dbget(M,T),
- OTag = Type#type.tag,
- Tag = [X#tag{class=decode_class(X#tag.class)}|| X <- OTag],
- emit({";",nl,indent(9),{asis,Name}," ->",nl}),
- if
- M == CurrMod ->
- emit([indent(12),"'dec_",T,"'(Bytes, ",DecProp,
- ", TagIn ++ ",{asis,Tag},")"]);
- true ->
- emit([indent(12),"'",M,"':'dec_",T,"'(Bytes, ",
- DecProp,", TagIn ++ ",{asis,Tag},")"])
- end,
- 0;
- false ->
- emit([";",nl,
- indent(9),{asis,Name}," ->",nl,
- indent(12),"Len = case Bytes of",nl,
- indent(15),"B when is_binary(B) -> size(B);",nl,
- indent(15),"_ -> length(Bytes)",nl,
- indent(12),"end,",nl,
- indent(12),"{Bytes,[],Len}"]),
- 0
- end,
- gen_inlined_dec_funs1(Erules,Fields,Rest,ObjSetName,NthObj+N);
-gen_inlined_dec_funs1(Erules,Fields,[_H|Rest],ObjSetName,NthObj)->
- gen_inlined_dec_funs1(Erules,Fields,Rest,ObjSetName,NthObj);
-gen_inlined_dec_funs1(_,_,[],_,NthObj) ->
- emit({nl,indent(6),"end",nl}),
- emit({indent(3),"end"}),
- NthObj.
-
-emit_inner_of_decfun(Erules,#typedef{name={ExtName,Name},typespec=Type},
- Prop,InternalDefFunName) ->
- OTag = Type#type.tag,
- Tag = [X#tag{class=decode_class(X#tag.class)}|| X <- OTag],
- case {ExtName,Name} of
- {primitive,bif} ->
- emit(indent(12)),
- gen_dec_prim(Erules,Type,"Bytes",Tag,"TagIn",no_length,
- ?PRIMITIVE,Prop),
- 0;
- {constructed,bif} ->
- emit({indent(12),"'dec_",
- asn1ct_gen:list2name(InternalDefFunName),"'(Bytes, ",Prop,
- ", TagIn ++ ",{asis,Tag},")"}),
- 1;
- _ ->
- emit({indent(12),"'",ExtName,"':'dec_",Name,"'(Bytes, ",Prop,
- ", TagIn ++ ",{asis,Tag},")"}),
- 0
- end;
-emit_inner_of_decfun(_,#typedef{name=Name,typespec=Type},Prop,_) ->
- OTag = Type#type.tag,
- Tag = [X#tag{class=decode_class(X#tag.class)}|| X <- OTag],
- emit({indent(12),"'dec_",Name,"'(Bytes, ",Prop,", TagIn ++ ",
- {asis,Tag},")"}),
- 0;
-emit_inner_of_decfun(Erules,Type,Prop,_) when is_record(Type,type) ->
- OTag = Type#type.tag,
- Tag = [X#tag{class=decode_class(X#tag.class)}|| X <- OTag],
- CurrMod = get(currmod),
- Def = Type#type.def,
- InnerType = asn1ct_gen:get_inner(Def),
- WhatKind = asn1ct_gen:type(InnerType),
- case WhatKind of
- {primitive,bif} ->
- emit({indent(9),Def," ->",nl,indent(12)}),
- gen_dec_prim(Erules,Type,"Bytes",Tag,"TagIn",no_length,
- ?PRIMITIVE,Prop);
-% TRef when is_record(TRef,typereference) ->
-% T = TRef#typereference.val,
-% emit({indent(9),T," ->",nl,indent(12),"'dec_",T,"'(Val)"});
- #'Externaltypereference'{module=CurrMod,type=T} ->
- emit({indent(9),T," ->",nl,indent(12),"'dec_",T,
- "'(Bytes, ",Prop,", TagIn ++ ",{asis,Tag},")"});
- #'Externaltypereference'{module=ExtMod,type=T} ->
- emit({indent(9),T," ->",nl,indent(12),ExtMod,":'dec_",
- T,"'(Bytes, ",Prop,", TagIn ++ ",{asis,Tag},")"})
- end,
- 0.
-
-
-gen_internal_funcs(_,[]) ->
- ok;
-gen_internal_funcs(Erules,[TypeDef|Rest]) ->
- gen_encode_user(Erules,TypeDef),
- emit({"'dec_",TypeDef#typedef.name,"'(Bytes, ",
- unused_optormand_var("OptOrMand",(TypeDef#typedef.typespec)#type.def),", TagIn) ->",nl}),
- gen_decode_user(Erules,TypeDef),
- gen_internal_funcs(Erules,Rest).
-
-
-dbdec(Type) ->
- demit({"io:format(\"decoding: ",{asis,Type},"~w~n\",[Bytes]),",nl}).
-
-
-decode_class('UNIVERSAL') ->
- ?UNIVERSAL;
-decode_class('APPLICATION') ->
- ?APPLICATION;
-decode_class('CONTEXT') ->
- ?CONTEXT;
-decode_class('PRIVATE') ->
- ?PRIVATE.
-
-decode_type('BOOLEAN') -> 1;
-decode_type('INTEGER') -> 2;
-decode_type('BIT STRING') -> 3;
-decode_type('OCTET STRING') -> 4;
-decode_type('NULL') -> 5;
-decode_type('OBJECT IDENTIFIER') -> 6;
-decode_type('ObjectDescriptor') -> 7;
-decode_type('EXTERNAL') -> 8;
-decode_type('REAL') -> 9;
-decode_type('ENUMERATED') -> 10;
-decode_type('EMBEDDED_PDV') -> 11;
-decode_type('UTF8String') -> 12;
-decode_type('RELATIVE-OID') -> 13;
-decode_type('SEQUENCE') -> 16;
-decode_type('SEQUENCE OF') -> 16;
-decode_type('SET') -> 17;
-decode_type('SET OF') -> 17;
-decode_type('NumericString') -> 18;
-decode_type('PrintableString') -> 19;
-decode_type('TeletexString') -> 20;
-decode_type('T61String') -> 20;
-decode_type('VideotexString') -> 21;
-decode_type('IA5String') -> 22;
-decode_type('UTCTime') -> 23;
-decode_type('GeneralizedTime') -> 24;
-decode_type('GraphicString') -> 25;
-decode_type('VisibleString') -> 26;
-decode_type('GeneralString') -> 27;
-decode_type('UniversalString') -> 28;
-decode_type('BMPString') -> 30;
-decode_type('CHOICE') -> 'CHOICE'; % choice gets the tag from the actual alternative
-decode_type(Else) -> exit({error,{asn1,{unrecognized_type,Else}}}).
-
-add_removed_bytes() ->
- asn1ct_name:delete(rb),
- add_removed_bytes(asn1ct_name:all(rb)).
-
-add_removed_bytes([H,T1|T]) ->
- emit({{var,H},"+"}),
- add_removed_bytes([T1|T]);
-add_removed_bytes([H|T]) ->
- emit({{var,H}}),
- add_removed_bytes(T);
-add_removed_bytes([]) ->
- true.
-
-mkfuncname(WhatKind,DecOrEnc) ->
- case WhatKind of
- #'Externaltypereference'{module=Mod,type=EType} ->
- CurrMod = get(currmod),
- case CurrMod of
- Mod ->
- lists:concat(["'",DecOrEnc,"_",EType,"'"]);
- _ ->
-% io:format("CurrMod: ~p, Mod: ~p~n",[CurrMod,Mod]),
- lists:concat(["'",Mod,"':'",DecOrEnc,"_",EType,"'"])
- end;
- #'typereference'{val=EType} ->
- lists:concat(["'",DecOrEnc,"_",EType,"'"]);
- 'ASN1_OPEN_TYPE' ->
- lists:concat(["'",DecOrEnc,"_",WhatKind,"'"])
-
- end.
-
-optionals(L) -> optionals(L,[],1).
-
-optionals([{'EXTENSIONMARK',_,_}|Rest],Acc,Pos) ->
- optionals(Rest,Acc,Pos); % optionals in extension are currently not handled
-optionals([#'ComponentType'{name=Name,prop='OPTIONAL'}|Rest],Acc,Pos) ->
- optionals(Rest,[{Name,Pos}|Acc],Pos+1);
-optionals([#'ComponentType'{name=Name,prop={'DEFAULT',_}}|Rest],Acc,Pos) ->
- optionals(Rest,[{Name,Pos}|Acc],Pos+1);
-optionals([#'ComponentType'{}|Rest],Acc,Pos) ->
- optionals(Rest,Acc,Pos+1);
-optionals([],Acc,_) ->
- lists:reverse(Acc).
-
-get_constraint(C,Key) ->
- case lists:keysearch(Key,1,C) of
- false ->
- no;
- {value,{_,V}} ->
- V
- end.
-
-%% if the original option was ber and it has been wrapped to ber_bin
-%% turn it back to ber
-re_wrap_erule(ber_bin) ->
- case get(encoding_options) of
- Options when is_list(Options) ->
- case lists:member(ber,Options) of
- true -> ber;
- _ -> ber_bin
- end;
- _ -> ber_bin
- end;
-re_wrap_erule(Erule) ->
- Erule.
-
-is_already_generated(Operation,Name) ->
- case get(class_default_type) of
- undefined ->
- put(class_default_type,[{Operation,Name}]),
- false;
- GeneratedList ->
- case lists:member({Operation,Name},GeneratedList) of
- true ->
- true;
- false ->
- put(class_default_type,[{Operation,Name}|GeneratedList]),
- false
- end
- end.
-
-get_class_fields(#classdef{typespec=ObjClass}) ->
- ObjClass#objectclass.fields;
-get_class_fields(#objectclass{fields=Fields}) ->
- Fields;
-get_class_fields(_) ->
- [].
-
-get_object_field(Name,ObjectFields) ->
- case lists:keysearch(Name,1,ObjectFields) of
- {value,Field} -> Field;
- false -> false
- end.
-
-%% For BER the ExtensionAdditionGroup notation has no impact on the encoding/decoding
-%% and therefore we only filter away the ExtensionAdditionGroup start and end markers
-%%
-extaddgroup2sequence(ExtList) when is_list(ExtList) ->
- lists:filter(fun(#'ExtensionAdditionGroup'{}) ->
- false;
- ('ExtensionAdditionGroupEnd') ->
- false;
- (_) ->
- true
- end, ExtList).
diff --git a/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl b/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl
index 3ccfca3784..664dfc2086 100644
--- a/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl
+++ b/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl
@@ -114,31 +114,6 @@ gen_encode(Erules,Typename,Type) when is_record(Type,type) ->
_ -> % embedded type with constructed name
true
end,
- case lists:member(InnerType,['SET','SEQUENCE']) of
- true ->
- case get(asn_keyed_list) of
- true ->
- CompList =
- case Type#type.def of
- #'SEQUENCE'{components=Cl} -> Cl;
- #'SET'{components=Cl} -> Cl
- end,
- emit([nl,"'enc_",asn1ct_gen:list2name(Typename),
- "'(Val, TagIn",ObjFun,
- ") when is_list(Val) ->",nl]),
- emit([" 'enc_",asn1ct_gen:list2name(Typename),
- "'(?RT_BER:fixoptionals(",
- {asis,optionals(CompList)},
- ",Val), TagIn",ObjFun,");",nl,nl]);
- _ -> true
- end;
- _ ->
- emit([nl,"'enc_",asn1ct_gen:list2name(Typename),
- "'({'",asn1ct_gen:list2name(Typename),
- "',Val}, TagIn",ObjFun,") ->",nl]),
- emit([" 'enc_",asn1ct_gen:list2name(Typename),
- "'(Val, TagIn",ObjFun,");",nl,nl])
- end,
emit(["'enc_",asn1ct_gen:list2name(Typename),
"'(Val, TagIn",ObjFun,") ->",nl," "]),
asn1ct_gen:gen_encode_constructed(Erules,Typename,InnerType,Type);
@@ -172,30 +147,6 @@ gen_encode_user(Erules,D) when is_record(D,typedef) ->
"'(Val",") ->",nl]),
emit([" 'enc_",asn1ct_gen:list2name(Typename),
"'(Val, ", {asis,lists:reverse(Tag)},").",nl,nl]),
-
- case lists:member(InnerType,['SET','SEQUENCE']) of
- true ->
- case get(asn_keyed_list) of
- true ->
- CompList =
- case Type#type.def of
- #'SEQUENCE'{components=Cl} -> Cl;
- #'SET'{components=Cl} -> Cl
- end,
-
- emit([nl,"'enc_",asn1ct_gen:list2name(Typename),
- "'(Val, TagIn) when is_list(Val) ->",nl]),
- emit([" 'enc_",asn1ct_gen:list2name(Typename),
- "'(?RT_BER:fixoptionals(",
- {asis,optionals(CompList)},
- ",Val), TagIn);",nl,nl]);
- _ -> true
- end;
- _ ->
- emit({nl,"'enc_",asn1ct_gen:list2name(Typename),
- "'({'",asn1ct_gen:list2name(Typename),"',Val}, TagIn) ->",nl}),
- emit({" 'enc_",asn1ct_gen:list2name(Typename),"'(Val, TagIn);",nl,nl})
- end,
emit({"'enc_",asn1ct_gen:list2name(Typename),"'(Val, TagIn) ->",nl}),
CurrentMod = get(currmod),
case asn1ct_gen:type(InnerType) of
@@ -1504,7 +1455,7 @@ gen_objset_dec(Erules,ObjSetName,_UniqueName,['EXTENSIONMARK'],_ClName,
emit([indent(2),"fun(_,Bytes, _RestPrimFieldName) ->",nl]),
case Erules of
- ber_bin_v2 ->
+ ber ->
emit([indent(4),"case Bytes of",nl,
indent(6),"Bin when is_binary(Bin) -> ",nl,
indent(8),"Bin;",nl,
@@ -1772,19 +1723,6 @@ mkfuncname(WhatKind,DecOrEnc) ->
end.
-optionals(L) -> optionals(L,[],1).
-
-optionals([{'EXTENSIONMARK',_,_}|Rest],Acc,Pos) ->
- optionals(Rest,Acc,Pos); % optionals in extension are currently not handled
-optionals([#'ComponentType'{name=Name,prop='OPTIONAL'}|Rest],Acc,Pos) ->
- optionals(Rest,[{Name,Pos}|Acc],Pos+1);
-optionals([#'ComponentType'{name=Name,prop={'DEFAULT',_}}|Rest],Acc,Pos) ->
- optionals(Rest,[{Name,Pos}|Acc],Pos+1);
-optionals([#'ComponentType'{}|Rest],Acc,Pos) ->
- optionals(Rest,Acc,Pos+1);
-optionals([],Acc,_) ->
- lists:reverse(Acc).
-
get_constraint(C,Key) ->
case lists:keysearch(Key,1,C) of
false ->
diff --git a/lib/asn1/src/asn1ct_gen_per.erl b/lib/asn1/src/asn1ct_gen_per.erl
index bd5b81991d..af19edb908 100644
--- a/lib/asn1/src/asn1ct_gen_per.erl
+++ b/lib/asn1/src/asn1ct_gen_per.erl
@@ -25,6 +25,7 @@
-include("asn1_records.hrl").
%-compile(export_all).
+-export([gen_dec_imm/2]).
-export([pgen/4,gen_dec_prim/3,gen_encode_prim/4]).
-export([gen_obj_code/3,gen_objectset_code/2]).
-export([gen_decode/2, gen_decode/3]).
@@ -78,18 +79,6 @@ gen_encode(Erules,Typename,Type) when is_record(Type,type) ->
end,
case asn1ct_gen:type(InnerType) of
{constructed,bif} ->
- case InnerType of
- 'SET' ->
- true;
- 'SEQUENCE' ->
- true;
- _ ->
- emit({nl,"'enc_",asn1ct_gen:list2name(Typename),
- "'({'",asn1ct_gen:list2name(Typename),
- "',Val}",ObjFun,") ->",nl}),
- emit({"'enc_",asn1ct_gen:list2name(Typename),
- "'(Val",ObjFun,");",nl,nl})
- end,
emit({"'enc_",asn1ct_gen:list2name(Typename),"'(Val",ObjFun,
") ->",nl}),
asn1ct_gen:gen_encode_constructed(Erules,Typename,InnerType,Type);
@@ -146,16 +135,18 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) ->
case D#type.def of
'INTEGER' ->
emit({"?RT_PER:encode_integer(", %fel
- {asis,effective_constraint(integer,Constraint)},",",Value,")"});
+ {asis,asn1ct_imm:effective_constraint(integer,Constraint)},
+ ",",Value,")"});
{'INTEGER',NamedNumberList} ->
emit({"?RT_PER:encode_integer(",
- {asis,effective_constraint(integer,Constraint)},",",Value,",",
+ {asis,asn1ct_imm:effective_constraint(integer,Constraint)},
+ ",",Value,",",
{asis,NamedNumberList},")"});
{'ENUMERATED',{Nlist1,Nlist2}} ->
NewList = lists:concat([[{0,X}||{X,_} <- Nlist1],['EXT_MARK'],[{1,X}||{X,_} <- Nlist2]]),
NewC = [{'ValueRange',{0,length(Nlist1)-1}}],
case Erules of
- uper_bin ->
+ uper ->
emit(["case ",Value," of",nl]);
_ ->
emit(["case (case ",Value," of {_,",{curr,enumval},"}-> ",
@@ -168,7 +159,7 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) ->
NewList = [X||{X,_} <- NamedNumberList],
NewC = [{'ValueRange',{0,length(NewList)-1}}],
case Erules of
- uper_bin ->
+ uper ->
emit(["case ",Value," of",nl]);
_ ->
emit(["case (case ",Value," of {_,",{curr,enumval},
@@ -184,7 +175,7 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) ->
{asis,Constraint},",",Value,",",
{asis,NamedNumberList},")"});
'NULL' ->
- emit({"?RT_PER:encode_null(",Value,")"});
+ emit("[]");
'OBJECT IDENTIFIER' ->
emit({"?RT_PER:encode_object_identifier(",Value,")"});
'RELATIVE-OID' ->
@@ -274,7 +265,7 @@ emit_enc_enumerated_cases(Erule, C, [H1,H2|T], Count) ->
-emit_enc_enumerated_case(uper_bin,_C, {asn1_enum,High}, _) ->
+emit_enc_enumerated_case(uper,_C, {asn1_enum,High}, _) ->
emit([
"{asn1_enum,EnumV} when is_integer(EnumV), EnumV > ",High," -> ",
"[<<1:1>>,?RT_PER:encode_small_number(EnumV)]"]);
@@ -284,118 +275,27 @@ emit_enc_enumerated_case(_Per,_C, {asn1_enum,High}, _) ->
"[{bit,1},?RT_PER:encode_small_number(EnumV)]"]);
emit_enc_enumerated_case(_Erule, _C, 'EXT_MARK', _Count) ->
true;
-emit_enc_enumerated_case(uper_bin,_C, {1,EnumName}, Count) ->
+emit_enc_enumerated_case(uper,_C, {1,EnumName}, Count) ->
emit(["'",EnumName,"' -> [<<1:1>>,?RT_PER:encode_small_number(",Count,")]"]);
emit_enc_enumerated_case(_Per,_C, {1,EnumName}, Count) ->
emit(["'",EnumName,"' -> [{bit,1},?RT_PER:encode_small_number(",Count,")]"]);
-emit_enc_enumerated_case(uper_bin,C, {0,EnumName}, Count) ->
+emit_enc_enumerated_case(uper,C, {0,EnumName}, Count) ->
emit(["'",EnumName,"' -> [<<0:1>>,?RT_PER:encode_integer(",{asis,C},", ",Count,")]"]);
emit_enc_enumerated_case(_Per,C, {0,EnumName}, Count) ->
emit(["'",EnumName,"' -> [{bit,0},?RT_PER:encode_integer(",{asis,C},", ",Count,")]"]);
emit_enc_enumerated_case(_Erule, C, EnumName, Count) ->
emit(["'",EnumName,"' -> ?RT_PER:encode_integer(",{asis,C},", ",Count,")"]).
-%% effective_constraint(Type,C)
-%% Type = atom()
-%% C = [C1,...]
-%% C1 = {'SingleValue',SV} | {'ValueRange',VR} | {atom(),term()}
-%% SV = integer() | [integer(),...]
-%% VR = {Lb,Ub}
-%% Lb = 'MIN' | integer()
-%% Ub = 'MAX' | integer()
-%% Returns a single value if C only has a single value constraint, and no
-%% value range constraints, that constrains to a single value, otherwise
-%% returns a value range that has the lower bound set to the lowest value
-%% of all single values and lower bound values in C and the upper bound to
-%% the greatest value.
-effective_constraint(integer,[C={{_,_},_}|_Rest]) -> % extension
- [C]; %% [C|effective_constraint(integer,Rest)]; XXX what is possible ???
-effective_constraint(integer,C) ->
- SVs = get_constraints(C,'SingleValue'),
- SV = effective_constr('SingleValue',SVs),
- VRs = get_constraints(C,'ValueRange'),
- VR = effective_constr('ValueRange',VRs),
- greatest_common_range(SV,VR).
-
-effective_constr(_,[]) ->
- [];
-effective_constr('SingleValue',List) ->
- SVList = lists:flatten(lists:map(fun(X)->element(2,X)end,List)),
- %% Sort and remove duplicates before generating SingleValue or ValueRange
- %% In case of ValueRange, also check for 'MIN and 'MAX'
- case lists:usort(SVList) of
- [N] ->
- [{'SingleValue',N}];
- L when is_list(L) ->
- [{'ValueRange',{least_Lb(L),greatest_Ub(L)}}]
- end;
-effective_constr('ValueRange',List) ->
- LBs = lists:map(fun({_,{Lb,_}})-> Lb end,List),
- UBs = lists:map(fun({_,{_,Ub}})-> Ub end,List),
- Lb = least_Lb(LBs),
- [{'ValueRange',{Lb,lists:max(UBs)}}].
-
-greatest_common_range([],VR) ->
- VR;
-greatest_common_range(SV,[]) ->
- SV;
-greatest_common_range(SV,VR) ->
- greatest_common_range2(mk_vr(SV),mk_vr(VR)).
-greatest_common_range2({_,Int},{'MIN',Ub}) when is_integer(Int),
- Int > Ub ->
- [{'ValueRange',{'MIN',Int}}];
-greatest_common_range2({_,Int},{Lb,Ub}) when is_integer(Int),
- Int < Lb ->
- [{'ValueRange',{Int,Ub}}];
-greatest_common_range2({_,Int},VR={_Lb,_Ub}) when is_integer(Int) ->
- [{'ValueRange',VR}];
-greatest_common_range2({_,L},{Lb,Ub}) when is_list(L) ->
- Min = least_Lb([Lb|L]),
- Max = greatest_Ub([Ub|L]),
- [{'ValueRange',{Min,Max}}];
-greatest_common_range2({Lb1,Ub1},{Lb2,Ub2}) ->
- Min = least_Lb([Lb1,Lb2]),
- Max = greatest_Ub([Ub1,Ub2]),
- [{'ValueRange',{Min,Max}}].
-
-mk_vr([{Type,I}]) when is_atom(Type), is_integer(I) ->
- {I,I};
-mk_vr([{Type,{Lb,Ub}}]) when is_atom(Type) ->
- {Lb,Ub};
-mk_vr(Other) ->
- Other.
-
-least_Lb(L) ->
- case lists:member('MIN',L) of
- true -> 'MIN';
- _ -> lists:min(L)
- end.
-
-greatest_Ub(L) ->
- case lists:member('MAX',L) of
- true -> 'MAX';
- _ -> lists:max(L)
- end.
-
-
-get_constraints(L=[{Key,_}],Key) ->
- L;
-get_constraints([],_) ->
- [];
-get_constraints(C,Key) ->
- {value,L} = keysearch_allwithkey(Key,1,C,[]),
- L.
-
-keysearch_allwithkey(Key,Ix,C,Acc) ->
- case lists:keysearch(Key,Ix,C) of
- false ->
- {value,Acc};
- {value,T} ->
- RestC = lists:delete(T,C),
- keysearch_allwithkey(Key,Ix,RestC,[T|Acc])
+get_constraint([{Key,V}], Key) ->
+ V;
+get_constraint([], _) ->
+ no;
+get_constraint(C, Key) ->
+ case lists:keyfind(Key, 1, C) of
+ false -> no;
+ {Key,V} -> V
end.
-
%% Object code generating for encoding and decoding
%% ------------------------------------------------
@@ -442,7 +342,7 @@ gen_encode_objectfields(Erule,ClassName,[{typefield,Name,OptOrMand}|Rest],
{false,'OPTIONAL'} ->
EmitFuncClause("Val"),
case Erule of
- uper_bin ->
+ uper ->
emit(" Val");
_ ->
emit(" [{octets,Val}]")
@@ -833,7 +733,7 @@ gen_objset_enc(Erule,ObjSetName,_UniqueName,['EXTENSIONMARK'],_ClName,
emit({"'getenc_",ObjSetName,"'(_, _) ->",nl}),
emit({indent(3),"fun(_, Val, _) ->",nl}),
case Erule of
- uper_bin ->
+ uper ->
emit([indent(6),"Val",nl]);
_ ->
emit([indent(6),"[{octets,Val}]",nl])
@@ -883,7 +783,7 @@ gen_inlined_enc_funs(Erule,Fields,[{typefield,Name,_}|Rest],ObjSetName,NthObj) -
emit({indent(9),{asis,Name}," ->",nl}),
emit([indent(12),"'",M,"'",":'enc_",T,"'(Val)"]),
gen_inlined_enc_funs1(Erule,Fields,Rest,ObjSetName,NthObj,[]);
- false when Erule == uper_bin ->
+ false when Erule =:= uper ->
emit([indent(3),"fun(Type,Val,_) ->",nl,
indent(6),"case Type of",nl,
indent(9),{asis,Name}," -> Val",nl]),
@@ -921,7 +821,7 @@ gen_inlined_enc_funs1(Erule,Fields,[{typefield,Name,_}|Rest],ObjSetName,
emit({";",nl,indent(9),{asis,Name}," ->",nl}),
emit([indent(12),"'",M,"'",":'enc_",T,"'(Val)"]),
{Acc,0};
- false when Erule == uper_bin ->
+ false when Erule =:= uper ->
emit([";",nl,
indent(9),{asis,Name}," -> ",nl,
"Val",nl]),
@@ -1031,7 +931,6 @@ gen_objset_dec(ObjSetName,_UniqueName,['EXTENSIONMARK'],_ClName,_ClFields,
_NthObj) ->
emit({"'getdec_",ObjSetName,"'(_, _) ->",nl}),
emit({indent(3),"fun(Attr1, Bytes, _,_) ->",nl}),
-%% emit({indent(6),"?RT_PER:decode_open_type(Bytes,[])",nl}),
emit({indent(6),"{Bytes,Attr1}",nl}),
emit({indent(3),"end.",nl,nl}),
ok;
@@ -1047,76 +946,42 @@ emit_default_getdec(ObjSetName,UniqueName) ->
emit([indent(2), "fun(C,V,_,_) -> exit({{component,C},{value,V},{unique_name_and_value,",{asis,UniqueName},",ErrV}}) end"]).
-gen_inlined_dec_funs(Fields,[{typefield,Name,_}|Rest],
- ObjSetName,NthObj) ->
- CurrMod = get(currmod),
- InternalDefFunName = [NthObj,Name,ObjSetName],
- case lists:keysearch(Name,1,Fields) of
- {value,{_,Type}} when is_record(Type,type) ->
- emit({indent(3),"fun(Type, Val, _, _) ->",nl,
- indent(6),"case Type of",nl}),
- N=emit_inner_of_decfun(Type,InternalDefFunName),
- gen_inlined_dec_funs1(Fields,Rest,ObjSetName,NthObj+N);
- {value,{_,Type}} when is_record(Type,typedef) ->
- emit({indent(3),"fun(Type, Val, _, _) ->",nl,
- indent(6),"case Type of",nl}),
- emit({indent(9),{asis,Name}," ->",nl}),
- N=emit_inner_of_decfun(Type,InternalDefFunName),
- gen_inlined_dec_funs1(Fields,Rest,ObjSetName,NthObj+N);
- {value,{_,#'Externaltypereference'{module=CurrMod,type=T}}} ->
- emit({indent(3),"fun(Type, Val, _, _) ->",nl,
- indent(6),"case Type of",nl}),
- emit({indent(9),{asis,Name}," ->",nl}),
- emit([indent(12),"'dec_",T,"'(Val, telltype)"]),
- gen_inlined_dec_funs1(Fields,Rest,ObjSetName,NthObj);
- {value,{_,#'Externaltypereference'{module=M,type=T}}} ->
- emit({indent(3),"fun(Type, Val, _, _) ->",nl,
- indent(6),"case Type of",nl}),
- emit({indent(9),{asis,Name}," ->",nl}),
- emit([indent(12),"'",M,"':'dec_",T,"'(Val, telltype)"]),
- gen_inlined_dec_funs1(Fields,Rest,ObjSetName,NthObj);
- false ->
- emit([indent(3),"fun(Type, Val, _, _) ->",nl,
- indent(6),"case Type of",nl,
- indent(9),{asis,Name}," ->{Val,Type}"]),
- gen_inlined_dec_funs1(Fields,Rest,ObjSetName,NthObj)
- end;
-gen_inlined_dec_funs(Fields,[_|Rest],ObjSetName,NthObj) ->
- gen_inlined_dec_funs(Fields,Rest,ObjSetName,NthObj);
-gen_inlined_dec_funs(_,[],_,NthObj) ->
+gen_inlined_dec_funs(Fields, List, ObjSetName, NthObj0) ->
+ emit([indent(3),"fun(Type, Val, _, _) ->",nl,
+ indent(6),"case Type of",nl]),
+ NthObj = gen_inlined_dec_funs1(Fields, List, ObjSetName, "", NthObj0),
+ emit([nl,indent(6),"end",nl,
+ indent(3),"end"]),
NthObj.
-gen_inlined_dec_funs1(Fields,[{typefield,Name,_}|Rest],
- ObjSetName,NthObj) ->
+gen_inlined_dec_funs1(Fields, [{typefield,Name,_}|Rest],
+ ObjSetName, Sep0, NthObj) ->
CurrentMod = get(currmod),
InternalDefFunName = [NthObj,Name,ObjSetName],
- N=case lists:keysearch(Name,1,Fields) of
- {value,{_,Type}} when is_record(Type,type) ->
- emit({";",nl}),
- emit_inner_of_decfun(Type,InternalDefFunName);
- {value,{_,Type}} when is_record(Type,typedef) ->
- emit({";",nl,indent(9),{asis,Name}," ->",nl}),
- emit_inner_of_decfun(Type,InternalDefFunName);
- {value,{_,#'Externaltypereference'{module=CurrentMod,type=T}}} ->
- emit([";",nl,indent(9),{asis,Name}," ->",nl]),
- emit([indent(12),"'dec_",T,"'(Val,telltype)"]),
- 0;
- {value,{_,#'Externaltypereference'{module=M,type=T}}} ->
- emit([";",nl,indent(9),{asis,Name}," ->",nl]),
- emit([indent(12),"'",M,"'",":'dec_",T,"'(Val,telltype)"]),
- 0;
- false ->
- emit([";",nl,
- indent(9),{asis,Name}," ->{Val,Type}"]),
- 0
- end,
- gen_inlined_dec_funs1(Fields,Rest,ObjSetName,NthObj+N);
-gen_inlined_dec_funs1(Fields,[_|Rest],ObjSetName,NthObj)->
- gen_inlined_dec_funs1(Fields,Rest,ObjSetName,NthObj);
-gen_inlined_dec_funs1(_,[],_,NthObj) ->
- emit({nl,indent(6),"end",nl}),
- emit({indent(3),"end"}),
- NthObj.
+ emit(Sep0),
+ Sep = [";",nl],
+ N = case lists:keyfind(Name, 1, Fields) of
+ {_,#type{}=Type} ->
+ emit_inner_of_decfun(Type, InternalDefFunName);
+ {_,#typedef{}=Type} ->
+ emit([indent(9),{asis,Name}," ->",nl]),
+ emit_inner_of_decfun(Type, InternalDefFunName);
+ {_,#'Externaltypereference'{module=CurrentMod,type=T}} ->
+ emit([indent(9),{asis,Name}," ->",nl,
+ indent(12),"'dec_",T,"'(Val,telltype)"]),
+ 0;
+ {_,#'Externaltypereference'{module=M,type=T}} ->
+ emit([indent(9),{asis,Name}," ->",nl,
+ indent(12),"'",M,"':'dec_",T,"'(Val,telltype)"]),
+ 0;
+ false ->
+ emit([indent(9),{asis,Name}," -> {Val,Type}"]),
+ 0
+ end,
+ gen_inlined_dec_funs1(Fields, Rest, ObjSetName, Sep, NthObj+N);
+gen_inlined_dec_funs1(Fields, [_|Rest], ObjSetName, Sep, NthObj) ->
+ gen_inlined_dec_funs1(Fields, Rest, ObjSetName, Sep, NthObj);
+gen_inlined_dec_funs1(_, [], _, _, NthObj) -> NthObj.
emit_inner_of_decfun(#typedef{name={ExtName,Name},typespec=Type},
InternalDefFunName) ->
@@ -1228,19 +1093,47 @@ gen_decode_user(Erules,D) when is_record(D,typedef) ->
exit({error,{asn1,{unknown,Other}}})
end.
+gen_dec_imm(Erule, #type{def=Name,constraint=C}) ->
+ Aligned = case Erule of
+ uper -> false;
+ per -> true
+ end,
+ gen_dec_imm_1(Name, C, Aligned).
+
+gen_dec_imm_1('ASN1_OPEN_TYPE', Constraint, Aligned) ->
+ imm_decode_open_type(Constraint, Aligned);
+gen_dec_imm_1('ANY', _Constraint, Aligned) ->
+ imm_decode_open_type([], Aligned);
+gen_dec_imm_1('BOOLEAN', _Constr, _Aligned) ->
+ asn1ct_imm:per_dec_boolean();
+gen_dec_imm_1({'ENUMERATED',{Base,Ext}}, _Constr, Aligned) ->
+ asn1ct_imm:per_dec_enumerated(Base, Ext, Aligned);
+gen_dec_imm_1({'ENUMERATED',NamedNumberList}, _Constr, Aligned) ->
+ asn1ct_imm:per_dec_enumerated(NamedNumberList, Aligned);
+gen_dec_imm_1('INTEGER', Constr, Aligned) ->
+ asn1ct_imm:per_dec_integer(Constr, Aligned);
+gen_dec_imm_1({'INTEGER',NamedNumberList}, Constraint, Aligned) ->
+ asn1ct_imm:per_dec_named_integer(Constraint,
+ NamedNumberList,
+ Aligned);
+gen_dec_imm_1('OCTET STRING', Constraint, Aligned) ->
+ SzConstr = get_constraint(Constraint, 'SizeConstraint'),
+ Imm = asn1ct_imm:per_dec_octet_string(SzConstr, Aligned),
+ {convert,binary_to_list,Imm};
+gen_dec_imm_1(_, _, _) -> no.
+
+gen_dec_prim(Erule, Type, BytesVar) ->
+ case gen_dec_imm(Erule, Type) of
+ no ->
+ gen_dec_prim_1(Erule, Type, BytesVar);
+ Imm ->
+ asn1ct_imm:dec_code_gen(Imm, BytesVar)
+ end.
-gen_dec_prim(Erules,Att,BytesVar) ->
- Typename = Att#type.def,
- Constraint = Att#type.constraint,
+gen_dec_prim_1(Erule,
+ #type{def=Typename,constraint=Constraint}=Att,
+ BytesVar) ->
case Typename of
- 'INTEGER' ->
- emit({"?RT_PER:decode_integer(",BytesVar,",",
- {asis,effective_constraint(integer,Constraint)},")"});
- {'INTEGER',NamedNumberList} ->
- emit({"?RT_PER:decode_integer(",BytesVar,",",
- {asis,effective_constraint(integer,Constraint)},",",
- {asis,NamedNumberList},")"});
-
'REAL' ->
emit({"?RT_PER:decode_real(",BytesVar,")"});
@@ -1256,8 +1149,7 @@ gen_dec_prim(Erules,Att,BytesVar) ->
{asis,NamedNumberList},")"})
end;
'NULL' ->
- emit({"?RT_PER:decode_null(",
- BytesVar,")"});
+ emit({"{'NULL',",BytesVar,"}"});
'OBJECT IDENTIFIER' ->
emit({"?RT_PER:decode_object_identifier(",
BytesVar,")"});
@@ -1267,24 +1159,6 @@ gen_dec_prim(Erules,Att,BytesVar) ->
'ObjectDescriptor' ->
emit({"?RT_PER:decode_ObjectDescriptor(",
BytesVar,")"});
- {'ENUMERATED',{NamedNumberList1,NamedNumberList2}} ->
- NewTup = {list_to_tuple([X||{X,_} <- NamedNumberList1]),
- list_to_tuple([X||{X,_} <- NamedNumberList2])},
- NewC = [{'ValueRange',{0,size(element(1,NewTup))-1}}],
- emit({"?RT_PER:decode_enumerated(",BytesVar,",",
- {asis,NewC},",",
- {asis,NewTup},")"});
- {'ENUMERATED',NamedNumberList} ->
- NewTup = list_to_tuple([X||{X,_} <- NamedNumberList]),
- NewC = [{'ValueRange',{0,size(NewTup)-1}}],
- emit({"?RT_PER:decode_enumerated(",BytesVar,",",
- {asis,NewC},",",
- {asis,NewTup},")"});
- 'BOOLEAN'->
- emit({"?RT_PER:decode_boolean(",BytesVar,")"});
- 'OCTET STRING' ->
- emit({"?RT_PER:decode_octet_string(",BytesVar,",",
- {asis,Constraint},")"});
'NumericString' ->
emit({"?RT_PER:decode_NumericString(",BytesVar,",",
{asis,Constraint},")"});
@@ -1322,42 +1196,12 @@ gen_dec_prim(Erules,Att,BytesVar) ->
",",{asis,Constraint},")"});
'UTF8String' ->
emit({"?RT_PER:decode_UTF8String(",BytesVar,")"});
- 'ANY' ->
- case Erules of
- per ->
- emit(["fun() -> {XTerm,YTermXBytes} = ?RT_PER:decode_open_type(",BytesVar,",",{asis,Constraint}, "), {binary_to_list(XTerm),XBytes} end ()"]);
- _ ->
- emit(["?RT_PER:decode_open_type(",BytesVar,",",
- {asis,Constraint}, ")"])
- end;
- 'ASN1_OPEN_TYPE' ->
- case Constraint of
- [#'Externaltypereference'{type=Tname}] ->
- emit(["fun(FBytes) ->",nl,
- " {XTerm,XBytes} = "]),
- emit(["?RT_PER:decode_open_type(FBytes,[]),",nl]),
- emit([" {YTerm,_} = dec_",Tname,"(XTerm,mandatory),",nl]),
- emit([" {YTerm,XBytes} end(",BytesVar,")"]);
- [#type{def=#'Externaltypereference'{type=Tname}}] ->
- emit(["fun(FBytes) ->",nl,
- " {XTerm,XBytes} = "]),
- emit(["?RT_PER:decode_open_type(FBytes,[]),",nl]),
- emit([" {YTerm,_} = dec_",Tname,"(XTerm,mandatory),",nl]),
- emit([" {YTerm,XBytes} end(",BytesVar,")"]);
- _ ->
- case Erules of
- per ->
- emit(["fun() -> {XTerm,XBytes} = ?RT_PER:decode_open_type(",BytesVar,", []), {binary_to_list(XTerm),XBytes} end()"]);
- _ ->
- emit(["?RT_PER:decode_open_type(",BytesVar,",[])"])
- end
- end;
#'ObjectClassFieldType'{} ->
- case asn1ct_gen:get_inner(Att#type.def) of
+ case asn1ct_gen:get_inner(Typename) of
{fixedtypevaluefield,_,InnerType} ->
- gen_dec_prim(Erules,InnerType,BytesVar);
+ gen_dec_prim(Erule, InnerType, BytesVar);
T ->
- gen_dec_prim(Erules,Att#type{def=T},BytesVar)
+ gen_dec_prim(Erule, Att#type{def=T}, BytesVar)
end;
Other ->
exit({'cant decode' ,Other})
@@ -1417,3 +1261,22 @@ extaddgroup2sequence([C|T],ExtNum,Acc) ->
extaddgroup2sequence(T,ExtNum,[C|Acc]);
extaddgroup2sequence([],_,Acc) ->
lists:reverse(Acc).
+
+imm_decode_open_type([#'Externaltypereference'{type=Tname}], Aligned) ->
+ imm_dec_open_type_1(Tname, Aligned);
+imm_decode_open_type([#type{def=#'Externaltypereference'{type=Tname}}],
+ Aligned) ->
+ imm_dec_open_type_1(Tname, Aligned);
+imm_decode_open_type(_, Aligned) ->
+ asn1ct_imm:per_dec_open_type(Aligned).
+
+imm_dec_open_type_1(Type, Aligned) ->
+ D = fun(OpenType, Buf) ->
+ asn1ct_name:new(tmpval),
+ emit(["begin",nl,
+ "{",{curr,tmpval},",_} = ",
+ "dec_",Type,"(",OpenType,", mandatory),",nl,
+ "{",{curr,tmpval},com,Buf,"}",nl,
+ "end"])
+ end,
+ {call,D,asn1ct_imm:per_dec_open_type(Aligned)}.
diff --git a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl
index 16eec92847..4f4563833f 100644
--- a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl
+++ b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl
@@ -69,18 +69,6 @@ gen_encode(Erules,Typename,Type) when is_record(Type,type) ->
end,
case asn1ct_gen:type(InnerType) of
{constructed,bif} ->
- case InnerType of
- 'SET' ->
- true;
- 'SEQUENCE' ->
- true;
- _ ->
- emit({nl,"'enc_",asn1ct_gen:list2name(Typename),
- "'({'",asn1ct_gen:list2name(Typename),
- "',Val}",ObjFun,") ->",nl}),
- emit({"'enc_",asn1ct_gen:list2name(Typename),
- "'(Val",ObjFun,");",nl,nl})
- end,
emit({"'enc_",asn1ct_gen:list2name(Typename),"'(Val",ObjFun,
") ->",nl}),
asn1ct_gen:gen_encode_constructed(Erules,Typename,InnerType,Type);
@@ -176,7 +164,7 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) ->
{asis,NamedNumberList},")"})
end;
'NULL' ->
- emit({"?RT_PER:encode_null(",Value,")"});
+ emit("[]");
'OBJECT IDENTIFIER' ->
emit({"?RT_PER:encode_object_identifier(",Value,")"});
'RELATIVE-OID' ->
@@ -417,50 +405,50 @@ emit_enc_octet_string(_Erules,Constraint,Value) ->
asn1ct_name:new(tmpval),
emit({" begin",nl}),
emit({" [",{curr,tmpval},"] = ",Value,",",nl}),
- emit({" [10,8,",{curr,tmpval},"]",nl}),
+ emit([" [[10,8],",{curr,tmpval},"]",nl]),
emit(" end");
2 ->
asn1ct_name:new(tmpval),
- emit({" begin",nl}),
- emit({" [",{curr,tmpval},",",{next,tmpval},"] = ",
- Value,",",nl}),
- emit({" [[10,8,",{curr,tmpval},"],[10,8,",
- {next,tmpval},"]]",nl}),
- emit(" end"),
- asn1ct_name:new(tmpval);
- Sv when is_integer(Sv),Sv =< 256 ->
+ emit([" begin",nl,
+ " ",{curr,tmpval}," = ",Value,",",nl,
+ " case length(",{curr,tmpval},") of",nl,
+ " 2 ->",nl,
+ " [[45,16,2]|",{curr,tmpval},"];",nl,
+ " _ ->",nl,
+ " exit({error,{value_out_of_bounds,",
+ {curr,tmpval},"}})",nl,
+ " end",nl,
+ " end"]);
+ Sv when is_integer(Sv), Sv < 256 ->
asn1ct_name:new(tmpval),
- emit({" begin",nl}),
- emit({" case length(",Value,") of",nl}),
- emit([" ",{curr,tmpval}," when ",{curr,tmpval}," == ",Sv," ->"]),
- emit([" [2,20,",{curr,tmpval},",",Value,"];",nl]),
- emit({" _ -> exit({error,{value_out_of_bounds,",
- Value,"}})", nl," end",nl}),
- emit(" end");
+ asn1ct_name:new(tmplen),
+ emit([" begin",nl,
+ " ",{curr,tmpval}," = ",Value,",",nl,
+ " case length(",{curr,tmpval},") of",nl,
+ " ",Sv,"=",{curr,tmplen}," ->",nl,
+ " [20,",{curr,tmplen},"|",{curr,tmpval},"];",nl,
+ " _ ->",nl,
+ " exit({error,{value_out_of_bounds,",
+ {curr,tmpval},"}})",nl,
+ " end",nl,
+ " end"]);
Sv when is_integer(Sv),Sv =< 65535 ->
asn1ct_name:new(tmpval),
- emit({" begin",nl}),
- emit({" case length(",Value,") of",nl}),
- emit([" ",{curr,tmpval}," when ",{curr,tmpval}," == ",Sv," ->"]),
- emit([" [2,21,",{curr,tmpval},",",Value,"];",nl]),
- emit({" _ -> exit({error,{value_out_of_bounds,",
- Value,"}})",nl," end",nl}),
- emit(" end");
+ asn1ct_name:new(tmplen),
+ emit([" begin",nl,
+ " ",{curr,tmpval}," = ",Value,",",nl,
+ " case length(",{curr,tmpval},") of",nl,
+ " ",Sv,"=",{curr,tmplen}," ->",nl,
+ " [<<21,",{curr,tmplen},":16>>|",Value,"];",nl,
+ " _ ->",nl,
+ " exit({error,{value_out_of_bounds,",
+ {curr,tmpval},"}})",nl,
+ " end",nl,
+ " end"]);
C ->
emit({" ?RT_PER:encode_octet_string(",{asis,C},",false,",Value,")",nl})
end.
-emit_dec_octet_string(Constraint,BytesVar) ->
- case get_constraint(Constraint,'SizeConstraint') of
- 0 ->
- emit({" {[],",BytesVar,"}",nl});
- {_,0} ->
- emit({" {[],",BytesVar,"}",nl});
- C ->
- emit({" ?RT_PER:decode_octet_string(",BytesVar,",",
- {asis,C},",false)",nl})
- end.
-
emit_enc_integer_case(Value) ->
case get(component_type) of
{true,#'ComponentType'{prop=Prop}} ->
@@ -624,23 +612,6 @@ get_constraint(C,Key) ->
V
end.
-get_constraints(L=[{Key,_}],Key) ->
- L;
-get_constraints([],_) ->
- [];
-get_constraints(C,Key) ->
- {value,L} = keysearch_allwithkey(Key,1,C,[]),
- L.
-
-keysearch_allwithkey(Key,Ix,C,Acc) ->
- case lists:keysearch(Key,Ix,C) of
- false ->
- {value,Acc};
- {value,T} ->
- RestC = lists:delete(T,C),
- keysearch_allwithkey(Key,Ix,RestC,[T|Acc])
- end.
-
%% effective_constraint(Type,C)
%% Type = atom()
%% C = [C1,...]
@@ -657,69 +628,9 @@ keysearch_allwithkey(Key,Ix,C,Acc) ->
effective_constraint(integer,[C={{_,_},_}|_Rest]) -> % extension
[C]; %% [C|effective_constraint(integer,Rest)]; XXX what is possible ???
effective_constraint(integer,C) ->
- SVs = get_constraints(C,'SingleValue'),
- SV = effective_constr('SingleValue',SVs),
- VRs = get_constraints(C,'ValueRange'),
- VR = effective_constr('ValueRange',VRs),
- CRange = greatest_common_range(SV,VR),
- pre_encode(integer,CRange);
+ pre_encode(integer, asn1ct_imm:effective_constraint(integer, C));
effective_constraint(bitstring,C) ->
- get_constraint(C,'SizeConstraint').
-
-effective_constr(_,[]) ->
- [];
-effective_constr('SingleValue',List) ->
- SVList = lists:flatten(lists:map(fun(X)->element(2,X)end,List)),
- %% Sort and remove duplicates before generating SingleValue or ValueRange
- %% In case of ValueRange, also check for 'MIN and 'MAX'
- case lists:usort(SVList) of
- [N] ->
- [{'SingleValue',N}];
- L when is_list(L) ->
- [{'ValueRange',{least_Lb(L),greatest_Ub(L)}}]
- end;
-effective_constr('ValueRange',List) ->
- LBs = lists:map(fun({_,{Lb,_}})-> Lb end,List),
- UBs = lists:map(fun({_,{_,Ub}})-> Ub end,List),
- Lb = least_Lb(LBs),
- [{'ValueRange',{Lb,lists:max(UBs)}}].
-
-greatest_common_range([],VR) ->
- VR;
-greatest_common_range(SV,[]) ->
- SV;
-greatest_common_range([{_,Int}],[{_,{'MIN',Ub}}]) when is_integer(Int),
- Int > Ub ->
- [{'ValueRange',{'MIN',Int}}];
-greatest_common_range([{_,Int}],[{_,{Lb,Ub}}]) when is_integer(Int),
- Int < Lb ->
- [{'ValueRange',{Int,Ub}}];
-greatest_common_range([{_,Int}],VR=[{_,{_Lb,_Ub}}]) when is_integer(Int) ->
- VR;
-greatest_common_range([{_,L}],[{_,{Lb,Ub}}]) when is_list(L) ->
- Min = least_Lb([Lb|L]),
- Max = greatest_Ub([Ub|L]),
- [{'ValueRange',{Min,Max}}];
-greatest_common_range([{_,{Lb1,Ub1}}],[{_,{Lb2,Ub2}}]) ->
- Min = least_Lb([Lb1,Lb2]),
- Max = greatest_Ub([Ub1,Ub2]),
- [{'ValueRange',{Min,Max}}].
-
-
-least_Lb(L) ->
- case lists:member('MIN',L) of
- true -> 'MIN';
- _ -> lists:min(L)
- end.
-
-greatest_Ub(L) ->
- case lists:member('MAX',L) of
- true -> 'MAX';
- _ -> lists:max(L)
- end.
-
-
-
+ asn1ct_imm:effective_constraint(bitstring, C).
pre_encode(integer,[]) ->
[];
@@ -1380,7 +1291,6 @@ gen_objset_dec(ObjSetName,_,['EXTENSIONMARK'],_ClName,_ClFields,
_NthObj) ->
emit({"'getdec_",ObjSetName,"'(_, _) ->",nl}),
emit({indent(3),"fun(Attr1, Bytes, _, _) ->",nl}),
- %% emit({indent(6),"?RT_PER:decode_open_type(Bytes,[])",nl}),
emit({indent(6),"{Bytes,Attr1}",nl}),
emit({indent(3),"end.",nl,nl}),
ok;
@@ -1396,77 +1306,42 @@ emit_default_getdec(ObjSetName,UniqueName) ->
emit([indent(2), "fun(C,V,_,_) -> exit({{component,C},{value,V},{unique_name_and_value,",{asis,UniqueName},",ErrV}}) end"]).
-gen_inlined_dec_funs(Fields,[{typefield,Name,_}|Rest],
- ObjSetName,NthObj) ->
- CurrMod = get(currmod),
- InternalDefFunName = [NthObj,Name,ObjSetName],
- case lists:keysearch(Name,1,Fields) of
- {value,{_,Type}} when is_record(Type,type) ->
- emit({indent(3),"fun(Type, Val, _, _) ->",nl,
- indent(6),"case Type of",nl}),
- N=emit_inner_of_decfun(Type,InternalDefFunName),
- gen_inlined_dec_funs1(Fields,Rest,ObjSetName,NthObj+N);
- {value,{_,Type}} when is_record(Type,typedef) ->
- emit({indent(3),"fun(Type, Val, _, _) ->",nl,
- indent(6),"case Type of",nl}),
- emit({indent(9),{asis,Name}," ->",nl}),
- N=emit_inner_of_decfun(Type,InternalDefFunName),
- gen_inlined_dec_funs1(Fields,Rest,ObjSetName,NthObj+N);
- {value,{_,#'Externaltypereference'{module=CurrMod,type=T}}} ->
- emit({indent(3),"fun(Type, Val, _, _) ->",nl,
- indent(6),"case Type of",nl}),
- emit({indent(9),{asis,Name}," ->",nl}),
- emit([indent(12),"'dec_",T,"'(Val, telltype)"]),
- gen_inlined_dec_funs1(Fields,Rest,ObjSetName,NthObj);
- {value,{_,#'Externaltypereference'{module=M,type=T}}} ->
- emit({indent(3),"fun(Type, Val, _, _) ->",nl,
- indent(6),"case Type of",nl}),
- emit({indent(9),{asis,Name}," ->",nl}),
- emit([indent(12),"'",M,"':'dec_",T,"'(Val, telltype)"]),
- gen_inlined_dec_funs1(Fields,Rest,ObjSetName,NthObj);
- false ->
- emit([indent(3),"fun(Type, Val, _, _) ->",nl,
- indent(6),"case Type of",nl,
- indent(9),{asis,Name}," -> {Val,Type}"]),
- gen_inlined_dec_funs1(Fields,Rest,ObjSetName,NthObj)
- end;
-gen_inlined_dec_funs(Fields,[_|Rest],ObjSetName,NthObj) ->
- gen_inlined_dec_funs(Fields,Rest,ObjSetName,NthObj);
-gen_inlined_dec_funs(_,[],_,NthObj) ->
+gen_inlined_dec_funs(Fields, List, ObjSetName, NthObj0) ->
+ emit([indent(3),"fun(Type, Val, _, _) ->",nl,
+ indent(6),"case Type of",nl]),
+ NthObj = gen_inlined_dec_funs1(Fields, List, ObjSetName, "", NthObj0),
+ emit([nl,indent(6),"end",nl,
+ indent(3),"end"]),
NthObj.
-gen_inlined_dec_funs1(Fields,[{typefield,Name,_}|Rest],
- ObjSetName,NthObj) ->
+gen_inlined_dec_funs1(Fields, [{typefield,Name,_}|Rest],
+ ObjSetName, Sep0, NthObj) ->
CurrentMod = get(currmod),
InternalDefFunName = [NthObj,Name,ObjSetName],
- N=
- case lists:keysearch(Name,1,Fields) of
- {value,{_,Type}} when is_record(Type,type) ->
- emit({";",nl}),
- emit_inner_of_decfun(Type,InternalDefFunName);
- {value,{_,Type}} when is_record(Type,typedef) ->
- emit({";",nl,indent(9),{asis,Name}," ->",nl}),
- emit_inner_of_decfun(Type,InternalDefFunName);
- {value,{_,#'Externaltypereference'{module=CurrentMod,type=T}}} ->
- emit([";",nl,indent(9),{asis,Name}," ->",nl]),
- emit([indent(12),"'dec_",T,"'(Val,telltype)"]),
- 0;
- {value,{_,#'Externaltypereference'{module=M,type=T}}} ->
- emit([";",nl,indent(9),{asis,Name}," ->",nl]),
- emit([indent(12),"'",M,"':'dec_",T,"'(Val,telltype)"]),
- 0;
- false ->
- emit([";",nl,
- indent(9),{asis,Name}," -> {Val,Type}"]),
- 0
- end,
- gen_inlined_dec_funs1(Fields,Rest,ObjSetName,NthObj+N);
-gen_inlined_dec_funs1(Fields,[_|Rest],ObjSetName,NthObj)->
- gen_inlined_dec_funs1(Fields,Rest,ObjSetName,NthObj);
-gen_inlined_dec_funs1(_,[],_,NthObj) ->
- emit({nl,indent(6),"end",nl}),
- emit({indent(3),"end"}),
- NthObj.
+ emit(Sep0),
+ Sep = [";",nl],
+ N = case lists:keyfind(Name, 1, Fields) of
+ {_,#type{}=Type} ->
+ emit_inner_of_decfun(Type, InternalDefFunName);
+ {_,#typedef{}=Type} ->
+ emit([indent(9),{asis,Name}," ->",nl]),
+ emit_inner_of_decfun(Type, InternalDefFunName);
+ {_,#'Externaltypereference'{module=CurrentMod,type=T}} ->
+ emit([indent(9),{asis,Name}," ->",nl,
+ indent(12),"'dec_",T,"'(Val,telltype)"]),
+ 0;
+ {_,#'Externaltypereference'{module=M,type=T}} ->
+ emit([indent(9),{asis,Name}," ->",nl,
+ indent(12),"'",M,"':'dec_",T,"'(Val,telltype)"]),
+ 0;
+ false ->
+ emit([indent(9),{asis,Name}," -> {Val,Type}"]),
+ 0
+ end,
+ gen_inlined_dec_funs1(Fields, Rest, ObjSetName, Sep, NthObj+N);
+gen_inlined_dec_funs1(Fields, [_|Rest], ObjSetName, Sep, NthObj) ->
+ gen_inlined_dec_funs1(Fields, Rest, ObjSetName, Sep, NthObj);
+gen_inlined_dec_funs1(_, [], _, _, NthObj) -> NthObj.
emit_inner_of_decfun(#typedef{name={ExtName,Name},typespec=Type},
InternalDefFunName) ->
@@ -1586,17 +1461,9 @@ gen_dec_prim(Erules,Att,BytesVar) ->
Constraint = Att#type.constraint,
case Typename of
'INTEGER' ->
- EffectiveConstr = effective_constraint(integer,Constraint),
- emit_dec_integer(EffectiveConstr,BytesVar);
-% emit({"?RT_PER:decode_integer(",BytesVar,",",
-% {asis,EffectiveConstr},")"});
- {'INTEGER',NamedNumberList} ->
- EffectiveConstr = effective_constraint(integer,Constraint),
- emit_dec_integer(EffectiveConstr,BytesVar,NamedNumberList);
-% emit({"?RT_PER:decode_integer(",BytesVar,",",
-% {asis,EffectiveConstr},",",
-% {asis,NamedNumberList},")"});
-
+ asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar);
+ {'INTEGER',_NamedNumberList} ->
+ asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar);
'REAL' ->
emit(["?RT_PER:decode_real(",BytesVar,")"]);
@@ -1612,8 +1479,7 @@ gen_dec_prim(Erules,Att,BytesVar) ->
{asis,NamedNumberList},")"})
end;
'NULL' ->
- emit({"?RT_PER:decode_null(",
- BytesVar,")"});
+ emit({"{'NULL',",BytesVar,"}"});
'OBJECT IDENTIFIER' ->
emit({"?RT_PER:decode_object_identifier(",
BytesVar,")"});
@@ -1623,23 +1489,13 @@ gen_dec_prim(Erules,Att,BytesVar) ->
'ObjectDescriptor' ->
emit({"?RT_PER:decode_ObjectDescriptor(",
BytesVar,")"});
- {'ENUMERATED',{NamedNumberList1,NamedNumberList2}} ->
- NewTup = {list_to_tuple([X||{X,_} <- NamedNumberList1]),
- list_to_tuple([X||{X,_} <- NamedNumberList2])},
- NewC = [{'ValueRange',{0,size(element(1,NewTup))-1}}],
- emit({"?RT_PER:decode_enumerated(",BytesVar,",",
- {asis,NewC},",",
- {asis,NewTup},")"});
- {'ENUMERATED',NamedNumberList} ->
- NewNNL = [X||{X,_} <- NamedNumberList],
- NewC = effective_constraint(integer,
- [{'ValueRange',{0,length(NewNNL)-1}}]),
- emit_dec_enumerated(BytesVar,NewC,NewNNL);
+ {'ENUMERATED',_} ->
+ asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar);
'BOOLEAN'->
- emit({"?RT_PER:decode_boolean(",BytesVar,")"});
+ asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar);
'OCTET STRING' ->
- emit_dec_octet_string(Constraint,BytesVar);
+ asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar);
'NumericString' ->
emit_dec_known_multiplier_string('NumericString',
@@ -1686,25 +1542,9 @@ gen_dec_prim(Erules,Att,BytesVar) ->
'UTF8String' ->
emit({"?RT_PER:decode_UTF8String(",BytesVar,")"});
'ANY' ->
- emit(["?RT_PER:decode_open_type(",BytesVar,",",
- {asis,Constraint}, ")"]);
+ asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar);
'ASN1_OPEN_TYPE' ->
- case Constraint of
- [#'Externaltypereference'{type=Tname}] ->
- emit(["fun(FBytes) ->",nl,
- " {XTerm,XBytes} = "]),
- emit(["?RT_PER:decode_open_type(FBytes,[]),",nl]),
- emit([" {YTerm,_} = dec_",Tname,"(XTerm,mandatory),",nl]),
- emit([" {YTerm,XBytes} end(",BytesVar,")"]);
- [#type{def=#'Externaltypereference'{type=Tname}}] ->
- emit(["fun(FBytes) ->",nl,
- " {XTerm,XBytes} = "]),
- emit(["?RT_PER:decode_open_type(FBytes,[]),",nl]),
- emit([" {YTerm,_} = dec_",Tname,"(XTerm,mandatory),",nl]),
- emit([" {YTerm,XBytes} end(",BytesVar,")"]);
- _ ->
- emit(["?RT_PER:decode_open_type(",BytesVar,",[])"])
- end;
+ asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar);
#'ObjectClassFieldType'{} ->
case asn1ct_gen:get_inner(Att#type.def) of
{fixedtypevaluefield,_,InnerType} ->
@@ -1716,88 +1556,6 @@ gen_dec_prim(Erules,Att,BytesVar) ->
exit({'cant decode' ,Other})
end.
-
-emit_dec_integer(C,BytesVar,NNL) ->
- asn1ct_name:new(tmpterm),
- asn1ct_name:new(buffer),
- Tmpterm = asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),
- Buffer = asn1ct_gen:mk_var(asn1ct_name:curr(buffer)),
- emit({" begin {",{curr,tmpterm},",",{curr,buffer},"} = ",nl}),
- emit_dec_integer(C,BytesVar),
- emit({",",nl," case ",Tmpterm," of",nl}),
- lists:map(fun({Name,Int})->emit({" ",Int," -> {",{asis,Name},",",
- Buffer,"};",nl});
- (_)-> exit({error,{asn1,{"error in named number list",NNL}}})
- end,
- NNL),
- emit({" _ -> {",Tmpterm,",",Buffer,"}",nl}),
- emit({" end",nl}), % end of case
- emit(" end"). % end of begin
-
-emit_dec_integer([{'SingleValue',Int}],BytesVar) when is_integer(Int) ->
- emit(["{",Int,",",BytesVar,"}"]);
-emit_dec_integer([{_,{Lb,_Ub},_Range,{BitsOrOctets,N}}],BytesVar) ->
- GetBorO =
- case BitsOrOctets of
- bits -> "getbits";
- _ -> "getoctets"
- end,
- asn1ct_name:new(tmpterm),
- asn1ct_name:new(tmpremain),
- emit({" begin",nl," {",{curr,tmpterm},",",{curr,tmpremain},"}=",
- "?RT_PER:",GetBorO,"(",BytesVar,",",N,"),",nl}),
- emit({" {",{curr,tmpterm},"+",Lb,",",{curr,tmpremain},"}",nl,
- " end"});
-emit_dec_integer([{_,{'MIN',_}}],BytesVar) ->
- emit({"?RT_PER:decode_unconstrained_number(",BytesVar,")"});
-emit_dec_integer([{_,{Lb,'MAX'}}],BytesVar) ->
- emit({"?RT_PER:decode_semi_constrained_number(",BytesVar,",",Lb,")"});
-emit_dec_integer([{'ValueRange',VR={Lb,Ub}}],BytesVar) ->
- Range = Ub-Lb+1,
- emit({"?RT_PER:decode_constrained_number(",BytesVar,",",
- {asis,VR},",",Range,")"});
-emit_dec_integer(C=[{Rc,_}],BytesVar) when is_tuple(Rc) ->
- emit({"?RT_PER:decode_integer(",BytesVar,",",{asis,C},")"});
-emit_dec_integer(_,BytesVar) ->
- emit({"?RT_PER:decode_unconstrained_number(",BytesVar,")"}).
-
-
-emit_dec_enumerated(BytesVar,C,NamedNumberList) ->
- emit_dec_enumerated_begin(),% emits a begin if component
- asn1ct_name:new(tmpterm),
- Tmpterm = asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),
- asn1ct_name:new(tmpremain),
- Tmpremain = asn1ct_gen:mk_var(asn1ct_name:curr(tmpremain)),
- emit({" {",{curr,tmpterm},",",{curr,tmpremain},"} =",nl}),
- emit_dec_integer(C,BytesVar),
- emit({",",nl," case ",Tmpterm," of "}),
-
- Cases=lists:flatten(dec_enumerated_cases(NamedNumberList,Tmpremain,0)),
- emit({Cases++"_->exit({error,{asn1,{decode_enumerated,{",Tmpterm,
- ",",{asis,NamedNumberList},"}}}}) end",nl}),
- emit_dec_enumerated_end().
-
-emit_dec_enumerated_begin() ->
- case get(component_type) of
- {true,_} ->
- emit({" begin",nl});
- _ -> ok
- end.
-
-emit_dec_enumerated_end() ->
- case get(component_type) of
- {true,_} ->
- emit(" end");
- _ -> ok
- end.
-
-
-dec_enumerated_cases([Name|Rest],Tmpremain,No) ->
- io_lib:format("~w->{~w,~s};",[No,Name,Tmpremain])++
- dec_enumerated_cases(Rest,Tmpremain,No+1);
-dec_enumerated_cases([],_,_) ->
- "".
-
%% For PER the ExtensionAdditionGroup notation has significance for the encoding and decoding
%% the components within the ExtensionAdditionGroup is treated in a similar way as if they
%% have been specified within a SEQUENCE, therefore we construct a fake sequence type here
diff --git a/lib/asn1/src/asn1ct_imm.erl b/lib/asn1/src/asn1ct_imm.erl
new file mode 100644
index 0000000000..34bb0b8714
--- /dev/null
+++ b/lib/asn1/src/asn1ct_imm.erl
@@ -0,0 +1,626 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012. All Rights Reserved.
+%%
+%% The 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(asn1ct_imm).
+-export([per_dec_boolean/0,per_dec_enumerated/2,per_dec_enumerated/3,
+ per_dec_extension_map/1,
+ per_dec_integer/2,per_dec_length/3,per_dec_named_integer/3,
+ per_dec_octet_string/2,per_dec_open_type/1]).
+-export([optimize_alignment/1,optimize_alignment/2,
+ dec_slim_cg/2,dec_code_gen/2]).
+-export([effective_constraint/2]).
+-import(asn1ct_gen, [emit/1]).
+
+-record(st, {var,
+ base}).
+
+dec_slim_cg(Imm0, BytesVar) ->
+ {Imm,_} = optimize_alignment(Imm0),
+ asn1ct_name:new(v),
+ [H|T] = atom_to_list(asn1ct_name:curr(v)) ++ "@",
+ VarBase = [H-($a-$A)|T],
+ St0 = #st{var=0,base=VarBase},
+ {Res,Pre,_} = flatten(Imm, BytesVar, St0),
+ dcg_list_outside(Pre),
+ Res.
+
+dec_code_gen(Imm, BytesVar) ->
+ emit(["begin",nl]),
+ {Dst,DstBuf} = dec_slim_cg(Imm, BytesVar),
+ emit([",",nl,
+ "{",Dst,",",DstBuf,"}",nl,
+ "end"]),
+ ok.
+
+optimize_alignment(Imm) ->
+ opt_al(Imm, unknown).
+
+optimize_alignment(Imm, Al) ->
+ opt_al(Imm, Al).
+
+
+per_dec_boolean() ->
+ {map,{get_bits,1,[1]},[{0,false},{1,true}]}.
+
+per_dec_enumerated(NamedList0, Aligned) ->
+ Constraint = [{'ValueRange',{0,length(NamedList0)-1}}],
+ NamedList = per_dec_enumerated_fix_list(NamedList0, [enum_error], 0),
+ Int = per_dec_integer(Constraint, Aligned),
+ {map,Int,NamedList}.
+
+per_dec_enumerated(BaseNamedList, NamedListExt0, Aligned) ->
+ Base = per_dec_enumerated(BaseNamedList, Aligned),
+ NamedListExt = per_dec_enumerated_fix_list(NamedListExt0,
+ [enum_default], 0),
+ Ext = {map,per_dec_normally_small_number(Aligned),NamedListExt},
+ bit_case(Base, Ext).
+
+per_dec_extension_map(Aligned) ->
+ Len = {add,per_dec_normally_small_number(Aligned),1},
+ {get_bits,Len,[1,bitstring]}.
+
+per_dec_integer(Constraint0, Aligned) ->
+ Constraint = effective_constraint(integer, Constraint0),
+ per_dec_integer_1(Constraint, Aligned).
+
+per_dec_length(SingleValue, _, _Aligned) when is_integer(SingleValue) ->
+ {value,SingleValue};
+per_dec_length({S,S}, _, _Aligned) when is_integer(S) ->
+ {value,S};
+per_dec_length({{_,_}=Constr,_}, AllowZero, Aligned) ->
+ bit_case(per_dec_length(Constr, AllowZero, Aligned),
+ per_dec_length(undefined, AllowZero, Aligned));
+per_dec_length({Lb,Ub}, _AllowZero, Aligned) when is_integer(Lb),
+ is_integer(Lb),
+ Ub =< 65535 ->
+ per_dec_constrained(Lb, Ub, Aligned);
+per_dec_length({_,_}, AllowZero, Aligned) ->
+ decode_unconstrained_length(AllowZero, Aligned);
+per_dec_length(undefined, AllowZero, Aligned) ->
+ decode_unconstrained_length(AllowZero, Aligned).
+
+per_dec_named_integer(Constraint, NamedList0, Aligned) ->
+ Int = per_dec_integer(Constraint, Aligned),
+ NamedList = [{K,V} || {V,K} <- NamedList0] ++ [integer_default],
+ {map,Int,NamedList}.
+
+per_dec_octet_string(Constraint, Aligned) ->
+ dec_string(Constraint, 8, Aligned).
+
+per_dec_open_type(Aligned) ->
+ {get_bits,decode_unconstrained_length(true, Aligned),
+ [8,binary,{align,Aligned}]}.
+
+
+%%%
+%%% Local functions.
+%%%
+
+dec_string(Sv, U, _Aligned) when is_integer(Sv), U*Sv =< 16 ->
+ {get_bits,Sv,[U,binary]};
+dec_string(Sv, U, Aligned) when is_integer(Sv), Sv < 16#10000 ->
+ {get_bits,Sv,[U,binary,{align,Aligned}]};
+dec_string(C, U, Aligned) when is_list(C) ->
+ dec_string({hd(C),lists:max(C)}, U, Aligned);
+dec_string({Sv,Sv}, U, Aligned) ->
+ dec_string(Sv, U, Aligned);
+dec_string({{_,_}=C,_}, U, Aligned) ->
+ bit_case(dec_string(C, U, Aligned),
+ dec_string(no, U, Aligned));
+dec_string({Lb,Ub}, U, Aligned) when Ub < 16#10000 ->
+ Len = per_dec_constrained(Lb, Ub, Aligned),
+ {get_bits,Len,[U,binary,{align,Aligned}]};
+dec_string(_, U, Aligned) ->
+ Al = [{align,Aligned}],
+ DecRest = fun(V, Buf) ->
+ emit(["?RT_PER:decode_fragmented(",V,", ",
+ Buf,", ",U,")"])
+ end,
+ {'case',[{test,{get_bits,1,[1|Al]},0,
+ {value,{get_bits,
+ {get_bits,7,[1]},
+ [U,binary]}}},
+ {test,{get_bits,1,[1|Al]},1,
+ {test,{get_bits,1,[1]},0,
+ {value,{get_bits,
+ {get_bits,14,[1]},
+ [U,binary]}}}},
+ {test,{get_bits,1,[1|Al]},1,
+ {test,{get_bits,1,[1]},1,
+ {value,{call,DecRest,{get_bits,6,[1]}}}}}]}.
+
+per_dec_enumerated_fix_list([{V,_}|T], Tail, N) ->
+ [{N,V}|per_dec_enumerated_fix_list(T, Tail, N+1)];
+per_dec_enumerated_fix_list([], Tail, _) -> Tail.
+
+per_dec_integer_1([{'SingleValue',Value}], _Aligned) ->
+ {value,Value};
+per_dec_integer_1([{'ValueRange',{Lb,'MAX'}}], Aligned) when is_integer(Lb) ->
+ per_dec_unconstrained(Aligned);
+per_dec_integer_1([{'ValueRange',{Lb,Ub}}], Aligned) when is_integer(Lb),
+ is_integer(Ub) ->
+ per_dec_constrained(Lb, Ub, Aligned);
+per_dec_integer_1([{{_,_}=Constr0,_}], Aligned) ->
+ Constr = effective_constraint(integer, [Constr0]),
+ bit_case(per_dec_integer(Constr, Aligned),
+ per_dec_unconstrained(Aligned));
+per_dec_integer_1([], Aligned) ->
+ per_dec_unconstrained(Aligned).
+
+per_dec_unconstrained(Aligned) ->
+ {get_bits,decode_unconstrained_length(false, Aligned),[8,signed]}.
+
+per_dec_constrained(Lb, Ub, false) ->
+ Range = Ub - Lb + 1,
+ Get = {get_bits,uper_num_bits(Range),[1]},
+ add_lb(Lb, Get);
+per_dec_constrained(Lb, Ub, true) ->
+ Range = Ub - Lb + 1,
+ Get = if
+ Range =< 255 ->
+ {get_bits,per_num_bits(Range),[1,unsigned]};
+ Range == 256 ->
+ {get_bits,1,[8,unsigned,{align,true}]};
+ Range =< 65536 ->
+ {get_bits,2,[8,unsigned,{align,true}]};
+ true ->
+ RangeOctLen = byte_size(binary:encode_unsigned(Range - 1)),
+ {get_bits,per_dec_length({1,RangeOctLen}, false, true),
+ [8,unsigned,{align,true}]}
+ end,
+ add_lb(Lb, Get).
+
+add_lb(0, Get) -> Get;
+add_lb(Lb, Get) -> {add,Get,Lb}.
+
+per_dec_normally_small_number(Aligned) ->
+ Small = {get_bits,6,[1]},
+ Unlimited = per_decode_semi_constrained(0, Aligned),
+ bit_case(Small, Unlimited).
+
+per_decode_semi_constrained(Lb, Aligned) ->
+ add_lb(Lb, {get_bits,decode_unconstrained_length(false, Aligned),[8]}).
+
+bit_case(Base, Ext) ->
+ {'case',[{test,{get_bits,1,[1]},0,Base},
+ {test,{get_bits,1,[1]},1,Ext}]}.
+
+decode_unconstrained_length(AllowZero, Aligned) ->
+ Al = [{align,Aligned}],
+ Zero = case AllowZero of
+ false -> [non_zero];
+ true -> []
+ end,
+ {'case',[{test,{get_bits,1,[1|Al]},0,
+ {value,{get_bits,7,[1|Zero]}}},
+ {test,{get_bits,1,[1|Al]},1,
+ {test,{get_bits,1,[1]},0,
+ {value,{get_bits,14,[1|Zero]}}}}]}.
+
+uper_num_bits(N) ->
+ uper_num_bits(N, 1, 0).
+
+uper_num_bits(N, T, B) when N =< T -> B;
+uper_num_bits(N, T, B) -> uper_num_bits(N, T bsl 1, B+1).
+
+per_num_bits(2) -> 1;
+per_num_bits(N) when N =< 4 -> 2;
+per_num_bits(N) when N =< 8 -> 3;
+per_num_bits(N) when N =< 16 -> 4;
+per_num_bits(N) when N =< 32 -> 5;
+per_num_bits(N) when N =< 64 -> 6;
+per_num_bits(N) when N =< 128 -> 7;
+per_num_bits(N) when N =< 255 -> 8.
+
+%%%
+%%% Remove unnecessary aligning to octet boundaries.
+%%%
+
+opt_al({get_bits,E0,Opts0}, A0) ->
+ {E,A1} = opt_al(E0, A0),
+ Opts = opt_al_1(A1, Opts0),
+ A = update_al(A1, E, Opts),
+ {{get_bits,E,Opts},A};
+opt_al({call,Fun,E0}, A0) ->
+ {E,A} = opt_al(E0, A0),
+ {{call,Fun,E},A};
+opt_al({convert,Op,E0}, A0) ->
+ {E,A} = opt_al(E0, A0),
+ {{convert,Op,E},A};
+opt_al({value,E0}, A0) ->
+ {E,A} = opt_al(E0, A0),
+ {{value,E},A};
+opt_al({add,E0,I}, A0) when is_integer(I) ->
+ {E,A} = opt_al(E0, A0),
+ {{add,E,I},A};
+opt_al({test,E0,V,B0}, A0) ->
+ {E,A1} = opt_al(E0, A0),
+ {B,A2} = opt_al(B0, A1),
+ {{test,E,V,B},A2};
+opt_al({'case',Cs0}, A0) ->
+ {Cs,A} = opt_al_cs(Cs0, A0),
+ {{'case',Cs},A};
+opt_al({map,E0,Cs}, A0) ->
+ {E,A} = opt_al(E0, A0),
+ {{map,E,Cs},A};
+opt_al(I, A) when is_integer(I) ->
+ {I,A}.
+
+opt_al_cs([C0|Cs0], A0) ->
+ {C,A1} = opt_al(C0, A0),
+ {Cs,A2} = opt_al_cs(Cs0, A0),
+ {[C|Cs],merge_al(A1, A2)};
+opt_al_cs([], _) -> {[],none}.
+
+merge_al(unknown, _) -> unknown;
+merge_al(Other, none) -> Other;
+merge_al(_, unknown) -> unknown;
+merge_al(I0, I1) ->
+ case {I0 rem 8,I1 rem 8} of
+ {I,I} -> I;
+ {_,_} -> unknown
+ end.
+
+opt_al_1(unknown, Opts) ->
+ Opts;
+opt_al_1(A, Opts0) ->
+ case alignment(Opts0) of
+ none ->
+ Opts0;
+ full ->
+ case A rem 8 of
+ 0 ->
+ %% Already in alignment.
+ proplists:delete(align, Opts0);
+ Bits ->
+ %% Cheaper alignment with a constant padding.
+ Opts1 = proplists:delete(align, Opts0),
+ [{align,8-Bits }|Opts1]
+ end;
+ A -> %Assertion.
+ Opts0
+ end.
+
+update_al(A0, E, Opts) ->
+ A = case alignment(Opts) of
+ none -> A0;
+ full -> 0;
+ Bits when is_integer(A0) ->
+ 0 = (A0 + Bits) rem 8; %Assertion.
+ _ ->
+ 0
+ end,
+ [U] = [U || U <- Opts, is_integer(U)],
+ if
+ U rem 8 =:= 0 -> A;
+ is_integer(A), is_integer(E) -> A + U*E;
+ true -> unknown
+ end.
+
+%%%
+%%% Flatten the intermediate format and assign temporaries.
+%%%
+
+flatten({get_bits,I,U}, Buf0, St0) when is_integer(I) ->
+ {Dst,St} = new_var_pair(St0),
+ Gb = {get_bits,{I,Buf0},U,Dst},
+ flatten_align(Gb, [], St);
+flatten({get_bits,E0,U}, Buf0, St0) ->
+ {E,Pre,St1} = flatten(E0, Buf0, St0),
+ {Dst,St2} = new_var_pair(St1),
+ Gb = {get_bits,E,U,Dst},
+ flatten_align(Gb, Pre, St2);
+flatten({test,{get_bits,I,U},V,E0}, Buf0, St0) when is_integer(I) ->
+ {DstBuf0,St1} = new_var("Buf", St0),
+ Gb = {get_bits,{I,Buf0},U,{V,DstBuf0}},
+ {{_Dst,DstBuf},Pre0,St2} = flatten_align(Gb, [], St1),
+ {E,Pre1,St3} = flatten(E0, DstBuf, St2),
+ {E,Pre0++Pre1,St3};
+flatten({add,E0,I}, Buf0, St0) ->
+ {{Src,Buf},Pre,St1} = flatten(E0, Buf0, St0),
+ {Dst,St} = new_var("Add", St1),
+ {{Dst,Buf},Pre++[{add,Src,I,Dst}],St};
+flatten({'case',Cs0}, Buf0, St0) ->
+ {Dst,St1} = new_var_pair(St0),
+ {Cs1,St} = flatten_cs(Cs0, Buf0, St1),
+ {Al,Cs2} = flatten_hoist_align(Cs1),
+ {Dst,Al++[{'case',Buf0,Cs2,Dst}],St};
+flatten({map,E0,Cs0}, Buf0, St0) ->
+ {{E,DstBuf},Pre,St1} = flatten(E0, Buf0, St0),
+ {Dst,St2} = new_var("Int", St1),
+ Cs = flatten_map_cs(Cs0, E),
+ {{Dst,DstBuf},Pre++[{'map',E,Cs,{Dst,DstBuf}}],St2};
+flatten({value,V0}, Buf0, St0) when is_integer(V0) ->
+ {{V0,Buf0},[],St0};
+flatten({value,V0}, Buf0, St0) ->
+ flatten(V0, Buf0, St0);
+flatten({convert,Op,E0}, Buf0, St0) ->
+ {{E,Buf},Pre,St1} = flatten(E0, Buf0, St0),
+ {Dst,St2} = new_var("Conv", St1),
+ {{Dst,Buf},Pre++[{convert,Op,E,Dst}],St2};
+flatten({call,Fun,E0}, Buf0, St0) ->
+ {Src,Pre,St1} = flatten(E0, Buf0, St0),
+ {Dst,St2} = new_var_pair(St1),
+ {Dst,Pre++[{call,Fun,Src,Dst}],St2}.
+
+flatten_cs([C0|Cs0], Buf, St0) ->
+ {C,Pre,St1} = flatten(C0, Buf, St0),
+ {Cs,St2} = flatten_cs(Cs0, Buf, St0),
+ St3 = St2#st{var=max(St1#st.var, St2#st.var)},
+ {[Pre++[{return,C}]|Cs],St3};
+flatten_cs([], _, St) -> {[],St}.
+
+flatten_map_cs(Cs, Var) ->
+ flatten_map_cs_1(Cs, {Var,Cs}).
+
+flatten_map_cs_1([{K,V}|Cs], DefData) ->
+ [{{asis,K},{asis,V}}|flatten_map_cs_1(Cs, DefData)];
+flatten_map_cs_1([integer_default], {Int,_}) ->
+ [{'_',Int}];
+flatten_map_cs_1([enum_default], {Int,_}) ->
+ [{'_',["{asn1_enum,",Int,"}"]}];
+flatten_map_cs_1([enum_error], {Var,Cs}) ->
+ Vs = [V || {_,V} <- Cs],
+ [{'_',["exit({error,{asn1,{decode_enumerated,{",Var,",",
+ {asis,Vs},"}}}})"]}];
+flatten_map_cs_1([], _) -> [].
+
+flatten_hoist_align([[{align_bits,_,_}=Ab|T]|Cs]) ->
+ flatten_hoist_align_1(Cs, Ab, [T]);
+flatten_hoist_align(Cs) -> {[],Cs}.
+
+flatten_hoist_align_1([[Ab|T]|Cs], Ab, Acc) ->
+ flatten_hoist_align_1(Cs, Ab, [T|Acc]);
+flatten_hoist_align_1([], Ab, Acc) ->
+ {[Ab],lists:reverse(Acc)}.
+
+flatten_align({get_bits,{SrcBits,SrcBuf},U,Dst}=Gb0, Pre, St0) ->
+ case alignment(U) of
+ none ->
+ flatten_align_1(U, Dst, Pre++[Gb0], St0);
+ full ->
+ {PadBits,St1} = new_var("Pad", St0),
+ {DstBuf,St2} = new_var("Buf", St1),
+ Ab = {align_bits,SrcBuf,PadBits},
+ Agb = {get_bits,{PadBits,SrcBuf},[1],{'_',DstBuf}},
+ Gb = {get_bits,{SrcBits,DstBuf},U,Dst},
+ flatten_align_1(U, Dst, Pre++[Ab,Agb,Gb], St2);
+ PadBits when is_integer(PadBits), PadBits > 0 ->
+ {DstBuf,St1} = new_var("Buf", St0),
+ Agb = {get_bits,{PadBits,SrcBuf},[1],{'_',DstBuf}},
+ Gb = {get_bits,{SrcBits,DstBuf},U,Dst},
+ flatten_align_1(U, Dst, Pre++[Agb,Gb], St1)
+ end.
+
+flatten_align_1(U, {D,_}=Dst, Pre, St) ->
+ case is_non_zero(U) of
+ false ->
+ {Dst,Pre,St};
+ true ->
+ {Dst,Pre++[{non_zero,D}],St}
+ end.
+
+new_var_pair(St0) ->
+ {Var,St1} = new_var("V", St0),
+ {Buf,St2} = new_var("Buf", St1),
+ {{Var,Buf},St2}.
+
+new_var(Tag, #st{base=VarBase,var=N}=St) ->
+ {VarBase++Tag++integer_to_list(N),St#st{var=N+1}}.
+
+alignment([{align,false}|_]) -> none;
+alignment([{align,true}|_]) -> full;
+alignment([{align,Bits}|_]) -> Bits;
+alignment([_|T]) -> alignment(T);
+alignment([]) -> none.
+
+is_non_zero(Fl) ->
+ lists:member(non_zero, Fl).
+
+%%%
+%%% Generate Erlang code from the flattened intermediate format.
+%%%
+
+dcg_list_outside([{align_bits,Buf,SzVar}|T]) ->
+ emit([SzVar," = bit_size(",Buf,") band 7"]),
+ iter_dcg_list_outside(T);
+dcg_list_outside([{'case',Buf,Cs,Dst}|T]) ->
+ dcg_case(Buf, Cs, Dst),
+ iter_dcg_list_outside(T);
+dcg_list_outside([{'map',Val,Cs,Dst}|T]) ->
+ dcg_map(Val, Cs, Dst),
+ iter_dcg_list_outside(T);
+dcg_list_outside([{add,S1,S2,Dst}|T]) ->
+ emit([Dst," = ",S1," + ",S2]),
+ iter_dcg_list_outside(T);
+dcg_list_outside([{return,{V,Buf}}|T]) ->
+ emit(["{",V,",",Buf,"}"]),
+ iter_dcg_list_outside(T);
+dcg_list_outside([{call,Fun,{V,Buf},{Dst,DstBuf}}|T]) ->
+ emit(["{",Dst,",",DstBuf,"} = "]),
+ Fun(V, Buf),
+ iter_dcg_list_outside(T);
+dcg_list_outside([{convert,Op,V,Dst}|T]) ->
+ emit([Dst," = ",Op,"(",V,")"]),
+ iter_dcg_list_outside(T);
+dcg_list_outside([{get_bits,{_,Buf0},_,_}|_]=L0) ->
+ emit("<<"),
+ {L,Buf} = dcg_list_inside(L0, buf),
+ emit([Buf,"/bitstring>> = ",Buf0]),
+ iter_dcg_list_outside(L);
+dcg_list_outside([]) ->
+ emit("ignore"),
+ ok.
+
+iter_dcg_list_outside([_|_]=T) ->
+ emit([",",nl]),
+ dcg_list_outside(T);
+iter_dcg_list_outside([]) -> ok.
+
+dcg_case(Buf, Cs, {Dst,DstBuf}) ->
+ emit(["{",Dst,",",DstBuf,"} = case ",Buf," of",nl]),
+ dcg_case_cs(Cs),
+ emit("end").
+
+dcg_case_cs([C|Cs]) ->
+ emit("<<"),
+ {T0,DstBuf} = dcg_list_inside(C, buf),
+ emit([DstBuf,"/bitstring>>"]),
+ T1 = dcg_guard(T0),
+ dcg_list_outside(T1),
+ case Cs of
+ [] -> emit([nl]);
+ [_|_] -> emit([";",nl])
+ end,
+ dcg_case_cs(Cs);
+dcg_case_cs([]) -> ok.
+
+dcg_guard([{non_zero,Src}|T]) ->
+ emit([" when ",Src," =/= 0 ->",nl]),
+ T;
+dcg_guard(T) ->
+ emit([" ->",nl]),
+ T.
+
+dcg_map(Val, Cs, {Dst,_}) ->
+ emit([Dst," = case ",Val," of",nl]),
+ dcg_map_cs(Cs),
+ emit("end").
+
+dcg_map_cs([{K,V}]) ->
+ emit([K," -> ",V,nl]);
+dcg_map_cs([{K,V}|Cs]) ->
+ emit([K," -> ",V,";",nl]),
+ dcg_map_cs(Cs).
+
+dcg_list_inside([{get_bits,{Sz,_},Fl0,{Dst,DstBuf}}|T], _) ->
+ Fl = bit_flags(Fl0, []),
+ emit([mk_dest(Dst),":",Sz,Fl,","]),
+ dcg_list_inside(T, DstBuf);
+dcg_list_inside(L, Dst) -> {L,Dst}.
+
+bit_flags([1|T], Acc) ->
+ bit_flags(T, Acc);
+bit_flags([{align,_}|T], Acc) ->
+ bit_flags(T, Acc);
+bit_flags([non_zero|T], Acc) ->
+ bit_flags(T, Acc);
+bit_flags([U|T], Acc) when is_integer(U) ->
+ bit_flags(T, ["unit:"++integer_to_list(U)|Acc]);
+bit_flags([H|T], Acc) ->
+ bit_flags(T, [atom_to_list(H)|Acc]);
+bit_flags([], []) ->
+ "";
+bit_flags([], Acc) ->
+ "/" ++ bit_flags_1(Acc, "").
+
+bit_flags_1([H|T], Sep) ->
+ Sep ++ H ++ bit_flags_1(T, "-");
+bit_flags_1([], _) -> [].
+
+mk_dest(I) when is_integer(I) ->
+ integer_to_list(I);
+mk_dest(S) -> S.
+
+%% effective_constraint(Type,C)
+%% Type = atom()
+%% C = [C1,...]
+%% C1 = {'SingleValue',SV} | {'ValueRange',VR} | {atom(),term()}
+%% SV = integer() | [integer(),...]
+%% VR = {Lb,Ub}
+%% Lb = 'MIN' | integer()
+%% Ub = 'MAX' | integer()
+%% Returns a single value if C only has a single value constraint, and no
+%% value range constraints, that constrains to a single value, otherwise
+%% returns a value range that has the lower bound set to the lowest value
+%% of all single values and lower bound values in C and the upper bound to
+%% the greatest value.
+effective_constraint(integer,[C={{_,_},_}|_Rest]) -> % extension
+ [C];
+effective_constraint(integer, C) ->
+ SVs = get_constraints(C, 'SingleValue'),
+ SV = effective_constr('SingleValue', SVs),
+ VRs = get_constraints(C, 'ValueRange'),
+ VR = effective_constr('ValueRange', VRs),
+ greatest_common_range(SV, VR);
+effective_constraint(bitstring, C) ->
+ get_constraint(C, 'SizeConstraint').
+
+effective_constr(_, []) -> [];
+effective_constr('SingleValue', List) ->
+ SVList = lists:flatten(lists:map(fun(X) -> element(2, X) end, List)),
+ %% Sort and remove duplicates before generating SingleValue or ValueRange
+ %% In case of ValueRange, also check for 'MIN and 'MAX'
+ case lists:usort(SVList) of
+ [N] ->
+ [{'SingleValue',N}];
+ [_|_]=L ->
+ [{'ValueRange',{least_Lb(L),greatest_Ub(L)}}]
+ end;
+effective_constr('ValueRange', List) ->
+ LBs = lists:map(fun({_,{Lb,_}}) -> Lb end, List),
+ UBs = lists:map(fun({_,{_,Ub}}) -> Ub end, List),
+ Lb = least_Lb(LBs),
+ [{'ValueRange',{Lb,lists:max(UBs)}}].
+
+greatest_common_range([], VR) ->
+ VR;
+greatest_common_range(SV, []) ->
+ SV;
+greatest_common_range([{_,Int}], [{_,{'MIN',Ub}}])
+ when is_integer(Int), Int > Ub ->
+ [{'ValueRange',{'MIN',Int}}];
+greatest_common_range([{_,Int}],[{_,{Lb,Ub}}])
+ when is_integer(Int), Int < Lb ->
+ [{'ValueRange',{Int,Ub}}];
+greatest_common_range([{_,Int}],VR=[{_,{_Lb,_Ub}}]) when is_integer(Int) ->
+ VR;
+greatest_common_range([{_,L}],[{_,{Lb,Ub}}]) when is_list(L) ->
+ Min = least_Lb([Lb|L]),
+ Max = greatest_Ub([Ub|L]),
+ [{'ValueRange',{Min,Max}}];
+greatest_common_range([{_,{Lb1,Ub1}}], [{_,{Lb2,Ub2}}]) ->
+ Min = least_Lb([Lb1,Lb2]),
+ Max = greatest_Ub([Ub1,Ub2]),
+ [{'ValueRange',{Min,Max}}].
+
+
+least_Lb(L) ->
+ case lists:member('MIN', L) of
+ true -> 'MIN';
+ false -> lists:min(L)
+ end.
+
+greatest_Ub(L) ->
+ case lists:member('MAX', L) of
+ true -> 'MAX';
+ false -> lists:max(L)
+ end.
+
+get_constraint(C, Key) ->
+ case lists:keyfind(Key, 1, C) of
+ false -> no;
+ {_,V} -> V
+ end.
+
+get_constraints([{Key,_}=Pair|T], Key) ->
+ [Pair|get_constraints(T, Key)];
+get_constraints([_|T], Key) ->
+ get_constraints(T, Key);
+get_constraints([], _) -> [].
diff --git a/lib/asn1/src/asn1ct_parser2.erl b/lib/asn1/src/asn1ct_parser2.erl
index 7301f49085..9e1fcce2b1 100644
--- a/lib/asn1/src/asn1ct_parser2.erl
+++ b/lib/asn1/src/asn1ct_parser2.erl
@@ -924,19 +924,8 @@ parse_UnionsRec([{'|',_}|Rest]) ->
{V1,V2} ->
{[V1,union,V2],Rest3}
end;
-parse_UnionsRec([{'UNION',_}|Rest]) ->
- {InterSec,Rest2} = parse_Intersections(Rest),
- {URec,Rest3} = parse_UnionsRec(Rest2),
- case {InterSec,URec} of
- {V1,[]} ->
- {V1,Rest3};
- {{'SingleValue',V1},{'SingleValue',V2}} ->
- {{'SingleValue',ordsets:union(to_set(V1),to_set(V2))},Rest3};
- {V1,V2} when is_list(V2) ->
- {[V1] ++ [union|V2],Rest3};
- {V1,V2} ->
- {[V1,union,V2],Rest3}
- end;
+parse_UnionsRec([{'UNION',Info}|Rest]) ->
+ parse_UnionsRec([{'|',Info}|Rest]);
parse_UnionsRec(Tokens) ->
{[],Tokens}.
@@ -971,20 +960,8 @@ parse_IElemsRec([{'^',_}|Rest]) ->
{V1,V2} ->
{[V1,intersection,V2],Rest3}
end;
-parse_IElemsRec([{'INTERSECTION',_}|Rest]) ->
- {InterSec,Rest2} = parse_IntersectionElements(Rest),
- {IRec,Rest3} = parse_IElemsRec(Rest2),
- case {InterSec,IRec} of
- {{'SingleValue',V1},{'SingleValue',V2}} ->
- {{'SingleValue',
- ordsets:intersection(to_set(V1),to_set(V2))},Rest3};
- {V1,[]} ->
- {V1,Rest3};
- {V1,V2} when is_list(V2) ->
- {[V1] ++ [intersection|V2],Rest3};
- {V1,V2} ->
- {[V1,intersection,V2],Rest3}
- end;
+parse_IElemsRec([{'INTERSECTION',Info}|Rest]) ->
+ parse_IElemsRec([{'^',Info}|Rest]);
parse_IElemsRec(Tokens) ->
{[],Tokens}.
diff --git a/lib/asn1/src/asn1ct_value.erl b/lib/asn1/src/asn1ct_value.erl
index 9013baef92..389642c446 100644
--- a/lib/asn1/src/asn1ct_value.erl
+++ b/lib/asn1/src/asn1ct_value.erl
@@ -54,7 +54,7 @@ from_type(M,Typename,Type) when is_record(Type,type) ->
{notype,_} ->
true;
{primitive,bif} ->
- from_type_prim(Type,get_encoding_rule(M));
+ from_type_prim(Type);
'ASN1_OPEN_TYPE' ->
case Type#type.constraint of
[#'Externaltypereference'{type=TrefConstraint}] ->
@@ -164,7 +164,7 @@ gen_list(_,_,_,0) ->
gen_list(M,Typename,Oftype,N) ->
[from_type(M,Typename,Oftype)|gen_list(M,Typename,Oftype,N-1)].
-from_type_prim(D,Erule) ->
+from_type_prim(D) ->
C = D#type.constraint,
case D#type.def of
'INTEGER' ->
@@ -303,12 +303,7 @@ from_type_prim(D,Erule) ->
adjust_list(size_random(C),c_string(C,"BMPString"));
'UTF8String' ->
{ok,Res}=asn1rt:utf8_list_to_binary(adjust_list(random(50),[$U,$T,$F,$8,$S,$t,$r,$i,$n,$g,16#ffff,16#fffffff,16#ffffff,16#fffff,16#fff])),
- case Erule of
- per ->
- binary_to_list(Res);
- _ ->
- Res
- end;
+ Res;
'UniversalString' ->
adjust_list(size_random(C),c_string(C,"UniversalString"));
XX ->
@@ -440,20 +435,9 @@ get_encoding_rule(M) ->
end.
open_type_value(ber) ->
- [4,9,111,112,101,110,95,116,121,112,101];
-open_type_value(ber_bin) ->
-% [4,9,111,112,101,110,95,116,121,112,101];
- <<4,9,111,112,101,110,95,116,121,112,101>>;
-open_type_value(ber_bin_v2) ->
-% [4,9,111,112,101,110,95,116,121,112,101];
<<4,9,111,112,101,110,95,116,121,112,101>>;
-open_type_value(per) ->
- "\n\topen_type"; %octet string value "open_type"
-open_type_value(per_bin) ->
- <<"\n\topen_type">>;
-% <<10,9,111,112,101,110,95,116,121,112,101>>;
open_type_value(_) ->
- [4,9,111,112,101,110,95,116,121,112,101].
+ <<"\n\topen_type">>. %octet string value "open_type"
to_textual_order({Root,Ext}) ->
{to_textual_order(Root),Ext};
diff --git a/lib/asn1/src/asn1rt_ber_bin.erl b/lib/asn1/src/asn1rt_ber_bin.erl
index 22f9f2ecfd..ec1549804b 100644
--- a/lib/asn1/src/asn1rt_ber_bin.erl
+++ b/lib/asn1/src/asn1rt_ber_bin.erl
@@ -19,337 +19,30 @@
%%
-module(asn1rt_ber_bin).
-%% encoding / decoding of BER
-
--export([decode/1]).
--export([fixoptionals/2,split_list/2,cindex/3,restbytes2/3,
- list_to_record/2,
- encode_tag_val/1,decode_tag/1,peek_tag/1,
- check_tags/3, encode_tags/3]).
--export([encode_boolean/2,decode_boolean/3,
- encode_integer/3,encode_integer/4,
- decode_integer/4,decode_integer/5,encode_enumerated/2,
- encode_enumerated/4,decode_enumerated/5,
+-export([decode_length/1,
encode_real/2, encode_real/3,
decode_real/2, decode_real/4,
- encode_bit_string/4,decode_bit_string/6,
- decode_compact_bit_string/6,
- encode_octet_string/3,decode_octet_string/5,
- encode_null/2,decode_null/3,
- encode_object_identifier/2,decode_object_identifier/3,
- encode_relative_oid/2,decode_relative_oid/3,
- encode_restricted_string/4,decode_restricted_string/6,
- encode_universal_string/3,decode_universal_string/5,
- encode_UTF8_string/3, decode_UTF8_string/3,
- encode_BMP_string/3,decode_BMP_string/5,
- encode_generalized_time/3,decode_generalized_time/5,
- encode_utc_time/3,decode_utc_time/5,
- encode_length/1,decode_length/1,
- check_if_valid_tag/3,
- decode_tag_and_length/1, decode_components/6,
- decode_components/7, decode_set/6]).
-
--export([encode_open_type/1,encode_open_type/2,decode_open_type/1,decode_open_type/2,decode_open_type/3]).
--export([skipvalue/1, skipvalue/2,skip_ExtensionAdditions/2]).
+ decode_tag/1]).
-include("asn1_records.hrl").
-% the encoding of class of tag bits 8 and 7
+%% the encoding of class of tag bits 8 and 7
-define(UNIVERSAL, 0).
--define(APPLICATION, 16#40).
--define(CONTEXT, 16#80).
--define(PRIVATE, 16#C0).
%%% primitive or constructed encoding % bit 6
-define(PRIMITIVE, 0).
-define(CONSTRUCTED, 2#00100000).
%%% The tag-number for universal types
--define(N_BOOLEAN, 1).
--define(N_INTEGER, 2).
--define(N_BIT_STRING, 3).
--define(N_OCTET_STRING, 4).
--define(N_NULL, 5).
--define(N_OBJECT_IDENTIFIER, 6).
--define(N_OBJECT_DESCRIPTOR, 7).
--define(N_EXTERNAL, 8).
-define(N_REAL, 9).
--define(N_ENUMERATED, 10).
--define(N_EMBEDDED_PDV, 11).
--define(N_UTF8String, 12).
--define('N_RELATIVE-OID',13).
--define(N_SEQUENCE, 16).
--define(N_SET, 17).
--define(N_NumericString, 18).
--define(N_PrintableString, 19).
--define(N_TeletexString, 20).
--define(N_VideotexString, 21).
--define(N_IA5String, 22).
--define(N_UTCTime, 23).
--define(N_GeneralizedTime, 24).
--define(N_GraphicString, 25).
--define(N_VisibleString, 26).
--define(N_GeneralString, 27).
--define(N_UniversalString, 28).
--define(N_BMPString, 30).
-
-
-% the complete tag-word of built-in types
--define(T_BOOLEAN, ?UNIVERSAL bor ?PRIMITIVE bor 1).
--define(T_INTEGER, ?UNIVERSAL bor ?PRIMITIVE bor 2).
--define(T_BIT_STRING, ?UNIVERSAL bor ?PRIMITIVE bor 3). % can be CONSTRUCTED
--define(T_OCTET_STRING, ?UNIVERSAL bor ?PRIMITIVE bor 4). % can be CONSTRUCTED
--define(T_NULL, ?UNIVERSAL bor ?PRIMITIVE bor 5).
--define(T_OBJECT_IDENTIFIER,?UNIVERSAL bor ?PRIMITIVE bor 6).
--define(T_OBJECT_DESCRIPTOR,?UNIVERSAL bor ?PRIMITIVE bor 7).
--define(T_EXTERNAL, ?UNIVERSAL bor ?PRIMITIVE bor 8).
--define(T_REAL, ?UNIVERSAL bor ?PRIMITIVE bor 9).
--define(T_ENUMERATED, ?UNIVERSAL bor ?PRIMITIVE bor 10).
--define(T_EMBEDDED_PDV, ?UNIVERSAL bor ?PRIMITIVE bor 11).
--define(T_SEQUENCE, ?UNIVERSAL bor ?CONSTRUCTED bor 16).
--define(T_SET, ?UNIVERSAL bor ?CONSTRUCTED bor 17).
--define(T_NumericString, ?UNIVERSAL bor ?PRIMITIVE bor 18). %can be constructed
--define(T_PrintableString, ?UNIVERSAL bor ?PRIMITIVE bor 19). %can be constructed
--define(T_TeletexString, ?UNIVERSAL bor ?PRIMITIVE bor 20). %can be constructed
--define(T_VideotexString, ?UNIVERSAL bor ?PRIMITIVE bor 21). %can be constructed
--define(T_IA5String, ?UNIVERSAL bor ?PRIMITIVE bor 22). %can be constructed
--define(T_UTCTime, ?UNIVERSAL bor ?PRIMITIVE bor 23).
--define(T_GeneralizedTime, ?UNIVERSAL bor ?PRIMITIVE bor 24).
--define(T_GraphicString, ?UNIVERSAL bor ?PRIMITIVE bor 25). %can be constructed
--define(T_VisibleString, ?UNIVERSAL bor ?PRIMITIVE bor 26). %can be constructed
--define(T_GeneralString, ?UNIVERSAL bor ?PRIMITIVE bor 27). %can be constructed
--define(T_UniversalString, ?UNIVERSAL bor ?PRIMITIVE bor 28). %can be constructed
--define(T_BMPString, ?UNIVERSAL bor ?PRIMITIVE bor 30). %can be constructed
-
-
-decode(Bin) ->
- decode_primitive(Bin).
-
-decode_primitive(Bin) ->
- {Tlv = {Tag,Len,V},<<>>} = decode_tlv(Bin),
- case element(2,Tag) of
- ?CONSTRUCTED ->
- {Tag,Len,decode_constructed(V)};
- _ ->
- Tlv
- end.
-
-decode_constructed(<<>>) ->
- [];
-decode_constructed(Bin) ->
- {Tlv = {Tag,Len,V},Rest} = decode_tlv(Bin),
- NewTlv =
- case element(2,Tag) of
- ?CONSTRUCTED ->
- {Tag,Len,decode_constructed(V)};
- _ ->
- Tlv
- end,
- [NewTlv|decode_constructed(Rest)].
-
-decode_tlv(Bin) ->
- {Tag,Bin1,_Rb1} = decode_tag(Bin),
- {{Len,Bin2},_Rb2} = decode_length(Bin1),
- <<V:Len/binary,Bin3/binary>> = Bin2,
- {{Tag,Len,V},Bin3}.
-
-
-
-%%%%%%%%%%%%%
-% split_list(List,HeadLen) -> {HeadList,TailList}
-%
-% splits List into HeadList (Length=HeadLen) and TailList
-% if HeadLen == indefinite -> return {List,indefinite}
-split_list(List,indefinite) ->
- {List, indefinite};
-split_list(Bin, Len) when is_binary(Bin) ->
- split_binary(Bin,Len);
-split_list(List,Len) ->
- {lists:sublist(List,Len),lists:nthtail(Len,List)}.
-
-%%% new function which fixes a bug regarding indefinite length decoding
-restbytes2(indefinite,<<0,0,RemBytes/binary>>,_) ->
- {RemBytes,2};
-restbytes2(indefinite,RemBytes,ext) ->
- skipvalue(indefinite,RemBytes);
-restbytes2(RemBytes,<<>>,_) ->
- {RemBytes,0};
-restbytes2(_RemBytes,Bytes,noext) ->
- exit({error,{asn1, {unexpected,Bytes}}});
-restbytes2(RemBytes,Bytes,ext) ->
-%% {RemBytes,0}.
- {RemBytes,byte_size(Bytes)}.
-
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% skipvalue(Length, Bytes) -> {RemainingBytes, RemovedNumberOfBytes}
-%%
-%% skips the one complete (could be nested) TLV from Bytes
-%% handles both definite and indefinite length encodings
-%%
-
-skipvalue(L, Bytes) ->
- skipvalue(L, Bytes, 0).
-
-skipvalue(L, Bytes, Rb) ->
- skipvalue(L, Bytes, Rb, 0).
-
-skipvalue(indefinite, Bytes, Rb, IndefLevel) ->
- {T,Bytes2,R2} = decode_tag(Bytes),
- {{L,Bytes3},R3} = decode_length(Bytes2),
- case {T,L} of
- {_,indefinite} ->
- skipvalue(indefinite,Bytes3,Rb+R2+R3,IndefLevel+1);
- {{0,0,0},0} when IndefLevel =:= 0 ->
- %% See X690 8.1.5 NOTE, end of indefinite content
- {Bytes3,Rb+2};
- {{0,0,0},0} ->
- skipvalue(indefinite,Bytes3,Rb+2,IndefLevel - 1);
- _ ->
- <<_:L/binary, RestBytes/binary>> = Bytes3,
- skipvalue(indefinite,RestBytes,Rb+R2+R3+L, IndefLevel)
- %%{RestBytes, R2+R3+L}
- end;
-%% case Bytes4 of
-%% <<0,0,Bytes5/binary>> ->
-%% {Bytes5,Rb+Rb4+2};
-%% _ -> skipvalue(indefinite,Bytes4,Rb+Rb4)
-%% end;
-skipvalue(L, Bytes, Rb, _) ->
-% <<Skip:L/binary, RestBytes/binary>> = Bytes,
- <<_:L/binary, RestBytes/binary>> = Bytes,
- {RestBytes,Rb+L}.
-
-
-skipvalue(Bytes) ->
- {_T,Bytes2,R2} = decode_tag(Bytes),
- {{L,Bytes3},R3} = decode_length(Bytes2),
- skipvalue(L,Bytes3,R2+R3).
-
-
-cindex(Ix,Val,Cname) ->
- case element(Ix,Val) of
- {Cname,Val2} -> Val2;
- X -> X
- end.
-
-%%%
-%% skips byte sequence of Bytes that do not match a tag in Tags
-skip_ExtensionAdditions(Bytes,Tags) ->
- skip_ExtensionAdditions(Bytes,Tags,0).
-skip_ExtensionAdditions(<<>>,_Tags,RmB) ->
- {<<>>,RmB};
-skip_ExtensionAdditions(Bytes,Tags,RmB) ->
- case catch decode_tag(Bytes) of
- {'EXIT',_Reason} ->
- tag_error(no_data,Tags,Bytes,'OPTIONAL');
- {_T={Class,_Form,TagNo},_Bytes2,_R2} ->
- case [X||X=#tag{class=Cl,number=TN} <- Tags,Cl==Class,TN==TagNo] of
- [] ->
- %% skip this TLV and continue with next
- {Bytes3,R3} = skipvalue(Bytes),
- skip_ExtensionAdditions(Bytes3,Tags,RmB+R3);
- _ ->
- {Bytes,RmB}
- end
- end.
-
-%%===============================================================================
-%%===============================================================================
-%%===============================================================================
-%% Optionals, preset not filled optionals with asn1_NOVALUE
-%%===============================================================================
-%%===============================================================================
-%%===============================================================================
-
-% converts a list to a record if necessary
-list_to_record(Name,List) when is_list(List) ->
- list_to_tuple([Name|List]);
-list_to_record(_Name,Tuple) when is_tuple(Tuple) ->
- Tuple.
-
-
-fixoptionals(OptList,Val) when is_list(Val) ->
- fixoptionals(OptList,Val,1,[],[]).
-
-fixoptionals([{Name,Pos}|Ot],[{Name,Val}|Vt],_Opt,Acc1,Acc2) ->
- fixoptionals(Ot,Vt,Pos+1,[1|Acc1],[{Name,Val}|Acc2]);
-fixoptionals([{_Name,Pos}|Ot],V,Pos,Acc1,Acc2) ->
- fixoptionals(Ot,V,Pos+1,[0|Acc1],[asn1_NOVALUE|Acc2]);
-fixoptionals(O,[Vh|Vt],Pos,Acc1,Acc2) ->
- fixoptionals(O,Vt,Pos+1,Acc1,[Vh|Acc2]);
-fixoptionals([],[Vh|Vt],Pos,Acc1,Acc2) ->
- fixoptionals([],Vt,Pos+1,Acc1,[Vh|Acc2]);
-fixoptionals([],[],_,_Acc1,Acc2) ->
- % return Val as a record
- list_to_tuple([asn1_RECORDNAME|lists:reverse(Acc2)]).
-
-
-%%encode_tag(TagClass(?UNI, APP etc), Form (?PRIM etx), TagInteger) ->
-%% 8bit Int | binary
encode_tag_val({Class, Form, TagNo}) when (TagNo =< 30) ->
<<(Class bsr 6):2,(Form bsr 5):1,TagNo:5>>;
encode_tag_val({Class, Form, TagNo}) ->
{Octets,_Len} = mk_object_val(TagNo),
BinOct = list_to_binary(Octets),
- <<(Class bsr 6):2, (Form bsr 5):1, 31:5,BinOct/binary>>;
-
-%% asumes whole correct tag bitpattern, multiple of 8
-encode_tag_val(Tag) when (Tag =< 255) -> Tag; %% anv�nds denna funktion??!!
-%% asumes correct bitpattern of 0-5
-encode_tag_val(Tag) -> encode_tag_val2(Tag,[]).
-
-encode_tag_val2(Tag, OctAck) when (Tag =< 255) ->
- [Tag | OctAck];
-encode_tag_val2(Tag, OctAck) ->
- encode_tag_val2(Tag bsr 8, [255 band Tag | OctAck]).
-
-
-%%%encode_tag(TagClass(?UNI, APP etc), Form (?PRIM etx), TagInteger) ->
-%%% 8bit Int | [list of octets]
-%encode_tag_val({Class, Form, TagNo}) when (TagNo =< 30) ->
-%%% <<Class:2,Form:1,TagNo:5>>;
-% [Class bor Form bor TagNo];
-%encode_tag_val({Class, Form, TagNo}) ->
-% {Octets,L} = mk_object_val(TagNo),
-% [Class bor Form bor 31 | Octets];
-
-
-%%============================================================================\%% Peek on the initial tag
-%% peek_tag(Bytes) -> TagBytes
-%% interprets the first byte and possible second, third and fourth byte as
-%% a tag and returns all the bytes comprising the tag, the constructed/primitive bit (6:th bit of first byte) is normalised to 0
-%%
-
-peek_tag(<<B7_6:2,_:1,31:5,Buffer/binary>>) ->
- Bin = peek_tag(Buffer, <<>>),
- <<B7_6:2,31:6,Bin/binary>>;
-%% single tag (tagno < 31)
-peek_tag(<<B7_6:2,_:1,B4_0:5,_Buffer/binary>>) ->
- <<B7_6:2,B4_0:6>>.
-
-peek_tag(<<0:1,PartialTag:7,_Buffer/binary>>, TagAck) ->
- <<TagAck/binary,PartialTag>>;
-peek_tag(<<PartialTag,Buffer/binary>>, TagAck) ->
- peek_tag(Buffer,<<TagAck/binary,PartialTag>>);
-peek_tag(_,TagAck) ->
- exit({error,{asn1, {invalid_tag,TagAck}}}).
-%%peek_tag([Tag|Buffer]) when (Tag band 31) =:= 31 ->
-%% [Tag band 2#11011111 | peek_tag(Buffer,[])];
-%%%% single tag (tagno < 31)
-%%peek_tag([Tag|Buffer]) ->
-%% [Tag band 2#11011111].
-
-%%peek_tag([PartialTag|Buffer], TagAck) when (PartialTag < 128 ) ->
-%% lists:reverse([PartialTag|TagAck]);
-%%peek_tag([PartialTag|Buffer], TagAck) ->
-%% peek_tag(Buffer,[PartialTag|TagAck]);
-%%peek_tag(Buffer,TagAck) ->
-%% exit({error,{asn1, {invalid_tag,lists:reverse(TagAck)}}}).
-
+ <<(Class bsr 6):2, (Form bsr 5):1, 31:5,BinOct/binary>>.
%%===============================================================================
%% Decode a tag
@@ -403,33 +96,11 @@ check_tags_i([Tag1|TagRest], Buffer, Rb, OptOrMand) ->
_ ->
check_tags_i(TagRest, Buffer2, Rb + Rb1, mandatory)
end
- end;
-
-check_tags_i([], Buffer, Rb, _) ->
- {[],{{0,0},Buffer,Rb}}.
+ end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% This function is called from generated code
-check_tags([Tag], Buffer, OptOrMand) -> % optimized very usual case
- check_one_tag(Tag, Buffer, OptOrMand);
-check_tags(Tags, Buffer, OptOrMand) ->
- check_tags(Tags, Buffer, 0, OptOrMand).
-
-check_tags([Tag1,Tag2|TagRest], Buffer, Rb, OptOrMand)
- when Tag1#tag.type == 'IMPLICIT' ->
- check_tags([Tag1#tag{type=Tag2#tag.type}|TagRest], Buffer, Rb, OptOrMand);
-
-check_tags([Tag1|TagRest], Buffer, Rb, OptOrMand) ->
- {Form_Length,Buffer2,Rb1} = check_one_tag(Tag1, Buffer, OptOrMand),
- case TagRest of
- [] -> {Form_Length, Buffer2, Rb + Rb1};
- _ -> check_tags(TagRest, Buffer2, Rb + Rb1, mandatory)
- end;
-
-check_tags([], Buffer, Rb, _) ->
- {{0,0},Buffer,Rb}.
-
check_one_tag(Tag=#tag{class=ExpectedClass,number=ExpectedNumber}, Buffer, OptOrMand) ->
case catch decode_tag(Buffer) of
{'EXIT',_Reason} ->
@@ -491,382 +162,6 @@ encode_one_tag(#tag{class=Class,number=No,type=Type, form = Form}) ->
Bytes = encode_tag_val({Class,NewForm,No}),
{Bytes,size(Bytes)}.
-%%===============================================================================
-%% Change the tag (used when an implicit tagged type has a reference to something else)
-%% The constructed bit in the tag is taken from the tag to be replaced.
-%%
-%% change_tag(NewTag,[Tag,Buffer]) -> [NewTag,Buffer]
-%%===============================================================================
-
-%change_tag({NewClass,NewTagNr}, Buffer) ->
-% {{OldClass, OldForm, OldTagNo}, Buffer1, RemovedBytes} = decode_tag(lists:flatten(Buffer)),
-% [encode_tag_val({NewClass, OldForm, NewTagNr}) | Buffer1].
-
-
-%%===============================================================================
-%%
-%% This comment is valid for all the encode/decode functions
-%%
-%% C = Constraint -> typically {'ValueRange',LowerBound,UpperBound}
-%% used for PER-coding but not for BER-coding.
-%%
-%% Val = Value. If Val is an atom then it is a symbolic integer value
-%% (i.e the atom must be one of the names in the NamedNumberList).
-%% The NamedNumberList is used to translate the atom to an integer value
-%% before encoding.
-%%
-%%===============================================================================
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% encode_open_type(Value) -> CompleteList
-%% Value = list of bytes of an already encoded value (the list must be flat)
-%% | binary
-
-%% This version does not consider Explicit tagging of the open type. It
-%% is only left because of backward compatibility.
-encode_open_type(Val) when is_list(Val) ->
- {Val, byte_size(list_to_binary(Val))};
-encode_open_type(Val) ->
- {Val, byte_size(Val)}.
-
-%%
-encode_open_type(Val, []) when is_list(Val) ->
- {Val, byte_size(list_to_binary(Val))};
-encode_open_type(Val, []) ->
- {Val, byte_size(Val)};
-encode_open_type(Val, Tag) when is_list(Val) ->
- encode_tags(Tag, Val, byte_size(list_to_binary(Val)));
-encode_open_type(Val, Tag) ->
- encode_tags(Tag, Val, byte_size(Val)).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% decode_open_type(Buffer) -> Value
-%% Bytes = [byte] with BER encoded data
-%% Value = [byte] with decoded data (which must be decoded again as some type)
-%%
-decode_open_type(Bytes) ->
-% {_Tag, Len, _RemainingBuffer, RemovedBytes} = decode_tag_and_length(Bytes),
-% N = Len + RemovedBytes,
- {_Tag, Len, RemainingBuffer, RemovedBytes} = decode_tag_and_length(Bytes),
- {_RemainingBuffer2, RemovedBytes2} = skipvalue(Len, RemainingBuffer, RemovedBytes),
- N = RemovedBytes2,
- <<Val:N/binary, RemainingBytes/binary>> = Bytes,
-% {Val, RemainingBytes, Len + RemovedBytes}.
- {Val,RemainingBytes,N}.
-
-decode_open_type(<<>>,[]=ExplTag) -> % R9C-0.patch-40
- exit({error, {asn1,{no_optional_tag, ExplTag}}});
-decode_open_type(Bytes,ExplTag) ->
- {Tag, Len, RemainingBuffer, RemovedBytes} = decode_tag_and_length(Bytes),
- case {Tag,ExplTag} of
-% {{Class,Form,32},[#tag{class=Class,number=No,form=32}]} ->
-% {_Tag2, Len2, RemainingBuffer2, RemovedBytes2} = decode_tag_and_length(RemainingBuffer),
-% {_RemainingBuffer3, RemovedBytes3} = skipvalue(Len2, RemainingBuffer2, RemovedBytes2),
-% N = RemovedBytes3,
-% <<_:RemovedBytes/unit:8,Val:N/binary,RemainingBytes/binary>> = Bytes,
-% {Val, RemainingBytes, N + RemovedBytes};
- {{Class,Form,No},[#tag{class=Class,number=No,form=Form}]} ->
- {_RemainingBuffer2, RemovedBytes2} =
- skipvalue(Len, RemainingBuffer),
- N = RemovedBytes2,
- <<_:RemovedBytes/unit:8,Val:N/binary,RemainingBytes/binary>> = Bytes,
- {Val, RemainingBytes, N + RemovedBytes};
- _ ->
- {_RemainingBuffer2, RemovedBytes2} =
- skipvalue(Len, RemainingBuffer, RemovedBytes),
- N = RemovedBytes2,
- <<Val:N/binary, RemainingBytes/binary>> = Bytes,
- {Val, RemainingBytes, N}
- end.
-
-decode_open_type(ber_bin,Bytes,ExplTag) ->
- decode_open_type(Bytes,ExplTag);
-decode_open_type(ber,Bytes,ExplTag) ->
- {Val,RemBytes,Len}=decode_open_type(Bytes,ExplTag),
- {binary_to_list(Val),RemBytes,Len}.
-
-%%===============================================================================
-%%===============================================================================
-%%===============================================================================
-%% Boolean, ITU_T X.690 Chapter 8.2
-%%===============================================================================
-%%===============================================================================
-%%===============================================================================
-
-%%===============================================================================
-%% encode_boolean(Integer, tag | notag) -> [octet list]
-%%===============================================================================
-
-encode_boolean({Name, Val}, DoTag) when is_atom(Name) ->
- dotag(DoTag, ?N_BOOLEAN, encode_boolean(Val));
-encode_boolean(true,[]) ->
- {[1,1,16#FF],3};
-encode_boolean(false,[]) ->
- {[1,1,0],3};
-encode_boolean(Val, DoTag) ->
- dotag(DoTag, ?N_BOOLEAN, encode_boolean(Val)).
-
-%% encode_boolean(Boolean) -> [Len, Boolean] = [1, $FF | 0]
-encode_boolean(true) -> {[16#FF],1};
-encode_boolean(false) -> {[0],1};
-encode_boolean(X) -> exit({error,{asn1, {encode_boolean, X}}}).
-
-
-%%===============================================================================
-%% decode_boolean(BuffList, HasTag, TotalLen) -> {true, Remain, RemovedBytes} |
-%% {false, Remain, RemovedBytes}
-%%===============================================================================
-
-decode_boolean(Buffer, Tags, OptOrMand) ->
- NewTags = new_tags(Tags,#tag{class=?UNIVERSAL,number=?N_BOOLEAN}),
- decode_boolean_notag(Buffer, NewTags, OptOrMand).
-
-decode_boolean_notag(Buffer, Tags, OptOrMand) ->
- {RestTags, {FormLen,Buffer0,Rb0}} =
- check_tags_i(Tags, Buffer, OptOrMand),
- case FormLen of
- {?CONSTRUCTED,Len} ->
- {Buffer00,RestBytes} = split_list(Buffer0,Len),
- {Val,Buffer1,Rb1} = decode_boolean_notag(Buffer00, RestTags, OptOrMand),
- {Buffer2, Rb2} = restbytes2(RestBytes,Buffer1,noext),
- {Val, Buffer2, Rb0+Rb1+Rb2};
- {_,_} ->
- decode_boolean2(Buffer0, Rb0)
- end.
-
-decode_boolean2(<<0:8, Buffer/binary>>, RemovedBytes) ->
- {false, Buffer, RemovedBytes + 1};
-decode_boolean2(<<_:8, Buffer/binary>>, RemovedBytes) ->
- {true, Buffer, RemovedBytes + 1};
-decode_boolean2(Buffer, _) ->
- exit({error,{asn1, {decode_boolean, Buffer}}}).
-
-
-%%===========================================================================
-%% Integer, ITU_T X.690 Chapter 8.3
-
-%% encode_integer(Constraint, Value, Tag) -> [octet list]
-%% encode_integer(Constraint, Name, NamedNumberList, Tag) -> [octet list]
-%% Value = INTEGER | {Name,INTEGER}
-%% Tag = tag | notag
-%%===========================================================================
-
-encode_integer(C, Val, []) when is_integer(Val) ->
- {EncVal,Len} = encode_integer(C, Val),
- dotag_universal(?N_INTEGER,EncVal,Len);
-encode_integer(C, Val, Tag) when is_integer(Val) ->
- dotag(Tag, ?N_INTEGER, encode_integer(C, Val));
-encode_integer(C,{Name,Val},Tag) when is_atom(Name) ->
- encode_integer(C,Val,Tag);
-encode_integer(_, Val, _) ->
- exit({error,{asn1, {encode_integer, Val}}}).
-
-
-encode_integer(C, Val, NamedNumberList, Tag) when is_atom(Val) ->
- case lists:keyfind(Val, 1, NamedNumberList) of
- {_, NewVal} ->
- dotag(Tag, ?N_INTEGER, encode_integer(C, NewVal));
- _ ->
- exit({error,{asn1, {encode_integer_namednumber, Val}}})
- end;
-encode_integer(C,{_,Val},NamedNumberList,Tag) ->
- encode_integer(C,Val,NamedNumberList,Tag);
-encode_integer(C, Val, _NamedNumberList, Tag) ->
- dotag(Tag, ?N_INTEGER, encode_integer(C, Val)).
-
-
-encode_integer(_C, Val) ->
- Bytes =
- if
- Val >= 0 ->
- encode_integer_pos(Val, []);
- true ->
- encode_integer_neg(Val, [])
- end,
- {Bytes,length(Bytes)}.
-
-encode_integer_pos(0, L=[B|_Acc]) when B < 128 ->
- L;
-encode_integer_pos(N, Acc) ->
- encode_integer_pos((N bsr 8), [N band 16#ff| Acc]).
-
-encode_integer_neg(-1, L=[B1|_T]) when B1 > 127 ->
- L;
-encode_integer_neg(N, Acc) ->
- encode_integer_neg(N bsr 8, [N band 16#ff|Acc]).
-
-%%===============================================================================
-%% decode integer
-%% (Buffer, Range, HasTag, TotalLen) -> {Integer, Remain, RemovedBytes}
-%% (Buffer, Range, NamedNumberList, HasTag, TotalLen) -> {Integer, Remain, RemovedBytes}
-%%===============================================================================
-
-decode_integer(Buffer, Range, Tags, OptOrMand) ->
- NewTags = new_tags(Tags,#tag{class=?UNIVERSAL,number=?N_INTEGER}),
- decode_integer_notag(Buffer, Range, [], NewTags, OptOrMand).
-
-decode_integer(Buffer, Range, NamedNumberList, Tags, OptOrMand) ->
- NewTags = new_tags(Tags,#tag{class=?UNIVERSAL,number=?N_INTEGER}),
- decode_integer_notag(Buffer, Range, NamedNumberList, NewTags, OptOrMand).
-
-decode_integer_notag(Buffer, Range, NamedNumberList, NewTags, OptOrMand) ->
- {RestTags, {FormLen, Buffer0, Rb0}} =
- check_tags_i(NewTags, Buffer, OptOrMand),
-% Result = {Val, Buffer2, RemovedBytes} =
- case FormLen of
- {?CONSTRUCTED,Len} ->
- {Buffer00, RestBytes} = split_list(Buffer0,Len),
- {Val01, Buffer01, Rb01} =
- decode_integer_notag(Buffer00, Range, NamedNumberList,
- RestTags, OptOrMand),
- {Buffer02, Rb02} = restbytes2(RestBytes,Buffer01,noext),
- {Val01, Buffer02, Rb0+Rb01+Rb02};
- {_, Len} ->
- Result =
- decode_integer2(Len,Buffer0,Rb0+Len),
- Result2 = check_integer_constraint(Result,Range),
- resolve_named_value(Result2,NamedNumberList)
- end.
-
-resolve_named_value(Result={Val,Buffer,RemBytes},NamedNumberList) ->
- case NamedNumberList of
- [] -> Result;
- _ ->
- NewVal = case lists:keyfind(Val, 2, NamedNumberList) of
- {NamedVal, _} ->
- NamedVal;
- _ ->
- Val
- end,
- {NewVal, Buffer, RemBytes}
- end.
-
-check_integer_constraint(Result={Val, _Buffer,_},Range) ->
- case Range of
- [] -> % No length constraint
- Result;
- {Lb,Ub} when Val >= Lb, Ub >= Val -> % variable length constraint
- Result;
- Val -> % fixed value constraint
- Result;
- {_,_} ->
- exit({error,{asn1,{integer_range,Range,Val}}});
- SingleValue when is_integer(SingleValue) ->
- exit({error,{asn1,{integer_range,Range,Val}}});
- _ -> % some strange constraint that we don't support yet
- Result
- end.
-
-%%============================================================================
-%% Enumerated value, ITU_T X.690 Chapter 8.4
-
-%% encode enumerated value
-%%============================================================================
-encode_enumerated(Val, []) when is_integer(Val) ->
- {EncVal,Len} = encode_integer(false,Val),
- dotag_universal(?N_ENUMERATED,EncVal,Len);
-encode_enumerated(Val, DoTag) when is_integer(Val) ->
- dotag(DoTag, ?N_ENUMERATED, encode_integer(false,Val));
-encode_enumerated({Name,Val}, DoTag) when is_atom(Name) ->
- encode_enumerated(Val, DoTag).
-
-%% The encode_enumerated functions below this line can be removed when the
-%% new code generation is stable. (the functions might have to be kept here
-%% a while longer for compatibility reasons)
-
-encode_enumerated(C, Val, {NamedNumberList,ExtList}, DoTag) when is_atom(Val) ->
- case catch encode_enumerated(C, Val, NamedNumberList, DoTag) of
- {'EXIT',_} -> encode_enumerated(C, Val, ExtList, DoTag);
- Result -> Result
- end;
-
-encode_enumerated(C, Val, NamedNumberList, DoTag) when is_atom(Val) ->
- case lists:keyfind(Val, 1, NamedNumberList) of
- {_, NewVal} when DoTag =:= [] ->
- {EncVal,Len} = encode_integer(C,NewVal),
- dotag_universal(?N_ENUMERATED,EncVal,Len);
- {_, NewVal} ->
- dotag(DoTag, ?N_ENUMERATED, encode_integer(C, NewVal));
- _ ->
- exit({error,{asn1, {enumerated_not_in_range, Val}}})
- end;
-
-encode_enumerated(C, {asn1_enum, Val}, {_,_}, DoTag) when is_integer(Val) ->
- dotag(DoTag, ?N_ENUMERATED, encode_integer(C,Val));
-
-encode_enumerated(C, {Name,Val}, NamedNumberList, DoTag) when is_atom(Name) ->
- encode_enumerated(C, Val, NamedNumberList, DoTag);
-
-encode_enumerated(_, Val, _, _) ->
- exit({error,{asn1, {enumerated_not_namednumber, Val}}}).
-
-
-
-%%============================================================================
-%% decode enumerated value
-%% (Buffer, Range, NamedNumberList, HasTag, TotalLen) ->
-%% {Value, RemainingBuffer, RemovedBytes}
-%%===========================================================================
-decode_enumerated(Buffer, Range, NamedNumberList, Tags, OptOrMand) ->
- NewTags = new_tags(Tags,#tag{class=?UNIVERSAL,number=?N_ENUMERATED}),
- decode_enumerated_notag(Buffer, Range, NamedNumberList,
- NewTags, OptOrMand).
-
-decode_enumerated_notag(Buffer, Range, NNList = {NamedNumberList,ExtList}, Tags, OptOrMand) ->
- {RestTags, {FormLen, Buffer0, Rb0}} =
- check_tags_i(Tags, Buffer, OptOrMand),
-
- case FormLen of
- {?CONSTRUCTED,Len} ->
- {Buffer00,RestBytes} = split_list(Buffer0,Len),
- {Val01, Buffer01, Rb01} =
- decode_enumerated_notag(Buffer00, Range, NNList, RestTags, OptOrMand),
- {Buffer02, Rb02} = restbytes2(RestBytes,Buffer01,noext),
- {Val01, Buffer02, Rb0+Rb01+Rb02};
- {_,Len} ->
- {Val01, Buffer01, Rb01} =
- decode_integer2(Len, Buffer0, Rb0+Len),
- case decode_enumerated1(Val01, NamedNumberList) of
- {asn1_enum,Val01} ->
- {decode_enumerated1(Val01,ExtList), Buffer01, Rb01};
- Result01 ->
- {Result01, Buffer01, Rb01}
- end
- end;
-
-decode_enumerated_notag(Buffer, Range, NNList, Tags, OptOrMand) ->
- {RestTags, {FormLen, Buffer0, Rb0}} =
- check_tags_i(Tags, Buffer, OptOrMand),
-
- case FormLen of
- {?CONSTRUCTED,Len} ->
- {Buffer00,RestBytes} = split_list(Buffer0,Len),
- {Val01, Buffer01, Rb01} =
- decode_enumerated_notag(Buffer00, Range, NNList, RestTags, OptOrMand),
- {Buffer02, Rb02} = restbytes2(RestBytes,Buffer01,noext),
- {Val01, Buffer02, Rb0+Rb01+Rb02};
- {_,Len} ->
- {Val01, Buffer02, Rb02} =
- decode_integer2(Len, Buffer0, Rb0+Len),
- case decode_enumerated1(Val01, NNList) of
- {asn1_enum,_} ->
- exit({error,{asn1, {illegal_enumerated, Val01}}});
- Result01 ->
- {Result01, Buffer02, Rb02}
- end
- end.
-
-decode_enumerated1(Val, NamedNumberList) ->
- %% it must be a named integer
- case lists:keyfind(Val, 2, NamedNumberList) of
- {NamedVal, _} ->
- NamedVal;
- _ ->
- {asn1_enum,Val}
- end.
-
-
%%============================================================================
%%
%% Real value, ITU_T X.690 Chapter 8.5
@@ -1117,513 +412,15 @@ decode_real2(Buffer0, _C, Len, RemBytes1) ->
{{Mantissa, Base, Exp}, Buffer4, RemBytes2+RemBytes3}
end.
+encode_integer_pos(0, L=[B|_Acc]) when B < 128 ->
+ L;
+encode_integer_pos(N, Acc) ->
+ encode_integer_pos((N bsr 8), [N band 16#ff| Acc]).
-%%============================================================================
-%% Bitstring value, ITU_T X.690 Chapter 8.6
-%%
-%% encode bitstring value
-%%
-%% bitstring NamedBitList
-%% Val can be of:
-%% - [identifiers] where only named identifers are set to one,
-%% the Constraint must then have some information of the
-%% bitlength.
-%% - [list of ones and zeroes] all bits
-%% - integer value representing the bitlist
-%% C is constrint Len, only valid when identifiers
-%%============================================================================
-
-encode_bit_string(C,Bin={Unused,BinBits},NamedBitList,DoTag) when is_integer(Unused), is_binary(BinBits) ->
- encode_bin_bit_string(C,Bin,NamedBitList,DoTag);
-encode_bit_string(C, [FirstVal | RestVal], NamedBitList, DoTag) when is_atom(FirstVal) ->
- encode_bit_string_named(C, [FirstVal | RestVal], NamedBitList, DoTag);
-
-encode_bit_string(C, [{bit,X} | RestVal], NamedBitList, DoTag) ->
- encode_bit_string_named(C, [{bit,X} | RestVal], NamedBitList, DoTag);
-
-encode_bit_string(C, [FirstVal| RestVal], NamedBitList, DoTag) when is_integer(FirstVal) ->
- encode_bit_string_bits(C, [FirstVal | RestVal], NamedBitList, DoTag);
-
-encode_bit_string(_, 0, _, []) ->
- {[?N_BIT_STRING,1,0],3};
-
-encode_bit_string(_, 0, _, DoTag) ->
- dotag(DoTag, ?N_BIT_STRING, {<<0>>,1});
-
-encode_bit_string(_, [], _, []) ->
- {[?N_BIT_STRING,1,0],3};
-
-encode_bit_string(_, [], _, DoTag) ->
- dotag(DoTag, ?N_BIT_STRING, {<<0>>,1});
-
-encode_bit_string(C, IntegerVal, NamedBitList, DoTag) when is_integer(IntegerVal) ->
- BitListVal = int_to_bitlist(IntegerVal),
- encode_bit_string_bits(C, BitListVal, NamedBitList, DoTag);
-
-encode_bit_string(C, {Name,BitList}, NamedBitList, DoTag) when is_atom(Name) ->
- encode_bit_string(C, BitList, NamedBitList, DoTag).
-
-
-
-int_to_bitlist(0) ->
- [];
-int_to_bitlist(Int) when is_integer(Int), Int >= 0 ->
- [Int band 1 | int_to_bitlist(Int bsr 1)].
-
-
-%%=================================================================
-%% Encode BIT STRING of the form {Unused,BinBits}.
-%% Unused is the number of unused bits in the last byte in BinBits
-%% and BinBits is a binary representing the BIT STRING.
-%%=================================================================
-encode_bin_bit_string(C,{Unused,BinBits},_NamedBitList,DoTag)->
- case get_constraint(C,'SizeConstraint') of
- no ->
- remove_unused_then_dotag(DoTag,?N_BIT_STRING,Unused,BinBits);
- {_Min,Max} ->
- BBLen = (size(BinBits)*8)-Unused,
- if
- BBLen > Max ->
- exit({error,{asn1,
- {bitstring_length,
- {{was,BBLen},{maximum,Max}}}}});
- true ->
- remove_unused_then_dotag(DoTag,?N_BIT_STRING,
- Unused,BinBits)
- end;
- Size ->
- case ((size(BinBits)*8)-Unused) of
- BBSize when BBSize =< Size ->
- remove_unused_then_dotag(DoTag,?N_BIT_STRING,
- Unused,BinBits);
- BBSize ->
- exit({error,{asn1,
- {bitstring_length,
- {{was,BBSize},{should_be,Size}}}}})
- end
- end.
-
-remove_unused_then_dotag(DoTag,StringType,Unused,BinBits) ->
- case Unused of
- 0 when (byte_size(BinBits) =:= 0), DoTag =:= [] ->
- %% time optimization of next case
- {[StringType,1,0],3};
- 0 when (byte_size(BinBits) =:= 0) ->
- dotag(DoTag,StringType,{<<0>>,1});
- 0 when DoTag =:= [] -> % time optimization of next case
- dotag_universal(StringType,[Unused|[BinBits]],size(BinBits)+1);
-% {LenEnc,Len} = encode_legth(size(BinBits)+1),
-% {[StringType,LenEnc,[Unused|BinBits]],size(BinBits)+1+Len+1};
- 0 ->
- dotag(DoTag,StringType,<<Unused,BinBits/binary>>);
- Num when DoTag =:= [] -> % time optimization of next case
- N = byte_size(BinBits) - 1,
- <<BBits:N/binary,LastByte>> = BinBits,
- dotag_universal(StringType,
- [Unused,BBits,(LastByte bsr Num) bsl Num],
- byte_size(BinBits) + 1);
-% {LenEnc,Len} = encode_legth(size(BinBits)+1),
-% {[StringType,LenEnc,[Unused,BBits,(LastByte bsr Num) bsl Num],
-% 1+Len+size(BinBits)+1};
- Num ->
- N = byte_size(BinBits) - 1,
- <<BBits:N/binary,LastByte>> = BinBits,
- dotag(DoTag,StringType,{[Unused,binary_to_list(BBits) ++
- [(LastByte bsr Num) bsl Num]],
- byte_size(BinBits) + 1})
- end.
-
-
-%%=================================================================
-%% Encode named bits
-%%=================================================================
-
-encode_bit_string_named(C, [FirstVal | RestVal], NamedBitList, DoTag) ->
- {Len,Unused,OctetList} =
- case get_constraint(C,'SizeConstraint') of
- no ->
- ToSetPos = get_all_bitposes([FirstVal | RestVal],
- NamedBitList, []),
- BitList = make_and_set_list(lists:max(ToSetPos)+1,
- ToSetPos, 0),
- encode_bitstring(BitList);
- {_Min,Max} ->
- ToSetPos = get_all_bitposes([FirstVal | RestVal],
- NamedBitList, []),
- BitList = make_and_set_list(Max, ToSetPos, 0),
- encode_bitstring(BitList);
- Size ->
- ToSetPos = get_all_bitposes([FirstVal | RestVal],
- NamedBitList, []),
- BitList = make_and_set_list(Size, ToSetPos, 0),
- encode_bitstring(BitList)
- end,
- case DoTag of
- [] ->
- dotag_universal(?N_BIT_STRING,[Unused|OctetList],Len+1);
-% {EncLen,LenLen} = encode_length(Len+1),
-% {[?N_BIT_STRING,EncLen,Unused,OctetList],1+LenLen+Len+1};
- _ ->
- dotag(DoTag, ?N_BIT_STRING, {[Unused|OctetList],Len+1})
- end.
-
-
-%%----------------------------------------
-%% get_all_bitposes([list of named bits to set], named_bit_db, []) ->
-%% [sorted_list_of_bitpositions_to_set]
-%%----------------------------------------
-
-get_all_bitposes([{bit,ValPos}|Rest], NamedBitList, Ack) ->
- get_all_bitposes(Rest, NamedBitList, [ValPos | Ack ]);
-get_all_bitposes([Val | Rest], NamedBitList, Ack) when is_atom(Val) ->
- case lists:keyfind(Val, 1, NamedBitList) of
- {_ValName, ValPos} ->
- get_all_bitposes(Rest, NamedBitList, [ValPos | Ack]);
- _ ->
- exit({error,{asn1, {bitstring_namedbit, Val}}})
- end;
-get_all_bitposes([], _NamedBitList, Ack) ->
- lists:sort(Ack).
-
-
-%%----------------------------------------
-%% make_and_set_list(Len of list to return, [list of positions to set to 1])->
-%% returns list of Len length, with all in SetPos set.
-%% in positioning in list the first element is 0, the second 1 etc.., but
-%% Len will make a list of length Len, not Len + 1.
-%% BitList = make_and_set_list(C, ToSetPos, 0),
-%%----------------------------------------
-
-make_and_set_list(0, [], _) -> [];
-make_and_set_list(0, _, _) ->
- exit({error,{asn1,bitstring_sizeconstraint}});
-make_and_set_list(Len, [XPos|SetPos], XPos) ->
- [1 | make_and_set_list(Len - 1, SetPos, XPos + 1)];
-make_and_set_list(Len, [Pos|SetPos], XPos) ->
- [0 | make_and_set_list(Len - 1, [Pos | SetPos], XPos + 1)];
-make_and_set_list(Len, [], XPos) ->
- [0 | make_and_set_list(Len - 1, [], XPos + 1)].
-
-
-%%=================================================================
-%% Encode bit string for lists of ones and zeroes
-%%=================================================================
-encode_bit_string_bits(C, BitListVal, _NamedBitList, DoTag) when is_list(BitListVal) ->
- {Len,Unused,OctetList} =
- case get_constraint(C,'SizeConstraint') of
- no ->
- encode_bitstring(BitListVal);
- Constr={Min,_Max} when is_integer(Min) ->
- encode_constr_bit_str_bits(Constr,BitListVal,DoTag);
- {Constr={_,_},[]} ->
- %% constraint with extension mark
- encode_constr_bit_str_bits(Constr,BitListVal,DoTag);
- Constr={{_,_},{_,_}} ->%{{Min1,Max1},{Min2,Max2}}
- %% constraint with extension mark
- encode_constr_bit_str_bits(Constr,BitListVal,DoTag);
- Size ->
- case length(BitListVal) of
- BitSize when BitSize =:= Size ->
- encode_bitstring(BitListVal);
- BitSize when BitSize < Size ->
- PaddedList =
- pad_bit_list(Size-BitSize,BitListVal),
- encode_bitstring(PaddedList);
- BitSize ->
- exit({error,
- {asn1,
- {bitstring_length,
- {{was,BitSize},
- {should_be,Size}}}}})
- end
- end,
- %%add unused byte to the Len
- case DoTag of
- [] ->
- dotag_universal(?N_BIT_STRING,[Unused|OctetList],Len+1);
-% {EncLen,LenLen}=encode_length(Len+1),
-% {[?N_BIT_STRING,EncLen,Unused|OctetList],1+LenLen+Len+1};
- _ ->
- dotag(DoTag, ?N_BIT_STRING,
- {[Unused | OctetList],Len+1})
- end.
-
-
-encode_constr_bit_str_bits({{_Min1,Max1},{Min2,Max2}},BitListVal,_DoTag) ->
- BitLen = length(BitListVal),
- case BitLen of
- Len when Len > Max2 ->
- exit({error,{asn1,{bitstring_length,{{was,BitLen},
- {maximum,Max2}}}}});
- Len when Len > Max1, Len < Min2 ->
- exit({error,{asn1,{bitstring_length,{{was,BitLen},
- {not_allowed_interval,
- Max1,Min2}}}}});
- _ ->
- encode_bitstring(BitListVal)
- end;
-encode_constr_bit_str_bits({Min,Max},BitListVal,_DoTag) ->
- BitLen = length(BitListVal),
- if
- BitLen > Max ->
- exit({error,{asn1,{bitstring_length,{{was,BitLen},
- {maximum,Max}}}}});
- BitLen < Min ->
- exit({error,{asn1,{bitstring_length,{{was,BitLen},
- {minimum,Min}}}}});
- true ->
- encode_bitstring(BitListVal)
- end.
-
-
-%% returns a list of length Size + length(BitListVal), with BitListVal
-%% as the most significant elements followed by padded zero elements
-pad_bit_list(Size,BitListVal) ->
- Tail = lists:duplicate(Size,0),
- BitListVal ++ Tail.
-
-%%=================================================================
-%% Do the actual encoding
-%% ([bitlist]) -> {ListLen, UnusedBits, OctetList}
-%%=================================================================
-
-encode_bitstring([B8, B7, B6, B5, B4, B3, B2, B1 | Rest]) ->
- Val = (B8 bsl 7) bor (B7 bsl 6) bor (B6 bsl 5) bor (B5 bsl 4) bor
- (B4 bsl 3) bor (B3 bsl 2) bor (B2 bsl 1) bor B1,
- encode_bitstring(Rest, [Val], 1);
-encode_bitstring(Val) ->
- {Unused, Octet} = unused_bitlist(Val, 7, 0),
- {1, Unused, [Octet]}.
-
-encode_bitstring([B8, B7, B6, B5, B4, B3, B2, B1 | Rest], Ack, Len) ->
- Val = (B8 bsl 7) bor (B7 bsl 6) bor (B6 bsl 5) bor (B5 bsl 4) bor
- (B4 bsl 3) bor (B3 bsl 2) bor (B2 bsl 1) bor B1,
- encode_bitstring(Rest, [Ack | [Val]], Len + 1);
-%%even multiple of 8 bits..
-encode_bitstring([], Ack, Len) ->
- {Len, 0, Ack};
-%% unused bits in last octet
-encode_bitstring(Rest, Ack, Len) ->
-% io:format("uneven ~w ~w ~w~n",[Rest, Ack, Len]),
- {Unused, Val} = unused_bitlist(Rest, 7, 0),
- {Len + 1, Unused, [Ack | [Val]]}.
-
-%%%%%%%%%%%%%%%%%%
-%% unused_bitlist([list of ones and zeros <= 7], 7, []) ->
-%% {Unused bits, Last octet with bits moved to right}
-unused_bitlist([], Trail, Ack) ->
- {Trail + 1, Ack};
-unused_bitlist([Bit | Rest], Trail, Ack) ->
-%% io:format("trail Bit: ~w Rest: ~w Trail: ~w Ack:~w~n",[Bit, Rest, Trail, Ack]),
- unused_bitlist(Rest, Trail - 1, (Bit bsl Trail) bor Ack).
-
-
-%%============================================================================
-%% decode bitstring value
-%% (Buffer, Range, NamedNumberList, HasTag, TotalLen) -> {Integer, Remain, RemovedBytes}
-%%============================================================================
-
-decode_compact_bit_string(Buffer, Range, NamedNumberList, Tags, LenIn, OptOrMand) ->
-% NewTags = new_tags(HasTag,#tag{class=?UNIVERSAL,number=?N_BIT_STRING}),
- decode_restricted_string(Buffer, Range, ?N_BIT_STRING, Tags, LenIn,
- NamedNumberList, OptOrMand,bin).
-
-decode_bit_string(Buffer, Range, NamedNumberList, Tags, LenIn, OptOrMand) ->
-% NewTags = new_tags(HasTag,#tag{class=?UNIVERSAL,number=?N_BIT_STRING}),
- decode_restricted_string(Buffer, Range, ?N_BIT_STRING, Tags, LenIn,
- NamedNumberList, OptOrMand,old).
-
-
-decode_bit_string2(1,<<0 ,Buffer/binary>>,_NamedNumberList,RemovedBytes,BinOrOld) ->
- case BinOrOld of
- bin ->
- {{0,<<>>},Buffer,RemovedBytes};
- _ ->
- {[], Buffer, RemovedBytes}
- end;
-decode_bit_string2(Len,<<Unused,Buffer/binary>>,NamedNumberList,
- RemovedBytes,BinOrOld) ->
- L = Len - 1,
- <<Bits:L/binary,BufferTail/binary>> = Buffer,
- case NamedNumberList of
- [] ->
- case BinOrOld of
- bin ->
- {{Unused,Bits},BufferTail,RemovedBytes};
- _ ->
- BitString = decode_bitstring2(L, Unused, Buffer),
- {BitString,BufferTail, RemovedBytes}
- end;
- _ ->
- BitString = decode_bitstring2(L, Unused, Buffer),
- {decode_bitstring_NNL(BitString,NamedNumberList),
- BufferTail,
- RemovedBytes}
- end.
-
-%%----------------------------------------
-%% Decode the in buffer to bits
-%%----------------------------------------
-decode_bitstring2(1,Unused,<<B7:1,B6:1,B5:1,B4:1,B3:1,B2:1,B1:1,B0:1,_/binary>>) ->
- lists:sublist([B7,B6,B5,B4,B3,B2,B1,B0],8-Unused);
-decode_bitstring2(Len, Unused,
- <<B7:1,B6:1,B5:1,B4:1,B3:1,B2:1,B1:1,B0:1,Buffer/binary>>) ->
- [B7, B6, B5, B4, B3, B2, B1, B0 |
- decode_bitstring2(Len - 1, Unused, Buffer)].
-
-%%decode_bitstring2(1, Unused, Buffer) ->
-%% make_bits_of_int(hd(Buffer), 128, 8-Unused);
-%%decode_bitstring2(Len, Unused, [BitVal | Buffer]) ->
-%% [B7, B6, B5, B4, B3, B2, B1, B0] = make_bits_of_int(BitVal, 128, 8),
-%% [B7, B6, B5, B4, B3, B2, B1, B0 |
-%% decode_bitstring2(Len - 1, Unused, Buffer)].
-
-
-%%make_bits_of_int(_, _, 0) ->
-%% [];
-%%make_bits_of_int(BitVal, MaskVal, Unused) when Unused > 0 ->
-%% X = case MaskVal band BitVal of
-%% 0 -> 0 ;
-%% _ -> 1
-%% end,
-%% [X | make_bits_of_int(BitVal, MaskVal bsr 1, Unused - 1)].
-
-
-
-%%----------------------------------------
-%% Decode the bitlist to names
-%%----------------------------------------
-
-decode_bitstring_NNL(BitList,NamedNumberList) ->
- decode_bitstring_NNL(BitList,NamedNumberList,0,[]).
-
-
-decode_bitstring_NNL([],_,_No,Result) ->
- lists:reverse(Result);
-
-decode_bitstring_NNL([B|BitList],[{Name,No}|NamedNumberList],No,Result) ->
- if
- B =:= 0 ->
- decode_bitstring_NNL(BitList,NamedNumberList,No+1,Result);
- true ->
- decode_bitstring_NNL(BitList,NamedNumberList,No+1,[Name|Result])
- end;
-decode_bitstring_NNL([1|BitList],NamedNumberList,No,Result) ->
- decode_bitstring_NNL(BitList,NamedNumberList,No+1,[{bit,No}|Result]);
-decode_bitstring_NNL([0|BitList],NamedNumberList,No,Result) ->
- decode_bitstring_NNL(BitList,NamedNumberList,No+1,Result).
-
-
-%%============================================================================
-%% Octet string, ITU_T X.690 Chapter 8.7
-%%
-%% encode octet string
-%% The OctetList must be a flat list of integers in the range 0..255
-%% the function does not check this because it takes to much time
-%%============================================================================
-encode_octet_string(_C, OctetList, []) when is_binary(OctetList) ->
- dotag_universal(?N_OCTET_STRING,OctetList,byte_size(OctetList));
-encode_octet_string(_C, OctetList, DoTag) when is_binary(OctetList) ->
- dotag(DoTag, ?N_OCTET_STRING, {OctetList,byte_size(OctetList)});
-encode_octet_string(_C, OctetList, DoTag) when is_list(OctetList) ->
- case length(OctetList) of
- Len when DoTag =:= [] ->
- dotag_universal(?N_OCTET_STRING,OctetList,Len);
- Len ->
- dotag(DoTag, ?N_OCTET_STRING, {OctetList,Len})
- end;
-%% encode_octet_string(C, OctetList, DoTag) when is_list(OctetList) ->
-%% dotag(DoTag, ?N_OCTET_STRING, {OctetList,length(OctetList)});
-encode_octet_string(C, {Name,OctetList}, DoTag) when is_atom(Name) ->
- encode_octet_string(C, OctetList, DoTag).
-
-
-%%============================================================================
-%% decode octet string
-%% (Buffer, Range, HasTag, TotalLen) -> {String, Remain, RemovedBytes}
-%%
-%% Octet string is decoded as a restricted string
-%%============================================================================
-decode_octet_string(Buffer, Range, Tags, TotalLen, OptOrMand) ->
-%% NewTags = new_tags(HasTag,#tag{class=?UNIVERSAL,number=?N_OCTET_STRING}),
- decode_restricted_string(Buffer, Range, ?N_OCTET_STRING,
- Tags, TotalLen, [], OptOrMand,old).
-
-%%============================================================================
-%% Null value, ITU_T X.690 Chapter 8.8
-%%
-%% encode NULL value
-%%============================================================================
-
-encode_null(_, []) ->
- {[?N_NULL,0],2};
-encode_null(_, DoTag) ->
- dotag(DoTag, ?N_NULL, {[],0}).
-
-%%============================================================================
-%% decode NULL value
-%% (Buffer, HasTag, TotalLen) -> {NULL, Remain, RemovedBytes}
-%%============================================================================
-decode_null(Buffer, Tags, OptOrMand) ->
- NewTags = new_tags(Tags,#tag{class=?UNIVERSAL,number=?N_NULL}),
- decode_null_notag(Buffer, NewTags, OptOrMand).
-
-decode_null_notag(Buffer, Tags, OptOrMand) ->
- {RestTags, {FormLen, Buffer0, Rb0}} =
- check_tags_i(Tags, Buffer, OptOrMand),
-
- case FormLen of
- {?CONSTRUCTED,Len} ->
- {_Buffer00,RestBytes} = split_list(Buffer0,Len),
- {Val01, Buffer01, Rb01} = decode_null_notag(Buffer0, RestTags,
- OptOrMand),
- {Buffer02, Rb02} = restbytes2(RestBytes,Buffer01,noext),
- {Val01, Buffer02, Rb0+Rb01+Rb02};
- {_,0} ->
- {'NULL', Buffer0, Rb0};
- {_,Len} ->
- exit({error,{asn1,{invalid_length,'NULL',Len}}})
- end.
-
-
-%%============================================================================
-%% Object identifier, ITU_T X.690 Chapter 8.19
-%%
-%% encode Object Identifier value
-%%============================================================================
-
-encode_object_identifier({Name,Val}, DoTag) when is_atom(Name) ->
- encode_object_identifier(Val, DoTag);
-encode_object_identifier(Val, []) ->
- {EncVal,Len} = e_object_identifier(Val),
- dotag_universal(?N_OBJECT_IDENTIFIER,EncVal,Len);
-encode_object_identifier(Val, DoTag) ->
- dotag(DoTag, ?N_OBJECT_IDENTIFIER, e_object_identifier(Val)).
-
-e_object_identifier({'OBJECT IDENTIFIER', V}) ->
- e_object_identifier(V);
-e_object_identifier({Cname, V}) when is_atom(Cname), is_tuple(V) ->
- e_object_identifier(tuple_to_list(V));
-e_object_identifier({Cname, V}) when is_atom(Cname), is_list(V) ->
- e_object_identifier(V);
-e_object_identifier(V) when is_tuple(V) ->
- e_object_identifier(tuple_to_list(V));
-
-%%%%%%%%%%%%%%%
-%% e_object_identifier([List of Obect Identifiers]) ->
-%% {[Encoded Octetlist of ObjIds], IntLength}
-%%
-e_object_identifier([E1, E2 | Tail]) ->
- Head = 40*E1 + E2, % wow!
- {H,Lh} = mk_object_val(Head),
- {R,Lr} = enc_obj_id_tail(Tail, [], 0),
- {[H|R], Lh+Lr}.
-
-enc_obj_id_tail([], Ack, Len) ->
- {lists:reverse(Ack), Len};
-enc_obj_id_tail([H|T], Ack, Len) ->
- {B, L} = mk_object_val(H),
- enc_obj_id_tail(T, [B|Ack], Len+L).
+encode_integer_neg(-1, L=[B1|_T]) when B1 > 127 ->
+ L;
+encode_integer_neg(N, Acc) ->
+ encode_integer_neg(N bsr 8, [N band 16#ff|Acc]).
%%%%%%%%%%%
@@ -1643,476 +440,6 @@ mk_object_val(Val, Ack, Len) ->
mk_object_val(Val bsr 7, [((Val band 127) bor 128) | Ack], Len + 1).
-
-%%============================================================================
-%% decode Object Identifier value
-%% (Buffer, HasTag, TotalLen) -> {{ObjId}, Remain, RemovedBytes}
-%%============================================================================
-
-decode_object_identifier(Buffer, Tags, OptOrMand) ->
- NewTags = new_tags(Tags,#tag{class=?UNIVERSAL,
- number=?N_OBJECT_IDENTIFIER}),
- decode_object_identifier_notag(Buffer, NewTags, OptOrMand).
-
-decode_object_identifier_notag(Buffer, Tags, OptOrMand) ->
- {RestTags, {FormLen, Buffer0, Rb0}} =
- check_tags_i(Tags, Buffer, OptOrMand),
-
- case FormLen of
- {?CONSTRUCTED,Len} ->
- {Buffer00,RestBytes} = split_list(Buffer0,Len),
- {Val01, Buffer01, Rb01} =
- decode_object_identifier_notag(Buffer00,
- RestTags, OptOrMand),
- {Buffer02, Rb02} = restbytes2(RestBytes,Buffer01,noext),
- {Val01, Buffer02, Rb0+Rb01+Rb02};
- {_,Len} ->
- {[AddedObjVal|ObjVals],Buffer01} =
- dec_subidentifiers(Buffer0,0,[],Len),
- {Val1, Val2} = if
- AddedObjVal < 40 ->
- {0, AddedObjVal};
- AddedObjVal < 80 ->
- {1, AddedObjVal - 40};
- true ->
- {2, AddedObjVal - 80}
- end,
- {list_to_tuple([Val1, Val2 | ObjVals]), Buffer01,
- Rb0+Len}
- end.
-
-dec_subidentifiers(Buffer,_Av,Al,0) ->
- {lists:reverse(Al),Buffer};
-dec_subidentifiers(<<1:1,H:7,T/binary>>,Av,Al,Len) ->
- dec_subidentifiers(T,(Av bsl 7) + H,Al,Len-1);
-dec_subidentifiers(<<H,T/binary>>,Av,Al,Len) ->
- dec_subidentifiers(T,0,[((Av bsl 7) + H)|Al],Len-1).
-
-%%============================================================================
-%% RELATIVE-OID, ITU_T X.690 Chapter 8.20
-%%
-%% encode Relative Object Identifier
-%%============================================================================
-encode_relative_oid({Name,Val},TagIn) when is_atom(Name) ->
- encode_relative_oid(Val,TagIn);
-encode_relative_oid(Val,TagIn) when is_tuple(Val) ->
- encode_relative_oid(tuple_to_list(Val),TagIn);
-encode_relative_oid(Val,[]) ->
- {EncVal,Len} = enc_relative_oid(Val),
- dotag_universal(?'N_RELATIVE-OID',EncVal,Len);
-encode_relative_oid(Val, DoTag) ->
- dotag(DoTag, ?'N_RELATIVE-OID', enc_relative_oid(Val)).
-
-enc_relative_oid(Val) ->
- lists:mapfoldl(fun(X,AccIn) ->
- {SO,L}=mk_object_val(X),
- {SO,L+AccIn}
- end
- ,0,Val).
-
-%%============================================================================
-%% decode Relative Object Identifier value
-%% (Buffer, HasTag, TotalLen) -> {{ObjId}, Remain, RemovedBytes}
-%%============================================================================
-decode_relative_oid(Buffer, Tags, OptOrMand) ->
- NewTags = new_tags(Tags,#tag{class=?UNIVERSAL,
- number=?'N_RELATIVE-OID'}),
- decode_relative_oid_notag(Buffer, NewTags, OptOrMand).
-
-decode_relative_oid_notag(Buffer, Tags, OptOrMand) ->
- {_RestTags, {_FormLen={_,Len}, Buffer0, Rb0}} =
- check_tags_i(Tags, Buffer, OptOrMand),
- {ObjVals,Buffer01} =
- dec_subidentifiers(Buffer0,0,[],Len),
- {list_to_tuple(ObjVals), Buffer01, Rb0+Len}.
-
-%%============================================================================
-%% Restricted character string types, ITU_T X.690 Chapter 8.21
-%%
-%% encode Numeric Printable Teletex Videotex Visible IA5 Graphic General strings
-%%============================================================================
-encode_restricted_string(_C, OctetList, StringType, [])
- when is_binary(OctetList) ->
- dotag_universal(StringType, OctetList, byte_size(OctetList));
-encode_restricted_string(_C, OctetList, StringType, DoTag)
- when is_binary(OctetList) ->
- dotag(DoTag, StringType, {OctetList, byte_size(OctetList)});
-encode_restricted_string(_C, OctetList, StringType, [])
- when is_list(OctetList) ->
- dotag_universal(StringType, OctetList, length(OctetList));
-encode_restricted_string(_C, OctetList, StringType, DoTag)
- when is_list(OctetList) ->
- dotag(DoTag, StringType, {OctetList, length(OctetList)});
-encode_restricted_string(C,{Name,OctetL},StringType,DoTag) when is_atom(Name) ->
- encode_restricted_string(C, OctetL, StringType, DoTag).
-
-%%============================================================================
-%% decode Numeric Printable Teletex Videotex Visible IA5 Graphic General strings
-%% (Buffer, Range, StringType, HasTag, TotalLen) ->
-%% {String, Remain, RemovedBytes}
-%%============================================================================
-
-decode_restricted_string(Buffer, Range, StringType, Tags, LenIn, OptOrMand) ->
- {Val,Buffer2,Rb} =
- decode_restricted_string_tag(Buffer, Range, StringType, Tags,
- LenIn, [], OptOrMand,old),
- {check_and_convert_restricted_string(Val,StringType,Range,[],old),
- Buffer2,Rb}.
-
-
-decode_restricted_string(Buffer, Range, StringType, Tags, LenIn, NNList, OptOrMand, BinOrOld ) ->
- {Val,Buffer2,Rb} =
- decode_restricted_string_tag(Buffer, Range, StringType, Tags,
- LenIn, NNList, OptOrMand, BinOrOld),
- {check_and_convert_restricted_string(Val,StringType,Range,NNList,BinOrOld),
- Buffer2,Rb}.
-
-decode_restricted_string_tag(Buffer, Range, StringType, TagsIn, LenIn, NNList, OptOrMand, BinOrOld ) ->
- NewTags = new_tags(TagsIn, #tag{class=?UNIVERSAL,number=StringType}),
- decode_restricted_string_notag(Buffer, Range, StringType, NewTags,
- LenIn, NNList, OptOrMand, BinOrOld).
-
-
-check_and_convert_restricted_string(Val,StringType,Range,NamedNumberList,_BinOrOld) ->
- {StrLen,NewVal} = case StringType of
- ?N_BIT_STRING when NamedNumberList =/= [] ->
- {no_check,Val};
- ?N_BIT_STRING when is_list(Val) ->
- {length(Val),Val};
- ?N_BIT_STRING when is_tuple(Val) ->
- {(size(element(2,Val))*8) - element(1,Val),Val};
- _ when is_binary(Val) ->
- {byte_size(Val),binary_to_list(Val)};
- _ when is_list(Val) ->
- {length(Val), Val}
- end,
- case Range of
- _ when StrLen =:= no_check ->
- NewVal;
- [] -> % No length constraint
- NewVal;
- {Lb,Ub} when StrLen >= Lb, Ub >= StrLen -> % variable length constraint
- NewVal;
- {{Lb,_Ub},[]} when StrLen >= Lb ->
- NewVal;
- {{Lb,_Ub},_Ext=[MinExt|_]} when StrLen >= Lb; StrLen >= MinExt ->
- NewVal;
- {{Lb1,Ub1},{Lb2,Ub2}} when StrLen >= Lb1, StrLen =< Ub1;
- StrLen =< Ub2, StrLen >= Lb2 ->
- NewVal;
- StrLen -> % fixed length constraint
- NewVal;
- {_,_} ->
- exit({error,{asn1,{length,Range,Val}}});
- _Len when is_integer(_Len) ->
- exit({error,{asn1,{length,Range,Val}}});
- _ -> % some strange constraint that we don't support yet
- NewVal
- end.
-
-%%=============================================================================
-%% Common routines for several string types including bit string
-%% handles indefinite length
-%%=============================================================================
-
-
-decode_restricted_string_notag(Buffer, _Range, StringType, TagsIn,
- _, NamedNumberList, OptOrMand, BinOrOld) ->
- %%-----------------------------------------------------------
- %% Get inner (the implicit tag or no tag) and
- %% outer (the explicit tag) lengths.
- %%-----------------------------------------------------------
- {RestTags, {FormLength={_,_Len01}, Buffer0, Rb0}} =
- check_tags_i(TagsIn, Buffer, OptOrMand),
-
- case FormLength of
- {?CONSTRUCTED,Len} ->
- {Buffer00, RestBytes} = split_list(Buffer0,Len),
- {Val01, Buffer01, Rb01} =
- decode_restricted_parts(Buffer00, RestBytes, [], StringType,
- RestTags,
- Len, NamedNumberList,
- OptOrMand,
- BinOrOld, 0, []),
- {Val01, Buffer01, Rb0+Rb01};
- {_, Len} ->
- {Val01, Buffer01, Rb01} =
- decode_restricted(Buffer0, Len, StringType,
- NamedNumberList, BinOrOld),
- {Val01, Buffer01, Rb0+Rb01}
- end.
-
-
-decode_restricted_parts(Buffer, RestBytes, [], StringType, RestTags, Len, NNList,
- OptOrMand, BinOrOld, AccRb, AccVal) ->
- DecodeFun = case RestTags of
- [] -> fun decode_restricted_string_tag/8;
- _ -> fun decode_restricted_string_notag/8
- end,
- {Val, Buffer1, Rb} =
- DecodeFun(Buffer, [], StringType, RestTags,
- no_length, NNList,
- OptOrMand, BinOrOld),
- {Buffer2,More} =
- case Buffer1 of
- <<0,0,Buffer10/binary>> when Len == indefinite ->
- {Buffer10,false};
- <<>> ->
- {RestBytes,false};
- _ ->
- {Buffer1,true}
- end,
- {NewVal, NewRb} =
- case StringType of
- ?N_BIT_STRING when BinOrOld == bin ->
- {concat_bit_binaries(AccVal, Val), AccRb+Rb};
- _ when is_binary(Val),is_binary(AccVal) ->
- {<<AccVal/binary,Val/binary>>,AccRb+Rb};
- _ when is_binary(Val), AccVal =:= [] ->
- {Val,AccRb+Rb};
- _ ->
- {AccVal++Val, AccRb+Rb}
- end,
- case More of
- false ->
- {NewVal, Buffer2, NewRb};
- true ->
- decode_restricted_parts(Buffer2, RestBytes, [], StringType, RestTags, Len, NNList,
- OptOrMand, BinOrOld, NewRb, NewVal)
- end.
-
-
-
-decode_restricted(Buffer, InnerLen, StringType, NamedNumberList,BinOrOld) ->
-
- case StringType of
- ?N_BIT_STRING ->
- decode_bit_string2(InnerLen,Buffer,NamedNumberList,InnerLen,BinOrOld);
-
- ?N_UniversalString ->
- <<PreBuff:InnerLen/binary,RestBuff/binary>> = Buffer,%%added for binary
- UniString = mk_universal_string(binary_to_list(PreBuff)),
- {UniString,RestBuff,InnerLen};
- ?N_BMPString ->
- <<PreBuff:InnerLen/binary,RestBuff/binary>> = Buffer,%%added for binary
- BMP = mk_BMP_string(binary_to_list(PreBuff)),
- {BMP,RestBuff,InnerLen};
- _ ->
- <<PreBuff:InnerLen/binary,RestBuff/binary>> = Buffer,%%added for binary
- {PreBuff, RestBuff, InnerLen}
- end.
-
-
-
-%%============================================================================
-%% encode Universal string
-%%============================================================================
-
-encode_universal_string(C, {Name, Universal}, DoTag) when is_atom(Name) ->
- encode_universal_string(C, Universal, DoTag);
-encode_universal_string(_C, Universal, []) ->
- OctetList = mk_uni_list(Universal),
- dotag_universal(?N_UniversalString,OctetList,length(OctetList));
-encode_universal_string(_C, Universal, DoTag) ->
- OctetList = mk_uni_list(Universal),
- dotag(DoTag, ?N_UniversalString, {OctetList,length(OctetList)}).
-
-mk_uni_list(In) ->
- mk_uni_list(In,[]).
-
-mk_uni_list([],List) ->
- lists:reverse(List);
-mk_uni_list([{A,B,C,D}|T],List) ->
- mk_uni_list(T,[D,C,B,A|List]);
-mk_uni_list([H|T],List) ->
- mk_uni_list(T,[H,0,0,0|List]).
-
-%%===========================================================================
-%% decode Universal strings
-%% (Buffer, Range, StringType, HasTag, LenIn) ->
-%% {String, Remain, RemovedBytes}
-%%===========================================================================
-
-decode_universal_string(Buffer, Range, Tags, LenIn, OptOrMand) ->
-% NewTags = new_tags(HasTag, #tag{class=?UNIVERSAL,number=?N_UniversalString}),
- decode_restricted_string(Buffer, Range, ?N_UniversalString,
- Tags, LenIn, [], OptOrMand,old).
-
-
-mk_universal_string(In) ->
- mk_universal_string(In,[]).
-
-mk_universal_string([],Acc) ->
- lists:reverse(Acc);
-mk_universal_string([0,0,0,D|T],Acc) ->
- mk_universal_string(T,[D|Acc]);
-mk_universal_string([A,B,C,D|T],Acc) ->
- mk_universal_string(T,[{A,B,C,D}|Acc]).
-
-
-%%============================================================================
-%% encode UTF8 string
-%%============================================================================
-encode_UTF8_string(_,UTF8String,[]) when is_binary(UTF8String) ->
- dotag_universal(?N_UTF8String,UTF8String,byte_size(UTF8String));
-encode_UTF8_string(_,UTF8String,DoTag) when is_binary(UTF8String) ->
- dotag(DoTag,?N_UTF8String,{UTF8String,byte_size(UTF8String)});
-encode_UTF8_string(_,UTF8String,[]) ->
- dotag_universal(?N_UTF8String,UTF8String,length(UTF8String));
-encode_UTF8_string(_,UTF8String,DoTag) ->
- dotag(DoTag,?N_UTF8String,{UTF8String,length(UTF8String)}).
-
-%%============================================================================
-%% decode UTF8 string
-%%============================================================================
-
-decode_UTF8_string(Buffer, Tags, OptOrMand) ->
- NewTags = new_tags(Tags, #tag{class=?UNIVERSAL,number=?N_UTF8String}),
- decode_UTF8_string_notag(Buffer, NewTags, OptOrMand).
-
-decode_UTF8_string_notag(Buffer, Tags, OptOrMand) ->
- {RestTags, {FormLen, Buffer0, Rb0}} =
- check_tags_i(Tags, Buffer, OptOrMand),
- case FormLen of
- {?CONSTRUCTED,Len} ->
- %% an UTF8String may be encoded as a constructed type
- {Buffer00,RestBytes} = split_list(Buffer0,Len),
- {Val01, Buffer01, Rb01} =
- decode_UTF8_string_notag(Buffer00,RestTags,OptOrMand),
- {Buffer02, Rb02} = restbytes2(RestBytes,Buffer01,noext),
- {Val01, Buffer02, Rb0+Rb01+Rb02};
- {_,Len} ->
- <<Result:Len/binary,RestBuff/binary>> = Buffer0,
- {Result,RestBuff,Rb0 + Len}
- end.
-
-
-%%============================================================================
-%% encode BMP string
-%%============================================================================
-
-encode_BMP_string(C, {Name,BMPString}, DoTag) when is_atom(Name) ->
- encode_BMP_string(C, BMPString, DoTag);
-encode_BMP_string(_C, BMPString, []) ->
- OctetList = mk_BMP_list(BMPString),
- dotag_universal(?N_BMPString,OctetList,length(OctetList));
-encode_BMP_string(_C, BMPString, DoTag) ->
- OctetList = mk_BMP_list(BMPString),
- dotag(DoTag, ?N_BMPString, {OctetList,length(OctetList)}).
-
-mk_BMP_list(In) ->
- mk_BMP_list(In,[]).
-
-mk_BMP_list([],List) ->
- lists:reverse(List);
-mk_BMP_list([{0,0,C,D}|T],List) ->
- mk_BMP_list(T,[D,C|List]);
-mk_BMP_list([H|T],List) ->
- mk_BMP_list(T,[H,0|List]).
-
-%%============================================================================
-%% decode (OctetList, Range(ignored), tag|notag) -> {ValList, RestList}
-%% (Buffer, Range, StringType, HasTag, TotalLen) ->
-%% {String, Remain, RemovedBytes}
-%%============================================================================
-decode_BMP_string(Buffer, Range, Tags, LenIn, OptOrMand) ->
-% NewTags = new_tags(HasTag, #tag{class=?UNIVERSAL,number=?N_BMPString}),
- decode_restricted_string(Buffer, Range, ?N_BMPString,
- Tags, LenIn, [], OptOrMand,old).
-
-mk_BMP_string(In) ->
- mk_BMP_string(In,[]).
-
-mk_BMP_string([],US) ->
- lists:reverse(US);
-mk_BMP_string([0,B|T],US) ->
- mk_BMP_string(T,[B|US]);
-mk_BMP_string([C,D|T],US) ->
- mk_BMP_string(T,[{0,0,C,D}|US]).
-
-
-%%============================================================================
-%% Generalized time, ITU_T X.680 Chapter 39
-%%
-%% encode Generalized time
-%%============================================================================
-
-encode_generalized_time(C, {Name,OctetList}, DoTag) when is_atom(Name) ->
- encode_generalized_time(C, OctetList, DoTag);
-encode_generalized_time(_C, OctetList, []) ->
- dotag_universal(?N_GeneralizedTime,OctetList,length(OctetList));
-encode_generalized_time(_C, OctetList, DoTag) ->
- dotag(DoTag, ?N_GeneralizedTime, {OctetList,length(OctetList)}).
-
-%%============================================================================
-%% decode Generalized time
-%% (Buffer, Range, HasTag, TotalLen) -> {String, Remain, RemovedBytes}
-%%============================================================================
-
-decode_generalized_time(Buffer, Range, Tags, TotalLen, OptOrMand) ->
- NewTags = new_tags(Tags,#tag{class=?UNIVERSAL,
- number=?N_GeneralizedTime}),
- decode_generalized_time_notag(Buffer, Range, NewTags, TotalLen, OptOrMand).
-
-decode_generalized_time_notag(Buffer, Range, Tags, TotalLen, OptOrMand) ->
- {RestTags, {FormLen, Buffer0, Rb0}} =
- check_tags_i(Tags, Buffer, OptOrMand),
-
- case FormLen of
- {?CONSTRUCTED,Len} ->
- {Buffer00,RestBytes} = split_list(Buffer0,Len),
- {Val01, Buffer01, Rb01} =
- decode_generalized_time_notag(Buffer00, Range,
- RestTags, TotalLen,
- OptOrMand),
- {Buffer02, Rb02} = restbytes2(RestBytes,Buffer01,noext),
- {Val01, Buffer02, Rb0+Rb01+Rb02};
- {_,Len} ->
- <<PreBuff:Len/binary,RestBuff/binary>> = Buffer0,
- {binary_to_list(PreBuff), RestBuff, Rb0+Len}
- end.
-
-%%============================================================================
-%% Universal time, ITU_T X.680 Chapter 40
-%%
-%% encode UTC time
-%%============================================================================
-
-encode_utc_time(C, {Name,OctetList}, DoTag) when is_atom(Name) ->
- encode_utc_time(C, OctetList, DoTag);
-encode_utc_time(_C, OctetList, []) ->
- dotag_universal(?N_UTCTime, OctetList,length(OctetList));
-encode_utc_time(_C, OctetList, DoTag) ->
- dotag(DoTag, ?N_UTCTime, {OctetList,length(OctetList)}).
-
-%%============================================================================
-%% decode UTC time
-%% (Buffer, Range, HasTag, TotalLen) -> {String, Remain, RemovedBytes}
-%%============================================================================
-
-decode_utc_time(Buffer, Range, Tags, TotalLen, OptOrMand) ->
- NewTags = new_tags(Tags,#tag{class=?UNIVERSAL,number=?N_UTCTime}),
- decode_utc_time_notag(Buffer, Range, NewTags, TotalLen, OptOrMand).
-
-decode_utc_time_notag(Buffer, Range, Tags, TotalLen, OptOrMand) ->
- {RestTags, {FormLen, Buffer0, Rb0}} =
- check_tags_i(Tags, Buffer, OptOrMand),
-
- case FormLen of
- {?CONSTRUCTED,Len} ->
- {Buffer00,RestBytes} = split_list(Buffer0,Len),
- {Val01, Buffer01, Rb01} =
- decode_utc_time_notag(Buffer00, Range,
- RestTags, TotalLen,
- OptOrMand),
- {Buffer02, Rb02} = restbytes2(RestBytes,Buffer01,noext),
- {Val01, Buffer02, Rb0+Rb01+Rb02};
- {_,Len} ->
- <<PreBuff:Len/binary,RestBuff/binary>> = Buffer0,
- {binary_to_list(PreBuff), RestBuff, Rb0+Len}
- end.
-
-
%%============================================================================
%% Length handling
%%
@@ -2122,8 +449,6 @@ decode_utc_time_notag(Buffer, Range, Tags, TotalLen, OptOrMand) ->
%% [<127]| [128 + Int (<127),OctetList] | [16#80]
%%============================================================================
-encode_length(indefinite) ->
- {[16#80],1}; % 128
encode_length(L) when L =< 16#7F ->
{[L],1};
encode_length(L) ->
@@ -2162,242 +487,12 @@ decode_length(<<1:1,LL:7,T/binary>>) ->
<<Length:LL/unit:8,Rest/binary>> = T,
{{Length,Rest}, LL+1}.
-%decode_length([128 | T]) ->
-% {{indefinite, T},1};
-%decode_length([H | T]) when H =< 127 ->
-% {{H, T},1};
-%decode_length([H | T]) ->
-% dec_long_length(H band 16#7F, T, 0, 1).
-
-
-%%dec_long_length(0, Buffer, Acc, Len) ->
-%% {{Acc, Buffer},Len};
-%%dec_long_length(Bytes, [H | T], Acc, Len) ->
-%% dec_long_length(Bytes - 1, T, (Acc bsl 8) + H, Len+1).
-
-%%===========================================================================
-%% Decode tag and length
-%%
-%% decode_tag_and_length(Buffer) -> {Tag, Len, RemainingBuffer, RemovedBytes}
-%%
-%%===========================================================================
-
-decode_tag_and_length(Buffer) ->
- {Tag, Buffer2, RemBytesTag} = decode_tag(Buffer),
- {{Len, Buffer3}, RemBytesLen} = decode_length(Buffer2),
- {Tag, Len, Buffer3, RemBytesTag+RemBytesLen}.
-
-
-%%============================================================================
-%% Check if valid tag
-%%
-%% check_if_valid_tag(Tag, List_of_valid_tags, OptOrMand) -> name of the tag
-%%============================================================================
-
-check_if_valid_tag(<<0,0,_/binary>>,_,_) ->
- asn1_EOC;
-check_if_valid_tag(<<>>, _, OptOrMand) ->
- check_if_valid_tag2_error([], OptOrMand);
-check_if_valid_tag(Bytes, ListOfTags, OptOrMand) when is_binary(Bytes) ->
- {Tag, _, _} = decode_tag(Bytes),
- check_if_valid_tag(Tag, ListOfTags, OptOrMand);
-
-%% This alternative should be removed in the near future
-%% Bytes as input should be the only necessary call
-check_if_valid_tag(Tag, ListOfTags, OptOrMand) ->
- {Class, _Form, TagNo} = Tag,
- C = code_class(Class),
- T = case C of
- 'UNIVERSAL' ->
- code_type(TagNo);
- _ ->
- TagNo
- end,
- check_if_valid_tag2({C,T}, ListOfTags, Tag, OptOrMand).
-
-check_if_valid_tag2(_Class_TagNo, [], Tag, MandOrOpt) ->
- check_if_valid_tag2_error(Tag,MandOrOpt);
-check_if_valid_tag2(Class_TagNo, [{TagName,TagList}|T], Tag, OptOrMand) ->
- case check_if_valid_tag_loop(Class_TagNo, TagList) of
- true ->
- TagName;
- false ->
- check_if_valid_tag2(Class_TagNo, T, Tag, OptOrMand)
- end.
-
--spec check_if_valid_tag2_error(term(), atom()) -> no_return().
-
-check_if_valid_tag2_error(Tag,mandatory) ->
- exit({error,{asn1,{invalid_tag,Tag}}});
-check_if_valid_tag2_error(Tag,_) ->
- exit({error,{asn1,{no_optional_tag,Tag}}}).
-
-check_if_valid_tag_loop(_Class_TagNo,[]) ->
- false;
-check_if_valid_tag_loop(Class_TagNo,[H|T]) ->
- %% It is not possible to distinguish between SEQUENCE OF and SEQUENCE, and
- %% between SET OF and SET because both are coded as 16 and 17, respectively.
- H_without_OF = case H of
- {C, 'SEQUENCE OF'} ->
- {C, 'SEQUENCE'};
- {C, 'SET OF'} ->
- {C, 'SET'};
- Else ->
- Else
- end,
-
- case H_without_OF of
- Class_TagNo ->
- true;
- {_,_} ->
- check_if_valid_tag_loop(Class_TagNo,T);
- _ ->
- check_if_valid_tag_loop(Class_TagNo,H),
- check_if_valid_tag_loop(Class_TagNo,T)
- end.
-
-
-
-code_class(0) -> 'UNIVERSAL';
-code_class(16#40) -> 'APPLICATION';
-code_class(16#80) -> 'CONTEXT';
-code_class(16#C0) -> 'PRIVATE'.
-
-
-code_type(1) -> 'BOOLEAN';
-code_type(2) -> 'INTEGER';
-code_type(3) -> 'BIT STRING';
-code_type(4) -> 'OCTET STRING';
-code_type(5) -> 'NULL';
-code_type(6) -> 'OBJECT IDENTIFIER';
-code_type(7) -> 'ObjectDescriptor';
-code_type(8) -> 'EXTERNAL';
-code_type(9) -> 'REAL';
-code_type(10) -> 'ENUMERATED';
-code_type(11) -> 'EMBEDDED_PDV';
-code_type(16) -> 'SEQUENCE';
-% code_type(16) -> 'SEQUENCE OF';
-code_type(17) -> 'SET';
-% code_type(17) -> 'SET OF';
-code_type(18) -> 'NumericString';
-code_type(19) -> 'PrintableString';
-code_type(20) -> 'TeletexString';
-code_type(21) -> 'VideotexString';
-code_type(22) -> 'IA5String';
-code_type(23) -> 'UTCTime';
-code_type(24) -> 'GeneralizedTime';
-code_type(25) -> 'GraphicString';
-code_type(26) -> 'VisibleString';
-code_type(27) -> 'GeneralString';
-code_type(28) -> 'UniversalString';
-code_type(30) -> 'BMPString';
-code_type(Else) -> exit({error,{asn1,{unrecognized_type,Else}}}).
-
-%%-------------------------------------------------------------------------
-%% decoding of the components of a SET
-%%-------------------------------------------------------------------------
-
-decode_set(Rb, indefinite, <<0,0,Bytes/binary>>, _OptOrMand, _Fun3, Acc) ->
- {lists:reverse(Acc),Bytes,Rb+2};
-
-decode_set(Rb, indefinite, Bytes, OptOrMand, Fun3, Acc) ->
- case Fun3(Bytes, OptOrMand) of
- {_Term, _Remain, 0} ->
- {lists:reverse(Acc),Bytes,Rb};
- {Term, Remain, Rb1} ->
- Fun3(Bytes, OptOrMand),
- decode_set(Rb+Rb1, indefinite, Remain, OptOrMand, Fun3, [Term|Acc])
- end;
-%% {Term, Remain, Rb1} = Fun3(Bytes, OptOrMand),
-%% decode_set(Rb+Rb1, indefinite, Remain, OptOrMand, Fun3, [Term|Acc]);
-
-decode_set(Rb, Num, Bytes, _OptOrMand, _Fun3, Acc) when Num == 0 ->
- {lists:reverse(Acc), Bytes, Rb};
-
-decode_set(_, Num, _, _, _, _) when Num < 0 ->
- exit({error,{asn1,{length_error,'SET'}}});
-
-decode_set(Rb, Num, Bytes, OptOrMand, Fun3, Acc) ->
- case Fun3(Bytes, OptOrMand) of
- {_Term, _Remain, 0} ->
- {lists:reverse(Acc),Bytes,Rb};
- {Term, Remain, Rb1} ->
- Fun3(Bytes, OptOrMand),
- decode_set(Rb+Rb1, Num-Rb1, Remain, OptOrMand, Fun3, [Term|Acc])
- end.
-%% {Term, Remain, Rb1} = Fun3(Bytes, OptOrMand),
-%% decode_set(Rb+Rb1, Num-Rb1, Remain, OptOrMand, Fun3, [Term|Acc]).
-
-
-%%-------------------------------------------------------------------------
-%% decoding of SEQUENCE OF and SET OF
-%%-------------------------------------------------------------------------
-
-decode_components(Rb, indefinite, <<0,0,Bytes/binary>>, _Fun3, _TagIn, Acc) ->
- {lists:reverse(Acc),Bytes,Rb+2};
-
-decode_components(Rb, indefinite, Bytes, Fun3, TagIn, Acc) ->
- {Term, Remain, Rb1} = Fun3(Bytes, mandatory, TagIn),
- decode_components(Rb+Rb1, indefinite, Remain, Fun3, TagIn, [Term|Acc]);
-
-decode_components(Rb, Num, Bytes, _Fun3, _TagIn, Acc) when Num == 0 ->
- {lists:reverse(Acc), Bytes, Rb};
-
-decode_components(_, Num, _, _, _, _) when Num < 0 ->
- exit({error,{asn1,{length_error,'SET/SEQUENCE OF'}}});
-
-decode_components(Rb, Num, Bytes, Fun3, TagIn, Acc) ->
- {Term, Remain, Rb1} = Fun3(Bytes, mandatory, TagIn),
- decode_components(Rb+Rb1, Num-Rb1, Remain, Fun3, TagIn, [Term|Acc]).
-
-%%decode_components(Rb, indefinite, [0,0|Bytes], _Fun3, _TagIn, Acc) ->
-%% {lists:reverse(Acc),Bytes,Rb+2};
-
-decode_components(Rb, indefinite, <<0,0,Bytes/binary>>, _Fun4, _TagIn, _Fun, Acc) ->
- {lists:reverse(Acc),Bytes,Rb+2};
-
-decode_components(Rb, indefinite, Bytes, _Fun4, TagIn, _Fun, Acc) ->
- {Term, Remain, Rb1} = _Fun4(Bytes, mandatory, TagIn, _Fun),
- decode_components(Rb+Rb1, indefinite, Remain, _Fun4, TagIn, _Fun, [Term|Acc]);
-
-decode_components(Rb, Num, Bytes, _Fun4, _TagIn, _Fun, Acc) when Num == 0 ->
- {lists:reverse(Acc), Bytes, Rb};
-
-decode_components(_, Num, _, _, _, _, _) when Num < 0 ->
- exit({error,{asn1,{length_error,'SET/SEQUENCE OF'}}});
-
-decode_components(Rb, Num, Bytes, _Fun4, TagIn, _Fun, Acc) ->
- {Term, Remain, Rb1} = _Fun4(Bytes, mandatory, TagIn, _Fun),
- decode_components(Rb+Rb1, Num-Rb1, Remain, _Fun4, TagIn, _Fun, [Term|Acc]).
-
-
-
-%%-------------------------------------------------------------------------
-%% INTERNAL HELPER FUNCTIONS (not exported)
-%%-------------------------------------------------------------------------
-
-
-%%==========================================================================
-%% Encode tag
-%%
-%% dotag(tag | notag, TagValpattern | TagValTuple, [Length, Value]) -> [Tag]
-%% TagValPattern is a correct bitpattern for a tag
-%% TagValTuple is a tuple of three bitpatterns, Class, Form and TagNo where
-%% Class = UNIVERSAL | APPLICATION | CONTEXT | PRIVATE
-%% Form = Primitive | Constructed
-%% TagNo = Number of tag
-%%==========================================================================
-
dotag([], Tag, {Bytes,Len}) ->
dotag_universal(Tag,Bytes,Len);
dotag(Tags, Tag, {Bytes,Len}) ->
encode_tags(Tags ++ [#tag{class=?UNIVERSAL,number=Tag,form=?PRIMITIVE}],
- Bytes, Len);
-
-dotag(Tags, Tag, Bytes) ->
- encode_tags(Tags ++ [#tag{class=?UNIVERSAL,number=Tag,form=?PRIMITIVE}],
- Bytes, size(Bytes)).
+ Bytes, Len).
dotag_universal(UniversalTag,Bytes,Len) when Len =< 16#7F->
{[UniversalTag,Len,Bytes],2+Len};
@@ -2415,47 +510,6 @@ decode_integer2(Len,<<1:1,B2:7,Bs/binary>>,RemovedBytes) ->
Int = N - (1 bsl (8 * Len - 1)),
{Int,Buffer2,RemovedBytes}.
-%%decode_integer2(Len,Buffer,Acc,RemovedBytes) when (hd(Buffer) band 16#FF) =< 16#7F ->
-%% {decode_integer_pos(Buffer, 8 * (Len - 1)),skip(Buffer,Len),RemovedBytes};
-%%decode_integer2(Len,Buffer,Acc,RemovedBytes) ->
-%% {decode_integer_neg(Buffer, 8 * (Len - 1)),skip(Buffer,Len),RemovedBytes}.
-
-%%decode_integer_pos([Byte|Tail], Shift) ->
-%% (Byte bsl Shift) bor decode_integer_pos(Tail, Shift-8);
-%%decode_integer_pos([], _) -> 0.
-
-
-%%decode_integer_neg([Byte|Tail], Shift) ->
-%% (-128 + (Byte band 127) bsl Shift) bor decode_integer_pos(Tail, Shift-8).
-
-
-concat_bit_binaries([],Bin={_,_}) ->
- Bin;
-concat_bit_binaries({0,B1},{U2,B2}) ->
- {U2,<<B1/binary,B2/binary>>};
-concat_bit_binaries({U1,B1},{U2,B2}) ->
- S1 = (size(B1) * 8) - U1,
- S2 = (size(B2) * 8) - U2,
- PadBits = 8 - ((S1+S2) rem 8),
- {PadBits, <<B1:S1/binary-unit:1,B2:S2/binary-unit:1,0:PadBits>>};
-concat_bit_binaries(L1,L2) when is_list(L1), is_list(L2) ->
- %% this case occur when decoding with NNL
- L1 ++ L2.
-
-
-get_constraint(C,Key) ->
- case lists:keyfind(Key,1,C) of
- false ->
- no;
- {_, V} ->
- V
- end.
-
-%%skip(Buffer, 0) ->
-%% Buffer;
-%%skip([H | T], Len) ->
-%% skip(T, Len-1).
-
new_tags([],LastTag) ->
[LastTag];
new_tags(Tags = [#tag{type='IMPLICIT'}],_LastTag) ->
diff --git a/lib/asn1/src/asn1rt_ber_bin_v2.erl b/lib/asn1/src/asn1rt_ber_bin_v2.erl
index 9ff5017c68..92ca11cf89 100644
--- a/lib/asn1/src/asn1rt_ber_bin_v2.erl
+++ b/lib/asn1/src/asn1rt_ber_bin_v2.erl
@@ -22,8 +22,7 @@
%% encoding / decoding of BER
-export([decode/1, decode/2, match_tags/2, encode/1, encode/2]).
--export([fixoptionals/2, cindex/3,
- list_to_record/2,
+-export([fixoptionals/2,
encode_tag_val/1,
encode_tags/3,
skip_ExtensionAdditions/2]).
@@ -54,8 +53,6 @@
decode_open_type_as_binary/3]).
-export([decode_primitive_incomplete/2,decode_selective/2]).
-
--export([is_nif_loadable/0]).
% the encoding of class of tag bits 8 and 7
-define(UNIVERSAL, 0).
@@ -135,12 +132,7 @@ encode(Tlv,_) when is_binary(Tlv) ->
encode([Tlv],Method) ->
encode(Tlv,Method);
encode(Tlv, nif) ->
- case is_nif_loadable() of
- true ->
- asn1rt_nif:encode_ber_tlv(Tlv);
- false ->
- encode_erl(Tlv)
- end;
+ asn1rt_nif:encode_ber_tlv(Tlv);
encode(Tlv, _) ->
encode_erl(Tlv).
@@ -178,36 +170,15 @@ decode(B) ->
%% asn1-1.7
decode(B, nif) ->
- case is_nif_loadable() of
- true ->
- case asn1rt_nif:decode_ber_tlv(B) of
- {error, Reason} -> handle_error(Reason, B);
- Else -> Else
- end;
- false ->
- decode(B)
+ case asn1rt_nif:decode_ber_tlv(B) of
+ {error, Reason} -> handle_error(Reason, B);
+ Else -> Else
end;
decode(B,erlang) when is_binary(B) ->
decode_primitive(B);
decode(Tlv,erlang) ->
{Tlv,<<>>}.
-%% Have to check this since asn1 is not guaranteed to be available
-is_nif_loadable() ->
- case application:get_env(asn1, nif_loadable) of
- {ok,R} ->
- R;
- undefined ->
- case catch code:load_file(asn1rt_nif) of
- {module, asn1rt_nif} ->
- application:set_env(asn1, nif_loadable, true),
- true;
- _Else ->
- application:set_env(asn1, nif_loadable, false),
- false
- end
- end.
-
handle_error([],_)->
exit({error,{asn1,{"memory allocation problem"}}});
handle_error({$1,_},L) -> % error in nif
@@ -612,13 +583,6 @@ match_tags(Tlv, []) ->
Tlv;
match_tags(Tlv = {Tag,_V},[T|_Tt]) ->
exit({error,{asn1,{wrong_tag,{{expected,T},{got,Tag,Tlv}}}}}).
-
-
-cindex(Ix,Val,Cname) ->
- case element(Ix,Val) of
- {Cname,Val2} -> Val2;
- X -> X
- end.
%%%
%% skips components that do not match a tag in Tags
@@ -642,13 +606,6 @@ skip_ExtensionAdditions(TLV=[{Tag,_}|Rest],Tags) ->
%%===============================================================================
%%===============================================================================
-% converts a list to a record if necessary
-list_to_record(Name,List) when is_list(List) ->
- list_to_tuple([Name|List]);
-list_to_record(_Name,Tuple) when is_tuple(Tuple) ->
- Tuple.
-
-
fixoptionals(OptList,Val) when is_list(Val) ->
fixoptionals(OptList,Val,1,[],[]).
diff --git a/lib/asn1/src/asn1rt_per_bin.erl b/lib/asn1/src/asn1rt_per_bin.erl
deleted file mode 100644
index 5772f09bf4..0000000000
--- a/lib/asn1/src/asn1rt_per_bin.erl
+++ /dev/null
@@ -1,2285 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2012. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(asn1rt_per_bin).
-%% encoding / decoding of PER aligned
-
--include("asn1_records.hrl").
-
--export([dec_fixup/3, cindex/3, list_to_record/2]).
--export([setchoiceext/1, setext/1, fixoptionals/2, fixoptionals/3,
- fixextensions/2,
- getext/1, getextension/2, skipextensions/3, getbit/1, getchoice/3 ]).
--export([getoptionals/2, getoptionals2/2, set_choice/3, encode_integer/2, encode_integer/3 ]).
--export([decode_integer/2, decode_integer/3, encode_small_number/1, encode_boolean/1,
- decode_boolean/1, encode_length/2, decode_length/1, decode_length/2,
- encode_small_length/1, decode_small_length/1,
- decode_compact_bit_string/3]).
--export([decode_enumerated/3,
- encode_bit_string/3, decode_bit_string/3 ]).
--export([encode_octet_string/2, decode_octet_string/2,
- encode_null/1, decode_null/1,
- encode_object_identifier/1, decode_object_identifier/1,
- encode_real/1, decode_real/1,
- encode_relative_oid/1, decode_relative_oid/1,
- complete/1]).
-
-
--export([encode_open_type/2, decode_open_type/2]).
-
--export([encode_UniversalString/2, decode_UniversalString/2,
- encode_PrintableString/2, decode_PrintableString/2,
- encode_GeneralString/2, decode_GeneralString/2,
- encode_GraphicString/2, decode_GraphicString/2,
- encode_TeletexString/2, decode_TeletexString/2,
- encode_VideotexString/2, decode_VideotexString/2,
- encode_VisibleString/2, decode_VisibleString/2,
- encode_UTF8String/1, decode_UTF8String/1,
- encode_BMPString/2, decode_BMPString/2,
- encode_IA5String/2, decode_IA5String/2,
- encode_NumericString/2, decode_NumericString/2,
- encode_ObjectDescriptor/2, decode_ObjectDescriptor/1
- ]).
--export([complete_bytes/1, getbits/2, getoctets/2, minimum_bits/1]).
-
--define('16K',16384).
--define('32K',32768).
--define('64K',65536).
-
-dec_fixup(Terms,Cnames,RemBytes) ->
- dec_fixup(Terms,Cnames,RemBytes,[]).
-
-dec_fixup([novalue|T],[_Hc|Tc],RemBytes,Acc) ->
- dec_fixup(T,Tc,RemBytes,Acc);
-dec_fixup([{_Name,novalue}|T],[_Hc|Tc],RemBytes,Acc) ->
- dec_fixup(T,Tc,RemBytes,Acc);
-dec_fixup([H|T],[Hc|Tc],RemBytes,Acc) ->
- dec_fixup(T,Tc,RemBytes,[{Hc,H}|Acc]);
-dec_fixup([],_Cnames,RemBytes,Acc) ->
- {lists:reverse(Acc),RemBytes}.
-
-cindex(Ix,Val,Cname) ->
- case element(Ix,Val) of
- {Cname,Val2} -> Val2;
- X -> X
- end.
-
-%% converts a list to a record if necessary
-list_to_record(_Name,Tuple) when is_tuple(Tuple) ->
- Tuple;
-list_to_record(Name,List) when is_list(List) ->
- list_to_tuple([Name|List]).
-
-%%--------------------------------------------------------
-%% setchoiceext(InRootSet) -> [{bit,X}]
-%% X is set to 1 when InRootSet==false
-%% X is set to 0 when InRootSet==true
-%%
-setchoiceext(true) ->
- [{debug,choiceext},{bits,1,0}];
-setchoiceext(false) ->
- [{debug,choiceext},{bits,1,1}].
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% setext(true|false) -> CompleteList
-%%
-
-setext(false) ->
- [{debug,ext},{bits,1,0}];
-setext(true) ->
- [{debug,ext},{bits,1,1}].
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% This version of fixoptionals/2 are left only because of
-%% backward compatibility with older generates
-
-fixoptionals(OptList,Val) when is_tuple(Val) ->
- fixoptionals1(OptList,Val,[]);
-
-fixoptionals(OptList,Val) when is_list(Val) ->
- fixoptionals1(OptList,Val,1,[],[]).
-
-fixoptionals1([],Val,Acc) ->
- %% return {Val,Opt}
- {Val,lists:reverse(Acc)};
-fixoptionals1([{_,Pos}|Ot],Val,Acc) ->
- case element(Pos+1,Val) of
- asn1_NOVALUE -> fixoptionals1(Ot,Val,[0|Acc]);
- asn1_DEFAULT -> fixoptionals1(Ot,Val,[0|Acc]);
- _ -> fixoptionals1(Ot,Val,[1|Acc])
- end.
-
-
-fixoptionals1([{Name,Pos}|Ot],[{Name,Val}|Vt],_Opt,Acc1,Acc2) ->
- fixoptionals1(Ot,Vt,Pos+1,[1|Acc1],[{Name,Val}|Acc2]);
-fixoptionals1([{_Name,Pos}|Ot],V,Pos,Acc1,Acc2) ->
- fixoptionals1(Ot,V,Pos+1,[0|Acc1],[asn1_NOVALUE|Acc2]);
-fixoptionals1(O,[Vh|Vt],Pos,Acc1,Acc2) ->
- fixoptionals1(O,Vt,Pos+1,Acc1,[Vh|Acc2]);
-fixoptionals1([],[Vh|Vt],Pos,Acc1,Acc2) ->
- fixoptionals1([],Vt,Pos+1,Acc1,[Vh|Acc2]);
-fixoptionals1([],[],_,Acc1,Acc2) ->
- % return {Val,Opt}
- {list_to_tuple([asn1_RECORDNAME|lists:reverse(Acc2)]),lists:reverse(Acc1)}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% This is the new fixoptionals/3 which is used by the new generates
-%%
-fixoptionals(OptList,OptLength,Val) when is_tuple(Val) ->
- Bits = fixoptionals(OptList,Val,0),
- {Val,{bits,OptLength,Bits}};
-
-fixoptionals([],_Val,Acc) ->
- %% Optbits
- Acc;
-fixoptionals([{Pos,DefVal}|Ot],Val,Acc) ->
- case element(Pos,Val) of
- asn1_DEFAULT -> fixoptionals(Ot,Val,Acc bsl 1);
- DefVal -> fixoptionals(Ot,Val,Acc bsl 1);
- _ -> fixoptionals(Ot,Val,(Acc bsl 1) + 1)
- end;
-fixoptionals([Pos|Ot],Val,Acc) ->
- case element(Pos,Val) of
- asn1_NOVALUE -> fixoptionals(Ot,Val,Acc bsl 1);
- asn1_DEFAULT -> fixoptionals(Ot,Val,Acc bsl 1);
- _ -> fixoptionals(Ot,Val,(Acc bsl 1) + 1)
- end.
-
-
-getext(Bytes) when is_tuple(Bytes) ->
- getbit(Bytes);
-getext(Bytes) when is_binary(Bytes) ->
- getbit({0,Bytes}).
-
-getextension(0, Bytes) ->
- {{},Bytes};
-getextension(1, Bytes) ->
- {Len,Bytes2} = decode_small_length(Bytes),
- {Blist, Bytes3} = getbits_as_list(Len,Bytes2),
- {list_to_tuple(Blist),Bytes3}.
-
-fixextensions({ext,ExtPos,ExtNum},Val) ->
- case fixextensions(ExtPos,ExtNum+ExtPos,Val,0) of
- 0 -> [];
- ExtBits ->
- [encode_small_length(ExtNum),{bits,ExtNum,ExtBits}]
- end.
-
-fixextensions(Pos,MaxPos,_,Acc) when Pos >= MaxPos ->
- Acc;
-fixextensions(Pos,ExtPos,Val,Acc) ->
- Bit = case catch(element(Pos+1,Val)) of
- asn1_NOVALUE ->
- 0;
- asn1_NOEXTVALUE ->
- 0;
- {'EXIT',_} ->
- 0;
- _ ->
- 1
- end,
- fixextensions(Pos+1,ExtPos,Val,(Acc bsl 1)+Bit).
-
-skipextensions(Bytes,Nr,ExtensionBitPattern) ->
- case (catch element(Nr,ExtensionBitPattern)) of
- 1 ->
- {_,Bytes2} = decode_open_type(Bytes,[]),
- skipextensions(Bytes2, Nr+1, ExtensionBitPattern);
- 0 ->
- skipextensions(Bytes, Nr+1, ExtensionBitPattern);
- {'EXIT',_} -> % badarg, no more extensions
- Bytes
- end.
-
-
-getchoice(Bytes,1,0) -> % only 1 alternative is not encoded
- {0,Bytes};
-getchoice(Bytes,_,1) ->
- decode_small_number(Bytes);
-getchoice(Bytes,NumChoices,0) ->
- decode_constrained_number(Bytes,{0,NumChoices-1}).
-
-%% old version kept for backward compatibility with generates from R7B
-getoptionals(Bytes,NumOpt) ->
- {Blist,Bytes1} = getbits_as_list(NumOpt,Bytes),
- {list_to_tuple(Blist),Bytes1}.
-
-%% new version used in generates from r8b_patch/3 and later
-getoptionals2(Bytes,NumOpt) ->
- getbits(Bytes,NumOpt).
-
-
-%% getbits_as_binary(Num,Bytes) -> {{Unused,BinBits},RestBytes},
-%% Num = integer(),
-%% Bytes = list() | tuple(),
-%% Unused = integer(),
-%% BinBits = binary(),
-%% RestBytes = tuple()
-getbits_as_binary(Num,Bytes) when is_binary(Bytes) ->
- getbits_as_binary(Num,{0,Bytes});
-getbits_as_binary(0,Buffer) ->
- {{0,<<>>},Buffer};
-getbits_as_binary(Num,{0,Bin}) when Num > 16 ->
- Used = Num rem 8,
- Pad = (8 - Used) rem 8,
-% Nbytes = Num div 8,
- <<Bits:Num,_:Pad,RestBin/binary>> = Bin,
- {{Pad,<<Bits:Num,0:Pad>>},RestBin};
-getbits_as_binary(Num,Buffer={_Used,_Bin}) -> % Unaligned buffer
- %% Num =< 16,
- {Bits2,Buffer2} = getbits(Buffer,Num),
- Pad = (8 - (Num rem 8)) rem 8,
- {{Pad,<<Bits2:Num,0:Pad>>},Buffer2}.
-
-
-% integer_from_list(Int,[],BigInt) ->
-% BigInt;
-% integer_from_list(Int,[H|T],BigInt) when Int < 8 ->
-% (BigInt bsl Int) bor (H bsr (8-Int));
-% integer_from_list(Int,[H|T],BigInt) ->
-% integer_from_list(Int-8,T,(BigInt bsl 8) bor H).
-
-getbits_as_list(Num,Bytes) when is_binary(Bytes) ->
- getbits_as_list(Num,{0,Bytes},[]);
-getbits_as_list(Num,Bytes) ->
- getbits_as_list(Num,Bytes,[]).
-
-%% If buffer is empty and nothing more will be picked.
-getbits_as_list(0, B, Acc) ->
- {lists:reverse(Acc),B};
-%% If first byte in buffer is full and at least one byte will be picked,
-%% then pick one byte.
-getbits_as_list(N,{0,Bin},Acc) when N >= 8 ->
- <<B7:1,B6:1,B5:1,B4:1,B3:1,B2:1,B1:1,B0:1,Rest/binary>> = Bin,
- getbits_as_list(N-8,{0,Rest},[B0,B1,B2,B3,B4,B5,B6,B7|Acc]);
-getbits_as_list(N,{Used,Bin},Acc) when N >= 4, Used =< 4 ->
- NewUsed = Used + 4,
- Rem = 8 - NewUsed,
- <<_:Used,B3:1,B2:1,B1:1,B0:1,_:Rem, Rest/binary>> = Bin,
- NewRest = case Rem of 0 -> Rest; _ -> Bin end,
- getbits_as_list(N-4,{NewUsed rem 8,NewRest},[B0,B1,B2,B3|Acc]);
-getbits_as_list(N,{Used,Bin},Acc) when N >= 2, Used =< 6 ->
- NewUsed = Used + 2,
- Rem = 8 - NewUsed,
- <<_:Used,B1:1,B0:1,_:Rem, Rest/binary>> = Bin,
- NewRest = case Rem of 0 -> Rest; _ -> Bin end,
- getbits_as_list(N-2,{NewUsed rem 8,NewRest},[B0,B1|Acc]);
-getbits_as_list(N,{Used,Bin},Acc) when Used =< 7 ->
- NewUsed = Used + 1,
- Rem = 8 - NewUsed,
- <<_:Used,B0:1,_:Rem, Rest/binary>> = Bin,
- NewRest = case Rem of 0 -> Rest; _ -> Bin end,
- getbits_as_list(N-1,{NewUsed rem 8,NewRest},[B0|Acc]).
-
-
-getbit({7,<<_:7,B:1,Rest/binary>>}) ->
- {B,{0,Rest}};
-getbit({0,Buffer = <<B:1,_:7,_/binary>>}) ->
- {B,{1,Buffer}};
-getbit({Used,Buffer}) ->
- Unused = (8 - Used) - 1,
- <<_:Used,B:1,_:Unused,_/binary>> = Buffer,
- {B,{Used+1,Buffer}};
-getbit(Buffer) when is_binary(Buffer) ->
- getbit({0,Buffer}).
-
-
-getbits({0,Buffer},Num) when (Num rem 8) == 0 ->
- <<Bits:Num,Rest/binary>> = Buffer,
- {Bits,{0,Rest}};
-getbits({Used,Bin},Num) ->
- NumPlusUsed = Num + Used,
- NewUsed = NumPlusUsed rem 8,
- Unused = (8-NewUsed) rem 8,
- case Unused of
- 0 ->
- <<_:Used,Bits:Num,Rest/binary>> = Bin,
- {Bits,{0,Rest}};
- _ ->
- Bytes = NumPlusUsed div 8,
- <<_:Used,Bits:Num,_UBits:Unused,_/binary>> = Bin,
- <<_:Bytes/binary,Rest/binary>> = Bin,
- {Bits,{NewUsed,Rest}}
- end;
-getbits(Bin,Num) when is_binary(Bin) ->
- getbits({0,Bin},Num).
-
-
-
-% getoctet(Bytes) when is_list(Bytes) ->
-% getoctet({0,Bytes});
-% getoctet(Bytes) ->
-% %% io:format("getoctet:Buffer = ~p~n",[Bytes]),
-% getoctet1(Bytes).
-
-% getoctet1({0,[H|T]}) ->
-% {H,{0,T}};
-% getoctet1({Pos,[_,H|T]}) ->
-% {H,{0,T}}.
-
-align({0,L}) ->
- {0,L};
-align({_Pos,<<_H,T/binary>>}) ->
- {0,T};
-align(Bytes) ->
- {0,Bytes}.
-
-%% First align buffer, then pick the first Num octets.
-%% Returns octets as an integer with bit significance as in buffer.
-getoctets({0,Buffer},Num) ->
- <<Val:Num/integer-unit:8,RestBin/binary>> = Buffer,
- {Val,{0,RestBin}};
-getoctets({U,<<_Padding,Rest/binary>>},Num) when U /= 0 ->
- getoctets({0,Rest},Num);
-getoctets(Buffer,Num) when is_binary(Buffer) ->
- getoctets({0,Buffer},Num).
-% getoctets(Buffer,Num) ->
-% %% io:format("getoctets:Buffer = ~p~nNum = ~p~n",[Buffer,Num]),
-% getoctets(Buffer,Num,0).
-
-% getoctets(Buffer,0,Acc) ->
-% {Acc,Buffer};
-% getoctets(Buffer,Num,Acc) ->
-% {Oct,NewBuffer} = getoctet(Buffer),
-% getoctets(NewBuffer,Num-1,(Acc bsl 8)+Oct).
-
-% getoctets_as_list(Buffer,Num) ->
-% getoctets_as_list(Buffer,Num,[]).
-
-% getoctets_as_list(Buffer,0,Acc) ->
-% {lists:reverse(Acc),Buffer};
-% getoctets_as_list(Buffer,Num,Acc) ->
-% {Oct,NewBuffer} = getoctet(Buffer),
-% getoctets_as_list(NewBuffer,Num-1,[Oct|Acc]).
-
-%% First align buffer, then pick the first Num octets.
-%% Returns octets as a binary
-getoctets_as_bin({0,Bin},Num)->
- <<Octets:Num/binary,RestBin/binary>> = Bin,
- {Octets,{0,RestBin}};
-getoctets_as_bin({_U,Bin},Num) ->
- <<_Padding,Octets:Num/binary,RestBin/binary>> = Bin,
- {Octets,{0,RestBin}};
-getoctets_as_bin(Bin,Num) when is_binary(Bin) ->
- getoctets_as_bin({0,Bin},Num).
-
-%% same as above but returns octets as a List
-getoctets_as_list(Buffer,Num) ->
- {Bin,Buffer2} = getoctets_as_bin(Buffer,Num),
- {binary_to_list(Bin),Buffer2}.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% set_choice(Alt,Choices,Altnum) -> ListofBitSettings
-%% Alt = atom()
-%% Altnum = integer() | {integer(),integer()}% number of alternatives
-%% Choices = [atom()] | {[atom()],[atom()]}
-%% When Choices is a tuple the first list is the Rootset and the
-%% second is the Extensions and then Altnum must also be a tuple with the
-%% lengths of the 2 lists
-%%
-set_choice(Alt,{L1,L2},{Len1,_Len2}) ->
- case set_choice_tag(Alt,L1) of
- N when is_integer(N), Len1 > 1 ->
- [{bits,1,0}, % the value is in the root set
- encode_integer([{'ValueRange',{0,Len1-1}}],N)];
- N when is_integer(N) ->
- [{bits,1,0}]; % no encoding if only 0 or 1 alternative
- false ->
- [{bits,1,1}, % extension value
- case set_choice_tag(Alt,L2) of
- N2 when is_integer(N2) ->
- encode_small_number(N2);
- false ->
- unknown_choice_alt
- end]
- end;
-set_choice(Alt,L,Len) ->
- case set_choice_tag(Alt,L) of
- N when is_integer(N), Len > 1 ->
- encode_integer([{'ValueRange',{0,Len-1}}],N);
- N when is_integer(N) ->
- []; % no encoding if only 0 or 1 alternative
- false ->
- [unknown_choice_alt]
- end.
-
-set_choice_tag(Alt,Choices) ->
- set_choice_tag(Alt,Choices,0).
-
-set_choice_tag(Alt,[Alt|_Rest],Tag) ->
- Tag;
-set_choice_tag(Alt,[_H|Rest],Tag) ->
- set_choice_tag(Alt,Rest,Tag+1);
-set_choice_tag(_Alt,[],_Tag) ->
- false.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% decode_fragmented_XXX; decode of values encoded fragmented according
-%% to ITU-T X.691 clause 10.9.3.8. The unit (XXX) is either bits, octets,
-%% characters or number of components (in a choice,sequence or similar).
-%% Buffer is a buffer {Used, Bin}.
-%% C is the constrained length.
-%% If the buffer is not aligned, this function does that.
-decode_fragmented_bits({0,Buffer},C) ->
- decode_fragmented_bits(Buffer,C,[]);
-decode_fragmented_bits({_N,<<_,Bs/binary>>},C) ->
- decode_fragmented_bits(Bs,C,[]).
-
-decode_fragmented_bits(<<3:2,Len:6,Bin/binary>>,C,Acc) ->
- {Value,Bin2} = split_binary(Bin, Len * ?'16K'),
- decode_fragmented_bits(Bin2,C,[Value,Acc]);
-decode_fragmented_bits(<<0:1,0:7,Bin/binary>>,C,Acc) ->
- BinBits = list_to_binary(lists:reverse(Acc)),
- case C of
- Int when is_integer(Int),C == size(BinBits) ->
- {BinBits,{0,Bin}};
- Int when is_integer(Int) ->
- exit({error,{asn1,{illegal_value,C,BinBits}}})
- end;
-decode_fragmented_bits(<<0:1,Len:7,Bin/binary>>,C,Acc) ->
- Result = {BinBits,{Used,_Rest}} =
- case (Len rem 8) of
- 0 ->
- <<Value:Len/binary-unit:1,Bin2/binary>> = Bin,
- {list_to_binary(lists:reverse([Value|Acc])),{0,Bin2}};
- Rem ->
- Bytes = Len div 8,
- U = 8 - Rem,
- <<Value:Bytes/binary-unit:8,Bits1:Rem,Bits2:U,Bin2/binary>> = Bin,
- {list_to_binary(lists:reverse([Bits1 bsl U,Value|Acc])),
- {Rem,<<Bits2,Bin2/binary>>}}
- end,
- case C of
- Int when is_integer(Int),C == (size(BinBits) - ((8 - Used) rem 8)) ->
- Result;
- Int when is_integer(Int) ->
- exit({error,{asn1,{illegal_value,C,BinBits}}})
- end.
-
-
-decode_fragmented_octets({0,Bin},C) ->
- decode_fragmented_octets(Bin,C,[]).
-
-decode_fragmented_octets(<<3:2,Len:6,Bin/binary>>,C,Acc) ->
- {Value,Bin2} = split_binary(Bin,Len * ?'16K'),
- decode_fragmented_octets(Bin2,C,[Value,Acc]);
-decode_fragmented_octets(<<0:1,0:7,Bin/binary>>,C,Acc) ->
- Octets = list_to_binary(lists:reverse(Acc)),
- case C of
- Int when is_integer(Int), C == size(Octets) ->
- {Octets,{0,Bin}};
- Int when is_integer(Int) ->
- exit({error,{asn1,{illegal_value,C,Octets}}})
- end;
-decode_fragmented_octets(<<0:1,Len:7,Bin/binary>>,C,Acc) ->
- <<Value:Len/binary-unit:8,Bin2/binary>> = Bin,
- BinOctets = list_to_binary(lists:reverse([Value|Acc])),
- case C of
- Int when is_integer(Int),size(BinOctets) == Int ->
- {BinOctets,Bin2};
- Int when is_integer(Int) ->
- exit({error,{asn1,{illegal_value,C,BinOctets}}})
- end.
-
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% encode_open_type(Constraint, Value) -> CompleteList
-%% Value = list of bytes of an already encoded value (the list must be flat)
-%% | binary
-%% Contraint = not used in this version
-%%
-encode_open_type(_C, Val) when is_list(Val) ->
- Bin = list_to_binary(Val),
- [encode_length(undefined,size(Bin)),{octets,Bin}]; % octets implies align
-encode_open_type(_C, Val) when is_binary(Val) ->
- [encode_length(undefined,size(Val)),{octets,Val}]. % octets implies align
-%% the binary_to_list is not optimal but compatible with the current solution
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% decode_open_type(Buffer,Constraint) -> Value
-%% Constraint is not used in this version
-%% Buffer = [byte] with PER encoded data
-%% Value = [byte] with decoded data (which must be decoded again as some type)
-%%
-decode_open_type(Bytes, _C) ->
- {Len,Bytes2} = decode_length(Bytes,undefined),
- getoctets_as_bin(Bytes2,Len).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% encode_integer(Constraint,Value,NamedNumberList) -> CompleteList
-%% encode_integer(Constraint,Value) -> CompleteList
-%% encode_integer(Constraint,{Name,Value}) -> CompleteList
-%%
-%%
-encode_integer(C,V,NamedNumberList) when is_atom(V) ->
- case lists:keysearch(V,1,NamedNumberList) of
- {value,{_,NewV}} ->
- encode_integer(C,NewV);
- _ ->
- exit({error,{asn1,{namednumber,V}}})
- end;
-encode_integer(C,V,_NamedNumberList) when is_integer(V) ->
- encode_integer(C,V);
-encode_integer(C,{Name,V},NamedNumberList) when is_atom(Name) ->
- encode_integer(C,V,NamedNumberList).
-
-encode_integer(C,{Name,Val}) when is_atom(Name) ->
- encode_integer(C,Val);
-
-encode_integer([{Rc,_Ec}],Val) when is_tuple(Rc) -> % XXX when is this invoked? First argument most often a list,...Ok this is the extension case...but it doesn't work.
- case (catch encode_integer([Rc],Val)) of
- {'EXIT',{error,{asn1,_}}} ->
- [{bits,1,1},encode_unconstrained_number(Val)];
- Encoded ->
- [{bits,1,0},Encoded]
- end;
-encode_integer(C,Val ) when is_list(C) ->
- case get_constraint(C,'SingleValue') of
- no ->
- encode_integer1(C,Val);
- V when is_integer(V),V == Val ->
- []; % a type restricted to a single value encodes to nothing
- V when is_list(V) ->
- case lists:member(Val,V) of
- true ->
- encode_integer1(C,Val);
- _ ->
- exit({error,{asn1,{illegal_value,Val}}})
- end;
- _ ->
- exit({error,{asn1,{illegal_value,Val}}})
- end.
-
-encode_integer1(C, Val) ->
- case VR = get_constraint(C,'ValueRange') of
- no ->
- encode_unconstrained_number(Val);
- {Lb,'MAX'} ->
- encode_semi_constrained_number(Lb,Val);
- %% positive with range
- {Lb,Ub} when Val >= Lb,
- Ub >= Val ->
- encode_constrained_number(VR,Val);
- _ ->
- exit({error,{asn1,{illegal_value,VR,Val}}})
- end.
-
-decode_integer(Buffer,Range,NamedNumberList) ->
- {Val,Buffer2} = decode_integer(Buffer,Range),
- case lists:keysearch(Val,2,NamedNumberList) of
- {value,{NewVal,_}} -> {NewVal,Buffer2};
- _ -> {Val,Buffer2}
- end.
-
-decode_integer(Buffer,[{Rc,_Ec}]) when is_tuple(Rc) ->
- {Ext,Buffer2} = getext(Buffer),
- case Ext of
- 0 -> decode_integer(Buffer2,[Rc]);
- 1 -> decode_unconstrained_number(Buffer2)
- end;
-decode_integer(Buffer,undefined) ->
- decode_unconstrained_number(Buffer);
-decode_integer(Buffer,C) ->
- case get_constraint(C,'SingleValue') of
- V when is_integer(V) ->
- {V,Buffer};
- V when is_list(V) ->
- {Val,Buffer2} = decode_integer1(Buffer,C),
- case lists:member(Val,V) of
- true ->
- {Val,Buffer2};
- _ ->
- exit({error,{asn1,{illegal_value,Val}}})
- end;
- _ ->
- decode_integer1(Buffer,C)
- end.
-
-decode_integer1(Buffer,C) ->
- case VR = get_constraint(C,'ValueRange') of
- no ->
- decode_unconstrained_number(Buffer);
- {Lb, 'MAX'} ->
- decode_semi_constrained_number(Buffer,Lb);
- {_,_} ->
- decode_constrained_number(Buffer,VR)
- end.
-
- % X.691:10.6 Encoding of a normally small non-negative whole number
- % Use this for encoding of CHOICE index if there is an extension marker in
- % the CHOICE
-encode_small_number({Name,Val}) when is_atom(Name) ->
- encode_small_number(Val);
-encode_small_number(Val) when Val =< 63 ->
-% [{bits,1,0},{bits,6,Val}];
- [{bits,7,Val}]; % same as above but more efficient
-encode_small_number(Val) ->
- [{bits,1,1},encode_semi_constrained_number(0,Val)].
-
-decode_small_number(Bytes) ->
- {Bit,Bytes2} = getbit(Bytes),
- case Bit of
- 0 ->
- getbits(Bytes2,6);
- 1 ->
- decode_semi_constrained_number(Bytes2,0)
- end.
-
-%% X.691:10.7 Encoding of a semi-constrained whole number
-%% might be an optimization encode_semi_constrained_number(0,Val) ->
-encode_semi_constrained_number(C,{Name,Val}) when is_atom(Name) ->
- encode_semi_constrained_number(C,Val);
-encode_semi_constrained_number({Lb,'MAX'},Val) ->
- encode_semi_constrained_number(Lb,Val);
-encode_semi_constrained_number(Lb,Val) ->
- Val2 = Val - Lb,
- Oct = eint_positive(Val2),
- Len = length(Oct),
- if
- Len < 128 ->
- {octets,[Len|Oct]}; % equiv with encode_length(undefined,Len) but faster
- true ->
- [encode_length(undefined,Len),{octets,Oct}]
- end.
-
-decode_semi_constrained_number(Bytes,{Lb,_}) ->
- decode_semi_constrained_number(Bytes,Lb);
-decode_semi_constrained_number(Bytes,Lb) ->
- {Len,Bytes2} = decode_length(Bytes,undefined),
- {V,Bytes3} = getoctets(Bytes2,Len),
- {V+Lb,Bytes3}.
-
-encode_constrained_number(Range,{Name,Val}) when is_atom(Name) ->
- encode_constrained_number(Range,Val);
-encode_constrained_number({Lb,Ub},Val) when Val >= Lb, Ub >= Val ->
- Range = Ub - Lb + 1,
- Val2 = Val - Lb,
- if
- Range == 1 ->
- [];
- Range == 2 ->
- {bits,1,Val2};
- Range =< 4 ->
- {bits,2,Val2};
- Range =< 8 ->
- {bits,3,Val2};
- Range =< 16 ->
- {bits,4,Val2};
- Range =< 32 ->
- {bits,5,Val2};
- Range =< 64 ->
- {bits,6,Val2};
- Range =< 128 ->
- {bits,7,Val2};
- Range =< 255 ->
- {bits,8,Val2};
- Range =< 256 ->
- {octets,[Val2]};
- Range =< 65536 ->
- {octets,<<Val2:16>>};
- Range =< (1 bsl (255*8)) ->
- Octs = binary:encode_unsigned(Val2),
- RangeOcts = binary:encode_unsigned(Range - 1),
- OctsLen = erlang:byte_size(Octs),
- RangeOctsLen = erlang:byte_size(RangeOcts),
- LengthBitsNeeded = minimum_bits(RangeOctsLen - 1),
- [{bits, LengthBitsNeeded, OctsLen - 1}, {octets, Octs}];
- true ->
- exit({not_supported,{integer_range,Range}})
- end;
-encode_constrained_number(Range,Val) ->
- exit({error,{asn1,{integer_range,Range,value,Val}}}).
-
-%% For some reason the minimum bits needed in the length field in encoding of
-%% constrained whole numbers must always be atleast 2?
-minimum_bits(N) when N < 4 -> 2;
-minimum_bits(N) when N < 8 -> 3;
-minimum_bits(N) when N < 16 -> 4;
-minimum_bits(N) when N < 32 -> 5;
-minimum_bits(N) when N < 64 -> 6;
-minimum_bits(N) when N < 128 -> 7;
-minimum_bits(_N) -> 8.
-
-decode_constrained_number(Buffer,{Lb,Ub}) ->
- Range = Ub - Lb + 1,
- % Val2 = Val - Lb,
- {Val,Remain} =
- if
- Range == 1 ->
- {0,Buffer};
- Range == 2 ->
- getbits(Buffer,1);
- Range =< 4 ->
- getbits(Buffer,2);
- Range =< 8 ->
- getbits(Buffer,3);
- Range =< 16 ->
- getbits(Buffer,4);
- Range =< 32 ->
- getbits(Buffer,5);
- Range =< 64 ->
- getbits(Buffer,6);
- Range =< 128 ->
- getbits(Buffer,7);
- Range =< 255 ->
- getbits(Buffer,8);
- Range =< 256 ->
- getoctets(Buffer,1);
- Range =< 65536 ->
- getoctets(Buffer,2);
- Range =< (1 bsl (255*8)) ->
- OList = binary:bin_to_list(binary:encode_unsigned(Range - 1)),
- RangeOctLen = length(OList),
- {Len, Bytes} = decode_length(Buffer, {1, RangeOctLen}),
- {Octs, RestBytes} = getoctets_as_list(Bytes, Len),
- {binary:decode_unsigned(binary:list_to_bin(Octs)), RestBytes};
- true ->
- exit({not_supported,{integer_range,Range}})
- end,
- {Val+Lb,Remain}.
-
-%% X.691:10.8 Encoding of an unconstrained whole number
-
-encode_unconstrained_number(Val) when Val >= 0 ->
- Oct = eint(Val,[]),
- Len = length(Oct),
- if
- Len < 128 ->
- {octets,[Len|Oct]}; % equiv with encode_length(undefined,Len) but faster
- true ->
- [encode_length(undefined,Len),{octets,Oct}]
- end;
-encode_unconstrained_number(Val) -> % negative
- Oct = enint(Val,[]),
- Len = length(Oct),
- if
- Len < 128 ->
- {octets,[Len|Oct]}; % equiv with encode_length(undefined,Len) but faster
- true ->
- [encode_length(undefined,Len),{octets,Oct}]
- end.
-
-
-%% used for positive Values which don't need a sign bit
-%% returns a binary
-eint_positive(Val) ->
- case eint(Val,[]) of
- [0,B1|T] ->
- [B1|T];
- T ->
- T
- end.
-
-
-eint(0, [B|Acc]) when B < 128 ->
- [B|Acc];
-eint(N, Acc) ->
- eint(N bsr 8, [N band 16#ff| Acc]).
-
-enint(-1, [B1|T]) when B1 > 127 ->
- [B1|T];
-enint(N, Acc) ->
- enint(N bsr 8, [N band 16#ff|Acc]).
-
-decode_unconstrained_number(Bytes) ->
- {Len,Bytes2} = decode_length(Bytes,undefined),
- {Ints,Bytes3} = getoctets_as_list(Bytes2,Len),
- {dec_integer(Ints),Bytes3}.
-
-dec_integer(Ints) when hd(Ints) band 255 =< 127 -> %% Positive number
- decpint(Ints, 8 * (length(Ints) - 1));
-dec_integer(Ints) -> %% Negative
- decnint(Ints, 8 * (length(Ints) - 1)).
-
-decpint([Byte|Tail], Shift) ->
- (Byte bsl Shift) bor decpint(Tail, Shift-8);
-decpint([], _) -> 0.
-
-decnint([Byte|Tail], Shift) ->
- (-128 + (Byte band 127) bsl Shift) bor decpint(Tail, Shift-8).
-
-% minimum_octets(Val) ->
-% minimum_octets(Val,[]).
-
-% minimum_octets(Val,Acc) when Val > 0 ->
-% minimum_octets((Val bsr 8),[Val band 16#FF|Acc]);
-% minimum_octets(0,Acc) ->
-% Acc.
-
-
-%% X.691:10.9 Encoding of a length determinant
-%%encode_small_length(undefined,Len) -> % null means no UpperBound
-%% encode_small_number(Len).
-
-%% X.691:10.9.3.5
-%% X.691:10.9.3.7
-encode_length(undefined,Len) -> % un-constrained
- if
- Len < 128 ->
- {octets,[Len]};
- Len < 16384 ->
- {octets,<<2:2,Len:14>>};
- true -> % should be able to endode length >= 16384
- exit({error,{asn1,{encode_length,{nyi,above_16k}}}})
- end;
-
-encode_length({0,'MAX'},Len) ->
- encode_length(undefined,Len);
-encode_length(Vr={Lb,Ub},Len) when Ub =< 65535 ,Lb >= 0 -> % constrained
- encode_constrained_number(Vr,Len);
-encode_length({Lb,_Ub},Len) when is_integer(Lb), Lb >= 0 -> % Ub > 65535
- encode_length(undefined,Len);
-encode_length({Vr={Lb,Ub},Ext},Len)
- when Ub =< 65535 ,Lb >= 0, Len=<Ub, is_list(Ext) ->
- %% constrained extensible
- [{bits,1,0},encode_constrained_number(Vr,Len)];
-encode_length({{Lb,_Ub},Ext},Len) when is_list(Ext) ->
- [{bits,1,1},encode_semi_constrained_number(Lb,Len)];
-encode_length(SingleValue,_Len) when is_integer(SingleValue) ->
- [].
-
-%% X.691 10.9.3.4 (only used for length of bitmap that prefixes extension
-%% additions in a sequence or set
-encode_small_length(Len) when Len =< 64 ->
-%% [{bits,1,0},{bits,6,Len-1}];
- {bits,7,Len-1}; % the same as above but more efficient
-encode_small_length(Len) ->
- [{bits,1,1},encode_length(undefined,Len)].
-
-% decode_small_length({Used,<<_:Used,0:1,Num:6,_:((8-Used+1) rem 8),Rest/binary>>}) ->
-% case Buffer of
-% <<_:Used,0:1,Num:6,_:((8-Used+1) rem 8),Rest/binary>> ->
-% {Num,
-% case getbit(Buffer) of
-% {0,Remain} ->
-% {Bits,Remain2} = getbits(Remain,6),
-% {Bits+1,Remain2};
-% {1,Remain} ->
-% decode_length(Remain,undefined)
-% end.
-
-decode_small_length(Buffer) ->
- case getbit(Buffer) of
- {0,Remain} ->
- {Bits,Remain2} = getbits(Remain,6),
- {Bits+1,Remain2};
- {1,Remain} ->
- decode_length(Remain,undefined)
- end.
-
-decode_length(Buffer) ->
- decode_length(Buffer,undefined).
-
-decode_length(Buffer,undefined) -> % un-constrained
- {0,Buffer2} = align(Buffer),
- case Buffer2 of
- <<0:1,Oct:7,Rest/binary>> ->
- {Oct,{0,Rest}};
- <<2:2,Val:14,Rest/binary>> ->
- {Val,{0,Rest}};
- <<3:2,_:14,_Rest/binary>> ->
- %% this case should be fixed
- exit({error,{asn1,{decode_length,{nyi,above_16k}}}})
- end;
-%% {Bits,_} = getbits(Buffer2,2),
-% case Bits of
-% 2 ->
-% {Val,Bytes3} = getoctets(Buffer2,2),
-% {(Val band 16#3FFF),Bytes3};
-% 3 ->
-% exit({error,{asn1,{decode_length,{nyi,above_16k}}}});
-% _ ->
-% {Val,Bytes3} = getoctet(Buffer2),
-% {Val band 16#7F,Bytes3}
-% end;
-
-decode_length(Buffer,{Lb,Ub}) when Ub =< 65535 ,Lb >= 0 -> % constrained
- decode_constrained_number(Buffer,{Lb,Ub});
-decode_length(Buffer,{Lb,_}) when is_integer(Lb), Lb >= 0 -> % Ub > 65535
- decode_length(Buffer,undefined);
-decode_length(Buffer,{VR={_Lb,_Ub},Ext}) when is_list(Ext) ->
- case getbit(Buffer) of
- {0,Buffer2} ->
- decode_length(Buffer2, VR);
- {1,Buffer2} ->
- decode_length(Buffer2, undefined)
- end;
-%% {0,Buffer2} = getbit(Buffer),
-%% decode_length(Buffer2, VR);
-
-
-%When does this case occur with {_,_Lb,Ub} ??
-% X.691:10.9.3.5
-decode_length({Used,Bin},{_,_Lb,_Ub}) -> %when Len =< 127 -> % Unconstrained or large Ub NOTE! this case does not cover case when Ub > 65535
- Unused = (8-Used) rem 8,
- case Bin of
- <<_:Used,0:1,Val:7,R:Unused,Rest/binary>> ->
- {Val,{Used,<<R,Rest/binary>>}};
- <<_:Used,_:Unused,2:2,Val:14,Rest/binary>> ->
- {Val, {0,Rest}};
- <<_:Used,_:Unused,3:2,_:14,_Rest/binary>> ->
- exit({error,{asn1,{decode_length,{nyi,length_above_64K}}}})
- end;
-% decode_length(Buffer,{_,_Lb,Ub}) -> %when Len =< 127 -> % Unconstrained or large Ub
-% case getbit(Buffer) of
-% {0,Remain} ->
-% getbits(Remain,7);
-% {1,Remain} ->
-% {Val,Remain2} = getoctets(Buffer,2),
-% {Val band 2#0111111111111111, Remain2}
-% end;
-decode_length(Buffer,SingleValue) when is_integer(SingleValue) ->
- {SingleValue,Buffer}.
-
-
- % X.691:11
-encode_boolean(true) ->
- {bits,1,1};
-encode_boolean(false) ->
- {bits,1,0};
-encode_boolean({Name,Val}) when is_atom(Name) ->
- encode_boolean(Val);
-encode_boolean(Val) ->
- exit({error,{asn1,{encode_boolean,Val}}}).
-
-decode_boolean(Buffer) -> %when record(Buffer,buffer)
- case getbit(Buffer) of
- {1,Remain} -> {true,Remain};
- {0,Remain} -> {false,Remain}
- end.
-
-
-%% ENUMERATED with extension marker
-decode_enumerated(Buffer,C,{Ntup1,Ntup2}) when is_tuple(Ntup1), is_tuple(Ntup2) ->
- {Ext,Buffer2} = getext(Buffer),
- case Ext of
- 0 -> % not an extension value
- {Val,Buffer3} = decode_integer(Buffer2,C),
- case catch (element(Val+1,Ntup1)) of
- NewVal when is_atom(NewVal) -> {NewVal,Buffer3};
- _Error -> exit({error,{asn1,{decode_enumerated,{Val,[Ntup1,Ntup2]}}}})
- end;
- 1 -> % this an extension value
- {Val,Buffer3} = decode_small_number(Buffer2),
- case catch (element(Val+1,Ntup2)) of
- NewVal when is_atom(NewVal) -> {NewVal,Buffer3};
- _ -> {{asn1_enum,Val},Buffer3}
- end
- end;
-
-decode_enumerated(Buffer,C,NamedNumberTup) when is_tuple(NamedNumberTup) ->
- {Val,Buffer2} = decode_integer(Buffer,C),
- case catch (element(Val+1,NamedNumberTup)) of
- NewVal when is_atom(NewVal) -> {NewVal,Buffer2};
- _Error -> exit({error,{asn1,{decode_enumerated,{Val,NamedNumberTup}}}})
- end.
-
-%%===============================================================================
-%%===============================================================================
-%%===============================================================================
-%% Bitstring value, ITU_T X.690 Chapter 8.5
-%%===============================================================================
-%%===============================================================================
-%%===============================================================================
-
-%%===============================================================================
-%% encode bitstring value
-%%===============================================================================
-
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% bitstring NamedBitList
-%% Val can be of:
-%% - [identifiers] where only named identifers are set to one,
-%% the Constraint must then have some information of the
-%% bitlength.
-%% - [list of ones and zeroes] all bits
-%% - integer value representing the bitlist
-%% C is constraint Len, only valid when identifiers
-
-
-%% when the value is a list of {Unused,BinBits}, where
-%% Unused = integer(),
-%% BinBits = binary().
-
-encode_bit_string(C,Bin={Unused,BinBits},NamedBitList) when is_integer(Unused),
- is_binary(BinBits) ->
- encode_bin_bit_string(C,Bin,NamedBitList);
-
-%% when the value is a list of named bits
-encode_bit_string(C, LoNB=[FirstVal | _RestVal], NamedBitList) when is_atom(FirstVal) ->
- ToSetPos = get_all_bitposes(LoNB, NamedBitList, []),
- BitList = make_and_set_list(ToSetPos,0),
- encode_bit_string(C,BitList,NamedBitList);
-
-encode_bit_string(C, BL=[{bit,_No} | _RestVal], NamedBitList) ->
- ToSetPos = get_all_bitposes(BL, NamedBitList, []),
- BitList = make_and_set_list(ToSetPos,0),
- encode_bit_string(C,BitList,NamedBitList);
-
-%% when the value is a list of ones and zeroes
-
-% encode_bit_string(C, BitListValue, NamedBitList) when is_list(BitListValue) ->
-% Bl1 =
-% case NamedBitList of
-% [] -> % dont remove trailing zeroes
-% BitListValue;
-% _ -> % first remove any trailing zeroes
-% lists:reverse(lists:dropwhile(fun(0)->true;(1)->false end,
-% lists:reverse(BitListValue)))
-% end,
-% BitList = [{bit,X} || X <- Bl1],
-% %% BListLen = length(BitList),
-% case get_constraint(C,'SizeConstraint') of
-% 0 -> % fixed length
-% []; % nothing to encode
-% V when is_integer(V),V=<16 -> % fixed length 16 bits or less
-% pad_list(V,BitList);
-% V when is_integer(V) -> % fixed length 16 bits or more
-% [align,pad_list(V,BitList)]; % should be another case for V >= 65537
-% {Lb,Ub} when is_integer(Lb),is_integer(Ub) ->
-% [encode_length({Lb,Ub},length(BitList)),align,BitList];
-% no ->
-% [encode_length(undefined,length(BitList)),align,BitList];
-% Sc -> % extension marker
-% [encode_length(Sc,length(BitList)),align,BitList]
-% end;
-encode_bit_string(C, BitListValue, NamedBitList) when is_list(BitListValue) ->
- BitListToBinary =
- %% fun that transforms a list of 1 and 0 to a tuple:
- %% {UnusedBitsInLastByte, Binary}
- fun([1|T],Acc,N,Fun) ->
- Fun(T,(Acc bsl 1)+1,N+1,Fun);
- ([0|T],Acc,N,Fun) ->
- Fun(T,(Acc bsl 1),N+1,Fun);
- ([_H|_T],_,_,_) ->
- exit({error,{asn1,{bitstring_bitlist,BitListValue}}});
- ([],Acc,N,_) ->
- Unused = (8 - (N rem 8)) rem 8,
- {Unused,<<Acc:N,0:Unused>>}
- end,
- UnusedAndBin =
- case NamedBitList of
- [] -> % dont remove trailing zeroes
- BitListToBinary(BitListValue,0,0,BitListToBinary);
- _ ->
- BitListToBinary(lists:reverse(
- lists:dropwhile(fun(0)->true;(_)->false end,
- lists:reverse(BitListValue))),
- 0,0,BitListToBinary)
- end,
- encode_bin_bit_string(C,UnusedAndBin,NamedBitList);
-
-%% when the value is an integer
-encode_bit_string(C, IntegerVal, NamedBitList) when is_integer(IntegerVal)->
- BitList = int_to_bitlist(IntegerVal),
- encode_bit_string(C,BitList,NamedBitList);
-
-%% when the value is a tuple
-encode_bit_string(C,{Name,Val}, NamedBitList) when is_atom(Name) ->
- encode_bit_string(C,Val,NamedBitList).
-
-
-%% encode_bin_bit_string/3, when value is a tuple of Unused and BinBits.
-%% Unused = integer(),i.e. number unused bits in least sign. byte of
-%% BinBits = binary().
-
-
-encode_bin_bit_string(C,UnusedAndBin={_Unused,_BinBits},NamedBitList) ->
- Constr = get_constraint(C,'SizeConstraint'),
- UnusedAndBin1 = {Unused1,Bin1} =
- remove_trailing_bin(NamedBitList,UnusedAndBin,lower_bound(Constr)),
- case Constr of
- 0 ->
- [];
- V when is_integer(V),V=<16 ->
- {Unused2,Bin2} = pad_list(V,UnusedAndBin1),
- <<BitVal:V,_:Unused2>> = Bin2,
- {bits,V,BitVal};
- V when is_integer(V) ->
- [align, pad_list(V, UnusedAndBin1)];
- {Lb,Ub} when is_integer(Lb),is_integer(Ub) ->
- [encode_length({Lb,Ub},size(Bin1)*8 - Unused1),
- align,UnusedAndBin1];
- {{Fix,Fix},L} when is_integer(Fix),is_list(L) ->
- %% X.691 � 15.6, the rest of this paragraph is covered by
- %% the last, ie. Sc, clause in this case
- case (size(Bin1)*8)-Unused1 of
- Size when Size =< Fix, Fix =< 16 ->
- {Unused2,Bin2} = pad_list(Fix,UnusedAndBin),
- <<BitVal:Fix,_:Unused2>> = Bin2,
- [{bits,1,0},{bits,Fix,BitVal}];
- Size when Size =< Fix ->
- [{bits,1,0},align, pad_list(Fix, UnusedAndBin1)];
- Size ->
- [{bits,1,1},encode_length(undefined,Size),
- align,UnusedAndBin1]
- end;
- no ->
- [encode_length(undefined,size(Bin1)*8 - Unused1),
- align,UnusedAndBin1];
- Sc ->
- [encode_length(Sc,size(Bin1)*8 - Unused1),
- align,UnusedAndBin1]
- end.
-
-
-remove_trailing_bin([], {Unused,Bin},_) ->
- {Unused,Bin};
-remove_trailing_bin(_NamedNumberList,{_Unused,<<>>},C) ->
- case C of
- Int when is_integer(Int),Int > 0 ->
- %% this padding see OTP-4353
- pad_list(Int,{0,<<>>});
- _ -> {0,<<>>}
- end;
-remove_trailing_bin(NamedNumberList, {_Unused,Bin},C) ->
- Size = size(Bin)-1,
- <<Bfront:Size/binary, LastByte:8>> = Bin,
- %% clear the Unused bits to be sure
- Unused1 = trailingZeroesInNibble(LastByte band 15),
- Unused2 =
- case Unused1 of
- 4 ->
- 4 + trailingZeroesInNibble(LastByte bsr 4);
- _ -> Unused1
- end,
- case Unused2 of
- 8 ->
- remove_trailing_bin(NamedNumberList,{0,Bfront},C);
- _ ->
- case C of
- Int when is_integer(Int),Int > ((size(Bin)*8)-Unused2) ->
- %% this padding see OTP-4353
- pad_list(Int,{Unused2,Bin});
- _ -> {Unused2,Bin}
- end
- end.
-
-
-trailingZeroesInNibble(0) ->
- 4;
-trailingZeroesInNibble(1) ->
- 0;
-trailingZeroesInNibble(2) ->
- 1;
-trailingZeroesInNibble(3) ->
- 0;
-trailingZeroesInNibble(4) ->
- 2;
-trailingZeroesInNibble(5) ->
- 0;
-trailingZeroesInNibble(6) ->
- 1;
-trailingZeroesInNibble(7) ->
- 0;
-trailingZeroesInNibble(8) ->
- 3;
-trailingZeroesInNibble(9) ->
- 0;
-trailingZeroesInNibble(10) ->
- 1;
-trailingZeroesInNibble(11) ->
- 0;
-trailingZeroesInNibble(12) -> %#1100
- 2;
-trailingZeroesInNibble(13) ->
- 0;
-trailingZeroesInNibble(14) ->
- 1;
-trailingZeroesInNibble(15) ->
- 0.
-
-lower_bound({{Lb,_},_}) when is_integer(Lb) ->
- Lb;
-lower_bound({Lb,_}) when is_integer(Lb) ->
- Lb;
-lower_bound(C) ->
- C.
-
-%%%%%%%%%%%%%%%
-%% The result is presented as a list of named bits (if possible)
-%% else as a tuple {Unused,Bits}. Unused is the number of unused
-%% bits, least significant bits in the last byte of Bits. Bits is
-%% the BIT STRING represented as a binary.
-%%
-decode_compact_bit_string(Buffer, C, NamedNumberList) ->
- case get_constraint(C,'SizeConstraint') of
- 0 -> % fixed length
- {{8,0},Buffer};
- V when is_integer(V),V=<16 -> %fixed length 16 bits or less
- compact_bit_string(Buffer,V,NamedNumberList);
- V when is_integer(V),V=<65536 -> %fixed length > 16 bits
- Bytes2 = align(Buffer),
- compact_bit_string(Bytes2,V,NamedNumberList);
- V when is_integer(V) -> % V > 65536 => fragmented value
- {Bin,Buffer2} = decode_fragmented_bits(Buffer,V),
- case Buffer2 of
- {0,_} -> {{0,Bin},Buffer2};
- {U,_} -> {{8-U,Bin},Buffer2}
- end;
- {Lb,Ub} when is_integer(Lb),is_integer(Ub) ->
- %% This case may demand decoding of fragmented length/value
- {Len,Bytes2} = decode_length(Buffer,{Lb,Ub}),
- Bytes3 = align(Bytes2),
- compact_bit_string(Bytes3,Len,NamedNumberList);
- no ->
- %% This case may demand decoding of fragmented length/value
- {Len,Bytes2} = decode_length(Buffer,undefined),
- Bytes3 = align(Bytes2),
- compact_bit_string(Bytes3,Len,NamedNumberList);
- {{Fix,Fix},L} = Sc when is_list(L), is_integer(Fix), Fix =< 16 ->
- %% X.691 �15.6, special case of extension marker
- case decode_length(Buffer,Sc) of
- {Len,Bytes2} when Len > Fix ->
- Bytes3 = align(Bytes2),
- compact_bit_string(Bytes3,Len,NamedNumberList);
- {Len,Bytes2} ->
- compact_bit_string(Bytes2,Len,NamedNumberList)
- end;
- Sc ->
- {Len,Bytes2} = decode_length(Buffer,Sc),
- Bytes3 = align(Bytes2),
- compact_bit_string(Bytes3,Len,NamedNumberList)
- end.
-
-
-%%%%%%%%%%%%%%%
-%% The result is presented as a list of named bits (if possible)
-%% else as a list of 0 and 1.
-%%
-decode_bit_string(Buffer, C, NamedNumberList) ->
- case get_constraint(C,'SizeConstraint') of
- {Lb,Ub} when is_integer(Lb),is_integer(Ub) ->
- {Len,Bytes2} = decode_length(Buffer,{Lb,Ub}),
- Bytes3 = align(Bytes2),
- bit_list_or_named(Bytes3,Len,NamedNumberList);
- no ->
- {Len,Bytes2} = decode_length(Buffer,undefined),
- Bytes3 = align(Bytes2),
- bit_list_or_named(Bytes3,Len,NamedNumberList);
- 0 -> % fixed length
- {[],Buffer}; % nothing to encode
- V when is_integer(V),V=<16 -> % fixed length 16 bits or less
- bit_list_or_named(Buffer,V,NamedNumberList);
- V when is_integer(V),V=<65536 ->
- Bytes2 = align(Buffer),
- bit_list_or_named(Bytes2,V,NamedNumberList);
- V when is_integer(V) ->
- Bytes2 = align(Buffer),
- {BinBits,_} = decode_fragmented_bits(Bytes2,V),
- bit_list_or_named(BinBits,V,NamedNumberList);
- {{Fix,Fix},L} = Sc when is_list(L), is_integer(Fix), Fix =< 16 ->
- %% X.691 �15.6, special case of extension marker
- case decode_length(Buffer,Sc) of
- {Len,Bytes2} when Len > Fix ->
- Bytes3 = align(Bytes2),
- bit_list_or_named(Bytes3,Len,NamedNumberList);
- {Len,Bytes2} when Len > 16 ->
- Bytes3 = align(Bytes2),
- bit_list_or_named(Bytes3,Len,NamedNumberList);
- {Len,Bytes2} ->
- bit_list_or_named(Bytes2,Len,NamedNumberList)
- end;
- Sc -> %% X.691 �15.6, extension marker
- {Len,Bytes2} = decode_length(Buffer,Sc),
- Bytes3 = align(Bytes2),
- bit_list_or_named(Bytes3,Len,NamedNumberList)
- end.
-
-
-%% if no named bits are declared we will return a
-%% {Unused,Bits}. Unused = integer(),
-%% Bits = binary().
-compact_bit_string(Buffer,Len,[]) ->
- getbits_as_binary(Len,Buffer); % {{Unused,BinBits},NewBuffer}
-compact_bit_string(Buffer,Len,NamedNumberList) ->
- bit_list_or_named(Buffer,Len,NamedNumberList).
-
-
-%% if no named bits are declared we will return a
-%% BitList = [0 | 1]
-
-bit_list_or_named(Buffer,Len,[]) ->
- getbits_as_list(Len,Buffer);
-
-%% if there are named bits declared we will return a named
-%% BitList where the names are atoms and unnamed bits represented
-%% as {bit,Pos}
-%% BitList = [atom() | {bit,Pos}]
-%% Pos = integer()
-
-bit_list_or_named(Buffer,Len,NamedNumberList) ->
- {BitList,Rest} = getbits_as_list(Len,Buffer),
- {bit_list_or_named1(0,BitList,NamedNumberList,[]), Rest}.
-
-bit_list_or_named1(Pos,[0|Bt],Names,Acc) ->
- bit_list_or_named1(Pos+1,Bt,Names,Acc);
-bit_list_or_named1(Pos,[1|Bt],Names,Acc) ->
- case lists:keysearch(Pos,2,Names) of
- {value,{Name,_}} ->
- bit_list_or_named1(Pos+1,Bt,Names,[Name|Acc]);
- _ ->
- bit_list_or_named1(Pos+1,Bt,Names,[{bit,Pos}|Acc])
- end;
-bit_list_or_named1(_,[],_,Acc) ->
- lists:reverse(Acc).
-
-
-
-%%%%%%%%%%%%%%%
-%%
-
-int_to_bitlist(Int) when is_integer(Int), Int > 0 ->
- [Int band 1 | int_to_bitlist(Int bsr 1)];
-int_to_bitlist(0) ->
- [].
-
-
-%%%%%%%%%%%%%%%%%%
-%% get_all_bitposes([list of named bits to set], named_bit_db, []) ->
-%% [sorted_list_of_bitpositions_to_set]
-
-get_all_bitposes([{bit,ValPos}|Rest], NamedBitList, Ack) ->
- get_all_bitposes(Rest, NamedBitList, [ValPos | Ack ]);
-
-get_all_bitposes([Val | Rest], NamedBitList, Ack) ->
- case lists:keysearch(Val, 1, NamedBitList) of
- {value, {_ValName, ValPos}} ->
- get_all_bitposes(Rest, NamedBitList, [ValPos | Ack]);
- _ ->
- exit({error,{asn1, {bitstring_namedbit, Val}}})
- end;
-get_all_bitposes([], _NamedBitList, Ack) ->
- lists:sort(Ack).
-
-%%%%%%%%%%%%%%%%%%
-%% make_and_set_list([list of positions to set to 1])->
-%% returns list with all in SetPos set.
-%% in positioning in list the first element is 0, the second 1 etc.., but
-%%
-
-make_and_set_list([XPos|SetPos], XPos) ->
- [1 | make_and_set_list(SetPos, XPos + 1)];
-make_and_set_list([Pos|SetPos], XPos) ->
- [0 | make_and_set_list([Pos | SetPos], XPos + 1)];
-make_and_set_list([], _) ->
- [].
-
-%%%%%%%%%%%%%%%%%
-%% pad_list(N,BitList) -> PaddedList
-%% returns a padded (with trailing {bit,0} elements) list of length N
-%% if Bitlist contains more than N significant bits set an exit asn1_error
-%% is generated
-
-pad_list(N,In={Unused,Bin}) ->
- pad_list(N, size(Bin)*8 - Unused, In).
-
-pad_list(N,Size,In={_,_}) when N < Size ->
- exit({error,{asn1,{range_error,{bit_string,In}}}});
-pad_list(N,Size,{Unused,Bin}) when N > Size, Unused > 0 ->
- pad_list(N,Size+1,{Unused-1,Bin});
-pad_list(N,Size,{_Unused,Bin}) when N > Size ->
- pad_list(N,Size+1,{7,<<Bin/binary,0>>});
-pad_list(N,N,In={_,_}) ->
- In.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% X.691:16
-%% encode_octet_string(Constraint,ExtensionMarker,Val)
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-encode_octet_string(C,Val) ->
- encode_octet_string2(C,Val).
-
-encode_octet_string2(C,{_Name,Val}) ->
- encode_octet_string2(C,Val);
-encode_octet_string2(C,Val) ->
- case get_constraint(C,'SizeConstraint') of
- 0 ->
- [];
- 1 ->
- [V] = Val,
- {bits,8,V};
- 2 ->
- [V1,V2] = Val,
- [{bits,8,V1},{bits,8,V2}];
- Sv when Sv =<65535, Sv == length(Val) -> % fixed length
- {octets,Val};
- {Lb,Ub} ->
- [encode_length({Lb,Ub},length(Val)),{octets,Val}];
- Sv when is_list(Sv) ->
- [encode_length({hd(Sv),lists:max(Sv)},length(Val)),{octets,Val}];
- no ->
- [encode_length(undefined,length(Val)),{octets,Val}]
- end.
-
-decode_octet_string(Bytes,Range) ->
- decode_octet_string(Bytes,Range,false).
-
-decode_octet_string(Bytes,C,false) ->
- case get_constraint(C,'SizeConstraint') of
- 0 ->
- {[],Bytes};
- 1 ->
- {B1,Bytes2} = getbits(Bytes,8),
- {[B1],Bytes2};
- 2 ->
- {Bs,Bytes2}= getbits(Bytes,16),
- {binary_to_list(<<Bs:16>>),Bytes2};
- {_,0} ->
- {[],Bytes};
- Sv when is_integer(Sv), Sv =<65535 -> % fixed length
- getoctets_as_list(Bytes,Sv);
- Sv when is_integer(Sv) -> % fragmented encoding
- Bytes2 = align(Bytes),
- decode_fragmented_octets(Bytes2,Sv);
- {Lb,Ub} ->
- {Len,Bytes2} = decode_length(Bytes,{Lb,Ub}),
- getoctets_as_list(Bytes2,Len);
- Sv when is_list(Sv) ->
- {Len,Bytes2} = decode_length(Bytes,{hd(Sv),lists:max(Sv)}),
- getoctets_as_list(Bytes2,Len);
- no ->
- {Len,Bytes2} = decode_length(Bytes,undefined),
- getoctets_as_list(Bytes2,Len)
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Restricted char string types
-%% (NumericString, PrintableString,VisibleString,IA5String,BMPString,UniversalString)
-%% X.691:26 and X.680:34-36
-%%encode_restricted_string(aligned,'BMPString',Constraints,Extension,Val)
-
-
-encode_restricted_string(aligned,{Name,Val}) when is_atom(Name) ->
- encode_restricted_string(aligned,Val);
-
-encode_restricted_string(aligned,Val) when is_list(Val)->
- [encode_length(undefined,length(Val)),{octets,Val}].
-
-encode_known_multiplier_string(aligned,StringType,C,_Ext,{Name,Val}) when is_atom(Name) ->
- encode_known_multiplier_string(aligned,StringType,C,false,Val);
-
-encode_known_multiplier_string(aligned,StringType,C,_Ext,Val) ->
- Result = chars_encode(C,StringType,Val),
- NumBits = get_NumBits(C,StringType),
- case get_constraint(C,'SizeConstraint') of
- Ub when is_integer(Ub), Ub*NumBits =< 16 ->
- Result;
- 0 ->
- [];
- Ub when is_integer(Ub),Ub =<65535 -> % fixed length
- [align,Result];
- {Ub,Lb} ->
- [encode_length({Ub,Lb},length(Val)),align,Result];
- Vl when is_list(Vl) ->
- [encode_length({lists:min(Vl),lists:max(Vl)},length(Val)),align,Result];
- no ->
- [encode_length(undefined,length(Val)),align,Result]
- end.
-
-decode_restricted_string(Bytes,aligned) ->
- {Len,Bytes2} = decode_length(Bytes,undefined),
- getoctets_as_list(Bytes2,Len).
-
-decode_known_multiplier_string(Bytes,aligned,StringType,C,_Ext) ->
- NumBits = get_NumBits(C,StringType),
- case get_constraint(C,'SizeConstraint') of
- Ub when is_integer(Ub), Ub*NumBits =< 16 ->
- chars_decode(Bytes,NumBits,StringType,C,Ub);
- Ub when is_integer(Ub),Ub =<65535 -> % fixed length
- Bytes1 = align(Bytes),
- chars_decode(Bytes1,NumBits,StringType,C,Ub);
- 0 ->
- {[],Bytes};
- Vl when is_list(Vl) ->
- {Len,Bytes1} = decode_length(Bytes,{hd(Vl),lists:max(Vl)}),
- Bytes2 = align(Bytes1),
- chars_decode(Bytes2,NumBits,StringType,C,Len);
- no ->
- {Len,Bytes1} = decode_length(Bytes,undefined),
- Bytes2 = align(Bytes1),
- chars_decode(Bytes2,NumBits,StringType,C,Len);
- {Lb,Ub}->
- {Len,Bytes1} = decode_length(Bytes,{Lb,Ub}),
- Bytes2 = align(Bytes1),
- chars_decode(Bytes2,NumBits,StringType,C,Len)
- end.
-
-
-encode_NumericString(C,Val) ->
- encode_known_multiplier_string(aligned,'NumericString',C,false,Val).
-decode_NumericString(Bytes,C) ->
- decode_known_multiplier_string(Bytes,aligned,'NumericString',C,false).
-
-encode_PrintableString(C,Val) ->
- encode_known_multiplier_string(aligned,'PrintableString',C,false,Val).
-decode_PrintableString(Bytes,C) ->
- decode_known_multiplier_string(Bytes,aligned,'PrintableString',C,false).
-
-encode_VisibleString(C,Val) -> % equivalent with ISO646String
- encode_known_multiplier_string(aligned,'VisibleString',C,false,Val).
-decode_VisibleString(Bytes,C) ->
- decode_known_multiplier_string(Bytes,aligned,'VisibleString',C,false).
-
-encode_IA5String(C,Val) ->
- encode_known_multiplier_string(aligned,'IA5String',C,false,Val).
-decode_IA5String(Bytes,C) ->
- decode_known_multiplier_string(Bytes,aligned,'IA5String',C,false).
-
-encode_BMPString(C,Val) ->
- encode_known_multiplier_string(aligned,'BMPString',C,false,Val).
-decode_BMPString(Bytes,C) ->
- decode_known_multiplier_string(Bytes,aligned,'BMPString',C,false).
-
-encode_UniversalString(C,Val) ->
- encode_known_multiplier_string(aligned,'UniversalString',C,false,Val).
-decode_UniversalString(Bytes,C) ->
- decode_known_multiplier_string(Bytes,aligned,'UniversalString',C,false).
-
-
-%% end of known-multiplier strings for which PER visible constraints are
-%% applied
-
-encode_GeneralString(_C,Val) ->
- encode_restricted_string(aligned,Val).
-decode_GeneralString(Bytes,_C) ->
- decode_restricted_string(Bytes,aligned).
-
-encode_GraphicString(_C,Val) ->
- encode_restricted_string(aligned,Val).
-decode_GraphicString(Bytes,_C) ->
- decode_restricted_string(Bytes,aligned).
-
-encode_ObjectDescriptor(_C,Val) ->
- encode_restricted_string(aligned,Val).
-decode_ObjectDescriptor(Bytes) ->
- decode_restricted_string(Bytes,aligned).
-
-encode_TeletexString(_C,Val) -> % equivalent with T61String
- encode_restricted_string(aligned,Val).
-decode_TeletexString(Bytes,_C) ->
- decode_restricted_string(Bytes,aligned).
-
-encode_VideotexString(_C,Val) ->
- encode_restricted_string(aligned,Val).
-decode_VideotexString(Bytes,_C) ->
- decode_restricted_string(Bytes,aligned).
-
-
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% getBMPChars(Bytes,Len) ->{BMPcharList,RemainingBytes}
-%%
-getBMPChars(Bytes,1) ->
- {O1,Bytes2} = getbits(Bytes,8),
- {O2,Bytes3} = getbits(Bytes2,8),
- if
- O1 == 0 ->
- {[O2],Bytes3};
- true ->
- {[{0,0,O1,O2}],Bytes3}
- end;
-getBMPChars(Bytes,Len) ->
- getBMPChars(Bytes,Len,[]).
-
-getBMPChars(Bytes,0,Acc) ->
- {lists:reverse(Acc),Bytes};
-getBMPChars(Bytes,Len,Acc) ->
- {Octs,Bytes1} = getoctets_as_list(Bytes,2),
- case Octs of
- [0,O2] ->
- getBMPChars(Bytes1,Len-1,[O2|Acc]);
- [O1,O2]->
- getBMPChars(Bytes1,Len-1,[{0,0,O1,O2}|Acc])
- end.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% chars_encode(C,StringType,Value) -> ValueList
-%%
-%% encodes chars according to the per rules taking the constraint PermittedAlphabet
-%% into account.
-%% This function does only encode the value part and NOT the length
-
-chars_encode(C,StringType,Value) ->
- case {StringType,get_constraint(C,'PermittedAlphabet')} of
- {'UniversalString',{_,_Sv}} ->
- exit({error,{asn1,{'not implemented',"UniversalString with PermittedAlphabet constraint"}}});
- {'BMPString',{_,_Sv}} ->
- exit({error,{asn1,{'not implemented',"BMPString with PermittedAlphabet constraint"}}});
- _ ->
- {NumBits,CharOutTab} = {get_NumBits(C,StringType),get_CharOutTab(C,StringType)},
- chars_encode2(Value,NumBits,CharOutTab)
- end.
-
-chars_encode2([H|T],NumBits,{Min,Max,notab}) when H =< Max, H >= Min ->
- [{bits,NumBits,H-Min}|chars_encode2(T,NumBits,{Min,Max,notab})];
-chars_encode2([H|T],NumBits,{Min,Max,Tab}) when H =< Max, H >= Min ->
- [{bits,NumBits,exit_if_false(H,element(H-Min+1,Tab))}|chars_encode2(T,NumBits,{Min,Max,Tab})];
-chars_encode2([{A,B,C,D}|T],NumBits,{Min,Max,notab}) ->
- %% no value range check here (ought to be, but very expensive)
-% [{bits,NumBits,(A*B*C*D)-Min}|chars_encode2(T,NumBits,{Min,Max,notab})];
- [{bits,NumBits,((((((A bsl 8)+B) bsl 8)+C) bsl 8)+D)-Min}|chars_encode2(T,NumBits,{Min,Max,notab})];
-chars_encode2([{A,B,C,D}|T],NumBits,{Min,Max,Tab}) ->
- %% no value range check here (ought to be, but very expensive)
-% [{bits,NumBits,element((A*B*C*D)-Min,Tab)}|chars_encode2(T,NumBits,{Min,Max,notab})];
- [{bits,NumBits,exit_if_false({A,B,C,D},element(((((((A bsl 8)+B) bsl 8)+C) bsl 8)+D)-Min,Tab))}|chars_encode2(T,NumBits,{Min,Max,notab})];
-chars_encode2([H|_T],_,{_,_,_}) ->
- exit({error,{asn1,{illegal_char_value,H}}});
-chars_encode2([],_,_) ->
- [].
-
-exit_if_false(V,false)->
- exit({error,{asn1,{"illegal value according to Permitted alphabet constraint",V}}});
-exit_if_false(_,V) ->V.
-
-
-get_NumBits(C,StringType) ->
- case get_constraint(C,'PermittedAlphabet') of
- {'SingleValue',Sv} ->
- charbits(length(Sv),aligned);
- no ->
- case StringType of
- 'IA5String' ->
- charbits(128,aligned); % 16#00..16#7F
- 'VisibleString' ->
- charbits(95,aligned); % 16#20..16#7E
- 'PrintableString' ->
- charbits(74,aligned); % [$\s,$',$(,$),$+,$,,$-,$.,$/,"0123456789",$:,$=,$?,$A..$Z,$a..$z
- 'NumericString' ->
- charbits(11,aligned); % $ ,"0123456789"
- 'UniversalString' ->
- 32;
- 'BMPString' ->
- 16
- end
- end.
-
-%%Maybe used later
-%%get_MaxChar(C,StringType) ->
-%% case get_constraint(C,'PermittedAlphabet') of
-%% {'SingleValue',Sv} ->
-%% lists:nth(length(Sv),Sv);
-%% no ->
-%% case StringType of
-%% 'IA5String' ->
-%% 16#7F; % 16#00..16#7F
-%% 'VisibleString' ->
-%% 16#7E; % 16#20..16#7E
-%% 'PrintableString' ->
-%% $z; % [$\s,$',$(,$),$+,$,,$-,$.,$/,"0123456789",$:,$=,$?,$A..$Z,$a..$z
-%% 'NumericString' ->
-%% $9; % $ ,"0123456789"
-%% 'UniversalString' ->
-%% 16#ffffffff;
-%% 'BMPString' ->
-%% 16#ffff
-%% end
-%% end.
-
-%%Maybe used later
-%%get_MinChar(C,StringType) ->
-%% case get_constraint(C,'PermittedAlphabet') of
-%% {'SingleValue',Sv} ->
-%% hd(Sv);
-%% no ->
-%% case StringType of
-%% 'IA5String' ->
-%% 16#00; % 16#00..16#7F
-%% 'VisibleString' ->
-%% 16#20; % 16#20..16#7E
-%% 'PrintableString' ->
-%% $\s; % [$\s,$',$(,$),$+,$,,$-,$.,$/,"0123456789",$:,$=,$?,$A..$Z,$a..$z
-%% 'NumericString' ->
-%% $\s; % $ ,"0123456789"
-%% 'UniversalString' ->
-%% 16#00;
-%% 'BMPString' ->
-%% 16#00
-%% end
-%% end.
-
-get_CharOutTab(C,StringType) ->
- get_CharTab(C,StringType,out).
-
-get_CharInTab(C,StringType) ->
- get_CharTab(C,StringType,in).
-
-get_CharTab(C,StringType,InOut) ->
- case get_constraint(C,'PermittedAlphabet') of
- {'SingleValue',Sv} ->
- get_CharTab2(C,StringType,hd(Sv),lists:max(Sv),Sv,InOut);
- no ->
- case StringType of
- 'IA5String' ->
- {0,16#7F,notab};
- 'VisibleString' ->
- get_CharTab2(C,StringType,16#20,16#7F,notab,InOut);
- 'PrintableString' ->
- Chars = lists:sort(
- " '()+,-./0123456789:=?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"),
- get_CharTab2(C,StringType,hd(Chars),lists:max(Chars),Chars,InOut);
- 'NumericString' ->
- get_CharTab2(C,StringType,16#20,$9," 0123456789",InOut);
- 'UniversalString' ->
- {0,16#FFFFFFFF,notab};
- 'BMPString' ->
- {0,16#FFFF,notab}
- end
- end.
-
-get_CharTab2(C,StringType,Min,Max,Chars,InOut) ->
- BitValMax = (1 bsl get_NumBits(C,StringType))-1,
- if
- Max =< BitValMax ->
- {0,Max,notab};
- true ->
- case InOut of
- out ->
- {Min,Max,create_char_tab(Min,Chars)};
- in ->
- {Min,Max,list_to_tuple(Chars)}
- end
- end.
-
-create_char_tab(Min,L) ->
- list_to_tuple(create_char_tab(Min,L,0)).
-create_char_tab(Min,[Min|T],V) ->
- [V|create_char_tab(Min+1,T,V+1)];
-create_char_tab(_Min,[],_V) ->
- [];
-create_char_tab(Min,L,V) ->
- [false|create_char_tab(Min+1,L,V)].
-
-%% This very inefficient and should be moved to compiletime
-charbits(NumOfChars,aligned) ->
- case charbits(NumOfChars) of
- 1 -> 1;
- 2 -> 2;
- B when B =< 4 -> 4;
- B when B =< 8 -> 8;
- B when B =< 16 -> 16;
- B when B =< 32 -> 32
- end.
-
-charbits(NumOfChars) when NumOfChars =< 2 -> 1;
-charbits(NumOfChars) when NumOfChars =< 4 -> 2;
-charbits(NumOfChars) when NumOfChars =< 8 -> 3;
-charbits(NumOfChars) when NumOfChars =< 16 -> 4;
-charbits(NumOfChars) when NumOfChars =< 32 -> 5;
-charbits(NumOfChars) when NumOfChars =< 64 -> 6;
-charbits(NumOfChars) when NumOfChars =< 128 -> 7;
-charbits(NumOfChars) when NumOfChars =< 256 -> 8;
-charbits(NumOfChars) when NumOfChars =< 512 -> 9;
-charbits(NumOfChars) when NumOfChars =< 1024 -> 10;
-charbits(NumOfChars) when NumOfChars =< 2048 -> 11;
-charbits(NumOfChars) when NumOfChars =< 4096 -> 12;
-charbits(NumOfChars) when NumOfChars =< 8192 -> 13;
-charbits(NumOfChars) when NumOfChars =< 16384 -> 14;
-charbits(NumOfChars) when NumOfChars =< 32768 -> 15;
-charbits(NumOfChars) when NumOfChars =< 65536 -> 16;
-charbits(NumOfChars) when is_integer(NumOfChars) ->
- 16 + charbits1(NumOfChars bsr 16).
-
-charbits1(0) ->
- 0;
-charbits1(NumOfChars) ->
- 1 + charbits1(NumOfChars bsr 1).
-
-
-chars_decode(Bytes,_,'BMPString',C,Len) ->
- case get_constraint(C,'PermittedAlphabet') of
- no ->
- getBMPChars(Bytes,Len);
- _ ->
- exit({error,{asn1,
- {'not implemented',
- "BMPString with PermittedAlphabet constraint"}}})
- end;
-chars_decode(Bytes,NumBits,StringType,C,Len) ->
- CharInTab = get_CharInTab(C,StringType),
- chars_decode2(Bytes,CharInTab,NumBits,Len).
-
-
-chars_decode2(Bytes,CharInTab,NumBits,Len) ->
- chars_decode2(Bytes,CharInTab,NumBits,Len,[]).
-
-chars_decode2(Bytes,_CharInTab,_NumBits,0,Acc) ->
- {lists:reverse(Acc),Bytes};
-chars_decode2(Bytes,{Min,Max,notab},NumBits,Len,Acc) when NumBits > 8 ->
- {Char,Bytes2} = getbits(Bytes,NumBits),
- Result =
- if
- Char < 256 -> Char;
- true ->
- list_to_tuple(binary_to_list(<<Char:32>>))
- end,
- chars_decode2(Bytes2,{Min,Max,notab},NumBits,Len -1,[Result|Acc]);
-% chars_decode2(Bytes,{Min,Max,notab},NumBits,Len,Acc) when NumBits > 8 ->
-% {Char,Bytes2} = getbits(Bytes,NumBits),
-% Result = case minimum_octets(Char+Min) of
-% [NewChar] -> NewChar;
-% [C1,C2] -> {0,0,C1,C2};
-% [C1,C2,C3] -> {0,C1,C2,C3};
-% [C1,C2,C3,C4] -> {C1,C2,C3,C4}
-% end,
-% chars_decode2(Bytes2,{Min,Max,notab},NumBits,Len -1,[Result|Acc]);
-chars_decode2(Bytes,{Min,Max,notab},NumBits,Len,Acc) ->
- {Char,Bytes2} = getbits(Bytes,NumBits),
- chars_decode2(Bytes2,{Min,Max,notab},NumBits,Len -1,[Char+Min|Acc]);
-
-%% BMPString and UniversalString with PermittedAlphabet is currently not supported
-chars_decode2(Bytes,{Min,Max,CharInTab},NumBits,Len,Acc) ->
- {Char,Bytes2} = getbits(Bytes,NumBits),
- chars_decode2(Bytes2,{Min,Max,CharInTab},NumBits,Len -1,[element(Char+1,CharInTab)|Acc]).
-
-
-%% UTF8String
-encode_UTF8String(Val) when is_binary(Val) ->
- [encode_length(undefined,size(Val)),{octets,Val}];
-encode_UTF8String(Val) ->
- Bin = list_to_binary(Val),
- encode_UTF8String(Bin).
-
-decode_UTF8String(Bytes) ->
- {Len,Bytes2} = decode_length(Bytes,undefined),
- {Octs,Bytes3} = getoctets_as_list(Bytes2,Len),
- {list_to_binary(Octs),Bytes3}.
-
-
- % X.691:17
-encode_null(_) -> []. % encodes to nothing
-%encode_null({Name,Val}) when is_atom(Name) ->
-% encode_null(Val).
-
-decode_null(Bytes) ->
- {'NULL',Bytes}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% encode_object_identifier(Val) -> CompleteList
-%% encode_object_identifier({Name,Val}) -> CompleteList
-%% Val -> {Int1,Int2,...,IntN} % N >= 2
-%% Name -> atom()
-%% Int1 -> integer(0..2)
-%% Int2 -> integer(0..39) when Int1 (0..1) else integer()
-%% Int3-N -> integer()
-%% CompleteList -> [{bits,8,Val}|{octets,Ol}|align|...]
-%%
-encode_object_identifier({Name,Val}) when is_atom(Name) ->
- encode_object_identifier(Val);
-encode_object_identifier(Val) ->
- OctetList = e_object_identifier(Val),
- Octets = list_to_binary(OctetList), % performs a flatten at the same time
- [{debug,object_identifier},encode_length(undefined,size(Octets)),{octets,Octets}].
-
-%% This code is copied from asn1_encode.erl (BER) and corrected and modified
-
-e_object_identifier({'OBJECT IDENTIFIER',V}) ->
- e_object_identifier(V);
-e_object_identifier({Cname,V}) when is_atom(Cname),is_tuple(V) ->
- e_object_identifier(tuple_to_list(V));
-e_object_identifier({Cname,V}) when is_atom(Cname),is_list(V) ->
- e_object_identifier(V);
-e_object_identifier(V) when is_tuple(V) ->
- e_object_identifier(tuple_to_list(V));
-
-%% E1 = 0|1|2 and (E2 < 40 when E1 = 0|1)
-e_object_identifier([E1,E2|Tail]) when E1 >= 0, E1 < 2, E2 < 40 ; E1==2 ->
- Head = 40*E1 + E2, % weird
- e_object_elements([Head|Tail],[]);
-e_object_identifier(Oid=[_,_|_Tail]) ->
- exit({error,{asn1,{'illegal_value',Oid}}}).
-
-e_object_elements([],Acc) ->
- lists:reverse(Acc);
-e_object_elements([H|T],Acc) ->
- e_object_elements(T,[e_object_element(H)|Acc]).
-
-e_object_element(Num) when Num < 128 ->
- [Num];
-e_object_element(Num) ->
- [e_o_e(Num bsr 7)|[Num band 2#1111111]].
-e_o_e(Num) when Num < 128 ->
- Num bor 2#10000000;
-e_o_e(Num) ->
- [e_o_e(Num bsr 7)|[(Num band 2#1111111) bor 2#10000000]].
-
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% decode_object_identifier(Bytes) -> {ObjId,RemainingBytes}
-%% ObjId -> {integer(),integer(),...} % at least 2 integers
-%% RemainingBytes -> [integer()] when integer() (0..255)
-decode_object_identifier(Bytes) ->
- {Len,Bytes2} = decode_length(Bytes,undefined),
- {Octs,Bytes3} = getoctets_as_list(Bytes2,Len),
- [First|Rest] = dec_subidentifiers(Octs,0,[]),
- Idlist = if
- First < 40 ->
- [0,First|Rest];
- First < 80 ->
- [1,First - 40|Rest];
- true ->
- [2,First - 80|Rest]
- end,
- {list_to_tuple(Idlist),Bytes3}.
-
-dec_subidentifiers([H|T],Av,Al) when H >=16#80 ->
- dec_subidentifiers(T,(Av bsl 7) + (H band 16#7F),Al);
-dec_subidentifiers([H|T],Av,Al) ->
- dec_subidentifiers(T,0,[(Av bsl 7) + H |Al]);
-dec_subidentifiers([],_Av,Al) ->
- lists:reverse(Al).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% encode_relative_oid(Val) -> CompleteList
-%% encode_relative_oid({Name,Val}) -> CompleteList
-encode_relative_oid({Name,Val}) when is_atom(Name) ->
- encode_relative_oid(Val);
-encode_relative_oid(Val) when is_tuple(Val) ->
- encode_relative_oid(tuple_to_list(Val));
-encode_relative_oid(Val) when is_list(Val) ->
- Octets = list_to_binary([e_object_element(X)||X <- Val]),
- [encode_length(undefined,size(Octets)),{octets,Octets}].
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% decode_relative_oid(Val) -> {ROID,Rest}
-%% decode_relative_oid({Name,Val}) -> {ROID,Rest}
-decode_relative_oid(Bytes) ->
- {Len,Bytes2} = decode_length(Bytes,undefined),
- {Octs,Bytes3} = getoctets_as_list(Bytes2,Len),
- ObjVals = dec_subidentifiers(Octs,0,[]),
- {list_to_tuple(ObjVals),Bytes3}.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% encode_real(Val) -> CompleteList
-%% encode_real({Name,Val}) -> CompleteList
-encode_real({Name,Val}) when is_atom(Name) ->
- encode_real(Val);
-encode_real(Real) ->
- {EncVal,Len} = ?RT_COMMON:encode_real([],Real),
- [encode_length(undefined,Len),{octets,EncVal}].
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% decode_real(Val) -> {REALvalue,Rest}
-%% decode_real({Name,Val}) -> {REALvalue,Rest}
-decode_real(Bytes) ->
- {Len,{0,Bytes2}} = decode_length(Bytes,undefined),
- {RealVal,Rest,Len} = ?RT_COMMON:decode_real(Bytes2,Len),
- {RealVal,{0,Rest}}.
-
-
-get_constraint([{Key,V}],Key) ->
- V;
-get_constraint([],_Key) ->
- no;
-get_constraint(C,Key) ->
- case lists:keysearch(Key,1,C) of
- false ->
- no;
- {value,{_,V}} ->
- V
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% complete(InList) -> ByteList
-%% Takes a coded list with bits and bytes and converts it to a list of bytes
-%% Should be applied as the last step at encode of a complete ASN.1 type
-%%
-
-% complete(L) ->
-% case complete1(L) of
-% {[],0} ->
-% <<0>>;
-% {Acc,0} ->
-% lists:reverse(Acc);
-% {[Hacc|Tacc],Acclen} -> % Acclen >0
-% Rest = 8 - Acclen,
-% NewHacc = Hacc bsl Rest,
-% lists:reverse([NewHacc|Tacc])
-% end.
-
-
-% complete1(InList) when is_list(InList) ->
-% complete1(InList,[]);
-% complete1(InList) ->
-% complete1([InList],[]).
-
-% complete1([{debug,_}|T], Acc) ->
-% complete1(T,Acc);
-% complete1([H|T],Acc) when is_list(H) ->
-% {NewH,NewAcclen} = complete1(H,Acc),
-% complete1(T,NewH,NewAcclen);
-
-% complete1([{0,Bin}|T],Acc,0) when is_binary(Bin) ->
-% complete1(T,[Bin|Acc],0);
-% complete1([{Unused,Bin}|T],Acc,0) when is_integer(Unused),is_binary(Bin) ->
-% Size = size(Bin)-1,
-% <<Bs:Size/binary,B>> = Bin,
-% complete1(T,[(B bsr Unused),Bs|Acc],8-Unused);
-% complete1([{Unused,Bin}|T],[Hacc|Tacc],Acclen) when is_integer(Unused),is_binary(Bin) ->
-% Rest = 8 - Acclen,
-% Used = 8 - Unused,
-% case size(Bin) of
-% 1 ->
-% if
-% Rest >= Used ->
-% <<B:Used,_:Unused>> = Bin,
-% complete1(T,[(Hacc bsl Used) + B|Tacc],
-% (Acclen+Used) rem 8);
-% true ->
-% LeftOver = 8 - Rest - Unused,
-% <<Val2:Rest,Val1:LeftOver,_:Unused>> = Bin,
-% complete1(T,[Val1,(Hacc bsl Rest) + Val2|Tacc],
-% (Acclen+Used) rem 8)
-% end;
-% N ->
-% if
-% Rest == Used ->
-% N1 = N - 1,
-% <<B:Rest,Bs:N1/binary,_:Unused>> = Bin,
-% complete1(T,[Bs,(Hacc bsl Rest) + B|Tacc],0);
-% Rest > Used ->
-% N1 = N - 2,
-% N2 = (8 - Rest) + Used,
-% <<B1:Rest,Bytes:N1/binary,B2:N2,_:Unused>> = Bin,
-% complete1(T,[B2,Bytes,(Hacc bsl Rest) + B1|Tacc],
-% (Acclen + Used) rem 8);
-% true -> % Rest < Used
-% N1 = N - 1,
-% N2 = Used - Rest,
-% <<B1:Rest,Bytes:N1/binary,B2:N2,_:Unused>> = Bin,
-% complete1(T,[B2,Bytes,(Hacc bsl Rest) + B1|Tacc],
-% (Acclen + Used) rem 8)
-% end
-% end;
-
-% %complete1([{octets,N,Val}|T],Acc,Acclen) when N =< 4 ,is_integer(Val) ->
-% % complete1([{octets,<<Val:N/unit:8>>}|T],Acc,Acclen);
-% complete1([{octets,N,Val}|T],Acc,Acclen) when N =< 4 ,is_integer(Val) ->
-% Newval = case N of
-% 1 ->
-% Val4 = Val band 16#FF,
-% [Val4];
-% 2 ->
-% Val3 = (Val bsr 8) band 16#FF,
-% Val4 = Val band 16#FF,
-% [Val3,Val4];
-% 3 ->
-% Val2 = (Val bsr 16) band 16#FF,
-% Val3 = (Val bsr 8) band 16#FF,
-% Val4 = Val band 16#FF,
-% [Val2,Val3,Val4];
-% 4 ->
-% Val1 = (Val bsr 24) band 16#FF,
-% Val2 = (Val bsr 16) band 16#FF,
-% Val3 = (Val bsr 8) band 16#FF,
-% Val4 = Val band 16#FF,
-% [Val1,Val2,Val3,Val4]
-% end,
-% complete1([{octets,Newval}|T],Acc,Acclen);
-
-% complete1([{octets,Bin}|T],Acc,Acclen) when is_binary(Bin) ->
-% Rest = 8 - Acclen,
-% if
-% Rest == 8 ->
-% complete1(T,[Bin|Acc],0);
-% true ->
-% [Hacc|Tacc]=Acc,
-% complete1(T,[Bin, Hacc bsl Rest|Tacc],0)
-% end;
-
-% complete1([{octets,Oct}|T],Acc,Acclen) when is_list(Oct) ->
-% Rest = 8 - Acclen,
-% if
-% Rest == 8 ->
-% complete1(T,[list_to_binary(Oct)|Acc],0);
-% true ->
-% [Hacc|Tacc]=Acc,
-% complete1(T,[list_to_binary(Oct), Hacc bsl Rest|Tacc],0)
-% end;
-
-% complete1([{bit,Val}|T], Acc, Acclen) ->
-% complete1([{bits,1,Val}|T],Acc,Acclen);
-% complete1([{octet,Val}|T], Acc, Acclen) ->
-% complete1([{octets,1,Val}|T],Acc,Acclen);
-
-% complete1([{bits,N,Val}|T], Acc, 0) when N =< 8 ->
-% complete1(T,[Val|Acc],N);
-% complete1([{bits,N,Val}|T], [Hacc|Tacc], Acclen) when N =< 8 ->
-% Rest = 8 - Acclen,
-% if
-% Rest >= N ->
-% complete1(T,[(Hacc bsl N) + Val|Tacc],(Acclen+N) rem 8);
-% true ->
-% Diff = N - Rest,
-% NewHacc = (Hacc bsl Rest) + (Val bsr Diff),
-% Mask = element(Diff,{1,3,7,15,31,63,127,255}),
-% complete1(T,[(Val band Mask),NewHacc|Tacc],(Acclen+N) rem 8)
-% end;
-% complete1([{bits,N,Val}|T], Acc, Acclen) -> % N > 8
-% complete1([{bits,N-8,Val bsr 8},{bits,8,Val band 255}|T],Acc,Acclen);
-
-% complete1([align|T],Acc,0) ->
-% complete1(T,Acc,0);
-% complete1([align|T],[Hacc|Tacc],Acclen) ->
-% Rest = 8 - Acclen,
-% complete1(T,[Hacc bsl Rest|Tacc],0);
-% complete1([{octets,N,Val}|T],Acc,Acclen) when is_list(Val) -> % no security check here
-% complete1([{octets,Val}|T],Acc,Acclen);
-
-% complete1([],Acc,Acclen) ->
-% {Acc,Acclen}.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% complete(InList) -> ByteList
-%% Takes a coded list with bits and bytes and converts it to a list of bytes
-%% Should be applied as the last step at encode of a complete ASN.1 type
-%%
-
-complete(L) ->
- case complete1(L) of
- {[],[]} ->
- <<0>>;
- {Acc,[]} ->
- Acc;
- {Acc,Bacc} ->
- [Acc|complete_bytes(Bacc)]
- end.
-
-%% this function builds the ugly form of lists [E1|E2] to avoid having to reverse it at the end.
-%% this is done because it is efficient and that the result always will be sent on a port or
-%% converted by means of list_to_binary/1
-complete1(InList) when is_list(InList) ->
- complete1(InList,[],[]);
-complete1(InList) ->
- complete1([InList],[],[]).
-
-complete1([],Acc,Bacc) ->
- {Acc,Bacc};
-complete1([H|T],Acc,Bacc) when is_list(H) ->
- {NewH,NewBacc} = complete1(H,Acc,Bacc),
- complete1(T,NewH,NewBacc);
-
-complete1([{octets,Bin}|T],Acc,[]) ->
- complete1(T,[Acc|Bin],[]);
-
-complete1([{octets,Bin}|T],Acc,Bacc) ->
- complete1(T,[Acc|[complete_bytes(Bacc),Bin]],[]);
-
-complete1([{debug,_}|T], Acc,Bacc) ->
- complete1(T,Acc,Bacc);
-
-complete1([{bits,N,Val}|T],Acc,Bacc) ->
- complete1(T,Acc,complete_update_byte(Bacc,Val,N));
-
-complete1([{bit,Val}|T],Acc,Bacc) ->
- complete1(T,Acc,complete_update_byte(Bacc,Val,1));
-
-complete1([align|T],Acc,[]) ->
- complete1(T,Acc,[]);
-complete1([align|T],Acc,Bacc) ->
- complete1(T,[Acc|complete_bytes(Bacc)],[]);
-complete1([{0,Bin}|T],Acc,[]) when is_binary(Bin) ->
- complete1(T,[Acc|Bin],[]);
-complete1([{Unused,Bin}|T],Acc,[]) when is_integer(Unused),is_binary(Bin) ->
- Size = size(Bin)-1,
- <<Bs:Size/binary,B>> = Bin,
- NumBits = 8-Unused,
- complete1(T,[Acc|Bs],[[B bsr Unused]|NumBits]);
-complete1([{Unused,Bin}|T],Acc,Bacc) when is_integer(Unused),is_binary(Bin) ->
- Size = size(Bin)-1,
- <<Bs:Size/binary,B>> = Bin,
- NumBits = 8 - Unused,
- Bf = complete_bytes(Bacc),
- complete1(T,[Acc|[Bf,Bs]],[[B bsr Unused]|NumBits]).
-
-
-complete_update_byte([],Val,Len) ->
- complete_update_byte([[0]|0],Val,Len);
-complete_update_byte([[Byte|Bacc]|NumBits],Val,Len) when NumBits + Len == 8 ->
- [[0,((Byte bsl Len) + Val) band 255|Bacc]|0];
-complete_update_byte([[Byte|Bacc]|NumBits],Val,Len) when NumBits + Len > 8 ->
- Rem = 8 - NumBits,
- Rest = Len - Rem,
- complete_update_byte([[0,((Byte bsl Rem) + (Val bsr Rest)) band 255 |Bacc]|0],Val,Rest);
-complete_update_byte([[Byte|Bacc]|NumBits],Val,Len) ->
- [[((Byte bsl Len) + Val) band 255|Bacc]|NumBits+Len].
-
-
-complete_bytes([[_Byte|Bacc]|0]) ->
- lists:reverse(Bacc);
-complete_bytes([[Byte|Bacc]|NumBytes]) ->
- lists:reverse([(Byte bsl (8-NumBytes)) band 255|Bacc]);
-complete_bytes([]) ->
- [].
-
-% complete_bytes(L) ->
-% complete_bytes1(lists:reverse(L),[],[],0,0).
-
-% complete_bytes1([H={V,B}|T],Acc,ReplyAcc,NumBits,NumFields) when ((NumBits+B) rem 8) == 0 ->
-% NewReplyAcc = [complete_bytes2([H|Acc],0)|ReplyAcc],
-% complete_bytes1(T,[],NewReplyAcc,0,0);
-% complete_bytes1([H={V,B}|T],Acc,ReplyAcc,NumBits,NumFields) when NumFields == 7; (NumBits+B) div 8 > 0 ->
-% Rem = (NumBits+B) rem 8,
-% NewReplyAcc = [complete_bytes2([{V bsr Rem,B - Rem}|Acc],0)|ReplyAcc],
-% complete_bytes1([{V,Rem}|T],[],NewReplyAcc,0,0);
-% complete_bytes1([H={V,B}|T],Acc,ReplyAcc,NumBits,NumFields) ->
-% complete_bytes1(T,[H|Acc],ReplyAcc,NumBits+B,NumFields+1);
-% complete_bytes1([],[],ReplyAcc,_,_) ->
-% lists:reverse(ReplyAcc);
-% complete_bytes1([],Acc,ReplyAcc,NumBits,_) ->
-% PadBits = case NumBits rem 8 of
-% 0 -> 0;
-% Rem -> 8 - Rem
-% end,
-% lists:reverse([complete_bytes2(Acc,PadBits)|ReplyAcc]).
-
-
-% complete_bytes2([{V1,B1}],PadBits) ->
-% <<V1:B1,0:PadBits>>;
-% complete_bytes2([{V2,B2},{V1,B1}],PadBits) ->
-% <<V1:B1,V2:B2,0:PadBits>>;
-% complete_bytes2([{V3,B3},{V2,B2},{V1,B1}],PadBits) ->
-% <<V1:B1,V2:B2,V3:B3,0:PadBits>>;
-% complete_bytes2([{V4,B4},{V3,B3},{V2,B2},{V1,B1}],PadBits) ->
-% <<V1:B1,V2:B2,V3:B3,V4:B4,0:PadBits>>;
-% complete_bytes2([{V5,B5},{V4,B4},{V3,B3},{V2,B2},{V1,B1}],PadBits) ->
-% <<V1:B1,V2:B2,V3:B3,V4:B4,V5:B5,0:PadBits>>;
-% complete_bytes2([{V6,B6},{V5,B5},{V4,B4},{V3,B3},{V2,B2},{V1,B1}],PadBits) ->
-% <<V1:B1,V2:B2,V3:B3,V4:B4,V5:B5,V6:B6,0:PadBits>>;
-% complete_bytes2([{V7,B7},{V6,B6},{V5,B5},{V4,B4},{V3,B3},{V2,B2},{V1,B1}],PadBits) ->
-% <<V1:B1,V2:B2,V3:B3,V4:B4,V5:B5,V6:B6,V7:B7,0:PadBits>>;
-% complete_bytes2([{V8,B8},{V7,B7},{V6,B6},{V5,B5},{V4,B4},{V3,B3},{V2,B2},{V1,B1}],PadBits) ->
-% <<V1:B1,V2:B2,V3:B3,V4:B4,V5:B5,V6:B6,V7:B7,V8:B8,0:PadBits>>.
-
-
-
-
-
-
diff --git a/lib/asn1/src/asn1rt_per_bin_rt2ct.erl b/lib/asn1/src/asn1rt_per_bin_rt2ct.erl
index 1df757a47f..5997232f13 100644
--- a/lib/asn1/src/asn1rt_per_bin_rt2ct.erl
+++ b/lib/asn1/src/asn1rt_per_bin_rt2ct.erl
@@ -22,25 +22,21 @@
-include("asn1_records.hrl").
--export([dec_fixup/3, cindex/3, list_to_record/2]).
+-export([decode_fragmented/3]).
-export([setchoiceext/1, setext/1, fixoptionals/3, fixextensions/2,
- getext/1, getextension/2, skipextensions/3, getbit/1, getchoice/3 ]).
--export([getoptionals/2, getoptionals2/2,
- set_choice/3, encode_integer/2, encode_integer/3 ]).
--export([decode_integer/2, decode_integer/3, encode_small_number/1,
- decode_boolean/1, encode_length/2, decode_length/1, decode_length/2,
- encode_small_length/1, decode_small_length/1,
+ skipextensions/3, getbit/1, getchoice/3 ]).
+-export([set_choice/3, encode_integer/2, encode_integer/3 ]).
+-export([encode_small_number/1,
+ encode_length/2,
+ encode_small_length/1,
decode_compact_bit_string/3]).
--export([decode_enumerated/3,
- encode_bit_string/3, decode_bit_string/3 ]).
--export([encode_octet_string/2, decode_octet_string/2,
- encode_null/1, decode_null/1,
+-export([encode_bit_string/3, decode_bit_string/3 ]).
+-export([encode_octet_string/2,
encode_object_identifier/1, decode_object_identifier/1,
encode_real/1, decode_real/1,
encode_relative_oid/1, decode_relative_oid/1,
complete/1]).
-
-export([encode_open_type/2, decode_open_type/2]).
-export([encode_GeneralString/2, decode_GeneralString/2,
@@ -51,19 +47,10 @@
encode_UTF8String/1,decode_UTF8String/1
]).
--export([decode_constrained_number/2,
- decode_constrained_number/3,
- decode_unconstrained_number/1,
- decode_semi_constrained_number/2,
- encode_unconstrained_number/1,
- decode_constrained_number/4,
+-export([encode_unconstrained_number/1,
encode_octet_string/3,
- decode_octet_string/3,
encode_known_multiplier_string/5,
- decode_known_multiplier_string/5,
- getoctets/2, getbits/2
-% start_drv/1,start_drv2/1,init_drv/1
- ]).
+ decode_known_multiplier_string/5]).
-export([eint_positive/1]).
@@ -73,32 +60,6 @@
-define('32K',32768).
-define('64K',65536).
-%%-define(nodriver,true).
-
-dec_fixup(Terms,Cnames,RemBytes) ->
- dec_fixup(Terms,Cnames,RemBytes,[]).
-
-dec_fixup([novalue|T],[_Hc|Tc],RemBytes,Acc) ->
- dec_fixup(T,Tc,RemBytes,Acc);
-dec_fixup([{_Name,novalue}|T],[_Hc|Tc],RemBytes,Acc) ->
- dec_fixup(T,Tc,RemBytes,Acc);
-dec_fixup([H|T],[Hc|Tc],RemBytes,Acc) ->
- dec_fixup(T,Tc,RemBytes,[{Hc,H}|Acc]);
-dec_fixup([],_Cnames,RemBytes,Acc) ->
- {lists:reverse(Acc),RemBytes}.
-
-cindex(Ix,Val,Cname) ->
- case element(Ix,Val) of
- {Cname,Val2} -> Val2;
- X -> X
- end.
-
-%% converts a list to a record if necessary
-list_to_record(_,Tuple) when is_tuple(Tuple) ->
- Tuple;
-list_to_record(Name,List) when is_list(List) ->
- list_to_tuple([Name|List]).
-
%%--------------------------------------------------------
%% setchoiceext(InRootSet) -> [{bit,X}]
%% X is set to 1 when InRootSet==false
@@ -143,15 +104,6 @@ fixoptionals([Pos|Ot],Val,Acc) ->
end.
-getext(Bytes) when is_bitstring(Bytes) ->
- getbit(Bytes).
-
-getextension(0, Bytes) ->
- {<<>>,Bytes};
-getextension(1, Bytes) ->
- {Len,Bytes2} = decode_small_length(Bytes),
- getbits_as_binary(Len,Bytes2).% {Bin,Bytes3}.
-
fixextensions({ext,ExtPos,ExtNum},Val) ->
case fixextensions(ExtPos,ExtNum+ExtPos,Val,0) of
0 -> [];
@@ -194,14 +146,6 @@ getchoice(Bytes,_,1) ->
getchoice(Bytes,NumChoices,0) ->
decode_constrained_number(Bytes,{0,NumChoices-1}).
-%% old version kept for backward compatibility with generates from R7B01
-getoptionals(Bytes,NumOpt) ->
- getbits_as_binary(NumOpt,Bytes).
-
-%% new version used in generates from r8b_patch/3 and later
-getoptionals2(Bytes,NumOpt) ->
- {_,_} = getbits(Bytes,NumOpt).
-
%% getbits_as_binary(Num,Bytes) -> {Bin,Rest}
%% Num = integer(),
@@ -344,32 +288,6 @@ decode_fragmented_bits(<<0:1,Len:7,Bin/binary>>,C,Acc) ->
exit({error,{asn1,{illegal_value,C,BinBits}}})
end.
-
-decode_fragmented_octets(Bin,C) ->
- decode_fragmented_octets(Bin,C,[]).
-
-decode_fragmented_octets(<<3:2,Len:6,Bin/binary>>,C,Acc) ->
- {Value,Bin2} = split_binary(Bin,Len * ?'16K'),
- decode_fragmented_octets(Bin2,C,[Value|Acc]);
-decode_fragmented_octets(<<0:1,0:7,Bin/binary>>,C,Acc) ->
- Octets = list_to_binary(lists:reverse(Acc)),
- case C of
- Int when is_integer(Int), C == size(Octets) ->
- {Octets,Bin};
- Int when is_integer(Int) ->
- exit({error,{asn1,{illegal_value,C,Octets}}})
- end;
-decode_fragmented_octets(<<0:1,Len:7,Bin/binary>>,C,Acc) ->
- <<Value:Len/binary-unit:8,Bin2/binary>> = Bin,
- BinOctets = list_to_binary(lists:reverse([Value|Acc])),
- case C of
- Int when is_integer(Int),size(BinOctets) == Int ->
- {BinOctets,Bin2};
- Int when is_integer(Int) ->
- exit({error,{asn1,{illegal_value,C,BinOctets}}})
- end.
-
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% encode_open_type(Constraint, Value) -> CompleteList
@@ -454,40 +372,6 @@ encode_integer(_,Val) ->
exit({error,{asn1,{illegal_value,Val}}}).
-
-decode_integer(Buffer,Range,NamedNumberList) ->
- {Val,Buffer2} = decode_integer(Buffer,Range),
- case lists:keysearch(Val,2,NamedNumberList) of
- {value,{NewVal,_}} -> {NewVal,Buffer2};
- _ -> {Val,Buffer2}
- end.
-
-decode_integer(Buffer,[{Rc,_Ec}]) when is_tuple(Rc) ->
- {Ext,Buffer2} = getext(Buffer),
- case Ext of
- 0 -> decode_integer(Buffer2,[Rc]);
- 1 -> decode_unconstrained_number(Buffer2)
- end;
-decode_integer(Buffer,undefined) ->
- decode_unconstrained_number(Buffer);
-decode_integer(Buffer,C) ->
- case get_constraint(C,'SingleValue') of
- V when is_integer(V) ->
- {V,Buffer};
- _ ->
- decode_integer1(Buffer,C)
- end.
-
-decode_integer1(Buffer,C) ->
- case VR = get_constraint(C,'ValueRange') of
- no ->
- decode_unconstrained_number(Buffer);
- {Lb, 'MAX'} ->
- decode_semi_constrained_number(Buffer,Lb);
- {_Lb,_Ub} ->
- decode_constrained_number(Buffer,VR)
- end.
-
%% X.691:10.6 Encoding of a normally small non-negative whole number
%% Use this for encoding of CHOICE index if there is an extension marker in
%% the CHOICE
@@ -507,7 +391,7 @@ decode_small_number(Bytes) ->
0 ->
getbits(Bytes2,6);
1 ->
- decode_semi_constrained_number(Bytes2,0)
+ decode_semi_constrained_number(Bytes2)
end.
%% X.691:10.7 Encoding of a semi-constrained whole number
@@ -530,12 +414,10 @@ encode_semi_constrained_number(Lb,Val) ->
[encode_length(undefined,Len),[21,<<Len:16>>,Oct]]
end.
-decode_semi_constrained_number(Bytes,{Lb,_}) ->
- decode_semi_constrained_number(Bytes,Lb);
-decode_semi_constrained_number(Bytes,Lb) ->
+decode_semi_constrained_number(Bytes) ->
{Len,Bytes2} = decode_length(Bytes,undefined),
{V,Bytes3} = getoctets(Bytes2,Len),
- {V+Lb,Bytes3}.
+ {V,Bytes3}.
encode_constrained_number({Lb,_Ub},_Range,{bits,N},Val) ->
Val2 = Val-Lb,
@@ -609,7 +491,7 @@ encode_constrained_number({Lb,Ub},Val) when Val >= Lb, Ub >= Val ->
RangeOcts = binary:encode_unsigned(Range - 1),
OctsLen = erlang:byte_size(Octs),
RangeOctsLen = erlang:byte_size(RangeOcts),
- LengthBitsNeeded = asn1rt_per_bin:minimum_bits(RangeOctsLen - 1),
+ LengthBitsNeeded = minimum_bits(RangeOctsLen - 1),
[10,LengthBitsNeeded,OctsLen-1,20,OctsLen,Octs];
true ->
exit({not_supported,{integer_range,Range}})
@@ -621,13 +503,6 @@ decode_constrained_number(Buffer,VR={Lb,Ub}) ->
Range = Ub - Lb + 1,
decode_constrained_number(Buffer,VR,Range).
-decode_constrained_number(Buffer,{Lb,_Ub},_Range,{bits,N}) ->
- {Val,Remain} = getbits(Buffer,N),
- {Val+Lb,Remain};
-decode_constrained_number(Buffer,{Lb,_Ub},_Range,{octets,N}) ->
- {Val,Remain} = getoctets(Buffer,N),
- {Val+Lb,Remain}.
-
decode_constrained_number(Buffer,{Lb,_Ub},Range) ->
% Val2 = Val - Lb,
{Val,Remain} =
@@ -665,6 +540,16 @@ decode_constrained_number(Buffer,{Lb,_Ub},Range) ->
end,
{Val+Lb,Remain}.
+%% For some reason the minimum bits needed in the length field in
+%% the encoding of constrained whole numbers must always be at least 2?
+minimum_bits(N) when N < 4 -> 2;
+minimum_bits(N) when N < 8 -> 3;
+minimum_bits(N) when N < 16 -> 4;
+minimum_bits(N) when N < 32 -> 5;
+minimum_bits(N) when N < 64 -> 6;
+minimum_bits(N) when N < 128 -> 7;
+minimum_bits(_N) -> 8.
+
%% X.691:10.8 Encoding of an unconstrained whole number
encode_unconstrained_number(Val) when Val >= 0 ->
@@ -718,23 +603,6 @@ enint(-1, [B1|T]) when B1 > 127 ->
enint(N, Acc) ->
enint(N bsr 8, [N band 16#ff|Acc]).
-decode_unconstrained_number(Bytes) ->
- {Len,Bytes2} = decode_length(Bytes,undefined),
- {Ints,Bytes3} = getoctets_as_bin(Bytes2,Len),
- {dec_integer(Ints),Bytes3}.
-
-dec_integer(Bin = <<0:1,_:7,_/binary>>) ->
- decpint(Bin);
-dec_integer(<<_:1,B:7,BitStr/bitstring>>) ->
- Size = bit_size(BitStr),
- <<I:Size>> = BitStr,
- (-128 + B) bsl bit_size(BitStr) bor I.
-
-decpint(Bin) ->
- Size = bit_size(Bin),
- <<Int:Size>> = Bin,
- Int.
-
%% X.691:10.9 Encoding of a length determinant
%%encode_small_length(undefined,Len) -> % null means no UpperBound
%% encode_small_number(Len).
@@ -779,18 +647,6 @@ encode_small_length(Len) ->
[1,encode_length(undefined,Len)].
-decode_small_length(Buffer) ->
- case getbit(Buffer) of
- {0,Remain} ->
- {Bits,Remain2} = getbits(Remain,6),
- {Bits+1,Remain2};
- {1,Remain} ->
- decode_length(Remain,undefined)
- end.
-
-decode_length(Buffer) ->
- decode_length(Buffer,undefined).
-
decode_length(Buffer,undefined) -> % un-constrained
case align(Buffer) of
<<0:1,Oct:7,Rest/binary>> ->
@@ -833,38 +689,6 @@ decode_length(Buffer,SingleValue) when is_integer(SingleValue) ->
{SingleValue,Buffer}.
- % X.691:11
-decode_boolean(Buffer) -> %when record(Buffer,buffer)
- case getbit(Buffer) of
- {1,Remain} -> {true,Remain};
- {0,Remain} -> {false,Remain}
- end.
-
-
-%% ENUMERATED with extension marker
-decode_enumerated(Buffer,C,{Ntup1,Ntup2}) when is_tuple(Ntup1), is_tuple(Ntup2) ->
- {Ext,Buffer2} = getext(Buffer),
- case Ext of
- 0 -> % not an extension value
- {Val,Buffer3} = decode_integer(Buffer2,C),
- case catch (element(Val+1,Ntup1)) of
- NewVal when is_atom(NewVal) -> {NewVal,Buffer3};
- _Error -> exit({error,{asn1,{decode_enumerated,{Val,[Ntup1,Ntup2]}}}})
- end;
- 1 -> % this an extension value
- {Val,Buffer3} = decode_small_number(Buffer2),
- case catch (element(Val+1,Ntup2)) of
- NewVal when is_atom(NewVal) -> {NewVal,Buffer3};
- _ -> {{asn1_enum,Val},Buffer3}
- end
- end;
-
-decode_enumerated(Buffer,C,NamedNumberTup) when is_tuple(NamedNumberTup) ->
- {Val,Buffer2} = decode_integer(Buffer,C),
- case catch (element(Val+1,NamedNumberTup)) of
- NewVal when is_atom(NewVal) -> {NewVal,Buffer2};
- _Error -> exit({error,{asn1,{decode_enumerated,{Val,NamedNumberTup}}}})
- end.
%%===============================================================================
%%===============================================================================
@@ -1315,49 +1139,74 @@ encode_octet_string(SZ={_,_},false,Val) ->
% [encode_length(SZ,length(Val)),align,
% {octets,Val}];
Len = length(Val),
- [encode_length(SZ,Len),2,
- octets_to_complete(Len,Val)];
+ try
+ [encode_length(SZ,Len),2,
+ octets_to_complete(Len,Val)]
+ catch
+ exit:{error,{asn1,{encode_length,_}}} ->
+ encode_fragmented_octet_string(Val)
+ end;
encode_octet_string(SZ,false,Val) when is_list(SZ) ->
Len = length(Val),
- [encode_length({hd(SZ),lists:max(SZ)},Len),2,
- octets_to_complete(Len,Val)];
+ try
+ [encode_length({hd(SZ),lists:max(SZ)},Len),2,
+ octets_to_complete(Len,Val)]
+ catch
+ exit:{error,{asn1,{encode_length,_}}} ->
+ encode_fragmented_octet_string(Val)
+ end;
+encode_octet_string(Sv,false,Val) when is_integer(Sv) ->
+ encode_fragmented_octet_string(Val);
encode_octet_string(no,false,Val) ->
Len = length(Val),
- [encode_length(undefined,Len),2,
- octets_to_complete(Len,Val)];
+ try
+ [encode_length(undefined,Len),2,
+ octets_to_complete(Len,Val)]
+ catch
+ exit:{error,{asn1,{encode_length,_}}} ->
+ encode_fragmented_octet_string(Val)
+ end;
encode_octet_string(C,_,_) ->
exit({error,{not_implemented,C}}).
-
-decode_octet_string(Bytes,Range) ->
- decode_octet_string(Bytes,Range,false).
-
-decode_octet_string(<<B1,Bytes/bitstring>>,1,false) ->
-%% {B1,Bytes2} = getbits(Bytes,8),
- {[B1],Bytes};
-decode_octet_string(<<B1,B2,Bytes/bitstring>>,2,false) ->
-%% {Bs,Bytes2}= getbits(Bytes,16),
-%% {binary_to_list(<<Bs:16>>),Bytes2};
- {[B1,B2],Bytes};
-decode_octet_string(Bytes,Sv,false) when is_integer(Sv),Sv=<65535 ->
- %% Bytes2 = align(Bytes),
- %% getoctets_as_list aligns buffer before it picks octets
- getoctets_as_list(Bytes,Sv);
-decode_octet_string(Bytes,Sv,false) when is_integer(Sv) ->
- Bytes2 = align(Bytes),
- decode_fragmented_octets(Bytes2,Sv);
-decode_octet_string(Bytes,{Lb,Ub},false) ->
- {Len,Bytes2} = decode_length(Bytes,{Lb,Ub}),
-%% Bytes3 = align(Bytes2),
- getoctets_as_list(Bytes2,Len);
-decode_octet_string(Bytes,Sv,false) when is_list(Sv) ->
- {Len,Bytes2} = decode_length(Bytes,{hd(Sv),lists:max(Sv)}),
-%% Bytes3 = align(Bytes2),
- getoctets_as_list(Bytes2,Len);
-decode_octet_string(Bytes,no,false) ->
- {Len,Bytes2} = decode_length(Bytes,undefined),
-%% Bytes3 = align(Bytes2),
- getoctets_as_list(Bytes2,Len).
+encode_fragmented_octet_string(Val) ->
+ Bin = iolist_to_binary(Val),
+ efos_1(Bin).
+
+efos_1(<<B1:16#C000/binary,B2:16#4000/binary,T/binary>>) ->
+ [20,1,<<3:2,4:6>>,
+ octets_to_complete(16#C000, B1),
+ octets_to_complete(16#4000, B2)|efos_1(T)];
+efos_1(<<B:16#C000/binary,T/binary>>) ->
+ [20,1,<<3:2,3:6>>,octets_to_complete(16#C000, B)|efos_1(T)];
+efos_1(<<B:16#8000/binary,T/binary>>) ->
+ [20,1,<<3:2,2:6>>,octets_to_complete(16#8000, B)|efos_1(T)];
+efos_1(<<B:16#4000/binary,T/binary>>) ->
+ [20,1,<<3:2,1:6>>,octets_to_complete(16#4000, B)|efos_1(T)];
+efos_1(<<>>) ->
+ [20,1,0];
+efos_1(<<B/bitstring>>) ->
+ Len = byte_size(B),
+ [encode_length(undefined, Len),octets_to_complete(Len, B)].
+
+decode_fragmented(SegSz0, Buf0, Unit) ->
+ SegSz = SegSz0 * Unit * ?'16K',
+ <<Res:SegSz/bitstring,Buf/bitstring>> = Buf0,
+ decode_fragmented_1(Buf, Unit, Res).
+
+decode_fragmented_1(<<0:1,N:7,Buf0/bitstring>>, Unit, Res) ->
+ Sz = N*Unit,
+ <<S:Sz/bitstring,Buf/bitstring>> = Buf0,
+ {<<Res/bitstring,S/bitstring>>,Buf};
+decode_fragmented_1(<<1:1,0:1,N:14,Buf0/bitstring>>, Unit, Res) ->
+ Sz = N*Unit,
+ <<S:Sz/bitstring,Buf/bitstring>> = Buf0,
+ {<<Res/bitstring,S/bitstring>>,Buf};
+decode_fragmented_1(<<1:1,1:1,SegSz0:6,Buf0/bitstring>>, Unit, Res0) ->
+ SegSz = SegSz0 * Unit * ?'16K',
+ <<Frag:SegSz/bitstring,Buf/bitstring>> = Buf0,
+ Res = <<Res0/bitstring,Frag/bitstring>>,
+ decode_fragmented_1(Buf, Unit, Res).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1545,16 +1394,6 @@ chars_decode2(Bytes,{Min,Max,CharInTab},NumBits,Len,Acc) ->
chars_decode2(Bytes2,{Min,Max,CharInTab},NumBits,Len -1,[element(Char+1,CharInTab)|Acc]).
- % X.691:17
-encode_null(_Val) -> []. % encodes to nothing
-%encode_null({Name,Val}) when is_atom(Name) ->
-% encode_null(Val).
-
-decode_null(Bytes) ->
- {'NULL',Bytes}.
-
-
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% encode_UTF8String(Val) -> CompleteList
%% Val -> <<utf8encoded binary>>
diff --git a/lib/asn1/src/asn1rt_uper_bin.erl b/lib/asn1/src/asn1rt_uper_bin.erl
index abe178a69e..fc65d80245 100644
--- a/lib/asn1/src/asn1rt_uper_bin.erl
+++ b/lib/asn1/src/asn1rt_uper_bin.erl
@@ -25,22 +25,20 @@
%%-compile(export_all).
- -export([cindex/3, list_to_record/2]).
- -export([setext/1, fixoptionals/3,
+-export([decode_fragmented/3]).
+-export([setext/1, fixoptionals/3,
fixextensions/2,
- getext/1, getextension/2, skipextensions/3, getbit/1, getchoice/3 ]).
- -export([getoptionals2/2, set_choice/3, encode_integer/2, encode_integer/3 ]).
- -export([decode_integer/2, decode_integer/3, encode_small_number/1, encode_boolean/1,
- decode_boolean/1, encode_length/2, decode_length/1, decode_length/2,
- encode_small_length/1, decode_small_length/1,
+ skipextensions/3, getbit/1, getchoice/3 ]).
+-export([set_choice/3, encode_integer/2, encode_integer/3]).
+-export([encode_small_number/1, encode_boolean/1,
+ encode_length/2,
+ encode_small_length/1,
decode_compact_bit_string/3]).
- -export([decode_enumerated/3,
- encode_bit_string/3, decode_bit_string/3 ]).
- -export([encode_octet_string/2, decode_octet_string/2,
- encode_null/1, decode_null/1,
- encode_relative_oid/1, decode_relative_oid/1,
+-export([encode_bit_string/3, decode_bit_string/3 ]).
+-export([encode_octet_string/2,
+ encode_relative_oid/1, decode_relative_oid/1,
encode_object_identifier/1, decode_object_identifier/1,
- encode_real/1, decode_real/1,
+ encode_real/1, decode_real/1,
complete/1, complete_NFP/1]).
@@ -65,19 +63,6 @@
-define('64K',65536).
-cindex(Ix,Val,Cname) ->
- case element(Ix,Val) of
- {Cname,Val2} -> Val2;
- X -> X
- end.
-
-%% converts a list to a record if necessary
-list_to_record(_Name,Tuple) when is_tuple(Tuple) ->
- Tuple;
-list_to_record(Name,List) when is_list(List) ->
- list_to_tuple([Name|List]).
-
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% setext(true|false) -> CompleteList
%%
@@ -113,16 +98,6 @@ fixoptionals([Pos|Ot],Val,Acc) ->
end.
-getext(Bytes) when is_bitstring(Bytes) ->
- getbit(Bytes).
-
-getextension(0, Bytes) ->
- {{},Bytes};
-getextension(1, Bytes) ->
- {Len,Bytes2} = decode_small_length(Bytes),
- {Blist, Bytes3} = getbits_as_list(Len,Bytes2),
- {list_to_tuple(Blist),Bytes3}.
-
fixextensions({ext,ExtPos,ExtNum},Val) ->
case fixextensions(ExtPos,ExtNum+ExtPos,Val,0) of
0 -> [];
@@ -145,14 +120,15 @@ fixextensions(Pos,ExtPos,Val,Acc) ->
end,
fixextensions(Pos+1,ExtPos,Val,(Acc bsl 1)+Bit).
-skipextensions(Bytes,Nr,ExtensionBitPattern) ->
- case (catch element(Nr,ExtensionBitPattern)) of
- 1 ->
+skipextensions(Bytes,Nr,ExtensionBitstr) when is_bitstring(ExtensionBitstr) ->
+ Prev = Nr - 1,
+ case ExtensionBitstr of
+ <<_:Prev,1:1,_/bitstring>> ->
{_,Bytes2} = decode_open_type(Bytes,[]),
- skipextensions(Bytes2, Nr+1, ExtensionBitPattern);
- 0 ->
- skipextensions(Bytes, Nr+1, ExtensionBitPattern);
- {'EXIT',_} -> % badarg, no more extensions
+ skipextensions(Bytes2, Nr+1, ExtensionBitstr);
+ <<_:Prev,0:1,_/bitstring>> ->
+ skipextensions(Bytes, Nr+1, ExtensionBitstr);
+ _ ->
Bytes
end.
@@ -165,11 +141,6 @@ getchoice(Bytes,NumChoices,0) ->
decode_constrained_number(Bytes,{0,NumChoices-1}).
-%%%%%%%%%%%%%%%
-getoptionals2(Bytes,NumOpt) ->
- getbits(Bytes,NumOpt).
-
-
%% getbits_as_binary(Num,Bytes) -> {{Unused,BinBits},RestBytes},
%% Num = integer(),
%% Bytes = list() | tuple(),
@@ -289,33 +260,6 @@ decode_fragmented_bits(<<0:1,Len:7,BitStr/bitstring>>,C,Acc) ->
exit({error,{asn1,{illegal_value,C,ResBitStr}}})
end.
-
-decode_fragmented_octets({0,Bin},C) ->
- decode_fragmented_octets(Bin,C,[]).
-
-decode_fragmented_octets(<<3:2,Len:6,BitStr/bitstring>>,C,Acc) ->
- FragLen = Len * ?'16K',
- <<Value:FragLen/binary,Rest/bitstring>> = BitStr,
- decode_fragmented_octets(Rest,C,[Value|Acc]);
-decode_fragmented_octets(<<0:1,0:7,Bin/bitstring>>,C,Acc) ->
- Octets = list_to_binary(lists:reverse(Acc)),
- case C of
- Int when is_integer(Int), C == size(Octets) ->
- {Octets,Bin};
- Int when is_integer(Int) ->
- exit({error,{asn1,{illegal_value,C,Octets}}})
- end;
-decode_fragmented_octets(<<0:1,Len:7,BitStr/bitstring>>,C,Acc) ->
- <<Value:Len/binary-unit:8,BitStr2/binary>> = BitStr,
- BinOctets = list_to_binary(lists:reverse([Value|Acc])),
- case C of
- Int when is_integer(Int),size(BinOctets) == Int ->
- {BinOctets,BitStr2};
- Int when is_integer(Int) ->
- exit({error,{asn1,{illegal_value,C,BinOctets}}})
- end.
-
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% encode_open_type(Constraint, Value) -> CompleteList
@@ -398,47 +342,6 @@ encode_integer1(C, Val) ->
exit({error,{asn1,{illegal_value,VR,Val}}})
end.
-decode_integer(Buffer,Range,NamedNumberList) ->
- {Val,Buffer2} = decode_integer(Buffer,Range),
- case lists:keysearch(Val,2,NamedNumberList) of
- {value,{NewVal,_}} -> {NewVal,Buffer2};
- _ -> {Val,Buffer2}
- end.
-
-decode_integer(Buffer,[{Rc,_Ec}]) when is_tuple(Rc) ->
- {Ext,Buffer2} = getext(Buffer),
- case Ext of
- 0 -> decode_integer(Buffer2,[Rc]); %% Value in root of constraint
- 1 -> decode_unconstrained_number(Buffer2)
- end;
-decode_integer(Buffer,undefined) ->
- decode_unconstrained_number(Buffer);
-decode_integer(Buffer,C) ->
- case get_constraint(C,'SingleValue') of
- V when is_integer(V) ->
- {V,Buffer};
- V when is_list(V) ->
- {Val,Buffer2} = decode_integer1(Buffer,C),
- case lists:member(Val,V) of
- true ->
- {Val,Buffer2};
- _ ->
- exit({error,{asn1,{illegal_value,Val}}})
- end;
- _ ->
- decode_integer1(Buffer,C)
- end.
-
-decode_integer1(Buffer,C) ->
- case VR = get_constraint(C,'ValueRange') of
- no ->
- decode_unconstrained_number(Buffer);
- {Lb, 'MAX'} ->
- decode_semi_constrained_number(Buffer,Lb);
- {_,_} ->
- decode_constrained_number(Buffer,VR)
- end.
-
%% X.691:10.6 Encoding of a normally small non-negative whole number
%% Use this for encoding of CHOICE index if there is an extension marker in
%% the CHOICE
@@ -455,7 +358,7 @@ decode_small_number(Bytes) ->
0 ->
getbits(Bytes2,6);
1 ->
- decode_semi_constrained_number(Bytes2,0)
+ decode_semi_constrained_number(Bytes2)
end.
%% X.691:10.7 Encoding of a semi-constrained whole number
@@ -479,12 +382,10 @@ encode_semi_constrained_number(Lb,Val) ->
[encode_length(undefined,Size),Bin]
end.
-decode_semi_constrained_number(Bytes,{Lb,_}) ->
- decode_semi_constrained_number(Bytes,Lb);
-decode_semi_constrained_number(Bytes,Lb) ->
+decode_semi_constrained_number(Bytes) ->
{Len,Bytes2} = decode_length(Bytes,undefined),
{V,Bytes3} = getoctets(Bytes2,Len),
- {V+Lb,Bytes3}.
+ {V,Bytes3}.
encode_constrained_number(Range,{Name,Val}) when is_atom(Name) ->
encode_constrained_number(Range,Val);
@@ -566,23 +467,6 @@ enint(-1, [B1|T]) when B1 > 127 ->
enint(N, Acc) ->
enint(N bsr 8, [N band 16#ff|Acc]).
-decode_unconstrained_number(Bytes) ->
- {Len,Bytes2} = decode_length(Bytes,undefined),
- {Ints,Bytes3} = getoctets_as_bin(Bytes2,Len),
- {dec_integer(Ints),Bytes3}.
-
-dec_integer(Bin = <<0:1,_:7,_/bitstring>>) ->
- decpint(Bin);
-dec_integer(<<_:1,B:7,BitStr/bitstring>>) ->
- Size = bit_size(BitStr),
- <<I:Size>> = BitStr,
- (-128 + B) bsl bit_size(BitStr) bor I.
-
-decpint(Bin) ->
- Size = bit_size(Bin),
- <<Int:Size>> = Bin,
- Int.
-
%% X.691:10.9 Encoding of a length determinant
%%encode_small_length(undefined,Len) -> % null means no UpperBound
@@ -597,7 +481,7 @@ encode_length(undefined,Len) -> % un-constrained
Len < 16384 ->
<<2:2,Len:14>>;
true -> % should be able to endode length >= 16384
- exit({error,{asn1,{encode_length,{nyi,above_16k}}}})
+ error({error,{asn1,{encode_length,{nyi,above_16k}}}})
end;
encode_length({0,'MAX'},Len) ->
@@ -623,18 +507,6 @@ encode_small_length(Len) ->
[<<1:1>>,encode_length(undefined,Len)].
-decode_small_length(Buffer) ->
- case getbit(Buffer) of
- {0,Remain} ->
- {Bits,Remain2} = getbits(Remain,6),
- {Bits+1,Remain2};
- {1,Remain} ->
- decode_length(Remain,undefined)
- end.
-
-decode_length(Buffer) ->
- decode_length(Buffer,undefined).
-
%% un-constrained
decode_length(<<0:1,Oct:7,Rest/bitstring>>,undefined) ->
{Oct,Rest};
@@ -677,38 +549,6 @@ encode_boolean({Name,Val}) when is_atom(Name) ->
encode_boolean(Val) ->
exit({error,{asn1,{encode_boolean,Val}}}).
-decode_boolean(Buffer) -> %when record(Buffer,buffer)
- case getbit(Buffer) of
- {1,Remain} -> {true,Remain};
- {0,Remain} -> {false,Remain}
- end.
-
-
-%% ENUMERATED with extension marker
-decode_enumerated(Buffer,C,{Ntup1,Ntup2}) when is_tuple(Ntup1), is_tuple(Ntup2) ->
- {Ext,Buffer2} = getext(Buffer),
- case Ext of
- 0 -> % not an extension value
- {Val,Buffer3} = decode_integer(Buffer2,C),
- case catch (element(Val+1,Ntup1)) of
- NewVal when is_atom(NewVal) -> {NewVal,Buffer3};
- _Error -> exit({error,{asn1,{decode_enumerated,{Val,[Ntup1,Ntup2]}}}})
- end;
- 1 -> % this an extension value
- {Val,Buffer3} = decode_small_number(Buffer2),
- case catch (element(Val+1,Ntup2)) of
- NewVal when is_atom(NewVal) -> {NewVal,Buffer3};
- _ -> {{asn1_enum,Val},Buffer3}
- end
- end;
-
-decode_enumerated(Buffer,C,NamedNumberTup) when is_tuple(NamedNumberTup) ->
- {Val,Buffer2} = decode_integer(Buffer,C),
- case catch (element(Val+1,NamedNumberTup)) of
- NewVal when is_atom(NewVal) -> {NewVal,Buffer2};
- _Error -> exit({error,{asn1,{decode_enumerated,{Val,NamedNumberTup}}}})
- end.
-
%%============================================================================
%%============================================================================
@@ -1067,36 +907,71 @@ encode_octet_string(C,Val) ->
list_to_binary(Val);
2 ->
list_to_binary(Val);
- Sv when Sv =<65535, Sv == length(Val) -> % fixed length
- list_to_binary(Val);
- VR = {_,_} ->
- [encode_length(VR,length(Val)),list_to_binary(Val)];
+ {_,_}=VR ->
+ try
+ [encode_length(VR, length(Val)),list_to_binary(Val)]
+ catch
+ error:{error,{asn1,{encode_length,_}}} ->
+ encode_fragmented_octet_string(Val)
+ end;
+ Sv when is_integer(Sv), Sv =:= length(Val) -> % fixed length
+ if
+ Sv =< 65535 ->
+ list_to_binary(Val);
+ true ->
+ encode_fragmented_octet_string(Val)
+ end;
Sv when is_list(Sv) ->
- [encode_length({hd(Sv),lists:max(Sv)},length(Val)),list_to_binary(Val)];
+ try
+ [encode_length({hd(Sv),lists:max(Sv)},
+ length(Val)),list_to_binary(Val)]
+ catch
+ error:{error,{asn1,{encode_length,_}}} ->
+ encode_fragmented_octet_string(Val)
+ end;
no ->
- [encode_length(undefined,length(Val)),list_to_binary(Val)]
+ try
+ [encode_length(undefined, length(Val)),list_to_binary(Val)]
+ catch
+ error:{error,{asn1,{encode_length,_}}} ->
+ encode_fragmented_octet_string(Val)
+ end
end.
-decode_octet_string(Bytes,C) ->
- decode_octet_string1(Bytes,get_constraint(C,'SizeConstraint')).
-decode_octet_string1(<<B1,Bytes/bitstring>>,1) ->
- {[B1],Bytes};
-decode_octet_string1(<<B1,B2,Bytes/bitstring>>,2) ->
- {[B1,B2],Bytes};
-decode_octet_string1(Bytes,Sv) when is_integer(Sv),Sv=<65535 ->
- getoctets_as_list(Bytes,Sv);
-decode_octet_string1(Bytes,Sv) when is_integer(Sv) ->
- decode_fragmented_octets(Bytes,Sv);
-decode_octet_string1(Bytes,{Lb,Ub}) ->
- {Len,Bytes2} = decode_length(Bytes,{Lb,Ub}),
- getoctets_as_list(Bytes2,Len);
-decode_octet_string1(Bytes,Sv) when is_list(Sv) ->
- {Len,Bytes2} = decode_length(Bytes,{hd(Sv),lists:max(Sv)}),
- getoctets_as_list(Bytes2,Len);
-decode_octet_string1(Bytes,no) ->
- {Len,Bytes2} = decode_length(Bytes,undefined),
- getoctets_as_list(Bytes2,Len).
-
+encode_fragmented_octet_string(Val) ->
+ Bin = list_to_binary(Val),
+ efos_1(Bin).
+
+efos_1(<<B:16#10000/binary,T/binary>>) ->
+ [<<3:2,4:6>>,B|efos_1(T)];
+efos_1(<<B:16#C000/binary,T/binary>>) ->
+ [<<3:2,3:6>>,B|efos_1(T)];
+efos_1(<<B:16#8000/binary,T/binary>>) ->
+ [<<3:2,2:6>>,B|efos_1(T)];
+efos_1(<<B:16#4000/binary,T/binary>>) ->
+ [<<3:2,1:6>>,B|efos_1(T)];
+efos_1(<<B/bitstring>>) ->
+ Len = byte_size(B),
+ [encode_length(undefined, Len),B].
+
+decode_fragmented(SegSz0, Buf0, Unit) ->
+ SegSz = SegSz0 * Unit * ?'16K',
+ <<Res:SegSz/bitstring,Buf/bitstring>> = Buf0,
+ decode_fragmented_1(Buf, Unit, Res).
+
+decode_fragmented_1(<<0:1,N:7,Buf0/bitstring>>, Unit, Res) ->
+ Sz = N*Unit,
+ <<S:Sz/bitstring,Buf/bitstring>> = Buf0,
+ {<<Res/bitstring,S/bitstring>>,Buf};
+decode_fragmented_1(<<1:1,0:1,N:14,Buf0/bitstring>>, Unit, Res) ->
+ Sz = N*Unit,
+ <<S:Sz/bitstring,Buf/bitstring>> = Buf0,
+ {<<Res/bitstring,S/bitstring>>,Buf};
+decode_fragmented_1(<<1:1,1:1,SegSz0:6,Buf0/bitstring>>, Unit, Res0) ->
+ SegSz = SegSz0 * Unit * ?'16K',
+ <<Frag:SegSz/bitstring,Buf/bitstring>> = Buf0,
+ Res = <<Res0/bitstring,Frag/bitstring>>,
+ decode_fragmented_1(Buf, Unit, Res).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1441,12 +1316,6 @@ decode_UTF8String(Bytes) ->
getoctets_as_bin(Bytes2,Len).
- % X.691:17
-encode_null(_) -> []. % encodes to nothing
-
-decode_null(Bytes) ->
- {'NULL',Bytes}.
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% encode_object_identifier(Val) -> CompleteList
%% encode_object_identifier({Name,Val}) -> CompleteList
diff --git a/lib/asn1/test/Makefile b/lib/asn1/test/Makefile
index 6e6374baf1..1794d6bb71 100644
--- a/lib/asn1/test/Makefile
+++ b/lib/asn1/test/Makefile
@@ -83,6 +83,7 @@ MODULES= \
testInfObj \
testParameterizedInfObj \
testMergeCompile \
+ testMultipleLevels \
testDeepTConstr \
testTimer \
testMegaco \
diff --git a/lib/asn1/test/asn1_SUITE.erl b/lib/asn1/test/asn1_SUITE.erl
index b0c37d79e7..325293f35d 100644
--- a/lib/asn1/test/asn1_SUITE.erl
+++ b/lib/asn1/test/asn1_SUITE.erl
@@ -1,3 +1,4 @@
+%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2001-2012. All Rights Reserved.
@@ -19,28 +20,9 @@
-module(asn1_SUITE).
--define(only_per(Func),
- if Rule == per orelse Rule == per_bin -> Func;
- true -> ok
- end).
-define(only_ber(Func),
- if Rule == ber orelse Rule == ber_bin orelse Rule == ber_bin_v2 -> Func;
- true -> ok
- end).
--define(only_uper(Func),
- case Rule of
- uper_bin -> Func;
- _ -> ok
- end).
--define(only_per_nif(Func),
- case {Rule, lists:member(optimize, Opts)} of
- {per_bin, true} -> Func;
- _ -> ok
- end).
--define(only_ber_nif(Func),
- case {Rule, lists:member(nif, Opts)} of
- {ber_bin_v2, true} -> Func;
- _ -> ok
+ if Rule =:= ber -> Func;
+ true -> ok
end).
-compile(export_all).
@@ -54,7 +36,8 @@
suite() -> [{ct_hooks, [ts_install_cth]}].
all() ->
- [{group, parallel},
+ [{group, compile},
+ {group, parallel},
{group, app_test},
{group, appup_test},
@@ -70,21 +53,20 @@ groups() ->
[{compile, parallel([]),
[c_syntax,
c_string,
- c_implicit_before_choice]},
+ c_implicit_before_choice,
+ constraint_equivalence]},
{ber, parallel([]),
[ber_choiceinseq,
% Uses 'SOpttest'
- {group, [], [ber_optional,
- ber_optional_keyed_list]}]},
+ ber_optional]},
{app_test, [], [{asn1_app_test, all}]},
{appup_test, [], [{asn1_appup_test, all}]},
{parallel, parallel([]),
- [{group, compile},
- {group, ber},
+ [{group, ber},
% Uses 'P-Record', 'Constraints', 'MEDIA-GATEWAY-CONTROL'...
{group, [], [parse,
test_driver_load,
@@ -115,6 +97,7 @@ groups() ->
testChoTypeRefPrim,
testChoTypeRefSeq,
testChoTypeRefSet,
+ testMultipleLevels,
testDef,
testOpt,
testSeqDefault,
@@ -197,18 +180,12 @@ groups() ->
testDoubleEllipses,
test_x691,
ticket_6143,
- testExtensionAdditionGroup,
test_OTP_9688]},
{performance, [],
[testTimer_ber,
- testTimer_ber_bin,
- testTimer_ber_bin_opt,
- testTimer_ber_bin_opt_driver,
testTimer_per,
- testTimer_per_bin,
- testTimer_per_bin_opt,
- testTimer_uper_bin,
+ testTimer_uper,
smp]}].
parallel(Options) ->
@@ -242,14 +219,13 @@ init_per_testcase(Func, Config) ->
true = code:add_patha(CaseDir),
Dog = case Func of
- testX420 -> test_server:timetrap({minutes, 90});
- _ -> test_server:timetrap({minutes, 60})
+ testX420 -> ct:timetrap({minutes, 90});
+ _ -> ct:timetrap({minutes, 60})
end,
[{case_dir, CaseDir}, {watchdog, Dog}|Config].
end_per_testcase(_Func, Config) ->
- code:del_path(?config(case_dir, Config)),
- test_server:timetrap_cancel(?config(watchdog, Config)).
+ code:del_path(?config(case_dir, Config)).
%%------------------------------------------------------------------------------
%% Test runners
@@ -257,14 +233,8 @@ end_per_testcase(_Func, Config) ->
test(Config, TestF) ->
test(Config, TestF, [per,
- per_bin,
- {per_bin, [optimize]},
- uper_bin,
- ber,
- ber_bin,
- ber_bin_v2,
- % TODO: {ber_bin_v2, [optimize, nif]} ?
- {ber_bin_v2, [nif]}]).
+ uper,
+ ber]).
test(Config, TestF, Rules) ->
Fun = fun(C, R, O) ->
@@ -342,12 +312,12 @@ testCompactBitString(Config, Rule, Opts) ->
asn1_test_lib:compile("PrimStrings", Config,
[Rule, compact_bit_string|Opts]),
testCompactBitString:compact_bit_string(Rule),
- ?only_uper(testCompactBitString:bit_string_unnamed(Rule)),
- ?only_per(testCompactBitString:bit_string_unnamed(Rule)),
- ?only_per_nif(testCompactBitString:ticket_7734(Rule)),
- ?only_per_nif(asn1_test_lib:compile("Constraints", Config,
- [Rule, compact_bit_string|Opts])),
- ?only_per_nif(testCompactBitString:otp_4869(Rule)).
+ testCompactBitString:bit_string_unnamed(Rule),
+ testCompactBitString:bit_string_unnamed(Rule),
+ testCompactBitString:ticket_7734(Rule),
+ asn1_test_lib:compile("Constraints", Config,
+ [Rule, compact_bit_string|Opts]),
+ testCompactBitString:otp_4869(Rule).
testPrimStrings(Config) -> test(Config, fun testPrimStrings/3).
testPrimStrings(Config, Rule, Opts) ->
@@ -371,10 +341,10 @@ testPrimExternal(Config, Rule, Opts) ->
asn1_test_lib:compile_all(["External", "PrimExternal"], Config,
[Rule|Opts]),
testPrimExternal:external(Rule),
- ?only_ber_nif(asn1_test_lib:compile_all(["PrimStrings", "BitStr"], Config,
+ ?only_ber(asn1_test_lib:compile_all(["PrimStrings", "BitStr"], Config,
[Rule|Opts])),
- ?only_ber_nif(testPrimStrings_cases(Rule)),
- ?only_ber_nif(testPrimStrings:more_strings(Rule)).
+ ?only_ber(testPrimStrings_cases(Rule)),
+ ?only_ber(testPrimStrings:more_strings(Rule)).
testChoPrim(Config) -> test(Config, fun testChoPrim/3).
testChoPrim(Config, Rule, Opts) ->
@@ -399,7 +369,7 @@ testChoOptional(Config, Rule, Opts) ->
testChoOptionalImplicitTag(Config) ->
test(Config, fun testChoOptionalImplicitTag/3,
- [ber, ber_bin, ber_bin_v2]).
+ [ber]).
testChoOptionalImplicitTag(Config, Rule, Opts) ->
%% Only meaningful for ber & co
asn1_test_lib:compile("ChoOptionalImplicitTag", Config, [Rule|Opts]),
@@ -430,6 +400,11 @@ testChoTypeRefSet(Config, Rule, Opts) ->
asn1_test_lib:compile("ChoTypeRefSet", Config, [Rule|Opts]),
testChoTypeRefSet:set(Rule).
+testMultipleLevels(Config) -> test(Config, fun testMultipleLevels/3).
+testMultipleLevels(Config, Rule, Opts) ->
+ asn1_test_lib:compile("MultipleLevels", Config, [Rule|Opts]),
+ testMultipleLevels:main(Rule).
+
testDef(Config) -> test(Config, fun testDef/3).
testDef(Config, Rule, Opts) ->
asn1_test_lib:compile("Def", Config, [Rule|Opts]),
@@ -455,7 +430,8 @@ testSeqExtension(Config) -> test(Config, fun testSeqExtension/3).
testSeqExtension(Config, Rule, Opts) ->
asn1_test_lib:compile_all(["External", "SeqExtension"], Config,
[Rule|Opts]),
- testSeqExtension:main(Rule).
+ DataDir = ?config(data_dir, Config),
+ testSeqExtension:main(DataDir, [Rule|Opts]).
testSeqExternal(Config) -> test(Config, fun testSeqExternal/3).
testSeqExternal(Config, Rule, Opts) ->
@@ -515,8 +491,7 @@ testSeqOfCho(Config, Rule, Opts) ->
testSeqOfCho:main(Rule).
testSeqOfIndefinite(Config) ->
- test(Config, fun testSeqOfIndefinite/3,
- [ber, ber_bin, ber_bin_v2, {ber_bin_v2, [nif]}]).
+ test(Config, fun testSeqOfIndefinite/3, [ber]).
testSeqOfIndefinite(Config, Rule, Opts) ->
Files = ["Mvrasn-Constants-1", "Mvrasn-DataTypes-1", "Mvrasn-21-4",
"Mvrasn-20-4", "Mvrasn-19-4", "Mvrasn-18-4", "Mvrasn-17-4",
@@ -632,29 +607,57 @@ c_syntax(Config) ->
"SeqBadComma"]].
c_string(Config) ->
- test(Config, fun c_string/3, [per, per_bin, ber, ber_bin, ber_bin_v2]).
+ test(Config, fun c_string/3, [per, ber]).
c_string(Config, Rule, Opts) ->
asn1_test_lib:compile("String", Config, [Rule|Opts]).
c_implicit_before_choice(Config) ->
- test(Config, fun c_implicit_before_choice/3,
- [ber, ber_bin, ber_bin_v2]).
+ test(Config, fun c_implicit_before_choice/3, [ber]).
c_implicit_before_choice(Config, Rule, Opts) ->
DataDir = ?config(data_dir, Config),
CaseDir = ?config(case_dir, Config),
{error, _R2} = asn1ct:compile(filename:join(DataDir, "CCSNARG3"),
[Rule, {outdir, CaseDir}|Opts]).
+constraint_equivalence(Config) ->
+ DataDir = ?config(data_dir, Config),
+ CaseDir = ?config(case_dir, Config),
+ Asn1Spec = "ConstraintEquivalence",
+ Asn1Src = filename:join(DataDir, Asn1Spec),
+ ok = asn1ct:compile(Asn1Src, [abs,{outdir,CaseDir}]),
+ AbsFile = filename:join(CaseDir, Asn1Spec++".abs"),
+ {ok,Terms} = file:consult(AbsFile),
+ Cs = [begin
+ 'INTEGER' = element(3, Type), %Assertion.
+ Constraints = element(4, Type),
+ Name1 = atom_to_list(Name0),
+ {Name,_} = lists:splitwith(fun(C) -> C =/= $X end, Name1),
+ {Name,Constraints}
+ end || {typedef,_,_,Name0,Type} <- Terms],
+ R = sofs:relation(Cs, [{name,constraint}]),
+ F0 = sofs:relation_to_family(R),
+ F = sofs:to_external(F0),
+ Diff = [E || {_,L}=E <- F, length(L) > 1],
+ case Diff of
+ [] ->
+ ok;
+ [_|_] ->
+ io:put_chars("Not equivalent:\n"),
+ [io:format("~s: ~p\n", [N,D]) || {N,D} <- Diff],
+ test_server:fail(length(Diff))
+ end.
+
parse(Config) ->
[asn1_test_lib:compile(M, Config, [abs]) || M <- test_modules()].
per(Config) ->
- test(Config, fun per/3, [per, per_bin, {per_bin, [optimize]}]).
+ test(Config, fun per/3, [per,uper]).
per(Config, Rule, Opts) ->
[module_test(M, Config, Rule, Opts) || M <- per_modules()].
ber_other(Config) ->
- test(Config, fun ber_other/3, [ber, ber_bin, ber_bin_v2]).
+ test(Config, fun ber_other/3, [ber]).
+
ber_other(Config, Rule, Opts) ->
[module_test(M, Config, Rule, Opts) || M <- ber_modules()].
@@ -669,12 +672,12 @@ module_test(M, Config, Rule, Opts) ->
ber_choiceinseq(Config) ->
- test(Config, fun ber_choiceinseq/3, [ber, ber_bin, ber_bin_v2]).
+ test(Config, fun ber_choiceinseq/3, [ber]).
ber_choiceinseq(Config, Rule, Opts) ->
asn1_test_lib:compile("ChoiceInSeq", Config, [Rule|Opts]).
ber_optional(Config) ->
- test(Config, fun ber_optional/3, [ber, ber_bin, ber_bin_v2]).
+ test(Config, fun ber_optional/3, [ber]).
ber_optional(Config, Rule, Opts) ->
asn1_test_lib:compile("SOpttest", Config, [Rule|Opts]),
V = {'S', {'A', 10, asn1_NOVALUE, asn1_NOVALUE},
@@ -685,21 +688,6 @@ ber_optional(Config, Rule, Opts) ->
V2 = asn1_wrapper:decode('SOpttest', 'S', Bytes),
V = element(2, V2).
-ber_optional_keyed_list(Config) ->
- test(Config, fun ber_optional_keyed_list/3, [ber, ber_bin]).
-ber_optional_keyed_list(Config, Rule, Opts) ->
- asn1_test_lib:compile("SOpttest", Config, [Rule, keyed_list|Opts]),
- Vrecord = {'S', {'A', 10, asn1_NOVALUE, asn1_NOVALUE},
- {'B', asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE},
- {'C', asn1_NOVALUE, 111, asn1_NOVALUE}},
- V = [{a, [{scriptKey, 10}]},
- {b, []},
- {c, [{callingPartysCategory, 111}]}],
- {ok, B} = asn1_wrapper:encode('SOpttest', 'S', V),
- Bytes = lists:flatten(B),
- V2 = asn1_wrapper:decode('SOpttest', 'S', Bytes),
- Vrecord = element(2, V2).
-
%% records used by test-case default
-record('Def1', {bool0,
bool1 = asn1_DEFAULT,
@@ -734,7 +722,7 @@ value_bad_enum_test(Config) ->
end.
constructed(Config) ->
- test(Config, fun constructed/3, [ber, ber_bin, ber_bin_v2]).
+ test(Config, fun constructed/3, [ber]).
constructed(Config, Rule, Opts) ->
asn1_test_lib:compile("Constructed", Config, [Rule|Opts]),
{ok, B} = asn1_wrapper:encode('Constructed', 'S', {'S', false}),
@@ -745,7 +733,7 @@ constructed(Config, Rule, Opts) ->
[136, 1, 10] = lists:flatten(B2).
ber_decode_error(Config) ->
- test(Config, fun ber_decode_error/3, [ber, ber_bin, ber_bin_v2]).
+ test(Config, fun ber_decode_error/3, [ber]).
ber_decode_error(Config, Rule, Opts) ->
asn1_test_lib:compile("Constructed", Config, [Rule|Opts]),
ber_decode_error:run(Opts).
@@ -758,14 +746,14 @@ h323test(Config, Rule, Opts) ->
h323test:run(Rule).
per_GeneralString(Config) ->
- test(Config, fun per_GeneralString/3, [per, per_bin]).
+ test(Config, fun per_GeneralString/3, [per]).
per_GeneralString(Config, Rule, Opts) ->
asn1_test_lib:compile("MULTIMEDIA-SYSTEM-CONTROL", Config, [Rule|Opts]),
UI = [109, 64, 1, 57],
{ok, _V} = asn1_wrapper:decode('MULTIMEDIA-SYSTEM-CONTROL',
'MultimediaSystemControlMessage', UI).
-per_open_type(Config) -> test(Config, fun per_open_type/3, [per, per_bin]).
+per_open_type(Config) -> test(Config, fun per_open_type/3, [per]).
per_open_type(Config, Rule, Opts) ->
asn1_test_lib:compile("OpenType", Config, [Rule|Opts]),
{ok, _} = asn1ct:test('OpenType', 'Ot', {'Stype', 10, true}).
@@ -778,24 +766,24 @@ testConstraints(Config, Rule, Opts) ->
testSeqIndefinite(Config) ->
- test(Config, fun testSeqIndefinite/3, [ber, ber_bin, ber_bin_v2,
- {ber_bin_v2, [nif]}]).
+ test(Config, fun testSeqIndefinite/3, [ber]).
+
testSeqIndefinite(Config, Rule, Opts) ->
asn1_test_lib:compile("SeqSetIndefinite", Config, [Rule|Opts]),
testSeqIndefinite:main(Rule).
testSetIndefinite(Config) ->
- test(Config, fun testSetIndefinite/3, [ber, ber_bin, ber_bin_v2,
- {ber_bin_v2, [nif]}]).
+ test(Config, fun testSetIndefinite/3, [ber]).
+
testSetIndefinite(Config, Rule, Opts) ->
asn1_test_lib:compile("SeqSetIndefinite", Config, [Rule|Opts]),
testSetIndefinite:main(Rule).
testChoiceIndefinite(Config) ->
- test(Config, fun testChoiceIndefinite/3, [ber, ber_bin, ber_bin_v2,
- {ber_bin_v2, [nif]}]).
+ test(Config, fun testChoiceIndefinite/3, [ber]).
+
testChoiceIndefinite(Config, Rule, Opts) ->
asn1_test_lib:compile("ChoiceIndef", Config, [Rule|Opts]),
testChoiceIndefinite:main(Rule).
@@ -857,7 +845,7 @@ testExport(Config) ->
end.
testImport(Config) ->
- test(Config, fun testImport/3, [ber, ber_bin, ber_bin_v2]).
+ test(Config, fun testImport/3, [ber]).
testImport(Config, Rule, Opts) ->
{error, _} = asn1ct:compile(filename:join(?config(data_dir, Config),
"ImportsFrom"),
@@ -906,8 +894,7 @@ duplicate_tags(Config) ->
{skip, "Runs in asn1_SUITE only"}
end.
-rtUI(Config) -> test(Config, fun rtUI/3, [per, per_bin, ber,
- ber_bin, ber_bin_v2]).
+rtUI(Config) -> test(Config, fun rtUI/3, [per,ber]).
rtUI(Config, Rule, Opts) ->
asn1_test_lib:compile("Prim", Config, [Rule|Opts]),
{ok, _} = asn1rt:info('Prim').
@@ -923,19 +910,19 @@ testINSTANCE_OF(Config, Rule, Opts) ->
testINSTANCE_OF:main(Rule).
testTCAP(Config) ->
- test(Config, fun testTCAP/3,
- [ber, ber_bin, ber_bin_v2, {ber_bin_v2, [nif]}]).
+ test(Config, fun testTCAP/3, [ber]).
testTCAP(Config, Rule, Opts) ->
testTCAP:compile(Config, [Rule|Opts]),
testTCAP:test(Rule, Config),
case Rule of
- ber_bin_v2 -> testTCAP:compile_asn1config(Config, [Rule, asn1config]),
- testTCAP:test_asn1config();
- _ -> ok
+ ber ->
+ testTCAP:compile_asn1config(Config, [Rule, asn1config]),
+ testTCAP:test_asn1config();
+ _ -> ok
end.
testDER(Config) ->
- test(Config, fun testDER/3, [ber, ber_bin, ber_bin_v2]).
+ test(Config, fun testDER/3, [ber]).
testDER(Config, Rule, Opts) ->
asn1_test_lib:compile("DERSpec", Config, [Rule, der|Opts]),
testDER:test(),
@@ -945,7 +932,7 @@ testDER(Config, Rule, Opts) ->
testSeqSetDefaultVal:main(Rule).
specialized_decodes(Config) ->
- test(Config, fun specialized_decodes/3, [ber_bin_v2]).
+ test(Config, fun specialized_decodes/3, [ber]).
specialized_decodes(Config, Rule, Opts) ->
asn1_test_lib:compile_all(["PartialDecSeq.asn",
"PartialDecSeq2.asn",
@@ -953,13 +940,12 @@ specialized_decodes(Config, Rule, Opts) ->
"PartialDecMyHTTP.asn",
"MEDIA-GATEWAY-CONTROL.asn",
"P-Record"],
- Config, [Rule, optimize, asn1config|Opts]),
+ Config, [Rule, asn1config|Opts]),
test_partial_incomplete_decode:test(Config),
test_selective_decode:test().
special_decode_performance(Config) ->
- test(Config, fun special_decode_performance/3,
- [{ber_bin, [optimize]}, {ber_bin_v2, [optimize, nif]}]).
+ test(Config, fun special_decode_performance/3, [ber]).
special_decode_performance(Config, Rule, Opts) ->
Files = ["MEDIA-GATEWAY-CONTROL", "PartialDecSeq"],
asn1_test_lib:compile_all(Files, Config, [Rule, asn1config|Opts]),
@@ -967,19 +953,19 @@ special_decode_performance(Config, Rule, Opts) ->
test_driver_load(Config) ->
- test(Config, fun test_driver_load/3, [{per_bin, [optimize]}]).
+ test(Config, fun test_driver_load/3, [per]).
test_driver_load(Config, Rule, Opts) ->
asn1_test_lib:compile("P-Record", Config, [Rule|Opts]),
test_driver_load:test(5).
test_ParamTypeInfObj(Config) ->
- asn1_test_lib:compile("IN-CS-1-Datatypes", Config, [ber_bin]).
+ asn1_test_lib:compile("IN-CS-1-Datatypes", Config, [ber]).
test_WS_ParamClass(Config) ->
- asn1_test_lib:compile("InformationFramework", Config, [ber_bin]).
+ asn1_test_lib:compile("InformationFramework", Config, [ber]).
test_Defed_ObjectIdentifier(Config) ->
- asn1_test_lib:compile("UsefulDefinitions", Config, [ber_bin]).
+ asn1_test_lib:compile("UsefulDefinitions", Config, [ber]).
testSelectionType(Config) -> test(Config, fun testSelectionType/3).
testSelectionType(Config, Rule, Opts) ->
@@ -987,7 +973,7 @@ testSelectionType(Config, Rule, Opts) ->
{ok, _} = testSelectionTypes:test().
testSSLspecs(Config) ->
- test(Config, fun testSSLspecs/3, [ber, ber_bin, ber_bin_v2, {ber_bin_v2, [optimize]}]).
+ test(Config, fun testSSLspecs/3, [ber]).
testSSLspecs(Config, Rule, Opts) ->
ok = testSSLspecs:compile(Config,
[Rule, compact_bit_string, der|Opts]),
@@ -1011,12 +997,12 @@ test_undecoded_rest(Config, Rule, Opts) ->
ok = test_undecoded_rest:test([], Config),
asn1_test_lib:compile("P-Record", Config, [Rule,undec_rest|Opts]),
case Rule of
- ber_bin_v2 -> ok;
+ ber -> ok;
_ -> test_undecoded_rest:test(undec_rest, Config)
end.
test_inline(Config) ->
- test(Config, fun test_inline/3, [ber, ber_bin, ber_bin_v2]).
+ test(Config, fun test_inline/3, [ber]).
test_inline(Config, Rule, Opts) ->
case code:which(asn1ct) of
cover_compiled ->
@@ -1029,12 +1015,11 @@ test_inline(Config, Rule, Opts) ->
end.
testTcapsystem(Config) ->
- test(Config, fun testTcapsystem/3, [ber, ber_bin, ber_bin_v2]).
+ test(Config, fun testTcapsystem/3, [ber]).
testTcapsystem(Config, Rule, Opts) ->
testTcapsystem:compile(Config, [Rule|Opts]).
-testNBAPsystem(Config) -> test(Config, fun testNBAPsystem/3,
- [per, per_bin, {per_bin, [optimize]}]).
+testNBAPsystem(Config) -> test(Config, fun testNBAPsystem/3, [per]).
testNBAPsystem(Config, Rule, Opts) ->
testNBAPsystem:compile(Config, [Rule|Opts]),
testNBAPsystem:test(Rule, Config).
@@ -1064,21 +1049,23 @@ test_modified_x420(Config) ->
asn1_test_lib:compile_all(Files, Config, [der]),
test_modified_x420:test_io(Config).
+
+testX420() ->
+ [{timetrap,{minutes,90}}].
testX420(Config) ->
- test(Config, fun testX420/3, [ber, ber_bin, ber_bin_v2]).
+ test(Config, fun testX420/3, [ber]).
testX420(Config, Rule, Opts) ->
testX420:compile(Rule, [der|Opts], Config),
ok = testX420:ticket7759(Rule, Config),
testX420:compile(Rule, Opts, Config).
test_x691(Config) ->
- test(Config, fun test_x691/3,
- [per, per_bin, uper_bin, {per_bin, [optimize]}]).
+ test(Config, fun test_x691/3, [per, uper]).
test_x691(Config, Rule, Opts) ->
Files = ["P-RecordA1", "P-RecordA2", "P-RecordA3"],
asn1_test_lib:compile_all(Files, Config, [Rule|Opts]),
test_x691:cases(Rule, case Rule of
- uper_bin -> unaligned;
+ uper -> unaligned;
_ -> aligned
end),
asn1_test_lib:ticket_7708(Config, []),
@@ -1089,14 +1076,14 @@ ticket_6143(Config) ->
testExtensionAdditionGroup(Config) ->
%% FIXME problems with automatic tags [ber_bin], [ber_bin, optimize]
- test(Config, fun testExtensionAdditionGroup/3,
- [per_bin, {per_bin, [optimize]}, uper_bin]).
+ test(Config, fun testExtensionAdditionGroup/3, [per, uper]).
testExtensionAdditionGroup(Config, Rule, Opts) ->
asn1_test_lib:compile("Extension-Addition-Group", Config, [Rule|Opts]),
asn1_test_lib:compile_erlang("extensionAdditionGroup", Config,
[debug_info]),
extensionAdditionGroup:run([Rule|Opts]),
extensionAdditionGroup:run2([Rule|Opts]),
+ extensionAdditionGroup:run3(),
asn1_test_lib:compile("EUTRA-RRC-Definitions", Config, [Rule, {record_name_prefix, "RRC-"}|Opts]),
extensionAdditionGroup:run3([Rule|Opts]).
@@ -1179,46 +1166,17 @@ timer_compile(Config, Rule, Opts) ->
asn1_test_lib:compile_all(["H235-SECURITY-MESSAGES", "H323-MESSAGES"],
Config, [Rule|Opts]).
-testTimer_ber(suite) -> [];
testTimer_ber(Config) ->
timer_compile(Config,ber,[]),
testTimer:go(Config,ber).
-testTimer_ber_bin(suite) -> [];
-testTimer_ber_bin(Config) ->
- timer_compile(Config,ber_bin,[]),
- testTimer:go(Config,ber_bin).
-
-testTimer_ber_bin_opt(suite) -> [];
-testTimer_ber_bin_opt(Config) ->
- timer_compile(Config,ber_bin,[optimize]),
- testTimer:go(Config,ber_bin).
-
-testTimer_ber_bin_opt_driver(suite) -> [];
-testTimer_ber_bin_opt_driver(Config) ->
- timer_compile(Config,ber_bin,[optimize,driver]),
- testTimer:go(Config,ber_bin).
-
-testTimer_per(suite) -> [];
testTimer_per(Config) ->
timer_compile(Config,per,[]),
testTimer:go(Config,per).
-testTimer_per_bin(suite) -> [];
-testTimer_per_bin(Config) ->
- timer_compile(Config,per_bin,[]),
- testTimer:go(Config,per_bin).
-
-testTimer_per_bin_opt(suite) -> [];
-testTimer_per_bin_opt(Config) ->
- timer_compile(Config,per_bin,[optimize]),
- testTimer:go(Config,per_bin).
-
-
-testTimer_uper_bin(suite) -> [];
-testTimer_uper_bin(Config) ->
- timer_compile(Config,uper_bin,[]),
- {comment,_} = testTimer:go(Config,uper_bin).
+testTimer_uper(Config) ->
+ timer_compile(Config,uper,[]),
+ {comment,_} = testTimer:go(Config,uper).
%% Test of multiple-line comment, OTP-8043
testComment(suite) -> [];
@@ -1261,11 +1219,11 @@ testName2Number(Config) ->
ok.
ticket_7407(Config) ->
- asn1_test_lib:compile("EUTRA-extract-7407", Config, [uper_bin]),
+ asn1_test_lib:compile("EUTRA-extract-7407", Config, [uper]),
asn1_test_lib:ticket_7407_code(true),
asn1_test_lib:compile("EUTRA-extract-7407", Config,
- [uper_bin, no_final_padding]),
+ [uper, no_final_padding]),
asn1_test_lib:ticket_7407_code(false).
smp(suite) -> [];
@@ -1276,7 +1234,7 @@ smp(Config) ->
io:format("smp starting ~p workers\n",[NumOfProcs]),
Msg = {initiatingMessage, testNBAPsystem:cell_setup_req_msg()},
- ok = testNBAPsystem:compile(Config, [per_bin, optimize]),
+ ok = testNBAPsystem:compile(Config, [per]),
enc_dec(NumOfProcs,Msg,2),
@@ -1285,7 +1243,7 @@ smp(Config) ->
{Time1,ok} = timer:tc(?MODULE,enc_dec,[NumOfProcs,Msg, N]),
{Time1S,ok} = timer:tc(?MODULE,enc_dec,[1, Msg, NumOfProcs * N]),
- ok = testNBAPsystem:compile(Config, [ber_bin, optimize, nif]),
+ ok = testNBAPsystem:compile(Config, [ber]),
{Time3,ok} = timer:tc(?MODULE,enc_dec,[NumOfProcs,Msg, N]),
{Time3S,ok} = timer:tc(?MODULE,enc_dec,[1, Msg, NumOfProcs * N]),
@@ -1306,10 +1264,8 @@ per_performance(Config) ->
file:make_dir(NifDir),file:make_dir(ErlDir),
Msg = {initiatingMessage, testNBAPsystem:cell_setup_req_msg()},
- ok = testNBAPsystem:compile([{priv_dir,NifDir}|Config],
- [per_bin, optimize]),
- ok = testNBAPsystem:compile([{priv_dir,ErlDir}|Config],
- [per_bin]),
+ ok = testNBAPsystem:compile([{priv_dir,NifDir}|Config], [per]),
+ ok = testNBAPsystem:compile([{priv_dir,ErlDir}|Config], [per]),
Modules = ['NBAP-CommonDataTypes',
'NBAP-Constants',
@@ -1347,7 +1303,7 @@ per_performance(Config) ->
ber_performance(Config) ->
Msg = {initiatingMessage, testNBAPsystem:cell_setup_req_msg()},
- ok = testNBAPsystem:compile(Config, [ber_bin, optimize, nif]),
+ ok = testNBAPsystem:compile(Config, [ber]),
BerFun = fun() ->
@@ -1521,7 +1477,7 @@ pforeach(_Fun,[],[]) ->
-record('Iu-ReleaseCommand',{first,second}).
ticket7904(Config) ->
- asn1_test_lib:compile("RANAPextract1", Config, [per_bin, optimize]),
+ asn1_test_lib:compile("RANAPextract1", Config, [per]),
Val1 = #'InitiatingMessage'{procedureCode=1,
criticality=ignore,
diff --git a/lib/asn1/test/asn1_SUITE_data/ConstraintEquivalence.asn1 b/lib/asn1/test/asn1_SUITE_data/ConstraintEquivalence.asn1
new file mode 100644
index 0000000000..6a97c1b38e
--- /dev/null
+++ b/lib/asn1/test/asn1_SUITE_data/ConstraintEquivalence.asn1
@@ -0,0 +1,42 @@
+ConstraintEquivalence DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+ SingleValueX42 ::= INTEGER (42)
+ SingleValueX1 ::= INTEGER ((42) ^ (42))
+ SingleValueX2 ::= INTEGER ((42) INTERSECTION (42))
+ SingleValueX3 ::= INTEGER ((42) | (42))
+ SingleValueX4 ::= INTEGER ((42) UNION (42))
+ SingleValueX5 ::= INTEGER ((42) INTERSECTION (MIN..MAX))
+ SingleValueX6 ::= INTEGER ((42) INTERSECTION (40..49))
+ SingleValueX7 ::= INTEGER (42..42)
+
+ UnconstrainedX0 ::= INTEGER
+ UnconstrainedX1 ::= INTEGER (MIN..MAX)
+ UnconstrainedX2 ::= INTEGER (1|(MIN..MAX))
+ UnconstrainedX3 ::= INTEGER (1..10|(MIN..MAX))
+ UnconstrainedX4 ::= INTEGER ((MIN..MAX)|9|10)
+ UnconstrainedX5 ::= INTEGER ((MIN..MAX)|10..20)
+ UnconstrainedX6 ::= INTEGER ((MIN..MAX) UNION (10..20))
+
+ RangeX00 ::= INTEGER (5..10)
+ RangeX01 ::= INTEGER (4<..<11)
+ RangeX02 ::= INTEGER (5..<11)
+ RangeX03 ::= INTEGER (4<..10)
+ RangeX04 ::= INTEGER (5|6|7|8|9|10)
+ RangeX05 ::= INTEGER (10|9|8|7|6|5)
+ RangeX06 ::= INTEGER (5|6|7..10)
+
+ RangeX10 ::= INTEGER ((5..6) UNION (7..8) UNION (9|10))
+ RangeX11 ::= INTEGER ((5|6) UNION (7..8) UNION (9|10))
+ RangeX12 ::= INTEGER ((5|6) UNION (7|8) UNION (9|10))
+ RangeX13 ::= INTEGER ((5|6) UNION (7) UNION (8..10))
+ RangeX14 ::= INTEGER ((5|6) UNION (7) UNION (8..10))
+ RangeX15 ::= INTEGER ((5|6) UNION (7) UNION ((8..8)|(9..9)|(10)))
+ RangeX16 ::= INTEGER ((5|6) UNION (7) UNION (7<..<11))
+
+ RangeX20 ::= INTEGER (0..20) (5..10)
+ RangeX21 ::= INTEGER (0..10) (5..20)
+ RangeX22 ::= INTEGER (0..10) (5..20) (MIN..MAX)
+ RangeX23 ::= INTEGER ((0..10) INTERSECTION (5..20) ^ (MIN..MAX))
+ RangeX24 ::= INTEGER ((5|6|7|8|9|10) INTERSECTION (5..20) ^ (MIN..MAX))
+
+END
diff --git a/lib/asn1/test/asn1_SUITE_data/Extension-Addition-Group.asn b/lib/asn1/test/asn1_SUITE_data/Extension-Addition-Group.asn
index 55124f9449..b7cc74ab07 100644
--- a/lib/asn1/test/asn1_SUITE_data/Extension-Addition-Group.asn
+++ b/lib/asn1/test/asn1_SUITE_data/Extension-Addition-Group.asn
@@ -95,6 +95,27 @@ AS-Config ::= SEQUENCE {
]]
}
+SystemInformationBlockType2 ::= SEQUENCE {
+ timeAlignmentTimerCommon TimeAlignmentTimer,
+ ...,
+ lateNonCriticalExtension OCTET STRING OPTIONAL,
+ [[ ssac-BarringForMMTEL-Voice-r9 AC-BarringConfig OPTIONAL,
+ ssac-BarringForMMTEL-Video-r9 AC-BarringConfig OPTIONAL
+ ]],
+ [[ ac-BarringForCSFB-r10 AC-BarringConfig OPTIONAL
+ ]]
+}
+
+TimeAlignmentTimer ::= ENUMERATED {
+ sf500, sf750, sf1280, sf1920, sf2560, sf5120,
+ sf10240, infinity}
+AC-BarringConfig ::= SEQUENCE {
+ ac-BarringFactor ENUMERATED {
+ p00, p05, p10, p15, p20, p25, p30, p40,
+ p50, p60, p70, p75, p80, p85, p90, p95},
+ ac-BarringTime ENUMERATED {s4, s8, s16, s32, s64, s128, s256, s512},
+ ac-BarringForSpecialAC BIT STRING (SIZE(5))
+}
END
diff --git a/lib/asn1/test/asn1_SUITE_data/MultipleLevels.asn b/lib/asn1/test/asn1_SUITE_data/MultipleLevels.asn
new file mode 100644
index 0000000000..1824e1fa5a
--- /dev/null
+++ b/lib/asn1/test/asn1_SUITE_data/MultipleLevels.asn
@@ -0,0 +1,19 @@
+MultipleLevels DEFINITIONS AUTOMATIC TAGS ::=
+
+BEGIN
+
+Top ::= SEQUENCE {
+ country CountryName,
+ region Name
+}
+
+CountryName ::= CountryName0
+
+CountryName0 ::= Name
+
+Name ::= CHOICE {
+ short PrintableString (SIZE (0..10)),
+ long PrintableString
+}
+
+END
diff --git a/lib/asn1/test/asn1_SUITE_data/PartialDecSeq.asn1config b/lib/asn1/test/asn1_SUITE_data/PartialDecSeq.asn1config
index 19fa3c990e..d388f6cd02 100644
--- a/lib/asn1/test/asn1_SUITE_data/PartialDecSeq.asn1config
+++ b/lib/asn1/test/asn1_SUITE_data/PartialDecSeq.asn1config
@@ -17,6 +17,6 @@
{decode_D_incomplete,['D',[{a,undecoded}]]},
{decode_F_fb_exclusive2,['F',[{fb,[{b,parts},{d,[{da,parts}]}]}]]}, {decode_F_fb_exclusive3,['F',[{fb,[{b,parts},{d,[{da,parts},{dc,[{dcc,undecoded}]}]}]}]]}]}}.
{module_name,'Seq.asn1'}.
-{compile_options,[ber_bin,optimize,debug_info]}.
+{compile_options,[ber,debug_info]}.
{multifile_compile,['M1.asn','M2.asn']}.
diff --git a/lib/asn1/test/asn1_SUITE_data/PrimStrings.asn1 b/lib/asn1/test/asn1_SUITE_data/PrimStrings.asn1
index d287840f30..9b6b34a776 100644
--- a/lib/asn1/test/asn1_SUITE_data/PrimStrings.asn1
+++ b/lib/asn1/test/asn1_SUITE_data/PrimStrings.asn1
@@ -55,6 +55,32 @@ BS1024 ::= BIT STRING (SIZE (1024))
OsExpCon ::= [60] EXPLICIT OCTET STRING
OsExpPri ::= [PRIVATE 61] EXPLICIT OCTET STRING
OsExpApp ::= [APPLICATION 62] EXPLICIT OCTET STRING
+ OsFrag ::= OCTET STRING (SIZE (0..100000))
+ FixedOs65536 ::= OCTET STRING (SIZE (65536))
+ FixedOs65537 ::= OCTET STRING (SIZE (65537))
+
+ OsFixedStrings ::= SEQUENCE {
+ b1 BOOLEAN, -- Unalign
+ s0 OCTET STRING (SIZE (0)),
+ s1 OCTET STRING (SIZE (1)),
+ s2 OCTET STRING (SIZE (2)),
+ s3 OCTET STRING (SIZE (3)),
+ b2 BOOLEAN, -- Unalign
+ s255 OCTET STRING (SIZE (255)),
+ s256 OCTET STRING (SIZE (256)),
+ s257 OCTET STRING (SIZE (257)),
+ i INTEGER (0..1024)
+ }
+
+ OsAlignment ::= SEQUENCE {
+ b1 BOOLEAN,
+ s1 Os,
+ b2 BOOLEAN,
+ s2 OsFrag,
+ b3 BOOLEAN,
+ s3 FixedOs65536,
+ i INTEGER (0..63)
+ }
Ns ::= NumericString
NsCon ::= [70] NumericString
diff --git a/lib/asn1/test/asn1_SUITE_data/SeqExtension.asn1 b/lib/asn1/test/asn1_SUITE_data/SeqExtension.asn1
index bb0a7cca3a..5fda19303a 100644
--- a/lib/asn1/test/asn1_SUITE_data/SeqExtension.asn1
+++ b/lib/asn1/test/asn1_SUITE_data/SeqExtension.asn1
@@ -31,7 +31,35 @@ SeqExt4 ::= SEQUENCE
int INTEGER
}
+SeqExt5 ::= SEQUENCE
+{
+ ...,
+ [[ name OCTET STRING (SIZE (1..8)),
+ shoesize INTEGER ]]
+}
+
+SeqExt6 ::= SEQUENCE
+{
+ -- The spaces between the ellipsis and the comma will prevent them
+ -- from being removed.
+ ... ,
+ [[ i1 [100] INTEGER, i2 [101] INTEGER, i3 [102] INTEGER ]],
+ [[ i4 [104] INTEGER, i5 [105] INTEGER ]],
+ [[ i6 [106] INTEGER, i7 [107] INTEGER ]]
+}
+
SeqExt1X ::= XSeqExt1
SeqExt2X ::= XSeqExt2
+SuperSeq ::= SEQUENCE
+{
+ s1 SeqExt1,
+ s2 SeqExt2,
+ s3 SeqExt3,
+ s4 SeqExt4,
+ s5 SeqExt5,
+ s6 SeqExt6,
+ i INTEGER
+}
+
END
diff --git a/lib/asn1/test/asn1_SUITE_data/extensionAdditionGroup.erl b/lib/asn1/test/asn1_SUITE_data/extensionAdditionGroup.erl
index 5fcec23756..8148381d92 100644
--- a/lib/asn1/test/asn1_SUITE_data/extensionAdditionGroup.erl
+++ b/lib/asn1/test/asn1_SUITE_data/extensionAdditionGroup.erl
@@ -130,3 +130,26 @@ run3(Erule) ->
_ -> exit({expected,Val, got, Val2})
end.
+run3() ->
+ SI = #'SystemInformationBlockType2'{
+ timeAlignmentTimerCommon = sf500,
+ lateNonCriticalExtension = asn1_NOVALUE,
+ 'ssac-BarringForMMTEL-Voice-r9' = asn1_NOVALUE,
+ 'ssac-BarringForMMTEL-Video-r9' = asn1_NOVALUE,
+ 'ac-BarringForCSFB-r10' = asn1_NOVALUE},
+ Barring = #'AC-BarringConfig'{
+ 'ac-BarringFactor' = p00,
+ 'ac-BarringTime' = s4,
+ 'ac-BarringForSpecialAC' = [0,0,0,0,0]},
+ roundtrip(SI),
+ roundtrip(SI#'SystemInformationBlockType2'{
+ 'ssac-BarringForMMTEL-Voice-r9'=Barring}),
+ roundtrip(SI#'SystemInformationBlockType2'{
+ 'ssac-BarringForMMTEL-Video-r9'=Barring}),
+ roundtrip(SI#'SystemInformationBlockType2'{
+ 'ac-BarringForCSFB-r10'=Barring}).
+
+roundtrip(V) ->
+ Mod = 'Extension-Addition-Group',
+ {ok,E} = Mod:encode('SystemInformationBlockType2', V),
+ {ok,V} = Mod:decode('SystemInformationBlockType2', iolist_to_binary(E)).
diff --git a/lib/asn1/test/asn1_SUITE_data/testobj.erl b/lib/asn1/test/asn1_SUITE_data/testobj.erl
index be7ceee7d1..d9f60ca8a3 100644
--- a/lib/asn1/test/asn1_SUITE_data/testobj.erl
+++ b/lib/asn1/test/asn1_SUITE_data/testobj.erl
@@ -883,7 +883,7 @@ initial_ue_ies() ->
cn_domain_indicator() ->
- {'CN-DomainIndicator', 'ps-domain'}.
+ 'ps-domain'.
init_lai() ->
#'ProtocolIE-Field'{
@@ -1279,11 +1279,11 @@ reset() ->
protocolIEs = reset_ies()
}.
reset_ies() ->
- {'Reset_protocolIEs', % this identifier is very unneccesary here
- [reset_cause(),
- cn_domain_ind(), % Se initial Ue
- init_global_rnc_id() % ---- " ----
- ]}.
+ [reset_cause(),
+ cn_domain_ind(), % Se initial Ue
+ init_global_rnc_id() % ---- " ----
+ ].
+
init_global_rnc_id() ->
#'ProtocolIE-Field'{
id = 86, % 86 = id-GlobalRNC-ID
@@ -1323,8 +1323,7 @@ reset_ack() ->
protocolIEs = reset_ack_ies()
}.
reset_ack_ies() ->
- {'ResetAcknowledge_protocolIEs', % very unneccesary
- [cn_domain_ind()]}. % Se initial Ue
+ [cn_domain_ind()]. % Se initial Ue
@@ -1336,13 +1335,12 @@ reset_res(IuSCId) ->
}.
reset_res_ies(IuSCId) ->
- {'ResetResource_protocolIEs', % very unneccesary
- [
- cn_domain_ind() % Se initial Ue
- ,reset_cause() % Se reset
- ,reset_res_list(IuSCId)
- ,init_global_rnc_id_reset_res() % ---- " ----
- ]}.
+ [
+ cn_domain_ind() % Se initial Ue
+ ,reset_cause() % Se reset
+ ,reset_res_list(IuSCId)
+ ,init_global_rnc_id_reset_res() % ---- " ----
+ ].
init_global_rnc_id_reset_res() ->
#'ProtocolIE-Field'{
@@ -1420,24 +1418,7 @@ wrapper_encode(Module,Type,Value) ->
Error
end.
-wrapper_decode(Module,Type,Bytes) ->
- case Module:encoding_rule() of
- ber ->
- asn1rt:decode(Module,Type,Bytes);
- ber_bin when binary(Bytes) ->
- asn1rt:decode(Module,Type,Bytes);
- ber_bin ->
- asn1rt:decode(Module,Type,list_to_binary(Bytes));
- ber_bin_v2 when binary(Bytes) ->
- asn1rt:decode(Module,Type,Bytes);
- ber_bin_v2 ->
- asn1rt:decode(Module,Type,list_to_binary(Bytes));
- per ->
- asn1rt:decode(Module,Type,Bytes);
- per_bin when binary(Bytes) ->
- asn1rt:decode(Module,Type,Bytes);
- per_bin ->
- asn1rt:decode(Module,Type,list_to_binary(Bytes));
- uper_bin ->
- asn1rt:decode(Module,Type,list_to_binary(Bytes))
- end.
+wrapper_decode(Module, Type, Bytes) when is_binary(Bytes) ->
+ asn1rt:decode(Module, Type, Bytes);
+wrapper_decode(Module, Type, Bytes) when is_list(Bytes) ->
+ asn1rt:decode(Module, Type, list_to_binary(Bytes)).
diff --git a/lib/asn1/test/asn1_app_test.erl b/lib/asn1/test/asn1_app_test.erl
index 2c31c3259d..9dbe1b50e0 100644
--- a/lib/asn1/test/asn1_app_test.erl
+++ b/lib/asn1/test/asn1_app_test.erl
@@ -138,7 +138,8 @@ check_asn1ct_modules(Extra) ->
asn1ct_name,asn1ct_constructed_per,asn1ct_constructed_ber,
asn1ct_gen_ber,asn1ct_constructed_ber_bin_v2,
asn1ct_gen_ber_bin_v2,asn1ct_value,
- asn1ct_tok,asn1ct_parser2,asn1ct_table],
+ asn1ct_tok,asn1ct_parser2,asn1ct_table,
+ asn1ct_imm],
case Extra -- ASN1CTMods of
[] ->
ok;
diff --git a/lib/asn1/test/asn1_test_lib.erl b/lib/asn1/test/asn1_test_lib.erl
index 96c04a9436..fda635d0eb 100644
--- a/lib/asn1/test/asn1_test_lib.erl
+++ b/lib/asn1/test/asn1_test_lib.erl
@@ -87,14 +87,14 @@ ticket_7407_compile(Config,Option) ->
?line OutDir = ?config(priv_dir,Config),
?line ok = asn1ct:compile(DataDir ++ "EUTRA-extract-7407",
- [uper_bin, {outdir,OutDir}]++Option).
+ [uper, {outdir,OutDir}]++Option).
ticket_7708(Config,Option) ->
?line DataDir = ?config(data_dir,Config),
?line OutDir = ?config(priv_dir,Config),
?line ok = asn1ct:compile(DataDir ++ "EUTRA-extract-55",
- [uper_bin, {outdir,OutDir}]++Option).
+ [uper, {outdir,OutDir}]++Option).
ticket_7407_code(FinalPadding) ->
@@ -154,7 +154,7 @@ ticket_7678(Config, Option) ->
?line OutDir = ?config(priv_dir,Config),
?line ok = asn1ct:compile(DataDir ++ "UPERDefault",
- [uper_bin, {outdir,OutDir}]++Option),
+ [uper, {outdir,OutDir}]++Option),
?line Val = 'UPERDefault':seq(),
?line {ok,<<0,6,0>>} = 'UPERDefault':encode('Seq',Val),
@@ -167,12 +167,12 @@ ticket_7763(Config) ->
?line OutDir = ?config(priv_dir,Config),
?line ok = asn1ct:compile(DataDir ++ "EUTRA-extract-55",
- [uper_bin, {outdir,OutDir}]),
+ [uper, {outdir,OutDir}]),
Val = {'Seq',15,lists:duplicate(8,0),[0],lists:duplicate(28,0),15,true},
?line {ok,Bin} = 'EUTRA-extract-55':encode('Seq',Val),
?line ok = asn1ct:compile(DataDir ++ "EUTRA-extract-55",
- [uper_bin,compact_bit_string,{outdir,OutDir}]),
+ [uper,compact_bit_string,{outdir,OutDir}]),
CompactVal = {'Seq',15,{0,<<0>>},{7,<<0>>},{4,<<0,0,0,0>>},15,true},
{ok,CompactBin} = 'EUTRA-extract-55':encode('Seq',CompactVal),
diff --git a/lib/asn1/test/asn1_wrapper.erl b/lib/asn1/test/asn1_wrapper.erl
index d515b99ac2..e764d8b4ca 100644
--- a/lib/asn1/test/asn1_wrapper.erl
+++ b/lib/asn1/test/asn1_wrapper.erl
@@ -34,41 +34,16 @@ encode(Module,Type,Value) ->
Error
end.
-decode(Module,Type,Bytes) ->
- case Module:encoding_rule() of
- ber ->
- asn1rt:decode(Module,Type,Bytes);
- ber_bin when is_binary(Bytes) ->
- asn1rt:decode(Module,Type,Bytes);
- ber_bin ->
- asn1rt:decode(Module,Type,list_to_binary(Bytes));
- ber_bin_v2 when is_binary(Bytes) ->
- asn1rt:decode(Module,Type,Bytes);
- ber_bin_v2 ->
- asn1rt:decode(Module,Type,list_to_binary(Bytes));
- per ->
- asn1rt:decode(Module,Type,Bytes);
- per_bin when is_binary(Bytes) ->
- asn1rt:decode(Module,Type,Bytes);
- per_bin ->
- asn1rt:decode(Module,Type,list_to_binary(Bytes));
- uper_bin when is_binary(Bytes) ->
- asn1rt:decode(Module,Type,Bytes);
- uper_bin ->
- asn1rt:decode(Module,Type,list_to_binary(Bytes))
- end.
+decode(Module, Type, Bytes) when is_binary(Bytes) ->
+ asn1rt:decode(Module, Type, Bytes);
+decode(Module, Type, Bytes) when is_list(Bytes) ->
+ asn1rt:decode(Module, Type, list_to_binary(Bytes)).
erule(ber) ->
ber;
-erule(ber_bin) ->
- ber;
-erule(ber_bin_v2) ->
- ber;
erule(per) ->
per;
-erule(per_bin) ->
- per;
-erule(uper_bin) ->
+erule(uper) ->
per.
diff --git a/lib/asn1/test/h323test.erl b/lib/asn1/test/h323test.erl
index b7a7d6e4df..426ae16994 100644
--- a/lib/asn1/test/h323test.erl
+++ b/lib/asn1/test/h323test.erl
@@ -22,7 +22,6 @@
-export([run/1]).
-include_lib("test_server/include/test_server.hrl").
-run(per_bin) -> run();
run(per) -> run();
run(_Rules) -> ok.
diff --git a/lib/asn1/test/testChoExtension.erl b/lib/asn1/test/testChoExtension.erl
index b75cfb6831..067d4d2bf7 100644
--- a/lib/asn1/test/testChoExtension.erl
+++ b/lib/asn1/test/testChoExtension.erl
@@ -25,42 +25,27 @@
extension(_Rules) ->
-
- ?line {ok,Bytes1} = asn1_wrapper:encode('ChoExtension','ChoExt1',{'ChoExt1',{bool,true}}),
- ?line {ok,{bool,true}} =
- asn1_wrapper:decode('ChoExtension','ChoExt1',lists:flatten(Bytes1)),
-
- ?line {ok,Bytes2} = asn1_wrapper:encode('ChoExtension','ChoExt1',{'ChoExt1',{int,33}}),
- ?line {ok,{int,33}} =
- asn1_wrapper:decode('ChoExtension','ChoExt1',lists:flatten(Bytes2)),
+ roundtrip('ChoExt1', {bool,true}),
+ roundtrip('ChoExt1', {int,33}),
%% A trick to encode with another compatible CHOICE type to test reception
%% extension alternative
- ?line {ok,Bytes2x} = asn1_wrapper:encode('ChoExtension','ChoExt1x',{str,"abc"}),
- ?line {ok,Val2x} =
+ {ok,Bytes2x} = asn1_wrapper:encode('ChoExtension','ChoExt1x',{str,"abc"}),
+ {ok,Val2x} =
asn1_wrapper:decode('ChoExtension','ChoExt1',lists:flatten(Bytes2x)),
io:format("Choice extension alternative = ~p~n",[Val2x]),
- ?line {ok,Bytes3} = asn1_wrapper:encode('ChoExtension','ChoExt2',{'ChoExt2',{bool,true}}),
- ?line {ok,{bool,true}} =
- asn1_wrapper:decode('ChoExtension','ChoExt2',lists:flatten(Bytes3)),
-
- ?line {ok,Bytes4} = asn1_wrapper:encode('ChoExtension','ChoExt2',{'ChoExt2',{int,33}}),
- ?line {ok,{int,33}} =
- asn1_wrapper:decode('ChoExtension','ChoExt2',lists:flatten(Bytes4)),
+ roundtrip('ChoExt2', {bool,true}),
+ roundtrip('ChoExt2', {int,33}),
+ roundtrip('ChoExt3', {bool,true}),
+ roundtrip('ChoExt3', {int,33}),
+ roundtrip('ChoExt4', {str,"abc"}),
- ?line {ok,Bytes5} = asn1_wrapper:encode('ChoExtension','ChoExt3',{'ChoExt3',{bool,true}}),
- ?line {ok,{bool,true}} =
- asn1_wrapper:decode('ChoExtension','ChoExt3',lists:flatten(Bytes5)),
-
- ?line {ok,Bytes6} = asn1_wrapper:encode('ChoExtension','ChoExt3',{'ChoExt3',{int,33}}),
- ?line {ok,{int,33}} =
- asn1_wrapper:decode('ChoExtension','ChoExt3',lists:flatten(Bytes6)),
-
- Val7 = {str,"abc"},
- ?line {ok,Bytes7} = asn1_wrapper:encode('ChoExtension','ChoExt4',Val7),
- ?line {ok,Val7} = asn1_wrapper:decode('ChoExtension','ChoExt4',lists:flatten(Bytes7)),
+ ok.
+roundtrip(Type, Value) ->
+ {ok,Encoded} = 'ChoExtension':encode(Type, Value),
+ {ok,Value} = 'ChoExtension':decode(Type, Encoded),
ok.
diff --git a/lib/asn1/test/testChoExternal.erl b/lib/asn1/test/testChoExternal.erl
index b2d171f9c7..5fdee48add 100644
--- a/lib/asn1/test/testChoExternal.erl
+++ b/lib/asn1/test/testChoExternal.erl
@@ -38,62 +38,27 @@ compile(Config, Rules, Optimize) ->
external(_Rules) ->
+ roundtrip('ChoXCho', {boolCho,true}),
+ roundtrip('ChoXCho', {intCho,77}),
- ?line {ok,Bytes11} = asn1_wrapper:encode('ChoExternal','ChoXCho',{'ChoXCho',{boolCho,true}}),
- ?line {ok,{boolCho,true}} = asn1_wrapper:decode('ChoExternal','ChoXCho',lists:flatten(Bytes11)),
-
-
- ?line {ok,Bytes12} = asn1_wrapper:encode('ChoExternal','ChoXCho',{'ChoXCho',{intCho,77}}),
- ?line {ok,{intCho,77}} = asn1_wrapper:decode('ChoExternal','ChoXCho',lists:flatten(Bytes12)),
-
-
-
- ?line {ok,Bytes21} = asn1_wrapper:encode('ChoExternal','ChoXBool',{'ChoXBool',{xbool,true}}),
- ?line {ok,{xbool,true}} = asn1_wrapper:decode('ChoExternal','ChoXBool',lists:flatten(Bytes21)),
-
-
- ?line {ok,Bytes22} = asn1_wrapper:encode('ChoExternal','ChoXBool',{'ChoXBool',{xboolImp,true}}),
- ?line {ok,{xboolImp,true}} = asn1_wrapper:decode('ChoExternal','ChoXBool',lists:flatten(Bytes22)),
-
-
- ?line {ok,Bytes23} = asn1_wrapper:encode('ChoExternal','ChoXBool',{'ChoXBool',{xboolExp,true}}),
- ?line {ok,{xboolExp,true}} = asn1_wrapper:decode('ChoExternal','ChoXBool',lists:flatten(Bytes23)),
-
-
-
- ?line {ok,Bytes31} = asn1_wrapper:encode('ChoExternal','NT',{os,"kalle"}),
- ?line {ok,{os,"kalle"}} = asn1_wrapper:decode('ChoExternal','NT',lists:flatten(Bytes31)),
-
- ?line {ok,Bytes32} = asn1_wrapper:encode('ChoExternal','Exp',{os,"kalle"}),
- ?line {ok,{os,"kalle"}} = asn1_wrapper:decode('ChoExternal','Exp',lists:flatten(Bytes32)),
-
- ?line {ok,Bytes33} = asn1_wrapper:encode('ChoExternal','NTNT',{os,"kalle"}),
- ?line {ok,{os,"kalle"}} = asn1_wrapper:decode('ChoExternal','NTNT',lists:flatten(Bytes33)),
-
- ?line {ok,Bytes34} = asn1_wrapper:encode('ChoExternal','NTExp',{os,"kalle"}),
- ?line {ok,{os,"kalle"}} = asn1_wrapper:decode('ChoExternal','NTExp',lists:flatten(Bytes34)),
-
- ?line {ok,Bytes35} = asn1_wrapper:encode('ChoExternal','ExpNT',{os,"kalle"}),
- ?line {ok,{os,"kalle"}} = asn1_wrapper:decode('ChoExternal','ExpNT',lists:flatten(Bytes35)),
-
- ?line {ok,Bytes36} = asn1_wrapper:encode('ChoExternal','ExpExp',{os,"kalle"}),
- ?line {ok,{os,"kalle"}} = asn1_wrapper:decode('ChoExternal','ExpExp',lists:flatten(Bytes36)),
-
-
-
-
-
- ?line {ok,Bytes41} = asn1_wrapper:encode('ChoExternal','XNTNT',{os,"kalle"}),
- ?line {ok,{os,"kalle"}} = asn1_wrapper:decode('ChoExternal','XNTNT',lists:flatten(Bytes41)),
-
- ?line {ok,Bytes42} = asn1_wrapper:encode('ChoExternal','XNTExp',{os,"kalle"}),
- ?line {ok,{os,"kalle"}} = asn1_wrapper:decode('ChoExternal','XNTExp',lists:flatten(Bytes42)),
-
- ?line {ok,Bytes43} = asn1_wrapper:encode('ChoExternal','XExpNT',{os,"kalle"}),
- ?line {ok,{os,"kalle"}} = asn1_wrapper:decode('ChoExternal','XExpNT',lists:flatten(Bytes43)),
-
- ?line {ok,Bytes44} = asn1_wrapper:encode('ChoExternal','XExpExp',{os,"kalle"}),
- ?line {ok,{os,"kalle"}} = asn1_wrapper:decode('ChoExternal','XExpExp',lists:flatten(Bytes44)),
+ roundtrip('ChoXBool', {xbool,true}),
+ roundtrip('ChoXBool', {xboolImp,true}),
+ roundtrip('ChoXBool', {xboolExp,true}),
+
+ roundtrip('NT', {os,"kalle"}),
+ roundtrip('Exp', {os,"kalle"}),
+ roundtrip('NTNT', {os,"kalle"}),
+ roundtrip('NTExp', {os,"kalle"}),
+ roundtrip('ExpNT', {os,"kalle"}),
+ roundtrip('ExpExp', {os,"kalle"}),
+ roundtrip('XNTNT', {os,"kalle"}),
+ roundtrip('XNTExp', {os,"kalle"}),
+ roundtrip('XExpNT', {os,"kalle"}),
+ roundtrip('XExpExp', {os,"kalle"}),
ok.
+roundtrip(Type, Value) ->
+ {ok,Encoded} = 'ChoExternal':encode(Type, Value),
+ {ok,Value} = 'ChoExternal':decode(Type, Encoded),
+ ok.
diff --git a/lib/asn1/test/testChoRecursive.erl b/lib/asn1/test/testChoRecursive.erl
index 22be26cbce..ee26d124a9 100644
--- a/lib/asn1/test/testChoRecursive.erl
+++ b/lib/asn1/test/testChoRecursive.erl
@@ -28,38 +28,21 @@
-record('ChoRec2_something',{a, b, c}).
recursive(_Rules) ->
-
- ?line {ok,Bytes11} = asn1_wrapper:encode('ChoRecursive','ChoRec',{'ChoRec',{something,
- #'ChoRec_something'{a = 77,
- b = "some octets here",
- c = {'ChoRec',{nothing,'NULL'}}}}}),
- ?line {ok,{something,{'ChoRec_something',77,"some octets here",{nothing,'NULL'}}}} =
- asn1_wrapper:decode('ChoRecursive','ChoRec',lists:flatten(Bytes11)),
-
-
- ?line {ok,Bytes12} = asn1_wrapper:encode('ChoRecursive','ChoRec',{'ChoRec',{nothing,'NULL'}}),
- ?line {ok,{nothing,'NULL'}} =
- asn1_wrapper:decode('ChoRecursive','ChoRec',lists:flatten(Bytes12)),
-
-
-
- ?line {ok,Bytes21} =
- asn1_wrapper:encode('ChoRecursive','ChoRec2',{'ChoRec2',
- {something,
- #'ChoRec2_something'{a = 77,
- b = "some octets here",
- c = {'ChoRec2',
- {nothing,'NULL'}}}}}),
- ?line {ok,{something,{'ChoRec2_something',77,"some octets here",{nothing,'NULL'}}}} =
- asn1_wrapper:decode('ChoRecursive','ChoRec2',lists:flatten(Bytes21)),
-
-
- ?line {ok,Bytes22} =
- asn1_wrapper:encode('ChoRecursive','ChoRec2',{'ChoRec2',{nothing,'NULL'}}),
- ?line {ok,{nothing,'NULL'}} =
- asn1_wrapper:decode('ChoRecursive','ChoRec2',lists:flatten(Bytes22)),
-
-
-
-
+ roundtrip('ChoRec',
+ {something,
+ #'ChoRec_something'{a = 77,
+ b = "some octets here",
+ c = {nothing,'NULL'}}}),
+ roundtrip('ChoRec', {nothing,'NULL'}),
+ roundtrip('ChoRec2',
+ {something,
+ #'ChoRec2_something'{a = 77,
+ b = "some octets here",
+ c = {nothing,'NULL'}}}),
+ roundtrip('ChoRec2', {nothing,'NULL'}),
+ ok.
+
+roundtrip(Type, Value) ->
+ {ok,Encoded} = 'ChoRecursive':encode(Type, Value),
+ {ok,Value} = 'ChoRecursive':decode(Type, Encoded),
ok.
diff --git a/lib/asn1/test/testChoiceIndefinite.erl b/lib/asn1/test/testChoiceIndefinite.erl
index 630efcf27a..b5832c985a 100644
--- a/lib/asn1/test/testChoiceIndefinite.erl
+++ b/lib/asn1/test/testChoiceIndefinite.erl
@@ -23,12 +23,7 @@
-include_lib("test_server/include/test_server.hrl").
-main(per_bin) -> ok;
main(per) -> ok;
-main(ber_bin_v2) ->
- main(ber);
-main(ber_bin) ->
- main(ber);
main(ber) ->
%% Test case related to OTP-4358
%% normal encoding
diff --git a/lib/asn1/test/testCompactBitString.erl b/lib/asn1/test/testCompactBitString.erl
index 9563a31bf3..96d9f0fdcb 100644
--- a/lib/asn1/test/testCompactBitString.erl
+++ b/lib/asn1/test/testCompactBitString.erl
@@ -22,240 +22,132 @@
-export([compact_bit_string/1, bit_string_unnamed/1,otp_4869/1,
ticket_7734/1]).
--include_lib("test_server/include/test_server.hrl").
-
compact_bit_string(Rules) ->
%%==========================================================
%% Bs1 ::= BIT STRING
%%==========================================================
- ?line {ok,Bytes1} = asn1_wrapper:encode('PrimStrings','Bs1',0),
- ?line {ok,{0,<<>>}} =
- asn1_wrapper:decode('PrimStrings','Bs1',lists:flatten(Bytes1)),
-
- ?line {ok,Bytes2} = asn1_wrapper:encode('PrimStrings','Bs1',4),
- ?line {ok,{5,<<32>>}} =
- asn1_wrapper:decode('PrimStrings','Bs1',lists:flatten(Bytes2)),
-
- ?line {ok,Bytes3} = asn1_wrapper:encode('PrimStrings','Bs1',15),
- ?line {ok,{4,<<240>>}} =
- asn1_wrapper:decode('PrimStrings','Bs1',
- lists:flatten(Bytes3)),
-
- ?line {ok,Bytes4} = asn1_wrapper:encode('PrimStrings','Bs1',255),
- ?line {ok,{0,<<255>>}} =
- asn1_wrapper:decode('PrimStrings','Bs1',lists:flatten(Bytes4)),
-
- ?line {ok,Bytes5} = asn1_wrapper:encode('PrimStrings','Bs1',256),
- ?line {ok,{7,<<0,128>>}} =
- asn1_wrapper:decode('PrimStrings','Bs1',lists:flatten(Bytes5)),
-
- ?line {ok,Bytes6} = asn1_wrapper:encode('PrimStrings','Bs1',257),
- ?line {ok,{7,<<128,128>>}} =
- asn1_wrapper:decode('PrimStrings','Bs1',
- lists:flatten(Bytes6)),
-
- ?line {ok,Bytes7} = asn1_wrapper:encode('PrimStrings','Bs1',444),
- ?line {ok,{7,<<61,128>>}} =
- asn1_wrapper:decode('PrimStrings','Bs1',
- lists:flatten(Bytes7)),
-
- ?line {ok,Bytes8} = asn1_wrapper:encode('PrimStrings','Bs1',
- 12345678901234567890),
- ?line {ok,_} = asn1_wrapper:decode('PrimStrings','Bs1',
- lists:flatten(Bytes8)),
-
-%% Removed due to beam cannot handle this big integers
-%% Bs1_1 = 123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890,
-%% ?line {ok,Bytes9} = asn1_wrapper:encode('PrimStrings','Bs1',Bs1_1),
-%% ?line {ok,_} = asn1_wrapper:decode('PrimStrings','Bs1',lists:flatten(Bytes9)),
-
-%% Bs1_2 = 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890,
-%% ?line {ok,Bytes10} = asn1_wrapper:encode('PrimStrings','Bs1',Bs1_2),
-%% ?line {ok,_} = asn1_wrapper:decode('PrimStrings','Bs1',lists:flatten(Bytes10)),
-
- ?line {ok,Bytes11} = asn1_wrapper:encode('PrimStrings','Bs1',
- [1,1,1,1,1,1,1,1]),
- ?line {ok,{0,<<255>>}} = asn1_wrapper:decode('PrimStrings','Bs1',
- lists:flatten(Bytes11)),
-
- ?line {ok,Bytes12} = asn1_wrapper:encode('PrimStrings',
- 'Bs1',
- [0,1,0,0,1,0]),
- ?line {ok,{2,<<72>>}} =
- asn1_wrapper:decode('PrimStrings','Bs1',
- lists:flatten(Bytes12)),
-
- ?line {ok,Bytes13} =
- asn1_wrapper:encode('PrimStrings', 'Bs1',
- [1,0,0,0,0,0,0,0,0]),
- ?line {ok,{7,<<128,0>>}} =
- asn1_wrapper:decode('PrimStrings','Bs1',
- lists:flatten(Bytes13)),
-
-
- ?line {ok,Bytes14} =
- asn1_wrapper:encode('PrimStrings','Bs1',
- [0,1,0,0,1,0,1,1,1,1,1,0,0,0,1,0,0,1,1]),
- ?line {ok,{5,<<75,226,96>>}} =
- asn1_wrapper:decode('PrimStrings','Bs1',lists:flatten(Bytes14)),
-
-
- ?line case asn1_wrapper:erule(Rules) of
- ber ->
- ?line Bytes15 = [35,8,3,2,0,73,3,2,4,32],
- ?line {ok,{4,<<73,32>>}} =
- asn1_wrapper:decode('PrimStrings','Bs1',
- lists:flatten(Bytes15)),
-
- ?line Bytes16 = [35,9,3,2,0,234,3,3,7,156,0],
- ?line {ok,{7,<<234,156,0>>}} =
- asn1_wrapper:decode('PrimStrings','Bs1',
- lists:flatten(Bytes16)),
-
- ?line Bytes17 = [35,128,3,2,0,73,3,2,4,32,0,0],
- ?line {ok,{4,<<73,32>>}} =
- asn1_wrapper:decode('PrimStrings','Bs1',
- lists:flatten(Bytes17)),
-
- ?line Bytes18 = [35,128,3,2,0,234,3,3,7,156,0,0,0],
- ?line {ok,{7,<<234,156,0>>}} =
- asn1_wrapper:decode('PrimStrings','Bs1',
- lists:flatten(Bytes18)),
- ok;
-
- per ->
- ok
- end,
+ roundtrip('Bs1', 0, {0,<<>>}),
+ roundtrip('Bs1', 4, {5,<<2#00100000>>}),
+ roundtrip('Bs1', 15, {4,<<2#11110000>>}),
+ roundtrip('Bs1', 255, {0,<<2#11111111>>}),
+ roundtrip('Bs1', 256, {7,<<16#00,16#80>>}),
+ roundtrip('Bs1', 257, {7,<<16#80,16#80>>}),
+ roundtrip('Bs1', 444, {7,<<16#3D,16#80>>}),
+ roundtrip('Bs1', 12345678901234567890,
+ {0,<<75,80,248,215,49,149,42,213>>}),
+
+ roundtrip('Bs1', [1,1,1,1,1,1,1,1], {0,<<255>>}),
+ roundtrip('Bs1', [0,1,0,0,1,0], {2,<<16#48>>}),
+ roundtrip('Bs1', [1,0,0,0,0,0,0,0,0], {7,<<16#80,0>>}),
+ roundtrip('Bs1', [0,1,0,0,1,0,1,1,1,1,1,0,0,0,1,0,0,1,1],
+ {5,<<75,226,96>>}),
- %% The following case to test OTP-4200
- ?line {ok,Bytes19} =
- asn1_wrapper:encode('PrimStrings','Bs1',{0,<<0,0,1,1>>}),
- ?line {ok,{0,<<0,0,1,1>>}} =
- asn1_wrapper:decode('PrimStrings','Bs1',lists:flatten(Bytes19)),
+ case Rules of
+ ber ->
+ {ok,{4,<<73,32>>}} =
+ 'PrimStrings':decode('Bs1', <<35,8,3,2,0,73,3,2,4,32>>),
+ {ok,{7,<<234,156,0>>}} =
+ 'PrimStrings':decode('Bs1', <<35,9,3,2,0,234,3,3,7,156,0>>),
+ {ok,{4,<<73,32>>}} =
+ 'PrimStrings':decode('Bs1', <<35,128,3,2,0,73,3,2,4,32,0,0>>),
+ {ok,{7,<<234,156,0>>}} =
+ 'PrimStrings':decode('Bs1',
+ <<35,128,3,2,0,234,3,3,7,156,0,0,0>>);
+ _ ->
+ ok
+ end,
+
+ %% Test OTP-4200
+ roundtrip('Bs1', {0,<<0,0,1,1>>}),
%%==========================================================
%% Bs2 ::= BIT STRING {su(0), mo(1), tu(2), we(3), th(4), fr(5), sa(6) } (SIZE (7))
%%==========================================================
-
- ?line {ok,Bytes21} = asn1_wrapper:encode('PrimStrings','Bs2',[mo,tu,fr]),
- ?line {ok,[mo,tu,fr]} = asn1_wrapper:decode('PrimStrings','Bs2',lists:flatten(Bytes21)),
-
- ?line {ok,Bytes22} = asn1_wrapper:encode('PrimStrings','Bs2',[0,1,1,0,0,1,0]),
- ?line {ok,[mo,tu,fr]} = asn1_wrapper:decode('PrimStrings','Bs2',lists:flatten(Bytes22)),
-
- % ?line case asn1_wrapper:erule(Rules) of
-% ber ->
-% ?line {ok,[mo,tu,fr,su,mo,th]} =
-% asn1_wrapper:decode('PrimStrings','Bs2',[35,8,3,2,1,100,3,2,2,200]),
-
-% ?line {ok,[mo,tu,fr,su,mo,th]} =
-% asn1_wrapper:decode('PrimStrings','Bs2',[35,128,3,2,1,100,3,2,2,200,0,0]),
-% ok;
-
-% per ->
-% ok
-% end,
-
-
+
+ roundtrip('Bs2', [mo,tu,fr]),
+ roundtrip('Bs2', [0,1,1,0,0,1,0], [mo,tu,fr]),
%%==========================================================
%% Bs3 ::= BIT STRING {su(0), mo(1), tu(2), we(3), th(4), fr(5), sa(6) } (SIZE (1..7))
%%==========================================================
- ?line {ok,Bytes31} = asn1_wrapper:encode('PrimStrings','Bs3',[mo,tu,fr]),
- ?line {ok,[mo,tu,fr]} = asn1_wrapper:decode('PrimStrings','Bs3',lists:flatten(Bytes31)),
-
- ?line {ok,Bytes32} = asn1_wrapper:encode('PrimStrings','Bs3',[0,1,1,0,0,1,0]),
- ?line {ok,[mo,tu,fr]} = asn1_wrapper:decode('PrimStrings','Bs3',lists:flatten(Bytes32)),
-
-
+ roundtrip('Bs3', [mo,tu,fr]),
+ roundtrip('Bs3', [0,1,1,0,0,1,0], [mo,tu,fr]),
%%==========================================================
%% BsPri ::= [PRIVATE 61] BIT STRING
%%==========================================================
-
- ?line {ok,Bytes41} = asn1_wrapper:encode('PrimStrings','BsPri',45),
- ?line {ok,{2,<<180>>}} =
- asn1_wrapper:decode('PrimStrings','BsPri',lists:flatten(Bytes41)),
-
- ?line {ok,Bytes42} = asn1_wrapper:encode('PrimStrings','BsPri',211),
- ?line {ok,{0,<<203>>}} =
- asn1_wrapper:decode('PrimStrings','BsPri',lists:flatten(Bytes42)),
-
- ?line case asn1_wrapper:erule(Rules) of
- ber ->
- ?line {ok,{5,<<75,226,96>>}} =
- asn1_wrapper:decode('PrimStrings','BsPri',
- [223,61,4,5,75,226,96]),
-
- ?line {ok,{5,<<75,226,96>>}} =
- asn1_wrapper:decode('PrimStrings','BsPri',
- [255,61,128,3,4,5,75,226,96,0,0]),
-
- ?line {ok,{5,<<75,226,96>>}} =
- asn1_wrapper:decode('PrimStrings','BsPri',
- [255,61,9,3,2,0,75,3,3,5,226,96]),
-
- ?line {ok,{5,<<75,226,96>>}} =
- asn1_wrapper:decode('PrimStrings','BsPri',
- [255,61,128,3,2,0,75,3,3,5,226,96,0,0]),
- ok;
-
- per ->
- ok
- end,
-
+
+ roundtrip('BsPri', 45, {2,<<180>>}),
+ roundtrip('BsPri', 211, {0,<<203>>}),
+
+ case Rules of
+ ber ->
+ {ok,{5,<<75,226,96>>}} =
+ 'PrimStrings':decode('BsPri',
+ <<223,61,4,5,75,226,96>>),
+
+ {ok,{5,<<75,226,96>>}} =
+ 'PrimStrings':decode('BsPri',
+ <<255,61,128,3,4,5,75,226,96,0,0>>),
+
+ {ok,{5,<<75,226,96>>}} =
+ 'PrimStrings':decode('BsPri',
+ <<255,61,9,3,2,0,75,3,3,5,226,96>>),
+
+ {ok,{5,<<75,226,96>>}} =
+ 'PrimStrings':decode('BsPri',
+ <<255,61,128,3,2,0,75,3,3,5,226,96,0,0>>),
+ ok;
+ _ ->
+ ok
+ end,
%%==========================================================
%% BsExpPri ::= [PRIVATE 61] EXPLICIT BIT STRING
%%==========================================================
-
- ?line {ok,Bytes51} = asn1_wrapper:encode('PrimStrings','BsExpPri',45),
- ?line {ok,{2,<<180>>}} =
- asn1_wrapper:decode('PrimStrings','BsExpPri',lists:flatten(Bytes51)),
-
- ?line {ok,Bytes52} = asn1_wrapper:encode('PrimStrings','BsExpPri',211),
- ?line {ok,{0,<<203>>}} =
- asn1_wrapper:decode('PrimStrings','BsExpPri',lists:flatten(Bytes52)),
-
- ?line case asn1_wrapper:erule(Rules) of
- ber ->
- ?line {ok,{5,<<75,226,96>>}} =
- asn1_wrapper:decode('PrimStrings','BsExpPri',[255,61,6,3,4,5,75,226,96]),
- ok;
-
- per ->
- ok
- end,
-
- ok.
-ticket_7734(per_bin) ->
- ?line BS = {0,list_to_binary(lists:duplicate(128,0))},
- ?line {ok,BSEnc} = asn1_wrapper:encode('PrimStrings','BS1024',BS),
- ?line {ok,BS} = asn1_wrapper:decode('PrimStrings','BS1024',BSEnc).
+ roundtrip('BsExpPri', 45, {2,<<180>>}),
+ roundtrip('BsExpPri', 211, {0,<<203>>}),
-bit_string_unnamed(Rules) ->
- case asn1_wrapper:erule(Rules) of
+ case Rules of
ber ->
- ok;
- per ->
- ?line {ok,Bytes1} =
- asn1_wrapper:encode('PrimStrings','TransportLayerAddress',
- [0,1,1,0]),
- ?line {ok,{4,<<96>>}} =
- asn1_wrapper:decode('PrimStrings','TransportLayerAddress',
- lists:flatten(Bytes1))
- end.
+ {ok,{5,<<75,226,96>>}} =
+ 'PrimStrings':decode('BsExpPri', <<255,61,6,3,4,5,75,226,96>>);
+ _ ->
+ ok
+ end,
-otp_4869(per_bin) ->
- ?line Val1={'IP',[0],{0,<<62,235,90,50,0,0,0,0,0,0,0,0,0,0,0,0>>},asn1_NOVALUE},
- ?line Val2 = {'IP',[0],[0,0,1,1,1,1,1,0,1,1,1,0,1,0,1,1,0,1,0,1,1,0,1,0,0,0,1,1,0,0,1,0] ++ lists:duplicate(128 - 32,0),asn1_NOVALUE},
+ ok.
- ?line {ok,Bytes1} = asn1_wrapper:encode('Constraints','IP',Val1),
- ?line {ok,Bytes1} = asn1_wrapper:encode('Constraints','IP',Val2);
+ticket_7734(_) ->
+ BS = {0,list_to_binary(lists:duplicate(128, 0))},
+ roundtrip('BS1024', BS).
+
+bit_string_unnamed(_Rules) ->
+ roundtrip('TransportLayerAddress', [0,1,1,0], {4,<<96>>}).
+
+otp_4869(per) ->
+ Val1 = {'IP',[0],{0,<<62,235,90,50,0,0,0,0,0,0,0,0,0,0,0,0>>},asn1_NOVALUE},
+ Val2 = {'IP',[0],[0,0,1,1,1,1,1,0,1,1,1,0,1,0,1,1,0,1,0,1,1,0,
+ 1,0,0,0,1,1,0,0,1,0] ++
+ lists:duplicate(128 - 32, 0),asn1_NOVALUE},
+ {ok,Encoded} = 'Constraints':encode('IP', Val1),
+ {ok,Encoded} = 'Constraints':encode('IP', Val2),
+ ok;
otp_4869(_) ->
ok.
+
+roundtrip(Type, Val) ->
+ roundtrip_1('PrimStrings', Type, Val, Val).
+
+roundtrip(Type, Val1, Val2) ->
+ roundtrip_1('PrimStrings', Type, Val1, Val2).
+
+roundtrip_1(Mod, Type, In, Out) ->
+ {ok,Encoded} = Mod:encode(Type, In),
+ {ok,Out} = Mod:decode(Type, Encoded),
+ ok.
diff --git a/lib/asn1/test/testConstraints.erl b/lib/asn1/test/testConstraints.erl
index 543c106e8a..c8d9008641 100644
--- a/lib/asn1/test/testConstraints.erl
+++ b/lib/asn1/test/testConstraints.erl
@@ -30,59 +30,20 @@ int_constraints(Rules) ->
%% SingleValue ::= INTEGER (1)
%%==========================================================
- ?line {ok,Bytes1} = asn1_wrapper:encode('Constraints','SingleValue',1),
- ?line {ok,1} = asn1_wrapper:decode('Constraints','SingleValue',
- lists:flatten(Bytes1)),
-
- ?line case asn1_wrapper:erule(Rules) of
- ber ->
- ?line {ok,Bytes2} =
- asn1_wrapper:encode('Constraints','SingleValue',0),
- ?line {error,{asn1,{integer_range,_,0}}} =
- asn1_wrapper:decode('Constraints','SingleValue',
- lists:flatten(Bytes2)),
- ?line {ok,Bytes3} =
- asn1_wrapper:encode('Constraints','SingleValue',1000),
- ?line {error,{asn1,{integer_range,_,1000}}} =
- asn1_wrapper:decode('Constraints','SingleValue',
- lists:flatten(Bytes3));
- per ->
- ?line {error,_Reason1} =
- asn1_wrapper:encode('Constraints','SingleValue',0),
- ?line {error,_Reason2} =
- asn1_wrapper:encode('Constraints','SingleValue',1000)
- end,
+ range_error(Rules, 'SingleValue', 0),
+ roundtrip('SingleValue', 1),
+ range_error(Rules, 'SingleValue', 2),
+ range_error(Rules, 'SingleValue', 1000),
%%==========================================================
%% SingleValue2 ::= INTEGER (1..20)
%%==========================================================
- ?line {ok,Bytes4} = asn1_wrapper:encode('Constraints','SingleValue2',1),
- ?line {ok,1} = asn1_wrapper:decode('Constraints','SingleValue2',
- lists:flatten(Bytes4)),
-
- ?line {ok,Bytes5} = asn1_wrapper:encode('Constraints','SingleValue2',20),
- ?line {ok,20} = asn1_wrapper:decode('Constraints','SingleValue2',
- lists:flatten(Bytes5)),
-
- ?line case asn1_wrapper:erule(Rules) of
- ber ->
- ?line {ok,Bytes6} =
- asn1_wrapper:encode('Constraints','SingleValue2',0),
- ?line {error,{asn1,{integer_range,{1,20},0}}} =
- asn1_wrapper:decode('Constraints','SingleValue2',
- lists:flatten(Bytes6)),
- ?line {ok,Bytes7} =
- asn1_wrapper:encode('Constraints','SingleValue2',21),
- ?line {error,{asn1,{integer_range,{1,20},21}}} =
- asn1_wrapper:decode('Constraints','SingleValue2',
- lists:flatten(Bytes7));
- per ->
- ?line {error,_Reason3} =
- asn1_wrapper:encode('Constraints','SingleValue',0),
- ?line {error,_Reason4} =
- asn1_wrapper:encode('Constraints','SingleValue',1000)
- end,
+ range_error(Rules, 'SingleValue2', 0),
+ roundtrip('SingleValue2', 1),
+ roundtrip('SingleValue2', 20),
+ range_error(Rules, 'SingleValue2', 21),
+ range_error(Rules, 'SingleValue2', 1000),
%%==========================================================
%% SingleValue3 ::= INTEGER (Predefined | 5 | 10)
@@ -90,136 +51,106 @@ int_constraints(Rules) ->
%% where one value is predefined.
%%==========================================================
- ?line {ok,BytesSV3} = asn1_wrapper:encode('Constraints','SingleValue3',1),
- ?line {ok,1} = asn1_wrapper:decode('Constraints','SingleValue3',
- lists:flatten(BytesSV3)),
- ?line {ok,BytesSV3_2} = asn1_wrapper:encode('Constraints','SingleValue3',5),
- ?line {ok,5} = asn1_wrapper:decode('Constraints','SingleValue3',
- lists:flatten(BytesSV3_2)),
- ?line {ok,BytesSV3_3} = asn1_wrapper:encode('Constraints','SingleValue3',10),
- ?line {ok,10} = asn1_wrapper:decode('Constraints','SingleValue3',
- lists:flatten(BytesSV3_3)),
+ roundtrip('SingleValue3', 1),
+ roundtrip('SingleValue3', 5),
+ roundtrip('SingleValue3', 10),
%%==========================================================
%% Range2to19 ::= INTEGER (1<..<20)
%%==========================================================
- ?line {ok,Bytes8} = asn1_wrapper:encode('Constraints','Range2to19',2),
- ?line {ok,2} = asn1_wrapper:decode('Constraints','Range2to19',lists:flatten(Bytes8)),
-
- ?line {ok,Bytes9} = asn1_wrapper:encode('Constraints','Range2to19',19),
- ?line {ok,19} = asn1_wrapper:decode('Constraints','Range2to19',lists:flatten(Bytes9)),
-
- ?line case asn1_wrapper:erule(Rules) of
- ber ->
- ?line {ok,Bytes10} =
- asn1_wrapper:encode('Constraints','Range2to19',1),
- ?line {error,{asn1,{integer_range,{2,19},1}}} =
- asn1_wrapper:decode('Constraints','Range2to19',
- lists:flatten(Bytes10)),
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('Constraints','Range2to19',20),
- ?line {error,{asn1,{integer_range,{2,19},20}}} =
- asn1_wrapper:decode('Constraints','Range2to19',
- lists:flatten(Bytes11));
- per ->
- ?line {error,_Reason5} =
- asn1_wrapper:encode('Constraints','Range2to19',1),
- ?line {error,_Reason6} =
- asn1_wrapper:encode('Constraints','Range2to19',20)
- end,
+ range_error(Rules, 'Range2to19', 1),
+ roundtrip('Range2to19', 2),
+ roundtrip('Range2to19', 19),
+ range_error(Rules, 'Range2to19', 20),
%%==========================================================
%% Tests for Range above 16^4 up to maximum supported by asn1 assuming the
%% octet length field is encoded on max 8 bits
%%==========================================================
LastNumWithoutLengthEncoding = 65536,
- ?line {ok,BytesFoo} = asn1_wrapper:encode('Constraints','Range256to65536',
- LastNumWithoutLengthEncoding),
- ?line {ok,LastNumWithoutLengthEncoding} =
- asn1_wrapper:decode('Constraints','Range256to65536',lists:flatten(BytesFoo)),
+ roundtrip('Range256to65536', LastNumWithoutLengthEncoding),
FirstNumWithLengthEncoding = 65537,
- ?line {ok,BytesBar} = asn1_wrapper:encode('LargeConstraints','RangeMax',
- FirstNumWithLengthEncoding),
- ?line {ok,FirstNumWithLengthEncoding} =
- asn1_wrapper:decode('LargeConstraints','RangeMax',lists:flatten(BytesBar)),
+ roundtrip('LargeConstraints', 'RangeMax', FirstNumWithLengthEncoding),
FirstNumOver16_6 = 16777217,
- ?line {ok, BytesBaz} =
- asn1_wrapper:encode('LargeConstraints','RangeMax', FirstNumOver16_6),
- ?line {ok, FirstNumOver16_6} =
- asn1_wrapper:decode('LargeConstraints','RangeMax',lists:flatten(BytesBaz)),
+ roundtrip('LargeConstraints', 'RangeMax', FirstNumOver16_6),
FirstNumOver16_8 = 4294967297,
- ?line {ok, BytesQux} =
- asn1_wrapper:encode('LargeConstraints','RangeMax', FirstNumOver16_8),
- ?line {ok, FirstNumOver16_8} =
- asn1_wrapper:decode('LargeConstraints','RangeMax',lists:flatten(BytesQux)),
+ roundtrip('LargeConstraints', 'RangeMax', FirstNumOver16_8),
FirstNumOver16_10 = 1099511627776,
- ?line {ok, BytesBur} =
- asn1_wrapper:encode('LargeConstraints','RangeMax', FirstNumOver16_10),
- ?line {ok, FirstNumOver16_10} =
- asn1_wrapper:decode('LargeConstraints','RangeMax',lists:flatten(BytesBur)),
+ roundtrip('LargeConstraints', 'RangeMax', FirstNumOver16_10),
FirstNumOver16_10 = 1099511627776,
- ?line {ok, BytesBur} =
- asn1_wrapper:encode('LargeConstraints','RangeMax', FirstNumOver16_10),
- ?line {ok, FirstNumOver16_10} =
- asn1_wrapper:decode('LargeConstraints','RangeMax',lists:flatten(BytesBur)),
+ roundtrip('LargeConstraints', 'RangeMax', FirstNumOver16_10),
HalfMax = 1 bsl (128*8),
- ?line {ok, BytesHalfMax} =
- asn1_wrapper:encode('LargeConstraints','RangeMax', HalfMax),
- ?line {ok, HalfMax} =
- asn1_wrapper:decode('LargeConstraints','RangeMax',lists:flatten(BytesHalfMax)),
+ roundtrip('LargeConstraints', 'RangeMax', HalfMax),
Max = 1 bsl (255*8),
- ?line {ok, BytesMax} =
- asn1_wrapper:encode('LargeConstraints','RangeMax', Max),
- ?line {ok, Max} =
- asn1_wrapper:decode('LargeConstraints','RangeMax',lists:flatten(BytesMax)),
+ roundtrip('LargeConstraints', 'RangeMax', Max),
%% Random number within longlong range
LongLong = 12672809400538808320,
- ?line {ok, BytesLongLong} =
- asn1_wrapper:encode('Constraints','LongLong', LongLong),
- ?line {ok, LongLong} =
- asn1_wrapper:decode('Constraints','LongLong',lists:flatten(BytesLongLong)),
+ roundtrip('LongLong', LongLong),
%%==========================================================
%% Constraint Combinations (Duboisson p. 285)
%% I ::= INTEGER (0|15..269)
%%==========================================================
- ?line {ok,Bytes12} = asn1_wrapper:encode('Constraints','I',0),
- ?line {ok,0} = asn1_wrapper:decode('Constraints','I',Bytes12),
- ?line {ok,Bytes13} = asn1_wrapper:encode('Constraints','I',20),
- ?line {ok,20} = asn1_wrapper:decode('Constraints','I',Bytes13),
+ range_error(Rules, 'I', -1),
+ roundtrip('I', 0),
+ roundtrip('I', 15),
+ roundtrip('I', 20),
+ roundtrip('I', 269),
+ range_error(Rules, 'I', 270),
%%==========================================================
%% Constraint Combinations (Duboisson p. 285)
%% X1 ::= INTEGER (1..4|8|10|20)
%%==========================================================
- ?line {ok,Bytes14} = asn1_wrapper:encode('Constraints','X1',1),
- ?line {ok,1} = asn1_wrapper:decode('Constraints','X1',Bytes14),
- ?line {ok,Bytes15} = asn1_wrapper:encode('Constraints','X1',20),
- ?line {ok,20} = asn1_wrapper:decode('Constraints','X1',Bytes15),
+ range_error(Rules, 'X1', 0),
+ roundtrip('X1', 1),
+ roundtrip('X1', 4),
+ roundtrip('X1', 8),
+ roundtrip('X1', 10),
+ roundtrip('X1', 20),
+ range_error(Rules, 'X1', 21),
+
%%==========================================================
%% SIZE Constraint (Duboisson p. 268)
%% T ::= IA5String (SIZE (1|2, ..., SIZE (1|2|3)))
%% T2 ::= IA5String (SIZE (1|2, ..., 3))
%%==========================================================
- ?line {ok,Bytes16} = asn1_wrapper:encode('Constraints','T',"IA"),
- ?line {ok,"IA"} = asn1_wrapper:decode('Constraints','T',Bytes16),
- ?line {ok,Bytes17} = asn1_wrapper:encode('Constraints','T2',"IA"),
- ?line {ok,"IA"} = asn1_wrapper:decode('Constraints','T2',Bytes17).
-
+ roundtrip('T', "IA"),
+ roundtrip('T2', "IA").
refed_NNL_name(_Erule) ->
?line {ok,_} = asn1_wrapper:encode('Constraints','AnotherThing',fred),
?line {error,_Reason} =
asn1_wrapper:encode('Constraints','AnotherThing',fred3).
+
+roundtrip(Type, Value) ->
+ roundtrip('Constraints', Type, Value).
+
+roundtrip(Module, Type, Value) ->
+ {ok,Encoded} = Module:encode(Type, Value),
+ {ok,Value} = Module:decode(Type, Encoded),
+ ok.
+
+range_error(ber, Type, Value) ->
+ %% BER: Values outside the effective range should be rejected
+ %% on decode.
+ {ok,Encoded} = 'Constraints':encode(Type, Value),
+ {error,{asn1,{integer_range,_,_}}} = 'Constraints':decode(Type, Encoded),
+ ok;
+range_error(Per, Type, Value) when Per =:= per; Per =:= uper ->
+ %% (U)PER: Values outside the effective range should be rejected
+ %% on encode.
+ {error,_} = 'Constraints':encode(Type, Value),
+ ok.
diff --git a/lib/asn1/test/testDeepTConstr.erl b/lib/asn1/test/testDeepTConstr.erl
index aa3afbb58f..3df7bcbaa0 100644
--- a/lib/asn1/test/testDeepTConstr.erl
+++ b/lib/asn1/test/testDeepTConstr.erl
@@ -26,21 +26,19 @@
-include_lib("test_server/include/test_server.hrl").
main(_Erule) ->
- Val1 = {'FilterItem',
- {substrings,
- {'FilterItem_substrings',
- {2,6},
- [{initial,"SE"},
- {any,"DK"},
- {final,"N"}]}}},
+ Val1 = {substrings,
+ {'FilterItem_substrings',
+ {2,6},
+ [{initial,"SE"},
+ {any,"DK"},
+ {final,"N"}]}},
- Val2 = {'FilterItem',
- {substrings,
- {'FilterItem_substrings',
- {2,6},
- [{initial,"SE"},
- {any,"DK"},
- {final,"NO"}]}}},
+ Val2 = {substrings,
+ {'FilterItem_substrings',
+ {2,6},
+ [{initial,"SE"},
+ {any,"DK"},
+ {final,"NO"}]}},
?line {ok,Bytes1} =
asn1_wrapper:encode('TConstrChoice','FilterItem',Val1),
diff --git a/lib/asn1/test/testEnumExt.erl b/lib/asn1/test/testEnumExt.erl
index c97116413a..0811f20571 100644
--- a/lib/asn1/test/testEnumExt.erl
+++ b/lib/asn1/test/testEnumExt.erl
@@ -23,64 +23,43 @@
-include_lib("test_server/include/test_server.hrl").
-main(Rules) when Rules == per; Rules == per_bin; Rules == uper_bin ->
- io:format("main(~p)~n",[Rules]),
- B32=[32],B64=[64],
+main(Rule) when Rule =:= per; Rule =:= uper ->
+ io:format("main(~p)~n",[Rule]),
+
%% ENUMERATED with extensionmark (value is in root set)
- ?line {ok,B32} = asn1_wrapper:encode('EnumExt','Ext',red),
- ?line {ok,red} = asn1_wrapper:decode('EnumExt','Ext',B32),
+ B32 = <<32>>,
+ B32 = roundtrip('Ext', red),
%% ENUMERATED with extensionmark (value is an extensionvalue)
- ?line {ok,Or} = asn1_wrapper:encode('EnumExt','Ext1',orange),
- ?line {ok,orange} = asn1_wrapper:decode('EnumExt','Ext1',Or),
+ Or = roundtrip('Ext1', orange),
%% unknown extensionvalue
- ?line {ok,{asn1_enum,0}} = asn1_wrapper:decode('EnumExt','Ext',Or),
-
+ {ok,{asn1_enum,0}} = asn1_wrapper:decode('EnumExt','Ext',Or),
%% ENUMERATED no extensionmark
- ?line {ok,B64} = asn1_wrapper:encode('EnumExt','Noext',red),
- ?line {ok,red} = asn1_wrapper:decode('EnumExt','Noext',B64),
+ B64 = <<64>>,
+ B64 = roundtrip('Noext', red),
ok;
-main(ber_bin_v2) ->
- main(ber);
-main(ber_bin) ->
- main(ber);
main(ber) ->
io:format("main(ber)~n",[]),
%% ENUMERATED with extensionmark (value is in root set)
- ?line {ok,Bytes1} = asn1_wrapper:encode('EnumExt','Ext',red),
- ?line {ok,red} = asn1_wrapper:decode('EnumExt','Ext',lists:flatten(Bytes1)),
+ roundtrip('Ext', red),
%% value is an extensionvalue
- ?line {ok,Bytes1_1} = asn1_wrapper:encode('EnumExt','Ext1',orange),
- ?line {ok,{asn1_enum,7}} = asn1_wrapper:decode('EnumExt','Ext',lists:flatten(Bytes1_1)),
-%% ?line {ok,Bytes1_1} = asn1_wrapper:encode('EnumExt','Ext',{asn1_enum,7}),
+ {ok,Bytes1_1} = asn1_wrapper:encode('EnumExt','Ext1',orange),
+ {ok,{asn1_enum,7}} = asn1_wrapper:decode('EnumExt','Ext',lists:flatten(Bytes1_1)),
- %% ENUMERATED no extensionmark
- ?line {ok,Bytes2} = asn1_wrapper:encode('EnumExt','Noext',red),
- ?line {ok,red} = asn1_wrapper:decode('EnumExt','Noext',lists:flatten(Bytes2)),
+ %% ENUMERATED no extensionmark
+ roundtrip('Noext', red),
?line {error,{asn1,_}} = (catch asn1_wrapper:encode('EnumExt','Noext',orange)),
-%% ?line {error,{asn1,_}} = (catch asn1_wrapper:encode('EnumExt','Noext',{asn1_enum,7})),
- ok,
%% ENUMERATED with atom 'com'
- ?line {ok,Bytes3} = asn1_wrapper:encode('EnumExt','Globalstate',{'Globalstate',preop}),
- ?line {ok,preop} = asn1_wrapper:decode('EnumExt','Globalstate',
- lists:flatten(Bytes3)),
- ?line {ok,Bytes4} = asn1_wrapper:encode('EnumExt','Globalstate',{'Globalstate',com}),
- ?line {ok,com} = asn1_wrapper:decode('EnumExt','Globalstate',
- lists:flatten(Bytes4)).
-
-
-
-
-
-
-
-
-
-
-
+ roundtrip('Globalstate', preop),
+ roundtrip('Globalstate', com),
+ ok.
+roundtrip(Type, Value) ->
+ {ok,Encoded} = 'EnumExt':encode(Type, Value),
+ {ok,Value} = 'EnumExt':decode(Type, Encoded),
+ Encoded.
diff --git a/lib/asn1/test/testINSTANCE_OF.erl b/lib/asn1/test/testINSTANCE_OF.erl
index 5986a00ec5..ce411beb92 100644
--- a/lib/asn1/test/testINSTANCE_OF.erl
+++ b/lib/asn1/test/testINSTANCE_OF.erl
@@ -26,7 +26,7 @@
main(Erule) ->
?line {ok,Integer} = asn1_wrapper:encode('INSTANCEOF','Int',3),
- Int = wrap(Erule,Integer),
+ Int = list_to_binary(Integer),
ValotherName = {otherName,{'INSTANCE OF',{2,4},Int}},
VallastName1 = {lastName,{'GeneralName_lastName',{2,4},12}},
VallastName2 = {lastName,{'GeneralName_lastName',{2,3,4},
@@ -61,18 +61,3 @@ test_encdec(_Erule,{lastName,{'GeneralName_lastName',{2,3,4},
ok;
test_encdec(Erule,Res) ->
{error,{Erule,Res}}.
-
-wrap(ber,Int) when is_list(Int) ->
- binary_to_list(list_to_binary(Int));
-wrap(per,Int) when is_list(Int) ->
- binary_to_list(list_to_binary(Int));
-wrap(ber_bin,Int) when is_list(Int) ->
- list_to_binary(Int);
-wrap(ber_bin_v2,Int) when is_list(Int) ->
- list_to_binary(Int);
-wrap(per_bin,Int) when is_list(Int) ->
- list_to_binary(Int);
-wrap(uper_bin,Int) when is_list(Int) ->
- list_to_binary(Int);
-wrap(_,Int) ->
- Int.
diff --git a/lib/asn1/test/testInfObjectClass.erl b/lib/asn1/test/testInfObjectClass.erl
index e639066246..98408502c6 100644
--- a/lib/asn1/test/testInfObjectClass.erl
+++ b/lib/asn1/test/testInfObjectClass.erl
@@ -37,15 +37,12 @@ main(Rule) ->
{component,'ArgumentType'},
{value,_},_}}} = asn1_wrapper:encode('InfClass','Seq',
{'Seq',12,13,1}),
- Bytes2 =
- if
- Rule==per;Rule==per_bin ->
- [1,12,1,11,1,1];
- Rule == uper_bin ->
- <<1,12,1,11,1,1>>;
- true ->
- [48,9,2,1,12,2,1,11,2,1,1]
- end,
+ Bytes2 = case Rule of
+ ber ->
+ <<48,9,2,1,12,2,1,11,2,1,1>>;
+ _ ->
+ <<1,12,1,11,1,1>>
+ end,
?line {error,{asn1,{'Type not compatible with table constraint',
{{component,_},
{value,_B},_}}}} =
diff --git a/lib/asn1/test/testMergeCompile.erl b/lib/asn1/test/testMergeCompile.erl
index 31aa3518f6..8ef7ba3458 100644
--- a/lib/asn1/test/testMergeCompile.erl
+++ b/lib/asn1/test/testMergeCompile.erl
@@ -37,23 +37,17 @@ main(Erule) ->
%% test of RANAP.set.asn1
?line _PIEVal = [{'ProtocolIE-Field',4,ignore,{'Cause',{radioNetwork,{'CauseRadioNetwork','rab-pre-empted'}}}}],
- ?line PIEVal2 = [{'ProtocolIE-Field',4,ignore,{'Cause',{radioNetwork,'rab-pre-empted'}}}],
+ PIEVal2 = [{'ProtocolIE-Field',4,ignore,{radioNetwork,'rab-pre-empted'}}],
?line _PEVal = [{'ProtocolExtensionField',[0]}],
%% ?line EncVal = asn1rt_per_v1:encode_integer([],100),
?line EncVal =
case Erule of
per ->
- [1,100];
- per_bin ->
<<1,100>>;
- uper_bin ->
+ uper ->
<<1,100>>;
ber ->
- [2,1,1];
- ber_bin ->
- <<2,1,1>>;
- ber_bin_v2 ->
- <<2,1,1>>
+ [2,1,1]
end,
?line PEVal2 = [{dummy,1,ignore,EncVal},{dummy,2,reject,EncVal}],
?line Val2 =
@@ -76,7 +70,7 @@ main(Erule) ->
mvrasn(Erule) ->
case Erule of
- Ber when Ber == ber;Ber == ber_bin ->
+ ber ->
?line ok = test(isd),
?line ok = test(isd2),
?line ok = test(dsd),
diff --git a/lib/compiler/test/compilation_SUITE_data/bad_functional_value.erl b/lib/asn1/test/testMultipleLevels.erl
index 126a573e83..ff6d023440 100644
--- a/lib/compiler/test/compilation_SUITE_data/bad_functional_value.erl
+++ b/lib/asn1/test/testMultipleLevels.erl
@@ -1,28 +1,27 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2012. All Rights Reserved.
+%%
%% The 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(bad_functional_value).
-
--export([?MODULE/0,a/0]).
-
-?MODULE() ->
- ok.
+%%
-a() ->
- .list_to_atom("ok").
+-module(testMultipleLevels).
+-export([main/1]).
+main(_) ->
+ Data = {'Top',{short,"abc"},{long,"a long string follows here"}},
+ {ok,B} = 'MultipleLevels':encode('Top', Data),
+ {ok,Data} = 'MultipleLevels':decode('Top', iolist_to_binary(B)).
diff --git a/lib/asn1/test/testParameterizedInfObj.erl b/lib/asn1/test/testParameterizedInfObj.erl
index 68faf08a61..17108e285b 100644
--- a/lib/asn1/test/testParameterizedInfObj.erl
+++ b/lib/asn1/test/testParameterizedInfObj.erl
@@ -86,7 +86,7 @@ main(Erule) ->
ranap(_Erule) ->
- ?line PIEVal2 = [{'ProtocolIE-Field',4,ignore,{'Cause',{radioNetwork,'rab-pre-empted'}}}],
+ PIEVal2 = [{'ProtocolIE-Field',4,ignore,{radioNetwork,'rab-pre-empted'}}],
?line Val2 =
#'InitiatingMessage'{procedureCode=1,
criticality=ignore,
@@ -98,7 +98,7 @@ ranap(_Erule) ->
ok.
-open_type(uper_bin,Val) when is_list(Val) ->
+open_type(uper,Val) when is_list(Val) ->
list_to_binary(Val);
open_type(_,Val) ->
Val.
diff --git a/lib/asn1/test/testPrimStrings.erl b/lib/asn1/test/testPrimStrings.erl
index b1c5172b95..263d9e5ed2 100644
--- a/lib/asn1/test/testPrimStrings.erl
+++ b/lib/asn1/test/testPrimStrings.erl
@@ -338,69 +338,24 @@ octet_string(Rules) ->
ok
end,
+ roundtrip('Os', [47,23,99,255,1]),
+ roundtrip('OsCon', [47,23,99,255,1]),
+ roundtrip('OsPri', [47,23,99,255,1]),
+ roundtrip('OsApp', [47,23,99,255,1]),
-
- ?line {ok,Bytes4} =
- asn1_wrapper:encode('PrimStrings','Os',[47,23,99,255,1]),
- ?line {ok,[47,23,99,255,1]} = asn1_wrapper:decode('PrimStrings','Os',lists:flatten(Bytes4)),
-
- ?line {ok,Bytes5} =
- asn1_wrapper:encode('PrimStrings','OsCon',[47,23,99,255,1]),
- ?line {ok,[47,23,99,255,1]} = asn1_wrapper:decode('PrimStrings','OsCon',lists:flatten(Bytes5)),
-
- ?line {ok,Bytes6} =
- asn1_wrapper:encode('PrimStrings','OsPri',[47,23,99,255,1]),
- ?line {ok,[47,23,99,255,1]} = asn1_wrapper:decode('PrimStrings','OsPri',lists:flatten(Bytes6)),
-
- ?line {ok,Bytes7} =
- asn1_wrapper:encode('PrimStrings','OsApp',[47,23,99,255,1]),
- ?line {ok,[47,23,99,255,1]} = asn1_wrapper:decode('PrimStrings','OsApp',lists:flatten(Bytes7)),
-
- ?line {ok,Bytes8} =
- asn1_wrapper:encode('PrimStrings','OsExpCon',[47,23,99,255,1]),
- ?line {ok,[47,23,99,255,1]} = asn1_wrapper:decode('PrimStrings','OsExpCon',lists:flatten(Bytes8)),
-
- ?line {ok,Bytes9} =
- asn1_wrapper:encode('PrimStrings','OsExpPri',[47,23,99,255,1]),
- ?line {ok,[47,23,99,255,1]} = asn1_wrapper:decode('PrimStrings','OsExpPri',lists:flatten(Bytes9)),
-
- ?line {ok,Bytes10} =
- asn1_wrapper:encode('PrimStrings','OsExpApp',[47,23,99,255,1]),
- ?line {ok,[47,23,99,255,1]} = asn1_wrapper:decode('PrimStrings','OsExpApp',lists:flatten(Bytes10)),
-
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('PrimStrings','Os',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','Os',lists:flatten(Bytes11)),
-
- ?line {ok,Bytes12} =
- asn1_wrapper:encode('PrimStrings','OsApp',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','OsApp',lists:flatten(Bytes12)),
-
- ?line {ok,Bytes13} =
- asn1_wrapper:encode('PrimStrings','OsExpApp',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','OsExpApp',lists:flatten(Bytes13)),
-
-
-
-
-
+ roundtrip('OsExpCon', [47,23,99,255,1]),
+ roundtrip('OsExpPri', [47,23,99,255,1]),
+ roundtrip('OsExpApp', [47,23,99,255,1]),
+ roundtrip('Os', []),
+ roundtrip('OsApp', []),
+ roundtrip('OsExpApp',[]),
OsR = "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
- ?line {ok,Bytes21} =
- asn1_wrapper:encode('PrimStrings','Os',OsR),
- ?line {ok,Os1} = asn1_wrapper:decode('PrimStrings','Os',lists:flatten(Bytes21)),
- ?line Os1 = OsR,
- ?line {ok,Bytes22} =
- asn1_wrapper:encode('PrimStrings','OsCon',OsR),
- ?line {ok,Os2} = asn1_wrapper:decode('PrimStrings','OsCon',lists:flatten(Bytes22)),
- ?line Os2 = OsR,
- ?line {ok,Bytes23} =
- asn1_wrapper:encode('PrimStrings','OsExpApp',OsR),
- ?line {ok,Os3} = asn1_wrapper:decode('PrimStrings','OsExpApp',lists:flatten(Bytes23)),
- ?line Os3 = OsR,
-
+ roundtrip('Os', OsR),
+ roundtrip('OsCon', OsR),
+ roundtrip('OsExpApp', OsR),
?line case asn1_wrapper:erule(Rules) of
@@ -416,21 +371,90 @@ octet_string(Rules) ->
ok
end,
+ fragmented_octet_string(Rules),
+ S255 = lists:seq(1, 255),
+ FixedStrings = {'OsFixedStrings',true,"","1","12","345",true,
+ S255,[$a|S255],[$a,$b|S255],397},
+ roundtrip('OsFixedStrings', FixedStrings),
ok.
+fragmented_octet_string(Erules) ->
+ K16 = 1 bsl 14,
+ K32 = K16 + K16,
+ K48 = K32 + K16,
+ K64 = K48 + K16,
+ Lens = [0,1,14,15,16,17,127,128,
+ K16-1,K16,K16+1,K16+(1 bsl 7)-1,K16+(1 bsl 7),K16+(1 bsl 7)+1,
+ K32-1,K32,K32+1,K32+(1 bsl 7)-1,K32+(1 bsl 7),K32+(1 bsl 7)+1,
+ K48-1,K48,K48+1,K48+(1 bsl 7)-1,K48+(1 bsl 7),K48+(1 bsl 7)+1,
+ K64-1,K64,K64+1,K64+(1 bsl 7)-1,K64+(1 bsl 7),K64+(1 bsl 7)+1,
+ K64+K16-1,K64+K16,K64+K16+1],
+ Types = ['Os','OsFrag'],
+ [fragmented_octet_string(Erules, Types, L) || L <- Lens],
+ fragmented_octet_string(Erules, ['FixedOs65536'], 65536),
+ fragmented_octet_string(Erules, ['FixedOs65537'], 65537),
+
+ %% Make sure that octet alignment works.
+ roundtrip('OsAlignment',
+ {'OsAlignment',false,make_value(70000),true,make_value(66666),
+ false,make_value(65536),42}),
+ roundtrip('OsAlignment',
+ {'OsAlignment',false,make_value(0),true,make_value(0),
+ false,make_value(65536),42}),
+ ok.
+fragmented_octet_string(Erules, Types, L) ->
+ Value = make_value(L),
+ [begin
+ Encoded = enc_frag(Erules, Type, Value),
+ {ok,Value} = 'PrimStrings':decode(Type, Encoded)
+ end || Type <- Types],
+ ok.
+
+enc_frag(Erules, Type, Value) ->
+ {ok,Encoded} = 'PrimStrings':encode(Type, Value),
+ case Erules of
+ ber ->
+ Encoded;
+ _ ->
+ %% Validate encoding with our own encoder.
+ Encoded = enc_frag_1(<<>>, list_to_binary(Value))
+ end.
+
+enc_frag_1(Res, Bin0) ->
+ K16 = 1 bsl 14,
+ Sz = byte_size(Bin0),
+ if
+ Sz >= K16 ->
+ F = min(Sz div K16, 4),
+ FragSize = F * K16,
+ <<Frag:FragSize/binary-unit:8,Bin/binary>> = Bin0,
+ enc_frag_1(<<Res/binary,3:2,F:6,Frag/binary>>, Bin);
+ Sz >= 128 ->
+ <<Res/binary,1:1,0:1,Sz:14,Bin0/binary>>;
+ true ->
+ <<Res/binary,0:1,Sz:7,Bin0/binary>>
+ end.
+
+make_value(L) ->
+ make_value(L, 0, []).
+
+make_value(0, _, Acc) ->
+ Acc;
+make_value(N, Byte, Acc) when Byte =< 255 ->
+ make_value(N-1, Byte+7, [Byte|Acc]);
+make_value(N, Byte, Acc) ->
+ make_value(N, Byte band 16#FF, Acc).
-
numeric_string(Rules) ->
%%==========================================================
%% Ns ::= NumericString
%%==========================================================
- ?line {ok,BytesNs2} = asn1_wrapper:encode('PrimStrings','Ns',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','Ns',lists:flatten(BytesNs2)),
+ roundtrip('Ns', []),
?line case asn1_wrapper:erule(Rules) of
ber ->
@@ -455,10 +479,7 @@ numeric_string(Rules) ->
%% NsCon ::= [70] NumericString
%%==========================================================
- ?line {ok,BytesNs12} = asn1_wrapper:encode('PrimStrings','NsCon',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','NsCon',lists:flatten(BytesNs12)),
-
-
+ roundtrip('NsCon', []),
?line case asn1_wrapper:erule(Rules) of
ber ->
@@ -482,10 +503,7 @@ numeric_string(Rules) ->
%% NsExpCon ::= [71] EXPLICIT NumericString
%%==========================================================
- ?line {ok,BytesNs22} = asn1_wrapper:encode('PrimStrings','NsExpCon',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','NsExpCon',lists:flatten(BytesNs22)),
-
-
+ roundtrip('NsExpCon', []),
?line case asn1_wrapper:erule(Rules) of
ber ->
@@ -507,9 +525,6 @@ numeric_string(Rules) ->
ok.
-
-
-
other_strings(_Rules) ->
@@ -517,49 +532,27 @@ other_strings(_Rules) ->
%% Ps ::= PrintableString
%%==========================================================
- ?line {ok,BytesPs1} = asn1_wrapper:encode('PrimStrings','Ps',[47,23,99,75,47]),
- ?line {ok,[47,23,99,75,47]} =
- asn1_wrapper:decode('PrimStrings','Ps',lists:flatten(BytesPs1)),
-
- ?line {ok,BytesPs2} = asn1_wrapper:encode('PrimStrings','Ps',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','Ps',lists:flatten(BytesPs2)),
-
+ roundtrip('Ps', [47,23,99,75,47]),
+ roundtrip('Ps', []),
%%==========================================================
%% Vis ::= VisibleString
%%==========================================================
- ?line {ok,BytesVis1} = asn1_wrapper:encode('PrimStrings','Vis',[47,23,99,75,47]),
- ?line {ok,[47,23,99,75,47]} =
- asn1_wrapper:decode('PrimStrings','Vis',lists:flatten(BytesVis1)),
-
- ?line {ok,BytesVis2} = asn1_wrapper:encode('PrimStrings','Vis',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','Vis',lists:flatten(BytesVis2)),
-
+ roundtrip('Vis', [47,23,99,75,47]),
+ roundtrip('Vis', []),
%%==========================================================
%% IA5 ::= IA5String
%%==========================================================
- ?line {ok,BytesIA51} = asn1_wrapper:encode('PrimStrings','IA5',[47,23,99,75,47]),
- ?line {ok,[47,23,99,75,47]} =
- asn1_wrapper:decode('PrimStrings','IA5',lists:flatten(BytesIA51)),
-
- ?line {ok,BytesIA52} = asn1_wrapper:encode('PrimStrings','IA5',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','IA5',lists:flatten(BytesIA52)),
+ roundtrip('IA5', [47,23,99,75,47]),
+ roundtrip('IA5', []),
-
IA5_1 = "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
-
- ?line {ok,BytesIA53} = asn1_wrapper:encode('PrimStrings','IA5',IA5_1),
- ?line {ok,IA5_1r} = asn1_wrapper:decode('PrimStrings','IA5',lists:flatten(BytesIA53)),
- ?line IA5_1 = IA5_1r,
-
-
-
-
+ roundtrip('IA5', IA5_1),
ok.
@@ -568,94 +561,60 @@ more_strings(_Rules) ->
%% Ts ::= TeletexString
%%==========================================================
- ?line {ok,BytesTs1} = asn1_wrapper:encode('PrimStrings','Ts',[47,23,99,75,47]),
- ?line {ok,[47,23,99,75,47]} =
- asn1_wrapper:decode('PrimStrings','Ts',lists:flatten(BytesTs1)),
-
- ?line {ok,BytesTs2} = asn1_wrapper:encode('PrimStrings','Ts',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','Ts',lists:flatten(BytesTs2)),
-
+ roundtrip('Ts', [47,23,99,75,47]),
+ roundtrip('Ts', []),
%%==========================================================
%% Vxs ::= VideotexString
%%==========================================================
- ?line {ok,BytesVxs1} = asn1_wrapper:encode('PrimStrings','Vxs',[47,23,99,75,47]),
- ?line {ok,[47,23,99,75,47]} =
- asn1_wrapper:decode('PrimStrings','Vxs',lists:flatten(BytesVxs1)),
-
- ?line {ok,BytesVxs2} = asn1_wrapper:encode('PrimStrings','Vxs',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','Vxs',lists:flatten(BytesVxs2)),
-
+ roundtrip('Vxs', [47,23,99,75,47]),
+ roundtrip('Vxs', []),
%%==========================================================
%% Grs ::= GraphicString
%%==========================================================
- ?line {ok,BytesGrs1} = asn1_wrapper:encode('PrimStrings','Grs',[47,23,99,75,47]),
- ?line {ok,[47,23,99,75,47]} =
- asn1_wrapper:decode('PrimStrings','Grs',lists:flatten(BytesGrs1)),
-
- ?line {ok,BytesGrs2} = asn1_wrapper:encode('PrimStrings','Grs',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','Grs',lists:flatten(BytesGrs2)),
+ roundtrip('Grs',[47,23,99,75,47]),
+ roundtrip('Grs', []),
%%==========================================================
%% ODesc ::= ObjectDescriptor, test case for OTP-4161
%%==========================================================
- ?line {ok,BytesODesc1} = asn1_wrapper:encode('PrimStrings','ODesc',[79,98,106,101,99,116,68,101,115,99,114,105,112,116,111,114]),
- ?line {ok,[79,98,106,101,99,116,68,101,115,99,114,105,112,116,111,114]} =
- asn1_wrapper:decode('PrimStrings','ODesc',lists:flatten(BytesODesc1)),
-
- ?line {ok,BytesODesc2} = asn1_wrapper:encode('PrimStrings','ODesc',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','ODesc',lists:flatten(BytesODesc2)),
+ roundtrip('ODesc', [79,98,106,101,99,116,68,101,115,99,114,
+ 105,112,116,111,114]),
+ roundtrip('ODesc', []),
%%==========================================================
%% Ges ::= GeneralString
%%==========================================================
- ?line {ok,BytesGes1} = asn1_wrapper:encode('PrimStrings','Ges',[47,23,99,75,47]),
- ?line {ok,[47,23,99,75,47]} =
- asn1_wrapper:decode('PrimStrings','Ges',lists:flatten(BytesGes1)),
-
- ?line {ok,BytesGes2} = asn1_wrapper:encode('PrimStrings','Ges',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','Ges',lists:flatten(BytesGes2)),
-
- ok.
+ roundtrip('Ges', [47,23,99,75,47]),
+ roundtrip('Ges', []),
+ ok.
universal_string(Rules) ->
-
%%==========================================================
%% Us ::= UniversalString
%%==========================================================
- ?line {ok,Bytes1} =
- asn1_wrapper:encode('PrimStrings','Us',[{47,23,99,47},{0,0,55,66}]),
- ?line {ok,[{47,23,99,47},{0,0,55,66}]} =
- asn1_wrapper:decode('PrimStrings','Us',lists:flatten(Bytes1)),
+ roundtrip('Us', [{47,23,99,47},{0,0,55,66}]),
?line {ok,Bytes2} =
asn1_wrapper:encode('PrimStrings','Us',[{47,23,99,255},{0,0,0,201}]),
?line {ok,[{47,23,99,255},201]} =
asn1_wrapper:decode('PrimStrings','Us',lists:flatten(Bytes2)),
- ?line {ok,Bytes3} = asn1_wrapper:encode('PrimStrings','Us',"Universal String"),
- ?line {ok,"Universal String"} =
- asn1_wrapper:decode('PrimStrings','Us',lists:flatten(Bytes3)),
-
- ?line {ok,Bytes4} = asn1_wrapper:encode('PrimStrings','Us',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','Us',lists:flatten(Bytes4)),
-
- ?line {ok,Bytes5} = asn1_wrapper:encode('PrimStrings','Us',[{47,23,99,47}]),
- ?line {ok,[{47,23,99,47}]} =
- asn1_wrapper:decode('PrimStrings','Us',lists:flatten(Bytes5)),
-
+ roundtrip('Us', "Universal String"),
+ roundtrip('Us', []),
+ roundtrip('Us', [{47,23,99,47}]),
?line case asn1_wrapper:erule(Rules) of
ber ->
@@ -670,32 +629,22 @@ universal_string(Rules) ->
Us1 = "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
- ?line {ok,Bytes15} = asn1_wrapper:encode('PrimStrings','IA5',Us1),
- ?line {ok,Us1r} = asn1_wrapper:decode('PrimStrings','IA5',lists:flatten(Bytes15)),
- ?line Us1 = Us1r,
-
+ roundtrip('IA5', Us1),
%%==========================================================
%% UsCon ::= [70] UniversalString
%%==========================================================
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('PrimStrings','UsCon',[{47,23,99,255},{0,0,2,201}]),
- ?line {ok,[{47,23,99,255},{0,0,2,201}]} =
- asn1_wrapper:decode('PrimStrings','UsCon',lists:flatten(Bytes11)),
+ roundtrip('UsCon', [{47,23,99,255},{0,0,2,201}]),
?line {ok,Bytes12} =
asn1_wrapper:encode('PrimStrings','UsCon',[{47,23,99,255},{0,0,0,201}]),
?line {ok,[{47,23,99,255},201]} =
asn1_wrapper:decode('PrimStrings','UsCon',lists:flatten(Bytes12)),
- ?line {ok,Bytes13} = asn1_wrapper:encode('PrimStrings','UsCon',"Universal String"),
- ?line {ok,"Universal String"} =
- asn1_wrapper:decode('PrimStrings','UsCon',lists:flatten(Bytes13)),
-
- ?line {ok,Bytes14} = asn1_wrapper:encode('PrimStrings','UsCon',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','UsCon',lists:flatten(Bytes14)),
+ roundtrip('UsCon', "Universal String"),
+ roundtrip('UsCon', []),
?line case asn1_wrapper:erule(Rules) of
ber ->
@@ -712,25 +661,15 @@ universal_string(Rules) ->
%% UsExpCon ::= [71] EXPLICIT UniversalString
%%==========================================================
- ?line {ok,Bytes21} =
- asn1_wrapper:encode('PrimStrings','UsExpCon',[{47,23,99,255},{0,0,2,201}]),
- ?line {ok,[{47,23,99,255},{0,0,2,201}]} =
- asn1_wrapper:decode('PrimStrings','UsExpCon',lists:flatten(Bytes21)),
+ roundtrip('UsExpCon', [{47,23,99,255},{0,0,2,201}]),
?line {ok,Bytes22} =
asn1_wrapper:encode('PrimStrings','UsExpCon',[{47,23,99,255},{0,0,0,201}]),
?line {ok,[{47,23,99,255},201]} =
asn1_wrapper:decode('PrimStrings','UsExpCon',lists:flatten(Bytes22)),
- ?line {ok,Bytes23} =
- asn1_wrapper:encode('PrimStrings','UsExpCon',"Universal String"),
- ?line {ok,"Universal String"} =
- asn1_wrapper:decode('PrimStrings','UsExpCon',lists:flatten(Bytes23)),
-
- ?line {ok,Bytes24} =
- asn1_wrapper:encode('PrimStrings','UsExpCon',[]),
- ?line {ok,[]} =
- asn1_wrapper:decode('PrimStrings','UsExpCon',lists:flatten(Bytes24)),
+ roundtrip('UsExpCon', "Universal String"),
+ roundtrip('UsExpCon', []),
?line case asn1_wrapper:erule(Rules) of
ber ->
@@ -740,12 +679,8 @@ universal_string(Rules) ->
asn1_wrapper:decode('PrimStrings','UsExpCon',lists:flatten([16#BF,16#47,16,60,16#80,28,4,47,23,99,255,28,4,0,0,2,201,0,0]));
_ -> ok
end,
-
-
-ok.
-
-
+ ok.
bmp_string(_Rules) ->
@@ -754,29 +689,18 @@ bmp_string(_Rules) ->
%% BMP ::= BMPString
%%==========================================================
- ?line {ok,Bytes1} =
- asn1_wrapper:encode('PrimStrings','BMP',[{0,0,99,48},{0,0,2,201}]),
- ?line {ok,[{0,0,99,48},{0,0,2,201}]} =
- asn1_wrapper:decode('PrimStrings','BMP',lists:flatten(Bytes1)),
+ roundtrip('BMP', [{0,0,99,48},{0,0,2,201}]),
?line {ok,Bytes2} =
asn1_wrapper:encode('PrimStrings','BMP',[{0,0,0,48},{0,0,2,201}]),
?line {ok,[48,{0,0,2,201}]} =
asn1_wrapper:decode('PrimStrings','BMP',lists:flatten(Bytes2)),
-
- ?line {ok,Bytes3} = asn1_wrapper:encode('PrimStrings','BMP',"BMP String"),
- ?line {ok,"BMP String"} =
- asn1_wrapper:decode('PrimStrings','BMP',lists:flatten(Bytes3)),
-
- ?line {ok,Bytes4} = asn1_wrapper:encode('PrimStrings','BMP',[]),
- ?line {ok,[]} = asn1_wrapper:decode('PrimStrings','BMP',lists:flatten(Bytes4)),
+ roundtrip('BMP', "BMP String"),
+ roundtrip('BMP', []),
BMP1 = "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
- ?line {ok,Bytes5} = asn1_wrapper:encode('PrimStrings','BMP',BMP1),
- ?line {ok,BMP1r} = asn1_wrapper:decode('PrimStrings','BMP',lists:flatten(Bytes5)),
- ?line BMP1 = BMP1r,
-
+ roundtrip('BMP', BMP1),
ok.
@@ -790,35 +714,17 @@ times(_Rules) ->
%% Gt ::= GeneralizedTime
%%==========================================================
- ?line {ok,Bytes1} = asn1_wrapper:encode('PrimStrings','Gt',"19970923110723.2"),
- ?line {ok,"19970923110723.2"} =
- asn1_wrapper:decode('PrimStrings','Gt',lists:flatten(Bytes1)),
+ roundtrip('Gt', "19970923110723.2"),
+ roundtrip('Gt', "19970923110723.2Z"),
+ roundtrip('Gt', "19970923110723.2-0500"),
- ?line {ok,Bytes2} = asn1_wrapper:encode('PrimStrings','Gt',"19970923110723.2Z"),
- ?line {ok,"19970923110723.2Z"} =
- asn1_wrapper:decode('PrimStrings','Gt',lists:flatten(Bytes2)),
-
- ?line {ok,Bytes3} = asn1_wrapper:encode('PrimStrings','Gt',"19970923110723.2-0500"),
- ?line {ok,"19970923110723.2-0500"} =
- asn1_wrapper:decode('PrimStrings','Gt',lists:flatten(Bytes3)),
-
-
-
-
-
-
%%==========================================================
%% UTC ::= UTCTime
%%==========================================================
- ?line {ok,Bytes11} = asn1_wrapper:encode('PrimStrings','UTC',"9709211107Z"),
- ?line {ok,"9709211107Z"} =
- asn1_wrapper:decode('PrimStrings','UTC',lists:flatten(Bytes11)),
-
- ?line {ok,Bytes12} = asn1_wrapper:encode('PrimStrings','UTC',"9709211107-0500"),
- ?line {ok,"9709211107-0500"} =
- asn1_wrapper:decode('PrimStrings','UTC',lists:flatten(Bytes12)),
+ roundtrip('UTC', "9709211107Z"),
+ roundtrip('UTC', "9709211107-0500"),
ok.
@@ -917,3 +823,8 @@ wrapper_utf8_binary_to_list(L) when is_list(L) ->
asn1rt:utf8_binary_to_list(list_to_binary(L));
wrapper_utf8_binary_to_list(B) ->
asn1rt:utf8_binary_to_list(B).
+
+roundtrip(Type, Value) ->
+ {ok,Encoded} = 'PrimStrings':encode(Type, Value),
+ {ok,Value} = 'PrimStrings':decode(Type, Encoded),
+ ok.
diff --git a/lib/asn1/test/testSSLspecs.erl b/lib/asn1/test/testSSLspecs.erl
index 51ef134e5f..45c5da50f0 100644
--- a/lib/asn1/test/testSSLspecs.erl
+++ b/lib/asn1/test/testSSLspecs.erl
@@ -42,11 +42,11 @@ compile(Config, Options) ->
asn1_test_lib:compile_all(["PKIX1Explicit93", "PKIX1Implicit93"],
Config, NewOptions).
-compile_inline(Config, Rule) when Rule == ber_bin; Rule == ber_bin_v2 ->
+compile_inline(Config, ber=Rule) ->
DataDir = ?config(data_dir, Config),
CaseDir = ?config(case_dir, Config),
Options = [{i, CaseDir}, {i, DataDir}, Rule,
- der, compact_bit_string, optimize, asn1config, inline],
+ der, compact_bit_string, asn1config, inline],
ok = remove_db_file_inline(CaseDir),
asn1_test_lib:compile("OTP-PKIX.set.asn", Config, Options);
compile_inline(_Config, _Rule) ->
@@ -73,7 +73,7 @@ remove_db_file_inline(Dir) ->
?line ok = remove_db_file(Dir ++ "PKIX1Explicit88.asn1db"),
?line ok = remove_db_file(Dir ++ "PKIX1Implicit88.asn1db").
-run(BER) when BER==ber_bin;BER==ber_bin_v2 ->
+run(ber) ->
run1(1);
run(_) ->
ok.
@@ -100,20 +100,20 @@ transform1(ATAV) ->
?line {ok, ATAVEnc} = 'PKIX1Explicit88':encode('AttributeTypeAndValue',
ATAV),
?line {ok, _ATAVDec} = 'SSL-PKIX':decode('AttributeTypeAndValue',
- list_to_binary(ATAVEnc)).
+ ATAVEnc).
transform2(ATAV) ->
?line {ok, ATAVEnc} = 'PKIX1Explicit88':encode('AttributeTypeAndValue',
ATAV),
?line {ok, _ATAVDec} = 'PKIX1Explicit88':decode('AttributeTypeAndValue',
- list_to_binary(ATAVEnc)).
+ ATAVEnc).
transform4(ATAV) ->
?line {ok, ATAVEnc} = 'PKIX1Explicit88':encode('Attribute',
ATAV),
?line {ok, _ATAVDec} = 'PKIX1Explicit88':decode('Attribute',
- list_to_binary(ATAVEnc)).
+ ATAVEnc).
ex(1) ->
@@ -146,7 +146,7 @@ ex(7) ->
{1,2,840,113549,1,9,1},
[[19,5,111,116,112,67,65]]}.
-run_inline(Rule) when Rule==ber_bin;Rule==ber_bin_v2 ->
+run_inline(ber) ->
Cert = cert(),
?line {ok,{'CertificatePKIX1Explicit88',{Type,UnDec},_,_}} = 'OTP-PKIX':decode_TBSCert_exclusive(Cert),
?line {ok,_} = 'OTP-PKIX':decode_part(Type,UnDec),
diff --git a/lib/asn1/test/testSeqExtension.erl b/lib/asn1/test/testSeqExtension.erl
index 7c77ab87e9..1128d9a7c3 100644
--- a/lib/asn1/test/testSeqExtension.erl
+++ b/lib/asn1/test/testSeqExtension.erl
@@ -20,7 +20,7 @@
-module(testSeqExtension).
-include("External.hrl").
--export([main/1]).
+-export([main/2]).
-include_lib("test_server/include/test_server.hrl").
@@ -28,70 +28,73 @@
-record('SeqExt2',{bool, int}).
-record('SeqExt3',{bool, int}).
-record('SeqExt4',{bool, int}).
-
-
-main(_Rules) ->
-
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('SeqExtension','SeqExt1',#'SeqExt1'{}),
- ?line {ok,{'SeqExt1'}} =
- asn1_wrapper:decode('SeqExtension','SeqExt1',lists:flatten(Bytes11)),
-
- ?line {ok,Bytes21} =
- asn1_wrapper:encode('SeqExtension','SeqExt2',#'SeqExt2'{bool = true,int = 99}),
- ?line {ok,{'SeqExt2',true,99}} =
- asn1_wrapper:decode('SeqExtension','SeqExt2',lists:flatten(Bytes21)),
-
- ?line {ok,Bytes22} =
- asn1_wrapper:encode('SeqExtension','SeqExt2',#'SeqExt2'{int = 99,bool = true}),
- ?line {ok,{'SeqExt2',true,99}} =
- asn1_wrapper:decode('SeqExtension','SeqExt2',lists:flatten(Bytes22)),
-
- ?line {ok,Bytes31} =
- asn1_wrapper:encode('SeqExtension','SeqExt3',#'SeqExt3'{bool = true,int = 99}),
- ?line {ok,{'SeqExt3',true,99}} =
- asn1_wrapper:decode('SeqExtension','SeqExt3',lists:flatten(Bytes31)),
-
- ?line {ok,Bytes32} =
- asn1_wrapper:encode('SeqExtension','SeqExt3',#'SeqExt3'{int = 99,bool = true}),
- ?line {ok,{'SeqExt3',true,99}} =
- asn1_wrapper:decode('SeqExtension','SeqExt3',lists:flatten(Bytes32)),
-
- ?line {ok,Bytes41} =
- asn1_wrapper:encode('SeqExtension','SeqExt4',#'SeqExt4'{bool = true,int = 99}),
- ?line {ok,{'SeqExt4',true,99}} =
- asn1_wrapper:decode('SeqExtension','SeqExt4',lists:flatten(Bytes41)),
-
- ?line {ok,Bytes42} =
- asn1_wrapper:encode('SeqExtension','SeqExt4',#'SeqExt4'{int = 99,bool = true}),
- ?line {ok,{'SeqExt4',true,99}} =
- asn1_wrapper:decode('SeqExtension','SeqExt4',lists:flatten(Bytes42)),
-
-
- % test of extension , not ready
-
- ?line {ok,BytesX11} =
- asn1_wrapper:encode('SeqExtension','SeqExt1',#'SeqExt1'{}),
- ?line {ok,{'SeqExt1'}} =
- asn1_wrapper:decode('SeqExtension','SeqExt1',lists:flatten(BytesX11)),
-
- ?line {ok,BytesX21} =
- asn1_wrapper:encode('SeqExtension','SeqExt2',#'SeqExt2'{bool = true,int = 99}),
- ?line {ok,{'SeqExt2',true,99}} =
- asn1_wrapper:decode('SeqExtension','SeqExt2',lists:flatten(BytesX21)),
-
- ?line {ok,BytesX22} =
- asn1_wrapper:encode('SeqExtension','SeqExt2',#'SeqExt2'{int = 99,bool = true}),
- ?line {ok,{'SeqExt2',true,99}} =
- asn1_wrapper:decode('SeqExtension','SeqExt2',lists:flatten(BytesX22)),
-
-
-
-
-
+-record('SeqExt5',{name, shoesize}).
+-record('SeqExt6',{i1,i2,i3,i4,i5,i6,i7}).
+-record('SuperSeq',{s1,s2,s3,s4,s5,s6,i}).
+
+main(DataDir, Opts) ->
+ roundtrip('SeqExt1', #'SeqExt1'{}),
+
+ roundtrip('SeqExt2', #'SeqExt2'{bool=true,int=99}),
+ roundtrip('SeqExt2', #'SeqExt2'{bool=false,int=42}),
+
+ roundtrip('SeqExt3', #'SeqExt3'{bool=true,int=-77777}),
+ roundtrip('SeqExt3', #'SeqExt3'{bool=false,int=-42000}),
+
+ roundtrip('SeqExt4', #'SeqExt4'{bool=true,int=12345}),
+ roundtrip('SeqExt4', #'SeqExt4'{bool=false,int=123456}),
+
+ roundtrip('SeqExt5', #'SeqExt5'{name="Arne",shoesize=47}),
+
+ %% Encode a value with this version of the specification.
+ BigInt = 128638468966,
+ SuperSeq = #'SuperSeq'{s1=#'SeqExt1'{},
+ s2=#'SeqExt2'{bool=true,int=2345},
+ s3=#'SeqExt3'{bool=false,int=17},
+ s4=#'SeqExt4'{bool=true,int=38739739},
+ s5=#'SeqExt5'{name="Arne",shoesize=47},
+ s6=#'SeqExt6'{i1=531,i2=601,i3=999,
+ i4=777,i5=11953,
+ i6=13553,i7=77777},
+ i=BigInt
+ },
+ {ok,SuperSeqEnc} = 'SeqExtension':encode('SuperSeq', SuperSeq),
+ {ok,SuperSeq} = 'SeqExtension':decode('SuperSeq', SuperSeqEnc),
+
+ %% Remove all extensions from the ASN.1 specification and compile it.
+ CaseDir = filename:dirname(code:which('SeqExtension')),
+ Asn1SrcBase = "SeqExtension.asn1",
+ Asn1SrcFile0 = filename:join(DataDir, Asn1SrcBase),
+ {ok,Src0} = file:read_file(Asn1SrcFile0),
+ %% Remove all declarations following "...," up to the end
+ %% of the SEQUENCE.
+ Src1 = re:replace(Src0, "[.][.][.],[^}]*", "...\n",
+ [global,{return,binary}]),
+ %% Remove the last double bracket group in the SEQUENCE.
+ Src = re:replace(Src1, ",\\s*\\[\\[.*?\\]\\]\\s*\\}", "\n}",
+ [global,{return,binary}]),
+ io:format("~s\n\n", [Src]),
+ Asn1SrcFile = filename:join(CaseDir, Asn1SrcBase),
+ ok = file:write_file(Asn1SrcFile, Src),
+ ok = asn1ct:compile(Asn1SrcFile,
+ [{i,DataDir},{outdir,CaseDir}|Opts]),
+
+ %% Decode the encoded sequence with the version of the spec
+ %% with no extensions following the extension marks
+ %% (except in SeqExt6). The integer 'i' at the end
+ %% of the sequence must still be the correct integer (otherwise
+ %% some extension has not been skipped correctly).
+ {ok,DecodedSuperSeq} = 'SeqExtension':decode('SuperSeq', SuperSeqEnc),
+ #'SuperSeq'{s1={'SeqExt1'},
+ s2=#'SeqExt2'{bool=true,int=2345},
+ s3={'SeqExt3'},
+ s4={'SeqExt4',true},
+ s5={'SeqExt5'},
+ s6={'SeqExt6',531,601,999,777,11953},
+ i=BigInt} = DecodedSuperSeq,
ok.
-
-
-
-
+roundtrip(Type, Value) ->
+ {ok,Encoded} = 'SeqExtension':encode(Type, Value),
+ {ok,Value} = 'SeqExtension':decode(Type, Encoded),
+ ok.
diff --git a/lib/asn1/test/testSeqIndefinite.erl b/lib/asn1/test/testSeqIndefinite.erl
index 25742474bb..c7b8aba523 100644
--- a/lib/asn1/test/testSeqIndefinite.erl
+++ b/lib/asn1/test/testSeqIndefinite.erl
@@ -23,13 +23,7 @@
-include_lib("test_server/include/test_server.hrl").
-
-main(per_bin) -> ok;
main(per) -> ok;
-main(ber_bin_v2) ->
- main(ber);
-main(ber_bin) ->
- main(ber);
main(ber) ->
%% normal encoding
diff --git a/lib/asn1/test/testSeqOf.erl b/lib/asn1/test/testSeqOf.erl
index 0c0bbc3e66..1aa1eab26d 100644
--- a/lib/asn1/test/testSeqOf.erl
+++ b/lib/asn1/test/testSeqOf.erl
@@ -198,19 +198,10 @@ main(Rules) ->
?line {ok,Bytes51} = asn1_wrapper:encode('SeqOf','SeqEmp',#'SeqEmp'{seq1 = [#'Empty'{}]}),
?line {ok,{'SeqEmp',[{'Empty'}]}} = asn1_wrapper:decode('SeqOf','SeqEmp',lists:flatten(Bytes51)),
-
- case Rules of
- ber ->
- ?line {ok,Bytes52} = asn1_wrapper:encode('SeqOfEnum','SeqOfEnum',
- {'SeqOfEnum',[{'Enum',a},{'Enum',b}]}),
- ?line {ok,[a,b]} = asn1_wrapper:decode('SeqOfEnum','SeqOfEnum',
- lists:flatten(Bytes52));
- _ -> ok
- end,
%% tests of OTP-4590
case Rules of
- PER when PER == per; PER == per_bin ->
+ per ->
DayNames = ["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"],
?line {ok,Bytes60} = asn1_wrapper:encode('XSeqOf','DayNames2',DayNames),
?line {ok,Bytes60} = asn1_wrapper:encode('XSeqOf','DayNames4',DayNames),
diff --git a/lib/asn1/test/testSetIndefinite.erl b/lib/asn1/test/testSetIndefinite.erl
index d8e2b6a9cf..73006da62b 100644
--- a/lib/asn1/test/testSetIndefinite.erl
+++ b/lib/asn1/test/testSetIndefinite.erl
@@ -24,12 +24,7 @@
-include_lib("test_server/include/test_server.hrl").
-main(per_bin) -> ok;
main(per) -> ok;
-main(ber_bin_v2) ->
- main(ber);
-main(ber_bin) ->
- main(ber);
main(ber) ->
%% normal encoding
diff --git a/lib/asn1/test/testSetOptional.erl b/lib/asn1/test/testSetOptional.erl
index 4692941524..bb43ff0a96 100644
--- a/lib/asn1/test/testSetOptional.erl
+++ b/lib/asn1/test/testSetOptional.erl
@@ -21,8 +21,7 @@
-include("External.hrl").
-export([main/1]).
--export([ticket_7533/1,decoder/4]).
--include_lib("test_server/include/test_server.hrl").
+-export([ticket_7533/1]).
-record('SetOpt1',{bool1 = asn1_NOVALUE, int1, set1 = asn1_NOVALUE}).
-record('SetOpt1Imp',{bool1 = asn1_NOVALUE, int1, set1 = asn1_NOVALUE}).
@@ -36,171 +35,64 @@
-record('SetIn',{boolIn, intIn}).
main(_Rules) ->
+ roundtrip('SetOpt1',
+ #'SetOpt1'{bool1=true,int1=15,
+ set1=#'SetIn'{boolIn=true,intIn=66}}),
+ roundtrip('SetOpt1', #'SetOpt1'{int1=15}),
+
+ roundtrip('SetOpt2', #'SetOpt2'{bool2=true,int2=15,
+ set2=#'SetIn'{boolIn=true,intIn=66}}),
+ roundtrip('SetOpt2', #'SetOpt2'{int2=15,bool2=true}),
+
+ roundtrip('SetOpt3', #'SetOpt3'{bool3=true,int3=15,
+ set3=#'SetIn'{boolIn=true,intIn=66}}),
+ roundtrip('SetOpt3', #'SetOpt3'{int3=15}),
+
+ roundtrip('SetOpt1Imp',
+ #'SetOpt1Imp'{bool1=true,int1 = 15,
+ set1=#'SetIn'{boolIn = true,intIn = 66}}),
+ roundtrip('SetOpt1Imp', #'SetOpt1Imp'{int1=15}),
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('SetOptional','SetOpt1',#'SetOpt1'{bool1 = true,
- int1 = 15,
- set1 = #'SetIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SetOpt1',true,15,{'SetIn',true,66}}} =
- asn1_wrapper:decode('SetOptional','SetOpt1',lists:flatten(Bytes11)),
-
-
- ?line {ok,Bytes12} = asn1_wrapper:encode('SetOptional','SetOpt1',#'SetOpt1'{int1 = 15}),
- ?line {ok,{'SetOpt1',asn1_NOVALUE,15,asn1_NOVALUE}} =
- asn1_wrapper:decode('SetOptional','SetOpt1',lists:flatten(Bytes12)),
-
-
- ?line {ok,Bytes21} =
- asn1_wrapper:encode('SetOptional','SetOpt2',#'SetOpt2'{bool2 = true,
- int2 = 15,
- set2 = #'SetIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SetOpt2',{'SetIn',true,66},true,15}} =
- asn1_wrapper:decode('SetOptional','SetOpt2',lists:flatten(Bytes21)),
-
-
- ?line {ok,Bytes22} = asn1_wrapper:encode('SetOptional','SetOpt2',#'SetOpt2'{int2 = 15,
- bool2 = true}),
- ?line {ok,{'SetOpt2',asn1_NOVALUE,true,15}} =
- asn1_wrapper:decode('SetOptional','SetOpt2',lists:flatten(Bytes22)),
-
-
-
- ?line {ok,Bytes31} =
- asn1_wrapper:encode('SetOptional','SetOpt3',#'SetOpt3'{bool3 = true,
- int3 = 15,
- set3 = #'SetIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SetOpt3',true,{'SetIn',true,66},15}} =
- asn1_wrapper:decode('SetOptional','SetOpt3',lists:flatten(Bytes31)),
-
-
- ?line {ok,Bytes32} = asn1_wrapper:encode('SetOptional','SetOpt3',#'SetOpt3'{int3 = 15}),
- ?line {ok,{'SetOpt3',asn1_NOVALUE,asn1_NOVALUE,15}} =
- asn1_wrapper:decode('SetOptional','SetOpt3',lists:flatten(Bytes32)),
-
-
-
-
-
- ?line {ok,Bytes41} =
- asn1_wrapper:encode('SetOptional','SetOpt1Imp',#'SetOpt1Imp'{bool1 = true,
- int1 = 15,
- set1 = #'SetIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SetOpt1Imp',true,15,{'SetIn',true,66}}} =
- asn1_wrapper:decode('SetOptional','SetOpt1Imp',lists:flatten(Bytes41)),
-
-
- ?line {ok,Bytes42} = asn1_wrapper:encode('SetOptional','SetOpt1Imp',#'SetOpt1Imp'{int1 = 15}),
- ?line {ok,{'SetOpt1Imp',asn1_NOVALUE,15,asn1_NOVALUE}} =
- asn1_wrapper:decode('SetOptional','SetOpt1Imp',lists:flatten(Bytes42)),
-
-
- ?line {ok,Bytes51} =
- asn1_wrapper:encode('SetOptional','SetOpt2Imp',#'SetOpt2Imp'{bool2 = true,
- int2 = 15,
- set2 = #'SetIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SetOpt2Imp',{'SetIn',true,66},true,15}} =
- asn1_wrapper:decode('SetOptional','SetOpt2Imp',lists:flatten(Bytes51)),
-
-
- ?line {ok,Bytes52} = asn1_wrapper:encode('SetOptional','SetOpt2Imp',#'SetOpt2Imp'{int2 = 15,
- bool2 = true}),
- ?line {ok,{'SetOpt2Imp',asn1_NOVALUE,true,15}} =
- asn1_wrapper:decode('SetOptional','SetOpt2Imp',lists:flatten(Bytes52)),
-
-
-
- ?line {ok,Bytes61} =
- asn1_wrapper:encode('SetOptional','SetOpt3Imp',#'SetOpt3Imp'{bool3 = true,
- int3 = 15,
- set3 = #'SetIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SetOpt3Imp',true,{'SetIn',true,66},15}} =
- asn1_wrapper:decode('SetOptional','SetOpt3Imp',lists:flatten(Bytes61)),
-
-
- ?line {ok,Bytes62} = asn1_wrapper:encode('SetOptional','SetOpt3Imp',#'SetOpt3Imp'{int3 = 15}),
- ?line {ok,{'SetOpt3Imp',asn1_NOVALUE,asn1_NOVALUE,15}} =
- asn1_wrapper:decode('SetOptional','SetOpt3Imp',lists:flatten(Bytes62)),
-
-
-
-
-
-
- ?line {ok,Bytes71} =
- asn1_wrapper:encode('SetOptional','SetOpt1Exp',#'SetOpt1Exp'{bool1 = true,
- int1 = 15,
- set1 = #'SetIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SetOpt1Exp',true,15,{'SetIn',true,66}}} =
- asn1_wrapper:decode('SetOptional','SetOpt1Exp',lists:flatten(Bytes71)),
-
-
- ?line {ok,Bytes72} = asn1_wrapper:encode('SetOptional','SetOpt1Exp',#'SetOpt1Exp'{int1 = 15}),
- ?line {ok,{'SetOpt1Exp',asn1_NOVALUE,15,asn1_NOVALUE}} =
- asn1_wrapper:decode('SetOptional','SetOpt1Exp',lists:flatten(Bytes72)),
-
-
- ?line {ok,Bytes81} =
- asn1_wrapper:encode('SetOptional','SetOpt2Exp',#'SetOpt2Exp'{bool2 = true,
- int2 = 15,
- set2 = #'SetIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SetOpt2Exp',{'SetIn',true,66},true,15}} =
- asn1_wrapper:decode('SetOptional','SetOpt2Exp',lists:flatten(Bytes81)),
-
-
- ?line {ok,Bytes82} = asn1_wrapper:encode('SetOptional','SetOpt2Exp',#'SetOpt2Exp'{int2 = 15,
- bool2 = true}),
- ?line {ok,{'SetOpt2Exp',asn1_NOVALUE,true,15}} =
- asn1_wrapper:decode('SetOptional','SetOpt2Exp',lists:flatten(Bytes82)),
-
-
-
- ?line {ok,Bytes91} =
- asn1_wrapper:encode('SetOptional','SetOpt3Exp',#'SetOpt3Exp'{bool3 = true,
- int3 = 15,
- set3 = #'SetIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SetOpt3Exp',true,{'SetIn',true,66},15}} =
- asn1_wrapper:decode('SetOptional','SetOpt3Exp',lists:flatten(Bytes91)),
-
-
- ?line {ok,Bytes92} = asn1_wrapper:encode('SetOptional','SetOpt3Exp',#'SetOpt3Exp'{int3 = 15}),
- ?line {ok,{'SetOpt3Exp',asn1_NOVALUE,asn1_NOVALUE,15}} =
- asn1_wrapper:decode('SetOptional','SetOpt3Exp',lists:flatten(Bytes92)),
-
+
+ roundtrip('SetOpt2Imp',
+ #'SetOpt2Imp'{bool2=true,int2=15,
+ set2=#'SetIn'{boolIn=true,intIn=66}}),
+ roundtrip('SetOpt2Imp',#'SetOpt2Imp'{int2=15,bool2=true}),
+
+ roundtrip('SetOpt3Imp',
+ #'SetOpt3Imp'{bool3=true,int3=15,
+ set3=#'SetIn'{boolIn=true,intIn=66}}),
+ roundtrip('SetOpt3Imp', #'SetOpt3Imp'{int3=15}),
+
+ roundtrip('SetOpt1Exp',
+ #'SetOpt1Exp'{bool1=true,int1=15,
+ set1=#'SetIn'{boolIn=true,intIn=66}}),
+ roundtrip('SetOpt1Exp', #'SetOpt1Exp'{int1=15}),
+
+ roundtrip('SetOpt2Exp',
+ #'SetOpt2Exp'{bool2=true,int2=15,
+ set2=#'SetIn'{boolIn=true,intIn=66}}),
+ roundtrip('SetOpt2Exp', #'SetOpt2Exp'{int2=15,bool2=true}),
+ roundtrip('SetOpt3Exp',
+ #'SetOpt3Exp'{bool3=true,int3=15,
+ set3=#'SetIn'{boolIn=true,intIn=66}}),
+ roundtrip('SetOpt3Exp', #'SetOpt3Exp'{int3=15}),
ok.
-ticket_7533(Ber) when Ber == ber; Ber == ber_bin ->
- Val = #'SetOpt1'{bool1 = true,int1=12,set1=#'SetIn'{boolIn=false,intIn=13}},
- ?line {ok,B} = asn1_wrapper:encode('SetOptional','SetOpt1',Val),
- ?line {ok,Val} = asn1_wrapper:decode('SetOptional','SetOpt1',B),
-
- CorruptVal = [49,14,1,1,255,2,1,12] ++ lists:duplicate(8,0),
- Pid = spawn(?MODULE,decoder,[self(),'SetOptional','SetOpt1',CorruptVal]),
- receive
- {ok,Pid,Result} ->
- io:format("Decode result: ~p~n",[Result]),
- ok
- after 10000 ->
- io:format("Decode timeout~n",[]),
- exit(Pid,normal)
- end;
+ticket_7533(Ber) when Ber == ber ->
+ Val = #'SetOpt1'{bool1=true,int1=12,set1=#'SetIn'{boolIn=false,intIn=13}},
+ roundtrip('SetOpt1', Val),
+ CorruptVal = <<49,14,1,1,255,2,1,12,0:8/unit:8>>,
+ {error,_} = 'SetOptional':decode('SetOpt1', CorruptVal),
+ ok;
ticket_7533(_) ->
ok.
-decoder(Parent,Module,Type,Val) ->
- io:format("Decoding~n",[]),
- ?line {ok,Res} = asn1_wrapper:decode(Module,Type,Val),
- io:format("Decode res: ~p~n",[Res]),
- Parent ! {ok,self(),Res}.
+roundtrip(Type, Value) ->
+ {ok,Encoded} = 'SetOptional':encode(Type, Value),
+ {ok,Value} = 'SetOptional':decode(Type, Encoded),
+ ok.
diff --git a/lib/asn1/test/testTCAP.erl b/lib/asn1/test/testTCAP.erl
index 878ce7c070..b723995e40 100644
--- a/lib/asn1/test/testTCAP.erl
+++ b/lib/asn1/test/testTCAP.erl
@@ -37,7 +37,7 @@ compile_asn1config(Config, Options) ->
asn1_test_lib:compile_all(Files, Config, Options),
asn1_test_lib:compile_erlang("TCAPPackage_msg", Config, []).
-test(Erule,_Config) when Erule==ber;Erule==ber_bin;Erule==ber_bin_v2 ->
+test(ber=Erule,_Config) ->
% ?line OutDir = ?config(priv_dir,Config),
%% testing OTP-4798, open type encoded with indefinite length
?line {ok,_Res} = asn1_wrapper:decode('TCAPMessages-simple','MessageType', val_OTP_4798(Erule)),
@@ -81,7 +81,7 @@ test_asn1config() ->
?line Val2 = 'TCAPPackage_msg':val('TransactionPDU'),
?line {ok,B2} = 'TCAPPackage':encode('TransactionPDU',Val2),
- ?line {ok,ExMsg2}='TCAPPackage':decode_TransactionPDU(list_to_binary(B2)),
+ {ok,ExMsg2}='TCAPPackage':decode_TransactionPDU(B2),
?line {_,_,_,{Key2,ExVal2}}=ExMsg2,
?line {ok,_Parts2}='TCAPPackage':decode_part(Key2,ExVal2),
diff --git a/lib/asn1/test/testTimer.erl b/lib/asn1/test/testTimer.erl
index 2d3b777558..cd7ceb5630 100644
--- a/lib/asn1/test/testTimer.erl
+++ b/lib/asn1/test/testTimer.erl
@@ -133,23 +133,7 @@ go(Config,Enc) ->
Module = 'H323-MESSAGES',
Type = 'H323-UserInformation',
Value = val(),
-%% ok = asn1ct:compile(HelpModule,[Enc]),
-
-%% ok = asn1ct:compile(Module,[Enc]),
- ?line {ok,B} = asn1rt:encode(Module,Type,Value),
- Bytes = case Enc of
- ber_bin ->
- list_to_binary(B);
- per_bin when is_list(B) ->
- list_to_binary(B);
- per_bin ->
- B;
- uper_bin ->
- B;
- _ ->
- %%lists:flatten(B)
- list_to_binary(B)
- end,
+ {ok,Bytes} = asn1rt:encode(Module,Type,Value),
CompileOptions = compile_options(),
@@ -181,35 +165,18 @@ encode(N, Module,Type,Value) ->
decode(0, _Module,_Type,_Value,_Erule) ->
done;
decode(N, Module,Type,Value,Erule) ->
- case Erule of
- ber ->
- ?line {ok,_B} = asn1rt:decode(Module,Type,binary_to_list(Value));
- per ->
- ?line {ok,_B} = asn1rt:decode(Module,Type,binary_to_list(Value));
- _ ->
- ?line {ok,_B} = asn1rt:decode(Module,Type,Value)
- end,
+ {ok,_B} = asn1rt:decode(Module,Type,Value),
decode(N-1, Module,Type,Value,Erule).
compile_options() ->
- ?line {ok,Info} = asn1rt:info('H323-MESSAGES'),
- case lists:keysearch(options,1,Info) of
- {_,{_,Opts}} ->
- Opts2 =
- case lists:member(ber_bin_v2,Opts) of
- true ->
- [ber_bin,optimize] ++ lists:delete(optimize,Opts);
- _ ->
- Opts
- end,
- Opts3 = [X||X <- Opts2,
- (X == ber orelse
- X == ber_bin orelse
- X == per orelse
- X == per_bin orelse
- X == optimize orelse
- X == driver)],
- lists:flatten(io_lib:format("~p",[Opts3]));
+ {ok,Info} = asn1rt:info('H323-MESSAGES'),
+ case lists:keyfind(options, 1, Info) of
+ {_,Opts0} ->
+ Opts1 = [X || X <- Opts0,
+ (X =:= ber orelse
+ X =:= per orelse
+ X =:= uper)],
+ lists:flatten(io_lib:format("~p", [Opts1]));
_ ->
"[]"
end.
diff --git a/lib/asn1/test/testTypeValueNotation.erl b/lib/asn1/test/testTypeValueNotation.erl
index cd5223ef23..59f7385f08 100644
--- a/lib/asn1/test/testTypeValueNotation.erl
+++ b/lib/asn1/test/testTypeValueNotation.erl
@@ -21,11 +21,9 @@
-export([main/2]).
--include_lib("test_server/include/test_server.hrl").
-
-record('Seq', {octstr, int, bool, enum, bitstr, null, oid, vstr}).
-main(Rule, Option) ->
+main(_Rule, _Option) ->
Value1 = #'Seq'{octstr = [1, 2, 3, 4],
int = 12,
bool = true,
@@ -34,28 +32,5 @@ main(Rule, Option) ->
null = 'NULL',
oid = {1, 2, 55},
vstr = "Hello World"},
- Value2 = #'Seq'{octstr = {'OctStr', [1, 2, 3, 4]},
- int = {'Int', 12},
- bool = {'Bool', true},
- enum = {'Enum', a},
- bitstr = {'BitStr', [1, 0, 1, 0]},
- null = {'Null', 'NULL'},
- oid = {'OId', {1, 2, 55}},
- vstr = {'VStr', "Hello World"}},
- main(Rule, Option, Value1, Value2).
-
-%% Value2 will fail for ber_bin_v2, per_bin with nifs (optimize) and uper_bin
-main(ber_bin_v2, _, Value1, Value2) -> encode_fail(Value1, Value2);
-main(per_bin, [optimize], Value1, Value2) -> encode_fail(Value1, Value2);
-main(uper_bin, [], Value1, Value2) -> encode_fail(Value1, Value2);
-main(_, _, Value1, Value2) -> encode_normal(Value1, Value2).
-
-encode_normal(Value1, Value2) ->
- {ok, Bytes} = asn1_wrapper:encode('SeqTypeRefPrim', 'Seq', Value1),
- {ok, Bytes} = asn1_wrapper:encode('SeqTypeRefPrim', 'Seq', Value2),
- {ok, Value1} = asn1_wrapper:decode('SeqTypeRefPrim', 'Seq', Bytes).
-
-encode_fail(Value1, Value2) ->
- {ok, Bytes} = asn1_wrapper:encode('SeqTypeRefPrim', 'Seq', Value1),
- {error, _Reason} = asn1_wrapper:encode('SeqTypeRefPrim', 'Seq', Value2),
- {ok, Value1} = asn1_wrapper:decode('SeqTypeRefPrim', 'Seq', Bytes).
+ {ok, Bytes} = asn1_wrapper:encode('SeqTypeRefPrim', 'Seq', Value1),
+ {ok, Value1} = asn1_wrapper:decode('SeqTypeRefPrim', 'Seq', Bytes).
diff --git a/lib/asn1/test/testX420.erl b/lib/asn1/test/testX420.erl
index abdbbfe536..52b20a2c70 100644
--- a/lib/asn1/test/testX420.erl
+++ b/lib/asn1/test/testX420.erl
@@ -34,7 +34,7 @@ compile(Erule, Options, Config) ->
compile_loop(_Erule, [], _Options, _Config) ->
ok;
compile_loop(Erule, [Spec|Specs], Options, Config)
- when Erule == ber; Erule == ber_bin; Erule == ber_bin_v2; Erule == per ->
+ when Erule =:= ber; Erule =:= per ->
CaseDir = ?config(case_dir, Config),
asn1_test_lib:compile(filename:join([x420, Spec]), Config,
[Erule, {i, CaseDir}]),
diff --git a/lib/asn1/test/test_compile_options.erl b/lib/asn1/test/test_compile_options.erl
index 4e732308d8..b973c5fbcc 100644
--- a/lib/asn1/test/test_compile_options.erl
+++ b/lib/asn1/test/test_compile_options.erl
@@ -92,7 +92,8 @@ noobj(Config) ->
file:delete(filename:join([OutDir,'P-Record.beam'])),
file:delete(filename:join([OutDir,'p_record.erl'])),
file:delete(filename:join([OutDir,'p_record.beam'])),
- ?line ok=asn1ct:compile(filename:join([DataDir,"p_record.set.asn"]),[asn1config,ber_bin,optimize,noobj,{outdir,OutDir}]),
+ ok = asn1ct:compile(filename:join([DataDir,"p_record.set.asn"]),
+ [asn1config,ber,noobj,{outdir,OutDir}]),
%% ?line false = code:is_loaded('P-Record'),
%% ?line false = code:is_loaded('p_record'),
?line {error,enoent} =
diff --git a/lib/asn1/test/test_inline.erl b/lib/asn1/test/test_inline.erl
index 62625572e3..e03ad739f9 100644
--- a/lib/asn1/test/test_inline.erl
+++ b/lib/asn1/test/test_inline.erl
@@ -41,16 +41,16 @@ inline1(Config, Rule, Opt) ->
asn1_test_lib:compile("P-Record", Config, [{inline, 'inlined_P_Record'}|Opt]),
test_inline1(),
- ok=remove_inlined_files2(CaseDir, ber_bin_v2),
+ ok=remove_inlined_files2(CaseDir, ber),
case Rule of
- ber_bin_v2 ->
+ ber ->
asn1_test_lib:compile("P-Record", Config,
- [ber_bin, inline, asn1config, optimize|Opt]),
+ [ber, inline, asn1config|Opt]),
test_inline2(Rule, 'P-Record'),
remove_inlined_files3(CaseDir, Rule),
asn1_test_lib:compile("p_record.set.asn", Config,
- [ber_bin, inline, asn1config, optimize|Opt]),
+ [ber, inline, asn1config|Opt]),
test_inline2(Rule, 'p_record'),
remove_inlined_files4(CaseDir, Rule);
_ ->
@@ -71,12 +71,12 @@ test_inline1() ->
?line {ok,_}=asn1_wrapper:decode('inlined_P_Record',
'PersonnelRecord',Bytes).
-test_inline2(ber_bin_v2,Mod) ->
+test_inline2(ber,Mod) ->
PRecMsg = {'PersonnelRecord',{'Name',"Sven","S","Svensson"},
"manager",123,"20000202",{'Name',"Inga","K","Svensson"},
asn1_DEFAULT},
?line {ok,Bytes} = Mod:encode('PersonnelRecord',PRecMsg),
- ?line {ok,_} = Mod:sel_dec(list_to_binary(Bytes));
+ {ok,_} = Mod:sel_dec(Bytes);
test_inline2(_,_) ->
ok.
@@ -243,7 +243,7 @@ remove_inlined_files2(Dir,Rule) ->
?line ok=file:delete(X)
end,[TargetErl,TargetBeam]),
ok.
-remove_inlined_files3(Dir,ber_bin_v2) ->
+remove_inlined_files3(Dir,ber) ->
Erl=filename:join([Dir,"P-Record.erl"]),
Beam=filename:join([Dir,"P-Record.beam"]),
Asn1DB=filename:join([Dir,"P-Record.asn1db"]),
@@ -255,7 +255,7 @@ remove_inlined_files3(Dir,ber_bin_v2) ->
remove_inlined_files3(_,_) ->
ok.
-remove_inlined_files4(Dir,ber_bin_v2) ->
+remove_inlined_files4(Dir,ber) ->
Erl=filename:join([Dir,"p_record.erl"]),
Beam=filename:join([Dir,"p_record.beam"]),
Asn1DB=filename:join([Dir,"p_record.asn1db"]),
diff --git a/lib/asn1/test/test_partial_incomplete_decode.erl b/lib/asn1/test/test_partial_incomplete_decode.erl
index df56c27115..8ede06938d 100644
--- a/lib/asn1/test/test_partial_incomplete_decode.erl
+++ b/lib/asn1/test/test_partial_incomplete_decode.erl
@@ -188,7 +188,7 @@ decode_parts('S1_2',PartDecMsg) ->
msg('F') ->
- {'F',{fb,{'E',35,[{'D',3,true},{'D',4,false},{'D',5,true},{'D',6,true},{'D',7,false},{'D',8,true},{'D',9,true},{'D',10,false},{'D',11,true},{'D',12,true},{'D',13,false},{'D',14,true}],false,{da,[{'A',16,{'D',17,true}}]}}}};
+ {fb,{'E',35,[{'D',3,true},{'D',4,false},{'D',5,true},{'D',6,true},{'D',7,false},{'D',8,true},{'D',9,true},{'D',10,false},{'D',11,true},{'D',12,true},{'D',13,false},{'D',14,true}],false,{da,[{'A',16,{'D',17,true}}]}}};
msg('F3') ->
{fb,{'E',10,[{'D',11,true},{'D',12,false}],false,{dc,{'E_d_dc',13,true,{'E_d_dc_dcc',14,15}}}}};
diff --git a/lib/asn1/test/test_selective_decode.erl b/lib/asn1/test/test_selective_decode.erl
index bb348611da..ebe1296cf3 100644
--- a/lib/asn1/test/test_selective_decode.erl
+++ b/lib/asn1/test/test_selective_decode.erl
@@ -53,7 +53,7 @@ test() ->
msg('F') ->
- {'F',{fb,{'E',35,[{'D',3,true},{'D',4,false},{'D',5,true},{'D',6,true},{'D',7,false},{'D',8,true},{'D',9,true},{'D',10,false},{'D',11,true},{'D',12,true},{'D',13,false},{'D',14,true}],false,{da,[{'A',16,{'D',17,true}}]}}}};
+ {fb,{'E',35,[{'D',3,true},{'D',4,false},{'D',5,true},{'D',6,true},{'D',7,false},{'D',8,true},{'D',9,true},{'D',10,false},{'D',11,true},{'D',12,true},{'D',13,false},{'D',14,true}],false,{da,[{'A',16,{'D',17,true}}]}}};
msg('E') ->
{'E',10,[{'D',11,true},{'D',12,false}],false,{dc,{'E_d_dc',13,true,{'E_d_dc_dcc',14,15}}}};
diff --git a/lib/asn1/test/test_special_decode_performance.erl b/lib/asn1/test/test_special_decode_performance.erl
index 4ac0ff2b27..7dfab1f25a 100644
--- a/lib/asn1/test/test_special_decode_performance.erl
+++ b/lib/asn1/test/test_special_decode_performance.erl
@@ -31,9 +31,9 @@ go(all) ->
{Time_S_c,Time_MGC_c}).
go(N,Mod) ->
- ?line Val = val(Mod),
- ?line {ok,B} = Mod:encode(element(1,Val),Val),
- ?line go(Mod,list_to_binary(B),N).
+ {Type,Val} = val(Mod),
+ {ok,B} = Mod:encode(Type, Val),
+ ?line go(Mod,B,N).
go(Mod,Bin,N) ->
?line FsS = get_selective_funcs(Mod),
@@ -92,7 +92,7 @@ val('PartialDecSeq') ->
{'F',{fb,{'E',12,[{'D',13,true},{'D',14,false},{'D',15,true},{'D',16,false},{'D',13,true},{'D',14,false},{'D',15,true},{'D',16,false},{'D',13,true},{'D',14,false},{'D',15,true},{'D',16,false}],true,{da,[{'A',17,{'D',18,false}},{'A',19,{'D',20,true}},{'A',21,{'D',22,false}},{'A',17,{'D',18,false}},{'A',19,{'D',20,true}},{'A',21,{'D',22,false}},{'A',17,{'D',18,false}},{'A',19,{'D',20,true}},{'A',21,{'D',22,false}},{'A',17,{'D',18,false}},{'A',19,{'D',20,true}},{'A',21,{'D',22,false}},{'A',17,{'D',18,false}},{'A',19,{'D',20,true}},{'A',21,{'D',22,false}},{'A',17,{'D',18,false}},{'A',19,{'D',20,true}},{'A',21,{'D',22,false}}]}}}};
val('MEDIA-GATEWAY-CONTROL') ->
- {'MegacoMessage',asn1_NOVALUE,{'Message',1,{ip4Address,{'IP4Address',[125,125,125,111],55555}},{transactions,[{transactionReply,{'TransactionReply',50007,asn1_NOVALUE,{actionReplies,[{'ActionReply',0,asn1_NOVALUE,asn1_NOVALUE,[{auditValueReply,{auditResult,{'AuditResult',{'TerminationID',[],[255,255,255]},[{mediaDescriptor,{'MediaDescriptor',asn1_NOVALUE,{multiStream,[{'StreamDescriptor',1,{'StreamParms',{'LocalControlDescriptor',sendRecv,asn1_NOVALUE,asn1_NOVALUE,[{'PropertyParm',[0,11,0,7],[[52,48]],asn1_NOVALUE}]},{'LocalRemoteDescriptor',[[{'PropertyParm',[0,0,176,1],[[48]],asn1_NOVALUE},{'PropertyParm',[0,0,176,8],[[73,78,32,73,80,52,32,49,50,53,46,49,50,53,46,49,50,53,46,49,49,49]],asn1_NOVALUE},{'PropertyParm',[0,0,176,15],[[97,117,100,105,111,32,49,49,49,49,32,82,84,80,47,65,86,80,32,32,52]],asn1_NOVALUE},{'PropertyParm',[0,0,176,12],[[112,116,105,109,101,58,51,48]],asn1_NOVALUE}]]},{'LocalRemoteDescriptor',[[{'PropertyParm',[0,0,176,1],[[48]],asn1_NOVALUE},{'PropertyParm',[0,0,176,8],[[73,78,32,73,80,52,32,49,50,52,46,49,50,52,46,49,50,52,46,50,50,50]],asn1_NOVALUE},{'PropertyParm',[0,0,176,15],[[97,117,100,105,111,32,50,50,50,50,32,82,84,80,47,65,86,80,32,32,52]],asn1_NOVALUE},{'PropertyParm',[0,0,176,12],[[112,116,105,109,101,58,51,48]],asn1_NOVALUE}]]}}}]}}},{packagesDescriptor,[{'PackagesItem',[0,11],1},{'PackagesItem',[0,11],1}]},{statisticsDescriptor,[{'StatisticsParameter',[0,12,0,4],[[49,50,48,48]]},{'StatisticsParameter',[0,11,0,2],[[54,50,51,48,48]]},{'StatisticsParameter',[0,12,0,5],[[55,48,48]]},{'StatisticsParameter',[0,11,0,3],[[52,53,49,48,48]]},{'StatisticsParameter',[0,12,0,6],[[48,46,50]]},{'StatisticsParameter',[0,12,0,7],[[50,48]]},{'StatisticsParameter',[0,12,0,8],[[52,48]]}]}]}}}]}]}}}]}}}.
+ {'MegacoMessage',{'MegacoMessage',asn1_NOVALUE,{'Message',1,{ip4Address,{'IP4Address',[125,125,125,111],55555}},{transactions,[{transactionReply,{'TransactionReply',50007,asn1_NOVALUE,{actionReplies,[{'ActionReply',0,asn1_NOVALUE,asn1_NOVALUE,[{auditValueReply,{auditResult,{'AuditResult',{'TerminationID',[],[255,255,255]},[{mediaDescriptor,{'MediaDescriptor',asn1_NOVALUE,{multiStream,[{'StreamDescriptor',1,{'StreamParms',{'LocalControlDescriptor',sendRecv,asn1_NOVALUE,asn1_NOVALUE,[{'PropertyParm',[0,11,0,7],[[52,48]],asn1_NOVALUE}]},{'LocalRemoteDescriptor',[[{'PropertyParm',[0,0,176,1],[[48]],asn1_NOVALUE},{'PropertyParm',[0,0,176,8],[[73,78,32,73,80,52,32,49,50,53,46,49,50,53,46,49,50,53,46,49,49,49]],asn1_NOVALUE},{'PropertyParm',[0,0,176,15],[[97,117,100,105,111,32,49,49,49,49,32,82,84,80,47,65,86,80,32,32,52]],asn1_NOVALUE},{'PropertyParm',[0,0,176,12],[[112,116,105,109,101,58,51,48]],asn1_NOVALUE}]]},{'LocalRemoteDescriptor',[[{'PropertyParm',[0,0,176,1],[[48]],asn1_NOVALUE},{'PropertyParm',[0,0,176,8],[[73,78,32,73,80,52,32,49,50,52,46,49,50,52,46,49,50,52,46,50,50,50]],asn1_NOVALUE},{'PropertyParm',[0,0,176,15],[[97,117,100,105,111,32,50,50,50,50,32,82,84,80,47,65,86,80,32,32,52]],asn1_NOVALUE},{'PropertyParm',[0,0,176,12],[[112,116,105,109,101,58,51,48]],asn1_NOVALUE}]]}}}]}}},{packagesDescriptor,[{'PackagesItem',[0,11],1},{'PackagesItem',[0,11],1}]},{statisticsDescriptor,[{'StatisticsParameter',[0,12,0,4],[[49,50,48,48]]},{'StatisticsParameter',[0,11,0,2],[[54,50,51,48,48]]},{'StatisticsParameter',[0,12,0,5],[[55,48,48]]},{'StatisticsParameter',[0,11,0,3],[[52,53,49,48,48]]},{'StatisticsParameter',[0,12,0,6],[[48,46,50]]},{'StatisticsParameter',[0,12,0,7],[[50,48]]},{'StatisticsParameter',[0,12,0,8],[[52,48]]}]}]}}}]}]}}}]}}}}.
%% val('PartialDecSeq') ->
%% {'F',{fb,{'E',35,[{'D',3,true},{'D',4,false},{'D',5,true},{'D',6,true},{'D',7,false},{'D',8,true},{'D',9,true},{'D',10,false},{'D',11,true},{'D',12,true},{'D',13,false},{'D',14,true}],false,{dc,{'E_d_dc',15,true,{'E_d_dc_dcc',17,4711}}}}}}.
diff --git a/lib/common_test/doc/src/common_test_app.xml b/lib/common_test/doc/src/common_test_app.xml
index b6d4a633cb..151159ad69 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>2012</year>
+ <year>2003</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -170,7 +170,9 @@
<v> UserData = term()</v>
<v> Conns = [atom()]</v>
<v> CSSFile = string()</v>
- <v> CTHs = [CTHModule | {CTHModule, CTHInitArgs} | {CTHModule, CTHInitArgs, CTHPriority}]</v>
+ <v> CTHs = [CTHModule |</v>
+ <v>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{CTHModule, CTHInitArgs} |</v>
+ <v>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{CTHModule, CTHInitArgs, CTHPriority}]</v>
<v> CTHModule = atom()</v>
<v> CTHInitArgs = term()</v>
</type>
@@ -297,8 +299,9 @@
<v> UserData = term()</v>
<v> Conns = [atom()]</v>
<v> CSSFile = string()</v>
- <v> CTHs = [CTHModule | {CTHModule, CTHInitArgs} |
- {CTHModule, CTHInitArgs, CTHPriority}]</v>
+ <v> CTHs = [CTHModule |</v>
+ <v> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{CTHModule, CTHInitArgs} |</v>
+ <v> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{CTHModule, CTHInitArgs, CTHPriority}]</v>
<v> CTHModule = atom()</v>
<v> CTHInitArgs = term()</v>
</type>
diff --git a/lib/common_test/doc/src/cover_chapter.xml b/lib/common_test/doc/src/cover_chapter.xml
index 803a71de07..4fa92d5583 100644
--- a/lib/common_test/doc/src/cover_chapter.xml
+++ b/lib/common_test/doc/src/cover_chapter.xml
@@ -108,6 +108,33 @@
specifications</seealso>).</p>
</section>
+ <marker id="cover_stop"></marker>
+ <section>
+ <title>Stopping the cover tool when tests are completed</title>
+ <p>By default the Cover tool is automatically stopped when the
+ tests are completed. This causes the original (non cover
+ compiled) modules to be loaded back in to the test node. If a
+ process at this point is still running old code of any of the
+ modules that are cover compiled, meaning that it has not done
+ any fully qualified function call after the cover compilation,
+ the process will now be killed. To avoid this it is possible to
+ set the value of the <c>cover_stop</c> option to
+ <c>false</c>. This means that the modules will stay cover
+ compiled, and it is therefore only recommended if the erlang
+ node(s) under test is terminated after the test is completed
+ or if cover can be manually stopped.</p>
+
+ <p>The option can be set by using the <c>-cover_stop</c> flag with
+ <c>ct_run</c>, by adding <c>{cover_stop,true|false}</c> to the
+ Opts argument to <c><seealso
+ marker="ct#run_test-1">ct:run_test/1</seealso></c>, or by adding
+ a <c>cover_stop</c> term in your test specification (see chapter
+ about <seealso
+ marker="run_test_chapter#test_specifications">test
+ specifications</seealso>).</p>
+
+ </section>
+
<section>
<title>The cover specification file</title>
<p>These are the terms allowed in a cover specification file:</p>
@@ -148,6 +175,11 @@
%% Specific modules to exclude in cover.
{excl_mods, Mods}.
+
+ %% Cross cover compilation
+ %% Tag = atom(), an identifier for a test run
+ %% Mod = [atom()], modules to compile for accumulated analysis
+ {cross,[{Tag,Mods}]}.
</pre>
<p>The <c>incl_dirs_r</c> and <c>excl_dirs_r</c> terms tell Common
@@ -163,6 +195,81 @@
specification file for Common Test).</p>
</section>
+ <marker id="cross_cover"/>
+ <section>
+ <title>Cross cover analysis</title>
+ <p>The cross cover mechanism allows cover analysis of modules
+ across multiple tests. It is useful if some code, e.g. a library
+ module, is used by many different tests and the accumulated cover
+ result is desirable.</p>
+
+ <p>This can of course also be achieved in a more customized way by
+ using the <c>export</c> parameter in the cover specification and
+ analysing the result off line, but the cross cover mechanism is a
+ build in solution which also provides the logging.</p>
+
+ <p>The mechanism is easiest explained via an example:</p>
+
+ <p>Let's say that there are two systems, <c>s1</c> and <c>s2</c>,
+ which are tested in separate test runs. System <c>s1</c> contains
+ a library module <c>m1</c> which is tested by the <c>s1</c> test
+ run and is included in <c>s1</c>'s cover specification:</p>
+
+<code type="none">
+s1.cover:
+ {incl_mods,[m1]}.</code>
+
+ <p>When analysing code coverage, the result for <c>m1</c> can be
+ seen in the cover log in the <c>s1</c> test result.</p>
+
+ <p>Now, let's imagine that since <c>m1</c> is a library module, it
+ is also used quite a bit by system <c>s2</c>. The <c>s2</c> test
+ run does not specifically test <c>m1</c>, but it might still be
+ interesting to see which parts of <c>m1</c> is actually covered by
+ the <c>s2</c> tests. To do this, <c>m1</c> could be included also
+ in <c>s2</c>'s cover specification:</p>
+
+<code type="none">
+s2.cover:
+ {incl_mods,[m1]}.</code>
+
+ <p>This would give an entry for <c>m1</c> also in the cover log
+ for the <c>s2</c> test run. The problem is that this would only
+ reflect the coverage by <c>s2</c> tests, not the accumulated
+ result over <c>s1</c> and <c>s2</c>. And this is where the cross
+ cover mechanism comes in handy.</p>
+
+ <p>If instead the cover specification for <c>s2</c> was like
+ this:</p>
+
+<code type="none">
+s2.cover:
+ {cross,[{s1,[m1]}]}.</code>
+
+ <p>then <c>m1</c> would be cover compiled in the <c>s2</c> test
+ run, but not shown in the coverage log. Instead, if
+ <c>ct_cover:cross_cover_analyse/2</c> is called after both
+ <c>s1</c> and <c>s2</c> test runs are completed, the accumulated
+ result for <c>m1</c> would be available in the cross cover log for
+ the <c>s1</c> test run.</p>
+
+ <p>The call to the analyse function must be like this:</p>
+
+<code type="none">
+ct_cover:cross_cover_analyse(Level, [{s1,S1LogDir},{s2,S2LogDir}]).</code>
+
+ <p>where <c>S1LogDir</c> and <c>S2LogDir</c> are the directories
+ named <c>&lt;TestName&gt;.logs</c> for each test respectively.</p>
+
+ <p>Note the tags <c>s1</c> and <c>s2</c> which are used in the
+ cover specification file and in the call to
+ <c>ct_cover:cross_cover_analyse/2</c>. The point of these are only
+ to map the modules specified in the cover specification to the log
+ directory specified in the call to the analyse function. The name
+ of the tag has no meaning beyond this.</p>
+
+ </section>
+
<section>
<title>Logging</title>
<p>To view the result of a code coverage test, follow the
@@ -170,6 +277,11 @@
takes you to the code coverage overview page. If you have
successfully performed a detailed coverage analysis, you
find links to each individual module coverage page here.</p>
+
+ <p>If cross cover analysis has been performed, and there are
+ accumulated coverage results for the current test, then the -
+ "Coverdata collected over all tests" link will take you to these
+ results.</p>
</section>
</chapter>
diff --git a/lib/common_test/doc/src/ct_hooks_chapter.xml b/lib/common_test/doc/src/ct_hooks_chapter.xml
index 86237f5fc1..fe871eb516 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>2012</year>
+ <year>2011</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -439,14 +439,14 @@ terminate(State) ->
<table>
<row>
- <cell><em>CTH Name</em></cell>
- <cell><em>Is Built-in</em></cell>
- <cell><em>Description</em></cell>
+ <cell align="left"><em>CTH Name</em></cell>
+ <cell align="left"><em>Is Built-in</em></cell>
+ <cell align="left"><em>Description</em></cell>
</row>
<row>
- <cell>cth_log_redirect</cell>
- <cell>yes</cell>
- <cell>Captures all error_logger and SASL logging events and prints them
+ <cell align="left">cth_log_redirect</cell>
+ <cell align="left">yes</cell>
+ <cell align="left">Captures all error_logger and SASL logging events and prints them
to the current test case log. If an event can not be associated with a
testcase it will be printed in the common test framework log. This will
happen for testcases which are run in parallel and events which occur
@@ -455,14 +455,29 @@ terminate(State) ->
using the normal SASL mechanisms. </cell>
</row>
<row>
- <cell>cth_surefire</cell>
- <cell>no</cell>
- <cell>Captures all test results and outputs them as surefire XML into
- a file. The file which is created is by default called junit_report.xml.
- The name can be by setting the path option for this hook. e.g.
+ <cell align="left">cth_surefire</cell>
+ <cell align="left">no</cell>
+ <cell align="left"><p>Captures all test results and outputs them as surefire
+ XML into a file. The file which is created is by default
+ called junit_report.xml. The file name can be changed by
+ setting the <c>path</c> option for this hook, e.g.</p>
+
<code>-ct_hooks cth_surefire [{path,"/tmp/report.xml"}]</code>
- Surefire XML can forinstance be used by Jenkins to display test
- results.</cell>
+
+ <p>If the <c>url_base</c> option is set, an additional
+ attribute named <c>url</c> will be added to each
+ <c>testsuite</c> and <c>testcase</c> XML element. The value will
+ be constructed from the <c>url_base</c> and a relative path
+ to the test suite or test case log respectively, e.g.</p>
+
+ <code>-ct_hooks cth_surefire [{url_base, "http://myserver.com/"}]</code>
+ <p>will give a url attribute value similar to</p>
+
+ <code>"http://myserver.com/[email protected]_11.19.39/
+x86_64-unknown-linux-gnu.my_test.logs/run.2012-12-12_11.19.39/suite.log.html"</code>
+
+ <p>Surefire XML can for instance be used by Jenkins to display test
+ results.</p></cell>
</row>
</table>
diff --git a/lib/common_test/doc/src/ct_run.xml b/lib/common_test/doc/src/ct_run.xml
index 9cc5495af7..0750f560b3 100644
--- a/lib/common_test/doc/src/ct_run.xml
+++ b/lib/common_test/doc/src/ct_run.xml
@@ -90,7 +90,7 @@
<pre>
ct_run [-dir TestDir1 TestDir2 .. TestDirN] |
[[-dir TestDir] -suite Suite1 Suite2 .. SuiteN
- [[-group Group1 Group2 .. GroupN] [-case Case1 Case2 .. CaseN]]]
+ [[-group Groups1 Groups2 .. GroupsN] [-case Case1 Case2 .. CaseN]]]
[-step [config | keep_inactive]]
[-config ConfigFile1 ConfigFile2 .. ConfigFileN]
[-userconfig CallbackModule1 ConfigString1 and CallbackModule2
@@ -104,6 +104,7 @@
[-silent_connections [ConnType1 ConnType2 .. ConnTypeN]]
[-stylesheet CSSFile]
[-cover CoverCfgFile]
+ [-cover_stop Bool]
[-event_handler EvHandler1 EvHandler2 .. EvHandlerN] |
[-event_handler_init EvHandler1 InitArg1 and
EvHandler2 InitArg2 and .. EvHandlerN InitArgN]
@@ -138,6 +139,7 @@
[-silent_connections [ConnType1 ConnType2 .. ConnTypeN]]
[-stylesheet CSSFile]
[-cover CoverCfgFile]
+ [-cover_stop Bool]
[-event_handler EvHandler1 EvHandler2 .. EvHandlerN] |
[-event_handler_init EvHandler1 InitArg1 and
EvHandler2 InitArg2 and .. EvHandlerN InitArgN]
diff --git a/lib/common_test/doc/src/notes.xml b/lib/common_test/doc/src/notes.xml
index abe8cb2041..0345fab8e8 100644
--- a/lib/common_test/doc/src/notes.xml
+++ b/lib/common_test/doc/src/notes.xml
@@ -32,6 +32,266 @@
<file>notes.xml</file>
</header>
+<section><title>Common_Test 1.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Severe errors detected by <c>test_server</c> (e.g. if log
+ files directories cannot be created) will now be reported
+ to <c>common_test</c> and noted in the <c>common_test</c>
+ logs.</p>
+ <p>
+ Own Id: OTP-9769 Aux Id: kunagi-202 [113] </p>
+ </item>
+ <item>
+ <p>
+ If a busy test case generated lots of error messages,
+ cth_log_redirect:post_end_per_testcase would crash with a
+ timeout while waiting for the error logger to finish
+ handling all error reports. The default timer was 5
+ seconds. This has now been extended to 5 minutes.</p>
+ <p>
+ Own Id: OTP-10040 Aux Id: kunagi-173 [84] </p>
+ </item>
+ <item>
+ <p>
+ Some bugfixes in <c>ct_snmp:</c></p>
+ <p>
+ <list> <item> ct_snmp will now use the value of the
+ 'agent_vsns' config variable when setting the 'variables'
+ parameter to snmp application agent configuration.
+ Earlier this had to be done separately - i.e. the
+ supported versions had to be specified twice. </item>
+ <item> Snmp application failed to write notify.conf since
+ ct_snmp gave the notify type as a string instead of an
+ atom. This has been corrected. </item> </list></p>
+ <p>
+ Own Id: OTP-10432</p>
+ </item>
+ <item>
+ <p>
+ Some bugfixes in <c>ct_snmp</c>:</p>
+ <p>
+ <list> <item> Functions <c>register_users/2</c>,
+ <c>register_agents/2</c> and <c>register_usm_users/2</c>,
+ and the corresponding <c>unregister_*/1</c> functions
+ were not executable. These are corrected/rewritten.
+ </item> <item> Function <c>update_usm_users/2</c> is
+ removed, and an unregister function is added instead.
+ Update can now be done with unregister_usm_users and then
+ register_usm_users. </item> <item> Functions
+ <c>unregister_*/2</c> are added, so specific
+ users/agents/usm users can be unregistered. </item>
+ <item> Function <c>unload_mibs/1</c> is added for
+ completeness. </item> <item> Overriding configuration
+ files did not work, since the files were written in
+ priv_dir instead of in the configuration dir
+ (priv_dir/conf). This has been corrected. </item> <item>
+ Arguments to <c>register_usm_users/2</c> were faulty
+ documented. This has been corrected. </item> </list></p>
+ <p>
+ Own Id: OTP-10434 Aux Id: kunagi-264 [175] </p>
+ </item>
+ <item>
+ <p>
+ Faulty exported specs in common test has been corrected
+ to <c>ct_netconfc:hook_options/0</c> and
+ <c>inet:hostname/0</c></p>
+ <p>
+ Own Id: OTP-10601</p>
+ </item>
+ <item>
+ <p>
+ The netconf client in common_test did not adjust the
+ window after receiving data. Due to this, the client
+ stopped receiving data after a while. This has been
+ corrected.</p>
+ <p>
+ Own Id: OTP-10646</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Known Bugs and Problems</title>
+ <list>
+ <item>
+ <p>
+ The earlier undocumented cross cover feature for
+ accumulating cover data over multiple tests has now been
+ fixed and documented.</p>
+ <p>
+ Own Id: OTP-9870 Aux Id: kunagi-206 [117] </p>
+ </item>
+ <item>
+ <p>
+ CT drops error reason when groups/0 crashes.</p>
+ <p>
+ Own Id: OTP-10631 Aux Id: kunagi-345 [256] </p>
+ </item>
+ <item>
+ <p>
+ Problem opening sftp connection with ct_ssh.</p>
+ <p>
+ Own Id: OTP-10632 Aux Id: kunagi-346 [257] </p>
+ </item>
+ <item>
+ <p>
+ Event handler on a ct_master node causes hanging.</p>
+ <p>
+ Own Id: OTP-10634 Aux Id: kunagi-347 [258] </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Common_Test 1.6.3.1</title>
+
+ <section><title>Known Bugs and Problems</title>
+ <list>
+ <item>
+ <p>
+ The following corrections/changes are done in the
+ cth_surefire hook:</p>
+ <p>
+ <list> <item> Earlier there would always be a
+ 'properties' element under the 'testsuites' element. This
+ would exist even if there were no 'property' element
+ inside it. This has been changed so if there are no
+ 'property' elements to display, then there will not be a
+ 'properties' element either. </item> <item> The XML file
+ will now (unless other is specified) be stored in the top
+ log directory. Earlier, the default directory would be
+ the current working directory for the erlang node, which
+ would mostly, but not always, be the top log directory.
+ </item> <item> The 'hostname' attribute in the
+ 'testsuite' element would earlier never have the correct
+ value. This has been corrected. </item> <item> The
+ 'errors' attribute in the 'testsuite' element would
+ earlier display the number of failed testcases. This has
+ been changed and will now always have the value 0, while
+ the 'failures' attribute will show the number of failed
+ testcases. </item> <item> A new attribute 'skipped' is
+ added to the 'testsuite' element. This will display the
+ number of skipped testcases. These would earlier be
+ included in the number of failed test cases. </item>
+ <item> The total number of tests displayed by the 'tests'
+ attribute in the 'testsuite' element would earlier
+ include init/end_per_suite and init/end_per_group. This
+ is no longer the case. The 'tests' attribute will now
+ only count "real" test cases. </item> <item> Earlier,
+ auto skipped test cases would have no value in the 'log'
+ attribute. This is now corrected. </item> <item> A new
+ attributes 'log' is added to the 'testsuite' element.
+ </item> <item> A new option named 'url_base' is added for
+ this hook. If this option is used, a new attribute named
+ 'url' will be added to the 'testcase' and 'testsuite'
+ elements. </item> </list></p>
+ <p>
+ Own Id: OTP-10589</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Common_Test 1.6.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The ct:run_test/1 option 'config' only worked with a
+ single config file, not a list of files. This has been
+ fixed.</p>
+ <p>
+ Own Id: OTP-10495</p>
+ </item>
+ <item>
+ <p>
+ ct_netconfc:close_session sometimes returned
+ {error,closed} because the ssh connection was closed
+ (from the server side) before the rpc-reply was received
+ by the client. This is normal and can not be helped. It
+ has been corrected so the return will be 'ok' in this
+ case. Other error situations will still give
+ {error,Reason}.</p>
+ <p>
+ Own Id: OTP-10510 Aux Id: kunagi-320 [231] </p>
+ </item>
+ <item>
+ <p>
+ ct_netconfc:close_session sometimes returned
+ {error,closed} or (if the connection was named)
+ {error,{process_down,Pid,normal}} because the ssh
+ connection was closed (from the server side) before the
+ rpc-reply was received by the client. This is normal and
+ can not be helped. It has been corrected so the return
+ will be 'ok' in this situation.</p>
+ <p>
+ Own Id: OTP-10570</p>
+ </item>
+ <item>
+ <p>
+ Fix bug where ct:require of same name with same config
+ would return name_in_use.</p>
+ <p>
+ Own Id: OTP-10572</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ A new test case group search functionality has been
+ implemented that makes Common Test search automatically
+ through the group definitions tree (the return value of
+ groups/0) and create tests for all paths of nested groups
+ that match the specification. It also allows for
+ specifying unique paths to sub groups in order to avoid
+ execution of unwanted tests. This new feature can be used
+ whenever starting a test run by means of the ct_run
+ program, the ct:run_test/1 API function, or a Test
+ Specification. Details can be found in the Test Case
+ Group Execution section in the Running Tests chapter.</p>
+ <p>
+ Own Id: OTP-10466 Aux Id: kunagi-276 [187] </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Known Bugs and Problems</title>
+ <list>
+ <item>
+ <p>
+ Restore Config data if lost when test case fails.</p>
+ <p>
+ Own Id: OTP-10070 Aux Id: kunagi-175 [86] </p>
+ </item>
+ <item>
+ <p>
+ IO server error in test_server.</p>
+ <p>
+ Own Id: OTP-10125 Aux Id: OTP-10101, kunagi-177 [88] </p>
+ </item>
+ <item>
+ <p>
+ Faulty connection handling in common_test.</p>
+ <p>
+ Own Id: OTP-10126 Aux Id: kunagi-178 [89] </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Common_Test 1.6.2.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/common_test/doc/src/run_test_chapter.xml b/lib/common_test/doc/src/run_test_chapter.xml
index ea62df27cc..d5f5d89e05 100644
--- a/lib/common_test/doc/src/run_test_chapter.xml
+++ b/lib/common_test/doc/src/run_test_chapter.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2003</year><year>2012</year>
+ <year>2003</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -119,7 +119,7 @@
<item><c><![CDATA[ct_run -userconfig <callbackmodulename> <configfilenames> -suite <suiteswithfullpath>]]></c>
</item>
<item><c><![CDATA[ct_run -config <configfilenames> -suite <suitewithfullpath>
- -group <groupnames> -case <casenames>]]></c></item>
+ -group <groups> -case <casenames>]]></c></item>
</list>
<p>Examples:</p>
<p><c>$ ct_run -config $CFGS/sys1.cfg $CFGS/sys2.cfg -dir $SYS1_TEST $SYS2_TEST</c></p>
@@ -137,6 +137,8 @@
<p><c>$ ct_run -suite ./testdir/x_SUITE ./testdir/y_SUITE</c></p>
+ <p>For more details on <seealso marker="run_test_chapter#group_execution">test case group execution</seealso>, please see below.</p>
+
<p>Other flags that may be used with <c>ct_run</c>:</p>
<list>
<item><c><![CDATA[-logdir <dir>]]></c>, specifies where the HTML log files are to be written.</item>
@@ -153,6 +155,8 @@
<item><c><![CDATA[-stylesheet <css_file>]]></c>, points out a user HTML style sheet (see below).</item>
<item><c><![CDATA[-cover <cover_cfg_file>]]></c>, to perform code coverage test (see
<seealso marker="cover_chapter#cover">Code Coverage Analysis</seealso>).</item>
+ <item><c><![CDATA[-cover_stop <bool>]]></c>, to specify if the cover tool shall be stopped after the test is completed (see
+ <seealso marker="cover_chapter#cover_stop">Code Coverage Analysis</seealso>).</item>
<item><c><![CDATA[-event_handler <event_handlers>]]></c>, to install
<seealso marker="event_handler_chapter#event_handling">event handlers</seealso>.</item>
<item><c><![CDATA[-event_handler_init <event_handlers>]]></c>, to install
@@ -267,6 +271,163 @@
<c><seealso marker="ct#run_test-1">ct</seealso></c> manual page.</p>
</section>
+ <marker id="group_execution"></marker>
+ <section>
+ <title>Test case group execution</title>
+
+ <p>With the <c>ct_run</c> flag, or <c>ct:run_test/1</c> option <c>group</c>,
+ one or more test case groups can be specified, optionally in combination
+ with specific test cases. The syntax for specifying groups is as follows
+ (on the command line):</p>
+
+ <pre>
+ <![CDATA[$ ct_run -group <group_names_or_paths> [-case <cases>]]]></pre>
+ <p>or (in the Erlang shell):</p>
+ <pre>
+ <![CDATA[1> ct:run_test([{group,GroupsNamesOrPaths}, {case,Cases}]).]]></pre>
+
+ <p>The <c>group_names_or_paths</c> parameter specifies either one
+ or more group names and/or one or more group paths. At start up,
+ Common Test will search for matching groups in the group definitions
+ tree (i.e. the list returned from <c>Suite:groups/0</c>, please see the
+ <seealso marker="write_test_chapter#test_case_groups">Test case groups</seealso>
+ chapter for details).
+ Given a group name, say <c>g</c>, Common Test will search for all paths
+ that lead to <c>g</c>. By path here we mean a sequence of nested groups,
+ all of which have to be followed in order to get from the top level
+ group to <c>g</c>. Actually, what Common Test needs to do in order to
+ execute the test cases in group <c>g</c>, is to call the
+ <c>init_per_group/2</c> function for each group in the path to
+ <c>g</c>, as well as all corresponding <c>end_per_group/2</c>
+ functions afterwards. The obvious reason for this is that the configuration
+ of a test case in <c>g</c> (and its <c>Config</c> input data) depends on
+ <c>init_per_testcase(TestCase, Config)</c> and its return value, which
+ in turn depends on <c>init_per_group(g, Config)</c> and its return value,
+ which in turn depends on <c>init_per_group/2</c> of the group above
+ <c>g</c>, etc, all the way up to the top level group.</p>
+
+ <p>As you may have already realized, this means that if there is more than
+ one way to locate a group (and its test cases) in a path, the result of the
+ group search operation is a number of tests, all of which will be performed.
+ Common Test actually interprets a group specification that consists of a
+ single name this way:</p>
+
+ <p>"Search and find all paths in the group definitions tree that lead
+ to the specified group and, for each path, create a test which (1) executes
+ all configuration functions in the path to the specified group, then (2)
+ executes all - or all matching - test cases in this group, as well as (3)
+ all - or all matching - test cases in all sub groups of the group".
+ </p>
+
+ <p>It is also possible for the user to specify a specific group path with
+ the <c>group_names_or_paths</c> parameter. With this type of specification it's
+ possible to avoid execution of unwanted groups (in otherwise matching paths),
+ and/or the execution of sub groups. The syntax of the group path is a list of
+ group names in the path, e.g. on the command line:
+ </p>
+ <p><c>$ ct_run -suite "./x_SUITE" -group [g1,g3,g4] -case tc1 tc5</c></p>
+ <p>or similarly in the Erlang shell (requires a list within the groups list):</p>
+ <p><c>1> ct:run_test([{suite,"./x_SUITE"}, {group,[[g1,g3,g4]]}, {testcase,[tc1,tc5]}]).</c></p>
+
+ <p>The last group in the specified path will be the terminating group in
+ the test, i.e. no sub groups following this group will be executed. In the
+ example above, <c>g4</c> is the terminating group, hence Common Test will
+ execute a test that calls all init configuration functions in the path to
+ <c>g4</c>, i.e. <c>g1..g3..g4</c>. It will then call test cases <c>tc1</c>
+ and <c>tc5</c> in <c>g4</c> and finally all end configuration functions in order
+ <c>g4..g3..g1</c>.</p>
+
+ <p>Note that the group path specification doesn't necessarily
+ have to include <em>all</em> groups in the path to the terminating group.
+ Common Test will search for all matching paths if given an incomplete group
+ path.</p>
+
+ <p>Note also that it's possible to combine group names and group paths with the
+ <c>group_names_or_paths</c> parameter. Each element is treated as
+ an individual specification in combination with the <c>cases</c> parameter.
+ See examples below.</p>
+
+ <p>Examples:</p>
+ <pre>
+ -module(x_SUITE).
+ ...
+ %% The group definitions:
+ groups() ->
+ [{top1,[],[tc11,tc12,
+ {sub11,[],[tc12,tc13]},
+ {sub12,[],[tc14,tc15,
+ {sub121,[],[tc12,tc16]}]}]},
+
+ {top2,[],[{group,sub21},{group,sub22}]},
+ {sub21,[],[tc21,{group,sub2X2}]},
+ {sub22,[],[{group,sub221},tc21,tc22,{group,sub2X2}]},
+ {sub221,[],[tc21,tc23]},
+ {sub2X2,[],[tc21,tc24]}].
+ </pre>
+ <br></br>
+ <p><c>$ ct_run -suite "x_SUITE" -group all</c></p>
+ <p><c>1> ct:run_test([{suite,"x_SUITE"}, {group,all}]).</c></p>
+ <p>Two tests will be executed, one for all cases and all sub groups under <c>top1</c>,
+ and one for all under <c>top2</c>. (We would get the same result with
+ <c>-group top1 top2</c>, or <c>{group,[top1,top2]}</c>.</p>
+ <br></br>
+ <p><c>$ ct_run -suite "x_SUITE" -group top1</c></p>
+ <p><c>1> ct:run_test([{suite,"x_SUITE"}, {group,[top1]}]).</c></p>
+ <p>This will execute one test for all cases and sub groups under <c>top1</c>.</p>
+ <br></br>
+ <p><c>$ ct_run -suite "x_SUITE" -group top1 -case tc12</c></p>
+ <p><c>1> ct:run_test([{suite,"x_SUITE"}, {group,[top1]}, {testcase,[tc12]}]).</c></p>
+ <p>This will run a test that executes <c>tc12</c> in <c>top1</c> and any sub group
+ under <c>top1</c> where it can be found (<c>sub11</c> and <c>sub121</c>).</p>
+ <br></br>
+ <p><c>$ ct_run -suite "x_SUITE" -group [top1] -case tc12</c></p>
+ <p><c>1> ct:run_test([{suite,"x_SUITE"}, {group,[[top1]]}, {testcase,[tc12]}]).</c></p>
+ <p>This will execute <c>tc12</c> <em>only</em> in group <c>top1</c>.</p>
+ <br></br>
+ <p><c>$ ct_run -suite "x_SUITE" -group top1 -case tc16</c></p>
+ <p><c>1> ct:run_test([{suite,"x_SUITE"}, {group,[top1]}, {testcase,[tc16]}]).</c></p>
+ <p>This will search <c>top1</c> and all its sub groups for <c>tc16</c> and the result
+ will be that this test case executes in group <c>sub121</c>. (The specific path:
+ <c>-group [sub121]</c> or <c>{group,[[sub121]]}</c>, would have given
+ us the same result in this example).</p>
+ <br></br>
+ <p><c>$ ct_run -suite "x_SUITE" -group sub12 [sub12]</c></p>
+ <p><c>1> ct:run_test([{suite,"x_SUITE"}, {group,[sub12,[sub12]]}]).</c></p>
+ <p>This will execute two tests, one that includes all cases and sub groups under
+ <c>sub12</c>, and one with <em>only</em> the test cases in <c>sub12</c>.</p>
+ <br></br>
+ <p><c>$ ct_run -suite "x_SUITE" -group sub2X2</c></p>
+ <p><c>1> ct:run_test([{suite,"x_SUITE"}, {group,[sub2X2]}]).</c></p>
+ <p>In this example, Common Test will find and execute two tests, one for the path from
+ <c>top2</c> to <c>sub2X2</c> via <c>sub21</c>, and one from <c>top2</c> to <c>sub2X2</c>
+ via <c>sub22</c>.</p>
+ <br></br>
+ <p><c>$ ct_run -suite "x_SUITE" -group [sub21,sub2X2]</c></p>
+ <p><c>1> ct:run_test([{suite,"x_SUITE"}, {group,[[sub21,sub2X2]]}]).</c></p>
+ <p>Here, by specifying the unique path: <c>top2 -> sub21 -> sub2X2</c>, only one test
+ is executed. The second possible path from <c>top2</c> to <c>sub2X2</c> (above)
+ will be discarded.</p>
+ <br></br>
+ <p><c>$ ct_run -suite "x_SUITE" -group [sub22] -case tc22 tc21</c></p>
+ <p><c>1> ct:run_test([{suite,"x_SUITE"}, {group,[[sub22]]}, {testcase,[tc22,tc21]}]).</c></p>
+ <p>In this example only the test cases for <c>sub22</c> will be executed, and in
+ reverse order compared to the group definition.</p>
+ <br></br>
+
+ <p>If a test case that belongs to a group (according to the group definition), is executed
+ without a group specification, i.e. simply by means of (command line):</p>
+ <p><c>$ ct_run -suite "my_SUITE" -case my_tc</c></p>
+ <p>or (Erlang shell):</p>
+ <p><c>1> ct:run_test([{suite,"my_SUITE"}, {testcase,my_tc}]).</c></p>
+ <p>then Common Test ignores the group definition and executes the test case in the scope of the
+ test suite only (no group configuration functions are called).</p>
+
+ <p>The group specification feature, exactly as it has been presented in this section, can also
+ be used in <seealso marker="run_test_chapter#test_specifications">Test
+ Specifications</seealso> (with some extra features added). Please see below.</p>
+ </section>
+
+
<section>
<title>Running the interactive shell mode</title>
@@ -398,8 +559,8 @@
terms (e.g. log directory, label, style sheet, auto compilation).</p>
<p>With test specification terms it is possible to state exactly
which tests should run and in which order. A test term specifies
- either one or more suites, one or more test case groups, or one
- or more test cases in a group or suite.</p>
+ either one or more suites, one or more test case groups (possibly nested),
+ or one or more test cases in a group (or in multiple groups) or in a suite.</p>
<p>An arbitrary number of test terms may be declared in sequence.
Common Test will by default compile the terms into one or more tests
to be performed in one resulting test run. Note that a term that
@@ -418,28 +579,32 @@
are not executed and show up in the HTML log files as
SKIPPED.</p>
<p>When a test case group is specified, the resulting test
- executes the
- <c>init_per_group</c> function, followed by all test cases and
- sub groups (including their configuration functions), and
+ executes the <c>init_per_group</c> function, followed by all test
+ cases and sub groups (including their configuration functions), and
finally the <c>end_per_group</c> function. Also if particular
test cases in a group are specified, <c>init_per_group</c>
and <c>end_per_group</c> for the group in question are
called. If a group which is defined (in <c>Suite:group/0</c>) to
- be a sub group of another group, is specified (or particular test
+ be a sub group of another group, is specified (or if particular test
cases of a sub group are), Common Test will call the configuration
functions for the top level groups as well as for the sub group
in question (making it possible to pass configuration data all
the way from <c>init_per_suite</c> down to the test cases in the
sub group).</p>
-
- <p>With the <c>GroupSpec</c> element (below) it's possible to specify
- group execution properties that will override those specified in the
+ <p>The test specification utilizes the same mechanism for specifying
+ test case groups by means of names and paths, as explained in the
+ <seealso marker="run_test_chapter#group_execution">Group Execution</seealso>
+ section above, with the addition of the <c>GroupSpec</c> element
+ described next.</p>
+ <p>The <c>GroupSpec</c> element makes it possible to specify
+ group execution properties that will override those in the
group definition (i.e. in <c>groups/0</c>). Execution properties for
sub-groups may be overridden as well. This feature makes it possible to
change properties of groups at the time of execution,
- without even having to edit the test suite. More detailed documentation,
- and examples, can be found in the
- <seealso marker="write_test_chapter#test_case_groups">
+ without even having to edit the test suite. The very same
+ feature is available for <c>group</c> elements in the <c>Suite:all/0</c>
+ list. Therefore, more detailed documentation, and examples, can be
+ found in the <seealso marker="write_test_chapter#test_case_groups">
Test case groups</seealso> chapter.</p>
<p>Below is the test specification syntax. Test specifications can
@@ -495,6 +660,9 @@
{cover, CoverSpecFile}.
{cover, NodeRefs, CoverSpecFile}.
+ {cover_stop, Bool}.
+ {cover_stop, NodeRefs, Bool}.
+
{include, IncludeDirs}.
{include, NodeRefs, IncludeDirs}.
@@ -541,8 +709,8 @@
{groups, Dir, Suite, Groups}.
{groups, NodeRefs, Dir, Suite, Groups}.
- {groups, Dir, Suite, GroupSpec, {cases,Cases}}.
- {groups, NodeRefs, Dir, Suite, GroupSpec, {cases,Cases}}.
+ {groups, Dir, Suite, Groups, {cases,Cases}}.
+ {groups, NodeRefs, Dir, Suite, Groups, {cases,Cases}}.
{cases, Dir, Suite, Cases}.
{cases, NodeRefs, Dir, Suite, Cases}.
@@ -584,13 +752,16 @@
PrivDirOption = auto_per_run | auto_per_tc | manual_per_tc
EventHandlers = atom() | [atom()]
InitArgs = [term()]
- CTHModules = [CTHModule | {CTHModule, CTHInitArgs} | {CTHModule, CTHInitArgs, CTHPriority}]
+ CTHModules = [CTHModule |
+ {CTHModule, CTHInitArgs} |
+ {CTHModule, CTHInitArgs, CTHPriority}]
CTHModule = atom()
CTHInitArgs = term()
Dir = string()
Suites = atom() | [atom()] | all
Suite = atom()
- Groups = GroupSpec | [GroupSpec] | all
+ Groups = GroupPath | [GroupPath] | GroupSpec | [GroupSpec] | all
+ GroupPath = [GroupName]
GroupSpec = GroupName | {GroupName,Properties} | {GroupName,Properties,GroupSpec}
GroupName = atom()
GroupNames = GroupName | [GroupName]
diff --git a/lib/common_test/doc/src/write_test_chapter.xml b/lib/common_test/doc/src/write_test_chapter.xml
index 248d7de8b6..cc8d913994 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>2012</year>
+ <year>2003</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -982,38 +982,36 @@
<p>Example:</p>
<pre>
+ Some printouts during test case execution:
- Some printouts during test case execution:
+ 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, ?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]),
- 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, ?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]),
+ If starting the test without specifying any verbosity levels:
- If starting the test without specifying any verbosity levels:
+ $ ct_run ...
- $ ct_run ...
+ the following gets printed:
- the following gets printed:
-
- 1. Standard IO, importance = 50
- 2. Uncategorized, importance = 50
- 3. Categorized info, importance = 50
- 5. Categorized error, importance = 75
- 6. Categorized error, importance = 99
-
- If starting the test with:
-
- $ ct_run -verbosity 1 and info 75
-
- the following gets printed:
+ 1. Standard IO, importance = 50
+ 2. Uncategorized, importance = 50
+ 3. Categorized info, importance = 50
+ 5. Categorized error, importance = 75
+ 6. Categorized error, importance = 99
+
+ If starting the test with:
+
+ $ ct_run -verbosity 1 and info 75
+
+ the following gets printed:
- 3. Categorized info, importance = 50
- 4. Categorized info, importance = 25
- 6. Categorized error, importance = 99
- </pre>
+ 3. Categorized info, importance = 50
+ 4. Categorized info, importance = 25
+ 6. Categorized error, importance = 99</pre>
<p>How categories can be mapped to CSS tags is documented in the
<seealso marker="run_test_chapter#html_stylesheet">Running Tests</seealso>
diff --git a/lib/common_test/priv/Makefile.in b/lib/common_test/priv/Makefile.in
index 4372ab124e..5a9fabbe45 100644
--- a/lib/common_test/priv/Makefile.in
+++ b/lib/common_test/priv/Makefile.in
@@ -68,15 +68,15 @@ JS = jquery-latest.js jquery.tablesorter.min.js
include ../../test_server/vsn.mk
debug opt:
- sed -e 's;@CT_VSN@;$(VSN);' \
+ $(V_at)sed -e 's;@CT_VSN@;$(VSN);' \
-e 's;@TS_VSN@;$(TEST_SERVER_VSN);' \
../install.sh.in > install.sh
- chmod 775 install.sh
+ $(V_at)chmod 775 install.sh
docs:
clean:
- rm -f $(SCRIPTS)
+ $(V_at)rm -f $(SCRIPTS)
# ----------------------------------------------------
diff --git a/lib/common_test/src/Makefile b/lib/common_test/src/Makefile
index f7dce195d7..eb35a43d99 100644
--- a/lib/common_test/src/Makefile
+++ b/lib/common_test/src/Makefile
@@ -73,7 +73,8 @@ MODULES= \
cth_surefire \
ct_netconfc \
ct_conn_log_h \
- cth_conn_log
+ cth_conn_log \
+ ct_groups
TARGET_MODULES= $(MODULES:%=$(EBIN)/%)
BEAM_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
@@ -126,10 +127,10 @@ clean:
# Special Build Targets
# ----------------------------------------------------
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
# ----------------------------------------------------
# Release Target
diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl
index 5014309c0f..8eafdff29f 100644
--- a/lib/common_test/src/ct.erl
+++ b/lib/common_test/src/ct.erl
@@ -148,7 +148,7 @@ run(TestDirs) ->
%%% {config,CfgFiles} | {userconfig, UserConfig} |
%%% {allow_user_terms,Bool} | {logdir,LogDir} |
%%% {silent_connections,Conns} | {stylesheet,CSSFile} |
-%%% {cover,CoverSpecFile} | {step,StepOpts} |
+%%% {cover,CoverSpecFile} | {cover_stop,Bool} | {step,StepOpts} |
%%% {event_handler,EventHandlers} | {include,InclDirs} |
%%% {auto_compile,Bool} | {create_priv_dir,CreatePrivDir} |
%%% {multiply_timetraps,M} | {scale_timetraps,Bool} |
@@ -161,7 +161,8 @@ run(TestDirs) ->
%%% TestDirs = [string()] | string()
%%% Suites = [string()] | [atom()] | string() | atom()
%%% Cases = [atom()] | atom()
-%%% Groups = [atom()] | atom()
+%%% Groups = GroupNameOrPath | [GroupNameOrPath]
+%%% GroupNameOrPath = [atom()] | atom() | all
%%% TestSpecs = [string()] | string()
%%% Label = string() | atom()
%%% CfgFiles = [string()] | string()
@@ -987,8 +988,9 @@ get_testdata(Key) ->
end.
%%%-----------------------------------------------------------------
-%%% @spec abort_current_testcase(Reason) -> ok | {error,no_testcase_running}
+%%% @spec abort_current_testcase(Reason) -> ok | {error,ErrorReason}
%%% Reason = term()
+%%% ErrorReason = no_testcase_running | parallel_group
%%%
%%% @doc <p>When calling this function, the currently executing test case will be aborted.
%%% It is the user's responsibility to know for sure which test case is currently
diff --git a/lib/common_test/src/ct_config.erl b/lib/common_test/src/ct_config.erl
index 30bf5925c0..b1d709bc75 100644
--- a/lib/common_test/src/ct_config.erl
+++ b/lib/common_test/src/ct_config.erl
@@ -171,7 +171,7 @@ process_default_configs(Opts) ->
lists:flatmap(fun({config,[_|_] = FileOrFiles}) ->
case {io_lib:printable_list(FileOrFiles),
io_lib:printable_list(hd(FileOrFiles))} of
- {true,true} ->
+ {false,true} ->
FileOrFiles;
{true,false} ->
[FileOrFiles];
@@ -532,7 +532,8 @@ do_require(Name,Key) ->
case get_key_from_name(Name) of
{error,_} ->
allocate(Name,Key);
- {ok,Key} ->
+ {ok,NameKey} when NameKey == Key;
+ is_tuple(Key) andalso element(1,Key) == NameKey ->
%% already allocated - check that it has all required subkeys
R = make_ref(),
case get_config(Key,R,[]) of
diff --git a/lib/common_test/src/ct_conn_log_h.erl b/lib/common_test/src/ct_conn_log_h.erl
index bf27238121..d7bd18606b 100644
--- a/lib/common_test/src/ct_conn_log_h.erl
+++ b/lib/common_test/src/ct_conn_log_h.erl
@@ -64,10 +64,16 @@ do_open_files([],Acc) ->
handle_event({_Type, GL, _Msg}, State) when node(GL) /= node() ->
{ok, State};
handle_event({_Type,_GL,{Pid,{ct_connection,Action,ConnName},Report}},State) ->
+ %% NOTE: if the format of this event is changed
+ %% ({ct_connection,Action,ConnName}) then remember to change
+ %% test_server_h:report_receiver as well!!!
Info = conn_info(Pid,#conn_log{name=ConnName,action=Action}),
write_report(now(),Info,Report,State),
{ok, State};
handle_event({_Type,_GL,{Pid,Info=#conn_log{},Report}},State) ->
+ %% NOTE: if the format of this event is changed
+ %% (Info=#conn_log{}) then remember to change
+ %% test_server_h:report_receiver as well!!!
write_report(now(),conn_info(Pid,Info),Report,State),
{ok, State};
handle_event({error_report,_,{Pid,_,[{ct_connection,ConnName}|R]}},State) ->
diff --git a/lib/common_test/src/ct_cover.erl b/lib/common_test/src/ct_cover.erl
index d39f50ba00..ae671c750a 100644
--- a/lib/common_test/src/ct_cover.erl
+++ b/lib/common_test/src/ct_cover.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -24,7 +24,7 @@
-module(ct_cover).
--export([get_spec/1, add_nodes/1, remove_nodes/1]).
+-export([get_spec/1, add_nodes/1, remove_nodes/1, cross_cover_analyse/2]).
-include("ct_util.hrl").
@@ -100,6 +100,22 @@ remove_nodes(Nodes) ->
%%%-----------------------------------------------------------------
+%%% @spec cross_cover_analyse(Level,Tests) -> ok
+%%% Level = overview | details
+%%% Tests = [{Tag,Dir}]
+%%% Tag = atom()
+%%% Dir = string()
+%%%
+%%% @doc Accumulate cover results over multiple tests.
+%%% See the chapter about <seealso
+%%% marker="cover_chapter#cross_cover">cross cover
+%%% analysis</seealso> in the users's guide.
+%%%
+cross_cover_analyse(Level,Tests) ->
+ test_server_ctrl:cross_cover_analyse(Level,Tests).
+
+
+%%%-----------------------------------------------------------------
%%% @hidden
%% Read cover specification file and return the parsed info.
@@ -249,9 +265,11 @@ get_app_info(App=#cover{app=Name}, [{excl_mods,Name,Mods1}|Terms]) ->
Mods = App#cover.excl_mods,
get_app_info(App#cover{excl_mods=Mods++Mods1},Terms);
-get_app_info(App=#cover{app=Name}, [{cross_apps,Name,AppMods1}|Terms]) ->
- AppMods = App#cover.cross,
- get_app_info(App#cover{cross=AppMods++AppMods1},Terms);
+get_app_info(App=#cover{app=none}, [{cross,Cross}|Terms]) ->
+ get_app_info(App, [{cross,none,Cross}|Terms]);
+get_app_info(App=#cover{app=Name}, [{cross,Name,Cross1}|Terms]) ->
+ Cross = App#cover.cross,
+ get_app_info(App#cover{cross=Cross++Cross1},Terms);
get_app_info(App=#cover{app=none}, [{src_dirs,Dirs}|Terms]) ->
get_app_info(App, [{src_dirs,none,Dirs}|Terms]);
@@ -354,10 +372,10 @@ remove_excludes_and_dups(CoverData=#cover{excl_mods=Excl,incl_mods=Incl}) ->
files2mods(Info=#cover{excl_mods=ExclFs,
incl_mods=InclFs,
- cross=CrossFs}) ->
+ cross=Cross}) ->
Info#cover{excl_mods=files2mods1(ExclFs),
incl_mods=files2mods1(InclFs),
- cross=files2mods1(CrossFs)}.
+ cross=[{Tag,files2mods1(Fs)} || {Tag,Fs} <- Cross]}.
files2mods1([M|Fs]) when is_atom(M) ->
[M|files2mods1(Fs)];
diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl
index bec3368869..c1abf27e9f 100644
--- a/lib/common_test/src/ct_framework.erl
+++ b/lib/common_test/src/ct_framework.erl
@@ -32,8 +32,6 @@
-export([error_in_suite/1, init_per_suite/1, end_per_suite/1,
init_per_group/2, end_per_group/2]).
--export([make_all_conf/3, make_conf/5]).
-
-include("ct_event.hrl").
-include("ct_util.hrl").
@@ -876,13 +874,13 @@ get_suite(Mod, all) ->
{'EXIT',_} ->
get_all(Mod, []);
GroupDefs when is_list(GroupDefs) ->
- case catch find_groups(Mod, all, all, GroupDefs) of
+ case catch ct_groups:find_groups(Mod, all, all, GroupDefs) of
{error,_} = Error ->
%% this makes test_server call error_in_suite as first
%% (and only) test case so we can report Error properly
[{?MODULE,error_in_suite,[[Error]]}];
ConfTests ->
- get_all(Mod, ConfTests)
+ get_all(Mod, ConfTests)
end;
_ ->
E = "Bad return value from "++atom_to_list(Mod)++":groups/0",
@@ -901,7 +899,7 @@ get_suite(Mod, Group={conf,Props,_Init,TCs,_End}) ->
{'EXIT',_} ->
[Group];
GroupDefs when is_list(GroupDefs) ->
- case catch find_groups(Mod, Name, TCs, GroupDefs) of
+ case catch ct_groups:find_groups(Mod, Name, TCs, GroupDefs) of
{error,_} = Error ->
%% this makes test_server call error_in_suite as first
%% (and only) test case so we can report Error properly
@@ -916,12 +914,13 @@ get_suite(Mod, Group={conf,Props,_Init,TCs,_End}) ->
%% init/end functions for top groups will be executed
case catch ?val(name, element(2, hd(ConfTests))) of
Name -> % top group
- delete_subs(ConfTests, ConfTests);
+ ct_groups:delete_subs(ConfTests, ConfTests);
_ ->
[]
end;
false ->
- ConfTests1 = delete_subs(ConfTests, ConfTests),
+ ConfTests1 = ct_groups:delete_subs(ConfTests,
+ ConfTests),
case ?val(override, Props) of
undefined ->
ConfTests1;
@@ -930,9 +929,9 @@ get_suite(Mod, Group={conf,Props,_Init,TCs,_End}) ->
ORSpec ->
ORSpec1 = if is_tuple(ORSpec) -> [ORSpec];
true -> ORSpec end,
- search_and_override(ConfTests1,
- ORSpec1, Mod)
- end
+ ct_groups:search_and_override(ConfTests1,
+ ORSpec1, Mod)
+ end
end
end;
_ ->
@@ -976,234 +975,6 @@ get_all_cases1(_, []) ->
%%%-----------------------------------------------------------------
-find_groups(Mod, Name, TCs, GroupDefs) ->
- Found = find(Mod, Name, TCs, GroupDefs, [], GroupDefs, false),
- trim(Found).
-
-find(Mod, all, _TCs, [{Name,Props,Tests} | Gs], Known, Defs, _)
- when is_atom(Name), is_list(Props), is_list(Tests) ->
- cyclic_test(Mod, Name, Known),
- [make_conf(Mod, Name, Props,
- find(Mod, all, all, Tests, [Name | Known], Defs, true)) |
- find(Mod, all, all, Gs, [], Defs, true)];
-
-find(Mod, Name, TCs, [{Name,Props,Tests} | _Gs], Known, Defs, false)
- when is_atom(Name), is_list(Props), is_list(Tests) ->
- cyclic_test(Mod, Name, Known),
- case TCs of
- all ->
- [make_conf(Mod, Name, Props,
- find(Mod, Name, TCs, Tests, [Name | Known], Defs, true))];
- _ ->
- Tests1 = [TC || TC <- TCs,
- lists:member(TC, Tests) == true],
- [make_conf(Mod, Name, Props, Tests1)]
- end;
-
-find(Mod, Name, TCs, [{Name1,Props,Tests} | Gs], Known, Defs, false)
- when is_atom(Name1), is_list(Props), is_list(Tests) ->
- cyclic_test(Mod, Name1, Known),
- [make_conf(Mod,Name1,Props,
- find(Mod, Name, TCs, Tests, [Name1 | Known], Defs, false)) |
- find(Mod, Name, TCs, Gs, [], Defs, false)];
-
-find(Mod, Name, _TCs, [{Name,_Props,_Tests} | _Gs], _Known, _Defs, true)
- when is_atom(Name) ->
- E = "Duplicate groups named "++atom_to_list(Name)++" in "++
- atom_to_list(Mod)++":groups/0",
- throw({error,list_to_atom(E)});
-
-find(Mod, Name, all, [{Name1,Props,Tests} | Gs], Known, Defs, true)
- when is_atom(Name1), is_list(Props), is_list(Tests) ->
- cyclic_test(Mod, Name1, Known),
- [make_conf(Mod, Name1, Props,
- find(Mod, Name, all, Tests, [Name1 | Known], Defs, true)) |
- find(Mod, Name, all, Gs, [], Defs, true)];
-
-find(Mod, Name, TCs, [{group,Name1} | Gs], Known, Defs, Found)
- when is_atom(Name1) ->
- find(Mod, Name, TCs, [expand(Mod, Name1, Defs) | Gs], Known, Defs, Found);
-
-%% Undocumented remote group feature, use with caution
-find(Mod, Name, TCs, [{group, ExtMod, ExtGrp} | Gs], Known, Defs, true)
- when is_atom(ExtMod), is_atom(ExtGrp) ->
- ExternalDefs = ExtMod:groups(),
- ExternalTCs = find(ExtMod, ExtGrp, TCs, [{group, ExtGrp}],
- [], ExternalDefs, false),
- ExternalTCs ++ find(Mod, Name, TCs, Gs, Known, Defs, true);
-
-find(Mod, Name, TCs, [{Name1,Tests} | Gs], Known, Defs, Found)
- when is_atom(Name1), is_list(Tests) ->
- find(Mod, Name, TCs, [{Name1,[],Tests} | Gs], Known, Defs, Found);
-
-find(Mod, Name, TCs, [_TC | Gs], Known, Defs, false) ->
- find(Mod, Name, TCs, Gs, Known, Defs, false);
-
-find(Mod, Name, TCs, [TC | Gs], Known, Defs, true) when is_atom(TC) ->
- [{Mod, TC} | find(Mod, Name, TCs, Gs, Known, Defs, true)];
-
-find(Mod, Name, TCs, [{ExternalTC, Case} = TC | Gs], Known, Defs, true)
- when is_atom(ExternalTC),
- is_atom(Case) ->
- [TC | find(Mod, Name, TCs, Gs, Known, Defs, true)];
-
-find(Mod, _Name, _TCs, [BadTerm | _Gs], Known, _Defs, _Found) ->
- Where = if length(Known) == 0 ->
- atom_to_list(Mod)++":groups/0";
- true ->
- "group "++atom_to_list(lists:last(Known))++
- " in "++atom_to_list(Mod)++":groups/0"
- end,
- Term = io_lib:format("~p", [BadTerm]),
- E = "Bad term "++lists:flatten(Term)++" in "++Where,
- throw({error,list_to_atom(E)});
-
-find(_Mod, _Name, _TCs, [], _Known, _Defs, false) ->
- ['$NOMATCH'];
-
-find(_Mod, _Name, _TCs, [], _Known, _Defs, _Found) ->
- [].
-
-delete_subs([{conf, _,_,_,_} = Conf | Confs], All) ->
- All1 = delete_conf(Conf, All),
- case is_sub(Conf, All1) of
- true ->
- delete_subs(Confs, All1);
- false ->
- delete_subs(Confs, All)
- end;
-delete_subs([_Else | Confs], All) ->
- delete_subs(Confs, All);
-delete_subs([], All) ->
- All.
-
-delete_conf({conf,Props,_,_,_}, Confs) ->
- Name = ?val(name, Props),
- [Conf || Conf = {conf,Props0,_,_,_} <- Confs,
- Name =/= ?val(name, Props0)].
-
-is_sub({conf,Props,_,_,_}=Conf, [{conf,_,_,Tests,_} | Confs]) ->
- Name = ?val(name, Props),
- case lists:any(fun({conf,Props0,_,_,_}) ->
- case ?val(name, Props0) of
- N when N == Name ->
- true;
- _ ->
- false
- end;
- (_) ->
- false
- end, Tests) of
- true ->
- true;
- false ->
- is_sub(Conf, Tests) or is_sub(Conf, Confs)
- end;
-
-is_sub(Conf, [_TC | Tests]) ->
- is_sub(Conf, Tests);
-
-is_sub(_Conf, []) ->
- false.
-
-trim(['$NOMATCH' | Tests]) ->
- trim(Tests);
-
-trim([{conf,Props,Init,Tests,End} | Confs]) ->
- case trim(Tests) of
- [] ->
- trim(Confs);
- Trimmed ->
- [{conf,Props,Init,Trimmed,End} | trim(Confs)]
- end;
-
-trim([TC | Tests]) ->
- [TC | trim(Tests)];
-
-trim([]) ->
- [].
-
-cyclic_test(Mod, Name, Names) ->
- case lists:member(Name, Names) of
- true ->
- E = "Cyclic reference to group "++atom_to_list(Name)++
- " in "++atom_to_list(Mod)++":groups/0",
- throw({error,list_to_atom(E)});
- false ->
- ok
- end.
-
-expand(Mod, Name, Defs) ->
- case lists:keysearch(Name, 1, Defs) of
- {value,Def} ->
- Def;
- false ->
- E = "Invalid group "++atom_to_list(Name)++
- " in "++atom_to_list(Mod)++":groups/0",
- throw({error,list_to_atom(E)})
- end.
-
-make_all_conf(Dir, Mod, _Props) ->
- case code:is_loaded(Mod) of
- false ->
- code:load_abs(filename:join(Dir,atom_to_list(Mod)));
- _ ->
- ok
- end,
- make_all_conf(Mod).
-
-make_all_conf(Mod) ->
- case catch apply(Mod, groups, []) of
- {'EXIT',_} ->
- {error,{invalid_group_definition,Mod}};
- GroupDefs when is_list(GroupDefs) ->
- case catch find_groups(Mod, all, all, GroupDefs) of
- {error,_} = Error ->
- %% this makes test_server call error_in_suite as first
- %% (and only) test case so we can report Error properly
- [{?MODULE,error_in_suite,[[Error]]}];
- [] ->
- {error,{invalid_group_spec,Mod}};
- ConfTests ->
- [{conf,Props,Init,all,End} ||
- {conf,Props,Init,_,End}
- <- delete_subs(ConfTests, ConfTests)]
- end
- end.
-
-make_conf(Dir, Mod, Name, Props, TestSpec) ->
- case code:is_loaded(Mod) of
- false ->
- code:load_abs(filename:join(Dir,atom_to_list(Mod)));
- _ ->
- ok
- end,
- make_conf(Mod, Name, Props, TestSpec).
-
-make_conf(Mod, Name, Props, TestSpec) ->
- case code:is_loaded(Mod) of
- false ->
- code:load_file(Mod);
- _ ->
- 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 ->
- ct_logs:log("TEST INFO", "init_per_group/2 and "
- "end_per_group/2 missing for group "
- "~p in ~p, using default.",
- [Name,Mod]),
- {{?MODULE,init_per_group},
- {?MODULE,end_per_group},
- [{suite,Mod}]}
- end,
- {conf,[{name,Name}|Props++ExtraProps],InitConf,TestSpec,EndConf}.
-
-%%%-----------------------------------------------------------------
-
get_all(Mod, ConfTests) ->
case catch apply(Mod, all, []) of
{'EXIT',_} ->
@@ -1218,133 +989,24 @@ get_all(Mod, ConfTests) ->
[{?MODULE,error_in_suite,[[{error,What}]]}];
SeqsAndTCs ->
%% expand group references in all() using ConfTests
- case catch expand_groups(SeqsAndTCs, ConfTests, Mod) of
+ case catch ct_groups:expand_groups(SeqsAndTCs,
+ ConfTests,
+ Mod) of
{error,_} = Error ->
[{?MODULE,error_in_suite,[[Error]]}];
Tests ->
- delete_subs(Tests, Tests)
+ ct_groups:delete_subs(Tests, Tests)
end
end;
Skip = {skip,_Reason} ->
Skip;
_ ->
Reason =
- list_to_atom("Bad return value from "++atom_to_list(Mod)++":all/0"),
+ list_to_atom("Bad return value from "++
+ atom_to_list(Mod)++":all/0"),
[{?MODULE,error_in_suite,[[{error,Reason}]]}]
end.
-expand_groups([H | T], ConfTests, Mod) ->
- [expand_groups(H, ConfTests, Mod) | expand_groups(T, ConfTests, Mod)];
-expand_groups([], _ConfTests, _Mod) ->
- [];
-expand_groups({group,Name}, ConfTests, Mod) ->
- expand_groups({group,Name,default,[]}, ConfTests, Mod);
-expand_groups({group,Name,default}, ConfTests, Mod) ->
- expand_groups({group,Name,default,[]}, ConfTests, Mod);
-expand_groups({group,Name,ORProps}, ConfTests, Mod) when is_list(ORProps) ->
- expand_groups({group,Name,ORProps,[]}, ConfTests, Mod);
-expand_groups({group,Name,ORProps,SubORSpec}, ConfTests, Mod) ->
- FindConf =
- fun(Conf = {conf,Props,Init,Ts,End}) ->
- case ?val(name, Props) of
- Name when ORProps == default ->
- [Conf];
- Name ->
- [{conf,[{name,Name}|ORProps],Init,Ts,End}];
- _ ->
- []
- end
- end,
- case lists:flatmap(FindConf, ConfTests) of
- [] ->
- throw({error,invalid_ref_msg(Name, Mod)});
- Matching when SubORSpec == [] ->
- Matching;
- Matching ->
- override_props(Matching, SubORSpec, Name,Mod)
- end;
-expand_groups(SeqOrTC, _ConfTests, _Mod) ->
- SeqOrTC.
-
-%% search deep for the matching conf test and modify it and any
-%% sub tests according to the override specification
-search_and_override([Conf = {conf,Props,Init,Tests,End}], ORSpec, Mod) ->
- Name = ?val(name, Props),
- case lists:keysearch(Name, 1, ORSpec) of
- {value,{Name,default}} ->
- [Conf];
- {value,{Name,ORProps}} ->
- [{conf,[{name,Name}|ORProps],Init,Tests,End}];
- {value,{Name,default,[]}} ->
- [Conf];
- {value,{Name,default,SubORSpec}} ->
- override_props([Conf], SubORSpec, Name,Mod);
- {value,{Name,ORProps,SubORSpec}} ->
- override_props([{conf,[{name,Name}|ORProps],
- Init,Tests,End}], SubORSpec, Name,Mod);
- _ ->
- [{conf,Props,Init,search_and_override(Tests,ORSpec,Mod),End}]
- end.
-
-%% Modify the Tests element according to the override specification
-override_props([{conf,Props,Init,Tests,End} | Confs], SubORSpec, Name,Mod) ->
- {Subs,SubORSpec1} = override_sub_props(Tests, [], SubORSpec, Mod),
- [{conf,Props,Init,Subs,End} | override_props(Confs, SubORSpec1, Name,Mod)];
-override_props([], [], _,_) ->
- [];
-override_props([], SubORSpec, Name,Mod) ->
- Es = [invalid_ref_msg(Name, element(1,Spec), Mod) || Spec <- SubORSpec],
- throw({error,Es}).
-
-override_sub_props([], New, ORSpec, _) ->
- {?rev(New),ORSpec};
-override_sub_props([T = {conf,Props,Init,Tests,End} | Ts],
- New, ORSpec, Mod) ->
- Name = ?val(name, Props),
- case lists:keysearch(Name, 1, ORSpec) of
- {value,Spec} -> % group found in spec
- Props1 =
- case element(2, Spec) of
- default -> Props;
- ORProps -> [{name,Name} | ORProps]
- end,
- case catch element(3, Spec) of
- Undef when Undef == [] ; 'EXIT' == element(1, Undef) ->
- override_sub_props(Ts, [{conf,Props1,Init,Tests,End} | New],
- lists:keydelete(Name, 1, ORSpec), Mod);
- SubORSpec when is_list(SubORSpec) ->
- case override_sub_props(Tests, [], SubORSpec, Mod) of
- {Subs,[]} ->
- override_sub_props(Ts, [{conf,Props1,Init,
- Subs,End} | New],
- lists:keydelete(Name, 1, ORSpec),
- Mod);
- {_,NonEmptySpec} ->
- Es = [invalid_ref_msg(Name, element(1, GrRef),
- Mod) || GrRef <- NonEmptySpec],
- throw({error,Es})
- end;
- BadGrSpec ->
- throw({error,{invalid_form,BadGrSpec}})
- end;
- _ -> % not a group in spec
- override_sub_props(Ts, [T | New], ORSpec, Mod)
- end;
-override_sub_props([TC | Ts], New, ORSpec, Mod) ->
- override_sub_props(Ts, [TC | New], ORSpec, Mod).
-
-invalid_ref_msg(Name, Mod) ->
- E = "Invalid reference to group "++
- atom_to_list(Name)++" in "++
- atom_to_list(Mod)++":all/0",
- list_to_atom(E).
-
-invalid_ref_msg(Name0, Name1, Mod) ->
- E = "Invalid reference to group "++
- atom_to_list(Name1)++" from "++atom_to_list(Name0)++
- " in "++atom_to_list(Mod)++":all/0",
- list_to_atom(E).
-
%%!============================================================
%%! The support for sequences by means of using sequences/0
%%! will be removed in OTP R15. The code below is only kept
diff --git a/lib/common_test/src/ct_groups.erl b/lib/common_test/src/ct_groups.erl
new file mode 100644
index 0000000000..74ab5e5439
--- /dev/null
+++ b/lib/common_test/src/ct_groups.erl
@@ -0,0 +1,599 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2012. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%% @doc Common Test Framework callback module.
+%%%
+%%% <p>This module contains CT internal help functions for searching
+%%% through groups specification trees and producing resulting
+%%% tests.</p>
+
+-module(ct_groups).
+
+-export([find_groups/4]).
+-export([make_all_conf/3, make_all_conf/4, make_conf/5]).
+-export([delete_subs/2]).
+-export([expand_groups/3, search_and_override/3]).
+
+-define(val(Key, List), proplists:get_value(Key, List)).
+-define(val(Key, List, Def), proplists:get_value(Key, List, Def)).
+-define(rev(L), lists:reverse(L)).
+
+find_groups(Mod, GrNames, TCs, GroupDefs) when is_atom(GrNames) ;
+ (length(GrNames) == 1) ->
+ find_groups1(Mod, GrNames, TCs, GroupDefs);
+
+find_groups(Mod, Groups, TCs, GroupDefs) when Groups /= [] ->
+ lists:append([find_groups1(Mod, [GrNames], TCs, GroupDefs) ||
+ GrNames <- Groups]);
+
+find_groups(_Mod, [], _TCs, _GroupDefs) ->
+ [].
+
+%% GrNames == atom(): Single group name, perform full search
+%% GrNames == list(): List of groups, find all matching paths
+%% GrNames == [list()]: Search path terminated by last group in GrNames
+find_groups1(Mod, GrNames, TCs, GroupDefs) ->
+ {GrNames1,FindAll} =
+ case GrNames of
+ Name when is_atom(Name), Name /= all ->
+ {[Name],true};
+ [Path] when is_list(Path) ->
+ {Path,false};
+ Path ->
+ {Path,true}
+ end,
+ TCs1 = if (is_atom(TCs) and (TCs /= all)) or is_tuple(TCs) ->
+ [TCs];
+ true ->
+ TCs
+ end,
+ Found = find(Mod, GrNames1, TCs1, GroupDefs, [],
+ GroupDefs, FindAll),
+ [Conf || Conf <- Found, Conf /= 'NOMATCH'].
+
+%% Locate all groups
+find(Mod, all, all, [{Name,Props,Tests} | Gs], Known, Defs, _)
+ when is_atom(Name), is_list(Props), is_list(Tests) ->
+ cyclic_test(Mod, Name, Known),
+ trim(make_conf(Mod, Name, Props,
+ find(Mod, all, all, Tests, [Name | Known],
+ Defs, true))) ++
+ find(Mod, all, all, Gs, Known, Defs, true);
+
+%% Locate particular TCs in all groups
+find(Mod, all, TCs, [{Name,Props,Tests} | Gs], Known, Defs, _)
+ when is_atom(Name), is_list(Props), is_list(Tests) ->
+ cyclic_test(Mod, Name, Known),
+ Tests1 = rm_unwanted_tcs(Tests, TCs, []),
+ trim(make_conf(Mod, Name, Props,
+ find(Mod, all, TCs, Tests1, [Name | Known],
+ Defs, true))) ++
+ find(Mod, all, TCs, Gs, Known, Defs, true);
+
+%% Found next group is in search path
+find(Mod, [Name|GrNames]=SPath, TCs, [{Name,Props,Tests} | Gs], Known,
+ Defs, FindAll) when is_atom(Name), is_list(Props), is_list(Tests) ->
+ cyclic_test(Mod, Name, Known),
+ Tests1 = rm_unwanted_tcs(Tests, TCs, GrNames),
+ trim(make_conf(Mod, Name, Props,
+ find(Mod, GrNames, TCs, Tests1, [Name|Known],
+ Defs, FindAll))) ++
+ find(Mod, SPath, TCs, Gs, Known, Defs, FindAll);
+
+%% Group path terminated, stop the search
+find(Mod, [], TCs, Tests, _Known, _Defs, false) ->
+ Cases = lists:flatmap(fun(TC) when is_atom(TC), TCs == all ->
+ [{Mod,TC}];
+ ({group,_}) ->
+ [];
+ ({_,_}=TC) when TCs == all ->
+ [TC];
+ (TC) ->
+ if is_atom(TC) ->
+ Tuple = {Mod,TC},
+ case lists:member(Tuple, TCs) of
+ true ->
+ [Tuple];
+ false ->
+ case lists:member(TC, TCs) of
+ true -> [{Mod,TC}];
+ false -> []
+ end
+ end;
+ true ->
+ []
+ end
+ end, Tests),
+ if Cases == [] -> ['NOMATCH'];
+ true -> Cases
+ end;
+
+%% No more groups
+find(_Mod, [_|_], _TCs, [], _Known, _Defs, _) ->
+ ['NOMATCH'];
+
+%% Found group not next in search path
+find(Mod, GrNames, TCs, [{Name,Props,Tests} | Gs], Known,
+ Defs, FindAll) when is_atom(Name), is_list(Props), is_list(Tests) ->
+ cyclic_test(Mod, Name, Known),
+ Tests1 = rm_unwanted_tcs(Tests, TCs, GrNames),
+ trim(make_conf(Mod, Name, Props,
+ find(Mod, GrNames, TCs, Tests1, [Name|Known],
+ Defs, FindAll))) ++
+ find(Mod, GrNames, TCs, Gs, Known, Defs, FindAll);
+
+%% A nested group defined on top level found
+find(Mod, GrNames, TCs, [{group,Name1} | Gs], Known, Defs, FindAll)
+ when is_atom(Name1) ->
+ find(Mod, GrNames, TCs, [expand(Mod, Name1, Defs) | Gs], Known,
+ Defs, FindAll);
+
+%% Undocumented remote group feature, use with caution
+find(Mod, GrNames, TCs, [{group, ExtMod, ExtGrp} | Gs], Known,
+ Defs, FindAll) when is_atom(ExtMod), is_atom(ExtGrp) ->
+ ExternalDefs = ExtMod:groups(),
+ ExternalTCs = find(ExtMod, ExtGrp, TCs, [{group, ExtGrp}],
+ [], ExternalDefs, FindAll),
+ ExternalTCs ++ find(Mod, GrNames, TCs, Gs, Known, Defs, FindAll);
+
+%% Group definition without properties, add an empty property list
+find(Mod, GrNames, TCs, [{Name1,Tests} | Gs], Known, Defs, FindAll)
+ when is_atom(Name1), is_list(Tests) ->
+ find(Mod, GrNames, TCs, [{Name1,[],Tests} | Gs], Known, Defs, FindAll);
+
+%% Save, and keep searching
+find(Mod, GrNames, TCs, [{ExternalTC, Case} = TC | Gs], Known,
+ Defs, FindAll) when is_atom(ExternalTC),
+ is_atom(Case) ->
+ [TC | find(Mod, GrNames, TCs, Gs, Known, Defs, FindAll)];
+
+%% Save test case
+find(Mod, GrNames, all, [TC | Gs], Known,
+ Defs, FindAll) when is_atom(TC) ->
+ [{Mod,TC} | find(Mod, GrNames, all, Gs, Known, Defs, FindAll)];
+
+%% Save test case
+find(Mod, GrNames, all, [{M,TC} | Gs], Known,
+ Defs, FindAll) when is_atom(M), M /= group, is_atom(TC) ->
+ [{M,TC} | find(Mod, GrNames, all, Gs, Known, Defs, FindAll)];
+
+%% Check if test case should be saved
+find(Mod, GrNames, TCs, [TC | Gs], Known,
+ Defs, FindAll) when is_atom(TC) orelse
+ ((size(TC) == 2) and (element(1,TC) /= group)) ->
+ Case =
+ if is_atom(TC) ->
+ Tuple = {Mod,TC},
+ case lists:member(Tuple, TCs) of
+ true ->
+ Tuple;
+ false ->
+ case lists:member(TC, TCs) of
+ true -> {Mod,TC};
+ false -> []
+ end
+ end;
+ true ->
+ case lists:member(TC, TCs) of
+ true -> {Mod,TC};
+ false -> []
+ end
+ end,
+ if Case == [] ->
+ find(Mod, GrNames, TCs, Gs, Known, Defs, FindAll);
+ true ->
+ [Case | find(Mod, GrNames, TCs, Gs, Known, Defs, FindAll)]
+ end;
+
+%% Unexpeted term in group list
+find(Mod, _GrNames, _TCs, [BadTerm | _Gs], Known, _Defs, _FindAll) ->
+ Where = if length(Known) == 0 ->
+ atom_to_list(Mod)++":groups/0";
+ true ->
+ "group "++atom_to_list(lists:last(Known))++
+ " in "++atom_to_list(Mod)++":groups/0"
+ end,
+ Term = io_lib:format("~p", [BadTerm]),
+ E = "Bad term "++lists:flatten(Term)++" in "++Where,
+ throw({error,list_to_atom(E)});
+
+%% No more groups
+find(_Mod, _GrNames, _TCs, [], _Known, _Defs, _) ->
+ [].
+
+%%%-----------------------------------------------------------------
+
+%% We have to always search bottom up to only remove a branch
+%% if there's 'NOMATCH' in the leaf (otherwise, the branch should
+%% be kept)
+
+trim({conf,Props,Init,Tests,End}) ->
+ try trim(Tests) of
+ [] -> [];
+ Tests1 -> [{conf,Props,Init,Tests1,End}]
+ catch
+ throw:_ -> []
+ end;
+
+trim(Tests) when is_list(Tests) ->
+ %% we need to compare the result of trimming each test on this
+ %% level, and only let a 'NOMATCH' fail the level if no
+ %% successful sub group can be found
+ Tests1 =
+ lists:flatmap(fun(Test) ->
+ IsConf = case Test of
+ {conf,_,_,_,_} ->
+ true;
+ _ ->
+ false
+ end,
+ try trim_test(Test) of
+ [] -> [];
+ Test1 when IsConf -> [{conf,Test1}];
+ Test1 -> [Test1]
+ catch
+ throw:_ -> ['NOMATCH']
+ end
+ end, Tests),
+ case lists:keymember(conf, 1, Tests1) of
+ true -> % at least one successful group
+ lists:flatmap(fun({conf,Test}) -> [Test];
+ ('NOMATCH') -> []; % ignore any 'NOMATCH'
+ (Test) -> [Test]
+ end, Tests1);
+ false ->
+ case lists:member('NOMATCH', Tests1) of
+ true ->
+ throw('NOMATCH');
+ false ->
+ Tests1
+ end
+ end.
+
+trim_test({conf,Props,Init,Tests,End}) ->
+ case trim(Tests) of
+ [] ->
+ [];
+ Tests1 ->
+ {conf,Props,Init,Tests1,End}
+ end;
+
+trim_test('NOMATCH') ->
+ throw('NOMATCH');
+
+trim_test(Test) ->
+ Test.
+
+%% GrNames is [] if the terminating group has been found. From
+%% that point, all specified test should be included (as well as
+%% sub groups for deeper search).
+rm_unwanted_tcs(Tests, all, []) ->
+ Tests;
+
+rm_unwanted_tcs(Tests, TCs, []) ->
+ sort_tests(lists:flatmap(fun(Test) when is_tuple(Test),
+ (size(Test) > 2) ->
+ [Test];
+ (Test={group,_}) ->
+ [Test];
+ (Test={_M,TC}) ->
+ case lists:member(TC, TCs) of
+ true -> [Test];
+ false -> []
+ end;
+ (Test) when is_atom(Test) ->
+ case lists:keysearch(Test, 2, TCs) of
+ {value,_} ->
+ [Test];
+ _ ->
+ case lists:member(Test, TCs) of
+ true -> [Test];
+ false -> []
+ end
+ end;
+ (Test) -> [Test]
+ end, Tests), TCs);
+
+rm_unwanted_tcs(Tests, _TCs, _) ->
+ [Test || Test <- Tests, not is_atom(Test)].
+
+%% make sure the order of tests is according to the order in TCs
+sort_tests(Tests, TCs) when is_list(TCs)->
+ lists:sort(fun(T1, T2) ->
+ case {is_tc(T1),is_tc(T2)} of
+ {true,true} ->
+ (position(T1, TCs) =<
+ position(T2, TCs));
+ {false,true} ->
+ (position(T2, TCs) == (length(TCs)+1));
+ _ -> true
+
+ end
+ end, Tests);
+sort_tests(Tests, _) ->
+ Tests.
+
+is_tc(T) when is_atom(T) -> true;
+is_tc({group,_}) -> false;
+is_tc({_M,T}) when is_atom(T) -> true;
+is_tc(_) -> false.
+
+position(T, TCs) ->
+ position(T, TCs, 1).
+
+position(T, [T|_TCs], Pos) ->
+ Pos;
+position(T, [{_,T}|_TCs], Pos) ->
+ Pos;
+position({M,T}, [T|_TCs], Pos) when M /= group ->
+ Pos;
+position(T, [_|TCs], Pos) ->
+ position(T, TCs, Pos+1);
+position(_, [], Pos) ->
+ Pos.
+
+%%%-----------------------------------------------------------------
+
+delete_subs([{conf, _,_,_,_} = Conf | Confs], All) ->
+ All1 = delete_conf(Conf, All),
+ case is_sub(Conf, All1) of
+ true ->
+ delete_subs(Confs, All1);
+ false ->
+ delete_subs(Confs, All)
+ end;
+delete_subs([_Else | Confs], All) ->
+ delete_subs(Confs, All);
+delete_subs([], All) ->
+ All.
+
+delete_conf({conf,Props,_,_,_}, Confs) ->
+ Name = ?val(name, Props),
+ [Conf || Conf = {conf,Props0,_,_,_} <- Confs,
+ Name =/= ?val(name, Props0)].
+
+is_sub({conf,Props,_,_,_}=Conf, [{conf,_,_,Tests,_} | Confs]) ->
+ Name = ?val(name, Props),
+ case lists:any(fun({conf,Props0,_,_,_}) ->
+ case ?val(name, Props0) of
+ N when N == Name ->
+ true;
+ _ ->
+ false
+ end;
+ (_) ->
+ false
+ end, Tests) of
+ true ->
+ true;
+ false ->
+ is_sub(Conf, Tests) orelse is_sub(Conf, Confs)
+ end;
+
+is_sub(Conf, [_TC | Tests]) ->
+ is_sub(Conf, Tests);
+
+is_sub(_Conf, []) ->
+ false.
+
+
+cyclic_test(Mod, Name, Names) ->
+ case lists:member(Name, Names) of
+ true ->
+ E = "Cyclic reference to group "++atom_to_list(Name)++
+ " in "++atom_to_list(Mod)++":groups/0",
+ throw({error,list_to_atom(E)});
+ false ->
+ ok
+ end.
+
+expand(Mod, Name, Defs) ->
+ case lists:keysearch(Name, 1, Defs) of
+ {value,Def} ->
+ Def;
+ false ->
+ E = "Invalid group "++atom_to_list(Name)++
+ " in "++atom_to_list(Mod)++":groups/0",
+ throw({error,list_to_atom(E)})
+ end.
+
+make_all_conf(Dir, Mod, Props, TestSpec) ->
+ case code:is_loaded(Mod) of
+ false ->
+ code:load_abs(filename:join(Dir,atom_to_list(Mod)));
+ _ ->
+ ok
+ end,
+ make_all_conf(Mod, Props, TestSpec).
+
+make_all_conf(Mod, Props, TestSpec) ->
+ case catch apply(Mod, groups, []) of
+ {'EXIT',_} ->
+ exit({invalid_group_definition,Mod});
+ GroupDefs when is_list(GroupDefs) ->
+ case catch find_groups(Mod, all, TestSpec, GroupDefs) of
+ {error,_} = Error ->
+ %% this makes test_server call error_in_suite as first
+ %% (and only) test case so we can report Error properly
+ [{ct_framework,error_in_suite,[[Error]]}];
+ [] ->
+ exit({invalid_group_spec,Mod});
+ _ConfTests ->
+ make_conf(Mod, all, Props, TestSpec)
+ end
+ end.
+
+make_conf(Dir, Mod, Name, Props, TestSpec) ->
+ case code:is_loaded(Mod) of
+ false ->
+ code:load_abs(filename:join(Dir,atom_to_list(Mod)));
+ _ ->
+ ok
+ end,
+ make_conf(Mod, Name, Props, TestSpec).
+
+make_conf(Mod, Name, Props, TestSpec) ->
+ case code:is_loaded(Mod) of
+ false ->
+ code:load_file(Mod);
+ _ ->
+ 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 ->
+ ct_logs:log("TEST INFO", "init_per_group/2 and "
+ "end_per_group/2 missing for group "
+ "~p in ~p, using default.",
+ [Name,Mod]),
+ {{ct_framework,init_per_group},
+ {ct_framework,end_per_group},
+ [{suite,Mod}]}
+ end,
+ {conf,[{name,Name}|Props++ExtraProps],InitConf,TestSpec,EndConf}.
+
+%%%-----------------------------------------------------------------
+
+expand_groups([H | T], ConfTests, Mod) ->
+ [expand_groups(H, ConfTests, Mod) | expand_groups(T, ConfTests, Mod)];
+expand_groups([], _ConfTests, _Mod) ->
+ [];
+expand_groups({group,Name}, ConfTests, Mod) ->
+ expand_groups({group,Name,default,[]}, ConfTests, Mod);
+expand_groups({group,Name,default}, ConfTests, Mod) ->
+ expand_groups({group,Name,default,[]}, ConfTests, Mod);
+expand_groups({group,Name,ORProps}, ConfTests, Mod) when is_list(ORProps) ->
+ expand_groups({group,Name,ORProps,[]}, ConfTests, Mod);
+expand_groups({group,Name,ORProps,SubORSpec}, ConfTests, Mod) ->
+ FindConf =
+ fun(Conf = {conf,Props,Init,Ts,End}) ->
+ case ?val(name, Props) of
+ Name when ORProps == default ->
+ [Conf];
+ Name ->
+ Props1 = case ?val(suite, Props) of
+ undefined ->
+ ORProps;
+ SuiteName ->
+ [{suite,SuiteName}|ORProps]
+ end,
+ [{conf,[{name,Name}|Props1],Init,Ts,End}];
+ _ ->
+ []
+ end
+ end,
+ case lists:flatmap(FindConf, ConfTests) of
+ [] ->
+ throw({error,invalid_ref_msg(Name, Mod)});
+ Matching when SubORSpec == [] ->
+ Matching;
+ Matching ->
+ override_props(Matching, SubORSpec, Name,Mod)
+ end;
+expand_groups(SeqOrTC, _ConfTests, _Mod) ->
+ SeqOrTC.
+
+%% search deep for the matching conf test and modify it and any
+%% sub tests according to the override specification
+search_and_override([Conf = {conf,Props,Init,Tests,End}], ORSpec, Mod) ->
+ InsProps = fun(GrName, undefined, Ps) ->
+ [{name,GrName} | Ps];
+ (GrName, Suite, Ps) ->
+ [{name,GrName}, {suite,Suite} | Ps]
+ end,
+ Name = ?val(name, Props),
+ Suite = ?val(suite, Props),
+ case lists:keysearch(Name, 1, ORSpec) of
+ {value,{Name,default}} ->
+ [Conf];
+ {value,{Name,ORProps}} ->
+ [{conf,InsProps(Name,Suite,ORProps),Init,Tests,End}];
+ {value,{Name,default,[]}} ->
+ [Conf];
+ {value,{Name,default,SubORSpec}} ->
+ override_props([Conf], SubORSpec, Name,Mod);
+ {value,{Name,ORProps,SubORSpec}} ->
+ override_props([{conf,InsProps(Name,Suite,ORProps),
+ Init,Tests,End}], SubORSpec, Name,Mod);
+ _ ->
+ [{conf,Props,Init,search_and_override(Tests,ORSpec,Mod),End}]
+ end.
+
+%% Modify the Tests element according to the override specification
+override_props([{conf,Props,Init,Tests,End} | Confs], SubORSpec, Name,Mod) ->
+ {Subs,SubORSpec1} = override_sub_props(Tests, [], SubORSpec, Mod),
+ [{conf,Props,Init,Subs,End} | override_props(Confs, SubORSpec1, Name,Mod)];
+override_props([], [], _,_) ->
+ [];
+override_props([], SubORSpec, Name,Mod) ->
+ Es = [invalid_ref_msg(Name, element(1,Spec), Mod) || Spec <- SubORSpec],
+ throw({error,Es}).
+
+override_sub_props([], New, ORSpec, _) ->
+ {?rev(New),ORSpec};
+override_sub_props([T = {conf,Props,Init,Tests,End} | Ts],
+ New, ORSpec, Mod) ->
+ Name = ?val(name, Props),
+ Suite = ?val(suite, Props),
+ case lists:keysearch(Name, 1, ORSpec) of
+ {value,Spec} -> % group found in spec
+ Props1 =
+ case element(2, Spec) of
+ default -> Props;
+ ORProps when Suite == undefined -> [{name,Name} | ORProps];
+ ORProps -> [{name,Name}, {suite,Suite} | ORProps]
+ end,
+ case catch element(3, Spec) of
+ Undef when Undef == [] ; 'EXIT' == element(1, Undef) ->
+ override_sub_props(Ts, [{conf,Props1,Init,Tests,End} | New],
+ lists:keydelete(Name, 1, ORSpec), Mod);
+ SubORSpec when is_list(SubORSpec) ->
+ case override_sub_props(Tests, [], SubORSpec, Mod) of
+ {Subs,[]} ->
+ override_sub_props(Ts, [{conf,Props1,Init,
+ Subs,End} | New],
+ lists:keydelete(Name, 1, ORSpec),
+ Mod);
+ {_,NonEmptySpec} ->
+ Es = [invalid_ref_msg(Name, element(1, GrRef),
+ Mod) || GrRef <- NonEmptySpec],
+ throw({error,Es})
+ end;
+ BadGrSpec ->
+ throw({error,{invalid_form,BadGrSpec}})
+ end;
+ _ -> % not a group in spec
+ override_sub_props(Ts, [T | New], ORSpec, Mod)
+ end;
+override_sub_props([TC | Ts], New, ORSpec, Mod) ->
+ override_sub_props(Ts, [TC | New], ORSpec, Mod).
+
+invalid_ref_msg(Name, Mod) ->
+ E = "Invalid reference to group "++
+ atom_to_list(Name)++" in "++
+ atom_to_list(Mod)++":all/0",
+ list_to_atom(E).
+
+invalid_ref_msg(Name0, Name1, Mod) ->
+ E = "Invalid reference to group "++
+ atom_to_list(Name1)++" from "++atom_to_list(Name0)++
+ " in "++atom_to_list(Mod)++":all/0",
+ list_to_atom(E).
diff --git a/lib/common_test/src/ct_master.erl b/lib/common_test/src/ct_master.erl
index 99bec3ea09..f29eba605c 100644
--- a/lib/common_test/src/ct_master.erl
+++ b/lib/common_test/src/ct_master.erl
@@ -51,7 +51,7 @@
%%% {testcase,Cases} | {spec,TestSpecs} | {allow_user_terms,Bool} |
%%% {logdir,LogDir} | {event_handler,EventHandlers} |
%%% {silent_connections,Conns} | {cover,CoverSpecFile} |
-%%% {userconfig, UserCfgFiles}
+%%% {cover_stop,Bool} | {userconfig, UserCfgFiles}
%%% CfgFiles = string() | [string()]
%%% TestDirs = string() | [string()]
%%% Suites = atom() | [atom()]
diff --git a/lib/common_test/src/ct_master_logs.erl b/lib/common_test/src/ct_master_logs.erl
index d76288feef..84f175c0a9 100644
--- a/lib/common_test/src/ct_master_logs.erl
+++ b/lib/common_test/src/ct_master_logs.erl
@@ -204,7 +204,7 @@ open_ct_master_log(Dir) ->
{ok,Fd} = file:open(FullName,[write]),
io:put_chars(Fd,header("Common Test Master Log", {[],[1,2],[]})),
%% maybe add config info here later
- io:put_chars(config_table([])),
+ io:put_chars(Fd,config_table([])),
io:put_chars(Fd,
"<style>\n"
"div.ct_internal { background:lightgrey; color:black }\n"
diff --git a/lib/common_test/src/ct_netconfc.erl b/lib/common_test/src/ct_netconfc.erl
index 52fe9599ce..1ccbc86d8f 100644
--- a/lib/common_test/src/ct_netconfc.erl
+++ b/lib/common_test/src/ct_netconfc.erl
@@ -307,7 +307,7 @@
-type option() :: {ssh,host()} | {port,inet:port_number()} | {user,string()} |
{password,string()} | {user_dir,string()} |
{timeout,timeout()}.
--type host() :: inet:host_name() | inet:ip_address().
+-type host() :: inet:hostname() | inet:ip_address().
-type notification() :: {notification, xml_attributes(), notification_content()}.
-type notification_content() :: [event_time()|simple_xml()].
@@ -968,7 +968,7 @@ close_session(Client) ->
%% @end
%%----------------------------------------------------------------------
close_session(Client, Timeout) ->
- call(Client,{send_rpc_op, close_session, [], Timeout}).
+ call(Client,{send_rpc_op, close_session, [], Timeout}, true).
%%----------------------------------------------------------------------
@@ -1073,7 +1073,8 @@ handle_msg({get_event_streams=Op,Streams,Timeout}, From, State) ->
SimpleXml = encode_rpc_operation(get,[Filter]),
do_send_rpc(Op, SimpleXml, Timeout, From, State).
-handle_msg({ssh_cm, _CM, {data, _Ch, _Type, Data}}, State) ->
+handle_msg({ssh_cm, CM, {data, Ch, _Type, Data}}, State) ->
+ ssh_connection:adjust_window(CM,Ch,size(Data)),
handle_data(Data, State);
handle_msg({ssh_cm, _CM, _SshCloseMsg}, State) ->
%% _SshCloseMsg can probably be one of
@@ -1121,17 +1122,38 @@ close(Client) ->
%% Internal functions
%%----------------------------------------------------------------------
call(Client, Msg) ->
- call(Client, Msg, infinity).
-call(Client, Msg, Timeout) ->
+ call(Client, Msg, infinity, false).
+call(Client, Msg, Timeout) when is_integer(Timeout); Timeout==infinity ->
+ call(Client, Msg, Timeout, false);
+call(Client, Msg, WaitStop) when is_boolean(WaitStop) ->
+ call(Client, Msg, infinity, WaitStop).
+call(Client, Msg, Timeout, WaitStop) ->
case get_handle(Client) of
{ok,Pid} ->
case ct_gen_conn:call(Pid,Msg,Timeout) of
- {error,{process_down,Client,noproc}} ->
+ {error,{process_down,Pid,noproc}} ->
{error,no_such_client};
- {error,{process_down,Client,normal}} ->
+ {error,{process_down,Pid,normal}} when WaitStop ->
+ %% This will happen when server closes connection
+ %% before clien received rpc-reply on
+ %% close-session.
+ ok;
+ {error,{process_down,Pid,normal}} ->
{error,closed};
- {error,{process_down,Client,Reason}} ->
+ {error,{process_down,Pid,Reason}} ->
{error,{closed,Reason}};
+ Other when WaitStop ->
+ MRef = erlang:monitor(process,Pid),
+ receive
+ {'DOWN',MRef,process,Pid,Normal} when Normal==normal;
+ Normal==noproc ->
+ Other;
+ {'DOWN',MRef,process,Pid,Reason} ->
+ {error,{{closed,Reason},Other}}
+ after Timeout ->
+ erlang:demonitor(MRef, [flush]),
+ {error,{timeout,Other}}
+ end;
Other ->
Other
end;
@@ -1784,7 +1806,8 @@ get_tag([]) ->
%%% SSH stuff
ssh_receive_data() ->
receive
- {ssh_cm, _CM, {data, _Ch, _Type, Data}} ->
+ {ssh_cm, CM, {data, Ch, _Type, Data}} ->
+ ssh_connection:adjust_window(CM,Ch,size(Data)),
{ok, Data};
{ssh_cm, _CM, {Closed, _Ch}} = X when Closed == closed; Closed == eof ->
{error,X};
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index 4a6a3cdcac..eb05c90ba8 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -58,6 +58,7 @@
vts,
shell,
cover,
+ cover_stop,
coverspec,
step,
logdir,
@@ -245,6 +246,7 @@ script_start1(Parent, Args) ->
Vts = get_start_opt(vts, true, Args),
Shell = get_start_opt(shell, true, Args),
Cover = get_start_opt(cover, fun([CoverFile]) -> ?abs(CoverFile) end, Args),
+ CoverStop = get_start_opt(cover_stop, fun([CS]) -> list_to_atom(CS) end, Args),
LogDir = get_start_opt(logdir, fun([LogD]) -> LogD end, Args),
LogOpts = get_start_opt(logopts, fun(Os) -> [list_to_atom(O) || O <- Os] end,
[], Args),
@@ -329,7 +331,8 @@ script_start1(Parent, Args) ->
end,
StartOpts = #opts{label = Label, profile = Profile,
- vts = Vts, shell = Shell, cover = Cover,
+ vts = Vts, shell = Shell,
+ cover = Cover, cover_stop = CoverStop,
logdir = LogDir, logopts = LogOpts,
basic_html = BasicHtml,
verbosity = Verbosity,
@@ -416,6 +419,9 @@ script_start2(StartOpts = #opts{vts = undefined,
Cover =
choose_val(StartOpts#opts.cover,
SpecStartOpts#opts.cover),
+ CoverStop =
+ choose_val(StartOpts#opts.cover_stop,
+ SpecStartOpts#opts.cover_stop),
MultTT =
choose_val(StartOpts#opts.multiply_timetraps,
SpecStartOpts#opts.multiply_timetraps),
@@ -475,6 +481,7 @@ script_start2(StartOpts = #opts{vts = undefined,
profile = Profile,
testspecs = Specs,
cover = Cover,
+ cover_stop = CoverStop,
logdir = LogDir,
logopts = AllLogOpts,
basic_html = BasicHtml,
@@ -723,6 +730,7 @@ script_usage() ->
"\n\t[-silent_connections [ConnType1 ConnType2 .. ConnTypeN]]"
"\n\t[-stylesheet CSSFile]"
"\n\t[-cover CoverCfgFile]"
+ "\n\t[-cover_stop Bool]"
"\n\t[-event_handler EvHandler1 EvHandler2 .. EvHandlerN]"
"\n\t[-ct_hooks CTHook1 CTHook2 .. CTHookN]"
"\n\t[-include InclDir1 InclDir2 .. InclDirN]"
@@ -745,6 +753,7 @@ script_usage() ->
"\n\t[-silent_connections [ConnType1 ConnType2 .. ConnTypeN]]"
"\n\t[-stylesheet CSSFile]"
"\n\t[-cover CoverCfgFile]"
+ "\n\t[-cover_stop Bool]"
"\n\t[-event_handler EvHandler1 EvHandler2 .. EvHandlerN]"
"\n\t[-ct_hooks CTHook1 CTHook2 .. CTHookN]"
"\n\t[-include InclDir1 InclDir2 .. InclDirN]"
@@ -938,6 +947,7 @@ run_test2(StartOpts) ->
%% code coverage
Cover = get_start_opt(cover,
fun(CoverFile) -> ?abs(CoverFile) end, StartOpts),
+ CoverStop = get_start_opt(cover_stop, value, StartOpts),
%% timetrap manipulation
MultiplyTT = get_start_opt(multiply_timetraps, value, 1, StartOpts),
@@ -1000,7 +1010,8 @@ run_test2(StartOpts) ->
Step = get_start_opt(step, value, StartOpts),
Opts = #opts{label = Label, profile = Profile,
- cover = Cover, step = Step, logdir = LogDir,
+ cover = Cover, cover_stop = CoverStop,
+ step = Step, logdir = LogDir,
logopts = LogOpts, basic_html = BasicHtml,
config = CfgFiles,
verbosity = Verbosity,
@@ -1063,6 +1074,8 @@ run_spec_file(Relaxed,
AllConfig = merge_vals([CfgFiles, SpecOpts#opts.config]),
Cover = choose_val(Opts#opts.cover,
SpecOpts#opts.cover),
+ CoverStop = choose_val(Opts#opts.cover_stop,
+ SpecOpts#opts.cover_stop),
MultTT = choose_val(Opts#opts.multiply_timetraps,
SpecOpts#opts.multiply_timetraps),
ScaleTT = choose_val(Opts#opts.scale_timetraps,
@@ -1103,6 +1116,7 @@ run_spec_file(Relaxed,
Opts1 = Opts#opts{label = Label,
profile = Profile,
cover = Cover,
+ cover_stop = CoverStop,
logdir = which(logdir, LogDir),
logopts = AllLogOpts,
stylesheet = Stylesheet,
@@ -1272,7 +1286,8 @@ run_dir(Opts = #opts{logdir = LogDir,
reformat_result(catch do_run(tests(Dir2, Mod),
[], Opts1, StartOpts));
_ ->
- reformat_result(catch do_run(tests(Dir2, Mod, GsAndCs),
+ reformat_result(catch do_run(tests(Dir2, Mod,
+ GsAndCs),
[], Opts1, StartOpts))
end;
@@ -1281,7 +1296,8 @@ run_dir(Opts = #opts{logdir = LogDir,
[_,_|_] when GsAndCs /= [] ->
exit({error,multiple_suites_and_cases});
[{Dir2,Mod}] when GsAndCs /= [] ->
- reformat_result(catch do_run(tests(Dir2, Mod, GsAndCs),
+ reformat_result(catch do_run(tests(Dir2, Mod,
+ GsAndCs),
[], Opts1, StartOpts));
DirMods ->
reformat_result(catch do_run(tests(DirMods),
@@ -1374,6 +1390,7 @@ get_data_for_node(#testspec{label = Labels,
verbosity = VLvls,
silent_connections = SilentConnsList,
cover = CoverFs,
+ cover_stop = CoverStops,
config = Cfgs,
userconfig = UsrCfgs,
event_handler = EvHs,
@@ -1405,6 +1422,7 @@ get_data_for_node(#testspec{label = Labels,
SCs -> SCs
end,
Cover = proplists:get_value(Node, CoverFs),
+ CoverStop = proplists:get_value(Node, CoverStops),
MT = proplists:get_value(Node, MTs),
ST = proplists:get_value(Node, STs),
CreatePrivDir = proplists:get_value(Node, PDs),
@@ -1423,6 +1441,7 @@ get_data_for_node(#testspec{label = Labels,
verbosity = Verbosity,
silent_connections = SilentConns,
cover = Cover,
+ cover_stop = CoverStop,
config = ConfigFiles,
event_handlers = EvHandlers,
ct_hooks = FiltCTHooks,
@@ -1536,17 +1555,36 @@ groups_and_cases(Gs, Cs) when ((Gs == undefined) or (Gs == [])) and
((Cs == undefined) or (Cs == [])) ->
[];
groups_and_cases(Gs, Cs) when Gs == undefined ; Gs == [] ->
- [ensure_atom(C) || C <- listify(Cs)];
-groups_and_cases(Gs, Cs) when Cs == undefined ; Cs == [] ->
- [{ensure_atom(G),all} || G <- listify(Gs)];
-groups_and_cases(G, Cs) when is_atom(G) ->
- [{G,[ensure_atom(C) || C <- listify(Cs)]}];
-groups_and_cases([G], Cs) ->
- [{ensure_atom(G),[ensure_atom(C) || C <- listify(Cs)]}];
-groups_and_cases([_,_|_] , Cs) when Cs =/= [] ->
- {error,multiple_groups_and_cases};
-groups_and_cases(_Gs, _Cs) ->
- {error,incorrect_group_or_case_option}.
+ if (Cs == all) or (Cs == [all]) or (Cs == ["all"]) -> all;
+ true -> [ensure_atom(C) || C <- listify(Cs)]
+ end;
+groups_and_cases(GOrGs, Cs) when (is_atom(GOrGs) orelse
+ (is_list(GOrGs) andalso
+ (is_atom(hd(GOrGs)) orelse
+ (is_list(hd(GOrGs)) andalso
+ is_atom(hd(hd(GOrGs))))))) ->
+ if (Cs == undefined) or (Cs == []) or
+ (Cs == all) or (Cs == [all]) or (Cs == ["all"]) ->
+ [{GOrGs,all}];
+ true ->
+ [{GOrGs,[ensure_atom(C) || C <- listify(Cs)]}]
+ end;
+groups_and_cases(Gs, Cs) when is_integer(hd(hd(Gs))) ->
+ %% if list of strings, this comes from 'ct_run -group G1 G2 ...' and
+ %% we need to parse the strings
+ Gs1 =
+ if (Gs == [all]) or (Gs == ["all"]) ->
+ all;
+ true ->
+ lists:map(fun(G) ->
+ {ok,Ts,_} = erl_scan:string(G++"."),
+ {ok,Term} = erl_parse:parse_term(Ts),
+ Term
+ end, Gs)
+ end,
+ groups_and_cases(Gs1, Cs);
+groups_and_cases(Gs, Cs) ->
+ {error,{incorrect_group_or_case_option,Gs,Cs}}.
tests(TestDir, Suites, []) when is_list(TestDir), is_integer(hd(TestDir)) ->
[{?testdir(TestDir,Suites),ensure_atom(Suites),all}];
@@ -1576,14 +1614,7 @@ do_run(Tests, Misc, LogDir, LogOpts) when is_list(Misc),
StepOpts ->
#opts{step = StepOpts}
end,
- Opts1 =
- case proplists:get_value(cover, Misc) of
- undefined ->
- Opts;
- CoverFile ->
- Opts#opts{cover = CoverFile}
- end,
- do_run(Tests, [], Opts1#opts{logdir = LogDir}, []);
+ do_run(Tests, [], Opts#opts{logdir = LogDir}, []);
do_run(Tests, Skip, Opts, Args) when is_record(Opts, opts) ->
#opts{label = Label, profile = Profile, cover = Cover,
@@ -1617,7 +1648,13 @@ do_run(Tests, Skip, Opts, Args) when is_record(Opts, opts) ->
{error,Reason} ->
exit({error,Reason});
CoverSpec ->
- Opts#opts{coverspec = CoverSpec}
+ CoverStop =
+ case Opts#opts.cover_stop of
+ undefined -> true;
+ Stop -> Stop
+ end,
+ Opts#opts{coverspec = CoverSpec,
+ cover_stop = CoverStop}
end
end,
%% This env variable is used by test_server to determine
@@ -1687,11 +1724,15 @@ compile_and_run(Tests, Skip, Opts, Args) ->
SavedErrors = save_make_errors(SuiteMakeErrors),
ct_repeat:log_loop_info(Args),
- {Tests1,Skip1} = final_tests(Tests,Skip,SavedErrors),
-
- ReleaseSh = proplists:get_value(release_shell, Args),
- ct_util:set_testdata({release_shell,ReleaseSh}),
- possibly_spawn(ReleaseSh == true, Tests1, Skip1, Opts);
+ try final_tests(Tests,Skip,SavedErrors) of
+ {Tests1,Skip1} ->
+ ReleaseSh = proplists:get_value(release_shell, Args),
+ ct_util:set_testdata({release_shell,ReleaseSh}),
+ possibly_spawn(ReleaseSh == true, Tests1, Skip1, Opts)
+ catch
+ _:BadFormat ->
+ {error,BadFormat}
+ end;
false ->
io:nl(),
ct_util:stop(clean),
@@ -1961,22 +2002,21 @@ final_tests1([{TestDir,Suite,GrsOrCs}|Tests], Final, Skip, Bad) when
%% for now, only flat group defs are allowed as
%% start options and test spec terms
fun({all,all}) ->
- ct_framework:make_all_conf(TestDir,
- Suite, []);
+ [ct_groups:make_conf(TestDir, Suite, all, [], all)];
({skipped,Group,TCs}) ->
- [ct_framework:make_conf(TestDir, Suite,
- Group, [skipped], TCs)];
- ({GrSpec = {Group,_},TCs}) ->
+ [ct_groups:make_conf(TestDir, Suite,
+ Group, [skipped], TCs)];
+ ({GrSpec = {GroupName,_},TCs}) ->
Props = [{override,GrSpec}],
- [ct_framework:make_conf(TestDir, Suite,
- Group, Props, TCs)];
- ({GrSpec = {Group,_,_},TCs}) ->
+ [ct_groups:make_conf(TestDir, Suite,
+ GroupName, Props, TCs)];
+ ({GrSpec = {GroupName,_,_},TCs}) ->
Props = [{override,GrSpec}],
- [ct_framework:make_conf(TestDir, Suite,
- Group, Props, TCs)];
- ({Group,TCs}) ->
- [ct_framework:make_conf(TestDir, Suite,
- Group, [], TCs)];
+ [ct_groups:make_conf(TestDir, Suite,
+ GroupName, Props, TCs)];
+ ({GroupOrGroups,TCs}) ->
+ [ct_groups:make_conf(TestDir, Suite,
+ GroupOrGroups, [], TCs)];
(TC) ->
[TC]
end, GrsOrCs),
@@ -1988,12 +2028,12 @@ final_tests1([], Final, Skip, _Bad) ->
{lists:reverse(Final),Skip}.
final_skip([{TestDir,Suite,{all,all},Reason}|Skips], Final) ->
- SkipConf = ct_framework:make_conf(TestDir, Suite, all, [], all),
+ SkipConf = ct_groups:make_conf(TestDir, Suite, all, [], all),
Skip = {TestDir,Suite,SkipConf,Reason},
final_skip(Skips, [Skip|Final]);
final_skip([{TestDir,Suite,{Group,TCs},Reason}|Skips], Final) ->
- Conf = ct_framework:make_conf(TestDir, Suite, Group, [], TCs),
+ Conf = ct_groups:make_conf(TestDir, Suite, Group, [], TCs),
Skip = {TestDir,Suite,Conf,Reason},
final_skip(Skips, [Skip|Final]);
@@ -2120,7 +2160,8 @@ do_run_test(Tests, Skip, Opts) ->
%% tell test_server which modules should be cover compiled
%% note that actual compilation is done when tests start
test_server_ctrl:cover(CovApp, CovFile, CovExcl, CovIncl,
- CovCross, CovExport, CovLevel),
+ CovCross, CovExport, CovLevel,
+ Opts#opts.cover_stop),
%% save cover data (used e.g. to add nodes dynamically)
ct_util:set_testdata({cover,CovData}),
%% start cover on specified nodes
@@ -2265,9 +2306,11 @@ add_jobs([{TestDir,all,_}|Tests], Skip, Opts, CleanUp) ->
wait_for_idle(),
add_jobs(Tests, Skip, Opts, CleanUp)
end;
-add_jobs([{TestDir,[Suite],all}|Tests], Skip, Opts, CleanUp) when is_atom(Suite) ->
+add_jobs([{TestDir,[Suite],all}|Tests], Skip,
+ Opts, CleanUp) when is_atom(Suite) ->
add_jobs([{TestDir,Suite,all}|Tests], Skip, Opts, CleanUp);
-add_jobs([{TestDir,Suites,all}|Tests], Skip, Opts, CleanUp) when is_list(Suites) ->
+add_jobs([{TestDir,Suites,all}|Tests], Skip,
+ Opts, CleanUp) when is_list(Suites) ->
Name = get_name(TestDir) ++ ".suites",
case catch test_server_ctrl:add_module_with_skip(Name, Suites,
skiplist(TestDir,Skip)) of
@@ -2282,7 +2325,8 @@ add_jobs([{TestDir,Suite,all}|Tests], Skip, Opts, CleanUp) ->
ok ->
Name = get_name(TestDir) ++ "." ++ atom_to_list(Suite),
case catch test_server_ctrl:add_module_with_skip(Name, [Suite],
- skiplist(TestDir,Skip)) of
+ skiplist(TestDir,
+ Skip)) of
{'EXIT',_} ->
CleanUp;
_ ->
@@ -2305,15 +2349,24 @@ add_jobs([{TestDir,Suite,Confs}|Tests], Skip, Opts, CleanUp) when
GrTestName =
case Confs of
[Conf] ->
- "." ++ atom_to_list(Group(Conf)) ++ TCTestName(TestCases(Conf));
+ case Group(Conf) of
+ GrName when is_atom(GrName) ->
+ "." ++ atom_to_list(GrName) ++
+ TCTestName(TestCases(Conf));
+ _ ->
+ ".groups" ++ TCTestName(TestCases(Conf))
+ end;
_ ->
".groups"
end,
TestName = get_name(TestDir) ++ "." ++ atom_to_list(Suite) ++ GrTestName,
case maybe_interpret(Suite, init_per_group, Opts) of
ok ->
- case catch test_server_ctrl:add_conf_with_skip(TestName, Suite, Confs,
- skiplist(TestDir,Skip)) of
+ case catch test_server_ctrl:add_conf_with_skip(TestName,
+ Suite,
+ Confs,
+ skiplist(TestDir,
+ Skip)) of
{'EXIT',_} ->
CleanUp;
_ ->
@@ -2325,18 +2378,21 @@ add_jobs([{TestDir,Suite,Confs}|Tests], Skip, Opts, CleanUp) when
end;
%% test case
-add_jobs([{TestDir,Suite,[Case]}|Tests], Skip, Opts, CleanUp) when is_atom(Case) ->
+add_jobs([{TestDir,Suite,[Case]}|Tests],
+ Skip, Opts, CleanUp) when is_atom(Case) ->
add_jobs([{TestDir,Suite,Case}|Tests], Skip, Opts, CleanUp);
-add_jobs([{TestDir,Suite,Cases}|Tests], Skip, Opts, CleanUp) when is_list(Cases) ->
+add_jobs([{TestDir,Suite,Cases}|Tests],
+ Skip, Opts, CleanUp) when is_list(Cases) ->
Cases1 = lists:map(fun({GroupName,_}) when is_atom(GroupName) -> GroupName;
(Case) -> Case
end, Cases),
case maybe_interpret(Suite, Cases1, Opts) of
ok ->
- Name = get_name(TestDir) ++ "." ++ atom_to_list(Suite) ++ ".cases",
+ Name = get_name(TestDir) ++ "." ++ atom_to_list(Suite) ++ ".cases",
case catch test_server_ctrl:add_cases_with_skip(Name, Suite, Cases1,
- skiplist(TestDir,Skip)) of
+ skiplist(TestDir,
+ Skip)) of
{'EXIT',_} ->
CleanUp;
_ ->
@@ -2352,7 +2408,8 @@ add_jobs([{TestDir,Suite,Case}|Tests], Skip, Opts, CleanUp) when is_atom(Case) -
Name = get_name(TestDir) ++ "." ++ atom_to_list(Suite) ++ "." ++
atom_to_list(Case),
case catch test_server_ctrl:add_case_with_skip(Name, Suite, Case,
- skiplist(TestDir,Skip)) of
+ skiplist(TestDir,
+ Skip)) of
{'EXIT',_} ->
CleanUp;
_ ->
@@ -2387,7 +2444,8 @@ skiplist(Dir, [{Dir,all,Cmt}|Skip]) ->
%% we need to turn 'all' into list of modules since
%% test_server doesn't do skips on Dir level
Ss = filelib:wildcard(filename:join(Dir, "*_SUITE.beam")),
- [{list_to_atom(filename:basename(S,".beam")),Cmt} || S <- Ss] ++ skiplist(Dir,Skip);
+ [{list_to_atom(filename:basename(S,".beam")),Cmt} || S <- Ss] ++
+ skiplist(Dir,Skip);
skiplist(Dir, [{Dir,S,Cmt}|Skip]) ->
[{S,Cmt} | skiplist(Dir, Skip)];
skiplist(Dir, [{Dir,S,C,Cmt}|Skip]) ->
@@ -2447,8 +2505,10 @@ run_make(Targets, TestDir0, Mod, UserInclude) ->
FileTest = fun(F, suites) -> is_suite(F);
(F, helpmods) -> not is_suite(F)
end,
- Files = lists:flatmap(fun({F,out_of_date}) ->
- case FileTest(F, Targets) of
+ Files =
+ lists:flatmap(fun({F,out_of_date}) ->
+ case FileTest(F,
+ Targets) of
true -> [F];
false -> []
end;
@@ -2584,6 +2644,9 @@ merge_arguments([LogDir={logdir,_}|Args], Merged) ->
merge_arguments([CoverFile={cover,_}|Args], Merged) ->
merge_arguments(Args, handle_arg(replace, CoverFile, Merged));
+merge_arguments([CoverStop={cover_stop,_}|Args], Merged) ->
+ merge_arguments(Args, handle_arg(replace, CoverStop, Merged));
+
merge_arguments([{'case',TC}|Args], Merged) ->
merge_arguments(Args, handle_arg(merge, {testcase,TC}, Merged));
@@ -2792,11 +2855,14 @@ opts2args(EnvStartOpts) ->
lists:flatmap(fun({exit_status,ExitStatusOpt}) when is_atom(ExitStatusOpt) ->
[{exit_status,[atom_to_list(ExitStatusOpt)]}];
({halt_with,{HaltM,HaltF}}) ->
- [{halt_with,[atom_to_list(HaltM),atom_to_list(HaltF)]}];
+ [{halt_with,[atom_to_list(HaltM),
+ atom_to_list(HaltF)]}];
({interactive_mode,true}) ->
[{shell,[]}];
- ({config,CfgFiles}) ->
- [{ct_config,[CfgFiles]}];
+ ({config,CfgFile}) when is_integer(hd(CfgFile)) ->
+ [{ct_config,[CfgFile]}];
+ ({config,CfgFiles}) when is_list(hd(CfgFiles)) ->
+ [{ct_config,CfgFiles}];
({userconfig,{CBM,CfgStr=[X|_]}}) when is_integer(X) ->
[{userconfig,[atom_to_list(CBM),CfgStr]}];
({userconfig,{CBM,CfgStrs}}) when is_list(CfgStrs) ->
@@ -2814,6 +2880,12 @@ opts2args(EnvStartOpts) ->
end, UserCfg),
[_LastAnd|StrsR] = lists:reverse(lists:flatten(Strs)),
[{userconfig,lists:reverse(StrsR)}];
+ ({group,G}) when is_atom(G) ->
+ [{group,[atom_to_list(G)]}];
+ ({group,Gs}) when is_list(Gs) ->
+ LOfGStrs = [lists:flatten(io_lib:format("~w",[G])) ||
+ G <- Gs],
+ [{group,LOfGStrs}];
({testcase,Case}) when is_atom(Case) ->
[{'case',[atom_to_list(Case)]}];
({testcase,Cases}) ->
diff --git a/lib/common_test/src/ct_slave.erl b/lib/common_test/src/ct_slave.erl
index aa3413fa89..1fd8c04f8b 100644
--- a/lib/common_test/src/ct_slave.erl
+++ b/lib/common_test/src/ct_slave.erl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -37,7 +37,7 @@
-record(options, {username, password, boot_timeout, init_timeout,
startup_timeout, startup_functions, monitor_master,
- kill_if_fail, erl_flags}).
+ kill_if_fail, erl_flags, env}).
%%%-----------------------------------------------------------------
%%% @spec start(Node) -> Result
@@ -85,7 +85,8 @@ start(Host, Node) ->
%%% {startup_functions, StartupFunctions} |
%%% {monitor_master, Monitor} |
%%% {kill_if_fail, KillIfFail} |
-%%% {erl_flags, ErlangFlags}
+%%% {erl_flags, ErlangFlags} |
+%%% {env, [{EnvVar,Value}]}
%%% Username = string()
%%% Password = string()
%%% BootTimeout = integer()
@@ -99,6 +100,8 @@ start(Host, Node) ->
%%% Monitor = bool()
%%% KillIfFail = bool()
%%% ErlangFlags = string()
+%%% EnvVar = string()
+%%% Value = string()
%%% Result = {ok, NodeName} | {error, already_started, NodeName} |
%%% {error, started_not_connected, NodeName} |
%%% {error, boot_timeout, NodeName} |
@@ -152,6 +155,9 @@ start(Host, Node) ->
%%% <p>Option <code>erlang_flags</code> specifies, which flags will be added
%%% to the parameters of the <code>erl</code> executable.</p>
%%%
+%%% <p>Option <code>env</code> specifies a list of environment variables
+%%% that will extended the environment.</p>
+%%%
%%% <p>Special return values are:
%%% <list>
%%% <item><code>{error, already_started, NodeName}</code> - if the node with
@@ -233,10 +239,12 @@ fetch_options(Options) ->
Monitor = get_option_value(monitor_master, Options, false),
KillIfFail = get_option_value(kill_if_fail, Options, true),
ErlFlags = get_option_value(erl_flags, Options, []),
+ EnvVars = get_option_value(env, Options, []),
#options{username=UserName, password=Password,
boot_timeout=BootTimeout, init_timeout=InitTimeout,
startup_timeout=StartupTimeout, startup_functions=StartupFunctions,
- monitor_master=Monitor, kill_if_fail=KillIfFail, erl_flags=ErlFlags}.
+ monitor_master=Monitor, kill_if_fail=KillIfFail,
+ erl_flags=ErlFlags, env=EnvVars}.
% send a message when slave node is started
% @hidden
@@ -306,11 +314,19 @@ do_start(Host, Node, Options) ->
true->
spawn_remote_node(Host, Node, Options)
end,
+
BootTimeout = Options#options.boot_timeout,
InitTimeout = Options#options.init_timeout,
StartupTimeout = Options#options.startup_timeout,
Result = case wait_for_node_alive(ENode, BootTimeout) of
pong->
+ case test_server:is_cover() of
+ true ->
+ MainCoverNode = cover:get_main_node(),
+ rpc:call(MainCoverNode,cover,start,[ENode]);
+ false ->
+ ok
+ end,
call_functions(ENode, Functions2),
receive
{node_started, ENode}->
@@ -365,9 +381,9 @@ get_cmd(Node, Flags) ->
% spawn node locally
spawn_local_node(Node, Options) ->
- ErlFlags = Options#options.erl_flags,
+ #options{env=Env,erl_flags=ErlFlags} = Options,
Cmd = get_cmd(Node, ErlFlags),
- open_port({spawn, Cmd}, [stream]).
+ open_port({spawn, Cmd}, [stream,{env,Env}]).
% start crypto and ssh if not yet started
check_for_ssh_running() ->
@@ -386,9 +402,10 @@ check_for_ssh_running() ->
% spawn node remotely
spawn_remote_node(Host, Node, Options) ->
- Username = Options#options.username,
- Password = Options#options.password,
- ErlFlags = Options#options.erl_flags,
+ #options{username=Username,
+ password=Password,
+ erl_flags=ErlFlags,
+ env=Env} = Options,
SSHOptions = case {Username, Password} of
{[], []}->
[];
@@ -400,8 +417,17 @@ spawn_remote_node(Host, Node, Options) ->
check_for_ssh_running(),
{ok, SSHConnRef} = ssh:connect(atom_to_list(Host), 22, SSHOptions),
{ok, SSHChannelId} = ssh_connection:session_channel(SSHConnRef, infinity),
+ ssh_setenv(SSHConnRef, SSHChannelId, Env),
ssh_connection:exec(SSHConnRef, SSHChannelId, get_cmd(Node, ErlFlags), infinity).
+
+ssh_setenv(SSHConnRef, SSHChannelId, [{Var, Value} | Vars])
+ when is_list(Var), is_list(Value) ->
+ success = ssh_connection:setenv(SSHConnRef, SSHChannelId,
+ Var, Value, infinity),
+ ssh_setenv(SSHConnRef, SSHChannelId, Vars);
+ssh_setenv(_SSHConnRef, _SSHChannelId, []) -> ok.
+
% call functions on a remote Erlang node
call_functions(_Node, []) ->
ok;
@@ -423,8 +449,29 @@ wait_for_node_alive(Node, N) ->
% call init:stop on a remote node
do_stop(ENode) ->
+ {Cover,MainCoverNode} =
+ case test_server:is_cover() of
+ true ->
+ Main = cover:get_main_node(),
+ rpc:call(Main,cover,flush,[ENode]),
+ {true,Main};
+ false ->
+ {false,undefined}
+ end,
spawn(ENode, init, stop, []),
- wait_for_node_dead(ENode, 5).
+ case wait_for_node_dead(ENode, 5) of
+ {ok,ENode} ->
+ if Cover ->
+ %% To avoid that cover is started again if a node
+ %% with the same name is started later.
+ rpc:call(MainCoverNode,cover,stop,[ENode]);
+ true ->
+ ok
+ end,
+ {ok,ENode};
+ Error ->
+ Error
+ end.
% wait N seconds until node is disconnected
wait_for_node_dead(Node, 0) ->
diff --git a/lib/common_test/src/ct_testspec.erl b/lib/common_test/src/ct_testspec.erl
index a8b67d0329..202d8f9373 100644
--- a/lib/common_test/src/ct_testspec.erl
+++ b/lib/common_test/src/ct_testspec.erl
@@ -903,6 +903,8 @@ handle_data(logdir,Node,Dir,Spec) ->
[{Node,ref2dir(Dir,Spec)}];
handle_data(cover,Node,File,Spec) ->
[{Node,get_absfile(File,Spec)}];
+handle_data(cover_stop,Node,Stop,_Spec) ->
+ [{Node,Stop}];
handle_data(include,Node,Dirs=[D|_],Spec) when is_list(D) ->
[{Node,ref2dir(Dir,Spec)} || Dir <- Dirs];
handle_data(include,Node,Dir=[Ch|_],Spec) when is_integer(Ch) ->
@@ -1026,20 +1028,24 @@ insert_groups(Node,Dir,Suite,Group,Cases,Tests,MergeTests)
insert_groups(Node,Dir,Suite,[Group],Cases,Tests,MergeTests);
insert_groups(Node,Dir,Suite,Groups,Cases,Tests,false) when
((Cases == all) or is_list(Cases)) and is_list(Groups) ->
- Groups1 = [{Gr,Cases} || Gr <- Groups],
+ Groups1 = [if is_list(Gr) -> % preserve group path
+ {[Gr],Cases};
+ true ->
+ {Gr,Cases} end || Gr <- Groups],
append({{Node,Dir},[{Suite,Groups1}]},Tests);
insert_groups(Node,Dir,Suite,Groups,Cases,Tests,true) when
((Cases == all) or is_list(Cases)) and is_list(Groups) ->
+ Groups1 = [if is_list(Gr) -> % preserve group path
+ {[Gr],Cases};
+ true ->
+ {Gr,Cases} end || Gr <- Groups],
case lists:keysearch({Node,Dir},1,Tests) of
{value,{{Node,Dir},[{all,_}]}} ->
Tests;
{value,{{Node,Dir},Suites0}} ->
- Suites1 = insert_groups1(Suite,
- [{Gr,Cases} || Gr <- Groups],
- Suites0),
+ Suites1 = insert_groups1(Suite,Groups1,Suites0),
insert_in_order({{Node,Dir},Suites1},Tests);
false ->
- Groups1 = [{Gr,Cases} || Gr <- Groups],
insert_in_order({{Node,Dir},[{Suite,Groups1}]},Tests)
end;
insert_groups(Node,Dir,Suite,Groups,Case,Tests, MergeTests)
@@ -1062,13 +1068,13 @@ insert_groups1(Suite,Groups,Suites0) ->
insert_groups2(_Groups,all) ->
all;
-insert_groups2([Group={GrName,Cases}|Groups],GrAndCases) ->
- case lists:keysearch(GrName,1,GrAndCases) of
- {value,{GrName,all}} ->
+insert_groups2([Group={Gr,Cases}|Groups],GrAndCases) ->
+ case lists:keysearch(Gr,1,GrAndCases) of
+ {value,{Gr,all}} ->
GrAndCases;
- {value,{GrName,Cases0}} ->
+ {value,{Gr,Cases0}} ->
Cases1 = insert_in_order(Cases,Cases0),
- insert_groups2(Groups,insert_in_order({GrName,Cases1},GrAndCases));
+ insert_groups2(Groups,insert_in_order({Gr,Cases1},GrAndCases));
false ->
insert_groups2(Groups,insert_in_order(Group,GrAndCases))
end;
@@ -1258,6 +1264,8 @@ valid_terms() ->
{node,3},
{cover,2},
{cover,3},
+ {cover_stop,2},
+ {cover_stop,3},
{config,2},
{config,3},
{config,4},
diff --git a/lib/common_test/src/ct_util.hrl b/lib/common_test/src/ct_util.hrl
index 196b5e46d0..c9c6514fa4 100644
--- a/lib/common_test/src/ct_util.hrl
+++ b/lib/common_test/src/ct_util.hrl
@@ -38,6 +38,7 @@
verbosity=[],
silent_connections=[],
cover=[],
+ cover_stop=[],
config=[],
userconfig=[],
event_handler=[],
diff --git a/lib/common_test/src/cth_conn_log.erl b/lib/common_test/src/cth_conn_log.erl
index 3af89db3a5..255f3ec78a 100644
--- a/lib/common_test/src/cth_conn_log.erl
+++ b/lib/common_test/src/cth_conn_log.erl
@@ -58,7 +58,7 @@
-spec init(Id, HookOpts) -> Result when
Id :: term(),
- HookOpts :: ct:hook_options(),
+ HookOpts :: ct_netconfc:hook_options(),
Result :: {ok,[{ct_netconfc:conn_mod(),
{ct_netconfc:log_type(),[ct_netconfc:key_or_name()]}}]}.
init(_Id, HookOpts) ->
diff --git a/lib/common_test/src/cth_log_redirect.erl b/lib/common_test/src/cth_log_redirect.erl
index 77f57c6195..78ae70f37e 100644
--- a/lib/common_test/src/cth_log_redirect.erl
+++ b/lib/common_test/src/cth_log_redirect.erl
@@ -54,7 +54,7 @@ post_init_per_group(_Group, _Config, Result, State) ->
post_end_per_testcase(_TC, _Config, Result, State) ->
%% Make sure that the event queue is flushed
%% before ending this test case.
- gen_event:call(error_logger, ?MODULE, flush),
+ gen_event:call(error_logger, ?MODULE, flush, 300000),
{Result, State}.
pre_end_per_group(Group, Config, {ct_log, Group}) ->
diff --git a/lib/common_test/src/cth_surefire.erl b/lib/common_test/src/cth_surefire.erl
index 76b0f0b5ea..e6eaad8d48 100644
--- a/lib/common_test/src/cth_surefire.erl
+++ b/lib/common_test/src/cth_surefire.erl
@@ -1,3 +1,22 @@
+%%--------------------------------------------------------------------
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%--------------------------------------------------------------------
+
%%% @doc Common Test Framework functions handling test specifications.
%%%
%%% <p>This module creates a junit report of the test run if plugged in
@@ -27,18 +46,28 @@
-export([terminate/1]).
-record(state, { filepath, axis, properties, package, hostname,
- curr_suite, curr_suite_ts, curr_group = [], curr_tc,
- curr_log_dir, timer, tc_log,
+ curr_suite, curr_suite_ts, curr_group = [],
+ curr_log_dir, timer, tc_log, url_base,
test_cases = [],
test_suites = [] }).
--record(testcase, { log, group, classname, name, time, failure, timestamp }).
--record(testsuite, { errors, failures, hostname, name, tests,
+-record(testcase, { log, url, group, classname, name, time, result, timestamp }).
+-record(testsuite, { errors, failures, skipped, hostname, name, tests,
time, timestamp, id, package,
- properties, testcases }).
+ properties, testcases, log, url }).
+
+-define(default_report,"junit_report.xml").
+-define(suite_log,"suite.log.html").
+
+%% Number of dirs from log root to testcase log file.
+%% ct_run.<node>.<timestamp>/<test_name>/run.<timestamp>/<tc_log>.html
+-define(log_depth,3).
id(Opts) ->
- filename:absname(proplists:get_value(path, Opts, "junit_report.xml")).
+ case proplists:get_value(path, Opts) of
+ undefined -> ?default_report;
+ Path -> filename:absname(Path)
+ end.
init(Path, Opts) ->
{ok, Host} = inet:gethostname(),
@@ -47,10 +76,24 @@ init(Path, Opts) ->
package = proplists:get_value(package,Opts),
axis = proplists:get_value(axis,Opts,[]),
properties = proplists:get_value(properties,Opts,[]),
+ url_base = proplists:get_value(url_base,Opts),
timer = now() }.
pre_init_per_suite(Suite,Config,#state{ test_cases = [] } = State) ->
- {Config, init_tc(State#state{ curr_suite = Suite, curr_suite_ts = now() },
+ TcLog = proplists:get_value(tc_logfile,Config),
+ CurrLogDir = filename:dirname(TcLog),
+ Path =
+ case State#state.filepath of
+ ?default_report ->
+ RootDir = get_test_root(TcLog),
+ filename:join(RootDir,?default_report);
+ P ->
+ P
+ end,
+ {Config, init_tc(State#state{ filepath = Path,
+ curr_suite = Suite,
+ curr_suite_ts = now(),
+ curr_log_dir = CurrLogDir},
Config) };
pre_init_per_suite(Suite,Config,State) ->
%% Have to close the previous suite
@@ -59,7 +102,8 @@ pre_init_per_suite(Suite,Config,State) ->
post_init_per_suite(_Suite,Config, Result, State) ->
{Result, end_tc(init_per_suite,Config,Result,State)}.
-pre_end_per_suite(_Suite,Config,State) -> {Config, init_tc(State, Config)}.
+pre_end_per_suite(_Suite,Config,State) ->
+ {Config, init_tc(State, Config)}.
post_end_per_suite(_Suite,Config,Result,State) ->
{Result, end_tc(end_per_suite,Config,Result,State)}.
@@ -71,13 +115,15 @@ pre_init_per_group(Group,Config,State) ->
post_init_per_group(_Group,Config,Result,State) ->
{Result, end_tc(init_per_group,Config,Result,State)}.
-pre_end_per_group(_Group,Config,State) -> {Config, init_tc(State, Config)}.
+pre_end_per_group(_Group,Config,State) ->
+ {Config, init_tc(State, Config)}.
post_end_per_group(_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) -> {Config, init_tc(State, Config)}.
+pre_init_per_testcase(_TC,Config,State) ->
+ {Config, init_tc(State, Config)}.
post_end_per_testcase(TC,Config,Result,State) ->
{Result, end_tc(TC,Config, Result,State)}.
@@ -88,11 +134,19 @@ on_tc_fail(_TC, Res, State) ->
TCs = State#state.test_cases,
TC = hd(TCs),
NewTC = TC#testcase{
- failure =
+ result =
{fail,lists:flatten(io_lib:format("~p",[Res]))} },
State#state{ test_cases = [NewTC | tl(TCs)]}.
-on_tc_skip(Tc,{Type,_Reason} = Res, State) when Type == tc_auto_skip ->
+on_tc_skip(Tc,{Type,_Reason} = Res, State0) when Type == tc_auto_skip ->
+ TcStr = atom_to_list(Tc),
+ State =
+ case State0#state.test_cases of
+ [#testcase{name=TcStr}|TCs] ->
+ State0#state{test_cases=TCs};
+ _ ->
+ State0
+ end,
do_tc_skip(Res, end_tc(Tc,[],Res,init_tc(State,[])));
on_tc_skip(_Tc, _Res, State = #state{test_cases = []}) ->
State;
@@ -103,7 +157,7 @@ do_tc_skip(Res, State) ->
TCs = State#state.test_cases,
TC = hd(TCs),
NewTC = TC#testcase{
- failure =
+ result =
{skipped,lists:flatten(io_lib:format("~p",[Res]))} },
State#state{ test_cases = [NewTC | tl(TCs)]}.
@@ -117,33 +171,52 @@ end_tc(Func, Config, Res, State) when is_atom(Func) ->
end_tc(atom_to_list(Func), Config, Res, State);
end_tc(Name, _Config, _Res, State = #state{ curr_suite = Suite,
curr_group = Groups,
- timer = TS, tc_log = Log } ) ->
+ curr_log_dir = CurrLogDir,
+ timer = TS,
+ tc_log = Log0,
+ url_base = UrlBase } ) ->
+ Log =
+ case Log0 of
+ "" ->
+ LowerSuiteName = string:to_lower(atom_to_list(Suite)),
+ filename:join(CurrLogDir,LowerSuiteName++"."++Name++".html");
+ _ ->
+ Log0
+ end,
+ Url = make_url(UrlBase,Log),
ClassName = atom_to_list(Suite),
PGroup = string:join([ atom_to_list(Group)||
Group <- lists:reverse(Groups)],"."),
TimeTakes = io_lib:format("~f",[timer:now_diff(now(),TS) / 1000000]),
State#state{ test_cases = [#testcase{ log = Log,
+ url = Url,
timestamp = now_to_string(TS),
classname = ClassName,
group = PGroup,
name = Name,
time = TimeTakes,
- failure = passed }| State#state.test_cases]}.
+ result = passed }|
+ State#state.test_cases],
+ tc_log = ""}. % so old tc_log is not set if next is on_tc_skip
close_suite(#state{ test_cases = [] } = State) ->
State;
-close_suite(#state{ test_cases = TCs } = State) ->
- Total = length(TCs),
- Succ = length(lists:filter(fun(#testcase{ failure = F }) ->
- F == passed
- end,TCs)),
- Fail = Total - Succ,
+close_suite(#state{ test_cases = TCs, url_base = UrlBase } = State) ->
+ {Total,Fail,Skip} = count_tcs(TCs,0,0,0),
TimeTaken = timer:now_diff(now(),State#state.curr_suite_ts) / 1000000,
+ SuiteLog = filename:join(State#state.curr_log_dir,?suite_log),
+ SuiteUrl = make_url(UrlBase,SuiteLog),
Suite = #testsuite{ name = atom_to_list(State#state.curr_suite),
package = State#state.package,
+ hostname = State#state.hostname,
time = io_lib:format("~f",[TimeTaken]),
timestamp = now_to_string(State#state.curr_suite_ts),
- errors = Fail, tests = Total,
- testcases = lists:reverse(TCs) },
+ errors = 0,
+ failures = Fail,
+ skipped = Skip,
+ tests = Total,
+ testcases = lists:reverse(TCs),
+ log = SuiteLog,
+ url = SuiteUrl},
State#state{ test_cases = [],
test_suites = [Suite | State#state.test_suites]}.
@@ -159,14 +232,15 @@ terminate(State) ->
-to_xml(#testcase{ group = Group, classname = CL, log = L, name = N, time = T, timestamp = TS, failure = F}) ->
+to_xml(#testcase{ group = Group, classname = CL, log = L, url = U, name = N, time = T, timestamp = TS, result = R}) ->
["<testcase ",
- [["group=\"",Group,"\""]||Group /= ""]," "
+ [["group=\"",Group,"\" "]||Group /= ""],
"name=\"",N,"\" "
"time=\"",T,"\" "
- "timestamp=\"",TS,"\" "
+ "timestamp=\"",TS,"\" ",
+ [["url=\"",U,"\" "]||U /= undefined],
"log=\"",L,"\">",
- case F of
+ case R of
passed ->
[];
{skipped,Reason} ->
@@ -176,22 +250,29 @@ to_xml(#testcase{ group = Group, classname = CL, log = L, name = N, time = T, ti
["<failure message=\"Test ",N," in ",CL," failed!\" type=\"crash\">",
sanitize(Reason),"</failure>"]
end,"</testcase>"];
-to_xml(#testsuite{ package = P, hostname = H, errors = E, time = Time,
- timestamp = TS, tests = T, name = N, testcases = Cases }) ->
+to_xml(#testsuite{ package = P, hostname = H, errors = E, failures = F,
+ skipped = S, time = Time, timestamp = TS, tests = T, name = N,
+ testcases = Cases, log = Log, url = Url }) ->
["<testsuite ",
[["package=\"",P,"\" "]||P /= undefined],
- [["hostname=\"",P,"\" "]||H /= undefined],
- [["name=\"",N,"\" "]||N /= undefined],
- [["time=\"",Time,"\" "]||Time /= undefined],
- [["timestamp=\"",TS,"\" "]||TS /= undefined],
+ "hostname=\"",H,"\" "
+ "name=\"",N,"\" "
+ "time=\"",Time,"\" "
+ "timestamp=\"",TS,"\" "
"errors=\"",integer_to_list(E),"\" "
- "tests=\"",integer_to_list(T),"\">",
+ "failures=\"",integer_to_list(F),"\" "
+ "skipped=\"",integer_to_list(S),"\" "
+ "tests=\"",integer_to_list(T),"\" ",
+ [["url=\"",Url,"\" "]||Url /= undefined],
+ "log=\"",Log,"\">",
[to_xml(Case) || Case <- Cases],
"</testsuite>"];
to_xml(#state{ test_suites = TestSuites, axis = Axis, properties = Props }) ->
["<testsuites>",properties_to_xml(Axis,Props),
[to_xml(TestSuite) || TestSuite <- TestSuites],"</testsuites>"].
+properties_to_xml([],[]) ->
+ [];
properties_to_xml(Axis,Props) ->
["<properties>",
[["<property name=\"",Name,"\" axis=\"yes\" value=\"",Value,"\" />"] || {Name,Value} <- Axis],
@@ -217,3 +298,37 @@ sanitize([]) ->
now_to_string(Now) ->
{{YY,MM,DD},{HH,Mi,SS}} = calendar:now_to_local_time(Now),
io_lib:format("~p-~2..0B-~2..0BT~2..0B:~2..0B:~2..0B",[YY,MM,DD,HH,Mi,SS]).
+
+make_url(undefined,_) ->
+ undefined;
+make_url(_,[]) ->
+ undefined;
+make_url(UrlBase0,Log) ->
+ UrlBase = string:strip(UrlBase0,right,$/),
+ RelativeLog = get_relative_log_url(Log),
+ string:join([UrlBase,RelativeLog],"/").
+
+get_test_root(Log) ->
+ LogParts = filename:split(Log),
+ filename:join(lists:sublist(LogParts,1,length(LogParts)-?log_depth)).
+
+get_relative_log_url(Log) ->
+ LogParts = filename:split(Log),
+ Start = length(LogParts)-?log_depth,
+ Length = ?log_depth+1,
+ string:join(lists:sublist(LogParts,Start,Length),"/").
+
+count_tcs([#testcase{name=ConfCase}|TCs],Ok,F,S)
+ when ConfCase=="init_per_suite";
+ ConfCase=="end_per_suite";
+ ConfCase=="init_per_group";
+ ConfCase=="end_per_group" ->
+ count_tcs(TCs,Ok,F,S);
+count_tcs([#testcase{result=passed}|TCs],Ok,F,S) ->
+ count_tcs(TCs,Ok+1,F,S);
+count_tcs([#testcase{result={fail,_}}|TCs],Ok,F,S) ->
+ count_tcs(TCs,Ok,F+1,S);
+count_tcs([#testcase{result={skipped,_}}|TCs],Ok,F,S) ->
+ count_tcs(TCs,Ok,F,S+1);
+count_tcs([],Ok,F,S) ->
+ {Ok+F+S,F,S}.
diff --git a/lib/common_test/test/Makefile b/lib/common_test/test/Makefile
index 7691920993..d469d03e04 100644
--- a/lib/common_test/test/Makefile
+++ b/lib/common_test/test/Makefile
@@ -53,7 +53,11 @@ MODULES= \
ct_verbosity_SUITE \
ct_shell_SUITE \
ct_system_error_SUITE \
- ct_snmp_SUITE
+ ct_snmp_SUITE \
+ ct_group_leader_SUITE \
+ ct_cover_SUITE \
+ ct_groups_search_SUITE \
+ ct_surefire_SUITE
ERL_FILES= $(MODULES:%=%.erl)
@@ -107,7 +111,7 @@ release_spec: opt
release_tests_spec:
$(INSTALL_DIR) "$(RELSYSDIR)"
$(INSTALL_DATA) $(ERL_FILES) $(COVERFILE) "$(RELSYSDIR)"
- $(INSTALL_DATA) common_test.spec "$(RELSYSDIR)"
+ $(INSTALL_DATA) common_test.spec common_test.cover "$(RELSYSDIR)"
chmod -R u+w "$(RELSYSDIR)"
@tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
diff --git a/lib/common_test/test/common_test.cover b/lib/common_test/test/common_test.cover
new file mode 100644
index 0000000000..3aa49623e7
--- /dev/null
+++ b/lib/common_test/test/common_test.cover
@@ -0,0 +1,10 @@
+%% -*- erlang -*-
+{incl_app,common_test,details}.
+{cross,common_test,[{test_server,[erl2html2,
+ test_server,
+ test_server_ctrl,
+ test_server_gl,
+ test_server_h,
+ test_server_io,
+ test_server_node,
+ test_server_sup]}]}.
diff --git a/lib/common_test/test/ct_config_SUITE.erl b/lib/common_test/test/ct_config_SUITE.erl
index 0b1abae757..d92be9ec6e 100644
--- a/lib/common_test/test/ct_config_SUITE.erl
+++ b/lib/common_test/test/ct_config_SUITE.erl
@@ -88,8 +88,8 @@ require(Config) when is_list(Config) ->
DataDir = ?config(data_dir, Config),
run_test(config_static_SUITE,
Config,
- [{config, filename:join(DataDir, "config/shadow.txt")},
- {config, filename:join(DataDir, "config/config.txt")}],
+ [{config, [filename:join(DataDir, "config/shadow.txt"),
+ filename:join(DataDir, "config/config.txt")]}],
["config_static_SUITE"]).
install_config(Config) when is_list(Config) ->
@@ -174,6 +174,7 @@ run_test(Name, Config, CTConfig, SuiteNames)->
Joiner = fun(Suite) -> filename:join(DataDir, "config/test/"++Suite) end,
Suites = lists:map(Joiner, SuiteNames),
{Opts,ERPid} = setup_env({suite,Suites}, Config, CTConfig),
+
ok = ct_test_support:run(Opts, Config),
TestEvents = ct_test_support:get_events(ERPid, Config),
ct_test_support:log_events(Name,
@@ -251,6 +252,7 @@ expected_events(config_static_SUITE)->
?sok(test_alias_tclocal_nested,{14,0,{2,1}}),
?sok(test_alias_tclocal_nested_backward_compat,{15,0,{2,1}}),
?sok(test_alias_tclocal_nested_backward_compat_subvals,{16,0,{2,1}}),
+ ?sok(test_config_same_name_already_in_use,{17,0,{2,1}}),
{?eh,tc_start,{config_static_SUITE,end_per_suite}},
{?eh,tc_done,{config_static_SUITE,end_per_suite,ok}},
{?eh,test_done,{'DEF','STOP_TIME'}},
diff --git a/lib/common_test/test/ct_config_SUITE_data/config/test/config_static_SUITE.erl b/lib/common_test/test/ct_config_SUITE_data/config/test/config_static_SUITE.erl
index 2e1ad651e8..19f1dab4af 100644
--- a/lib/common_test/test/ct_config_SUITE_data/config/test/config_static_SUITE.erl
+++ b/lib/common_test/test/ct_config_SUITE_data/config/test/config_static_SUITE.erl
@@ -64,7 +64,8 @@ all() -> [test_get_config_simple, test_get_config_nested,
test_shadow_all,test_element,test_shadow_all_element,
test_internal_deep, test_alias_tclocal_nested,
test_alias_tclocal_nested_backward_compat,
- test_alias_tclocal_nested_backward_compat_subvals
+ test_alias_tclocal_nested_backward_compat_subvals,
+ test_config_same_name_already_in_use
].
init_per_testcase(_,Config) ->
@@ -124,6 +125,13 @@ test_config_name_already_in_use2(_) ->
ct:fail("Test should've been skipped, you shouldn't see this!"),
ok.
+
+test_config_same_name_already_in_use() ->
+ [].
+test_config_same_name_already_in_use(_) ->
+ ok = ct:require(x2,{gen_cfg,c}),
+ ok = ct:require(x2,{gen_cfg,c}).
+
%% test aliases
test_alias_tclocal() ->
[{require,newalias,gen_cfg}].
diff --git a/lib/common_test/test/ct_config_info_SUITE.erl b/lib/common_test/test/ct_config_info_SUITE.erl
index 40da377ee5..10fe8286dd 100644
--- a/lib/common_test/test/ct_config_info_SUITE.erl
+++ b/lib/common_test/test/ct_config_info_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -123,8 +123,7 @@ test_events(config_info) ->
{?eh,tc_done,{config_info_1_SUITE,init_per_suite,ok}},
[{?eh,tc_start,{config_info_1_SUITE,{init_per_group,g1,[]}}},
- {?eh,tc_done,{config_info_1_SUITE,
- {init_per_group,unknown,[]},
+ {?eh,tc_done,{config_info_1_SUITE,{init_per_group,g1,[]},
{failed,{timetrap_timeout,350}}}},
{?eh,tc_auto_skip,{config_info_1_SUITE,t11,
{failed,{config_info_1_SUITE,init_per_group,{timetrap_timeout,350}}}}},
@@ -136,14 +135,12 @@ test_events(config_info) ->
{?eh,tc_done,{config_info_1_SUITE,{init_per_group,g2,[]},ok}},
{?eh,tc_done,{config_info_1_SUITE,t21,ok}},
{?eh,tc_start,{config_info_1_SUITE,{end_per_group,g2,[]}}},
- {?eh,tc_done,{config_info_1_SUITE,
- {end_per_group,unknown,[]},
+ {?eh,tc_done,{config_info_1_SUITE,{end_per_group,g2,[]},
{failed,{timetrap_timeout,450}}}}],
[{?eh,tc_start,{config_info_1_SUITE,{init_per_group,g3,[]}}},
{?eh,tc_done,{config_info_1_SUITE,{init_per_group,g3,[]},ok}},
[{?eh,tc_start,{config_info_1_SUITE,{init_per_group,g4,[]}}},
- {?eh,tc_done,{config_info_1_SUITE,
- {init_per_group,unknown,[]},
+ {?eh,tc_done,{config_info_1_SUITE,{init_per_group,g4,[]},
{failed,{timetrap_timeout,400}}}},
{?eh,tc_auto_skip,{config_info_1_SUITE,t41,
{failed,{config_info_1_SUITE,init_per_group,
@@ -164,8 +161,7 @@ test_events(config_info) ->
{?eh,tc_done,{config_info_1_SUITE,{init_per_group,g5,[]},ok}},
{?eh,tc_done,{config_info_1_SUITE,t51,ok}},
{?eh,tc_start,{config_info_1_SUITE,{end_per_group,g5,[]}}},
- {?eh,tc_done,{config_info_1_SUITE,
- {end_per_group,unknown,[]},
+ {?eh,tc_done,{config_info_1_SUITE,{end_per_group,g5,[]},
{failed,{timetrap_timeout,400}}}}],
{?eh,tc_start,{config_info_1_SUITE,{end_per_group,g3,[]}}},
{?eh,tc_done,{config_info_1_SUITE,{end_per_group,g3,[]},ok}}],
diff --git a/lib/common_test/test/ct_cover_SUITE.erl b/lib/common_test/test/ct_cover_SUITE.erl
new file mode 100644
index 0000000000..cb49dc423f
--- /dev/null
+++ b/lib/common_test/test/ct_cover_SUITE.erl
@@ -0,0 +1,312 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012. All Rights Reserved.
+%%
+%% The 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%
+%%
+
+%%%-------------------------------------------------------------------
+%%% File: ct_cover_SUITE
+%%%
+%%% Description:
+%%% Test code cover analysis support
+%%%
+%%%-------------------------------------------------------------------
+-module(ct_cover_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("common_test/include/ct_event.hrl").
+
+-define(eh, ct_test_support_eh).
+-define(suite, cover_SUITE).
+-define(mod, cover_test_mod).
+
+%%--------------------------------------------------------------------
+%% TEST SERVER CALLBACK FUNCTIONS
+%%--------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% Description: Since Common Test starts another Test Server
+%% instance, the tests need to be performed on a separate node (or
+%% there will be clashes with logging processes etc).
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ case test_server:is_cover() of
+ true ->
+ {skip,"Test server is running cover already - skipping"};
+ false ->
+ ct_test_support:init_per_suite(Config)
+ end.
+
+end_per_suite(Config) ->
+ ct_test_support:end_per_suite(Config).
+
+init_per_testcase(TestCase, Config) ->
+ ct_test_support:init_per_testcase(TestCase, Config).
+
+end_per_testcase(TestCase, Config) ->
+ Node = fullname(existing_node),
+ case lists:member(Node,nodes()) of
+ true -> rpc:call(Node,erlang,halt,[]);
+ false -> ok
+ end,
+ ct_test_support:end_per_testcase(TestCase, Config).
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [
+ default,
+ cover_stop_true,
+ cover_stop_false,
+ slave,
+ slave_start_slave,
+ cover_node_option,
+ ct_cover_add_remove_nodes,
+ otp_9956,
+ cross
+ ].
+
+%%--------------------------------------------------------------------
+%% TEST CASES
+%%--------------------------------------------------------------------
+
+%% Check that cover is collected from test node
+%% Also check that cover is by default stopped after test is completed
+default(Config) ->
+ {ok,Events} = run_test(default,Config),
+ false = check_cover(Config),
+ check_calls(Events,1),
+ ok.
+
+%% Check that cover is stopped when cover_stop option is set to true
+cover_stop_true(Config) ->
+ {ok,_Events} = run_test(cover_stop_true,[{cover_stop,true}],Config),
+ false = check_cover(Config).
+
+%% Check that cover is not stopped when cover_stop option is set to false
+cover_stop_false(Config) ->
+ {ok,_Events} = run_test(cover_stop_false,[{cover_stop,false}],Config),
+ {true,[],[?mod]} = check_cover(Config),
+ CTNode = proplists:get_value(ct_node, Config),
+ ok = rpc:call(CTNode,cover,stop,[]),
+ false = check_cover(Config),
+ ok.
+
+%% Let test node start a slave node - check that cover is collected
+%% from both nodes
+slave(Config) ->
+ {ok,Events} = run_test(slave,slave,[],Config),
+ check_calls(Events,2),
+ ok.
+
+%% Let test node start a slave node which in turn starts another slave
+%% node - check that cover is collected from all three nodes
+slave_start_slave(Config) ->
+ {ok,Events} = run_test(slave_start_slave,slave_start_slave,[],Config),
+ check_calls(Events,3),
+ ok.
+
+%% Start a slave node before test starts - the node is listed in cover
+%% spec file.
+%% Check that cover is collected from test node and slave node.
+cover_node_option(Config) ->
+ {ok, HostStr}=inet:gethostname(),
+ Host = list_to_atom(HostStr),
+ DataDir = ?config(data_dir,Config),
+ {ok,Node} = ct_slave:start(Host,existing_node,
+ [{erl_flags,"-pa " ++ DataDir}]),
+ false = check_cover(Node),
+ CoverSpec = default_cover_file_content() ++ [{nodes,[Node]}],
+ CoverFile = create_cover_file(cover_node_option,CoverSpec,Config),
+ {ok,Events} = run_test(cover_node_option,cover_node_option,
+ [{cover,CoverFile}],Config),
+ check_calls(Events,2),
+ {ok,Node} = ct_slave:stop(existing_node),
+ ok.
+
+%% Test ct_cover:add_nodes/1 and ct_cover:remove_nodes/1
+%% Check that cover is collected from added node
+ct_cover_add_remove_nodes(Config) ->
+ {ok, HostStr}=inet:gethostname(),
+ Host = list_to_atom(HostStr),
+ DataDir = ?config(data_dir,Config),
+ {ok,Node} = ct_slave:start(Host,existing_node,
+ [{erl_flags,"-pa " ++ DataDir}]),
+ false = check_cover(Node),
+ {ok,Events} = run_test(ct_cover_add_remove_nodes,ct_cover_add_remove_nodes,
+ [],Config),
+ check_calls(Events,2),
+ {ok,Node} = ct_slave:stop(existing_node),
+ ok.
+
+%% Test that the test suite itself can be cover compiled and that
+%% data_dir is set correctly (OTP-9956)
+otp_9956(Config) ->
+ CoverFile = create_cover_file(otp_9956,[{incl_mods,[?suite]}],Config),
+ {ok,Events} = run_test(otp_9956,otp_9956,[{cover,CoverFile}],Config),
+ check_calls(Events,{?suite,otp_9956,1},1),
+ ok.
+
+%% Test cross cover mechanism
+cross(Config) ->
+ {ok,Events1} = run_test(cross1,Config),
+ check_calls(Events1,1),
+
+ CoverFile2 = create_cover_file(cross1,[{cross,[{cross1,[?mod]}]}],Config),
+ {ok,Events2} = run_test(cross2,[{cover,CoverFile2}],Config),
+ check_calls(Events2,1),
+
+ %% Get the log dirs for each test and run cross cover analyse
+ [D11,D12] = lists:sort(get_run_dirs(Events1)),
+ [D21,D22] = lists:sort(get_run_dirs(Events2)),
+
+ ct_cover:cross_cover_analyse(details,[{cross1,D11},{cross2,D21}]),
+ ct_cover:cross_cover_analyse(details,[{cross1,D12},{cross2,D22}]),
+
+ %% Get the cross cover logs and read for each test
+ [C11,C12,C21,C22] =
+ [filename:join(D,"cross_cover.html") || D <- [D11,D12,D21,D22]],
+
+ {ok,CrossData} = file:read_file(C11),
+ {ok,CrossData} = file:read_file(C12),
+
+ {ok,Def} = file:read_file(C21),
+ {ok,Def} = file:read_file(C22),
+
+ %% A simple test: just check that the test module exists in the
+ %% log from cross1 test, and that it does not exist in the log
+ %% from cross2 test.
+ TestMod = list_to_binary(atom_to_list(?mod)),
+ {_,_} = binary:match(CrossData,TestMod),
+ nomatch = binary:match(Def,TestMod),
+ {_,_} = binary:match(Def,
+ <<"No cross cover modules exist for this application">>),
+
+ ok.
+
+
+%%%-----------------------------------------------------------------
+%%% HELP FUNCTIONS
+%%%-----------------------------------------------------------------
+run_test(Label,Config) ->
+ run_test(Label,[],Config).
+run_test(Label,ExtraOpts,Config) ->
+ run_test(Label,default,ExtraOpts,Config).
+run_test(Label,Testcase,ExtraOpts,Config) ->
+ DataDir = ?config(data_dir, Config),
+ Suite = filename:join(DataDir, ?suite),
+ CoverFile =
+ case proplists:get_value(cover,ExtraOpts) of
+ undefined ->
+ create_default_cover_file(Label,Config);
+ CF ->
+ CF
+ end,
+ RestOpts = lists:keydelete(cover,1,ExtraOpts),
+ {Opts,ERPid} = setup([{suite,Suite},{testcase,Testcase},
+ {cover,CoverFile},{label,Label}] ++ RestOpts, Config),
+ execute(Label, Testcase, Opts, ERPid, Config).
+
+setup(Test, Config) ->
+ Opts0 = ct_test_support:get_opts(Config),
+ Level = ?config(trace_level, Config),
+ EvHArgs = [{cbm,ct_test_support},{trace_level,Level}],
+ Opts = Opts0 ++ [{event_handler,{?eh,EvHArgs}}|Test],
+ ERPid = ct_test_support:start_event_receiver(Config),
+ {Opts,ERPid}.
+
+execute(Name, Testcase, Opts, ERPid, Config) ->
+ ok = ct_test_support:run(Opts, Config),
+ Events = ct_test_support:get_events(ERPid, Config),
+
+ ct_test_support:log_events(Name,
+ reformat(Events, ?eh),
+ ?config(priv_dir, Config),
+ Opts),
+ TestEvents = events_to_check(Testcase),
+ R = ct_test_support:verify_events(TestEvents, Events, Config),
+ {R,Events}.
+
+reformat(Events, EH) ->
+ ct_test_support:reformat(Events, EH).
+
+events_to_check(Testcase) ->
+ OneTest =
+ [{?eh,start_logging,{'DEF','RUNDIR'}}] ++
+ [{?eh,tc_done,{?suite,Testcase,ok}}] ++
+ [{?eh,stop_logging,[]}],
+
+ %% 2 tests (ct:run_test + script_start) is default
+ OneTest ++ OneTest.
+
+check_cover(Config) when is_list(Config) ->
+ CTNode = proplists:get_value(ct_node, Config),
+ check_cover(CTNode);
+check_cover(Node) when is_atom(Node) ->
+ case rpc:call(Node,test_server,is_cover,[]) of
+ true ->
+ {true,
+ rpc:call(Node,cover,which_nodes,[]),
+ rpc:call(Node,cover,modules,[])};
+ false ->
+ false
+ end.
+
+%% Get the log dir "run.<timestamp>" for all (both!) tests
+get_run_dirs(Events) ->
+ [filename:dirname(TCLog) ||
+ {ct_test_support_eh,
+ {event,tc_logfile,_Node,
+ {{?suite,init_per_suite},TCLog}}} <- Events].
+
+%% Check that each coverlog includes N calls to ?mod:foo/0
+check_calls(Events,N) ->
+ check_calls(Events,{?mod,foo,0},N).
+check_calls(Events,MFA,N) ->
+ CoverLogs = [filename:join(D,"all.coverdata") || D <- get_run_dirs(Events)],
+ do_check_logs(CoverLogs,MFA,N).
+
+do_check_logs([CoverLog|CoverLogs],{Mod,_,_} = MFA,N) ->
+ {ok,_} = cover:start(),
+ ok = cover:import(CoverLog),
+ {ok,Calls} = cover:analyse(Mod,calls,function),
+ ok = cover:stop(),
+ {MFA,N} = lists:keyfind(MFA,1,Calls),
+ do_check_logs(CoverLogs,MFA,N);
+do_check_logs([],_,_) ->
+ ok.
+
+fullname(Name) ->
+ {ok,Host} = inet:gethostname(),
+ list_to_atom(atom_to_list(Name) ++ "@" ++ Host).
+
+default_cover_file_content() ->
+ [{incl_mods,[?mod]}].
+
+create_default_cover_file(Filename,Config) ->
+ create_cover_file(Filename,default_cover_file_content(),Config).
+
+create_cover_file(Filename,Terms,Config) ->
+ PrivDir = ?config(priv_dir,Config),
+ File = filename:join(PrivDir,Filename) ++ ".cover",
+ {ok,Fd} = file:open(File,[write]),
+ lists:foreach(fun(Term) ->
+ file:write(Fd,io_lib:format("~p.~n",[Term]))
+ end,Terms),
+ ok = file:close(Fd),
+ File.
diff --git a/lib/common_test/test/ct_cover_SUITE_data/cover_SUITE.erl b/lib/common_test/test/ct_cover_SUITE_data/cover_SUITE.erl
new file mode 100644
index 0000000000..fdc3323f0a
--- /dev/null
+++ b/lib/common_test/test/ct_cover_SUITE_data/cover_SUITE.erl
@@ -0,0 +1,156 @@
+%%--------------------------------------------------------------------
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012. All Rights Reserved.
+%%
+%% The 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%
+%%
+%%----------------------------------------------------------------------
+%% File: cover_SUITE.erl
+%%
+%% Description:
+%% This file contains the test cases for the code coverage support
+%%
+%% @author Support
+%% @doc Test of code coverage support in common_test
+%% @end
+%%----------------------------------------------------------------------
+%%----------------------------------------------------------------------
+-module(cover_SUITE).
+-include_lib("common_test/include/ct.hrl").
+
+-compile(export_all).
+
+%% Default timetrap timeout (set in init_per_testcase).
+-define(default_timeout, ?t:minutes(1)).
+
+suite() ->
+ [].
+
+all() ->
+ [].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(Config) ->
+ Config.
+
+init_per_testcase(_Case, Config) ->
+ Dog = test_server:timetrap(?default_timeout),
+ [{watchdog, Dog}|Config].
+
+end_per_testcase(Case, Config) ->
+ %% try apply(?MODULE,Case,[cleanup,Config])
+ %% catch error:undef -> ok
+ %% end,
+
+ kill_slaves(Case,nodes()),
+ Dog=?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+%%%-----------------------------------------------------------------
+%%% Test cases
+break(_Config) ->
+ test_server:break(""),
+ ok.
+
+default(Config) ->
+ cover_compiled = code:which(cover_test_mod),
+ cover_test_mod:foo(),
+ ok.
+
+slave(Config) ->
+ cover_compiled = code:which(cover_test_mod),
+ cover_test_mod:foo(),
+ N1 = nodename(slave,1),
+ {ok,Node} = ct_slave:start(N1),
+ cover_compiled = rpc:call(Node,code,which,[cover_test_mod]),
+ rpc:call(Node,cover_test_mod,foo,[]),
+ {ok,Node} = ct_slave:stop(N1),
+ ok.
+
+slave_start_slave(Config) ->
+ cover_compiled = code:which(cover_test_mod),
+ cover_test_mod:foo(),
+ N1 = nodename(slave_start_slave,1),
+ N2 = nodename(slave_start_slave,2),
+ {ok,Node} = ct_slave:start(N1),
+ cover_compiled = rpc:call(Node,code,which,[cover_test_mod]),
+ rpc:call(Node,cover_test_mod,foo,[]),
+ {ok,Node2} = rpc:call(Node,ct_slave,start,[N2]),
+ rpc:call(Node2,cover_test_mod,foo,[]),
+ {ok,Node2} = rpc:call(Node,ct_slave,stop,[N2]),
+ {ok,Node} = ct_slave:stop(N1),
+ ok.
+
+cover_node_option(Config) ->
+ cover_compiled = code:which(cover_test_mod),
+ cover_test_mod:foo(),
+ Node = fullname(existing_node),
+ cover_compiled = rpc:call(Node,code,which,[cover_test_mod]),
+ rpc:call(Node,cover_test_mod,foo,[]),
+ ok.
+
+ct_cover_add_remove_nodes(Config) ->
+ cover_compiled = code:which(cover_test_mod),
+ cover_test_mod:foo(),
+ Node = fullname(existing_node),
+ Beam = rpc:call(Node,code,which,[cover_test_mod]),
+ false = (Beam == cover_compiled),
+
+ rpc:call(Node,cover_test_mod,foo,[]), % should not be collected
+ {ok,[Node]} = ct_cover:add_nodes([Node]),
+ cover_compiled = rpc:call(Node,code,which,[cover_test_mod]),
+ rpc:call(Node,cover_test_mod,foo,[]), % should be collected
+ ok = ct_cover:remove_nodes([Node]),
+ rpc:call(Node,cover_test_mod,foo,[]), % should not be collected
+
+ Beam = rpc:call(Node,code,which,[cover_test_mod]),
+
+ ok.
+
+otp_9956(Config) ->
+ cover_compiled = code:which(?MODULE),
+ DataDir = ?config(data_dir,Config),
+ absolute = filename:pathtype(DataDir),
+ true = filelib:is_dir(DataDir),
+ ok.
+
+
+%%%-----------------------------------------------------------------
+%%% Internal
+nodename(Case,N) ->
+ list_to_atom(nodeprefix(Case) ++ integer_to_list(N)).
+
+nodeprefix(Case) ->
+ atom_to_list(?MODULE) ++ "_" ++ atom_to_list(Case) ++ "_node".
+
+
+fullname(Name) ->
+ {ok,Host} = inet:gethostname(),
+ list_to_atom(atom_to_list(Name) ++ "@" ++ Host).
+
+kill_slaves(Case, [Node|Nodes]) ->
+ Prefix = nodeprefix(Case),
+ case lists:prefix(Prefix,atom_to_list(Node)) of
+ true ->
+ rpc:call(Node,erlang,halt,[]);
+ _ ->
+ ok
+ end,
+ kill_slaves(Case,Nodes);
+kill_slaves(_,[]) ->
+ ok.
diff --git a/lib/common_test/test/ct_cover_SUITE_data/cover_SUITE_data/.gitignore b/lib/common_test/test/ct_cover_SUITE_data/cover_SUITE_data/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/common_test/test/ct_cover_SUITE_data/cover_SUITE_data/.gitignore
diff --git a/lib/common_test/test/ct_cover_SUITE_data/cover_test_mod.erl b/lib/common_test/test/ct_cover_SUITE_data/cover_test_mod.erl
new file mode 100644
index 0000000000..d4f69452c3
--- /dev/null
+++ b/lib/common_test/test/ct_cover_SUITE_data/cover_test_mod.erl
@@ -0,0 +1,4 @@
+-module(cover_test_mod).
+-compile(export_all).
+foo() ->
+ ok.
diff --git a/lib/common_test/test/ct_error_SUITE.erl b/lib/common_test/test/ct_error_SUITE.erl
index 338e76264e..6d90b29f41 100644
--- a/lib/common_test/test/ct_error_SUITE.erl
+++ b/lib/common_test/test/ct_error_SUITE.erl
@@ -61,7 +61,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[cfg_error, lib_error, no_compile, timetrap_end_conf,
timetrap_normal, timetrap_extended, timetrap_parallel,
- timetrap_fun, misc_errors].
+ timetrap_fun, timetrap_fun_group, misc_errors].
groups() ->
[].
@@ -251,6 +251,24 @@ timetrap_fun(Config) when is_list(Config) ->
%%%-----------------------------------------------------------------
%%%
+timetrap_fun_group(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ Join = fun(D, S) -> filename:join(D, "error/test/"++S) end,
+ Suites = [Join(DataDir, "timetrap_8_SUITE")],
+ {Opts,ERPid} = setup([{suite,Suites}], Config),
+ ok = ct_test_support:run(Opts, Config),
+ Events = ct_test_support:get_events(ERPid, Config),
+
+ ct_test_support:log_events(timetrap_fun_group,
+ reformat(Events, ?eh),
+ ?config(priv_dir, Config),
+ Opts),
+
+ TestEvents = events_to_check(timetrap_fun_group),
+ ok = ct_test_support:verify_events(TestEvents, Events, Config).
+
+%%%-----------------------------------------------------------------
+%%%
misc_errors(Config) when is_list(Config) ->
DataDir = ?config(data_dir, Config),
Join = fun(D, S) -> filename:join(D, "error/test/"++S) end,
@@ -429,8 +447,7 @@ test_events(cfg_error) ->
{'EXIT',{init_per_group_fails,g1}}}}}}],
[{?eh,tc_start,{cfg_error_8_SUITE,{init_per_group,g2,[]}}},
- {?eh,tc_done,{cfg_error_8_SUITE,
- {init_per_group,unknown,[]},
+ {?eh,tc_done,{cfg_error_8_SUITE,{init_per_group,g2,[]},
{failed,{timetrap_timeout,2000}}}},
{?eh,tc_auto_skip,{cfg_error_8_SUITE,tc1,
{failed,{cfg_error_8_SUITE,init_per_group,
@@ -500,7 +517,7 @@ test_events(cfg_error) ->
{?eh,tc_done,{cfg_error_8_SUITE,tc1,ok}},
{?eh,test_stats,{9,0,{0,14}}},
{?eh,tc_start,{cfg_error_8_SUITE,{end_per_group,g12,[]}}},
- {?eh,tc_done,{cfg_error_8_SUITE,{end_per_group,unknown,[]},
+ {?eh,tc_done,{cfg_error_8_SUITE,{end_per_group,g12,[]},
{failed,{timetrap_timeout,2000}}}}],
{?eh,tc_start,{cfg_error_8_SUITE,end_per_suite}},
@@ -971,11 +988,423 @@ test_events(timetrap_fun) ->
{?eh,stop_logging,[]}
];
+test_events(timetrap_fun_group) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{1,1,58}},
+ {?eh,tc_start,{timetrap_8_SUITE,init_per_suite}},
+ {?eh,tc_done,{timetrap_8_SUITE,init_per_suite,ok}},
+
+ [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,g0,[]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,g0,[]},ok}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc0}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc0,
+ {failed,{timetrap_timeout,{'$approx',1000}}}}},
+ {?eh,test_stats,{0,1,{0,0}}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc2}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc2,
+ {failed,{timetrap_timeout,{'$approx',500}}}}},
+ {?eh,test_stats,{0,2,{0,0}}},
+ {?eh,tc_start,{timetrap_8_SUITE,{end_per_group,g0,[]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{end_per_group,g0,[]},ok}}],
+
+ [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,g1,[]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,g1,[]},ok}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc0}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc0,
+ {failed,{timetrap_timeout,{'$approx',1000}}}}},
+ {?eh,test_stats,{0,3,{0,0}}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc2}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc2,
+ {failed,{timetrap_timeout,{'$approx',500}}}}},
+ {?eh,test_stats,{0,4,{0,0}}},
+ {?eh,tc_start,{timetrap_8_SUITE,{end_per_group,g1,[]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{end_per_group,g1,[]},ok}}],
+
+ [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,g2,[]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,g2,[]},ok}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc1}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc1,
+ {failed,{timetrap_timeout,{'$approx',1000}}}}},
+ {?eh,test_stats,{0,5,{0,0}}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc2}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc2,
+ {failed,{timetrap_timeout,{'$approx',500}}}}},
+ {?eh,test_stats,{0,6,{0,0}}},
+ {?eh,tc_start,{timetrap_8_SUITE,{end_per_group,g2,[]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{end_per_group,g2,[]},ok}}],
+
+ [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,g3,[]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,g3,[]},ok}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc4}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc4,
+ {failed,{timetrap_timeout,{'$approx',2000}}}}},
+ {?eh,test_stats,{0,7,{0,0}}},
+ [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,g1,[]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,g1,[]},ok}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc0}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc0,
+ {failed,{timetrap_timeout,{'$approx',1000}}}}},
+ {?eh,test_stats,{0,8,{0,0}}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc2}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc2,
+ {failed,{timetrap_timeout,{'$approx',500}}}}},
+ {?eh,test_stats,{0,9,{0,0}}},
+ {?eh,tc_start,{timetrap_8_SUITE,{end_per_group,g1,[]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{end_per_group,g1,[]},ok}}],
+ [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,g2,[]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,g2,[]},ok}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc1}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc1,
+ {failed,{timetrap_timeout,{'$approx',1000}}}}},
+ {?eh,test_stats,{0,10,{0,0}}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc2}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc2,
+ {failed,{timetrap_timeout,{'$approx',500}}}}},
+ {?eh,test_stats,{0,11,{0,0}}},
+ {?eh,tc_start,{timetrap_8_SUITE,{end_per_group,g2,[]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{end_per_group,g2,[]},ok}}],
+ {?eh,tc_start,{timetrap_8_SUITE,{end_per_group,g3,[]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{end_per_group,g3,[]},ok}}],
+
+ [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,g4,[]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,g4,[]},
+ {user_timetrap_error,{kaboom,'_'}}}},
+ {?eh,tc_auto_skip,{timetrap_8_SUITE,tc0,
+ {failed,{timetrap_8_SUITE,init_per_group,
+ {user_timetrap_error,{kaboom,'_'}}}}}},
+ {?eh,test_stats,{0,11,{0,1}}},
+ {?eh,tc_auto_skip,{timetrap_8_SUITE,tc2,
+ {failed,{timetrap_8_SUITE,init_per_group,
+ {user_timetrap_error,{kaboom,'_'}}}}}},
+ {?eh,test_stats,{0,11,{0,2}}},
+ {?eh,tc_auto_skip,{timetrap_8_SUITE,end_per_group,
+ {failed,{timetrap_8_SUITE,init_per_group,
+ {user_timetrap_error,{kaboom,'_'}}}}}}],
+
+ [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,g5,[]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,g5,[]},
+ {user_timetrap_error,{kaboom,'_'}}}},
+ {?eh,tc_auto_skip,{timetrap_8_SUITE,tc0,
+ {failed,{timetrap_8_SUITE,init_per_group,
+ {user_timetrap_error,{kaboom,'_'}}}}}},
+ {?eh,test_stats,{0,11,{0,3}}},
+ {?eh,tc_auto_skip,{timetrap_8_SUITE,tc2,
+ {failed,{timetrap_8_SUITE,init_per_group,
+ {user_timetrap_error,{kaboom,'_'}}}}}},
+ {?eh,test_stats,{0,11,{0,4}}},
+ {?eh,tc_auto_skip,{timetrap_8_SUITE,end_per_group,
+ {failed,{timetrap_8_SUITE,init_per_group,
+ {user_timetrap_error,{kaboom,'_'}}}}}}],
+
+ [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,g6,[]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,g6,[]},
+ {failed,{timetrap_timeout,{'$approx',500}}}}},
+ {?eh,tc_auto_skip,{timetrap_8_SUITE,tc0,
+ {failed,{timetrap_8_SUITE,init_per_group,
+ {timetrap_timeout,'_'}}}}},
+ {?eh,test_stats,{0,11,{0,5}}},
+ {?eh,tc_auto_skip,{timetrap_8_SUITE,tc2,
+ {failed,{timetrap_8_SUITE,init_per_group,
+ {timetrap_timeout,'_'}}}}},
+ {?eh,test_stats,{0,11,{0,6}}},
+ {?eh,tc_auto_skip,{timetrap_8_SUITE,end_per_group,
+ {failed,{timetrap_8_SUITE,init_per_group,
+ {timetrap_timeout,'_'}}}}}],
+
+ [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,g7,[]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,g7,[]},ok}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc5}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc5,ok}},
+ {?eh,test_stats,{1,11,{0,6}}},
+ {?eh,tc_start,{timetrap_8_SUITE,{end_per_group,g7,[]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{end_per_group,g7,[]},
+ {user_timetrap_error,{kaboom,'_'}}}}],
+
+ [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,g8,[]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,g8,[]},ok}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc5}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc5,ok}},
+ {?eh,test_stats,{2,11,{0,6}}},
+ {?eh,tc_start,{timetrap_8_SUITE,{end_per_group,g8,[]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{end_per_group,g8,[]},
+ {failed,{timetrap_timeout,{'$approx',500}}}}}],
+
+ [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,g9,[]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,g9,[]},ok}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc5}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc5,ok}},
+ {?eh,test_stats,{3,11,{0,6}}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc0}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc0,
+ {user_timetrap_error,{kaboom,'_'}}}},
+ {?eh,test_stats,{3,12,{0,6}}},
+ {?eh,tc_start,{timetrap_8_SUITE,{end_per_group,g9,[]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{end_per_group,g9,[]},ok}}],
+
+ [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,g10,[]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,g10,[]},ok}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc0}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc0,
+ {user_timetrap_error,{kaboom,'_'}}}},
+ {?eh,test_stats,{3,13,{0,6}}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc5}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc5,ok}},
+ {?eh,test_stats,{4,13,{0,6}}},
+ {?eh,tc_start,{timetrap_8_SUITE,{end_per_group,g10,[]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{end_per_group,g10,[]},ok}}],
+
+ [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,g11,[]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,g11,[]},ok}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc3}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc3,
+ {failed,{timetrap_timeout,{'$approx',4000}}}}},
+ {?eh,test_stats,{4,14,{0,6}}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc2}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc2,
+ {failed,{timetrap_timeout,{'$approx',500}}}}},
+ {?eh,test_stats,{4,15,{0,6}}},
+ {?eh,tc_start,{timetrap_8_SUITE,{end_per_group,g11,[]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{end_per_group,g11,[]},ok}}],
+
+ {parallel,
+ [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,pg0,[parallel]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,pg0,[parallel]},ok}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc0}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc0,
+ {failed,{timetrap_timeout,{'$approx',1000}}}}},
+ {?eh,test_stats,{4,16,{0,6}}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc2}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc2,
+ {failed,{timetrap_timeout,{'$approx',500}}}}},
+ {?eh,test_stats,{4,17,{0,6}}},
+ {?eh,tc_start,{timetrap_8_SUITE,{end_per_group,pg0,[parallel]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{end_per_group,pg0,[parallel]},ok}}]},
+
+ {parallel,
+ [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,pg1,[parallel]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,pg1,[parallel]},ok}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc0}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc0,
+ {failed,{timetrap_timeout,{'$approx',1000}}}}},
+ {?eh,test_stats,{4,18,{0,6}}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc2}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc2,
+ {failed,{timetrap_timeout,{'$approx',500}}}}},
+ {?eh,test_stats,{4,19,{0,6}}},
+ {?eh,tc_start,{timetrap_8_SUITE,{end_per_group,pg1,[parallel]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{end_per_group,pg1,[parallel]},ok}}]},
+
+ {parallel,
+ [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,pg2,[parallel]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,pg2,[parallel]},ok}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc1}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc1,
+ {failed,{timetrap_timeout,{'$approx',1000}}}}},
+ {?eh,test_stats,{4,20,{0,6}}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc2}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc2,
+ {failed,{timetrap_timeout,{'$approx',500}}}}},
+ {?eh,test_stats,{4,21,{0,6}}},
+ {?eh,tc_start,{timetrap_8_SUITE,{end_per_group,pg2,[parallel]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{end_per_group,pg2,[parallel]},ok}}]},
+
+ {parallel,
+ [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,pg3,[parallel]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,pg3,[parallel]},ok}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc4}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc4,
+ {failed,{timetrap_timeout,{'$approx',2000}}}}},
+ {?eh,test_stats,{4,22,{0,6}}},
+ {parallel,
+ [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,pg1,[parallel]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,pg1,[parallel]},
+ ok}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc0}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc0,
+ {failed,{timetrap_timeout,{'$approx',1000}}}}},
+ {?eh,test_stats,{4,23,{0,6}}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc2}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc2,
+ {failed,{timetrap_timeout,{'$approx',500}}}}},
+ {?eh,test_stats,{4,24,{0,6}}},
+ {?eh,tc_start,{timetrap_8_SUITE,{end_per_group,pg1,[parallel]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{end_per_group,pg1,[parallel]},
+ ok}}]},
+ {parallel,
+ [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,pg2,[parallel]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,pg2,[parallel]},
+ ok}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc1}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc1,
+ {failed,{timetrap_timeout,{'$approx',1000}}}}},
+ {?eh,test_stats,{4,25,{0,6}}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc2}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc2,
+ {failed,{timetrap_timeout,{'$approx',500}}}}},
+ {?eh,test_stats,{4,26,{0,6}}},
+ {?eh,tc_start,{timetrap_8_SUITE,{end_per_group,pg2,[parallel]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{end_per_group,pg2,[parallel]},
+ ok}}]},
+ {?eh,tc_start,{timetrap_8_SUITE,{end_per_group,pg3,[parallel]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{end_per_group,pg3,[parallel]},ok}}]},
+
+ {parallel,
+ [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,pg4,[parallel]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,pg4,[parallel]},
+ {user_timetrap_error,{kaboom,'_'}}}},
+ {?eh,tc_auto_skip,{timetrap_8_SUITE,tc0,
+ {failed,{timetrap_8_SUITE,init_per_group,
+ {user_timetrap_error,{kaboom,'_'}}}}}},
+ {?eh,test_stats,{4,26,{0,7}}},
+ {?eh,tc_auto_skip,{timetrap_8_SUITE,tc2,
+ {failed,{timetrap_8_SUITE,init_per_group,
+ {user_timetrap_error,{kaboom,'_'}}}}}},
+ {?eh,test_stats,{4,26,{0,8}}},
+ {?eh,tc_auto_skip,{timetrap_8_SUITE,end_per_group,
+ {failed,{timetrap_8_SUITE,init_per_group,
+ {user_timetrap_error,{kaboom,'_'}}}}}}]},
+
+ {parallel,
+ [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,pg5,[parallel]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,pg5,[parallel]},
+ {user_timetrap_error,{kaboom,'_'}}}},
+ {?eh,tc_auto_skip,{timetrap_8_SUITE,tc0,
+ {failed,{timetrap_8_SUITE,init_per_group,
+ {user_timetrap_error,{kaboom,'_'}}}}}},
+ {?eh,test_stats,{4,26,{0,9}}},
+ {?eh,tc_auto_skip,{timetrap_8_SUITE,tc2,
+ {failed,{timetrap_8_SUITE,init_per_group,
+ {user_timetrap_error,{kaboom,'_'}}}}}},
+ {?eh,test_stats,{4,26,{0,10}}},
+ {?eh,tc_auto_skip,{timetrap_8_SUITE,end_per_group,
+ {failed,{timetrap_8_SUITE,init_per_group,
+ {user_timetrap_error,{kaboom,'_'}}}}}}]},
+
+ {parallel,
+ [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,pg6,[parallel]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,pg6,[parallel]},
+ {failed,{timetrap_timeout,{'$approx',500}}}}},
+ {?eh,tc_auto_skip,{timetrap_8_SUITE,tc0,
+ {failed,{timetrap_8_SUITE,init_per_group,
+ {timetrap_timeout,'_'}}}}},
+ {?eh,test_stats,{4,26,{0,11}}},
+ {?eh,tc_auto_skip,{timetrap_8_SUITE,tc2,
+ {failed,{timetrap_8_SUITE,init_per_group,
+ {timetrap_timeout,'_'}}}}},
+ {?eh,test_stats,{4,26,{0,12}}},
+ {?eh,tc_auto_skip,{timetrap_8_SUITE,end_per_group,
+ {failed,{timetrap_8_SUITE,init_per_group,
+ {timetrap_timeout,'_'}}}}}]},
+
+ {parallel,
+ [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,pg7,[parallel]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,pg7,[parallel]},ok}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc5}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc5,ok}},
+ {?eh,test_stats,{5,26,{0,12}}},
+ {?eh,tc_start,{timetrap_8_SUITE,{end_per_group,pg7,[parallel]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{end_per_group,pg7,[parallel]},
+ {user_timetrap_error,{kaboom,'_'}}}}]},
+
+ {parallel,
+ [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,pg8,[parallel]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,pg8,[parallel]},ok}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc5}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc5,ok}},
+ {?eh,test_stats,{6,26,{0,12}}},
+ {?eh,tc_start,{timetrap_8_SUITE,{end_per_group,pg8,[parallel]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{end_per_group,pg8,[parallel]},
+ {failed,{timetrap_timeout,{'$approx',500}}}}}]},
+
+ {parallel,
+ [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,pg9,[parallel]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,pg9,[parallel]},ok}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc5}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc5,ok}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc0}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc0,
+ {user_timetrap_error,{kaboom,'_'}}}},
+ %% Due to parallelism only checking final test stat in group
+ {?eh,test_stats,{7,27,{0,12}}},
+ {?eh,tc_start,{timetrap_8_SUITE,{end_per_group,pg9,[parallel]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{end_per_group,pg9,[parallel]},ok}}]},
+
+ {parallel,
+ [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,pg10,[parallel]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,pg10,[parallel]},ok}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc0}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc0,
+ {user_timetrap_error,{kaboom,'_'}}}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc5}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc5,ok}},
+ %% Due to parallelism only checking final test stat in group
+ {?eh,test_stats,{8,28,{0,12}}},
+ {?eh,tc_start,{timetrap_8_SUITE,{end_per_group,pg10,[parallel]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{end_per_group,pg10,[parallel]},ok}}]},
+
+ {parallel,
+ [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,pg11,[parallel]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,pg11,[parallel]},ok}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc3}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc3,
+ {failed,{timetrap_timeout,{'$approx',4000}}}}},
+ {?eh,test_stats,{8,29,{0,12}}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc2}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc2,
+ {failed,{timetrap_timeout,{'$approx',500}}}}},
+ {?eh,test_stats,{8,30,{0,12}}},
+ {?eh,tc_start,{timetrap_8_SUITE,{end_per_group,pg11,[parallel]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{end_per_group,pg11,[parallel]},ok}}]},
+
+ [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,sg1,[sequence]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,sg1,[sequence]},ok}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc5}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc5,ok}},
+ {?eh,test_stats,{9,30,{0,12}}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc0}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc0,
+ {user_timetrap_error,{kaboom,'_'}}}},
+ {?eh,test_stats,{9,31,{0,12}}},
+ {?eh,tc_auto_skip,{timetrap_8_SUITE,tc1,
+ {failed,{timetrap_8_SUITE,tc0}}}},
+ {?eh,test_stats,{9,31,{0,13}}},
+ {?eh,tc_auto_skip,{timetrap_8_SUITE,tc2,
+ {failed,{timetrap_8_SUITE,tc0}}}},
+ {?eh,test_stats,{9,31,{0,14}}},
+ {?eh,tc_start,{timetrap_8_SUITE,{end_per_group,sg1,[sequence]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{end_per_group,sg1,[sequence]},ok}}],
+
+ [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,sg2,[sequence]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,sg2,[sequence]},ok}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc5}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc5,ok}},
+ {?eh,test_stats,{10,31,{0,14}}},
+ {?eh,tc_start,{timetrap_8_SUITE,tc0}},
+ {?eh,tc_done,{timetrap_8_SUITE,tc0,
+ {failed,{timetrap_timeout,{'$approx',1000}}}}},
+ {?eh,test_stats,{10,32,{0,14}}},
+ {?eh,tc_auto_skip,{timetrap_8_SUITE,tc1,
+ {failed,{timetrap_8_SUITE,tc0}}}},
+ {?eh,test_stats,{10,32,{0,15}}},
+ {?eh,tc_auto_skip,{timetrap_8_SUITE,tc2,
+ {failed,{timetrap_8_SUITE,tc0}}}},
+ {?eh,test_stats,{10,32,{0,16}}},
+ {?eh,tc_start,{timetrap_8_SUITE,{end_per_group,sg2,[sequence]}}},
+ {?eh,tc_done,{timetrap_8_SUITE,{end_per_group,sg2,[sequence]},ok}}],
+
+ {?eh,tc_start,{timetrap_8_SUITE,end_per_suite}},
+ {?eh,tc_done,{timetrap_8_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}
+ ];
+
test_events(misc_errors) ->
[
{?eh,start_logging,{'DEF','RUNDIR'}},
{?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
- {?eh,start_info,{1,1,7}},
+ {?eh,start_info,{1,1,9}},
{?eh,tc_start,{misc_error_1_SUITE,ct_fail_1}},
{?eh,tc_done,{misc_error_1_SUITE,ct_fail_1,
{failed,{error,{test_case_failed,{error,this_is_expected}}}}}},
@@ -1002,7 +1431,12 @@ test_events(misc_errors) ->
{?eh,tc_start,{misc_error_1_SUITE,killed_by_signal_2}},
{?eh,tc_done,{misc_error_1_SUITE,killed_by_signal_2,
{failed,testcase_aborted_or_killed}}},
- {?eh,test_stats,{0,7,{0,0}}},
+ {parallel,
+ [{?eh,tc_start,{misc_error_1_SUITE,p1}},
+ {?eh,tc_done,{misc_error_1_SUITE,p1,ok}},
+ {?eh,tc_start,{misc_error_1_SUITE,p2}},
+ {?eh,tc_done,{misc_error_1_SUITE,p2,ok}}]},
+ {?eh,test_stats,{2,7,{0,0}}},
{?eh,test_done,{'DEF','STOP_TIME'}},
{?eh,stop_logging,[]}
].
diff --git a/lib/common_test/test/ct_error_SUITE_data/error/test/misc_error_1_SUITE.erl b/lib/common_test/test/ct_error_SUITE_data/error/test/misc_error_1_SUITE.erl
index 99c3ed05ec..61f3fa7e59 100644
--- a/lib/common_test/test/ct_error_SUITE_data/error/test/misc_error_1_SUITE.erl
+++ b/lib/common_test/test/ct_error_SUITE_data/error/test/misc_error_1_SUITE.erl
@@ -96,7 +96,7 @@ end_per_testcase(_TestCase, _Config) ->
%% N = integer() | forever
%%--------------------------------------------------------------------
groups() ->
- [].
+ [{p,[parallel],[p1,p2]}].
%%--------------------------------------------------------------------
%% Function: all() -> GroupsAndTestCases | {skip,Reason}
@@ -107,7 +107,8 @@ groups() ->
%%--------------------------------------------------------------------
all() ->
[ct_fail_1, ct_fail_2, ct_fail_3, ts_fail_1, ts_fail_2,
- killed_by_signal_1, killed_by_signal_2].
+ killed_by_signal_1, killed_by_signal_2,
+ {group,p}].
ct_fail_1(_) ->
ct:fail({error,this_is_expected}),
@@ -152,3 +153,10 @@ killed_by_signal_2(_) ->
end),
ct:sleep(1000),
exit(this_should_not_be_seen).
+
+p1(_) ->
+ {error,parallel_group} = ct:abort_current_testcase(aborted),
+ ok.
+
+p2(_) ->
+ receive after 1000 -> ok end.
diff --git a/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_8_SUITE.erl b/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_8_SUITE.erl
new file mode 100644
index 0000000000..ff138f38b5
--- /dev/null
+++ b/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_8_SUITE.erl
@@ -0,0 +1,258 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012. All Rights Reserved.
+%%
+%% The 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(timetrap_8_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+-define(TO, 4).
+
+%%--------------------------------------------------------------------
+%% Function: suite() -> Info
+%% Info = [tuple()]
+%%--------------------------------------------------------------------
+suite() ->
+ [{timetrap,{timetrap_utils,timetrap_val,[{seconds,?TO}]}}].
+
+%%--------------------------------------------------------------------
+%% Function: init_per_suite(Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Function: end_per_suite(Config0) -> void() | {save_config,Config1}
+%% Config0 = Config1 = [tuple()]
+%%--------------------------------------------------------------------
+end_per_suite(_Config) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% Function: init_per_group(GroupName, Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%% GroupName = atom()
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%%--------------------------------------------------------------------
+init_per_group(G6, Config) when G6==g6; G6==pg6 ->
+ ct:sleep({seconds,1}),
+ Config;
+init_per_group(_GroupName, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Function: end_per_group(GroupName, Config0) ->
+%% void() | {save_config,Config1}
+%% GroupName = atom()
+%% Config0 = Config1 = [tuple()]
+%%--------------------------------------------------------------------
+end_per_group(G7or8, _Config) when G7or8==g7; G7or8==pg7; G7or8==g8; G7or8==pg8 ->
+ ct:sleep({seconds,5}),
+ ok;
+end_per_group(_GroupName, _Config) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% Function: init_per_testcase(TestCase, Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%% TestCase = atom()
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%%--------------------------------------------------------------------
+init_per_testcase(_, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Function: end_per_testcase(TestCase, Config0) ->
+%% void() | {save_config,Config1}
+%% TestCase = atom()
+%% Config0 = Config1 = [tuple()]
+%%--------------------------------------------------------------------
+end_per_testcase(_, _Config) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% Function: groups() -> [Group]
+%% Group = {GroupName,Properties,GroupsAndTestCases}
+%% GroupName = atom()
+%% Properties = [parallel | sequence | Shuffle | {RepeatType,N}]
+%% GroupsAndTestCases = [Group | {group,GroupName} | TestCase]
+%% TestCase = atom()
+%% Shuffle = shuffle | {shuffle,{integer(),integer(),integer()}}
+%% RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail |
+%% repeat_until_any_ok | repeat_until_any_fail
+%% N = integer() | forever
+%%--------------------------------------------------------------------
+groups() ->
+ [
+ {g0,[],[tc0,tc2]}, % group override suite and tc overrides group
+ {g1,[],[tc0,tc2]}, % group override suite and tc overrides group
+ {g2,[],[tc1,tc2]}, % tc override group
+ {g3,[],[tc4,{group,g1},{group,g2}]}, % subgroup override group
+ {g4,[],[tc0,tc2]}, % exit during init_per_group
+ {g5,[],[tc0,tc2]}, % exit during init_per_group
+ {g6,[],[tc0,tc2]}, % timeout during init_per_group
+ {g7,[],[tc5]}, % exit during end_per_group
+ {g8,[],[tc5]}, % timeout during end_per_group
+ {g9,[],[tc5,tc0]}, % exit during testcase
+ {g10,[],[tc0,tc5]}, % exit during testcase
+ {g11,[],[tc3,tc2]}, % suite is valid if nothing else is specified
+ {pg0,[parallel],[tc0,tc2]}, % group override suite and tc overrides group
+ {pg1,[parallel],[tc0,tc2]}, % group override suite and tc overrides group
+ {pg2,[parallel],[tc1,tc2]}, % tc override group
+ {pg3,[parallel],[tc4,{group,pg1},{group,pg2}]}, % subgroup override group
+ {pg4,[parallel],[tc0,tc2]}, % exit during init_per_group
+ {pg5,[parallel],[tc0,tc2]}, % exit during init_per_group
+ {pg6,[parallel],[tc0,tc2]}, % timeout during init_per_group
+ {pg7,[parallel],[tc5]}, % exit during end_per_group
+ {pg8,[parallel],[tc5]}, % timeout during end_per_group
+ {pg9,[parallel],[tc5,tc0]}, % exit during testcase
+ {pg10,[parallel],[tc0,tc5]},% exit during testcase
+ {pg11,[parallel],[tc3,tc2]},% suite is valid if nothing else is specified
+ {sg1,[sequence],[tc5,tc0,tc1,tc2]}, % exit during sequencial testcase
+ {sg2,[sequence],[tc5,tc0,tc1,tc2]}].% timeout during sequencial testcase
+
+group(g0) ->
+ [{timetrap,{timetrap_utils,timetrap_val,[{seconds,1}]}}];
+group(g1) ->
+ [{timetrap,fun() -> timetrap_utils:timetrap_val(1000) end}];
+group(g2) ->
+ [{timetrap,fun() -> timetrap_utils:timetrap_val(3000) end}];
+group(g3) ->
+ [{timetrap,fun() -> timetrap_utils:timetrap_val(2000) end}];
+group(g4) ->
+ [{timetrap,{timetrap_utils,timetrap_exit,[kaboom]}}];
+group(g5) ->
+ [{timetrap,fun() -> exit(kaboom) end}];
+group(g6) ->
+ [{timetrap,{timetrap_utils,timetrap_val,[500]}}];
+group(g7) ->
+ [{timetrap,fun() -> ct:sleep(1000),exit(kaboom) end}];
+group(g8) ->
+ [{timetrap,{timetrap_utils,timetrap_val,[500]}}];
+group(g9) ->
+ [{timetrap,fun() -> ct:sleep(1000),exit(kaboom) end}];
+group(g10) ->
+ [{timetrap,fun() -> ct:sleep(1000),exit(kaboom) end}];
+group(g11) ->
+ [];
+group(pg0) ->
+ [{timetrap,{timetrap_utils,timetrap_val,[{seconds,1}]}}];
+group(pg1) ->
+ [{timetrap,fun() -> timetrap_utils:timetrap_val(1000) end}];
+group(pg2) ->
+ [{timetrap,fun() -> timetrap_utils:timetrap_val(3000) end}];
+group(pg3) ->
+ [{timetrap,fun() -> timetrap_utils:timetrap_val(2000) end}];
+group(pg4) ->
+ [{timetrap,{timetrap_utils,timetrap_exit,[kaboom]}}];
+group(pg5) ->
+ [{timetrap,fun() -> exit(kaboom) end}];
+group(pg6) ->
+ [{timetrap,{timetrap_utils,timetrap_val,[500]}}];
+group(pg7) ->
+ [{timetrap,fun() -> ct:sleep(1000),exit(kaboom) end}];
+group(pg8) ->
+ [{timetrap,{timetrap_utils,timetrap_val,[500]}}];
+group(pg9) ->
+ [{timetrap,fun() -> ct:sleep(1000),exit(kaboom) end}];
+group(pg10) ->
+ [{timetrap,fun() -> ct:sleep(1000),exit(kaboom) end}];
+group(pg11) ->
+ [];
+group(sg1) ->
+ [{timetrap,fun() -> ct:sleep(1000),exit(kaboom) end}];
+group(sg2) ->
+ [{timetrap,{timetrap_utils,timetrap_val,[{seconds,1}]}}].
+
+
+%%--------------------------------------------------------------------
+%% Function: all() -> GroupsAndTestCases | {skip,Reason}
+%% GroupsAndTestCases = [{group,GroupName} | TestCase]
+%% GroupName = atom()
+%% TestCase = atom()
+%% Reason = term()
+%%--------------------------------------------------------------------
+all() ->
+ [
+ {group,g0},
+ {group,g1},
+ {group,g2},
+ {group,g3},
+ {group,g4},
+ {group,g5},
+ {group,g6},
+ {group,g7},
+ {group,g8},
+ {group,g9},
+ {group,g10},
+ {group,g11},
+ {group,pg0},
+ {group,pg1},
+ {group,pg2},
+ {group,pg3},
+ {group,pg4},
+ {group,pg5},
+ {group,pg6},
+ {group,pg7},
+ {group,pg8},
+ {group,pg9},
+ {group,pg10},
+ {group,pg11},
+ {group,sg1},
+ {group,sg2}].
+
+
+
+tc0(_) ->
+ ct:comment("TO set by group"),
+ ct:sleep({seconds,5}),
+ ok.
+
+tc1() ->
+ [{timetrap,{timetrap_utils,timetrap_val,[1000]}}].
+tc1(_) ->
+ ct:comment("TO after 1 sec"),
+ ct:sleep({seconds,2}),
+ ok.
+
+tc2() ->
+ [{timetrap,fun() -> timetrap_utils:timetrap_val(500) end}].
+tc2(_) ->
+ ct:comment("TO after 0.5 sec"),
+ ct:sleep({seconds,2}),
+ ok.
+
+tc3(_) ->
+ ct:comment(io_lib:format("TO after ~w sec", [?TO])),
+ ct:sleep({seconds,5}),
+ ok.
+
+tc4(_) ->
+ ct:comment("TO set by group"),
+ ct:sleep({seconds,5}),
+ ok.
+
+tc5(_) ->
+ ct:comment("No TO in this testcase, maybe later"),
+ ok.
diff --git a/lib/common_test/test/ct_group_leader_SUITE.erl b/lib/common_test/test/ct_group_leader_SUITE.erl
new file mode 100644
index 0000000000..cde3061d6a
--- /dev/null
+++ b/lib/common_test/test/ct_group_leader_SUITE.erl
@@ -0,0 +1,181 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012. All Rights Reserved.
+%%
+%% The 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%
+%%
+
+%%%-------------------------------------------------------------------
+%%% File: ct_system_error_SUITE
+%%%
+%%% Description:
+%%%
+%%% Test the group leader functionality in the test_server application.
+%%%-------------------------------------------------------------------
+-module(ct_group_leader_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("common_test/include/ct_event.hrl").
+
+-define(eh, ct_test_support_eh).
+
+%%--------------------------------------------------------------------
+%% TEST SERVER CALLBACK FUNCTIONS
+%%--------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% Description: Since Common Test starts another Test Server
+%% instance, the tests need to be performed on a separate node (or
+%% there will be clashes with logging processes etc).
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ Config1 = ct_test_support:init_per_suite(Config),
+ Config1.
+
+end_per_suite(Config) ->
+ ct_test_support:end_per_suite(Config).
+
+init_per_testcase(TestCase, Config) ->
+ ct_test_support:init_per_testcase(TestCase, Config).
+
+end_per_testcase(TestCase, Config) ->
+ ct_test_support:end_per_testcase(TestCase, Config).
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [
+ basic
+ ].
+
+%%--------------------------------------------------------------------
+%% TEST CASES
+%%--------------------------------------------------------------------
+
+%%%-----------------------------------------------------------------
+%%%
+basic(Config) ->
+ TC = basic,
+ DataDir = ?config(data_dir, Config),
+ Suite = filename:join(DataDir, "group_leader_SUITE"),
+ {Opts,ERPid} = setup([{suite,Suite},{label,TC}], Config),
+ SuiteLog = execute(TC, Opts, ERPid, Config),
+ {ok,Data} = file:read_file(SuiteLog),
+ Lines = binary:split(Data, <<"\n">>, [global]),
+ {ok,RE} = re:compile("(\\S+):(\\S+)$"),
+ Cases0 = [begin
+ {match,[M,F]} = re:run(Case, RE, [{capture,all_but_first,list}]),
+ {list_to_atom(M),list_to_atom(F)}
+ end || <<"=case ",Case/binary>> <- Lines],
+ Cases = [MF || {_,F}=MF <- Cases0,
+ F =/= init_per_suite,
+ F =/= end_per_suite,
+ F =/= init_per_group,
+ F =/= end_per_group],
+ io:format("~p\n", [Cases]),
+ [] = verify_cases(events_to_check(TC), Cases, false),
+ ok.
+
+verify_cases([{parallel,P}|Ts], Cases0, Par) ->
+ Cases = verify_cases(P, Cases0, true),
+ verify_cases(Ts, Cases, Par);
+verify_cases([{?eh,tc_done,{M,F,_}}|Ts], Cases0, false) ->
+ [{M,F}|Cases] = Cases0,
+ verify_cases(Ts, Cases, false);
+verify_cases([{?eh,tc_done,{M,F,_}}|Ts], Cases0, true) ->
+ case lists:member({M,F}, Cases0) of
+ true ->
+ Cases = Cases0 -- [{M,F}],
+ verify_cases(Ts, Cases, true);
+ false ->
+ io:format("~p not found\n", [{M,F}]),
+ ?t:fail()
+ end;
+verify_cases([{?eh,_,_}|Ts], Cases, Par) ->
+ verify_cases(Ts, Cases, Par);
+verify_cases([], Cases, _) ->
+ Cases;
+verify_cases([List|Ts], Cases0, Par) when is_list(List) ->
+ Cases = verify_cases(List, Cases0, false),
+ verify_cases(Ts, Cases, Par).
+
+%%%-----------------------------------------------------------------
+%%% HELP FUNCTIONS
+%%%-----------------------------------------------------------------
+
+setup(Test, Config) ->
+ Opts0 = ct_test_support:get_opts(Config),
+ Level = ?config(trace_level, Config),
+ EvHArgs = [{cbm,ct_test_support},{trace_level,Level}],
+ Opts = Opts0 ++ [{event_handler,{?eh,EvHArgs}}|Test],
+ ERPid = ct_test_support:start_event_receiver(Config),
+ {Opts,ERPid}.
+
+execute(Name, Opts, ERPid, Config) ->
+ ok = ct_test_support:run(Opts, Config),
+ Events = ct_test_support:get_events(ERPid, Config),
+
+ ct_test_support:log_events(Name,
+ reformat(Events, ?eh),
+ ?config(priv_dir, Config),
+ Opts),
+
+ TestEvents = events_to_check(Name),
+ ok = ct_test_support:verify_events(TestEvents, Events, Config),
+ {event,tc_logfile,_,{_,File}} =
+ lists:keyfind(tc_logfile, 2, [Ev || {?eh,Ev} <- Events]),
+ LogDir = filename:dirname(File),
+ filename:join(LogDir, "suite.log").
+
+reformat(Events, EH) ->
+ ct_test_support:reformat(Events, EH).
+
+%%%-----------------------------------------------------------------
+%%% TEST EVENTS
+%%%-----------------------------------------------------------------
+
+events_to_check(_Test) ->
+ [{?eh,tc_done,{group_leader_SUITE,tc1,ok}},
+ {parallel,[{?eh,tc_start,{group_leader_SUITE,p1}},
+ {?eh,tc_done,{group_leader_SUITE,p1,ok}},
+ {?eh,tc_start,{group_leader_SUITE,p2}},
+ {?eh,tc_done,{group_leader_SUITE,p2,ok}}]},
+ {?eh,tc_done,{group_leader_SUITE,p_restart_my_io_server,ok}},
+ {?eh,tc_done,{group_leader_SUITE,p3,ok}},
+ {parallel,[
+ {?eh,tc_start,{group_leader_SUITE,p10}},
+ {?eh,tc_start,{group_leader_SUITE,p11}},
+ {?eh,tc_done,{group_leader_SUITE,p10,ok}},
+ {?eh,tc_done,{group_leader_SUITE,p11,ok}},
+ [{?eh,tc_done,{group_leader_SUITE,s1,ok}},
+ {?eh,tc_done,{group_leader_SUITE,s2,ok}},
+ {?eh,tc_done,{group_leader_SUITE,s3,ok}}],
+ {?eh,tc_start,{group_leader_SUITE,p12}},
+ {?eh,tc_done,{group_leader_SUITE,p12,ok}},
+ [{?eh,tc_done,{group_leader_SUITE,s4,ok}},
+ {?eh,tc_done,{group_leader_SUITE,s5,ok}}],
+ {?eh,tc_start,{group_leader_SUITE,p13}},
+ {?eh,tc_done,{group_leader_SUITE,p13,ok}} ]},
+ {?eh,tc_done,{group_leader_SUITE,cap1,ok}},
+ {?eh,tc_done,{group_leader_SUITE,cap2,ok}},
+ {parallel,[{?eh,tc_start,{group_leader_SUITE,cap1}},
+ {?eh,tc_done,{group_leader_SUITE,cap1,ok}},
+ {?eh,tc_start,{group_leader_SUITE,cap2}},
+ {?eh,tc_done,{group_leader_SUITE,cap2,ok}}]},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}
+ ].
diff --git a/lib/common_test/test/ct_group_leader_SUITE_data/group_leader_SUITE.erl b/lib/common_test/test/ct_group_leader_SUITE_data/group_leader_SUITE.erl
new file mode 100644
index 0000000000..3f1844b4ae
--- /dev/null
+++ b/lib/common_test/test/ct_group_leader_SUITE_data/group_leader_SUITE.erl
@@ -0,0 +1,252 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012. All Rights Reserved.
+%%
+%% The 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(group_leader_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+%%--------------------------------------------------------------------
+%% @spec suite() -> Info
+%% Info = [tuple()]
+%% @end
+%%--------------------------------------------------------------------
+suite() ->
+ [{timetrap,{seconds,10}}].
+
+%%--------------------------------------------------------------------
+%% @spec init_per_suite(Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ start_my_io_server(),
+ Config.
+
+%%--------------------------------------------------------------------
+%% @spec end_per_suite(Config0) -> void() | {save_config,Config1}
+%% Config0 = Config1 = [tuple()]
+%% @end
+%%--------------------------------------------------------------------
+end_per_suite(_Config) ->
+ my_io_server ! die,
+ ok.
+
+%%--------------------------------------------------------------------
+%% @spec init_per_group(GroupName, Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%% GroupName = atom()
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+init_per_group(_GroupName, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% @spec end_per_group(GroupName, Config0) ->
+%% void() | {save_config,Config1}
+%% GroupName = atom()
+%% Config0 = Config1 = [tuple()]
+%% @end
+%%--------------------------------------------------------------------
+end_per_group(_GroupName, _Config) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% @spec init_per_testcase(TestCase, Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%% TestCase = atom()
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% @spec end_per_testcase(TestCase, Config0) ->
+%% void() | {save_config,Config1} | {fail,Reason}
+%% TestCase = atom()
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+end_per_testcase(_TestCase, _Config) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% @spec groups() -> [Group]
+%% Group = {GroupName,Properties,GroupsAndTestCases}
+%% GroupName = atom()
+%% Properties = [parallel | sequence | Shuffle | {RepeatType,N}]
+%% GroupsAndTestCases = [Group | {group,GroupName} | TestCase]
+%% TestCase = atom()
+%% Shuffle = shuffle | {shuffle,{integer(),integer(),integer()}}
+%% RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail |
+%% repeat_until_any_ok | repeat_until_any_fail
+%% N = integer() | forever
+%% @end
+%%--------------------------------------------------------------------
+groups() ->
+ [{p,[parallel],[p1,p2]},
+ {p_restart,[parallel],[p_restart_my_io_server]},
+ {seq,[],[s1,s2,s3]},
+ {seq2,[],[s4,s5]},
+ {seq_in_par,[parallel],[p10,p11,{group,seq},p12,{group,seq2},p13]},
+ {capture_io,[parallel],[cap1,cap2]}].
+
+%%--------------------------------------------------------------------
+%% @spec all() -> GroupsAndTestCases | {skip,Reason}
+%% GroupsAndTestCases = [{group,GroupName} | TestCase]
+%% GroupName = atom()
+%% TestCase = atom()
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+all() ->
+ [tc1,{group,p},{group,p_restart},p3,
+ {group,seq_in_par},
+ cap1,cap2,
+ {group,capture_io}].
+
+tc1(_C) ->
+ ok.
+
+p1(_) ->
+ %% OTP-10101:
+ %%
+ %% External apps/processes started by init_per_suite (common operation),
+ %% will inherit the group leader of the init_per_suite process, i.e. the
+ %% test_server test case control process (executing run_test_case_msgloop/7).
+ %% If, later, a parallel test case triggers the external app to print with
+ %% e.g. io:format() (also common operation), the calling process will hang!
+ %% The reason for this is that a parallel test case has a dedicated IO
+ %% server process, other than the central test case control process. The
+ %% latter process is not executing run_test_case_msgloop/7 and will not
+ %% respond to IO messages. The process is still group leader for the
+ %% external app, however, which is wrong. It's the IO process for the
+ %% parallel test case that should be group leader - but only for the
+ %% particular invokation, since other parallel test cases could be
+ %% invoking the external app too.
+ print("hej\n").
+
+p2(_) ->
+ print("hopp\n").
+
+p_restart_my_io_server(_) ->
+ %% Restart the IO server and change its group leader. This used
+ %% to set to the group leader to a process that would soon die.
+ Ref = erlang:monitor(process, my_io_server),
+ my_io_server ! die,
+ receive
+ {'DOWN',Ref,_,_,_} ->
+ start_my_io_server()
+ end.
+
+p3(_) ->
+ %% OTP-10125. This would crash since the group leader process
+ %% for the my_io_server had died.
+ print("hoppsan\n").
+
+print(String) ->
+ my_io_server ! {print,self(),String},
+ receive
+ {printed,String} ->
+ ok
+ end.
+
+start_my_io_server() ->
+ Parent = self(),
+ Pid = spawn(fun() -> my_io_server(Parent) end),
+ receive
+ {Pid,started} ->
+ io:format("~p\n", [process_info(Pid)]),
+ ok
+ end.
+
+my_io_server(Parent) ->
+ register(my_io_server, self()),
+ Parent ! {self(),started},
+ my_io_server_loop().
+
+my_io_server_loop() ->
+ receive
+ {print,From,String} ->
+ io:put_chars(String),
+ From ! {printed,String},
+ my_io_server_loop();
+ die ->
+ ok
+ end.
+
+p10(_) ->
+ receive after 1 -> ok end.
+
+p11(_) ->
+ ok.
+
+p12(_) ->
+ ok.
+
+p13(_) ->
+ ok.
+
+s1(_) ->
+ ok.
+
+s2(_) ->
+ ok.
+
+s3(_) ->
+ ok.
+
+s4(_) ->
+ ok.
+
+s5(_) ->
+ ok.
+
+cap1(_) ->
+ ct:capture_start(),
+ IO = gen_io(cap1, 10, []),
+ ct:capture_stop(),
+ IO = ct:capture_get(),
+ ok.
+
+cap2(_) ->
+ ct:capture_start(),
+ {Pid,Ref} = spawn_monitor(fun() ->
+ exit(gen_io(cap2, 42, []))
+ end),
+ receive
+ {'DOWN',Ref,process,Pid,IO} ->
+ ct:capture_stop(),
+ IO = ct:capture_get(),
+ ok
+ end.
+
+gen_io(_, 0, Acc) ->
+ lists:reverse(Acc);
+gen_io(Label, N, Acc) ->
+ S = lists:flatten(io_lib:format("~s: ~p\n", [Label,N])),
+ io:put_chars(S),
+ gen_io(Label, N-1, [S|Acc]).
diff --git a/lib/common_test/test/ct_groups_search_SUITE.erl b/lib/common_test/test/ct_groups_search_SUITE.erl
new file mode 100644
index 0000000000..6b1c1f4634
--- /dev/null
+++ b/lib/common_test/test/ct_groups_search_SUITE.erl
@@ -0,0 +1,1245 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
+%%
+%% The 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%
+%%
+
+%%%-------------------------------------------------------------------
+%%% File:
+%%%
+%%% Description:
+%%%
+%%%
+%%% The suites used for the test are located in the data directory.
+%%%
+%%% The group(s) and case(s) are specified according to this:
+%%%
+%%% Tests = ct_groups:find_groups(Mod, GroupPaths, TestCases, GroupDef)
+%%%
+%%% GroupPaths = GroupPath | [GroupPath]
+%%% GroupPath = atom() | [atom()]
+%%%
+%%% CT will find all paths that include GroupPath. GroupPath can be a
+%%% single group, or a list of groups along the path to TestCases.
+%%% If GroupPath is the latter, the last group in the list must be
+%%% the "terminating" group in the path, or it will be impossible to
+%%% execute test cases in higher level groups *only*, as in this case:
+%%% groups() -> [{g1,[],[tc1,{g2,[],[tc2]}]}].
+%%% Compare: find_groups(x, g1, all, groups()), and
+%%% find_groups(x, [[g1]], all, groups())
+%%%
+%%% Some examples:
+%%%
+%%% GroupPaths = g1, means find all paths with g1 included
+%%% GroupPaths = [g1], -''-
+%%% GroupPaths = [g1,g2], search twice - once for g1 and once for g2
+%%% GroupPaths = [[g1,g2]], find cases under group g1 and sub group g2
+%%% GroupPaths = [[g1,g2],[g1,g3]], find cases for g1-g2 AND g1-g3
+%%%
+%%% TestCases = all | atom() | [atom()]
+%%%
+%%%-------------------------------------------------------------------
+
+-module(ct_groups_search_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("common_test/src/ct_util.hrl").
+
+
+-define(eh, ct_test_support_eh).
+
+-define(M1, groups_search_dummy_1_SUITE).
+-define(M2, groups_search_dummy_2_SUITE).
+
+%%--------------------------------------------------------------------
+%% TEST SERVER CALLBACK FUNCTIONS
+%%--------------------------------------------------------------------
+
+init_per_suite(Config) ->
+ DataDir = proplists:get_value(data_dir, Config),
+ code:add_patha(DataDir),
+ M1Erl = filename:join(DataDir, atom_to_list(?M1)++".erl"),
+ M2Erl = filename:join(DataDir, atom_to_list(?M2)++".erl"),
+ {ok,?M1} = compile:file(M1Erl, [{outdir,DataDir}]),
+ {ok,?M2} = compile:file(M2Erl, [{outdir,DataDir}]),
+ {module,?M1} = code:load_file(?M1),
+ {module,?M2} = code:load_file(?M2),
+
+ Config1 = ct_test_support:init_per_suite(Config),
+ Config1.
+
+end_per_suite(Config) ->
+ ct_test_support:end_per_suite(Config).
+
+init_per_testcase(TestCase, Config) ->
+ ct_test_support:init_per_testcase(TestCase, Config).
+
+end_per_testcase(TestCase, Config) ->
+ ct_test_support:end_per_testcase(TestCase, Config).
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+groups() ->
+ [
+ {find_groups,[],[all_groups,
+ testcases_in_all_groups,
+ all_in_top_group1,
+ all_in_top_group2,
+ all_in_sub_group1,
+ all_in_sub_group2,
+ testcase_in_top_group1,
+ testcase_in_top_group2,
+ testcase_in_sub_group1,
+ testcase_in_sub_group2,
+ testcase_in_top_groups1,
+ testcase_in_top_groups2,
+ testcase_in_top_groups3,
+ testcase_in_top_groups4,
+ testcase_in_top_groups5,
+ testcase_in_top_groups6,
+ testcase_in_top_groups7,
+ testcase_in_sub_groups1,
+ testcase_in_sub_groups2,
+ testcase_in_sub_groups3,
+ testcase_in_sub_groups4,
+ testcase_in_sub_groups5,
+ testcase_in_sub_groups6,
+ testcase_in_sub_groups7,
+ testcase_in_sub_groups8,
+ testcase_in_sub_groups9,
+ testcase_in_sub_groups10,
+ testcase_in_sub_groups11,
+ testcase_in_sub_groups12,
+ testcase_in_sub_groups13,
+ bad_testcase_in_sub_groups1]},
+
+ {run_groups,[sequence],[run_groups_with_options,
+ run_groups_with_testspec]}
+ ].
+
+all() ->
+ [{group,find_groups,[parallel]},
+ {group,run_groups}].
+
+
+
+%%--------------------------------------------------------------------
+%% TEST CASES CHECKING RETURN VALUE ONLY
+%%--------------------------------------------------------------------
+
+all_groups(_) ->
+ GPath = all, TCs = all,
+
+ Found = ct_groups:find_groups(?M1, GPath, TCs, groups1()),
+
+ Top1 = ct_groups:find_groups(?M1, top1, TCs, groups1()),
+ Top2 = ct_groups:find_groups(?M1, top2, TCs, groups1()),
+
+ All = Top1 ++ Top2 ++ [{conf,[{name,sub2}],
+ {?M1,init_per_group},
+ [{?M1,sub2_tc1},{?M1,sub2_tc2}],
+ {?M1,end_per_group}}],
+
+ All = Found,
+
+ {?M1,GPath,TCs,Top1++Top2}.
+
+%%%-----------------------------------------------------------------
+%%%
+testcases_in_all_groups(_) ->
+ GPath = all, TCs = [tc3,sub_tc2],
+
+ Found = ct_groups:find_groups(?M2, GPath, TCs, groups2()),
+
+ [Top1 =
+ {conf,[{name,top1}],{?M2,init_per_group},
+ [{?M2,tc3},
+ {conf,[{name,sub11}],
+ {?M2,init_per_group},[{?M2,tc3},{?M2,sub_tc2}],
+ {?M2,end_per_group}},
+ {conf,[{name,sub12}],
+ {?M2,init_per_group},
+ [{?M2,tc3},{?M2,sub_tc2},
+ {conf,[{name,sub121}],
+ {?M2,init_per_group},[{?M2,tc3},{?M2,sub_tc2}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}},
+
+ Top2 =
+ {conf,[{name,top2}],{?M2,init_per_group},
+ [{?M2,tc3},
+ {conf,[{name,sub21}],
+ {?M2,init_per_group},
+ [{?M2,tc3},{?M2,sub_tc2},
+ {conf,[{name,sub2xx}],
+ {?M2,init_per_group},[{?M2,tc3},{?M2,sub_tc2}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}},
+
+ {conf,[{name,sub22}],
+ {?M2,init_per_group},
+ [{?M2,tc3},{?M2,sub_tc2},
+ {conf,[{name,sub221}],
+ {?M2,init_per_group},[{?M2,tc3},{?M2,sub_tc2}],
+ {?M2,end_per_group}},
+ {conf,[{name,sub2xx}],
+ {?M2,init_per_group},[{?M2,tc3},{?M2,sub_tc2}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}},
+
+ {conf,[{name,sub21}],
+ {?M2,init_per_group},
+ [{?M2,tc3},{?M2,sub_tc2},
+ {conf,[{name,sub2xx}],
+ {?M2,init_per_group},[{?M2,tc3},{?M2,sub_tc2}],{?M2,end_per_group}}],
+ {?M2,end_per_group}},
+
+ {conf,[{name,sub22}],
+ {?M2,init_per_group},
+ [{?M2,tc3},{?M2,sub_tc2},
+ {conf,[{name,sub221}],
+ {?M2,init_per_group},[{?M2,tc3},{?M2,sub_tc2}],{?M2,end_per_group}},
+ {conf,[{name,sub2xx}],
+ {?M2,init_per_group},[{?M2,tc3},{?M2,sub_tc2}],{?M2,end_per_group}}],
+ {?M2,end_per_group}},
+
+ {conf,[{name,sub221}],
+ {?M2,init_per_group},[{?M2,tc3},{?M2,sub_tc2}],{?M2,end_per_group}},
+
+ {conf,[{name,sub2xx}],
+ {?M2,init_per_group},[{?M2,tc3},{?M2,sub_tc2}],{?M2,end_per_group}}]
+
+ = Found,
+
+ {?M2,GPath,TCs,[Top1,Top2]}.
+
+%%%-----------------------------------------------------------------
+%%%
+all_in_top_group1(_) ->
+ GPath= top1, TCs = all,
+
+ Found = ct_groups:find_groups(?M1, GPath, TCs, groups1()),
+
+ [{conf,[{name,top1}],
+ {?M1,init_per_group},
+ [{?M1,top1_tc1},{?M1,top1_tc2},
+ {conf,[{name,sub1}],
+ {?M1,init_per_group},
+ [{?M1,sub1_tc1},{?M1,sub1_tc2}],
+ {?M1,end_per_group}}],
+ {?M1,end_per_group}}] = Found,
+
+ {?M1,GPath,TCs,Found}.
+
+%%%-----------------------------------------------------------------
+%%%
+all_in_top_group2(_) ->
+ GPath= top2, TCs = all,
+
+ Found = ct_groups:find_groups(?M1, GPath, TCs, groups1()),
+
+ [{conf,[{name,top2}],
+ {?M1,init_per_group},
+ [{conf,[{name,sub2}],
+ {?M1,init_per_group},
+ [{?M1,sub2_tc1},{?M1,sub2_tc2}],
+ {?M1,end_per_group}},
+ {?M1,top2_tc1},{?M1,top2_tc2}],
+ {?M1,end_per_group}}] = Found,
+
+ {?M1,GPath,TCs,Found}.
+
+%%%-----------------------------------------------------------------
+%%%
+all_in_sub_group1(_) ->
+ GPath = sub1, TCs = all,
+
+ Found = ct_groups:find_groups(?M1, GPath, TCs, groups1()),
+
+ [{conf,[{name,top1}],
+ {?M1,init_per_group},
+ [{conf,[{name,sub1}],
+ {?M1,init_per_group},
+ [{?M1,sub1_tc1},{?M1,sub1_tc2}],
+ {?M1,end_per_group}}],
+ {?M1,end_per_group}}] = Found,
+
+ {?M1,GPath,TCs,Found}.
+
+%%%-----------------------------------------------------------------
+%%%
+all_in_sub_group2(_) ->
+ GPath = sub2, TCs = all,
+
+ Found = ct_groups:find_groups(?M1, GPath, TCs, groups1()),
+
+ [Top2 =
+ {conf,[{name,top2}],
+ {?M1,init_per_group},
+ [{conf,[{name,sub2}],
+ {?M1,init_per_group},
+ [{?M1,sub2_tc1},{?M1,sub2_tc2}],
+ {?M1,end_per_group}}],
+ {?M1,end_per_group}},
+
+ {conf,[{name,sub2}],
+ {?M1,init_per_group},
+ [{?M1,sub2_tc1},{?M1,sub2_tc2}],
+ {?M1,end_per_group}}] = Found,
+
+ {?M1,GPath,TCs,Top2}.
+
+%%%-----------------------------------------------------------------
+%%%
+testcase_in_top_group1(_) ->
+ GPath = top1, TCs = [top1_tc2],
+
+ Found = ct_groups:find_groups(?M1, GPath, TCs, groups1()),
+
+ [{conf,[{name,top1}],
+ {?M1,init_per_group},
+ [{?M1,top1_tc2}],
+ {?M1,end_per_group}}] = Found,
+
+ {?M1,GPath,TCs,Found}.
+
+%%%-----------------------------------------------------------------
+%%%
+testcase_in_top_group2(_) ->
+ GPath = top2, TCs = [top2_tc2],
+
+ Found = ct_groups:find_groups(?M1, GPath, TCs, groups1()),
+
+ [{conf,[{name,top2}],
+ {?M1,init_per_group},
+ [{?M1,top2_tc2}],
+ {?M1,end_per_group}}] = Found,
+
+ {?M1,GPath,TCs,Found}.
+
+%%%-----------------------------------------------------------------
+%%%
+testcase_in_sub_group1(_) ->
+ GPath = sub1, TCs = [sub1_tc2],
+
+ Found = ct_groups:find_groups(?M1, GPath, TCs, groups1()),
+
+ [{conf,[{name,top1}],
+ {?M1,init_per_group},
+ [{conf,[{name,sub1}],
+ {?M1,init_per_group},
+ [{?M1,sub1_tc2}],
+ {?M1,end_per_group}}],
+ {?M1,end_per_group}}] = Found,
+
+ {?M1,GPath,TCs,Found}.
+
+%%%-----------------------------------------------------------------
+%%%
+testcase_in_sub_group2(_) ->
+ GPath = sub2, TCs = [sub2_tc2],
+
+ Found = ct_groups:find_groups(?M1, GPath, TCs, groups1()),
+
+ [Top2 =
+ {conf,[{name,top2}],
+ {?M1,init_per_group},
+ [{conf,[{name,sub2}],
+ {?M1,init_per_group},
+ [{?M1,sub2_tc2}],
+ {?M1,end_per_group}}],
+ {?M1,end_per_group}},
+
+ {conf,[{name,sub2}],
+ {?M1,init_per_group},
+ [{?M1,sub2_tc2}],
+ {?M1,end_per_group}}] = Found,
+
+ {?M1,GPath,TCs,Top2}.
+
+%%%-----------------------------------------------------------------
+%%%
+testcase_in_top_groups1(_) ->
+ GPath = [top1,top2], TCs = all,
+
+ Found = ct_groups:find_groups(?M2, GPath, TCs, groups2()),
+
+ [{conf,[{name,top1}],
+ {?M2,init_per_group},
+ [{?M2,top1_tc1},{?M2,top_tc2},{?M2,tc3},
+ {conf,[{name,sub11}],
+ {?M2,init_per_group},
+ [{?M2,sub11_tc1},{?M2,sub_tc2},{?M2,tc3}],
+ {?M2,end_per_group}},
+ {conf,[{name,sub12}],
+ {?M2,init_per_group},
+ [{?M2,sub12_tc1},{?M2,sub_tc2},{?M2,tc3},
+ {conf,[{name,sub121}],
+ {?M2,init_per_group},
+ [{?M2,sub121_tc1},{?M2,sub_tc2},{?M2,tc3}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}},
+
+ {conf,[{name,top2}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub21}],
+ {?M2,init_per_group},
+ [{?M2,sub21_tc1},{?M2,sub_tc2},{?M2,tc3},
+ {conf,[{name,sub2xx}],
+ {?M2,init_per_group},
+ [{?M2,sub2xx_tc1},{?M2,sub_tc2},{?M2,tc3}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}},
+ {?M2,top2_tc1},{?M2,top_tc2},{?M2,tc3},
+ {conf,[{name,sub22}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub221}],
+ {?M2,init_per_group},
+ [{?M2,sub221_tc1},{?M2,sub_tc2},{?M2,tc3}],
+ {?M2,end_per_group}},
+ {?M2,sub22_tc1},{?M2,sub_tc2},{?M2,tc3},
+ {conf,[{name,sub2xx}],
+ {?M2,init_per_group},
+ [{?M2,sub2xx_tc1},{?M2,sub_tc2},{?M2,tc3}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}] = Found,
+
+ {?M2,GPath,TCs,Found}.
+
+%%%-----------------------------------------------------------------
+%%%
+testcase_in_top_groups2(_) ->
+ GPath = [top1,top2], TCs = tc3,
+
+ Found = ct_groups:find_groups(?M2, GPath, TCs, groups2()),
+
+ [{conf,[{name,top1}],
+ {?M2,init_per_group},
+ [{?M2,tc3},
+ {conf,[{name,sub11}],
+ {?M2,init_per_group},
+ [{?M2,tc3}],
+ {?M2,end_per_group}},
+ {conf,[{name,sub12}],
+ {?M2,init_per_group},
+ [{?M2,tc3},
+ {conf,[{name,sub121}],
+ {?M2,init_per_group},
+ [{?M2,tc3}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}},
+
+ {conf,[{name,top2}],
+ {?M2,init_per_group},
+ [{?M2,tc3},
+ {conf,[{name,sub21}],
+ {?M2,init_per_group},
+ [{?M2,tc3},
+ {conf,[{name,sub2xx}],
+ {?M2,init_per_group},
+ [{?M2,tc3}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}},
+
+ {conf,[{name,sub22}],
+ {?M2,init_per_group},
+ [{?M2,tc3},
+ {conf,[{name,sub221}],
+ {?M2,init_per_group},
+ [{?M2,tc3}],
+ {?M2,end_per_group}},
+ {conf,[{name,sub2xx}],
+ {?M2,init_per_group},
+ [{?M2,tc3}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}] = Found,
+
+ {?M2,GPath,TCs,Found}.
+
+%%%-----------------------------------------------------------------
+%%%
+testcase_in_top_groups3(_) ->
+ GPath = [top1,top2], TCs = top1_tc1,
+
+ Found = ct_groups:find_groups(?M2, GPath, TCs, groups2()),
+
+ [{conf,[{name,top1}],
+ {?M2,init_per_group},
+ [{?M2,top1_tc1}],
+ {?M2,end_per_group}}] = Found,
+
+ {?M2,GPath,TCs,Found}.
+
+%%%-----------------------------------------------------------------
+%%%
+testcase_in_top_groups4(_) ->
+ GPath = [top1,top2], TCs = sub2xx_tc1,
+
+ Found = ct_groups:find_groups(?M2, GPath, TCs, groups2()),
+
+ [{conf,[{name,top2}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub21}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub2xx}],
+ {?M2,init_per_group},
+ [{?M2,sub2xx_tc1}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}},
+ {conf,[{name,sub22}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub2xx}],
+ {?M2,init_per_group},
+ [{?M2,sub2xx_tc1}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}] = Found,
+
+ {?M2,GPath,TCs,Found}.
+
+%%%-----------------------------------------------------------------
+%%%
+testcase_in_top_groups5(_) ->
+ GPath = [top1,top2], TCs = [sub21_tc1,sub22_tc1],
+
+ Found = ct_groups:find_groups(?M2, [top1,top2], [sub21_tc1,sub22_tc1],
+ groups2()),
+
+ [{conf,[{name,top2}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub21}],
+ {?M2,init_per_group},
+ [{?M2,sub21_tc1}],
+ {?M2,end_per_group}},
+ {conf,[{name,sub22}],
+ {?M2,init_per_group},
+ [{?M2,sub22_tc1}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}] = Found,
+
+ {?M2,GPath,TCs,Found}.
+
+%%%-----------------------------------------------------------------
+%%%
+testcase_in_top_groups6(_) ->
+ GPath = [[top1],[top2]], TCs = tc3,
+
+ Found = ct_groups:find_groups(?M2, GPath, TCs, groups2()),
+
+ [{conf,[{name,top1}],
+ {?M2,init_per_group},
+ [{?M2,tc3}],
+ {?M2,end_per_group}},
+ {conf,[{name,top2}],
+ {?M2,init_per_group},
+ [{?M2,tc3}],
+ {?M2,end_per_group}}] = Found,
+
+ {?M2,GPath,TCs,Found}.
+
+%%%-----------------------------------------------------------------
+%%%
+testcase_in_top_groups7(_) ->
+ GPath = [[top1],[top2]], TCs = all,
+
+ Found = ct_groups:find_groups(?M2, GPath, TCs, groups2()),
+
+ [{conf,[{name,top1}],
+ {?M2,init_per_group},
+ [{?M2,top1_tc1},
+ {?M2,top_tc2},
+ {?M2,tc3}],
+ {?M2,end_per_group}},
+ {conf,[{name,top2}],
+ {?M2,init_per_group},
+ [{?M2,top2_tc1},
+ {?M2,top_tc2},
+ {?M2,tc3}],
+ {?M2,end_per_group}}] = Found,
+
+ {?M2,GPath,TCs,Found}.
+
+%%%-----------------------------------------------------------------
+%%%
+testcase_in_sub_groups1(_) ->
+ GPath = [sub121], TCs = tc3,
+
+ Found = ct_groups:find_groups(?M2, sub121, tc3, groups2()),
+ Found = ct_groups:find_groups(?M2, [sub121], tc3, groups2()),
+
+ [{conf,[{name,top1}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub12}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub121}],
+ {?M2,init_per_group},
+ [{?M2,tc3}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}] = Found,
+
+ {?M2,GPath,TCs,Found}.
+
+%%%-----------------------------------------------------------------
+%%%
+testcase_in_sub_groups2(_) ->
+ GPath = sub12, TCs = tc3,
+
+ Found = ct_groups:find_groups(?M2, sub12, tc3, groups2()),
+ Found = ct_groups:find_groups(?M2, [sub12], tc3, groups2()),
+
+ [{conf,[{name,top1}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub12}],
+ {?M2,init_per_group},
+ [{?M2,tc3},
+ {conf,[{name,sub121}],
+ {?M2,init_per_group},
+ [{?M2,tc3}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}] = Found,
+
+ FoundX = ct_groups:find_groups(?M2, [[sub12]], tc3, groups2()),
+
+ [{conf,[{name,top1}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub12}],
+ {?M2,init_per_group},
+ [{?M2,tc3}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}] = FoundX,
+
+ {?M2,GPath,TCs,Found}.
+
+%%%-----------------------------------------------------------------
+%%%
+testcase_in_sub_groups3(_) ->
+ GPath = [sub121,sub221], TCs = all,
+
+ Found = ct_groups:find_groups(?M2, GPath, TCs, groups2()),
+
+ [Top1 =
+ {conf,[{name,top1}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub12}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub121}],
+ {?M2,init_per_group},
+ [{?M2,sub121_tc1},
+ {?M2,sub_tc2},
+ {?M2,tc3}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}},
+
+ Top2 =
+ {conf,[{name,top2}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub22}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub221}],
+ {?M2,init_per_group},
+ [{?M2,sub221_tc1},
+ {?M2,sub_tc2},
+ {?M2,tc3}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}},
+
+ {conf,[{name,sub22}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub221}],
+ {?M2,init_per_group},
+ [{?M2,sub221_tc1},
+ {?M2,sub_tc2},
+ {?M2,tc3}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}},
+
+ {conf,[{name,sub221}],
+ {?M2,init_per_group},
+ [{?M2,sub221_tc1},
+ {?M2,sub_tc2},
+ {?M2,tc3}],
+ {?M2,end_per_group}}] = Found,
+
+ {?M2,GPath,TCs,[Top1,Top2]}.
+
+%%%-----------------------------------------------------------------
+%%%
+testcase_in_sub_groups4(_) ->
+ GPath = [top1,sub21], TCs = sub_tc2,
+
+ Found = ct_groups:find_groups(?M2, GPath, TCs, groups2()),
+
+ [Top1 =
+ {conf,[{name,top1}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub11}],
+ {?M2,init_per_group},
+ [{?M2,sub_tc2}],
+ {?M2,end_per_group}},
+ {conf,[{name,sub12}],
+ {?M2,init_per_group},
+ [{?M2,sub_tc2},
+ {conf,[{name,sub121}],
+ {?M2,init_per_group},
+ [{?M2,sub_tc2}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}},
+
+ Top2 =
+ {conf,[{name,top2}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub21}],
+ {?M2,init_per_group},
+ [{?M2,sub_tc2},
+ {conf,[{name,sub2xx}],
+ {?M2,init_per_group},
+ [{?M2,sub_tc2}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}},
+
+ {conf,[{name,sub21}],
+ {?M2,init_per_group},
+ [{?M2,sub_tc2},
+ {conf,[{name,sub2xx}],
+ {?M2,init_per_group},
+ [{?M2,sub_tc2}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}] = Found,
+
+ {?M2,GPath,TCs,[Top1,Top2]}.
+
+%%%-----------------------------------------------------------------
+%%%
+testcase_in_sub_groups5(_) ->
+ GPath = [[top1,sub12]], TCs = sub12_tc1,
+
+ Found = ct_groups:find_groups(?M2, GPath, TCs, groups2()),
+
+ [{conf,[{name,top1}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub12}],
+ {?M2,init_per_group},
+ [{?M2,sub12_tc1}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}] = Found,
+
+ {?M2,GPath,TCs,Found}.
+
+%%%-----------------------------------------------------------------
+%%%
+testcase_in_sub_groups6(_) ->
+ GPath = [[top1,sub12]], TCs = [sub_tc2],
+
+ Found = ct_groups:find_groups(?M2, GPath, TCs, groups2()),
+
+ [{conf,[{name,top1}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub12}],
+ {?M2,init_per_group},
+ [{?M2,sub_tc2}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}] = Found,
+
+ {?M2,GPath,TCs,Found}.
+
+%%%-----------------------------------------------------------------
+%%%
+testcase_in_sub_groups7(_) ->
+ GPath = [[top1,sub12]], TCs = [sub12_tc1,sub_tc2],
+
+ Found = ct_groups:find_groups(?M2, GPath, TCs, groups2()),
+
+ [{conf,[{name,top1}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub12}],
+ {?M2,init_per_group},
+ [{?M2,sub12_tc1},
+ {?M2,sub_tc2}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}] = Found,
+
+ {?M2,GPath,TCs,Found}.
+
+%%%-----------------------------------------------------------------
+%%%
+testcase_in_sub_groups8(_) ->
+ GPath = [[top2,sub22]], TCs = [sub22_tc1,sub_tc2],
+
+ Found = ct_groups:find_groups(?M2, GPath, TCs, groups2()),
+
+ [{conf,[{name,top2}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub22}],
+ {?M2,init_per_group},
+ [{?M2,sub22_tc1},
+ {?M2,sub_tc2}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}] = Found,
+
+ {?M2,GPath,TCs,Found}.
+
+%%%-----------------------------------------------------------------
+%%%
+testcase_in_sub_groups9(_) ->
+ GPath = [[sub2xx]], TCs = tc3,
+
+ Found = ct_groups:find_groups(?M2, sub2xx, tc3, groups2()),
+ Found = ct_groups:find_groups(?M2, [[sub2xx]], tc3, groups2()),
+
+ [Top2 =
+ {conf,[{name,top2}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub21}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub2xx}],
+ {?M2,init_per_group},
+ [{?M2,tc3}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}},
+ {conf,[{name,sub22}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub2xx}],
+ {?M2,init_per_group},
+ [{?M2,tc3}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}},
+
+ {conf,[{name,sub21}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub2xx}],
+ {?M2,init_per_group},
+ [{?M2,tc3}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}},
+
+ {conf,[{name,sub22}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub2xx}],
+ {?M2,init_per_group},
+ [{?M2,tc3}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}},
+
+ {conf,[{name,sub2xx}],
+ {?M2,init_per_group},
+ [{?M2,tc3}],
+ {?M2,end_per_group}}] = Found,
+
+ {?M2,GPath,TCs,Top2}.
+
+%%%-----------------------------------------------------------------
+%%%
+testcase_in_sub_groups10(_) ->
+ GPath = [[sub22,sub2xx]], TCs = tc3,
+
+ Found = ct_groups:find_groups(?M2, GPath, TCs, groups2()),
+
+ [Top2 =
+ {conf,[{name,top2}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub22}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub2xx}],
+ {?M2,init_per_group},
+ [{?M2,tc3}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}},
+
+ {conf,[{name,sub22}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub2xx}],
+ {?M2,init_per_group},
+ [{?M2,tc3}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}] = Found,
+
+ {?M2,GPath,TCs,Top2}.
+
+%%%-----------------------------------------------------------------
+%%%
+testcase_in_sub_groups11(_) ->
+ GPath = [[top1,sub12,sub121]], TCs = all,
+
+ Found = ct_groups:find_groups(?M2, GPath, TCs, groups2()),
+
+ [{conf,[{name,top1}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub12}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub121}],
+ {?M2,init_per_group},
+ [{?M2,sub121_tc1},
+ {?M2,sub_tc2},
+ {?M2,tc3}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}] = Found,
+
+ {?M2,GPath,TCs,Found}.
+
+%%%-----------------------------------------------------------------
+%%%
+testcase_in_sub_groups12(_) ->
+ GPath = [[top2,sub2xx]], TCs = [sub2xx_tc1,tc3],
+
+ Found = ct_groups:find_groups(?M2, GPath, TCs, groups2()),
+
+ [{conf,[{name,top2}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub21}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub2xx}],
+ {?M2,init_per_group},
+ [{?M2,sub2xx_tc1},
+ {?M2,tc3}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}},
+ {conf,[{name,sub22}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub2xx}],
+ {?M2,init_per_group},
+ [{?M2,sub2xx_tc1},
+ {?M2,tc3}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}] = Found,
+
+ {?M2,GPath,TCs,Found}.
+
+%%%-----------------------------------------------------------------
+%%%
+testcase_in_sub_groups13(_) ->
+ GPath = [[top2,sub22,sub2xx]], TCs = [top2_tc1,sub2xx_tc1,tc3],
+
+ Found = ct_groups:find_groups(?M2, GPath, TCs, groups2()),
+
+ [{conf,[{name,top2}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub22}],
+ {?M2,init_per_group},
+ [{conf,[{name,sub2xx}],
+ {?M2,init_per_group},
+ [{?M2,sub2xx_tc1},
+ {?M2,tc3}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}],
+ {?M2,end_per_group}}] = Found,
+
+ {?M2,GPath,TCs,Found}.
+
+%%%-----------------------------------------------------------------
+%%%
+bad_testcase_in_sub_groups1(_) ->
+ GPath = [sub2xx], TCs = [top2_tc1],
+
+ Found = ct_groups:find_groups(?M2, GPath, TCs, groups2()),
+
+ [] = Found,
+
+ {?M2,GPath,TCs,Found}.
+
+%%%-----------------------------------------------------------------
+%%%
+bad_testcase_in_sub_groups2(_) ->
+ GPath = [sub12,sub2xx], TCs = [top1_tc1,top2_tc1],
+
+ Found = ct_groups:find_groups(?M2, GPath, TCs, groups2()),
+
+ [] = Found,
+
+ {?M2,GPath,TCs,Found}.
+
+%%%-----------------------------------------------------------------
+%%% CASES EXECUTING THE TESTS
+%%%-----------------------------------------------------------------
+
+run_groups_with_options(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ {M1All,M1Rest,M2All,M2Rest} = get_all_groups_and_cases(Config),
+
+ M1AllGrs = lists:flatmap(fun({Path,_,_}) when is_atom(hd(Path)) -> Path;
+ ({Path,_,_}) when is_list(hd(Path)) -> Path;
+ ({Path,_,_}) -> [Path]
+ end, M1All),
+
+ %% ct:pal("NOW RUNNING M1 TEST: ~p", [M1All]),
+
+ {OptsM11,ERPidM11} = setup([{dir,DataDir},{suite,?M1},
+ {group,M1AllGrs},{label,m1_all_cases}], Config),
+ M1AllGrInfo = {M1AllGrs,lists:flatten([Found || {_,_,Found} <- M1All])},
+ ok = execute(m1_all_cases, M1AllGrInfo, OptsM11, ERPidM11, Config),
+
+ lists:foldl(
+ fun({GrPath,TCs,Found}, N) ->
+ TestName = list_to_atom("m1_spec_cases_" ++ integer_to_list(N)),
+ %% ct:pal("NOW RUNNING M1 TEST ~p: ~p + ~p",
+ %% [TestName,GrPath,TCs]),
+ {OptsM12,ERPidM12} = setup([{dir,DataDir},{suite,?M1},
+ {group,GrPath},{testcase,TCs},
+ {label,TestName}], Config),
+ ok = execute(TestName, {GrPath,TCs,Found},
+ OptsM12, ERPidM12, Config),
+ N+1
+ end, 1, M1Rest),
+
+ %% ct:pal("NOW RUNNING M2 TEST: ~p", [M2All]),
+
+ M2AllGrs = lists:flatmap(fun({Path,_,_}) when is_atom(hd(Path)) -> Path;
+ ({Path,_,_}) when is_list(hd(Path)) -> Path;
+ ({Path,_,_}) -> [Path]
+ end, M2All),
+
+
+ {OptsM21,ERPidM21} = setup([{dir,DataDir},{suite,?M2},
+ {group,M2AllGrs},{testcase,all},
+ {label,m2_all_cases}], Config),
+ M2AllGrInfo = {M2AllGrs,lists:flatten([Found || {_,_,Found} <- M2All])},
+ ok = execute(m2_all_cases, M2AllGrInfo, OptsM21, ERPidM21, Config),
+
+ lists:foldl(
+ fun({GrPath,TCs,Found}, N) ->
+ TestName = list_to_atom("m2_spec_cases_" ++ integer_to_list(N)),
+ %% ct:pal("NOW RUNNING M2 TEST ~p: ~p + ~p", [TestName,GrPath,TCs]),
+ {OptsM22,ERPidM22} = setup([{dir,DataDir},{suite,?M2},
+ {group,GrPath},{testcase,TCs},
+ {label,TestName}], Config),
+ ok = execute(TestName, {GrPath,TCs,Found},
+ OptsM22, ERPidM22, Config),
+ N+1
+ end, 1, M2Rest),
+ ok.
+
+
+%%%-----------------------------------------------------------------
+%%%
+run_groups_with_testspec(Config) ->
+ Name = run_groups_with_testspec,
+ DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+
+ {M1All,M1Rest,M2All,M2Rest} = get_all_groups_and_cases(Config),
+
+ M1AllGrs = lists:flatmap(fun({Path,_,_}) when is_atom(hd(Path)) -> Path;
+ ({Path,_,_}) when is_list(hd(Path)) -> Path;
+ ({Path,_,_}) -> [Path]
+ end, M1All),
+ M1AllTerm = {groups,DataDir,?M1,M1AllGrs},
+
+ M1RestTerms = lists:map(
+ fun({GrPath,TCs,_}) ->
+ {groups,DataDir,?M1,GrPath,{cases,TCs}}
+ end, M1Rest),
+
+ M2AllGrs = lists:flatmap(fun({Path,_,_}) when is_atom(hd(Path)) -> Path;
+ ({Path,_,_}) when is_list(hd(Path)) -> Path;
+ ({Path,_,_}) -> [Path]
+ end, M2All),
+ M2AllTerm = {groups,DataDir,?M2,M2AllGrs,{cases,all}},
+
+ M2RestTerms = lists:map(
+ fun({GrPath,TCs,_}) ->
+ {groups,DataDir,?M2,GrPath,{cases,TCs}}
+ end, M2Rest),
+
+ GroupTerms = lists:flatten([M1AllTerm,
+ M1RestTerms,
+ M2AllTerm,
+ M2RestTerms]),
+
+ TestSpec = [{merge_tests,false},
+ {label,Name}] ++ GroupTerms,
+
+ ct:pal("Here's the test spec:~n~p", [TestSpec]),
+
+ TestSpecName = ct_test_support:write_testspec(TestSpec, PrivDir,
+ "groups_search_spec"),
+
+ {Opts,ERPid} = setup([{spec,TestSpecName}], Config),
+ GroupInfo =
+ [{M1AllTerm,lists:flatten([Found || {_,_,Found} <- M1All])} |
+ M1Rest] ++
+ [{M2AllTerm,lists:flatten([Found || {_,_,Found} <- M2All])} |
+ M2Rest],
+ ok = execute(Name, GroupInfo, Opts, ERPid, Config).
+
+%%%-----------------------------------------------------------------
+%%% HELP FUNCTIONS
+%%%-----------------------------------------------------------------
+
+groups1() ->
+ [{top1,[],[top1_tc1,top1_tc2,{sub1,[],[sub1_tc1,sub1_tc2]}]},
+ {top2,[],[{group,sub2},top2_tc1,top2_tc2]},
+ {sub2,[],[sub2_tc1,sub2_tc2]}].
+
+groups2() ->
+ [{top1,[],[top1_tc1,top_tc2,tc3,
+ {sub11,[],[sub11_tc1,sub_tc2,tc3]},
+ {sub12,[],[sub12_tc1,sub_tc2,tc3,
+ {sub121,[],[sub121_tc1,sub_tc2,tc3]}]}]},
+ {top2,[],[{group,sub21},top2_tc1,top_tc2,tc3,{group,sub22}]},
+ {sub21,[],[sub21_tc1,sub_tc2,tc3,{group,sub2xx}]},
+ {sub22,[],[{group,sub221},sub22_tc1,sub_tc2,tc3,{group,sub2xx}]},
+ {sub221,[],[sub221_tc1,sub_tc2,tc3]},
+ {sub2xx,[],[sub2xx_tc1,sub_tc2,tc3]}].
+
+get_all_groups_and_cases(Config) ->
+ {value,{_,_,FindGrTCs}} = lists:keysearch(find_groups, 1, groups()),
+
+ MGTFs = [apply(?MODULE, TC, [Config]) || TC <- FindGrTCs],
+
+ ct:pal("Extracted data from ~p test cases", [length(MGTFs)]),
+
+ lists:foldr(fun({M,Gs,TCs,F},
+ {M11,M12,M21,M22}) ->
+ case {M,Gs,TCs} of
+ {?M1,all,_} -> {M11,[{Gs,TCs,F}|M12],M21,M22};
+ {?M1,_,all} -> {[{Gs,all,F}|M11],M12,M21,M22};
+ {?M1,_,_} -> {M11,[{Gs,TCs,F}|M12],M21,M22};
+ {?M2,all,_} -> {M11,M12,M21,[{Gs,TCs,F}|M22]};
+ {?M2,_,all} -> {M11,M12,[{Gs,all,F}|M21],M22};
+ {?M2,_,_} -> {M11,M12,M21,[{Gs,TCs,F}|M22]}
+ end
+ end, {[],[],[],[]}, MGTFs).
+
+%%%-----------------------------------------------------------------
+
+setup(Test, Config) ->
+ Opts0 = ct_test_support:get_opts(Config),
+ Level = ?config(trace_level, Config),
+ EvHArgs = [{cbm,ct_test_support},{trace_level,Level}],
+ Opts = Opts0 ++ [{event_handler,{?eh,EvHArgs}}|Test],
+ ERPid = ct_test_support:start_event_receiver(Config),
+ {Opts,ERPid}.
+
+execute(Name, TestParams, Opts, ERPid, Config) ->
+ ok = ct_test_support:run(Opts, Config),
+ Events = ct_test_support:get_events(ERPid, Config),
+ Events1 = reformat(Events, ?eh),
+ ct_test_support:log_events(Name,
+ Events1,
+ ?config(priv_dir, Config),
+ Opts),
+ verify_events(Name, TestParams, Events1).
+
+reformat(Events, EH) ->
+ ct_test_support:reformat(Events, EH).
+
+%%%-----------------------------------------------------------------
+%%% TEST EVENTS
+verify_events(Name, Params, Events) ->
+ %% 2 tests (ct:run_test + script_start) is default
+ verify_events(Name, Params, Events, 2).
+
+verify_events(_, _, _, 0) ->
+ ok;
+verify_events(Name, Params, Events, N) ->
+ test_events(Name, Params, Events),
+ verify_events(Name, Params, Events, N-1).
+
+%%%-----------------------------------------------------------------
+%%% check run_groups_with_options
+
+test_events(TestName, {GrPath,Found}, Events) ->
+ test_events(TestName, {GrPath,all,Found}, Events);
+
+test_events(TestName, {GrPath,TCs,Found}, Events)
+ when TestName /= run_groups_with_testspec ->
+ try check_events(Events, flatten_tests(Found)) of
+ ok -> ok
+ catch
+ throw:Reason ->
+ ct:pal("Test failed for ~p with group path ~p and cases ~p"
+ "~nReason: ~p", [TestName,GrPath,TCs,Reason]),
+ throw(failed)
+ end;
+
+%%%-----------------------------------------------------------------
+%%% check run_groups_with_testspec
+
+test_events(run_groups_with_testspec, Params, Events) ->
+ AllFound = lists:flatmap(fun({_All,Found}) when is_tuple(Found) ->
+ [Found];
+ ({_All,Found}) ->
+ Found;
+ ({_Gr,_TCs,Found}) when is_tuple(Found) ->
+ [Found];
+ ({_Gr,_TCs,Found}) ->
+ Found
+ end, Params),
+ try check_events(Events, flatten_tests(AllFound)) of
+ ok -> ok
+ catch
+ throw:Reason ->
+ ct:pal("Test failed for run_groups_with_testspec."
+ "~nReason: ~p", [Reason]),
+ throw(failed)
+ end.
+
+flatten_tests({conf,[{name,G}|_],{Mod,_I},Tests,_E}) ->
+ lists:flatten([{group,Mod,G} | flatten_tests(Tests)]);
+flatten_tests([{conf,[{name,G}|_],{Mod,_I},Tests,_E} | Confs]) ->
+ lists:flatten([{group,Mod,G} | flatten_tests(Tests)]) ++
+ lists:flatten(flatten_tests(Confs));
+flatten_tests([{_Mod,_TC} = Case | Tests]) ->
+ lists:flatten([Case | flatten_tests(Tests)]);
+flatten_tests([]) ->
+ [].
+
+check_events([{_,tc_start,{Mod,{init_per_group,G,_}}} | Evs],
+ [{group,Mod,G} | Check]) ->
+ check_events(Evs, Check);
+check_events([{_,tc_start,{Mod,TC}} | Evs],
+ [{Mod,TC} | Check]) when is_atom(TC) ->
+ check_events(Evs, Check);
+check_events([{_,tc_start,{Mod,{init_per_group,G,_}}} | _Evs], Check) ->
+ ct:pal("CHECK FAILED!~nGroup ~p in ~p not found in ~p.",
+ [G,Mod,Check]),
+ throw({test_not_found,{Mod,G}});
+check_events([{_,tc_start,{Mod,TC}} | _Evs], Check)
+ when is_atom(TC), TC /= init_per_suite, TC /= end_per_suite ->
+ ct:pal("CHECK FAILED!~nCase ~p in ~p not found in ~p.",
+ [TC,Mod,Check]),
+ throw({test_not_found,{Mod,TC}});
+check_events([Group | Evs], Check) when is_list(Group) ->
+ Check1 = check_events(Group, Check),
+ check_events(Evs, Check1);
+check_events(_, []) ->
+ ok;
+check_events([Elem | Evs], Check) when is_tuple(Elem) ->
+ check_events(Evs, Check);
+check_events([], Check = [_|_]) ->
+ ct:pal("CHECK FAILED!~nTests remain: ~p", [Check]),
+ throw({tests_remain,Check});
+check_events([Wut | _],_) ->
+ throw({unexpected,Wut}).
+
diff --git a/lib/common_test/test/ct_groups_search_SUITE_data/groups_search_dummy_1_SUITE.erl b/lib/common_test/test/ct_groups_search_SUITE_data/groups_search_dummy_1_SUITE.erl
new file mode 100644
index 0000000000..1c5b572f92
--- /dev/null
+++ b/lib/common_test/test/ct_groups_search_SUITE_data/groups_search_dummy_1_SUITE.erl
@@ -0,0 +1,83 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
+%%
+%% The 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(groups_search_dummy_1_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+
+all() ->
+ [{group,top1},
+ {group,top2}].
+
+groups() ->
+ [{top1,[],[top1_tc1,top1_tc2,{sub1,[],[sub1_tc1,sub1_tc2]}]},
+ {top2,[],[{group,sub2},top2_tc1,top2_tc2]},
+ {sub2,[],[sub2_tc1,sub2_tc2]}].
+
+%%%-----------------------------------------------------------------
+%%% CONFIG FUNCS
+%%%-----------------------------------------------------------------
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+end_per_testcase(_TestCase, _Config) ->
+ ok.
+
+init_per_group(_, Config) ->
+ Config.
+
+end_per_group(_, _Config) ->
+ ok.
+
+%%%-----------------------------------------------------------------
+%%% TEST CASES
+%%%-----------------------------------------------------------------
+
+top1_tc1(_) ->
+ ok.
+
+top1_tc2(_) ->
+ ok.
+
+sub1_tc1(_) ->
+ ok.
+
+sub1_tc2(_) ->
+ ok.
+
+top2_tc1(_) ->
+ ok.
+
+top2_tc2(_) ->
+ ok.
+
+sub2_tc1(_) ->
+ ok.
+
+sub2_tc2(_) ->
+ ok.
diff --git a/lib/common_test/test/ct_groups_search_SUITE_data/groups_search_dummy_2_SUITE.erl b/lib/common_test/test/ct_groups_search_SUITE_data/groups_search_dummy_2_SUITE.erl
new file mode 100644
index 0000000000..060012de29
--- /dev/null
+++ b/lib/common_test/test/ct_groups_search_SUITE_data/groups_search_dummy_2_SUITE.erl
@@ -0,0 +1,102 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
+%%
+%% The 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(groups_search_dummy_2_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+
+all() ->
+ [{group,top1},
+ {group,top2}].
+
+groups() ->
+ [{top1,[],[top1_tc1,top_tc2,tc3,
+ {sub11,[],[sub11_tc1,sub_tc2,tc3]},
+ {sub12,[],[sub12_tc1,sub_tc2,tc3,
+ {sub121,[],[sub121_tc1,sub_tc2,tc3]}]}]},
+
+ {top2,[],[{group,sub21},top2_tc1,top_tc2,tc3,{group,sub22}]},
+ {sub21,[],[sub21_tc1,sub_tc2,tc3,{group,sub2xx}]},
+ {sub22,[],[{group,sub221},sub22_tc1,sub_tc2,tc3,{group,sub2xx}]},
+ {sub221,[],[sub221_tc1,sub_tc2,tc3]},
+ {sub2xx,[],[sub2xx_tc1,sub_tc2,tc3]}].
+
+%%%-----------------------------------------------------------------
+%%% CONFIG FUNCS
+%%%-----------------------------------------------------------------
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+end_per_testcase(_TestCase, _Config) ->
+ ok.
+
+init_per_group(_, Config) ->
+ Config.
+
+end_per_group(_, _Config) ->
+ ok.
+
+%%%------------------------------------------------------------------
+%%% TEST CASES
+%%%------------------------------------------------------------------
+
+top1_tc1(_) ->
+ ok.
+
+top_tc2(_) ->
+ ok.
+
+tc3(_) ->
+ ok.
+
+sub_tc2(_) ->
+ ok.
+
+sub11_tc1(_) ->
+ ok.
+
+sub12_tc1(_) ->
+ ok.
+
+sub121_tc1(_) ->
+ ok.
+
+top2_tc1(_) ->
+ ok.
+
+sub21_tc1(_) ->
+ ok.
+
+sub22_tc1(_) ->
+ ok.
+
+sub221_tc1(_) ->
+ ok.
+
+sub2xx_tc1(_) ->
+ ok.
diff --git a/lib/common_test/test/ct_master_SUITE.erl b/lib/common_test/test/ct_master_SUITE.erl
index 27243a0067..56a343a96f 100644
--- a/lib/common_test/test/ct_master_SUITE.erl
+++ b/lib/common_test/test/ct_master_SUITE.erl
@@ -117,14 +117,8 @@ ct_master_test(Config) when is_list(Config) ->
reformat(Events, ?eh),
PrivDir, []),
- find_events(NodeNames, [{tc_start,{master_SUITE,init_per_suite}},
- {tc_start,{master_SUITE,first_testcase}},
- {tc_start,{master_SUITE,second_testcase}},
- {tc_start,{master_SUITE,third_testcase}},
- {tc_start,{master_SUITE,end_per_suite}}],
- Events),
-
- ok.
+ TestEvents = events_to_check(ct_master_test),
+ ok = find_events(NodeNames, TestEvents, Events, Config).
%%%-----------------------------------------------------------------
%%% HELP FUNCTIONS
@@ -153,13 +147,15 @@ make_spec(DataDir, FileName, NodeNames, Suites, Config) ->
CM = [{config,master,filename:join(DataDir,"master/config.txt")}],
+ Env = [{"THIS_MUST_BE_SET","yes"},
+ {"SO_MUST_THIS","value"}],
NS = lists:map(
fun(NodeName) ->
{init,NodeName,[
{node_start,[{startup_functions,[]},
- {monitor_master,true}]},
- {eval,{erlang,nodes,[]}}
- ]
+ {monitor_master,true},
+ {env,Env}]},
+ {eval,{erlang,nodes,[]}}]
}
end,
NodeNames),
@@ -199,7 +195,6 @@ run_test(_Name, FileName, Config) ->
[{FileName,ok}] = ct_test_support:run({ct_master,run,[FileName]},
[{ct_master,basic_html,[true]}],
Config),
- timer:sleep(5000),
[{FileName,ok}] = ct_test_support:run({ct_master,run,[FileName]},
[{ct_master,basic_html,[false]}],
Config).
@@ -210,28 +205,26 @@ reformat(Events, EH) ->
%%%-----------------------------------------------------------------
%%% TEST EVENTS
%%%-----------------------------------------------------------------
-find_events([], _CheckEvents, _) ->
- ok;
-find_events([NodeName|NodeNames],CheckEvents,AllEvents) ->
- find_events(NodeNames, CheckEvents,
- remove_events(add_host(NodeName),CheckEvents, AllEvents, [])).
-
-remove_events(Node,[{Name,Data} | RestChecks],
- [{?eh,#event{ name = Name, node = Node, data = Data }}|RestEvs],
- Acc) ->
- remove_events(Node, RestChecks, RestEvs, Acc);
-remove_events(Node, Checks, [Event|RestEvs], Acc) ->
- remove_events(Node, Checks, RestEvs, [Event | Acc]);
-remove_events(_Node, [], [], Acc) ->
- lists:reverse(Acc);
-remove_events(Node, Events, [], Acc) ->
- test_server:format("Could not find events: ~p in ~p for node ~p",
- [Events, lists:reverse(Acc), Node]),
- exit(event_not_found).
+
+find_events(NodeNames, TestEvents, Events, Config) ->
+ [begin
+ Node = add_host(Node0),
+ io:format("Searching for events for node: ~s", [Node]),
+ ok = ct_test_support:verify_events(TestEvents, Events, Node, Config),
+ io:nl()
+ end || Node0 <- NodeNames],
+ ok.
add_host(NodeName) ->
{ok, HostName} = inet:gethostname(),
list_to_atom(atom_to_list(NodeName)++"@"++HostName).
-expected_events(_) ->
- [].
+events_to_check(_) ->
+ [{?eh,tc_start,{master_SUITE,first_testcase}},
+ {?eh,tc_done,{master_SUITE,first_testcase,ok}},
+ {?eh,tc_start,{master_SUITE,second_testcase}},
+ {?eh,tc_done,{master_SUITE,second_testcase,ok}},
+ {?eh,tc_start,{master_SUITE,third_testcase}},
+ {?eh,tc_done,{master_SUITE,third_testcase,ok}},
+ {?eh,tc_start,{master_SUITE,env_vars}},
+ {?eh,tc_done,{master_SUITE,env_vars,ok}}].
diff --git a/lib/common_test/test/ct_master_SUITE_data/master/master_SUITE.erl b/lib/common_test/test/ct_master_SUITE_data/master/master_SUITE.erl
index 032d69ad9f..8a5009ad62 100644
--- a/lib/common_test/test/ct_master_SUITE_data/master/master_SUITE.erl
+++ b/lib/common_test/test/ct_master_SUITE_data/master/master_SUITE.erl
@@ -39,7 +39,8 @@ init_per_suite(Config) ->
end_per_suite(_) ->
ok.
-all() -> [first_testcase, second_testcase, third_testcase].
+all() -> [first_testcase, second_testcase, third_testcase,
+ env_vars].
init_per_testcase(_, Config) ->
Config.
@@ -56,3 +57,9 @@ second_testcase(_)->
third_testcase(_)->
A = 4,
A = 2*2.
+
+env_vars(_) ->
+ io:format("~p\n", [os:getenv()]),
+ "yes" = os:getenv("THIS_MUST_BE_SET"),
+ "value" = os:getenv("SO_MUST_THIS"),
+ ok.
diff --git a/lib/common_test/test/ct_netconfc_SUITE.erl b/lib/common_test/test/ct_netconfc_SUITE.erl
index e6e8d5b09c..3042a924fe 100644
--- a/lib/common_test/test/ct_netconfc_SUITE.erl
+++ b/lib/common_test/test/ct_netconfc_SUITE.erl
@@ -44,7 +44,12 @@
%%--------------------------------------------------------------------
init_per_suite(Config) ->
Config1 = ct_test_support:init_per_suite(Config),
- Config1.
+ case application:load(crypto) of
+ {error,Reason} ->
+ {skip, Reason};
+ _ ->
+ Config1
+ end.
end_per_suite(Config) ->
ct_test_support:end_per_suite(Config).
@@ -108,7 +113,7 @@ reformat(Events, EH) ->
%%%-----------------------------------------------------------------
%%% TEST EVENTS
%%%-----------------------------------------------------------------
-events_to_check(Test,Config) ->
+events_to_check(default,Config) ->
{module,_} = code:load_abs(filename:join(?config(data_dir,Config),
netconfc1_SUITE)),
TCs = netconfc1_SUITE:all(),
diff --git a/lib/common_test/test/ct_surefire_SUITE.erl b/lib/common_test/test/ct_surefire_SUITE.erl
new file mode 100644
index 0000000000..69e98cef48
--- /dev/null
+++ b/lib/common_test/test/ct_surefire_SUITE.erl
@@ -0,0 +1,351 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012. All Rights Reserved.
+%%
+%% The 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%
+%%
+
+%%%-------------------------------------------------------------------
+%%% File: ct_surefire_SUITE
+%%%
+%%% Description:
+%%% Test cth_surefire hook
+%%%
+%%%-------------------------------------------------------------------
+-module(ct_surefire_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("common_test/include/ct_event.hrl").
+
+-include_lib("xmerl/include/xmerl.hrl").
+
+-define(eh, ct_test_support_eh).
+
+-define(url_base,"http://my.host.com/").
+
+%%--------------------------------------------------------------------
+%% TEST SERVER CALLBACK FUNCTIONS
+%%--------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% Description: Since Common Test starts another Test Server
+%% instance, the tests need to be performed on a separate node (or
+%% there will be clashes with logging processes etc).
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ Config1 = ct_test_support:init_per_suite(Config),
+ Config1.
+
+end_per_suite(Config) ->
+ ct_test_support:end_per_suite(Config).
+
+init_per_testcase(TestCase, Config) ->
+ ct_test_support:init_per_testcase(TestCase, Config).
+
+end_per_testcase(TestCase, Config) ->
+ ct_test_support:end_per_testcase(TestCase, Config).
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [
+ default,
+ absolute_path,
+ relative_path,
+ url,
+ logdir
+ ].
+
+%%--------------------------------------------------------------------
+%% TEST CASES
+%%--------------------------------------------------------------------
+
+%%%-----------------------------------------------------------------
+%%%
+default(Config) when is_list(Config) ->
+ run(default,[cth_surefire],Config),
+ PrivDir = ?config(priv_dir,Config),
+ XmlRe = filename:join([PrivDir,"*","junit_report.xml"]),
+ check_xml(default,XmlRe).
+
+absolute_path(Config) when is_list(Config) ->
+ PrivDir = ?config(priv_dir,Config),
+ Path = filename:join(PrivDir,"abspath.xml"),
+ run(absolute_path,[{cth_surefire,[{path,Path}]}],Config),
+ check_xml(absolute_path,Path).
+
+relative_path(Config) when is_list(Config) ->
+ Path = "relpath.xml",
+ run(relative_path,[{cth_surefire,[{path,Path}]}],Config),
+ PrivDir = ?config(priv_dir,Config),
+ XmlRe = filename:join([PrivDir,"*",Path]),
+ check_xml(relative_path,XmlRe).
+
+url(Config) when is_list(Config) ->
+ Path = "url.xml",
+ run(url,[{cth_surefire,[{url_base,?url_base},
+ {path,Path}]}],Config),
+ PrivDir = ?config(priv_dir,Config),
+ XmlRe = filename:join([PrivDir,"*",Path]),
+ check_xml(url,XmlRe).
+
+logdir(Config) when is_list(Config) ->
+ PrivDir = ?config(priv_dir,Config),
+ LogDir = filename:join(PrivDir,"specific_logdir"),
+ file:make_dir(LogDir),
+ Path = "logdir.xml",
+ run(logdir,[{cth_surefire,[{path,Path}]}],Config,[{logdir,LogDir}]),
+ PrivDir = ?config(priv_dir,Config),
+ XmlRe = filename:join([LogDir,"*",Path]),
+ check_xml(logdir,XmlRe).
+
+%%%-----------------------------------------------------------------
+%%% HELP FUNCTIONS
+%%%-----------------------------------------------------------------
+run(Case,CTHs,Config) ->
+ run(Case,CTHs,Config,[]).
+run(Case,CTHs,Config,ExtraOpts) ->
+ DataDir = ?config(data_dir, Config),
+ Suite = filename:join(DataDir, "surefire_SUITE"),
+ {Opts,ERPid} = setup([{suite,Suite},{ct_hooks,CTHs},{label,Case}|ExtraOpts],
+ Config),
+ ok = execute(Case, Opts, ERPid, Config).
+
+setup(Test, Config) ->
+ Opts0 = ct_test_support:get_opts(Config),
+ Opts1 =
+ case lists:keymember(logdir,1,Test) of
+ true -> lists:keydelete(logdir,1,Opts0);
+ false -> Opts0
+ end,
+ Level = ?config(trace_level, Config),
+ EvHArgs = [{cbm,ct_test_support},{trace_level,Level}],
+ Opts = Opts1 ++ [{event_handler,{?eh,EvHArgs}}|Test],
+ ERPid = ct_test_support:start_event_receiver(Config),
+ {Opts,ERPid}.
+
+execute(Name, Opts, ERPid, Config) ->
+ ok = ct_test_support:run(Opts, Config),
+ Events = ct_test_support:get_events(ERPid, Config),
+
+ ct_test_support:log_events(Name,
+ reformat(Events, ?eh),
+ ?config(priv_dir, Config),
+ Opts),
+
+ TestEvents = events_to_check(Name),
+ ct_test_support:verify_events(TestEvents, Events, Config).
+
+reformat(Events, EH) ->
+ ct_test_support:reformat(Events, EH).
+
+%%%-----------------------------------------------------------------
+%%% TEST EVENTS
+%%%-----------------------------------------------------------------
+events_to_check(Test) ->
+ %% 2 tests (ct:run_test + script_start) is default
+ events_to_check(Test, 2).
+
+events_to_check(_, 0) ->
+ [];
+events_to_check(Test, N) ->
+ test_events(Test) ++ events_to_check(Test, N-1).
+
+test_events(_) ->
+ [{?eh,start_logging,'_'},
+ {?eh,start_info,{1,1,9}},
+ {?eh,tc_start,{surefire_SUITE,init_per_suite}},
+ {?eh,tc_done,{surefire_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{surefire_SUITE,tc_ok}},
+ {?eh,tc_done,{surefire_SUITE,tc_ok,ok}},
+ {?eh,test_stats,{1,0,{0,0}}},
+ {?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,
+ {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,
+ {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,
+ {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,
+ {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,stop_logging,[]}].
+
+
+%%%-----------------------------------------------------------------
+%%% Check generated xml log files
+check_xml(Case,XmlRe) ->
+ case filelib:wildcard(XmlRe) of
+ [] ->
+ ct:fail("No xml files found with regexp ~p~n", [XmlRe]);
+ [_] = Xmls when Case==absolute_path ->
+ do_check_xml(Case,Xmls);
+ [_,_] = Xmls ->
+ do_check_xml(Case,Xmls)
+ end.
+
+%% Allowed structure:
+%% <testsuites>
+%% <testsuite>
+%% <properties>
+%% <property/>
+%% ...
+%% </properties>
+%% <testcase>
+%% [<failure/> | <error/> | <skipped/> ]
+%% </testcase>
+%% ...
+%% </testsuite>
+%% ...
+%% </testsuites>
+do_check_xml(Case,[Xml|Xmls]) ->
+ ct:log("Checking <a href=~p>~s</a>~n",[Xml,Xml]),
+ {E,_} = xmerl_scan:file(Xml),
+ Expected = events_to_result(lists:flatten(test_events(Case))),
+ ParseResult = testsuites(Case,E),
+ ct:log("Expecting: ~p~n",[[Expected]]),
+ ct:log("Actual : ~p~n",[ParseResult]),
+ [Expected] = ParseResult,
+ do_check_xml(Case,Xmls);
+do_check_xml(_,[]) ->
+ ok.
+
+%% Scanning the XML to get the same type of result as events_to_result/1
+testsuites(Case,#xmlElement{name=testsuites,content=TS}) ->
+ %% OTP-10589 - move properties element to <testsuite>
+ false = lists:keytake(properties,#xmlElement.name,TS),
+ testsuite(Case,TS).
+
+testsuite(Case,[#xmlElement{name=testsuite,content=TC,attributes=A}|TS]) ->
+ {ET,EF,ES} = events_to_numbers(lists:flatten(test_events(Case))),
+ {T,E,F,S} = get_numbers_from_attrs(A,false,false,false,false),
+ ct:log("Expecting total:~p, error:~p, failure:~p, skipped:~p~n",[ET,0,EF,ES]),
+ ct:log("Actual total:~p, error:~p, failure:~p, skipped:~p~n",[T,E,F,S]),
+ {ET,0,EF,ES} = {T,E,F,S},
+
+ %% properties should only be there if given a options to hook
+ false = lists:keytake(properties,#xmlElement.name,TC),
+ %% system-out and system-err is not used by common_test
+ false = lists:keytake('system-out',#xmlElement.name,TC),
+ false = lists:keytake('system-err',#xmlElement.name,TC),
+ R=testcase(Case,TC),
+ [R|testsuite(Case,TS)];
+testsuite(_Case,[]) ->
+ [].
+
+testcase(url=Case,[#xmlElement{name=testcase,attributes=A,content=C}|TC]) ->
+ R = failed_or_skipped(C),
+ case R of
+ [s] ->
+ case lists:keyfind(url,#xmlAttribute.name,A) of
+ false -> ok;
+ #xmlAttribute{value=UrlAttr} ->
+ lists:keyfind(url,#xmlAttribute.name,A),
+ true = lists:prefix(?url_base,UrlAttr)
+ end;
+ _ ->
+ #xmlAttribute{value=UrlAttr} =
+ lists:keyfind(url,#xmlAttribute.name,A),
+ true = lists:prefix(?url_base,UrlAttr)
+ end,
+ [R|testcase(Case,TC)];
+testcase(Case,[#xmlElement{name=testcase,attributes=A,content=C}|TC]) ->
+ false = lists:keyfind(url,#xmlAttribute.name,A),
+ R = failed_or_skipped(C),
+ [R|testcase(Case,TC)];
+testcase(_Case,[]) ->
+ [].
+
+failed_or_skipped([#xmlElement{name=failure}|E]) ->
+ [f|failed_or_skipped(E)];
+failed_or_skipped([#xmlElement{name=error}|E]) ->
+ [e|failed_or_skipped(E)];
+failed_or_skipped([#xmlElement{name=skipped}|E]) ->
+ [s|failed_or_skipped(E)];
+failed_or_skipped([]) ->
+ [].
+
+%% Using the expected events to produce the expected result of the XML scanning.
+%% The result is a list of test suites:
+%% Testsuites = [Testsuite]
+%% Testsuite = [Testcase]
+%% Testcase = [] | [f] | [s], indicating ok, failed and skipped respectively
+events_to_result([{?eh,tc_done,{_Suite,_Case,R}}|E]) ->
+ [result(R)|events_to_result(E)];
+events_to_result([{?eh,tc_auto_skip,_}|E]) ->
+ [[s]|events_to_result(E)];
+events_to_result([_|E]) ->
+ events_to_result(E);
+events_to_result([]) ->
+ [].
+
+result(ok) ->[];
+result({skipped,_}) -> [s];
+result({failed,_}) -> [f].
+
+%% Using the expected events' last test_stats element to produce the
+%% expected number of totla, errors, failed and skipped testcases.
+events_to_numbers(E) ->
+ RevE = lists:reverse(E),
+ {?eh,test_stats,{Ok,F,{US,AS}}} = lists:keyfind(test_stats,2,RevE),
+ {Ok+F+US+AS,F,US+AS}.
+
+get_numbers_from_attrs([#xmlAttribute{name=tests,value=X}|A],false,E,F,S) ->
+ get_numbers_from_attrs(A,list_to_integer(X),E,F,S);
+get_numbers_from_attrs([#xmlAttribute{name=errors,value=X}|A],T,false,F,S) ->
+ get_numbers_from_attrs(A,T,list_to_integer(X),F,S);
+get_numbers_from_attrs([#xmlAttribute{name=failures,value=X}|A],T,E,false,S) ->
+ get_numbers_from_attrs(A,T,E,list_to_integer(X),S);
+get_numbers_from_attrs([#xmlAttribute{name=skipped,value=X}|A],T,E,F,false) ->
+ get_numbers_from_attrs(A,T,E,F,list_to_integer(X));
+get_numbers_from_attrs([_|A],T,E,F,S) ->
+ get_numbers_from_attrs(A,T,E,F,S);
+get_numbers_from_attrs([],T,E,F,S) ->
+ {T,E,F,S}.
diff --git a/lib/common_test/test/ct_surefire_SUITE_data/surefire_SUITE.erl b/lib/common_test/test/ct_surefire_SUITE_data/surefire_SUITE.erl
new file mode 100644
index 0000000000..677aee46c5
--- /dev/null
+++ b/lib/common_test/test/ct_surefire_SUITE_data/surefire_SUITE.erl
@@ -0,0 +1,92 @@
+%%--------------------------------------------------------------------
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012. All Rights Reserved.
+%%
+%% The 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%
+%%
+%%----------------------------------------------------------------------
+%% File: surefire_SUITE.erl
+%%
+%% Description:
+%% This file contains the test cases for cth_surefire.
+%%
+%% @author Support
+%% @doc Test of surefire support in common_test
+%% @end
+%%----------------------------------------------------------------------
+%%----------------------------------------------------------------------
+-module(surefire_SUITE).
+-include_lib("common_test/include/ct.hrl").
+
+-compile(export_all).
+
+%% Default timetrap timeout (set in init_per_testcase).
+-define(default_timeout, ?t:minutes(1)).
+
+all() ->
+ testcases() ++ [{group,g},{group,g_fail}].
+
+groups() ->
+ [{g,testcases()},
+ {g_fail,[tc_ok]}].
+
+testcases() ->
+ [tc_ok,
+ tc_fail,
+ tc_skip,
+ tc_autoskip_require].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(Config) ->
+ Config.
+
+init_per_group(g_fail, _Config) ->
+ exit(all_cases_should_be_skipped);
+init_per_group(_, Config) ->
+ Config.
+
+end_per_group(_Group, Config) ->
+ Config.
+
+init_per_testcase(_Case, Config) ->
+ Dog = test_server:timetrap(?default_timeout),
+ [{watchdog, Dog}|Config].
+
+end_per_testcase(_Case, Config) ->
+ Dog=?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+%%%-----------------------------------------------------------------
+%%% Test cases
+break(_Config) ->
+ test_server:break(""),
+ ok.
+
+tc_ok(_Config) ->
+ ok.
+
+tc_fail(_Config) ->
+ ct:fail("this test should fail").
+
+tc_skip(_Config) ->
+ {skip,"this test is skipped"}.
+
+tc_autoskip_require() ->
+ [{require,whatever}].
+tc_autoskip_require(Config) ->
+ ct:fail("this test should never be executed - it should be autoskipped").
diff --git a/lib/common_test/test/ct_system_error_SUITE.erl b/lib/common_test/test/ct_system_error_SUITE.erl
index f00f470c33..f2d6ef4b1b 100644
--- a/lib/common_test/test/ct_system_error_SUITE.erl
+++ b/lib/common_test/test/ct_system_error_SUITE.erl
@@ -87,7 +87,7 @@ test_server_failing_logs(Config) ->
crash_test_server(Config) ->
DataDir = ?config(data_dir, Config),
- Root = ?config(priv_dir, Config),
+ Root = proplists:get_value(logdir, ct_test_support:get_opts(Config)),
[$@|Host] = lists:dropwhile(fun(C) ->
C =/= $@
end, atom_to_list(node())),
diff --git a/lib/common_test/test/ct_test_support.erl b/lib/common_test/test/ct_test_support.erl
index 80cca4a1cc..fc572aa82f 100644
--- a/lib/common_test/test/ct_test_support.erl
+++ b/lib/common_test/test/ct_test_support.erl
@@ -32,7 +32,7 @@
run/2, run/3, run/4, get_opts/1, wait_for_ct_stop/1]).
-export([handle_event/2, start_event_receiver/1, get_events/2,
- verify_events/3, reformat/2, log_events/4,
+ verify_events/3, verify_events/4, reformat/2, log_events/4,
join_abs_dirs/2]).
-export([ct_test_halt/1]).
@@ -117,8 +117,7 @@ end_per_suite(Config) ->
CTNode = proplists:get_value(ct_node, Config),
PrivDir = proplists:get_value(priv_dir, Config),
true = rpc:call(CTNode, code, del_path, [filename:join(PrivDir,"")]),
- cover:stop(CTNode),
- slave:stop(CTNode),
+ slave_stop(CTNode),
ok.
%%%-----------------------------------------------------------------
@@ -149,8 +148,7 @@ end_per_testcase(_TestCase, Config) ->
case wait_for_ct_stop(CTNode) of
%% Common test was not stopped to we restart node.
false ->
- cover:stop(CTNode),
- slave:stop(CTNode),
+ slave_stop(CTNode),
start_slave(Config,proplists:get_value(trace_level,Config)),
{fail, "Could not stop common_test"};
true ->
@@ -364,6 +362,14 @@ verify_events(TEvs, Evs, Config) ->
ok
end.
+verify_events(TEvs, Evs, Node, Config) ->
+ case catch verify_events1(TEvs, Evs, Node, Config) of
+ {'EXIT',Reason} ->
+ Reason;
+ _ ->
+ ok
+ end.
+
verify_events1([TestEv|_], [{TEH,#event{name=stop_logging,node=Node,data=_}}|_], Node, _)
when element(1,TestEv) == TEH, element(2,TestEv) =/= stop_logging ->
test_server:format("Failed to find ~p in the list of events!~n", [TestEv]),
@@ -612,8 +618,11 @@ locate({parallel,TEvs}, Node, Evs, Config) ->
fun({EH,#event{name=tc_auto_skip,
node=EvNode,
data={Mod,end_per_group,Reason}}}) when
- EH == TEH, EvNode == Node, Mod == M, Reason == R ->
- false;
+ EH == TEH, EvNode == Node, Mod == M ->
+ case match_data(R, Reason) of
+ match -> false;
+ _ -> true
+ end;
({EH,#event{name=stop_logging,
node=EvNode,data=_}}) when
EH == TEH, EvNode == Node ->
@@ -627,23 +636,12 @@ locate({parallel,TEvs}, Node, Evs, Config) ->
[_AutoSkip | RemEvs2] ->
{Done,RemEvs2,length(RemEvs2)}
end;
- %% match other event than test case
- (TEv={TEH,N,D}, Acc) when D == '_' ->
- case [E || E={EH,#event{name=Name,
- node=EvNode,
- data=_}} <- Evs1,
- EH == TEH, EvNode == Node, Name == N] of
- [] ->
- exit({unmatched,TEv});
- _ ->
- test_server:format("Found ~p!", [TEv]),
- Acc
- end;
(TEv={TEH,N,D}, Acc) ->
case [E || E={EH,#event{name=Name,
node=EvNode,
data=Data}} <- Evs1,
- EH == TEH, EvNode == Node, Name == N, Data == D] of
+ EH == TEH, EvNode == Node, Name == N,
+ match == match_data(D,Data)] of
[] ->
exit({unmatched,TEv});
_ ->
@@ -1002,33 +1000,39 @@ locate({TEH,Name,Data}, Node, [{TEH,#event{name=Name,
data = EvData,
node = Node}}|Evs],
Config) ->
- try match_data(Data, EvData) of
+ case match_data(Data, EvData) of
match ->
- {Config,Evs}
- catch _:_ ->
+ {Config,Evs};
+ _ ->
nomatch
end;
locate({_TEH,_Name,_Data}, _Node, [_|_Evs], _Config) ->
nomatch.
-match_data(D,D) ->
+match_data(Data, EvData) ->
+ try do_match_data(Data, EvData)
+ catch _:_ ->
+ nomatch
+ end.
+
+do_match_data(D,D) ->
match;
-match_data('_',_) ->
+do_match_data('_',_) ->
match;
-match_data(Fun,Data) when is_function(Fun) ->
+do_match_data(Fun,Data) when is_function(Fun) ->
Fun(Data);
-match_data('$proplist',Proplist) ->
- match_data(
+do_match_data('$proplist',Proplist) ->
+ do_match_data(
fun(List) ->
lists:foreach(fun({_,_}) -> ok end,List)
end,Proplist);
-match_data([H1|MatchT],[H2|ValT]) ->
- match_data(H1,H2),
- match_data(MatchT,ValT);
-match_data(Tuple1,Tuple2) when is_tuple(Tuple1),is_tuple(Tuple2) ->
- match_data(tuple_to_list(Tuple1),tuple_to_list(Tuple2));
-match_data([],[]) ->
+do_match_data([H1|MatchT],[H2|ValT]) ->
+ do_match_data(H1,H2),
+ do_match_data(MatchT,ValT);
+do_match_data(Tuple1,Tuple2) when is_tuple(Tuple1),is_tuple(Tuple2) ->
+ do_match_data(tuple_to_list(Tuple1),tuple_to_list(Tuple2));
+do_match_data([],[]) ->
match.
result_match({SkipOrFail,{ErrorInd,{Why,'_'}}},
@@ -1043,6 +1047,9 @@ result_match({failed,{timetrap_timeout,{'$approx',Num}}},
Value =< trunc(Num+0.02*Num) -> true;
true -> false
end;
+result_match({user_timetrap_error,{Why,'_'}},
+ {user_timetrap_error,{Why,_Stack}}) ->
+ true;
result_match(Result, Result) ->
true;
result_match(_, _) ->
@@ -1259,3 +1266,22 @@ rm_files([F | Fs]) ->
rm_files([]) ->
ok.
+%%%-----------------------------------------------------------------
+%%%
+slave_stop(Node) ->
+ Cover = test_server:is_cover(),
+ if Cover-> cover:flush(Node);
+ true -> ok
+ end,
+ erlang:monitor_node(Node, true),
+ slave:stop(Node),
+ receive
+ {nodedown, Node} ->
+ if Cover -> cover:stop(Node);
+ true -> ok
+ end
+ after 5000 ->
+ erlang:monitor_node(Node, false),
+ receive {nodedown, Node} -> ok after 0 -> ok end %flush
+ end,
+ ok.
diff --git a/lib/common_test/vsn.mk b/lib/common_test/vsn.mk
index 5c9fdfc47e..c92fb2ca37 100644
--- a/lib/common_test/vsn.mk
+++ b/lib/common_test/vsn.mk
@@ -1 +1 @@
-COMMON_TEST_VSN = 1.6.2.1
+COMMON_TEST_VSN = 1.7
diff --git a/lib/compiler/doc/src/compile.xml b/lib/compiler/doc/src/compile.xml
index 27d750f929..ddaae2655d 100644
--- a/lib/compiler/doc/src/compile.xml
+++ b/lib/compiler/doc/src/compile.xml
@@ -816,6 +816,32 @@ pi() -> 3.1416.
</section>
<section>
+ <title>Inlining of list functions</title>
+ <p>The compiler can also inline a variety of list manipulation functions
+ from the stdlib's lists module.</p>
+
+ <p>This feature must be explicitly enabled with a compiler option or a
+ <c>-compile()</c> attribute in the source module.</p>
+
+ <p>To enable inlining of list functions, use the <c>inline_list_funcs</c>
+ option.</p>
+
+ <p>The following functions are inlined:</p>
+ <list type="bulleted">
+ <item><seealso marker="stdlib:lists#all/2">lists:all/2</seealso></item>
+ <item><seealso marker="stdlib:lists#any/2">lists:any/2</seealso></item>
+ <item><seealso marker="stdlib:lists#foreach/2">lists:foreach/2</seealso></item>
+ <item><seealso marker="stdlib:lists#map/2">lists:map/2</seealso></item>
+ <item><seealso marker="stdlib:lists#flatmap/2">lists:flatmap/2</seealso></item>
+ <item><seealso marker="stdlib:lists#filter/2">lists:filter/2</seealso></item>
+ <item><seealso marker="stdlib:lists#foldl/3">lists:foldl/3</seealso></item>
+ <item><seealso marker="stdlib:lists#foldr/3">lists:foldr/3</seealso></item>
+ <item><seealso marker="stdlib:lists#mapfoldl/3">lists:mapfoldl/3</seealso></item>
+ <item><seealso marker="stdlib:lists#mapfoldr/3">lists:mapfoldr/3</seealso></item>
+ </list>
+ </section>
+
+ <section>
<title>Parse Transformations</title>
<p>Parse transformations are used when a programmer wants to use
diff --git a/lib/compiler/src/Makefile b/lib/compiler/src/Makefile
index 958d3501c7..8d54dffd73 100644
--- a/lib/compiler/src/Makefile
+++ b/lib/compiler/src/Makefile
@@ -45,6 +45,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/compiler-$(VSN)
# Target Specs
# ----------------------------------------------------
MODULES = \
+ beam_a \
beam_asm \
beam_block \
beam_bool \
@@ -65,6 +66,7 @@ MODULES = \
beam_type \
beam_utils \
beam_validator \
+ beam_z \
cerl \
cerl_clauses \
cerl_inline \
@@ -80,7 +82,6 @@ MODULES = \
sys_core_dsetel \
sys_core_fold \
sys_core_inline \
- sys_expand_pmod \
sys_pre_attributes \
sys_pre_expand \
v3_codegen \
@@ -143,19 +144,19 @@ clean:
# ----------------------------------------------------
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(EGEN)/beam_opcodes.erl $(EGEN)/beam_opcodes.hrl: genop.tab
- $(PERL) $(ERL_TOP)/erts/emulator/utils/beam_makeops -compiler -outdir $(EGEN) $<
+ $(gen_verbose)$(PERL) $(ERL_TOP)/erts/emulator/utils/beam_makeops -compiler -outdir $(EGEN) $<
$(EBIN)/beam_asm.beam: $(ESRC)/beam_asm.erl $(EGEN)/beam_opcodes.hrl
- $(ERLC) $(ERL_COMPILE_FLAGS) -DCOMPILER_VSN='"$(VSN)"' -o$(EBIN) $<
+ $(V_ERLC) $(ERL_COMPILE_FLAGS) -DCOMPILER_VSN='"$(VSN)"' -o$(EBIN) $<
$(EBIN)/cerl_inline.beam: $(ESRC)/cerl_inline.erl
- $(ERLC) $(ERL_COMPILE_FLAGS) +nowarn_shadow_vars -o$(EBIN) $<
+ $(V_ERLC) $(ERL_COMPILE_FLAGS) +nowarn_shadow_vars -o$(EBIN) $<
# ----------------------------------------------------
# Release Target
diff --git a/lib/compiler/src/beam_a.erl b/lib/compiler/src/beam_a.erl
new file mode 100644
index 0000000000..1c51226314
--- /dev/null
+++ b/lib/compiler/src/beam_a.erl
@@ -0,0 +1,97 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% Purpose: Run directly after code generation to do any normalization
+%% or preparation to simplify the optimization passes.
+%% (Mandatory.)
+
+-module(beam_a).
+
+-export([module/2]).
+
+module({Mod,Exp,Attr,Fs0,Lc}, _Opt) ->
+ Fs = [function(F) || F <- Fs0],
+ {ok,{Mod,Exp,Attr,Fs,Lc}}.
+
+function({function,Name,Arity,CLabel,Is0}) ->
+ try
+ %% Rename certain operations to simplify the optimization passes.
+ Is1 = rename_instrs(Is0),
+
+ %% Remove unusued labels for cleanliness and to help
+ %% optimization passes and HiPE.
+ Is = beam_jump:remove_unused_labels(Is1),
+ {function,Name,Arity,CLabel,Is}
+ catch
+ Class:Error ->
+ Stack = erlang:get_stacktrace(),
+ io:fwrite("Function: ~w/~w\n", [Name,Arity]),
+ erlang:raise(Class, Error, Stack)
+ end.
+
+rename_instrs([{apply_last,A,N}|Is]) ->
+ [{apply,A},{deallocate,N},return|rename_instrs(Is)];
+rename_instrs([{call_last,A,F,N}|Is]) ->
+ [{call,A,F},{deallocate,N},return|rename_instrs(Is)];
+rename_instrs([{call_ext_last,A,F,N}|Is]) ->
+ [{call_ext,A,F},{deallocate,N},return|rename_instrs(Is)];
+rename_instrs([{call_only,A,F}|Is]) ->
+ [{call,A,F},return|rename_instrs(Is)];
+rename_instrs([{call_ext_only,A,F}|Is]) ->
+ [{call_ext,A,F},return|rename_instrs(Is)];
+rename_instrs([I|Is]) ->
+ [rename_instr(I)|rename_instrs(Is)];
+rename_instrs([]) -> [].
+
+rename_instr({bs_put_binary=I,F,Sz,U,Fl,Src}) ->
+ {bs_put,F,{I,U,Fl},[Sz,Src]};
+rename_instr({bs_put_float=I,F,Sz,U,Fl,Src}) ->
+ {bs_put,F,{I,U,Fl},[Sz,Src]};
+rename_instr({bs_put_integer=I,F,Sz,U,Fl,Src}) ->
+ {bs_put,F,{I,U,Fl},[Sz,Src]};
+rename_instr({bs_put_utf8=I,F,Fl,Src}) ->
+ {bs_put,F,{I,Fl},[Src]};
+rename_instr({bs_put_utf16=I,F,Fl,Src}) ->
+ {bs_put,F,{I,Fl},[Src]};
+rename_instr({bs_put_utf32=I,F,Fl,Src}) ->
+ {bs_put,F,{I,Fl},[Src]};
+%% rename_instr({bs_put_string,_,_}=I) ->
+%% {bs_put,{f,0},I,[]};
+rename_instr({bs_add=I,F,[Src1,Src2,U],Dst}) when is_integer(U) ->
+ {bif,I,F,[Src1,Src2,{integer,U}],Dst};
+rename_instr({bs_utf8_size=I,F,Src,Dst}) ->
+ {bif,I,F,[Src],Dst};
+rename_instr({bs_utf16_size=I,F,Src,Dst}) ->
+ {bif,I,F,[Src],Dst};
+rename_instr({bs_init2=I,F,Sz,Extra,Live,Flags,Dst}) ->
+ {bs_init,F,{I,Extra,Flags},Live,[Sz],Dst};
+rename_instr({bs_init_bits=I,F,Sz,Extra,Live,Flags,Dst}) ->
+ {bs_init,F,{I,Extra,Flags},Live,[Sz],Dst};
+rename_instr({bs_append=I,F,Sz,Extra,Live,U,Src,Flags,Dst}) ->
+ {bs_init,F,{I,Extra,U,Flags},Live,[Sz,Src],Dst};
+rename_instr({bs_private_append=I,F,Sz,U,Src,Flags,Dst}) ->
+ {bs_init,F,{I,U,Flags},none,[Sz,Src],Dst};
+rename_instr(bs_init_writable=I) ->
+ {bs_init,{f,0},I,1,[{x,0}],{x,0}};
+rename_instr({select_val=I,Reg,Fail,{list,List}}) ->
+ {select,I,Reg,Fail,List};
+rename_instr({select_tuple_arity=I,Reg,Fail,{list,List}}) ->
+ {select,I,Reg,Fail,List};
+rename_instr(send) ->
+ {call_ext,2,send};
+rename_instr(I) -> I.
diff --git a/lib/compiler/src/beam_block.erl b/lib/compiler/src/beam_block.erl
index cd568097fa..3e0050382c 100644
--- a/lib/compiler/src/beam_block.erl
+++ b/lib/compiler/src/beam_block.erl
@@ -31,19 +31,16 @@ module({Mod,Exp,Attr,Fs0,Lc0}, _Opt) ->
function({function,Name,Arity,CLabel,Is0}, Lc0) ->
try
- %% Extra labels may thwart optimizations.
- Is1 = beam_jump:remove_unused_labels(Is0),
-
%% Collect basic blocks and optimize them.
- Is2 = blockify(Is1),
- Is3 = embed_lines(Is2),
- Is4 = move_allocates(Is3),
- Is5 = beam_utils:live_opt(Is4),
- Is6 = opt_blocks(Is5),
- Is7 = beam_utils:delete_live_annos(Is6),
+ Is1 = blockify(Is0),
+ Is2 = embed_lines(Is1),
+ Is3 = move_allocates(Is2),
+ Is4 = beam_utils:live_opt(Is3),
+ Is5 = opt_blocks(Is4),
+ Is6 = beam_utils:delete_live_annos(Is5),
%% Optimize bit syntax.
- {Is,Lc} = bsm_opt(Is7, Lc0),
+ {Is,Lc} = bsm_opt(Is6, Lc0),
%% Done.
{{function,Name,Arity,CLabel,Is},Lc}
@@ -74,9 +71,9 @@ blockify([{bs_save2,R,Point}=I,{test,is_eq_exact,_,_}=Test,
%% Do other peep-hole optimizations.
blockify([{test,is_atom,{f,Fail},[Reg]}=I|
- [{select_val,Reg,{f,Fail},
- {list,[{atom,false},{f,_}=BrFalse,
- {atom,true}=AtomTrue,{f,_}=BrTrue]}}|Is]=Is0],
+ [{select,select_val,Reg,{f,Fail},
+ [{atom,false},{f,_}=BrFalse,
+ {atom,true}=AtomTrue,{f,_}=BrTrue]}|Is]=Is0],
[{block,Bl}|_]=Acc) ->
case is_last_bool(Bl, Reg) of
false ->
@@ -89,9 +86,9 @@ blockify([{test,is_atom,{f,Fail},[Reg]}=I|
{test,is_eq_exact,BrFalse,[Reg,AtomTrue]}|Acc])
end;
blockify([{test,is_atom,{f,Fail},[Reg]}=I|
- [{select_val,Reg,{f,Fail},
- {list,[{atom,true}=AtomTrue,{f,_}=BrTrue,
- {atom,false},{f,_}=BrFalse]}}|Is]=Is0],
+ [{select,select_val,Reg,{f,Fail},
+ [{atom,true}=AtomTrue,{f,_}=BrTrue,
+ {atom,false},{f,_}=BrFalse]}|Is]=Is0],
[{block,Bl}|_]=Acc) ->
case is_last_bool(Bl, Reg) of
false ->
@@ -423,8 +420,8 @@ inverse_comp_op(_) -> none.
%%% Evaluation of constant bit fields.
%%%
-is_bs_put({bs_put_integer,_,_,_,_,_}) -> true;
-is_bs_put({bs_put_float,_,_,_,_,_}) -> true;
+is_bs_put({bs_put,_,{bs_put_integer,_,_},_}) -> true;
+is_bs_put({bs_put,_,{bs_put_float,_,_},_}) -> true;
is_bs_put(_) -> false.
collect_bs_puts(Is) ->
@@ -439,20 +436,24 @@ collect_bs_puts_1([I|Is]=Is0, Acc) ->
opt_bs_puts(Is) ->
opt_bs_1(Is, []).
-opt_bs_1([{bs_put_float,Fail,{integer,Sz},1,Flags0,Src}=I0|Is], Acc) ->
+opt_bs_1([{bs_put,Fail,
+ {bs_put_float,1,Flags0},[{integer,Sz},Src]}=I0|Is], Acc) ->
try eval_put_float(Src, Sz, Flags0) of
<<Int:Sz>> ->
Flags = force_big(Flags0),
- I = {bs_put_integer,Fail,{integer,Sz},1,Flags,{integer,Int}},
+ I = {bs_put,Fail,{bs_put_integer,1,Flags},
+ [{integer,Sz},{integer,Int}]},
opt_bs_1([I|Is], Acc)
catch
error:_ ->
opt_bs_1(Is, [I0|Acc])
end;
-opt_bs_1([{bs_put_integer,_,{integer,8},1,_,{integer,_}}|_]=IsAll, Acc0) ->
+opt_bs_1([{bs_put,_,{bs_put_integer,1,_},[{integer,8},{integer,_}]}|_]=IsAll,
+ Acc0) ->
{Is,Acc} = bs_collect_string(IsAll, Acc0),
opt_bs_1(Is, Acc);
-opt_bs_1([{bs_put_integer,Fail,{integer,Sz},1,F,{integer,N}}=I|Is0], Acc) when Sz > 8 ->
+opt_bs_1([{bs_put,Fail,{bs_put_integer,1,F},[{integer,Sz},{integer,N}]}=I|Is0],
+ Acc) when Sz > 8 ->
case field_endian(F) of
big ->
%% We can do this optimization for any field size without risk
@@ -466,14 +467,14 @@ opt_bs_1([{bs_put_integer,Fail,{integer,Sz},1,F,{integer,N}}=I|Is0], Acc) when S
%% an explosion in code size.
<<Int:Sz>> = <<N:Sz/little>>,
Flags = force_big(F),
- Is = [{bs_put_integer,Fail,{integer,Sz},1,
- Flags,{integer,Int}}|Is0],
+ Is = [{bs_put,Fail,{bs_put_integer,1,Flags},
+ [{integer,Sz},{integer,Int}]}|Is0],
opt_bs_1(Is, Acc);
_ -> %native or too wide little field
opt_bs_1(Is0, [I|Acc])
end;
-opt_bs_1([{Op,Fail,{integer,Sz},U,F,Src}|Is], Acc) when U > 1 ->
- opt_bs_1([{Op,Fail,{integer,U*Sz},1,F,Src}|Is], Acc);
+opt_bs_1([{bs_put,Fail,{Op,U,F},[{integer,Sz},Src]}|Is], Acc) when U > 1 ->
+ opt_bs_1([{bs_put,Fail,{Op,1,F},[{integer,U*Sz},Src]}|Is], Acc);
opt_bs_1([I|Is], Acc) ->
opt_bs_1(Is, [I|Acc]);
opt_bs_1([], Acc) -> reverse(Acc).
@@ -489,17 +490,17 @@ eval_put_float(Src, Sz, Flags) when Sz =< 256 -> %Only evaluate if Sz is reasona
value({integer,I}) -> I;
value({float,F}) -> F.
-bs_collect_string(Is, [{bs_put_string,Len,{string,Str}}|Acc]) ->
+bs_collect_string(Is, [{bs_put,_,{bs_put_string,Len,{string,Str}},[]}|Acc]) ->
bs_coll_str_1(Is, Len, reverse(Str), Acc);
bs_collect_string(Is, Acc) ->
bs_coll_str_1(Is, 0, [], Acc).
-bs_coll_str_1([{bs_put_integer,_,{integer,Sz},U,_,{integer,V}}|Is],
+bs_coll_str_1([{bs_put,_,{bs_put_integer,U,_},[{integer,Sz},{integer,V}]}|Is],
Len, StrAcc, IsAcc) when U*Sz =:= 8 ->
Byte = V band 16#FF,
bs_coll_str_1(Is, Len+1, [Byte|StrAcc], IsAcc);
bs_coll_str_1(Is, Len, StrAcc, IsAcc) ->
- {Is,[{bs_put_string,Len,{string,reverse(StrAcc)}}|IsAcc]}.
+ {Is,[{bs_put,{f,0},{bs_put_string,Len,{string,reverse(StrAcc)}},[]}|IsAcc]}.
field_endian({field_flags,F}) -> field_endian_1(F).
@@ -531,15 +532,17 @@ bs_split_int(N, Sz, Fail, Acc) ->
bs_split_int_1(N, FirstByteSz, Sz, Fail, Acc).
bs_split_int_1(-1, _, Sz, Fail, Acc) when Sz > 64 ->
- I = {bs_put_integer,Fail,{integer,Sz},1,{field_flags,[big]},{integer,-1}},
+ I = {bs_put,Fail,{bs_put_integer,1,{field_flags,[big]}},
+ [{integer,Sz},{integer,-1}]},
[I|Acc];
bs_split_int_1(0, _, Sz, Fail, Acc) when Sz > 64 ->
- I = {bs_put_integer,Fail,{integer,Sz},1,{field_flags,[big]},{integer,0}},
+ I = {bs_put,Fail,{bs_put_integer,1,{field_flags,[big]}},
+ [{integer,Sz},{integer,0}]},
[I|Acc];
bs_split_int_1(N, ByteSz, Sz, Fail, Acc) when Sz > 0 ->
Mask = (1 bsl ByteSz) - 1,
- I = {bs_put_integer,Fail,{integer,ByteSz},1,
- {field_flags,[big]},{integer,N band Mask}},
+ I = {bs_put,Fail,{bs_put_integer,1,{field_flags,[big]}},
+ [{integer,ByteSz},{integer,N band Mask}]},
bs_split_int_1(N bsr ByteSz, 8, Sz-ByteSz, Fail, [I|Acc]);
bs_split_int_1(_, _, _, _, Acc) -> Acc.
@@ -577,9 +580,9 @@ bsm_reroute([{bs_restore2,Reg,Save}=I|Is], D, _, Acc) ->
bsm_reroute(Is, D, {Reg,Save}, [I|Acc]);
bsm_reroute([{label,_}=I|Is], D, S, Acc) ->
bsm_reroute(Is, D, S, [I|Acc]);
-bsm_reroute([{select_val,Reg,F0,{list,Lbls0}}|Is], D, {_,Save}=S, Acc0) ->
+bsm_reroute([{select,select_val,Reg,F0,Lbls0}|Is], D, {_,Save}=S, Acc0) ->
[F|Lbls] = bsm_subst_labels([F0|Lbls0], Save, D),
- Acc = [{select_val,Reg,F,{list,Lbls}}|Acc0],
+ Acc = [{select,select_val,Reg,F,Lbls}|Acc0],
bsm_reroute(Is, D, S, Acc);
bsm_reroute([{test,TestOp,F0,TestArgs}=I|Is], D, {_,Save}=S, Acc0) ->
F = bsm_subst_label(F0, Save, D),
@@ -615,10 +618,6 @@ bsm_opt_2([{test,bs_skip_bits2,F,[Ctx,{integer,I1},Unit1,_]}|Is],
[{test,bs_skip_bits2,F,[Ctx,{integer,I2},Unit2,Flags]}|Acc]) ->
bsm_opt_2(Is, [{test,bs_skip_bits2,F,
[Ctx,{integer,I1*Unit1+I2*Unit2},1,Flags]}|Acc]);
-bsm_opt_2([{test,bs_match_string,F,[Ctx,Bin1]},
- {test,bs_match_string,F,[Ctx,Bin2]}|Is], Acc) ->
- I = {test,bs_match_string,F,[Ctx,<<Bin1/bitstring,Bin2/bitstring>>]},
- bsm_opt_2([I|Is], Acc);
bsm_opt_2([I|Is], Acc) ->
bsm_opt_2(Is, [I|Acc]);
bsm_opt_2([], Acc) -> reverse(Acc).
diff --git a/lib/compiler/src/beam_bool.erl b/lib/compiler/src/beam_bool.erl
index d9ea6f5a70..81be262d6d 100644
--- a/lib/compiler/src/beam_bool.erl
+++ b/lib/compiler/src/beam_bool.erl
@@ -168,18 +168,18 @@ bopt_block(Reg, Fail, OldIs, [{block,Bl0}|Acc0], St0) ->
end.
%% ensure_opt_safe(OriginalCode, OptCode, FollowingCode, Fail,
-%% ReversedPreceedingCode, State) -> ok
+%% ReversedPrecedingCode, State) -> ok
%% Comparing the original code to the optimized code, determine
%% whether the optimized code is guaranteed to work in the same
%% way as the original code.
%%
%% Throw an exception if the optimization is not safe.
%%
-ensure_opt_safe(Bl, NewCode, OldIs, Fail, PreceedingCode, St) ->
+ensure_opt_safe(Bl, NewCode, OldIs, Fail, PrecedingCode, St) ->
%% Here are the conditions that must be true for the
%% optimization to be safe.
%%
- %% 1. If a register is INITIALIZED by PreceedingCode,
+ %% 1. If a register is INITIALIZED by PrecedingCode,
%% then if that register assigned a value in the original
%% code, but not in the optimized code, it must be UNUSED or KILLED
%% in the code that follows.
@@ -190,29 +190,50 @@ ensure_opt_safe(Bl, NewCode, OldIs, Fail, PreceedingCode, St) ->
%% by the code that follows.
%%
%% 3. Any register that is assigned a value in the optimized
- %% code must be UNUSED or KILLED in the following code
- %% (because the register might be assigned the wrong value,
- %% and even if the value is right it might no longer be
- %% assigned on *all* paths leading to its use).
+ %% code must be UNUSED or KILLED in the following code,
+ %% unless we can be sure that it is always assigned the same
+ %% value.
- InitInPreceeding = initialized_regs(PreceedingCode),
+ InitInPreceding = initialized_regs(PrecedingCode),
PrevDst = dst_regs(Bl),
NewDst = dst_regs(NewCode),
NotSet = ordsets:subtract(PrevDst, NewDst),
- MustBeKilled = ordsets:subtract(NotSet, InitInPreceeding),
- MustBeUnused = ordsets:subtract(ordsets:union(NotSet, NewDst), MustBeKilled),
+ MustBeKilled = ordsets:subtract(NotSet, InitInPreceding),
case all_killed(MustBeKilled, OldIs, Fail, St) of
false -> throw(all_registers_not_killed);
true -> ok
end,
+ Same = assigned_same_value(Bl, NewCode),
+ MustBeUnused = ordsets:subtract(ordsets:union(NotSet, NewDst),
+ ordsets:union(MustBeKilled, Same)),
case none_used(MustBeUnused, OldIs, Fail, St) of
false -> throw(registers_used);
true -> ok
end,
ok.
+%% assigned_same_value(OldCode, NewCodeReversed) -> [DestinationRegs]
+%% Return an ordset with a list of all y registers that are always
+%% assigned the same value in the old and new code. Currently, we
+%% are very conservative in that we only consider identical move
+%% instructions in the same order.
+%%
+assigned_same_value(Old, New) ->
+ case reverse(New) of
+ [{block,Bl}|_] ->
+ assigned_same_value(Old, Bl, []);
+ _ ->
+ ordsets:new()
+ end.
+
+assigned_same_value([{set,[{y,_}=D],[S],move}|T1],
+ [{set,[{y,_}=D],[S],move}|T2], Acc) ->
+ assigned_same_value(T1, T2, [D|Acc]);
+assigned_same_value(_, _, Acc) ->
+ ordsets:from_list(Acc).
+
update_fail_label([{set,_,_,move}=I|Is], Fail, Acc) ->
update_fail_label(Is, Fail, [I|Acc]);
update_fail_label([{set,Ds,As,{bif,N,{f,_}}}|Is], Fail, Acc) ->
diff --git a/lib/compiler/src/beam_bsm.erl b/lib/compiler/src/beam_bsm.erl
index 1217f7f777..02794a8e18 100644
--- a/lib/compiler/src/beam_bsm.erl
+++ b/lib/compiler/src/beam_bsm.erl
@@ -204,16 +204,6 @@ 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_only,Arity,{f,Lbl}}|_], Regs0, D) ->
- Regs = btb_kill_not_live(Arity, Regs0),
- btb_tail_call(Lbl, Regs, D);
-btb_reaches_match_2([{call_ext_only,Arity,Func}|_], Regs0, D) ->
- Regs = btb_kill_not_live(Arity, Regs0),
- btb_tail_call(Func, Regs, D);
-btb_reaches_match_2([{call_last,Arity,{f,Lbl},_}|_], Regs0, D) ->
- Regs1 = btb_kill_not_live(Arity, Regs0),
- Regs = btb_kill_yregs(Regs1),
- btb_tail_call(Lbl, Regs, D);
btb_reaches_match_2([{call,Arity,{f,Lbl}}|Is], Regs, D) ->
btb_call(Arity, Lbl, Regs, Is, D);
btb_reaches_match_2([{apply,Arity}|Is], Regs, D) ->
@@ -222,19 +212,16 @@ btb_reaches_match_2([{call_fun,Live}=I|Is], Regs, D) ->
btb_call(Live, I, Regs, Is, D);
btb_reaches_match_2([{make_fun2,_,_,_,Live}|Is], Regs, D) ->
btb_call(Live, make_fun2, Regs, Is, D);
-btb_reaches_match_2([{call_ext,Arity,{extfunc,Mod,Name,Arity}=Func}|Is], Regs0, D) ->
+btb_reaches_match_2([{call_ext,Arity,Func}=I|Is], Regs0, D) ->
%% Allow us scanning beyond the call in case the match
%% context is saved on the stack.
- case erl_bifs:is_exit_bif(Mod, Name, Arity) of
+ case beam_jump:is_exit_instruction(I) of
false ->
btb_call(Arity, Func, Regs0, Is, D);
true ->
Regs = btb_kill_not_live(Arity, Regs0),
btb_tail_call(Func, Regs, D)
end;
-btb_reaches_match_2([{call_ext_last,Arity,_,_}=I|_], Regs, D) ->
- btb_ensure_not_used(btb_regs_from_arity(Arity), I, Regs),
- D;
btb_reaches_match_2([{kill,Y}|Is], Regs, D) ->
btb_reaches_match_1(Is, btb_kill([Y], Regs), D);
btb_reaches_match_2([{deallocate,_}|Is], Regs0, D) ->
@@ -254,21 +241,45 @@ btb_reaches_match_2([{bif,_,{f,F},Ss,Dst}=I|Is], Regs0, D0) ->
Regs = btb_kill([Dst], Regs0),
D = btb_follow_branch(F, Regs, D0),
btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{test,bs_start_match2,_,_,[Ctx,_],Ctx}|Is], Regs, D) ->
- case btb_context_regs(Regs) of
- [Ctx] ->
- D;
- CtxRegs ->
- case member(Ctx, CtxRegs) of
- false -> btb_reaches_match_2(Is, Regs, D);
- true -> btb_error(unsuitable_bs_start_match)
+btb_reaches_match_2([{test,bs_start_match2,{f,F},Live,[Ctx,_],Ctx}=I|Is],
+ Regs0, D0) ->
+ CtxRegs = btb_context_regs(Regs0),
+ case member(Ctx, CtxRegs) of
+ false ->
+ %% This bs_start_match2 instruction does not use "our"
+ %% match state. Therefore we can continue the search
+ %% for another bs_start_match2 instruction.
+ D = btb_follow_branch(F, Regs0, D0),
+ Regs = btb_kill_not_live(Live, Regs0),
+ btb_reaches_match_2(Is, Regs, D);
+ true ->
+ %% OK. This instruction will use "our" match state,
+ %% but we must make sure that all other copies of the
+ %% match state are killed in the code that follows
+ %% the instruction. (We know that the fail branch cannot
+ %% be taken in this case.)
+ OtherCtxRegs = CtxRegs -- [Ctx],
+ case btb_are_all_unused(OtherCtxRegs, Is, D0) of
+ false -> btb_error({OtherCtxRegs,not_all_unused_after,I});
+ true -> D0
end
end;
-btb_reaches_match_2([{test,bs_start_match2,_,_,[Bin,_],Ctx}|Is], Regs, D) ->
- CtxRegs = btb_context_regs(Regs),
+btb_reaches_match_2([{test,bs_start_match2,{f,F},Live,[Bin,_],Ctx}|Is],
+ Regs0, D0) ->
+ CtxRegs = btb_context_regs(Regs0),
case member(Bin, CtxRegs) orelse member(Ctx, CtxRegs) of
- false -> btb_reaches_match_2(Is, Regs, D);
- true -> btb_error(unsuitable_bs_start_match)
+ false ->
+ %% This bs_start_match2 does not reference any copy of the
+ %% match state. Therefore it can safely be passed on the
+ %% way to another (perhaps more suitable) bs_start_match2
+ %% instruction.
+ D = btb_follow_branch(F, Regs0, D0),
+ Regs = btb_kill_not_live(Live, Regs0),
+ btb_reaches_match_2(Is, Regs, D);
+ true ->
+ %% This variant of the bs_start_match2 instruction does
+ %% not accept a match state as source.
+ btb_error(unsuitable_bs_start_match)
end;
btb_reaches_match_2([{test,_,{f,F},Ss}=I|Is], Regs, D0) ->
btb_ensure_not_used(Ss, I, Regs),
@@ -278,12 +289,7 @@ btb_reaches_match_2([{test,_,{f,F},_,Ss,_}=I|Is], Regs, D0) ->
btb_ensure_not_used(Ss, I, Regs),
D = btb_follow_branch(F, Regs, D0),
btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{select_val,Src,{f,F},{list,Conds}}=I|Is], Regs, D0) ->
- btb_ensure_not_used([Src], I, Regs),
- D1 = btb_follow_branch(F, Regs, D0),
- D = btb_follow_branches(Conds, Regs, D1),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{select_tuple_arity,Src,{f,F},{list,Conds}}=I|Is], Regs, D0) ->
+btb_reaches_match_2([{select,_,Src,{f,F},Conds}=I|Is], Regs, D0) ->
btb_ensure_not_used([Src], I, Regs),
D1 = btb_follow_branch(F, Regs, D0),
D = btb_follow_branches(Conds, Regs, D1),
@@ -293,46 +299,11 @@ btb_reaches_match_2([{jump,{f,Lbl}}|_], Regs, #btb{index=Li}=D) ->
btb_reaches_match_2(Is, Regs, D);
btb_reaches_match_2([{label,_}|Is], Regs, D) ->
btb_reaches_match_2(Is, Regs, D);
-btb_reaches_match_2([{bs_add,{f,0},_,Dst}|Is], Regs, D) ->
- btb_reaches_match_1(Is, btb_kill([Dst], Regs), D);
-btb_reaches_match_2([bs_init_writable|Is], Regs0, D) ->
- Regs = btb_kill_not_live(0, Regs0),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{bs_init2,{f,0},_,_,_,_,Dst}|Is], Regs, D) ->
- btb_reaches_match_1(Is, btb_kill([Dst], Regs), D);
-btb_reaches_match_2([{bs_init_bits,{f,0},_,_,_,_,Dst}|Is], Regs, D) ->
- btb_reaches_match_1(Is, btb_kill([Dst], Regs), D);
-btb_reaches_match_2([{bs_append,{f,0},_,_,_,_,Src,_,Dst}=I|Is], Regs, D) ->
- btb_ensure_not_used([Src], I, Regs),
- btb_reaches_match_1(Is, btb_kill([Dst], Regs), D);
-btb_reaches_match_2([{bs_private_append,{f,0},_,_,Src,_,Dst}=I|Is], Regs, D) ->
- btb_ensure_not_used([Src], I, Regs),
- btb_reaches_match_1(Is, btb_kill([Dst], Regs), D);
-btb_reaches_match_2([{bs_put_integer,{f,0},_,_,_,Src}=I|Is], Regs, D) ->
- btb_ensure_not_used([Src], I, Regs),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{bs_put_float,{f,0},_,_,_,Src}=I|Is], Regs, D) ->
- btb_ensure_not_used([Src], I, Regs),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{bs_put_binary,{f,0},_,_,_,Src}=I|Is], Regs, D) ->
- btb_ensure_not_used([Src], I, Regs),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{bs_put_string,_,_}|Is], Regs, D) ->
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{bs_utf8_size,_,Src,Dst}=I|Is], Regs, D) ->
- btb_ensure_not_used([Src], I, Regs),
- btb_reaches_match_1(Is, btb_kill([Dst], Regs), D);
-btb_reaches_match_2([{bs_utf16_size,_,Src,Dst}=I|Is], Regs, D) ->
- btb_ensure_not_used([Src], I, Regs),
+btb_reaches_match_2([{bs_init,{f,0},_,_,Ss,Dst}=I|Is], Regs, D) ->
+ btb_ensure_not_used(Ss, I, Regs),
btb_reaches_match_1(Is, btb_kill([Dst], Regs), D);
-btb_reaches_match_2([{bs_put_utf8,_,_,Src}=I|Is], Regs, D) ->
- btb_ensure_not_used([Src], I, Regs),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{bs_put_utf16,_,_,Src}=I|Is], Regs, D) ->
- btb_ensure_not_used([Src], I, Regs),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{bs_put_utf32,_,_,Src}=I|Is], Regs, D) ->
- btb_ensure_not_used([Src], I, Regs),
+btb_reaches_match_2([{bs_put,{f,0},_,Ss}=I|Is], Regs, D) ->
+ btb_ensure_not_used(Ss, I, Regs),
btb_reaches_match_1(Is, Regs, D);
btb_reaches_match_2([{bs_restore2,Src,_}=I|Is], Regs0, D) ->
case btb_contains_context(Src, Regs0) of
@@ -340,11 +311,11 @@ btb_reaches_match_2([{bs_restore2,Src,_}=I|Is], Regs0, D) ->
btb_reaches_match_1(Is, Regs0, D);
true ->
%% Check that all other copies of the context registers
- %% are killed by the following instructions.
+ %% are unused by the following instructions.
Regs = btb_kill([Src], Regs0),
CtxRegs = btb_context_regs(Regs),
- case btb_are_all_killed(CtxRegs, Is, D) of
- false -> btb_error({CtxRegs,not_all_killed_after,I});
+ case btb_are_all_unused(CtxRegs, Is, D) of
+ false -> btb_error({CtxRegs,not_all_unused_after,I});
true -> D#btb{must_not_save=true}
end
end;
@@ -354,11 +325,11 @@ btb_reaches_match_2([{bs_context_to_binary,Src}=I|Is], Regs0, D) ->
btb_reaches_match_1(Is, Regs0, D);
true ->
%% Check that all other copies of the context registers
- %% are killed by the following instructions.
+ %% are unused by the following instructions.
Regs = btb_kill([Src], Regs0),
CtxRegs = btb_context_regs(Regs),
- case btb_are_all_killed(CtxRegs, Is, D) of
- false -> btb_error({CtxRegs,not_all_killed_after,I});
+ case btb_are_all_unused(CtxRegs, Is, D) of
+ false -> btb_error({CtxRegs,not_all_unused_after,I});
true -> D#btb{must_not_save=true}
end
end;
@@ -389,13 +360,16 @@ btb_call(Arity, Lbl, Regs0, Is, D0) ->
%% First handle the call as if it were a tail call.
D = btb_tail_call(Lbl, Regs, D0),
- %% No problem so far, but now we must make sure that
- %% we don't have any copies of the match context
- %% tucked away in an y register.
+ %% 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.
RegList = btb_context_regs(Regs),
- case [R || {y,_}=R <- RegList] of
- [] -> D;
- [_|_] -> btb_error({multiple_uses,RegList})
+ YRegs = [R || {y,_}=R <- RegList],
+ case btb_are_all_unused(YRegs, Is, D) of
+ true -> D;
+ false -> btb_error({multiple_uses,RegList})
end;
true ->
%% No match context in any x register. It could have been
@@ -475,21 +449,12 @@ btb_reaches_match_block([{set,Ds,Ss,_}=I|Is], Regs0) ->
btb_reaches_match_block([], Regs) ->
Regs.
-%% btb_regs_from_arity(Arity) -> [Register])
-%% Create a list of x registers from a function arity.
-
-btb_regs_from_arity(Arity) ->
- btb_regs_from_arity_1(Arity, []).
-
-btb_regs_from_arity_1(0, Acc) -> Acc;
-btb_regs_from_arity_1(N, Acc) -> btb_regs_from_arity_1(N-1, [{x,N-1}|Acc]).
-
%% btb_are_all_killed([Register], [Instruction], D) -> true|false
-%% Test whether all of the register are killed in the instruction stream.
+%% Test whether all of the register are unused in the instruction stream.
-btb_are_all_killed(RegList, Is, #btb{index=Li}) ->
+btb_are_all_unused(RegList, Is, #btb{index=Li}) ->
all(fun(R) ->
- beam_utils:is_killed(R, Is, Li)
+ beam_utils:is_not_used(R, Is, Li)
end, RegList).
%% btp_regs_from_list([Register]) -> RegisterSet.
diff --git a/lib/compiler/src/beam_clean.erl b/lib/compiler/src/beam_clean.erl
index a7994ab3b3..26ba93b91c 100644
--- a/lib/compiler/src/beam_clean.erl
+++ b/lib/compiler/src/beam_clean.erl
@@ -74,10 +74,6 @@ find_all_used([], _All, Used) -> Used.
update_work_list([{call,_,{f,L}}|Is], Sets) ->
update_work_list(Is, add_to_work_list(L, Sets));
-update_work_list([{call_last,_,{f,L},_}|Is], Sets) ->
- update_work_list(Is, add_to_work_list(L, Sets));
-update_work_list([{call_only,_,{f,L}}|Is], Sets) ->
- update_work_list(Is, add_to_work_list(L, Sets));
update_work_list([{make_fun2,{f,L},_,_,_}|Is], Sets) ->
update_work_list(Is, add_to_work_list(L, Sets));
update_work_list([_|Is], Sets) ->
@@ -200,7 +196,7 @@ replace([{test,Test,{f,Lbl},Ops}|Is], Acc, D) ->
replace(Is, [{test,Test,{f,label(Lbl, D)},Ops}|Acc], D);
replace([{test,Test,{f,Lbl},Live,Ops,Dst}|Is], Acc, D) ->
replace(Is, [{test,Test,{f,label(Lbl, D)},Live,Ops,Dst}|Acc], D);
-replace([{select_val,R,{f,Fail0},{list,Vls0}}|Is], Acc, D) ->
+replace([{select,I,R,{f,Fail0},Vls0}|Is], Acc, D) ->
Vls1 = map(fun ({f,L}) -> {f,label(L, D)};
(Other) -> Other end, Vls0),
Fail = label(Fail0, D),
@@ -210,12 +206,8 @@ replace([{select_val,R,{f,Fail0},{list,Vls0}}|Is], Acc, D) ->
%% Convert to a plain jump.
replace(Is, [{jump,{f,Fail}}|Acc], D);
Vls ->
- replace(Is, [{select_val,R,{f,Fail},{list,Vls}}|Acc], D)
+ replace(Is, [{select,I,R,{f,Fail},Vls}|Acc], D)
end;
-replace([{select_tuple_arity,R,{f,Fail},{list,Vls0}}|Is], Acc, D) ->
- Vls = map(fun ({f,L}) -> {f,label(L, D)};
- (Other) -> Other end, Vls0),
- replace(Is, [{select_tuple_arity,R,{f,label(Fail, D)},{list,Vls}}|Acc], D);
replace([{'try',R,{f,Lbl}}|Is], Acc, D) ->
replace(Is, [{'try',R,{f,label(Lbl, D)}}|Acc], D);
replace([{'catch',R,{f,Lbl}}|Is], Acc, D) ->
@@ -236,37 +228,12 @@ replace([{gc_bif,Name,{f,Lbl},Live,As,R}|Is], Acc, D) when Lbl =/= 0 ->
replace(Is, [{gc_bif,Name,{f,label(Lbl, D)},Live,As,R}|Acc], D);
replace([{call,Ar,{f,Lbl}}|Is], Acc, D) ->
replace(Is, [{call,Ar,{f,label(Lbl,D)}}|Acc], D);
-replace([{call_last,Ar,{f,Lbl},N}|Is], Acc, D) ->
- replace(Is, [{call_last,Ar,{f,label(Lbl,D)},N}|Acc], D);
-replace([{call_only,Ar,{f,Lbl}}|Is], Acc, D) ->
- replace(Is, [{call_only,Ar,{f,label(Lbl, D)}}|Acc], D);
replace([{make_fun2,{f,Lbl},U1,U2,U3}|Is], Acc, D) ->
replace(Is, [{make_fun2,{f,label(Lbl, D)},U1,U2,U3}|Acc], D);
-replace([{bs_init2,{f,Lbl},Sz,Words,R,F,Dst}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{bs_init2,{f,label(Lbl, D)},Sz,Words,R,F,Dst}|Acc], D);
-replace([{bs_init_bits,{f,Lbl},Sz,Words,R,F,Dst}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{bs_init_bits,{f,label(Lbl, D)},Sz,Words,R,F,Dst}|Acc], D);
-replace([{bs_put_integer,{f,Lbl},Bits,Unit,Fl,Val}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{bs_put_integer,{f,label(Lbl, D)},Bits,Unit,Fl,Val}|Acc], D);
-replace([{bs_put_utf8=I,{f,Lbl},Fl,Val}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{I,{f,label(Lbl, D)},Fl,Val}|Acc], D);
-replace([{bs_put_utf16=I,{f,Lbl},Fl,Val}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{I,{f,label(Lbl, D)},Fl,Val}|Acc], D);
-replace([{bs_put_utf32=I,{f,Lbl},Fl,Val}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{I,{f,label(Lbl, D)},Fl,Val}|Acc], D);
-replace([{bs_put_binary,{f,Lbl},Bits,Unit,Fl,Val}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{bs_put_binary,{f,label(Lbl, D)},Bits,Unit,Fl,Val}|Acc], D);
-replace([{bs_put_float,{f,Lbl},Bits,Unit,Fl,Val}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{bs_put_float,{f,label(Lbl, D)},Bits,Unit,Fl,Val}|Acc], D);
-replace([{bs_add,{f,Lbl},Src,Dst}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{bs_add,{f,label(Lbl, D)},Src,Dst}|Acc], D);
-replace([{bs_append,{f,Lbl},_,_,_,_,_,_,_}=I0|Is], Acc, D) when Lbl =/= 0 ->
- I = setelement(2, I0, {f,label(Lbl, D)}),
- replace(Is, [I|Acc], D);
-replace([{bs_utf8_size=I,{f,Lbl},Src,Dst}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{I,{f,label(Lbl, D)},Src,Dst}|Acc], D);
-replace([{bs_utf16_size=I,{f,Lbl},Src,Dst}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{I,{f,label(Lbl, D)},Src,Dst}|Acc], D);
+replace([{bs_init,{f,Lbl},Info,Live,Ss,Dst}|Is], Acc, D) when Lbl =/= 0 ->
+ replace(Is, [{bs_init,{f,label(Lbl, D)},Info,Live,Ss,Dst}|Acc], D);
+replace([{bs_put,{f,Lbl},Info,Ss}|Is], Acc, D) when Lbl =/= 0 ->
+ replace(Is, [{bs_put,{f,label(Lbl, D)},Info,Ss}|Acc], D);
replace([I|Is], Acc, D) ->
replace(Is, [I|Acc], D);
replace([], Acc, _) -> Acc.
diff --git a/lib/compiler/src/beam_dead.erl b/lib/compiler/src/beam_dead.erl
index 5f12a98f09..92d8e5acb3 100644
--- a/lib/compiler/src/beam_dead.erl
+++ b/lib/compiler/src/beam_dead.erl
@@ -182,7 +182,7 @@ forward(Is, Lc) ->
forward([{block,[]}|Is], D, Lc, Acc) ->
%% Empty blocks can prevent optimizations.
forward(Is, D, Lc, Acc);
-forward([{select_val,Reg,_,{list,List}}=I|Is], D0, Lc, Acc) ->
+forward([{select,select_val,Reg,_,List}=I|Is], D0, Lc, Acc) ->
D = update_value_dict(List, Reg, D0),
forward(Is, D, Lc, [I|Acc]);
forward([{label,Lbl}=LblI,{block,[{set,[Dst],[Lit],move}|BlkIs]}=Blk|Is], D, Lc, Acc) ->
@@ -271,11 +271,11 @@ backward([{test,is_eq_exact,Fail,[Dst,{integer,Arity}]}=I|
end;
backward([{label,Lbl}=L|Is], D, Acc) ->
backward(Is, beam_utils:index_label(Lbl, Acc, D), [L|Acc]);
-backward([{select_val,Reg,{f,Fail0},{list,List0}}|Is], D, Acc) ->
+backward([{select,select_val,Reg,{f,Fail0},List0}|Is], D, Acc) ->
List = shortcut_select_list(List0, Reg, D, []),
Fail1 = shortcut_label(Fail0, D),
Fail = shortcut_bs_test(Fail1, Is, D),
- Sel = {select_val,Reg,{f,Fail},{list,List}},
+ Sel = {select,select_val,Reg,{f,Fail},List},
backward(Is, D, [Sel|Acc]);
backward([{jump,{f,To0}},{move,Src,Reg}=Move0|Is], D, Acc) ->
{To,Move} = case Src of
@@ -382,7 +382,7 @@ shortcut_select_label(To0, Reg, Val, D) ->
case beam_utils:code_at(To0, D) of
[{jump,{f,To}}|_] ->
shortcut_select_label(To, Reg, Val, D);
- [{test,is_atom,_,[Reg]},{select_val,Reg,{f,Fail},{list,Map}}|_] ->
+ [{test,is_atom,_,[Reg]},{select,select_val,Reg,{f,Fail},Map}|_] ->
To = find_select_val(Map, Val, Fail),
shortcut_select_label(To, Reg, Val, D);
[{test,is_eq_exact,{f,_},[Reg,{atom,Val}]},{label,To}|_] when is_atom(Val) ->
@@ -472,10 +472,10 @@ combine_eqs(To, [Reg,{Type,_}=Lit1]=Ops, D, [{label,L1}|_])
case beam_utils:code_at(To, D) of
[{test,is_eq_exact,{f,F2},[Reg,{Type,_}=Lit2]},
{label,L2}|_] when Lit1 =/= Lit2 ->
- {select_val,Reg,{f,F2},{list,[Lit1,{f,L1},Lit2,{f,L2}]}};
- [{select_val,Reg,{f,F2},{list,[{Type,_}|_]=List0}}|_] ->
+ {select,select_val,Reg,{f,F2},[Lit1,{f,L1},Lit2,{f,L2}]};
+ [{select,select_val,Reg,{f,F2},[{Type,_}|_]=List0}|_] ->
List = remove_from_list(Lit1, List0),
- {select_val,Reg,{f,F2},{list,[Lit1,{f,L1}|List]}};
+ {select,select_val,Reg,{f,F2},[Lit1,{f,L1}|List]};
_Is ->
{test,is_eq_exact,{f,To},Ops}
end;
@@ -527,6 +527,8 @@ count_bits_matched([{test,_,_,_,[_,Sz,U,{field_flags,_}],_}|Is], SavePoint, Bits
{integer,N} -> count_bits_matched(Is, SavePoint, Bits+N*U);
_ -> count_bits_matched(Is, SavePoint, Bits)
end;
+count_bits_matched([{test,bs_match_string,_,[_,Bits,_]}|Is], SavePoint, Bits0) ->
+ count_bits_matched(Is, SavePoint, Bits0+Bits);
count_bits_matched([{test,_,_,_}|Is], SavePoint, Bits) ->
count_bits_matched(Is, SavePoint, Bits);
count_bits_matched([{bs_save2,Reg,SavePoint}|_], {Reg,SavePoint}, Bits) ->
diff --git a/lib/compiler/src/beam_dict.erl b/lib/compiler/src/beam_dict.erl
index 531968b3c8..ff6c7c11dc 100644
--- a/lib/compiler/src/beam_dict.erl
+++ b/lib/compiler/src/beam_dict.erl
@@ -138,7 +138,17 @@ string(Str, Dict) when is_list(Str) ->
-spec lambda(label(), non_neg_integer(), bdict()) ->
{non_neg_integer(), bdict()}.
-lambda(Lbl, NumFree, #asm{lambdas=Lambdas0}=Dict) ->
+lambda(Lbl, 0, #asm{lambdas=Lambdas0}=Dict) ->
+ case lists:keyfind(Lbl, 1, Lambdas0) of
+ {Lbl,{OldIndex,_,_,_,_}} ->
+ {OldIndex,Dict};
+ false ->
+ new_lambda(Lbl, 0, Dict)
+ end;
+lambda(Lbl, NumFree, Dict) ->
+ new_lambda(Lbl, NumFree, Dict).
+
+new_lambda(Lbl, NumFree, #asm{lambdas=Lambdas0}=Dict) ->
OldIndex = length(Lambdas0),
%% Set Index the same as OldIndex.
Index = OldIndex,
@@ -235,10 +245,12 @@ string_table(#asm{strings=Strings,string_offset=Size}) ->
-spec lambda_table(bdict()) -> {non_neg_integer(), [<<_:192>>]}.
-lambda_table(#asm{locals=Loc0,lambdas=Lambdas0}) ->
+lambda_table(#asm{exports=Ext0,locals=Loc0,lambdas=Lambdas0}) ->
Lambdas1 = sofs:relation(Lambdas0),
Loc = sofs:relation([{Lbl,{F,A}} || {F,A,Lbl} <- Loc0]),
- Lambdas2 = sofs:relative_product1(Lambdas1, Loc),
+ Ext = sofs:relation([{Lbl,{F,A}} || {F,A,Lbl} <- Ext0]),
+ All = sofs:union(Loc, Ext),
+ Lambdas2 = sofs:relative_product1(Lambdas1, All),
Lambdas = [<<F:32,A:32,Lbl:32,Index:32,NumFree:32,OldUniq:32>> ||
{{_,Lbl,Index,NumFree,OldUniq},{F,A}} <- sofs:to_external(Lambdas2)],
{length(Lambdas),Lambdas}.
diff --git a/lib/compiler/src/beam_except.erl b/lib/compiler/src/beam_except.erl
index fb1a43cd9e..14e9943f88 100644
--- a/lib/compiler/src/beam_except.erl
+++ b/lib/compiler/src/beam_except.erl
@@ -65,10 +65,6 @@ function_1(Is0) ->
translate([{call_ext,Ar,{extfunc,erlang,error,Ar}}=I|Is], St, Acc) ->
translate_1(Ar, I, Is, St, Acc);
-translate([{call_ext_only,Ar,{extfunc,erlang,error,Ar}}=I|Is], St, Acc) ->
- translate_1(Ar, I, Is, St, Acc);
-translate([{call_ext_last,Ar,{extfunc,erlang,error,Ar},_}=I|Is], St, Acc) ->
- translate_1(Ar, I, Is, St, Acc);
translate([I|Is], St, Acc) ->
translate(Is, St, [I|Acc]);
translate([], _, Acc) ->
diff --git a/lib/compiler/src/beam_flatten.erl b/lib/compiler/src/beam_flatten.erl
index 6c7cb849aa..04232d8fd2 100644
--- a/lib/compiler/src/beam_flatten.erl
+++ b/lib/compiler/src/beam_flatten.erl
@@ -79,49 +79,28 @@ norm_allocate({nozero,Ns,Nh,Inits}, Regs) ->
%% insert_alloc_in_bs_init(ReverseInstructionStream, AllocationInfo) ->
%% impossible | ReverseInstructionStream'
-%% A bs_init2/6 instruction should not be followed by a test heap instruction.
+%% A bs_init/6 instruction should not be followed by a test heap instruction.
%% Given the AllocationInfo from a test heap instruction, merge the
-%% allocation amounts into the previous bs_init2/6 instruction (if any).
+%% allocation amounts into the previous bs_init/6 instruction (if any).
%%
-insert_alloc_in_bs_init([I|_]=Is, Alloc) ->
- case is_bs_constructor(I) of
- false -> impossible;
- true -> insert_alloc_1(Is, Alloc, [])
- end.
-
-insert_alloc_1([{bs_init2=Op,Fail,Bs,Ws1,Regs,F,Dst}|Is], {_,nostack,Ws2,[]}, Acc) ->
- Al = beam_utils:combine_heap_needs(Ws1, Ws2),
- I = {Op,Fail,Bs,Al,Regs,F,Dst},
- reverse(Acc, [I|Is]);
-insert_alloc_1([{bs_init_bits=Op,Fail,Bs,Ws1,Regs,F,Dst}|Is], {_,nostack,Ws2,[]}, Acc) ->
- Al = beam_utils:combine_heap_needs(Ws1, Ws2),
- I = {Op,Fail,Bs,Al,Regs,F,Dst},
- reverse(Acc, [I|Is]);
-insert_alloc_1([{bs_append,Fail,Sz,Ws1,Regs,U,Bin,Fl,Dst}|Is],
- {_,nostack,Ws2,[]}, Acc) ->
+insert_alloc_in_bs_init([{bs_put,_,_,_}=I|Is], Alloc) ->
+ %% The instruction sequence ends with an bs_put/4 instruction.
+ %% We'll need to search backwards for the bs_init/6 instruction.
+ insert_alloc_1(Is, Alloc, [I]);
+insert_alloc_in_bs_init(_, _) -> impossible.
+
+insert_alloc_1([{bs_init=Op,Fail,Info0,Live,Ss,Dst}|Is],
+ {_,nostack,Ws2,[]}, Acc) when is_integer(Live) ->
+ %% The number of extra heap words is always in the second position
+ %% in the Info tuple.
+ Ws1 = element(2, Info0),
Al = beam_utils:combine_heap_needs(Ws1, Ws2),
- I = {bs_append,Fail,Sz,Al,Regs,U,Bin,Fl,Dst},
+ Info = setelement(2, Info0, Al),
+ I = {Op,Fail,Info,Live,Ss,Dst},
reverse(Acc, [I|Is]);
-insert_alloc_1([I|Is], Alloc, Acc) ->
+insert_alloc_1([{bs_put,_,_,_}=I|Is], Alloc, Acc) ->
insert_alloc_1(Is, Alloc, [I|Acc]).
-
-%% is_bs_constructor(Instruction) -> true|false.
-%% Test whether the instruction is a bit syntax construction
-%% instruction that can occur at the end of a bit syntax
-%% construction. (Since an empty binary would be expressed
-%% as a literal, the bs_init2/6 instruction will not occur
-%% at the end and therefore it is no need to test for it here.)
-%%
-is_bs_constructor({bs_put_integer,_,_,_,_,_}) -> true;
-is_bs_constructor({bs_put_utf8,_,_,_}) -> true;
-is_bs_constructor({bs_put_utf16,_,_,_}) -> true;
-is_bs_constructor({bs_put_utf32,_,_,_}) -> true;
-is_bs_constructor({bs_put_float,_,_,_,_,_}) -> true;
-is_bs_constructor({bs_put_binary,_,_,_,_,_}) -> true;
-is_bs_constructor({bs_put_string,_,_}) -> true;
-is_bs_constructor(_) -> false.
-
%% opt(Is0) -> Is
%% Simple peep-hole optimization to move a {move,Any,{x,0}} past
%% any kill up to the next call instruction. (To give the loader
diff --git a/lib/compiler/src/beam_jump.erl b/lib/compiler/src/beam_jump.erl
index db67d24514..636c299e47 100644
--- a/lib/compiler/src/beam_jump.erl
+++ b/lib/compiler/src/beam_jump.erl
@@ -20,7 +20,7 @@
-module(beam_jump).
--export([module/2,module_labels/1,
+-export([module/2,
is_unreachable_after/1,is_exit_instruction/1,
remove_unused_labels/1,is_label_used_in/2]).
@@ -46,10 +46,13 @@
%%% such as a jump that never transfers control to the instruction
%%% following it.
%%%
-%%% (2) case_end, if_end, and badmatch, and function calls that cause an
-%%% exit (such as calls to exit/1) are moved to the end of the function.
-%%% The purpose is to allow further optimizations at the place from
-%%% which the code was moved.
+%%% (2) Short sequences starting with a label and ending in case_end, if_end,
+%%% and badmatch, and function calls that cause an exit (such as calls
+%%% to exit/1) are moved to the end of the function, but only if the
+%%% the block is not entered via a fallthrough. The purpose of this move
+%%% is to allow further optimizations at the place from which the
+%%% code was moved (a jump around the block could be replaced with a
+%%% fallthrough).
%%%
%%% (3) Any unreachable code is removed. Unreachable code is code
%%% after jump, call_last and other instructions which never
@@ -130,13 +133,6 @@ module({Mod,Exp,Attr,Fs0,Lc}, _Opt) ->
Fs = [function(F) || F <- Fs0],
{ok,{Mod,Exp,Attr,Fs,Lc}}.
-module_labels({Mod,Exp,Attr,Fs,Lc}) ->
- {Mod,Exp,Attr,[function_labels(F) || F <- Fs],Lc}.
-
-function_labels({function,Name,Arity,CLabel,Asm0}) ->
- Asm = remove_unused_labels(Asm0),
- {function,Name,Arity,CLabel,Asm}.
-
%% function(Function) -> Function'
%% Optimize jumps and branches.
%%
@@ -224,6 +220,8 @@ extract_seq([{line,_}=Line|Is], Acc) ->
extract_seq(Is, [Line|Acc]);
extract_seq([{block,_}=Bl|Is], Acc) ->
extract_seq_1(Is, [Bl|Acc]);
+extract_seq([{bs_context_to_binary,_}=I|Is], Acc) ->
+ extract_seq_1(Is, [I|Acc]);
extract_seq([{label,_}|_]=Is, Acc) ->
extract_seq_1(Is, Acc);
extract_seq(_, _) -> no.
@@ -232,6 +230,9 @@ extract_seq_1([{line,_}=Line|Is], Acc) ->
extract_seq_1(Is, [Line|Acc]);
extract_seq_1([{label,_},{func_info,_,_,_}|_], _) ->
no;
+extract_seq_1([{label,Lbl},{jump,{f,Lbl}}|_], _) ->
+ %% Don't move a sequence which have a fallthrough entering it.
+ no;
extract_seq_1([{label,_}=Lbl|Is], Acc) ->
{yes,[Lbl|Acc],Is};
extract_seq_1(_, _) -> no.
@@ -260,43 +261,39 @@ find_fixpoint(OptFun, Is0) ->
Is -> find_fixpoint(OptFun, Is)
end.
-opt([{test,Test0,{f,Lnum}=Lbl,Ops}=I|Is0], Acc, St) ->
- case Is0 of
- [{jump,{f,Lnum}}|Is] ->
- %% We have
- %% Test Label Ops
- %% jump Label
- %% The test instruction is definitely not needed.
- %% The jump instruction is not needed if there is
- %% a definition of Label following the jump instruction.
- case is_label_defined(Is, Lnum) of
- false ->
- %% The jump instruction is still needed.
- opt(Is0, [I|Acc], label_used(Lbl, St));
- true ->
- %% Neither the test nor the jump are needed.
- opt(Is, Acc, St)
- end;
- [{jump,To}|Is] ->
- case is_label_defined(Is, Lnum) of
- false ->
+opt([{test,_,{f,L}=Lbl,_}=I|[{jump,{f,L}}|_]=Is], Acc, St) ->
+ %% We have
+ %% Test Label Ops
+ %% jump Label
+ %% The test instruction is not needed if the test is pure
+ %% (it modifies neither registers nor bit syntax state).
+ case beam_utils:is_pure_test(I) of
+ false ->
+ %% Test is not pure; we must keep it.
+ opt(Is, [I|Acc], label_used(Lbl, St));
+ true ->
+ %% The test is pure and its failure label is the same
+ %% as in the jump that follows -- thus it is not needed.
+ opt(Is, Acc, St)
+ end;
+opt([{test,Test0,{f,L}=Lbl,Ops}=I|[{jump,To}|Is]=Is0], Acc, St) ->
+ case is_label_defined(Is, L) of
+ false ->
+ opt(Is0, [I|Acc], label_used(Lbl, St));
+ true ->
+ case invert_test(Test0) of
+ not_possible ->
opt(Is0, [I|Acc], label_used(Lbl, St));
- true ->
- case invert_test(Test0) of
- not_possible ->
- opt(Is0, [I|Acc], label_used(Lbl, St));
- Test ->
- opt([{test,Test,To,Ops}|Is], Acc, St)
- end
- end;
- _Other ->
- opt(Is0, [I|Acc], label_used(Lbl, St))
+ Test ->
+ %% Invert the test and remove the jump.
+ opt([{test,Test,To,Ops}|Is], Acc, St)
+ end
end;
+opt([{test,_,{f,_}=Lbl,_}=I|Is], Acc, St) ->
+ opt(Is, [I|Acc], label_used(Lbl, St));
opt([{test,_,{f,_}=Lbl,_,_,_}=I|Is], Acc, St) ->
opt(Is, [I|Acc], label_used(Lbl, St));
-opt([{select_val,_R,Fail,{list,Vls}}=I|Is], Acc, St) ->
- skip_unreachable(Is, [I|Acc], label_used([Fail|Vls], St));
-opt([{select_tuple_arity,_R,Fail,{list,Vls}}=I|Is], Acc, St) ->
+opt([{select,_,_R,Fail,Vls}=I|Is], Acc, St) ->
skip_unreachable(Is, [I|Acc], label_used([Fail|Vls], St));
opt([{label,L}=I|Is], Acc, #st{entry=L}=St) ->
%% NEVER move the entry label.
@@ -412,14 +409,8 @@ is_label_used(L, St) ->
is_unreachable_after({func_info,_M,_F,_A}) -> true;
is_unreachable_after(return) -> true;
-is_unreachable_after({call_ext_last,_Ar,_ExtFunc,_D}) -> true;
-is_unreachable_after({call_ext_only,_Ar,_ExtFunc}) -> true;
-is_unreachable_after({call_last,_Ar,_Lbl,_D}) -> true;
-is_unreachable_after({call_only,_Ar,_Lbl}) -> true;
-is_unreachable_after({apply_last,_Ar,_N}) -> true;
is_unreachable_after({jump,_Lbl}) -> true;
-is_unreachable_after({select_val,_R,_Lbl,_Cases}) -> true;
-is_unreachable_after({select_tuple_arity,_R,_Lbl,_Cases}) -> true;
+is_unreachable_after({select,_What,_R,_Lbl,_Cases}) -> true;
is_unreachable_after({loop_rec_end,_}) -> true;
is_unreachable_after({wait,_}) -> true;
is_unreachable_after(I) -> is_exit_instruction(I).
@@ -430,10 +421,6 @@ is_unreachable_after(I) -> is_exit_instruction(I).
is_exit_instruction({call_ext,_,{extfunc,M,F,A}}) ->
erl_bifs:is_exit_bif(M, F, A);
-is_exit_instruction({call_ext_last,_,{extfunc,M,F,A},_}) ->
- erl_bifs:is_exit_bif(M, F, A);
-is_exit_instruction({call_ext_only,_,{extfunc,M,F,A}}) ->
- erl_bifs:is_exit_bif(M, F, A);
is_exit_instruction(if_end) -> true;
is_exit_instruction({case_end,_}) -> true;
is_exit_instruction({try_case_end,_}) -> true;
@@ -516,9 +503,7 @@ ulbl({test,_,Fail,_}, Used) ->
mark_used(Fail, Used);
ulbl({test,_,Fail,_,_,_}, Used) ->
mark_used(Fail, Used);
-ulbl({select_val,_,Fail,{list,Vls}}, Used) ->
- mark_used_list(Vls, mark_used(Fail, Used));
-ulbl({select_tuple_arity,_,Fail,{list,Vls}}, Used) ->
+ulbl({select,_,_,Fail,Vls}, Used) ->
mark_used_list(Vls, mark_used(Fail, Used));
ulbl({'try',_,Lbl}, Used) ->
mark_used(Lbl, Used);
@@ -538,29 +523,9 @@ ulbl({bif,_Name,Lbl,_As,_R}, Used) ->
mark_used(Lbl, Used);
ulbl({gc_bif,_Name,Lbl,_Live,_As,_R}, Used) ->
mark_used(Lbl, Used);
-ulbl({bs_init2,Lbl,_,_,_,_,_}, Used) ->
- mark_used(Lbl, Used);
-ulbl({bs_init_bits,Lbl,_,_,_,_,_}, Used) ->
- mark_used(Lbl, Used);
-ulbl({bs_put_integer,Lbl,_Bits,_Unit,_Fl,_Val}, Used) ->
- mark_used(Lbl, Used);
-ulbl({bs_put_float,Lbl,_Bits,_Unit,_Fl,_Val}, Used) ->
- mark_used(Lbl, Used);
-ulbl({bs_put_binary,Lbl,_Bits,_Unit,_Fl,_Val}, Used) ->
- mark_used(Lbl, Used);
-ulbl({bs_put_utf8,Lbl,_Fl,_Val}, Used) ->
- mark_used(Lbl, Used);
-ulbl({bs_put_utf16,Lbl,_Fl,_Val}, Used) ->
- mark_used(Lbl, Used);
-ulbl({bs_put_utf32,Lbl,_Fl,_Val}, Used) ->
- mark_used(Lbl, Used);
-ulbl({bs_add,Lbl,_,_}, Used) ->
- mark_used(Lbl, Used);
-ulbl({bs_append,Lbl,_,_,_,_,_,_,_}, Used) ->
- mark_used(Lbl, Used);
-ulbl({bs_utf8_size,Lbl,_,_}, Used) ->
+ulbl({bs_init,Lbl,_,_,_,_}, Used) ->
mark_used(Lbl, Used);
-ulbl({bs_utf16_size,Lbl,_,_}, Used) ->
+ulbl({bs_put,Lbl,_,_}, Used) ->
mark_used(Lbl, Used);
ulbl(_, Used) -> Used.
diff --git a/lib/compiler/src/beam_peep.erl b/lib/compiler/src/beam_peep.erl
index f39fc50b95..a199aa50ed 100644
--- a/lib/compiler/src/beam_peep.erl
+++ b/lib/compiler/src/beam_peep.erl
@@ -120,13 +120,13 @@ peep([{test,Op,_,Ops}=I|Is], SeenTests0, Acc) ->
peep(Is, SeenTests, [I|Acc])
end
end;
-peep([{select_val,Src,Fail,
- {list,[{atom,false},{f,L},{atom,true},{f,L}]}}|
+peep([{select,select_val,Src,Fail,
+ [{atom,false},{f,L},{atom,true},{f,L}]}|
[{label,L}|_]=Is], SeenTests, Acc) ->
I = {test,is_boolean,Fail,[Src]},
peep([I|Is], SeenTests, Acc);
-peep([{select_val,Src,Fail,
- {list,[{atom,true},{f,L},{atom,false},{f,L}]}}|
+peep([{select,select_val,Src,Fail,
+ [{atom,true},{f,L},{atom,false},{f,L}]}|
[{label,L}|_]=Is], SeenTests, Acc) ->
I = {test,is_boolean,Fail,[Src]},
peep([I|Is], SeenTests, Acc);
diff --git a/lib/compiler/src/beam_receive.erl b/lib/compiler/src/beam_receive.erl
index bd1f44f66b..fe95a7e35b 100644
--- a/lib/compiler/src/beam_receive.erl
+++ b/lib/compiler/src/beam_receive.erl
@@ -84,13 +84,29 @@ function({function,Name,Arity,Entry,Is}) ->
erlang:raise(Class, Error, Stack)
end.
+opt([{call_ext,A,{extfunc,erlang,spawn_monitor,A}}=I0|Is0], D, Acc)
+ when A =:= 1; A =:= 3 ->
+ case ref_in_tuple(Is0) of
+ no ->
+ opt(Is0, D, [I0|Acc]);
+ {yes,Regs,Is1,MatchReversed} ->
+ %% The call creates a brand new reference. Now
+ %% search for a receive statement in the same
+ %% function that will match against the reference.
+ case opt_recv(Is1, Regs, D) of
+ no ->
+ opt(Is0, D, [I0|Acc]);
+ {yes,Is,Lbl} ->
+ opt(Is, D, MatchReversed++[I0,{recv_mark,{f,Lbl}}|Acc])
+ end
+ end;
opt([{call_ext,Arity,{extfunc,erlang,Name,Arity}}=I|Is0], D, Acc) ->
case creates_new_ref(Name, Arity) of
true ->
%% The call creates a brand new reference. Now
%% search for a receive statement in the same
%% function that will match against the reference.
- case opt_recv(Is0, D) of
+ case opt_recv(Is0, regs_init_x0(), D) of
no ->
opt(Is0, D, [I|Acc]);
{yes,Is,Lbl} ->
@@ -104,19 +120,34 @@ opt([I|Is], D, Acc) ->
opt([], _, Acc) ->
reverse(Acc).
+ref_in_tuple([{test,is_tuple,_,[{x,0}]}=I1,
+ {test,test_arity,_,[{x,0},2]}=I2,
+ {block,[{set,[_],[{x,0}],{get_tuple_element,0}},
+ {set,[Dst],[{x,0}],{get_tuple_element,1}}|Bl]}=I3|Is]) ->
+ ref_in_tuple_1(Bl, Dst, Is, [I3,I2,I1]);
+ref_in_tuple([{test,is_tuple,_,[{x,0}]}=I1,
+ {test,test_arity,_,[{x,0},2]}=I2,
+ {block,[{set,[Dst],[{x,0}],{get_tuple_element,1}}|Bl]}=I3|Is]) ->
+ ref_in_tuple_1(Bl, Dst, Is, [I3,I2,I1]);
+ref_in_tuple(_) -> no.
+
+ref_in_tuple_1(Bl, Dst, Is, MatchReversed) ->
+ Regs0 = regs_init_singleton(Dst),
+ Regs = opt_update_regs_bl(Bl, Regs0),
+ {yes,Regs,Is,MatchReversed}.
+
%% creates_new_ref(Name, Arity) -> true|false.
%% Return 'true' if the BIF Name/Arity will create a new reference.
creates_new_ref(monitor, 2) -> true;
creates_new_ref(make_ref, 0) -> true;
creates_new_ref(_, _) -> false.
-%% opt_recv([Instruction], LabelIndex) -> no|{yes,[Instruction]}
+%% opt_recv([Instruction], Regs, LabelIndex) -> no|{yes,[Instruction]}
%% Search for a receive statement that will only retrieve messages
%% that contain the newly created reference (which is currently in {x,0}).
-opt_recv(Is, D) ->
- R = regs_init_x0(),
+opt_recv(Is, Regs, D) ->
L = gb_sets:empty(),
- opt_recv(Is, D, R, L, []).
+ opt_recv(Is, D, Regs, L, []).
opt_recv([{label,L}=Lbl,{loop_rec,{f,Fail},_}=Loop|Is], D, R0, _, Acc) ->
R = regs_kill_not_live(0, R0),
@@ -157,8 +188,6 @@ opt_update_regs({call_fun,_}, R, L) ->
{regs_kill_not_live(0, R),L};
opt_update_regs({kill,Y}, R, L) ->
{regs_kill([Y], R),L};
-opt_update_regs(send, R, L) ->
- {regs_kill_not_live(0, R),L};
opt_update_regs({'catch',_,{f,Lbl}}, R, L) ->
{R,gb_sets:add(Lbl, L)};
opt_update_regs({catch_end,_}, R, L) ->
@@ -253,10 +282,7 @@ opt_ref_used_1([{test,is_ne_exact,{f,Fail},Args}|Is], RefReg, D, Done0, Regs) ->
opt_ref_used_1([{test,_,{f,Fail},_}|Is], RefReg, D, Done0, Regs) ->
Done = opt_ref_used_at(Fail, RefReg, D, Done0, Regs),
opt_ref_used_1(Is, RefReg, D, Done, Regs);
-opt_ref_used_1([{select_tuple_arity,_,{f,Fail},{list,List}}|_], RefReg, D, Done, Regs) ->
- Lbls = [F || {f,F} <- List] ++ [Fail],
- opt_ref_used_in_all(Lbls, RefReg, D, Done, Regs);
-opt_ref_used_1([{select_val,_,{f,Fail},{list,List}}|_], RefReg, D, Done, Regs) ->
+opt_ref_used_1([{select,_,_,{f,Fail},List}|_], RefReg, D, Done, Regs) ->
Lbls = [F || {f,F} <- List] ++ [Fail],
opt_ref_used_in_all(Lbls, RefReg, D, Done, Regs);
opt_ref_used_1([{label,Lbl}|Is], RefReg, D, Done, Regs) ->
@@ -323,6 +349,12 @@ opt_ref_used_bl([], Regs) -> Regs.
regs_init() ->
{0,0}.
+%% regs_init_singleton(Register) -> RegisterSet
+%% Return a set that only contains one register.
+
+regs_init_singleton(Reg) ->
+ regs_add(Reg, regs_init()).
+
%% regs_init_x0() -> RegisterSet
%% Return a set that only contains the {x,0} register.
diff --git a/lib/compiler/src/beam_trim.erl b/lib/compiler/src/beam_trim.erl
index 5f4fa3b1f8..d95db1f681 100644
--- a/lib/compiler/src/beam_trim.erl
+++ b/lib/compiler/src/beam_trim.erl
@@ -172,38 +172,16 @@ remap([{bif,Name,Fail,Ss,D}|Is], Map, Acc) ->
remap([{gc_bif,Name,Fail,Live,Ss,D}|Is], Map, Acc) ->
I = {gc_bif,Name,Fail,Live,[Map(S) || S <- Ss],Map(D)},
remap(Is, Map, [I|Acc]);
-remap([{bs_add,Fail,[SrcA,SrcB,U],D}|Is], Map, Acc) ->
- I = {bs_add,Fail,[Map(SrcA),Map(SrcB),U],Map(D)},
+remap([{bs_init,Fail,Info,Live,Ss0,Dst0}|Is], Map, Acc) ->
+ Ss = [Map(Src) || Src <- Ss0],
+ Dst = Map(Dst0),
+ I = {bs_init,Fail,Info,Live,Ss,Dst},
remap(Is, Map, [I|Acc]);
-remap([{bs_append=Op,Fail,Bits,Heap,Live,Unit,Bin,Flags,D}|Is], Map, Acc) ->
- I = {Op,Fail,Map(Bits),Heap,Live,Unit,Map(Bin),Flags,Map(D)},
- remap(Is, Map, [I|Acc]);
-remap([{bs_private_append=Op,Fail,Bits,Unit,Bin,Flags,D}|Is], Map, Acc) ->
- I = {Op,Fail,Map(Bits),Unit,Map(Bin),Flags,Map(D)},
- remap(Is, Map, [I|Acc]);
-remap([bs_init_writable=I|Is], Map, Acc) ->
- remap(Is, Map, [I|Acc]);
-remap([{bs_init2,Fail,Src,Live,U,Flags,D}|Is], Map, Acc) ->
- I = {bs_init2,Fail,Map(Src),Live,U,Flags,Map(D)},
- remap(Is, Map, [I|Acc]);
-remap([{bs_init_bits,Fail,Src,Live,U,Flags,D}|Is], Map, Acc) ->
- I = {bs_init_bits,Fail,Map(Src),Live,U,Flags,Map(D)},
- remap(Is, Map, [I|Acc]);
-remap([{bs_put_binary=Op,Fail,Src,U,Flags,D}|Is], Map, Acc) ->
- I = {Op,Fail,Map(Src),U,Flags,Map(D)},
- remap(Is, Map, [I|Acc]);
-remap([{bs_put_integer=Op,Fail,Src,U,Flags,D}|Is], Map, Acc) ->
- I = {Op,Fail,Map(Src),U,Flags,Map(D)},
- remap(Is, Map, [I|Acc]);
-remap([{bs_put_float=Op,Fail,Src,U,Flags,D}|Is], Map, Acc) ->
- I = {Op,Fail,Map(Src),U,Flags,Map(D)},
- remap(Is, Map, [I|Acc]);
-remap([{bs_put_string,_,_}=I|Is], Map, Acc) ->
+remap([{bs_put=Op,Fail,Info,Ss}|Is], Map, Acc) ->
+ I = {Op,Fail,Info,[Map(S) || S <- Ss]},
remap(Is, Map, [I|Acc]);
remap([{kill,Y}|T], Map, Acc) ->
remap(T, Map, [{kill,Map(Y)}|Acc]);
-remap([send=I|T], Map, Acc) ->
- remap(T, Map, [I|Acc]);
remap([{make_fun2,_,_,_,_}=I|T], Map, Acc) ->
remap(T, Map, [I|Acc]);
remap([{deallocate,N}|Is], Map, Acc) ->
@@ -217,12 +195,6 @@ remap([{test,Name,Fail,Live,Ss,Dst}|Is], Map, Acc) ->
remap(Is, Map, [I|Acc]);
remap([return|_]=Is, _, Acc) ->
reverse(Acc, Is);
-remap([{call_last,Ar,Name,N}|Is], Map, Acc) ->
- I = {call_last,Ar,Name,Map({frame_size,N})},
- reverse(Acc, [I|Is]);
-remap([{call_ext_last,Ar,Name,N}|Is], Map, Acc) ->
- I = {call_ext_last,Ar,Name,Map({frame_size,N})},
- reverse(Acc, [I|Is]);
remap([{line,_}=I|Is], Map, Acc) ->
remap(Is, Map, [I|Acc]).
@@ -280,8 +252,8 @@ frame_size([{call_fun,_}|Is], Safe) ->
frame_size(Is, Safe);
frame_size([{call,_,_}|Is], Safe) ->
frame_size(Is, Safe);
-frame_size([{call_ext,A,{extfunc,M,F,A}}|Is], Safe) ->
- case erl_bifs:is_exit_bif(M, F, A) of
+frame_size([{call_ext,_,_}=I|Is], Safe) ->
+ case beam_jump:is_exit_instruction(I) of
true -> throw(not_possible);
false -> frame_size(Is, Safe)
end;
@@ -295,35 +267,15 @@ frame_size([{test,_,{f,L},_}|Is], Safe) ->
frame_size_branch(L, Is, Safe);
frame_size([{test,_,{f,L},_,_,_}|Is], Safe) ->
frame_size_branch(L, Is, Safe);
-frame_size([{bs_add,{f,L},_,_}|Is], Safe) ->
+frame_size([{bs_init,{f,L},_,_,_,_}|Is], Safe) ->
frame_size_branch(L, Is, Safe);
-frame_size([{bs_append,{f,L},_,_,_,_,_,_,_}|Is], Safe) ->
+frame_size([{bs_put,{f,L},_,_}|Is], Safe) ->
frame_size_branch(L, Is, Safe);
-frame_size([{bs_private_append,{f,L},_,_,_,_,_}|Is], Safe) ->
- frame_size_branch(L, Is, Safe);
-frame_size([bs_init_writable|Is], Safe) ->
- frame_size(Is, Safe);
-frame_size([{bs_init2,{f,L},_,_,_,_,_}|Is], Safe) ->
- frame_size_branch(L, Is, Safe);
-frame_size([{bs_init_bits,{f,L},_,_,_,_,_}|Is], Safe) ->
- frame_size_branch(L, Is, Safe);
-frame_size([{bs_put_binary,{f,L},_,_,_,_}|Is], Safe) ->
- frame_size_branch(L, Is, Safe);
-frame_size([{bs_put_integer,{f,L},_,_,_,_}|Is], Safe) ->
- frame_size_branch(L, Is, Safe);
-frame_size([{bs_put_float,{f,L},_,_,_,_}|Is], Safe) ->
- frame_size_branch(L, Is, Safe);
-frame_size([{bs_put_string,_,_}|Is], Safe) ->
- frame_size(Is, Safe);
frame_size([{kill,_}|Is], Safe) ->
frame_size(Is, Safe);
-frame_size([send|Is], Safe) ->
- frame_size(Is, Safe);
frame_size([{make_fun2,_,_,_,_}|Is], Safe) ->
frame_size(Is, Safe);
frame_size([{deallocate,N}|_], _) -> N;
-frame_size([{call_last,_,_,N}|_], _) -> N;
-frame_size([{call_ext_last,_,_,N}|_], _) -> N;
frame_size([{line,_}|Is], Safe) ->
frame_size(Is, Safe);
frame_size([_|_], _) -> throw(not_possible).
diff --git a/lib/compiler/src/beam_utils.erl b/lib/compiler/src/beam_utils.erl
index 194f089ba1..8af0447f63 100644
--- a/lib/compiler/src/beam_utils.erl
+++ b/lib/compiler/src/beam_utils.erl
@@ -87,7 +87,7 @@ is_killed_at(R, Lbl, D) when is_integer(Lbl) ->
%% across branches.
is_not_used(R, Is, D) ->
- St = #live{bl=fun check_used_block/2,lbl=D,res=gb_trees:empty()},
+ St = #live{bl=check_used_block_fun(D),lbl=D,res=gb_trees:empty()},
case check_liveness(R, Is, St) of
{killed,_} -> true;
{used,_} -> false;
@@ -102,7 +102,7 @@ is_not_used(R, Is, D) ->
%% across branches.
is_not_used_at(R, Lbl, D) ->
- St = #live{bl=fun check_used_block/2,lbl=D,res=gb_trees:empty()},
+ St = #live{bl=check_used_block_fun(D),lbl=D,res=gb_trees:empty()},
case check_liveness_at(R, Lbl, St) of
{killed,_} -> true;
{used,_} -> false;
@@ -263,26 +263,14 @@ check_liveness(R, [{test,_,{f,Fail},As}|Is], St0) ->
{_,_}=Other -> Other
end
end;
-check_liveness(R, [{test,_,{f,Fail},Live,Ss,_}|Is], St0) ->
- case R of
- {x,X} ->
- case X < Live orelse member(R, Ss) of
- true -> {used,St0};
- false -> check_liveness_at(R, Fail, St0)
- end;
- {y,_} ->
- case check_liveness_at(R, Fail, St0) of
- {killed,St} -> check_liveness(R, Is, St);
- {_,_}=Other -> Other
- end
- end;
-check_liveness(R, [{select_val,R,_,_}|_], St) ->
- {used,St};
-check_liveness(R, [{select_val,_,Fail,{list,Branches}}|_], St) ->
- check_liveness_everywhere(R, [Fail|Branches], St);
-check_liveness(R, [{select_tuple_arity,R,_,_}|_], St) ->
+check_liveness(R, [{test,Op,Fail,Live,Ss,Dst}|Is], St) ->
+ %% Check this instruction as a block to get a less conservative
+ %% result if the caller is is_not_used/3.
+ Block = [{set,[Dst],Ss,{alloc,Live,{bif,Op,Fail}}}],
+ check_liveness(R, [{block,Block}|Is], St);
+check_liveness(R, [{select,_,R,_,_}|_], St) ->
{used,St};
-check_liveness(R, [{select_tuple_arity,_,Fail,{list,Branches}}|_], St) ->
+check_liveness(R, [{select,_,_,Fail,Branches}|_], St) ->
check_liveness_everywhere(R, [Fail|Branches], St);
check_liveness(R, [{jump,{f,F}}|_], St) ->
check_liveness_at(R, F, St);
@@ -301,37 +289,33 @@ check_liveness(R, [{kill,R}|_], St) ->
{killed,St};
check_liveness(R, [{kill,_}|Is], St) ->
check_liveness(R, Is, St);
-check_liveness(R, [bs_init_writable|Is], St) ->
- if
- R =:= {x,0} -> {used,St};
- true -> check_liveness(R, Is, St)
- end;
-check_liveness(R, [{bs_private_append,_,Bits,_,Bin,_,Dst}|Is], St) ->
- case R of
- Bits -> {used,St};
- Bin -> {used,St};
- Dst -> {killed,St};
- _ -> check_liveness(R, Is, St)
+check_liveness(R, [{bs_init,_,_,none,Ss,Dst}|Is], St) ->
+ case member(R, Ss) of
+ true ->
+ {used,St};
+ false ->
+ if
+ R =:= Dst -> {killed,St};
+ true -> check_liveness(R, Is, St)
+ end
end;
-check_liveness(R, [{bs_append,_,Bits,_,_,_,Bin,_,Dst}|Is], St) ->
+check_liveness(R, [{bs_init,_,_,Live,Ss,Dst}|Is], St) ->
case R of
- Bits -> {used,St};
- Bin -> {used,St};
- Dst -> {killed,St};
- _ -> check_liveness(R, Is, St)
- end;
-check_liveness(R, [{bs_init2,_,_,_,_,_,Dst}|Is], St) ->
- if
- R =:= Dst -> {killed,St};
- true -> check_liveness(R, Is, St)
- end;
-check_liveness(R, [{bs_init_bits,_,_,_,_,_,Dst}|Is], St) ->
- if
- R =:= Dst -> {killed,St};
- true -> check_liveness(R, Is, St)
+ {x,X} ->
+ case X < Live orelse member(R, Ss) of
+ true -> {used,St};
+ false -> {killed,St}
+ end;
+ {y,_} ->
+ case member(R, Ss) of
+ true -> {used,St};
+ false ->
+ if
+ R =:= Dst -> {killed,St};
+ true -> check_liveness(R, Is, St)
+ end
+ end
end;
-check_liveness(R, [{bs_put_string,_,_}|Is], St) ->
- check_liveness(R, Is, St);
check_liveness(R, [{deallocate,_}|Is], St) ->
case R of
{y,_} -> {killed,St};
@@ -339,29 +323,20 @@ check_liveness(R, [{deallocate,_}|Is], St) ->
end;
check_liveness(R, [return|_], St) ->
check_liveness_live_ret(R, 1, St);
-check_liveness(R, [{call_last,Live,_,_}|_], St) ->
- check_liveness_live_ret(R, Live, St);
-check_liveness(R, [{call_only,Live,_}|_], St) ->
- check_liveness_live_ret(R, Live, St);
-check_liveness(R, [{call_ext_last,Live,_,_}|_], St) ->
- check_liveness_live_ret(R, Live, St);
-check_liveness(R, [{call_ext_only,Live,_}|_], St) ->
- check_liveness_live_ret(R, Live, St);
check_liveness(R, [{call,Live,_}|Is], St) ->
case R of
{x,X} when X < Live -> {used,St};
{x,_} -> {killed,St};
{y,_} -> check_liveness(R, Is, St)
end;
-check_liveness(R, [{call_ext,Live,Func}|Is], St) ->
+check_liveness(R, [{call_ext,Live,_}=I|Is], St) ->
case R of
{x,X} when X < Live ->
{used,St};
{x,_} ->
{killed,St};
{y,_} ->
- {extfunc,Mod,Name,Arity} = Func,
- case erl_bifs:is_exit_bif(Mod, Name, Arity) of
+ case beam_jump:is_exit_instruction(I) of
false ->
check_liveness(R, Is, St);
true ->
@@ -387,14 +362,6 @@ check_liveness(R, [{apply,Args}|Is], St) ->
{x,_} -> {killed,St};
{y,_} -> check_liveness(R, Is, St)
end;
-check_liveness(R, [{apply_last,Args,_}|_], St) ->
- check_liveness_live_ret(R, Args+2, St);
-check_liveness(R, [send|Is], St) ->
- case R of
- {x,X} when X < 2 -> {used,St};
- {x,_} -> {killed,St};
- {y,_} -> check_liveness(R, Is, St)
- end;
check_liveness({x,R}, [{'%live',Live}|Is], St) ->
if
R < Live -> check_liveness(R, Is, St);
@@ -429,25 +396,9 @@ check_liveness(R, [{gc_bif,Op,{f,Fail},Live,Ss,D}|Is], St0) ->
Other
end
end;
-check_liveness(R, [{bs_add,{f,0},Ss,D}|Is], St) ->
+check_liveness(R, [{bs_put,{f,0},_,Ss}|Is], St) ->
case member(R, Ss) of
true -> {used,St};
- false when R =:= D -> {killed,St};
- false -> check_liveness(R, Is, St)
- end;
-check_liveness(R, [{bs_put_binary,{f,0},Sz,_,_,Src}|Is], St) ->
- case member(R, [Sz,Src]) of
- true -> {used,St};
- false -> check_liveness(R, Is, St)
- end;
-check_liveness(R, [{bs_put_integer,{f,0},Sz,_,_,Src}|Is], St) ->
- case member(R, [Sz,Src]) of
- true -> {used,St};
- false -> check_liveness(R, Is, St)
- end;
-check_liveness(R, [{bs_put_float,{f,0},Sz,_,_,Src}|Is], St) ->
- case member(R, [Sz,Src]) of
- true -> {used,St};
false -> check_liveness(R, Is, St)
end;
check_liveness(R, [{bs_restore2,S,_}|Is], St) ->
@@ -472,6 +423,16 @@ check_liveness(R, [{make_fun2,_,_,_,NumFree}|Is], St) ->
{x,_} -> {killed,St};
_ -> check_liveness(R, Is, St)
end;
+check_liveness({x,_}=R, [{'catch',_,_}|Is], St) ->
+ %% All x registers will be killed if an exception occurs.
+ %% Therefore we only need to check the liveness for the
+ %% instructions following the catch instruction.
+ check_liveness(R, Is, St);
+check_liveness({x,_}=R, [{'try',_,_}|Is], St) ->
+ %% All x registers will be killed if an exception occurs.
+ %% Therefore we only need to check the liveness for the
+ %% instructions inside the 'try' block.
+ check_liveness(R, Is, St);
check_liveness(R, [{try_end,Y}|Is], St) ->
case R of
Y ->
@@ -602,26 +563,50 @@ check_killed_block(_, []) -> transparent.
%%
%% (Unknown instructions will cause an exception.)
-check_used_block({x,X}=R, [{set,_,_,{alloc,Live,_}}|Is]) ->
+check_used_block_fun(D) ->
+ fun(R, Is) -> check_used_block(R, Is, D) end.
+
+check_used_block({x,X}=R, [{set,Ds,Ss,{alloc,Live,Op}}|Is], D) ->
if
X >= Live -> killed;
- true -> check_used_block(R, Is)
+ true ->
+ case member(R, Ss) orelse
+ is_reg_used_at(R, Op, D) of
+ true -> used;
+ false ->
+ case member(R, Ds) of
+ true -> killed;
+ false -> check_used_block(R, Is, D)
+ end
+ end
end;
-check_used_block(R, [{set,Ds,Ss,_Op}|Is]) ->
- case member(R, Ss) of
+check_used_block(R, [{set,Ds,Ss,Op}|Is], D) ->
+ case member(R, Ss) orelse
+ is_reg_used_at(R, Op, D) of
true -> used;
false ->
case member(R, Ds) of
true -> killed;
- false -> check_used_block(R, Is)
+ false -> check_used_block(R, Is, D)
end
end;
-check_used_block(R, [{'%live',Live}|Is]) ->
+check_used_block(R, [{'%live',Live}|Is], D) ->
case R of
{x,X} when X >= Live -> killed;
- _ -> check_used_block(R, Is)
+ _ -> check_used_block(R, Is, D)
end;
-check_used_block(_, []) -> transparent.
+check_used_block(_, [], _) -> transparent.
+
+is_reg_used_at(R, {gc_bif,_,{f,Lbl}}, D) ->
+ is_reg_used_at_1(R, Lbl, D);
+is_reg_used_at(R, {bif,_,{f,Lbl}}, D) ->
+ is_reg_used_at_1(R, Lbl, D);
+is_reg_used_at(_, _, _) -> false.
+
+is_reg_used_at_1(_, 0, _) ->
+ false;
+is_reg_used_at_1(R, Lbl, D) ->
+ not is_not_used_at(R, Lbl, D).
index_labels_1([{label,Lbl}|Is0], Acc) ->
Is = lists:dropwhile(fun({label,_}) -> true;
@@ -654,49 +639,21 @@ combine_alloc_lists_1([]) -> [].
live_opt([{bs_context_to_binary,Src}=I|Is], Regs0, D, Acc) ->
Regs = x_live([Src], Regs0),
live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_add,Fail,[Src1,Src2,_],Dst}=I|Is], Regs0, D, Acc) ->
- Regs1 = x_live([Src1,Src2], x_dead([Dst], Regs0)),
- Regs = live_join_label(Fail, D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_init2,Fail,_,_,Live,_,_}=I|Is], _, D, Acc) ->
- Regs1 = live_call(Live),
- Regs = live_join_label(Fail, D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_init_bits,Fail,Src1,_,Live,_,Src2}=I|Is], _, D, Acc) ->
- Regs1 = live_call(Live),
- Regs2 = x_live([Src1,Src2], Regs1),
- Regs = live_join_label(Fail, D, Regs2),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_append,Fail,Src1,_,Live,_,Src2,_,Dst}=I|Is], _Regs0, D, Acc) ->
- Regs1 = x_dead([Dst], x_live([Src1,Src2], live_call(Live))),
- Regs = live_join_label(Fail, D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_private_append,Fail,Src1,_,Src2,_,Dst}=I|Is], Regs0, D, Acc) ->
- Regs1 = x_live([Src1,Src2], x_dead([Dst], Regs0)),
- Regs = live_join_label(Fail, D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_put_binary,Fail,Src1,_,_,Src2}=I|Is], Regs0, D, Acc) ->
- Regs1 = x_live([Src1,Src2], Regs0),
- Regs = live_join_label(Fail, D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_put_float,Fail,Src1,_,_,Src2}=I|Is], Regs0, D, Acc) ->
- Regs1 = x_live([Src1,Src2], Regs0),
+live_opt([{bs_init,Fail,_,none,Ss,Dst}=I|Is], Regs0, D, Acc) ->
+ Regs1 = x_live(Ss, x_dead([Dst], Regs0)),
Regs = live_join_label(Fail, D, Regs1),
live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_put_integer,Fail,Src1,_,_,Src2}=I|Is], Regs0, D, Acc) ->
- Regs1 = x_live([Src1,Src2], Regs0),
- Regs = live_join_label(Fail, D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_put_utf8,Fail,_,Src}=I|Is], Regs0, D, Acc) ->
- Regs1 = x_live([Src], Regs0),
- Regs = live_join_label(Fail, D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_put_utf16,Fail,_,Src}=I|Is], Regs0, D, Acc) ->
- Regs1 = x_live([Src], Regs0),
- Regs = live_join_label(Fail, D, Regs1),
+live_opt([{bs_init,Fail,Info,Live0,Ss,Dst}|Is], Regs0, D, Acc) ->
+ Regs1 = x_dead([Dst], Regs0),
+ Live = live_regs(Regs1),
+ true = Live =< Live0, %Assertion.
+ Regs2 = live_call(Live),
+ Regs3 = x_live(Ss, Regs2),
+ Regs = live_join_label(Fail, D, Regs3),
+ I = {bs_init,Fail,Info,Live,Ss,Dst},
live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_put_utf32,Fail,_,Src}=I|Is], Regs0, D, Acc) ->
- Regs1 = x_live([Src], Regs0),
+live_opt([{bs_put,Fail,_,Ss}=I|Is], Regs0, D, Acc) ->
+ Regs1 = x_live(Ss, Regs0),
Regs = live_join_label(Fail, D, Regs1),
live_opt(Is, Regs, D, [I|Acc]);
live_opt([{bs_restore2,Src,_}=I|Is], Regs0, D, Acc) ->
@@ -705,14 +662,6 @@ live_opt([{bs_restore2,Src,_}=I|Is], Regs0, D, Acc) ->
live_opt([{bs_save2,Src,_}=I|Is], Regs0, D, Acc) ->
Regs = x_live([Src], Regs0),
live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_utf8_size,Fail,Src,Dst}=I|Is], Regs0, D, Acc) ->
- Regs1 = x_live([Src], x_dead([Dst], Regs0)),
- Regs = live_join_label(Fail, D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_utf16_size,Fail,Src,Dst}=I|Is], Regs0, D, Acc) ->
- Regs1 = x_live([Src], x_dead([Dst], Regs0)),
- Regs = live_join_label(Fail, D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
live_opt([{test,bs_start_match2,Fail,Live,[Src,_],_}=I|Is], _, D, Acc) ->
Regs0 = live_call(Live),
Regs1 = x_live([Src], Regs0),
@@ -747,30 +696,16 @@ live_opt([{try_case_end,Src}=I|Is], _, D, Acc) ->
live_opt([if_end=I|Is], _, D, Acc) ->
Regs = 0,
live_opt(Is, Regs, D, [I|Acc]);
-live_opt([bs_init_writable=I|Is], _, D, Acc) ->
- live_opt(Is, live_call(1), D, [I|Acc]);
live_opt([{call,Arity,_}=I|Is], _, D, Acc) ->
live_opt(Is, live_call(Arity), D, [I|Acc]);
live_opt([{call_ext,Arity,_}=I|Is], _, D, Acc) ->
live_opt(Is, live_call(Arity), D, [I|Acc]);
live_opt([{call_fun,Arity}=I|Is], _, D, Acc) ->
live_opt(Is, live_call(Arity+1), D, [I|Acc]);
-live_opt([{call_last,Arity,_,_}=I|Is], _, D, Acc) ->
- live_opt(Is, live_call(Arity), D, [I|Acc]);
-live_opt([{call_ext_last,Arity,_,_}=I|Is], _, D, Acc) ->
- live_opt(Is, live_call(Arity), D, [I|Acc]);
live_opt([{apply,Arity}=I|Is], _, D, Acc) ->
live_opt(Is, live_call(Arity+2), D, [I|Acc]);
-live_opt([{apply_last,Arity,_}=I|Is], _, D, Acc) ->
- live_opt(Is, live_call(Arity+2), D, [I|Acc]);
-live_opt([{call_only,Arity,_}=I|Is], _, D, Acc) ->
- live_opt(Is, live_call(Arity), D, [I|Acc]);
-live_opt([{call_ext_only,Arity,_}=I|Is], _, D, Acc) ->
- live_opt(Is, live_call(Arity), D, [I|Acc]);
live_opt([{make_fun2,_,_,_,Arity}=I|Is], _, D, Acc) ->
live_opt(Is, live_call(Arity), D, [I|Acc]);
-live_opt([send=I|Is], _, D, Acc) ->
- live_opt(Is, live_call(2), D, [I|Acc]);
live_opt([{test,_,Fail,Ss}=I|Is], Regs0, D, Acc) ->
Regs1 = x_live(Ss, Regs0),
Regs = live_join_label(Fail, D, Regs1),
@@ -780,16 +715,14 @@ live_opt([{test,_,Fail,Live,Ss,_}=I|Is], _, D, Acc) ->
Regs1 = x_live(Ss, Regs0),
Regs = live_join_label(Fail, D, Regs1),
live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{select_val,Src,Fail,{list,List}}=I|Is], Regs0, D, Acc) ->
+live_opt([{select,_,Src,Fail,List}=I|Is], Regs0, D, Acc) ->
Regs1 = x_live([Src], Regs0),
Regs = live_join_labels([Fail|List], D, Regs1),
live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{select_tuple_arity,Src,Fail,{list,List}}=I|Is], Regs0, D, Acc) ->
- Regs1 = x_live([Src], Regs0),
- Regs = live_join_labels([Fail|List], D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{'try',_,Fail}=I|Is], Regs0, D, Acc) ->
- Regs = live_join_label(Fail, D, Regs0),
+live_opt([{'try',_,_}=I|Is], Regs, D, Acc) ->
+ %% If an exeption happens, all x registers will be killed.
+ %% Therefore, we should only base liveness of the code inside
+ %% the try.
live_opt(Is, Regs, D, [I|Acc]);
live_opt([{try_case,_}=I|Is], _, D, Acc) ->
live_opt(Is, live_call(1), D, [I|Acc]);
@@ -799,8 +732,6 @@ live_opt([timeout=I|Is], _, D, Acc) ->
live_opt(Is, 0, D, [I|Acc]);
%% Transparent instructions - they neither use nor modify x registers.
-live_opt([{bs_put_string,_,_}=I|Is], Regs, D, Acc) ->
- live_opt(Is, Regs, D, [I|Acc]);
live_opt([{deallocate,_}=I|Is], Regs, D, Acc) ->
live_opt(Is, Regs, D, [I|Acc]);
live_opt([{kill,_}=I|Is], Regs, D, Acc) ->
@@ -827,13 +758,24 @@ live_opt([{allocate_heap,_,_,Live}=I|Is], _, D, Acc) ->
live_opt([], _, _, Acc) -> Acc.
-live_opt_block([{set,[],[],{alloc,Live,_}}=I|Is], _, D, Acc) ->
- live_opt_block(Is, live_call(Live), D, [I|Acc]);
-live_opt_block([{set,Ds,Ss,Op}=I|Is], Regs0, D, Acc) ->
- Regs = case Op of
- {alloc,Live,_} -> live_call(Live);
- _ -> x_live(Ss, x_dead(Ds, Regs0))
- end,
+live_opt_block([{set,Ds,Ss,Op}=I0|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,
case Ds of
[{x,X}] ->
case (not is_live(X, Regs0)) andalso Op =:= move of
diff --git a/lib/compiler/src/beam_z.erl b/lib/compiler/src/beam_z.erl
new file mode 100644
index 0000000000..8c6b0c916d
--- /dev/null
+++ b/lib/compiler/src/beam_z.erl
@@ -0,0 +1,79 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% Purpose: Run right before beam_asm to do any final fix-ups or clean-ups.
+%% (Mandatory.)
+
+-module(beam_z).
+
+-export([module/2]).
+
+module({Mod,Exp,Attr,Fs0,Lc}, _Opt) ->
+ Fs = [function(F) || F <- Fs0],
+ {ok,{Mod,Exp,Attr,Fs,Lc}}.
+
+function({function,Name,Arity,CLabel,Is0}) ->
+ try
+ Is = undo_renames(Is0),
+ {function,Name,Arity,CLabel,Is}
+ catch
+ Class:Error ->
+ Stack = erlang:get_stacktrace(),
+ io:fwrite("Function: ~w/~w\n", [Name,Arity]),
+ erlang:raise(Class, Error, Stack)
+ end.
+
+undo_renames([{call_ext,2,send}|Is]) ->
+ [send|undo_renames(Is)];
+undo_renames([{apply,A},{deallocate,N},return|Is]) ->
+ [{apply_last,A,N}|undo_renames(Is)];
+undo_renames([{call,A,F},{deallocate,N},return|Is]) ->
+ [{call_last,A,F,N}|undo_renames(Is)];
+undo_renames([{call_ext,A,F},{deallocate,N},return|Is]) ->
+ [{call_ext_last,A,F,N}|undo_renames(Is)];
+undo_renames([{call,A,F},return|Is]) ->
+ [{call_only,A,F}|undo_renames(Is)];
+undo_renames([{call_ext,A,F},return|Is]) ->
+ [{call_ext_only,A,F}|undo_renames(Is)];
+undo_renames([I|Is]) ->
+ [undo_rename(I)|undo_renames(Is)];
+undo_renames([]) -> [].
+
+undo_rename({bs_put,F,{I,U,Fl},[Sz,Src]}) ->
+ {I,F,Sz,U,Fl,Src};
+undo_rename({bs_put,F,{I,Fl},[Src]}) ->
+ {I,F,Fl,Src};
+undo_rename({bs_put,{f,0},{bs_put_string,_,_}=I,[]}) ->
+ I;
+undo_rename({bif,bs_add=I,F,[Src1,Src2,{integer,U}],Dst}) ->
+ {I,F,[Src1,Src2,U],Dst};
+undo_rename({bif,bs_utf8_size=I,F,[Src],Dst}) ->
+ {I,F,Src,Dst};
+undo_rename({bif,bs_utf16_size=I,F,[Src],Dst}) ->
+ {I,F,Src,Dst};
+undo_rename({bs_init,F,{I,U,Flags},none,[Sz,Src],Dst}) ->
+ {I,F,Sz,U,Src,Flags,Dst};
+undo_rename({bs_init,F,{I,Extra,Flags},Live,[Sz],Dst}) ->
+ {I,F,Sz,Extra,Live,Flags,Dst};
+undo_rename({bs_init,F,{I,Extra,U,Flags},Live,[Sz,Src],Dst}) ->
+ {I,F,Sz,Extra,Live,U,Src,Flags,Dst};
+undo_rename({bs_init,_,bs_init_writable=I,_,_,_}) ->
+ I;
+undo_rename({select,I,Reg,Fail,List}) ->
+ {I,Reg,Fail,{list,List}};
+undo_rename(I) -> I.
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index 0a368df5d6..5f394f0b65 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -224,6 +224,8 @@ format_error({delete_temp,File,Error}) ->
[File,file:format_error(Error)]);
format_error({parse_transform,M,R}) ->
io_lib:format("error in parse transform '~s': ~p", [M, R]);
+format_error({undef_parse_transform,M}) ->
+ io_lib:format("undefined parse transform '~s'", [M]);
format_error({core_transform,M,R}) ->
io_lib:format("error in core transform '~s': ~p", [M, R]);
format_error({crash,Pass,Reason}) ->
@@ -246,6 +248,7 @@ format_error({module_name,Mod,Filename}) ->
abstract_code=[], %Abstract code for debugger.
options=[] :: [option()], %Options for compilation
mod_options=[] :: [option()], %Options for module_info
+ encoding=none :: none | epp:source_coding(),
errors=[],
warnings=[]}).
@@ -551,12 +554,12 @@ select_list_passes_1([{iff,Flag,{done,Ext}}|Ps], Opts, Acc) ->
end;
select_list_passes_1([{iff=Op,Flag,List0}|Ps], Opts, Acc) when is_list(List0) ->
case select_list_passes(List0, Opts) of
- {done,_}=Done -> Done;
+ {done,List} -> {done,reverse(Acc) ++ List};
{not_done,List} -> select_list_passes_1(Ps, Opts, [{Op,Flag,List}|Acc])
end;
select_list_passes_1([{unless=Op,Flag,List0}|Ps], Opts, Acc) when is_list(List0) ->
case select_list_passes(List0, Opts) of
- {done,_}=Done -> Done;
+ {done,List} -> {done,reverse(Acc) ++ List};
{not_done,List} -> select_list_passes_1(Ps, Opts, [{Op,Flag,List}|Acc])
end;
select_list_passes_1([P|Ps], Opts, Acc) ->
@@ -630,7 +633,8 @@ kernel_passes() ->
asm_passes() ->
%% Assembly level optimisations.
[{delay,
- [{unless,no_postopt,
+ [{pass,beam_a},
+ {unless,no_postopt,
[{pass,beam_block},
{iff,dblk,{listing,"block"}},
{unless,no_except,{pass,beam_except}},
@@ -657,13 +661,11 @@ asm_passes() ->
{iff,dtrim,{listing,"trim"}},
{pass,beam_flatten}]},
- %% If post optimizations are turned off, we still coalesce
- %% adjacent labels and remove unused labels to keep the
- %% HiPE compiler happy.
- {iff,no_postopt,
- [?pass(beam_unused_labels),
- {pass,beam_clean}]},
+ %% If post optimizations are turned off, we still
+ %% need to do a few clean-ups to code.
+ {iff,no_postopt,[{pass,beam_clean}]},
+ {pass,beam_z},
{iff,dopt,{listing,"optimize"}},
{iff,'S',{listing,"S"}},
{iff,'to_asm',{done,"S"}}]},
@@ -733,8 +735,9 @@ collect_asm([X | Rest], R) ->
beam_consult_asm(St) ->
case file:consult(St#compile.ifile) of
{ok, Forms0} ->
+ Encoding = epp:read_encoding(St#compile.ifile),
{Module, Forms} = preprocess_asm_forms(Forms0),
- {ok,St#compile{module=Module, code=Forms}};
+ {ok,St#compile{module=Module, code=Forms, encoding=Encoding}};
{error,E} ->
Es = [{St#compile.ifile,[{none,?MODULE,{open,E}}]}],
{error,St#compile{errors=St#compile.errors ++ Es}}
@@ -776,7 +779,8 @@ parse_module(St) ->
R = epp:parse_file(St#compile.ifile, IncludePath, pre_defs(Opts)),
case R of
{ok,Forms} ->
- {ok,St#compile{code=Forms}};
+ Encoding = epp:read_encoding(St#compile.ifile),
+ {ok,St#compile{code=Forms,encoding=Encoding}};
{error,E} ->
Es = [{St#compile.ifile,[{none,?MODULE,{epp,E}}]}],
{error,St#compile{errors=St#compile.errors ++ Es}}
@@ -850,6 +854,10 @@ foldl_transform(St, [T|Ts]) ->
{error,Es,Ws} ->
{error,St#compile{warnings=St#compile.warnings ++ Ws,
errors=St#compile.errors ++ Es}};
+ {'EXIT',{undef,_}} ->
+ Es = [{St#compile.ifile,[{none,compile,
+ {undef_parse_transform,T}}]}],
+ {error,St#compile{errors=St#compile.errors ++ Es}};
{'EXIT',R} ->
Es = [{St#compile.ifile,[{none,compile,{parse_transform,T,R}}]}],
{error,St#compile{errors=St#compile.errors ++ Es}};
@@ -887,7 +895,6 @@ foldl_core_transforms(St, []) -> {ok,St}.
%%% Fetches the module name from a list of forms. The module attribute must
%%% be present.
-get_module([{attribute,_,module,{M,_As}} | _]) -> M;
get_module([{attribute,_,module,M} | _]) -> M;
get_module([_ | Rest]) ->
get_module(Rest).
@@ -899,11 +906,8 @@ add_default_base(St, Forms) ->
F = St#compile.filename,
case F of
"" ->
- M = case get_module(Forms) of
- PackageModule when is_list(PackageModule) -> last(PackageModule);
- M0 -> M0
- end,
- St#compile{base = atom_to_list(M)};
+ M = get_module(Forms),
+ St#compile{base=atom_to_list(M)};
_ ->
St
end.
@@ -1236,10 +1240,6 @@ random_bytes_1(N, Acc) -> random_bytes_1(N-1, [random:uniform(255)|Acc]).
save_core_code(St) ->
{ok,St#compile{core_code=cerl:from_records(St#compile.code)}}.
-beam_unused_labels(#compile{code=Code0}=St) ->
- Code = beam_jump:module_labels(Code0),
- {ok,St#compile{code=Code}}.
-
beam_asm(#compile{ifile=File,code=Code0,
abstract_code=Abst,mod_options=Opts0}=St) ->
Source = filename:absname(File),
@@ -1338,16 +1338,12 @@ save_binary(#compile{code=none}=St) -> {ok,St};
save_binary(#compile{module=Mod,ofile=Outfile,
options=Opts}=St) ->
%% Test that the module name and output file name match.
- %% We must take care to not completely break a packaged module
- %% (even though packages still is as an experimental, unsupported
- %% feature) - so we will extract the last part of a packaged
- %% module name and compare only that.
case member(no_error_module_mismatch, Opts) of
true ->
save_binary_1(St);
false ->
Base = filename:rootname(filename:basename(Outfile)),
- case lists:last(packages:split(Mod)) of
+ case atom_to_list(Mod) of
Base ->
save_binary_1(St);
_ ->
@@ -1423,28 +1419,28 @@ report_warnings(#compile{options=Opts,warnings=Ws0}) ->
end.
format_message(F, P, [{{Line,Column}=Loc,Mod,E}|Es]) ->
- M = {{F,Loc},io_lib:format("~s:~w:~w ~s~s\n",
+ M = {{F,Loc},io_lib:format("~s:~w:~w ~s~ts\n",
[F,Line,Column,P,Mod:format_error(E)])},
[M|format_message(F, P, Es)];
format_message(F, P, [{Line,Mod,E}|Es]) ->
- M = {{F,{Line,0}},io_lib:format("~s:~w: ~s~s\n",
+ M = {{F,{Line,0}},io_lib:format("~s:~w: ~s~ts\n",
[F,Line,P,Mod:format_error(E)])},
[M|format_message(F, P, Es)];
format_message(F, P, [{Mod,E}|Es]) ->
- M = {none,io_lib:format("~s: ~s~s\n", [F,P,Mod:format_error(E)])},
+ M = {none,io_lib:format("~s: ~s~ts\n", [F,P,Mod:format_error(E)])},
[M|format_message(F, P, Es)];
format_message(_, _, []) -> [].
%% list_errors(File, ErrorDescriptors) -> ok
list_errors(F, [{{Line,Column},Mod,E}|Es]) ->
- io:fwrite("~s:~w:~w: ~s\n", [F,Line,Column,Mod:format_error(E)]),
+ io:fwrite("~s:~w:~w: ~ts\n", [F,Line,Column,Mod:format_error(E)]),
list_errors(F, Es);
list_errors(F, [{Line,Mod,E}|Es]) ->
- io:fwrite("~s:~w: ~s\n", [F,Line,Mod:format_error(E)]),
+ io:fwrite("~s:~w: ~ts\n", [F,Line,Mod:format_error(E)]),
list_errors(F, Es);
list_errors(F, [{Mod,E}|Es]) ->
- io:fwrite("~s: ~s\n", [F,Mod:format_error(E)]),
+ io:fwrite("~s: ~ts\n", [F,Mod:format_error(E)]),
list_errors(F, Es);
list_errors(_F, []) -> ok.
@@ -1500,10 +1496,12 @@ src_listing(Ext, St) ->
Ext, St).
do_src_listing(Lf, Fs) ->
- foreach(fun (F) -> io:put_chars(Lf, [erl_pp:form(F),"\n"]) end,
+ Opts = [lists:keyfind(encoding, 1, io:getopts(Lf))],
+ foreach(fun (F) -> io:put_chars(Lf, [erl_pp:form(F, Opts),"\n"]) end,
Fs).
-listing(Ext, St) ->
+listing(Ext, St0) ->
+ St = St0#compile{encoding = none},
listing(fun(Lf, Fs) -> beam_listing:module(Lf, Fs) end, Ext, St).
listing(LFun, Ext, St) ->
@@ -1511,6 +1509,7 @@ listing(LFun, Ext, St) ->
case file:open(Lfile, [write,delayed_write]) of
{ok,Lf} ->
Code = restore_expanded_types(Ext, St#compile.code),
+ output_encoding(Lf, St),
LFun(Lf, Code),
ok = file:close(Lf),
{ok,St};
@@ -1519,6 +1518,12 @@ listing(LFun, Ext, St) ->
{error,St#compile{errors=St#compile.errors ++ Es}}
end.
+output_encoding(F, #compile{encoding = none}) ->
+ ok = io:setopts(F, [{encoding, epp:default_encoding()}]);
+output_encoding(F, #compile{encoding = Encoding}) ->
+ ok = io:setopts(F, [{encoding, Encoding}]),
+ ok = io:fwrite(F, <<"%% ~s\n">>, [epp:encoding_to_string(Encoding)]).
+
restore_expanded_types("P", Fs) ->
epp:restore_typed_record_fields(Fs);
restore_expanded_types("E", {M,I,Fs0}) ->
diff --git a/lib/compiler/src/compiler.app.src b/lib/compiler/src/compiler.app.src
index 1133882728..9a02121d8b 100644
--- a/lib/compiler/src/compiler.app.src
+++ b/lib/compiler/src/compiler.app.src
@@ -20,6 +20,7 @@
[{description, "ERTS CXC 138 10"},
{vsn, "%VSN%"},
{modules, [
+ beam_a,
beam_asm,
beam_block,
beam_bool,
@@ -40,6 +41,7 @@
beam_type,
beam_utils,
beam_validator,
+ beam_z,
cerl,
cerl_clauses,
cerl_inline,
@@ -55,7 +57,6 @@
sys_core_dsetel,
sys_core_fold,
sys_core_inline,
- sys_expand_pmod,
sys_pre_attributes,
sys_pre_expand,
v3_codegen,
diff --git a/lib/compiler/src/core_lint.erl b/lib/compiler/src/core_lint.erl
index b513a8965c..21296a8b66 100644
--- a/lib/compiler/src/core_lint.erl
+++ b/lib/compiler/src/core_lint.erl
@@ -247,7 +247,8 @@ gbody(E, Def, Rt, St0) ->
false -> St1
end.
-gexpr(#c_var{name=N}, Def, _Rt, St) -> expr_var(N, Def, St);
+gexpr(#c_var{name=N}, Def, _Rt, St) when is_atom(N); is_integer(N) ->
+ expr_var(N, Def, St);
gexpr(#c_literal{}, _Def, _Rt, St) -> St;
gexpr(#c_cons{hd=H,tl=T}, Def, _Rt, St) ->
gexpr_list([H,T], Def, St);
diff --git a/lib/compiler/src/core_scan.erl b/lib/compiler/src/core_scan.erl
index 5aab8ae855..0ca2f57dde 100644
--- a/lib/compiler/src/core_scan.erl
+++ b/lib/compiler/src/core_scan.erl
@@ -1,7 +1,8 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -31,16 +32,16 @@
%% 173 - 176 { - ~ punctuation
%% 177 DEL control
%% 200 - 237 control
-%% 240 - 277 NBSP - � punctuation
-%% 300 - 326 � - � uppercase
-%% 327 � punctuation
-%% 330 - 336 � - � uppercase
-%% 337 - 366 � - � lowercase
-%% 367 � punctuation
-%% 370 - 377 � - � lowercase
+%% 240 - 277 NBSP - ¿ punctuation
+%% 300 - 326 À - Ö uppercase
+%% 327 × punctuation
+%% 330 - 336 Ø - Þ uppercase
+%% 337 - 366 ß - ö lowercase
+%% 367 ÷ punctuation
+%% 370 - 377 ø - ÿ lowercase
%%
%% Many punctuation characters region have special meaning. Must
-%% watch using � \327, bvery close to x \170
+%% watch using × \327, bvery close to x \170
-module(core_scan).
@@ -239,11 +240,11 @@ scan1([C|Cs], Toks, Pos) when C >= $\200, C =< $\240 ->
scan1(Cs, Toks, Pos);
scan1([C|Cs], Toks, Pos) when C >= $a, C =< $z -> %Keywords
scan_key_word(C, Cs, Toks, Pos);
-scan1([C|Cs], Toks, Pos) when C >= $�, C =< $�, C /= $� ->
+scan1([C|Cs], Toks, Pos) when C >= $ß, C =< $ÿ, C /= $÷ ->
scan_key_word(C, Cs, Toks, Pos);
scan1([C|Cs], Toks, Pos) when C >= $A, C =< $Z -> %Variables
scan_variable(C, Cs, Toks, Pos);
-scan1([C|Cs], Toks, Pos) when C >= $�, C =< $�, C /= $� ->
+scan1([C|Cs], Toks, Pos) when C >= $À, C =< $Þ, C /= $× ->
scan_variable(C, Cs, Toks, Pos);
scan1([C|Cs], Toks, Pos) when C >= $0, C =< $9 -> %Numbers
scan_number(C, Cs, Toks, Pos);
@@ -308,9 +309,9 @@ scan_name([], Ncs) ->
{Ncs,[]}.
name_char(C) when C >= $a, C =< $z -> true;
-name_char(C) when C >= $�, C =< $�, C /= $� -> true;
+name_char(C) when C >= $ß, C =< $ÿ, C /= $÷ -> true;
name_char(C) when C >= $A, C =< $Z -> true;
-name_char(C) when C >= $�, C =< $�, C /= $� -> true;
+name_char(C) when C >= $À, C =< $Þ, C /= $× -> true;
name_char(C) when C >= $0, C =< $9 -> true;
name_char($_) -> true;
name_char($@) -> true;
diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index 18fba7962b..f17b0bd130 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -686,11 +686,14 @@ call_1(#c_call{anno=Anno}, lists, all, [Arg1,Arg2], Sub) ->
C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
body=#c_case{arg=#c_apply{anno=Anno, op=F, args=[X]},
clauses = [CC1, CC2, CC3]}},
- C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true},
+ C2 = #c_clause{pats=[#c_literal{val=[]}],
+ guard=#c_call{module=#c_literal{val=erlang},
+ name=#c_literal{val=is_function},
+ args=[F, #c_literal{val=1}]},
body=#c_literal{val=true}},
- Err2 = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
+ Err2 = #c_tuple{es=[#c_literal{val='function_clause'}, F, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=match_fail(Anno, Err2)},
+ body=match_fail([{function_name,{'lists^all',1}}|Anno], Err2)},
Fun = #c_fun{vars=[Xs],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
@@ -713,11 +716,14 @@ call_1(#c_call{anno=Anno}, lists, any, [Arg1,Arg2], Sub) ->
C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
body=#c_case{arg=#c_apply{anno=Anno, op=F, args=[X]},
clauses = [CC1, CC2, CC3]}},
- C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true},
+ C2 = #c_clause{pats=[#c_literal{val=[]}],
+ guard=#c_call{module=#c_literal{val=erlang},
+ name=#c_literal{val=is_function},
+ args=[F, #c_literal{val=1}]},
body=#c_literal{val=false}},
- Err2 = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
+ Err2 = #c_tuple{es=[#c_literal{val='function_clause'}, F, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=match_fail(Anno, Err2)},
+ body=match_fail([{function_name,{'lists^any',1}}|Anno], Err2)},
Fun = #c_fun{vars=[Xs],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
@@ -733,11 +739,14 @@ call_1(#c_call{anno=Anno}, lists, foreach, [Arg1,Arg2], Sub) ->
C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
body=#c_seq{arg=#c_apply{anno=Anno, op=F, args=[X]},
body=#c_apply{anno=Anno, op=Loop, args=[Xs]}}},
- C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true},
+ C2 = #c_clause{pats=[#c_literal{val=[]}],
+ guard=#c_call{module=#c_literal{val=erlang},
+ name=#c_literal{val=is_function},
+ args=[F, #c_literal{val=1}]},
body=#c_literal{val=ok}},
- Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
+ Err = #c_tuple{es=[#c_literal{val='function_clause'}, F, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=match_fail(Anno, Err)},
+ body=match_fail([{function_name,{'lists^foreach',1}}|Anno], Err)},
Fun = #c_fun{vars=[Xs],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
@@ -756,14 +765,18 @@ call_1(#c_call{anno=Anno}, lists, map, [Arg1,Arg2], Sub) ->
op=F,
args=[X]},
body=#c_cons{hd=H,
+ anno=[compiler_generated],
tl=#c_apply{anno=Anno,
op=Loop,
args=[Xs]}}}},
- C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true},
+ C2 = #c_clause{pats=[#c_literal{val=[]}],
+ guard=#c_call{module=#c_literal{val=erlang},
+ name=#c_literal{val=is_function},
+ args=[F, #c_literal{val=1}]},
body=#c_literal{val=[]}},
- Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
+ Err = #c_tuple{es=[#c_literal{val='function_clause'}, F, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=match_fail(Anno, Err)},
+ body=match_fail([{function_name,{'lists^map',1}}|Anno], Err)},
Fun = #c_fun{vars=[Xs],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
@@ -780,18 +793,21 @@ call_1(#c_call{anno=Anno}, lists, flatmap, [Arg1,Arg2], Sub) ->
C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
body=#c_let{vars=[H],
arg=#c_apply{anno=Anno, op=F, args=[X]},
- body=#c_call{anno=Anno,
+ body=#c_call{anno=[compiler_generated|Anno],
module=#c_literal{val=erlang},
name=#c_literal{val='++'},
args=[H,
#c_apply{anno=Anno,
op=Loop,
args=[Xs]}]}}},
- C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true},
+ C2 = #c_clause{pats=[#c_literal{val=[]}],
+ guard=#c_call{module=#c_literal{val=erlang},
+ name=#c_literal{val=is_function},
+ args=[F, #c_literal{val=1}]},
body=#c_literal{val=[]}},
- Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
+ Err = #c_tuple{es=[#c_literal{val='function_clause'}, F, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=match_fail(Anno, Err)},
+ body=match_fail([{function_name,{'lists^flatmap',1}}|Anno], Err)},
Fun = #c_fun{vars=[Xs],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
@@ -807,7 +823,7 @@ call_1(#c_call{anno=Anno}, lists, filter, [Arg1,Arg2], Sub) ->
B = #c_var{name='B'},
Err1 = #c_tuple{es=[#c_literal{val='case_clause'}, X]},
CC1 = #c_clause{pats=[#c_literal{val=true}], guard=#c_literal{val=true},
- body=#c_cons{hd=X, tl=Xs}},
+ body=#c_cons{anno=[compiler_generated], hd=X, tl=Xs}},
CC2 = #c_clause{pats=[#c_literal{val=false}], guard=#c_literal{val=true},
body=Xs},
CC3 = #c_clause{pats=[X], guard=#c_literal{val=true},
@@ -821,11 +837,14 @@ call_1(#c_call{anno=Anno}, lists, filter, [Arg1,Arg2], Sub) ->
op=Loop,
args=[Xs]},
body=Case}}},
- C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true},
+ C2 = #c_clause{pats=[#c_literal{val=[]}],
+ guard=#c_call{module=#c_literal{val=erlang},
+ name=#c_literal{val=is_function},
+ args=[F, #c_literal{val=1}]},
body=#c_literal{val=[]}},
- Err2 = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
+ Err2 = #c_tuple{es=[#c_literal{val='function_clause'}, F, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=match_fail(Anno, Err2)},
+ body=match_fail([{function_name,{'lists^filter',1}}|Anno], Err2)},
Fun = #c_fun{vars=[Xs],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
@@ -845,10 +864,14 @@ call_1(#c_call{anno=Anno}, lists, foldl, [Arg1,Arg2,Arg3], Sub) ->
args=[Xs, #c_apply{anno=Anno,
op=F,
args=[X, A]}]}},
- C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true}, body=A},
- Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
+ C2 = #c_clause{pats=[#c_literal{val=[]}],
+ guard=#c_call{module=#c_literal{val=erlang},
+ name=#c_literal{val=is_function},
+ args=[F, #c_literal{val=2}]},
+ body=A},
+ Err = #c_tuple{es=[#c_literal{val='function_clause'}, F, A, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=match_fail(Anno, Err)},
+ body=match_fail([{function_name,{'lists^foldl',2}}|Anno], Err)},
Fun = #c_fun{vars=[Xs, A],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
@@ -868,10 +891,14 @@ call_1(#c_call{anno=Anno}, lists, foldr, [Arg1,Arg2,Arg3], Sub) ->
args=[X, #c_apply{anno=Anno,
op=Loop,
args=[Xs, A]}]}},
- C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true}, body=A},
- Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
+ C2 = #c_clause{pats=[#c_literal{val=[]}],
+ guard=#c_call{module=#c_literal{val=erlang},
+ name=#c_literal{val=is_function},
+ args=[F, #c_literal{val=2}]},
+ body=A},
+ Err = #c_tuple{es=[#c_literal{val='function_clause'}, F, A, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=match_fail(Anno, Err)},
+ body=match_fail([{function_name,{'lists^foldr',2}}|Anno], Err)},
Fun = #c_fun{vars=[Xs, A],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
@@ -901,7 +928,10 @@ call_1(#c_call{anno=Anno}, lists, mapfoldl, [Arg1,Arg2,Arg3], Sub) ->
op=Loop,
args=[Xs, Avar]},
#c_tuple{es=[Xs, Avar]},
- #c_tuple{es=[#c_cons{hd=X, tl=Xs}, Avar]})
+ #c_tuple{anno=[compiler_generated],
+ es=[#c_cons{anno=[compiler_generated],
+ hd=X, tl=Xs},
+ Avar]})
%%% Multiple-value version
%%% #c_let{vars=[Xs,A],
%%% %% The tuple here will be optimised
@@ -910,14 +940,18 @@ call_1(#c_call{anno=Anno}, lists, mapfoldl, [Arg1,Arg2,Arg3], Sub) ->
%%% body=#c_values{es=[#c_cons{hd=X, tl=Xs},
%%% A]}}
)},
- C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true},
+ C2 = #c_clause{pats=[#c_literal{val=[]}],
+ guard=#c_call{module=#c_literal{val=erlang},
+ name=#c_literal{val=is_function},
+ args=[F, #c_literal{val=2}]},
%%% Tuple passing version
- body=#c_tuple{es=[#c_literal{val=[]}, Avar]}},
+ body=#c_tuple{anno=[compiler_generated],
+ es=[#c_literal{val=[]}, Avar]}},
%%% Multiple-value version
%%% body=#c_values{es=[#c_literal{val=[]}, A]}},
- Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
+ Err = #c_tuple{es=[#c_literal{val='function_clause'}, F, Avar, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=match_fail(Anno, Err)},
+ body=match_fail([{function_name,{'lists^mapfoldl',2}}|Anno], Err)},
Fun = #c_fun{vars=[Xs, Avar],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
@@ -955,7 +989,9 @@ call_1(#c_call{anno=Anno}, lists, mapfoldr, [Arg1,Arg2,Arg3], Sub) ->
#c_tuple{es=[Xs, Avar]},
Match(#c_apply{anno=Anno, op=F, args=[X, Avar]},
#c_tuple{es=[X, Avar]},
- #c_tuple{es=[#c_cons{hd=X, tl=Xs}, Avar]}))
+ #c_tuple{anno=[compiler_generated],
+ es=[#c_cons{anno=[compiler_generated],
+ hd=X, tl=Xs}, Avar]}))
%%% Multiple-value version
%%% body=#c_let{vars=[Xs,A],
%%% %% The tuple will be optimised away
@@ -965,14 +1001,18 @@ call_1(#c_call{anno=Anno}, lists, mapfoldr, [Arg1,Arg2,Arg3], Sub) ->
%%% #c_values{es=[#c_cons{hd=X, tl=Xs},
%%% A]})}
},
- C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true},
+ C2 = #c_clause{pats=[#c_literal{val=[]}],
+ guard=#c_call{module=#c_literal{val=erlang},
+ name=#c_literal{val=is_function},
+ args=[F, #c_literal{val=2}]},
%%% Tuple passing version
- body=#c_tuple{es=[#c_literal{val=[]}, Avar]}},
+ body=#c_tuple{anno=[compiler_generated],
+ es=[#c_literal{val=[]}, Avar]}},
%%% Multiple-value version
%%% body=#c_values{es=[#c_literal{val=[]}, A]}},
- Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
+ Err = #c_tuple{es=[#c_literal{val='function_clause'}, F, Avar, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=match_fail(Anno, Err)},
+ body=match_fail([{function_name,{'lists^mapfoldr',2}}|Anno], Err)},
Fun = #c_fun{vars=[Xs, Avar],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
diff --git a/lib/compiler/src/sys_expand_pmod.erl b/lib/compiler/src/sys_expand_pmod.erl
deleted file mode 100644
index da644b4f0b..0000000000
--- a/lib/compiler/src/sys_expand_pmod.erl
+++ /dev/null
@@ -1,433 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
--module(sys_expand_pmod).
-
-%% Expand function definition forms of parameterized module. We assume
-%% all record definitions, imports, queries, etc., have been expanded
-%% away. Any calls on the form 'foo(...)' must be calls to local
-%% functions. Auto-generated functions (module_info,...) have not yet
-%% been added to the function definitions, but are listed in 'defined'
-%% and 'exports'. The automatic 'new/N' function is neither added to the
-%% definitions nor to the 'exports'/'defines' lists yet.
-
--export([forms/4]).
-
--record(pmod, {parameters, exports, defined, predef}).
-
-%% TODO: more abstract handling of predefined/static functions.
-
-forms(Fs0, Ps, Es0, Ds0) ->
- PreDef = [{module_info,0},{module_info,1}],
- forms(Fs0, Ps, Es0, Ds0, PreDef).
-
-forms(Fs0, Ps, Es0, Ds0, PreDef) ->
- St0 = #pmod{parameters=Ps,exports=Es0,defined=Ds0, predef=PreDef},
- {Fs1, St1} = forms(Fs0, St0),
- Es1 = update_function_names(Es0, St1),
- Ds1 = update_function_names(Ds0, St1),
- Fs2 = update_forms(Fs1, St1),
- {Fs2,Es1,Ds1}.
-
-%% This is extremely simplistic for now; all functions get an extra
-%% parameter, whether they need it or not, except for static functions.
-
-update_function_names(Es, St) ->
- [update_function_name(E, St) || E <- Es].
-
-update_function_name(E={F,A}, St) when F =/= new ->
- case ordsets:is_element(E, St#pmod.predef) of
- true -> E;
- false -> {F, A + 1}
- end;
-update_function_name(E, _St) ->
- E.
-
-update_forms([{function,L,N,A,Cs}|Fs],St) when N =/= new ->
- [{function,L,N,A+1,Cs}|update_forms(Fs,St)];
-update_forms([F|Fs],St) ->
- [F|update_forms(Fs,St)];
-update_forms([],_St) ->
- [].
-
-%% Process the program forms.
-
-forms([F0|Fs0],St0) ->
- {F1,St1} = form(F0,St0),
- {Fs1,St2} = forms(Fs0,St1),
- {[F1|Fs1],St2};
-forms([], St0) ->
- {[], St0}.
-
-%% Only function definitions are of interest here. State is not updated.
-form({function,Line,Name0,Arity0,Clauses0},St) when Name0 =/= new ->
- {Name,Arity,Clauses} = function(Name0, Arity0, Clauses0, St),
- {{function,Line,Name,Arity,Clauses},St};
-%% Pass anything else through
-form(F,St) -> {F,St}.
-
-function(Name, Arity, Clauses0, St) ->
- Clauses1 = clauses(Clauses0,St),
- {Name,Arity,Clauses1}.
-
-clauses([C|Cs],St) ->
- {clause,L,H,G,B} = clause(C,St),
- T = {tuple,L,[{var,L,V} || V <- ['_'|St#pmod.parameters]]},
- [{clause,L,H++[{match,L,T,{var,L,'THIS'}}],G,B}|clauses(Cs,St)];
-clauses([],_St) -> [].
-
-clause({clause,Line,H0,G0,B0},St) ->
- H1 = head(H0,St),
- G1 = guard(G0,St),
- B1 = exprs(B0,St),
- {clause,Line,H1,G1,B1}.
-
-head(Ps,St) -> patterns(Ps,St).
-
-patterns([P0|Ps],St) ->
- P1 = pattern(P0,St),
- [P1|patterns(Ps,St)];
-patterns([],_St) -> [].
-
-string_to_conses([], _Line, Tail) ->
- Tail;
-string_to_conses([E|Rest], Line, Tail) ->
- {cons, Line, {integer, Line, E}, string_to_conses(Rest, Line, Tail)}.
-
-pattern({var,_Line,_V}=Var,_St) -> Var;
-pattern({match,Line,L0,R0},St) ->
- L1 = pattern(L0,St),
- R1 = pattern(R0,St),
- {match,Line,L1,R1};
-pattern({integer,_Line,_I}=Integer,_St) -> Integer;
-pattern({char,_Line,_C}=Char,_St) -> Char;
-pattern({float,_Line,_F}=Float,_St) -> Float;
-pattern({atom,_Line,_A}=Atom,_St) -> Atom;
-pattern({string,_Line,_S}=String,_St) -> String;
-pattern({nil,_Line}=Nil,_St) -> Nil;
-pattern({cons,Line,H0,T0},St) ->
- H1 = pattern(H0,St),
- T1 = pattern(T0,St),
- {cons,Line,H1,T1};
-pattern({tuple,Line,Ps0},St) ->
- Ps1 = pattern_list(Ps0,St),
- {tuple,Line,Ps1};
-pattern({bin,Line,Fs},St) ->
- Fs2 = pattern_grp(Fs,St),
- {bin,Line,Fs2};
-pattern({op,_Line,'++',{nil,_},R},St) ->
- pattern(R,St);
-pattern({op,_Line,'++',{cons,Li,{char,_C2,_I}=Char,T},R},St) ->
- pattern({cons,Li,Char,{op,Li,'++',T,R}},St);
-pattern({op,_Line,'++',{cons,Li,{integer,_L2,_I}=Integer,T},R},St) ->
- pattern({cons,Li,Integer,{op,Li,'++',T,R}},St);
-pattern({op,_Line,'++',{string,Li,L},R},St) ->
- pattern(string_to_conses(L, Li, R),St);
-pattern({op,_Line,_Op,_A}=Op4,_St) -> Op4;
-pattern({op,_Line,_Op,_L,_R}=Op5,_St) -> Op5.
-
-pattern_grp([{bin_element,L1,E1,S1,T1} | Fs],St) ->
- S2 = case S1 of
- default ->
- default;
- _ ->
- expr(S1,St)
- end,
- T2 = case T1 of
- default ->
- default;
- _ ->
- bit_types(T1)
- end,
- [{bin_element,L1,expr(E1,St),S2,T2} | pattern_grp(Fs,St)];
-pattern_grp([],_St) ->
- [].
-
-bit_types([]) ->
- [];
-bit_types([Atom | Rest]) when is_atom(Atom) ->
- [Atom | bit_types(Rest)];
-bit_types([{Atom, Integer} | Rest]) when is_atom(Atom), is_integer(Integer) ->
- [{Atom, Integer} | bit_types(Rest)].
-
-pattern_list([P0|Ps],St) ->
- P1 = pattern(P0,St),
- [P1|pattern_list(Ps,St)];
-pattern_list([],_St) -> [].
-
-guard([G0|Gs],St) when is_list(G0) ->
- [guard0(G0,St) | guard(Gs,St)];
-guard(L,St) ->
- guard0(L,St).
-
-guard0([G0|Gs],St) ->
- G1 = guard_test(G0,St),
- [G1|guard0(Gs,St)];
-guard0([],_St) -> [].
-
-guard_test(Expr={call,Line,{atom,La,F},As0},St) ->
- case erl_internal:type_test(F, length(As0)) of
- true ->
- As1 = gexpr_list(As0,St),
- {call,Line,{atom,La,F},As1};
- _ ->
- gexpr(Expr,St)
- end;
-guard_test(Any,St) ->
- gexpr(Any,St).
-
-gexpr({var,_L,_V}=Var,_St) -> Var;
-% %% alternative implementation of accessing module parameters
-% case index(V,St#pmod.parameters) of
-% N when N > 0 ->
-% {call,L,{remote,L,{atom,L,erlang},{atom,L,element}},
-% [{integer,L,N+1},{var,L,'THIS'}]};
-% _ ->
-% Var
-% end;
-gexpr({integer,_Line,_I}=Integer,_St) -> Integer;
-gexpr({char,_Line,_C}=Char,_St) -> Char;
-gexpr({float,_Line,_F}=Float,_St) -> Float;
-gexpr({atom,_Line,_A}=Atom,_St) -> Atom;
-gexpr({string,_Line,_S}=String,_St) -> String;
-gexpr({nil,_Line}=Nil,_St) -> Nil;
-gexpr({cons,Line,H0,T0},St) ->
- H1 = gexpr(H0,St),
- T1 = gexpr(T0,St),
- {cons,Line,H1,T1};
-gexpr({tuple,Line,Es0},St) ->
- Es1 = gexpr_list(Es0,St),
- {tuple,Line,Es1};
-gexpr({call,Line,{atom,_La,F}=Atom,As0},St) ->
- true = erl_internal:guard_bif(F, length(As0)),
- As1 = gexpr_list(As0,St),
- {call,Line,Atom,As1};
-%% Pre-expansion generated calls to erlang:is_record/3 must also be handled
-gexpr({call,Line,{remote,La,{atom,Lb,erlang},{atom,Lc,is_record}},[_,_,_]=As0},St) ->
- As1 = gexpr_list(As0,St),
- {call,Line,{remote,La,{atom,Lb,erlang},{atom,Lc,is_record}},As1};
-%% Guard BIFs can be remote, but only in the module erlang...
-gexpr({call,Line,{remote,La,{atom,Lb,erlang},{atom,Lc,F}},As0},St) ->
- A = length(As0),
- true =
- erl_internal:guard_bif(F, A) orelse erl_internal:arith_op(F, A) orelse
- erl_internal:comp_op(F, A) orelse erl_internal:bool_op(F, A),
- As1 = gexpr_list(As0,St),
- {call,Line,{remote,La,{atom,Lb,erlang},{atom,Lc,F}},As1};
-%% Unfortunately, writing calls as {M,F}(...) is also allowed.
-gexpr({call,Line,{tuple,La,[{atom,Lb,erlang},{atom,Lc,F}]},As0},St) ->
- A = length(As0),
- true =
- erl_internal:guard_bif(F, A) orelse erl_internal:arith_op(F, A) orelse
- erl_internal:comp_op(F, A) orelse erl_internal:bool_op(F, A),
- As1 = gexpr_list(As0,St),
- {call,Line,{tuple,La,[{atom,Lb,erlang},{atom,Lc,F}]},As1};
-gexpr({bin,Line,Fs},St) ->
- Fs2 = pattern_grp(Fs,St),
- {bin,Line,Fs2};
-gexpr({op,Line,Op,A0},St) ->
- true = erl_internal:arith_op(Op, 1) orelse erl_internal:bool_op(Op, 1),
- A1 = gexpr(A0,St),
- {op,Line,Op,A1};
-gexpr({op,Line,Op,L0,R0},St) ->
- true =
- Op =:= 'andalso' orelse Op =:= 'orelse' orelse
- erl_internal:arith_op(Op, 2) orelse
- erl_internal:bool_op(Op, 2) orelse erl_internal:comp_op(Op, 2),
- L1 = gexpr(L0,St),
- R1 = gexpr(R0,St),
- {op,Line,Op,L1,R1}.
-
-gexpr_list([E0|Es],St) ->
- E1 = gexpr(E0,St),
- [E1|gexpr_list(Es,St)];
-gexpr_list([],_St) -> [].
-
-exprs([E0|Es],St) ->
- E1 = expr(E0,St),
- [E1|exprs(Es,St)];
-exprs([],_St) -> [].
-
-expr({var,_L,_V}=Var,_St) ->
- Var;
-% case index(V,St#pmod.parameters) of
-% N when N > 0 ->
-% {call,L,{remote,L,{atom,L,erlang},{atom,L,element}},
-% [{integer,L,N+1},{var,L,'THIS'}]};
-% _ ->
-% Var
-% end;
-expr({integer,_Line,_I}=Integer,_St) -> Integer;
-expr({float,_Line,_F}=Float,_St) -> Float;
-expr({atom,_Line,_A}=Atom,_St) -> Atom;
-expr({string,_Line,_S}=String,_St) -> String;
-expr({char,_Line,_C}=Char,_St) -> Char;
-expr({nil,_Line}=Nil,_St) -> Nil;
-expr({cons,Line,H0,T0},St) ->
- H1 = expr(H0,St),
- T1 = expr(T0,St),
- {cons,Line,H1,T1};
-expr({lc,Line,E0,Qs0},St) ->
- Qs1 = lc_bc_quals(Qs0,St),
- E1 = expr(E0,St),
- {lc,Line,E1,Qs1};
-expr({bc,Line,E0,Qs0},St) ->
- Qs1 = lc_bc_quals(Qs0,St),
- E1 = expr(E0,St),
- {bc,Line,E1,Qs1};
-expr({tuple,Line,Es0},St) ->
- Es1 = expr_list(Es0,St),
- {tuple,Line,Es1};
-expr({block,Line,Es0},St) ->
- Es1 = exprs(Es0,St),
- {block,Line,Es1};
-expr({'if',Line,Cs0},St) ->
- Cs1 = icr_clauses(Cs0,St),
- {'if',Line,Cs1};
-expr({'case',Line,E0,Cs0},St) ->
- E1 = expr(E0,St),
- Cs1 = icr_clauses(Cs0,St),
- {'case',Line,E1,Cs1};
-expr({'receive',Line,Cs0},St) ->
- Cs1 = icr_clauses(Cs0,St),
- {'receive',Line,Cs1};
-expr({'receive',Line,Cs0,To0,ToEs0},St) ->
- To1 = expr(To0,St),
- ToEs1 = exprs(ToEs0,St),
- Cs1 = icr_clauses(Cs0,St),
- {'receive',Line,Cs1,To1,ToEs1};
-expr({'try',Line,Es0,Scs0,Ccs0,As0},St) ->
- Es1 = exprs(Es0,St),
- Scs1 = icr_clauses(Scs0,St),
- Ccs1 = icr_clauses(Ccs0,St),
- As1 = exprs(As0,St),
- {'try',Line,Es1,Scs1,Ccs1,As1};
-expr({'fun',_,{function,_,_,_}}=ExtFun,_St) ->
- ExtFun;
-expr({'fun',Line,Body,Info},St) ->
- case Body of
- {clauses,Cs0} ->
- Cs1 = fun_clauses(Cs0,St),
- {'fun',Line,{clauses,Cs1},Info};
- {function,F,A} = Function ->
- {F1,A1} = update_function_name({F,A},St),
- if A1 =:= A ->
- {'fun',Line,Function,Info};
- true ->
- %% Must rewrite local fun-name to a fun that does a
- %% call with the extra THIS parameter.
- As = make_vars(A, Line),
- As1 = As ++ [{var,Line,'THIS'}],
- Call = {call,Line,{atom,Line,F1},As1},
- Cs = [{clause,Line,As,[],[Call]}],
- {'fun',Line,{clauses,Cs},Info}
- end;
- {function,_M,_F,_A} = Fun4 -> %This is an error in lint!
- {'fun',Line,Fun4,Info}
- end;
-expr({call,Lc,{atom,_,instance}=Name,As0},St) ->
- %% All local functions 'instance(...)' are static by definition,
- %% so they do not take a 'THIS' argument when called
- As1 = expr_list(As0,St),
- {call,Lc,Name,As1};
-expr({call,Lc,{atom,_,new}=Name,As0},St) ->
- %% All local functions 'new(...)' are static by definition,
- %% so they do not take a 'THIS' argument when called
- As1 = expr_list(As0,St),
- {call,Lc,Name,As1};
-expr({call,Lc,{atom,_,module_info}=Name,As0},St)
- when length(As0) =:= 0; length(As0) =:= 1 ->
- %% The module_info/0 and module_info/1 functions are also static.
- As1 = expr_list(As0,St),
- {call,Lc,Name,As1};
-expr({call,Lc,{atom,_Lf,_F}=Atom,As0},St) ->
- %% Local function call - needs THIS parameter.
- As1 = expr_list(As0,St),
- {call,Lc,Atom,As1 ++ [{var,0,'THIS'}]};
-expr({call,Line,F0,As0},St) ->
- %% Other function call
- F1 = expr(F0,St),
- As1 = expr_list(As0,St),
- {call,Line,F1,As1};
-expr({'catch',Line,E0},St) ->
- E1 = expr(E0,St),
- {'catch',Line,E1};
-expr({match,Line,P0,E0},St) ->
- E1 = expr(E0,St),
- P1 = pattern(P0,St),
- {match,Line,P1,E1};
-expr({bin,Line,Fs},St) ->
- Fs2 = pattern_grp(Fs,St),
- {bin,Line,Fs2};
-expr({op,Line,Op,A0},St) ->
- A1 = expr(A0,St),
- {op,Line,Op,A1};
-expr({op,Line,Op,L0,R0},St) ->
- L1 = expr(L0,St),
- R1 = expr(R0,St),
- {op,Line,Op,L1,R1};
-%% The following are not allowed to occur anywhere!
-expr({remote,Line,M0,F0},St) ->
- M1 = expr(M0,St),
- F1 = expr(F0,St),
- {remote,Line,M1,F1}.
-
-expr_list([E0|Es],St) ->
- E1 = expr(E0,St),
- [E1|expr_list(Es,St)];
-expr_list([],_St) -> [].
-
-icr_clauses([C0|Cs],St) ->
- C1 = clause(C0,St),
- [C1|icr_clauses(Cs,St)];
-icr_clauses([],_St) -> [].
-
-lc_bc_quals([{generate,Line,P0,E0}|Qs],St) ->
- E1 = expr(E0,St),
- P1 = pattern(P0,St),
- [{generate,Line,P1,E1}|lc_bc_quals(Qs,St)];
-lc_bc_quals([{b_generate,Line,P0,E0}|Qs],St) ->
- E1 = expr(E0,St),
- P1 = pattern(P0,St),
- [{b_generate,Line,P1,E1}|lc_bc_quals(Qs,St)];
-lc_bc_quals([E0|Qs],St) ->
- E1 = expr(E0,St),
- [E1|lc_bc_quals(Qs,St)];
-lc_bc_quals([],_St) -> [].
-
-fun_clauses([C0|Cs],St) ->
- C1 = clause(C0,St),
- [C1|fun_clauses(Cs,St)];
-fun_clauses([],_St) -> [].
-
-%% %% Return index from 1 upwards, or 0 if not in the list.
-%%
-%% index(X,Ys) -> index(X,Ys,1).
-%%
-%% index(X,[X|Ys],A) -> A;
-%% index(X,[Y|Ys],A) -> index(X,Ys,A+1);
-%% index(X,[],A) -> 0.
-
-make_vars(N, L) ->
- make_vars(1, N, L).
-
-make_vars(N, M, L) when N =< M ->
- V = list_to_atom("X"++integer_to_list(N)),
- [{var,L,V} | make_vars(N + 1, M, L)];
-make_vars(_, _, _) ->
- [].
diff --git a/lib/compiler/src/sys_pre_expand.erl b/lib/compiler/src/sys_pre_expand.erl
index e55fb2a037..7d918a55ed 100644
--- a/lib/compiler/src/sys_pre_expand.erl
+++ b/lib/compiler/src/sys_pre_expand.erl
@@ -28,17 +28,14 @@
%% Main entry point.
-export([module/2]).
--import(ordsets, [from_list/1,add_element/2,union/2]).
+-import(ordsets, [from_list/1,union/2]).
-import(lists, [member/2,foldl/3,foldr/3]).
-include("../include/erl_bits.hrl").
-record(expand, {module=[], %Module name
- parameters=undefined, %Module parameters
- package="", %Module package
exports=[], %Exports
imports=[], %Imports
- mod_imports, %Module Imports
compile=[], %Compile flags
attributes=[], %Attributes
callbacks=[], %Callbacks
@@ -67,12 +64,8 @@ module(Fs0, Opts0) ->
%% Set pre-defined exported functions.
PreExp = [{module_info,0},{module_info,1}],
- %% Set pre-defined module imports.
- PreModImp = [{erlang,erlang},{packages,packages}],
-
%% Build initial expand record.
St0 = #expand{exports=PreExp,
- mod_imports=dict:from_list(PreModImp),
compile=Opts,
defined=PreExp,
bitdefault = erl_bits:system_bitdefault(),
@@ -80,88 +73,20 @@ module(Fs0, Opts0) ->
},
%% Expand the functions.
{Tfs,St1} = forms(Fs, define_functions(Fs, St0)),
- {Efs,St2} = expand_pmod(Tfs, St1),
%% Get the correct list of exported functions.
- Exports = case member(export_all, St2#expand.compile) of
- true -> gb_sets:to_list(St2#expand.defined);
- false -> St2#expand.exports
+ Exports = case member(export_all, St1#expand.compile) of
+ true -> gb_sets:to_list(St1#expand.defined);
+ false -> St1#expand.exports
end,
%% Generate all functions from stored info.
- {Ats,St3} = module_attrs(St2#expand{exports = Exports}),
+ {Ats,St3} = module_attrs(St1#expand{exports = Exports}),
{Mfs,St4} = module_predef_funcs(St3),
- {St4#expand.module, St4#expand.exports, Ats ++ Efs ++ Mfs,
+ {St4#expand.module, St4#expand.exports, Ats ++ Tfs ++ Mfs,
St4#expand.compile}.
compiler_options(Forms) ->
lists:flatten([C || {attribute,_,compile,C} <- Forms]).
-expand_pmod(Fs0, St0) ->
- case St0#expand.parameters of
- undefined ->
- {Fs0,St0};
- Ps0 ->
- Base = get_base(St0#expand.attributes),
- Ps = if is_atom(Base) ->
- ['BASE' | Ps0];
- true ->
- Ps0
- end,
- Def = gb_sets:to_list(St0#expand.defined),
- {Fs1,Xs,Ds} = sys_expand_pmod:forms(Fs0, Ps,
- St0#expand.exports,
- Def),
- St1 = St0#expand{exports=Xs,defined=gb_sets:from_list(Ds)},
- {Fs2,St2} = add_instance(Ps, Fs1, St1),
- {Fs3,St3} = ensure_new(Base, Ps0, Fs2, St2),
- {Fs3,St3#expand{attributes = [{abstract, 0, [true]}
- | St3#expand.attributes]}}
- end.
-
-get_base(As) ->
- case lists:keyfind(extends, 1, As) of
- {extends,_,[Base]} when is_atom(Base) ->
- Base;
- _ ->
- []
- end.
-
-ensure_new(Base, Ps, Fs, St) ->
- case has_new(Fs) of
- true ->
- {Fs, St};
- false ->
- add_new(Base, Ps, Fs, St)
- end.
-
-has_new([{function,_L,new,_A,_Cs} | _Fs]) ->
- true;
-has_new([_ | Fs]) ->
- has_new(Fs);
-has_new([]) ->
- false.
-
-add_new(Base, Ps, Fs, St) ->
- Vs = [{var,0,V} || V <- Ps],
- As = if is_atom(Base) ->
- [{call,0,{remote,0,{atom,0,Base},{atom,0,new}},Vs} | Vs];
- true ->
- Vs
- end,
- Body = [{call,0,{atom,0,instance},As}],
- add_func(new, Vs, Body, Fs, St).
-
-add_instance(Ps, Fs, St) ->
- Vs = [{var,0,V} || V <- Ps],
- AbsMod = [{tuple,0,[{atom,0,St#expand.module}|Vs]}],
- add_func(instance, Vs, AbsMod, Fs, St).
-
-add_func(Name, Args, Body, Fs, St) ->
- A = length(Args),
- F = {function,0,Name,A,[{clause,0,Args,[],Body}]},
- NA = {Name,A},
- {[F|Fs],St#expand{exports=add_element(NA, St#expand.exports),
- defined=gb_sets:add_element(NA, St#expand.defined)}}.
-
%% define_function(Form, State) -> State.
%% Add function to defined if form is a function.
@@ -241,15 +166,9 @@ forms([], St) -> {[],St}.
%% attribute(Attribute, Value, Line, State) -> State'.
%% Process an attribute, this just affects the state.
-attribute(module, {Module, As}, _L, St) ->
- M = package_to_string(Module),
- St#expand{module=list_to_atom(M),
- package=packages:strip_last(M),
- parameters=As};
attribute(module, Module, _L, St) ->
- M = package_to_string(Module),
- St#expand{module=list_to_atom(M),
- package=packages:strip_last(M)};
+ true = is_atom(Module),
+ St#expand{module=Module};
attribute(export, Es, _L, St) ->
St#expand{exports=union(from_list(Es), St#expand.exports)};
attribute(import, Is, _L, St) ->
@@ -312,8 +231,6 @@ pattern({tuple,Line,Ps}, St0) ->
%%pattern({struct,Line,Tag,Ps}, St0) ->
%% {TPs,TPsvs,St1} = pattern_list(Ps, St0),
%% {{tuple,Line,[{atom,Line,Tag}|TPs]},TPsvs,St1};
-pattern({record_field,_,_,_}=M, St) ->
- {expand_package(M, St),St}; % must be a package name
pattern({bin,Line,Es0}, St0) ->
{Es1,St1} = pattern_bin(Es0, St0),
{{bin,Line,Es1},St1};
@@ -404,8 +321,6 @@ expr({tuple,Line,Es0}, St0) ->
%%expr({struct,Line,Tag,Es0}, Vs, St0) ->
%% {Es1,Esvs,Esus,St1} = expr_list(Es0, Vs, St0),
%% {{tuple,Line,[{atom,Line,Tag}|Es1]},Esvs,Esus,St1};
-expr({record_field,_,_,_}=M, St) ->
- {expand_package(M, St),St}; % must be a package name
expr({bin,Line,Es0}, St0) ->
{Es1,St1} = expr_bin(Es0, St0),
{{bin,Line,Es1},St1};
@@ -448,12 +363,9 @@ expr({call,Line,{atom,La,N}=Atom,As0}, St0) ->
end
end
end;
-expr({call,Line,{record_field,_,_,_}=M,As0}, St0) ->
- expr({call,Line,expand_package(M, St0),As0}, St0);
-expr({call,Line,{remote,Lr,M,F},As0}, St0) ->
- M1 = expand_package(M, St0),
- {[M2,F1|As1],St1} = expr_list([M1,F|As0], St0),
- {{call,Line,{remote,Lr,M2,F1},As1},St1};
+expr({call,Line,{remote,Lr,M0,F},As0}, St0) ->
+ {[M1,F1|As1],St1} = expr_list([M0,F|As0], St0),
+ {{call,Line,{remote,Lr,M1,F1},As1},St1};
expr({call,Line,F,As0}, St0) ->
{[Fun1|As1],St1} = expr_list([F|As0], St0),
{{call,Line,Fun1,As1},St1};
@@ -666,32 +578,6 @@ string_to_conses(Line, Cs, Tail) ->
foldr(fun (C, T) -> {cons,Line,{char,Line,C},T} end, Tail, Cs).
-%% In syntax trees, module/package names are atoms or lists of atoms.
-
-package_to_string(A) when is_atom(A) -> atom_to_list(A);
-package_to_string(L) when is_list(L) -> packages:concat(L).
-
-expand_package({atom,L,A} = M, St) ->
- case dict:find(A, St#expand.mod_imports) of
- {ok, A1} ->
- {atom,L,A1};
- error ->
- case packages:is_segmented(A) of
- true ->
- M;
- false ->
- M1 = packages:concat(St#expand.package, A),
- {atom,L,list_to_atom(M1)}
- end
- end;
-expand_package(M, _St) ->
- case erl_parse:package_segments(M) of
- error ->
- M;
- M1 ->
- {atom,element(2,M),list_to_atom(package_to_string(M1))}
- end.
-
%% import(Line, Imports, State) ->
%% State'
%% imported(Name, Arity, State) ->
@@ -699,15 +585,10 @@ expand_package(M, _St) ->
%% Handle import declarations and test for imported functions. No need to
%% check when building imports as code is correct.
-import({Mod0,Fs}, St) ->
- Mod = list_to_atom(package_to_string(Mod0)),
+import({Mod,Fs}, St) ->
+ true = is_atom(Mod),
Mfs = from_list(Fs),
- St#expand{imports=add_imports(Mod, Mfs, St#expand.imports)};
-import(Mod0, St) ->
- Mod = package_to_string(Mod0),
- Key = list_to_atom(packages:last(Mod)),
- St#expand{mod_imports=dict:store(Key, list_to_atom(Mod),
- St#expand.mod_imports)}.
+ St#expand{imports=add_imports(Mod, Mfs, St#expand.imports)}.
add_imports(Mod, [F|Fs], Is) ->
add_imports(Mod, Fs, orddict:store(F, Mod, Is));
diff --git a/lib/compiler/src/v3_codegen.erl b/lib/compiler/src/v3_codegen.erl
index be15495672..6a13495523 100644
--- a/lib/compiler/src/v3_codegen.erl
+++ b/lib/compiler/src/v3_codegen.erl
@@ -123,15 +123,24 @@ cg_fun(Les, Hvs, Vdb, AtomMod, NameArity, Anno, St0) ->
put_reg(V, Reg)
end, [], Hvs),
stk=[]}, 0, Vdb),
- {B,_Aft,St} = cg_list(Les, 0, Vdb, Bef,
+ {B0,_Aft,St} = cg_list(Les, 0, Vdb, Bef,
St3#cg{bfail=0,
ultimate_failure=UltimateMatchFail,
is_top_block=true}),
+ B = fix_bs_match_strings(B0),
{Name,Arity} = NameArity,
Asm = [{label,Fi},line(Anno),{func_info,AtomMod,{atom,Name},Arity},
{label,Fl}|B++[{label,UltimateMatchFail},if_end]],
{Asm,Fl,St}.
+fix_bs_match_strings([{test,bs_match_string,F,[Ctx,BinList]}|Is])
+ when is_list(BinList) ->
+ I = {test,bs_match_string,F,[Ctx,list_to_bitstring(BinList)]},
+ [I|fix_bs_match_strings(Is)];
+fix_bs_match_strings([I|Is]) ->
+ [I|fix_bs_match_strings(Is)];
+fix_bs_match_strings([]) -> [].
+
%% cg(Lkexpr, Vdb, StackReg, State) -> {[Ainstr],StackReg,State}.
%% Generate code for a kexpr.
%% Split function into two steps for clarity, not efficiency.
@@ -370,6 +379,7 @@ bsm_rename_ctx(#l{ke={test,_,_}}=L, _, _, _) -> L;
bsm_rename_ctx(#l{ke={bif,_,_,_}}=L, _, _, _) -> L;
bsm_rename_ctx(#l{ke={gc_bif,_,_,_}}=L, _, _, _) -> L;
bsm_rename_ctx(#l{ke={set,_,_}}=L, _, _, _) -> L;
+bsm_rename_ctx(#l{ke={call,_,_,_}}=L, _, _, _) -> L;
bsm_rename_ctx(#l{ke={block,_}}=L, Old, _, false) ->
%% This block is not inside a protected. The match context variable cannot
%% possibly be live inside the block.
@@ -713,7 +723,22 @@ select_bin_seg(#l{ke={val_clause,{bin_int,Ctx,Sz,U,Fs,Val,Es},B},i=I,vdb=Vdb},
I, Vdb, Bef, Ctx, St0),
{Bis,Aft,St2} = match_cg(B, Fail, Int, St1),
CtxReg = fetch_var(Ctx, Bef),
- {[{bs_restore2,CtxReg,{Ctx,Ivar}}|Mis] ++ Bis,Aft,St2}.
+ Is = case Mis ++ Bis of
+ [{test,bs_match_string,F,[OtherCtx,Bin1]},
+ {bs_save2,OtherCtx,_},
+ {bs_restore2,OtherCtx,_},
+ {test,bs_match_string,F,[OtherCtx,Bin2]}|Is0] ->
+ %% We used to do this optimization later, but it
+ %% turns out that in huge functions with many
+ %% bs_match_string instructions, it's a big win
+ %% to do the combination now. To avoid copying the
+ %% binary data again and again, we'll combine bitstrings
+ %% in a list and convert all of it to a bitstring later.
+ [{test,bs_match_string,F,[OtherCtx,[Bin1,Bin2]]}|Is0];
+ Is0 ->
+ Is0
+ end,
+ {[{bs_restore2,CtxReg,{Ctx,Ivar}}|Is],Aft,St2}.
select_extract_int([{var,Tl}], Val, {integer,Sz}, U, Fs, Vf,
I, Vdb, Bef, Ctx, St) ->
@@ -1385,22 +1410,32 @@ catch_cg(C, {var,R}, Le, Vdb, Bef, St0) ->
%%
%% put_list for constructing a cons is an atomic instruction
%% which can safely resuse one of the source registers as target.
-%% Also binaries can reuse a source register as target.
set_cg([{var,R}], {cons,Es}, Le, Vdb, Bef, St) ->
- [S1,S2] = map(fun ({var,V}) -> fetch_var(V, Bef);
- (Other) -> Other
- end, Es),
+ [S1,S2] = cg_reg_args(Es, Bef),
Int0 = clear_dead(Bef, Le#l.i, Vdb),
Int1 = Int0#sr{reg=put_reg(R, Int0#sr.reg)},
Ret = fetch_reg(R, Int1#sr.reg),
{[{put_list,S1,S2,Ret}], Int1, St};
set_cg([{var,R}], {binary,Segs}, Le, Vdb, Bef,
#cg{in_catch=InCatch, bfail=Bfail}=St) ->
+ %% At run-time, binaries are constructed in three stages:
+ %% 1) First the size of the binary is calculated.
+ %% 2) Then the binary is allocated.
+ %% 3) Then each field in the binary is constructed.
+ %% For simplicity, we use the target register to also hold the
+ %% size of the binary. Therefore the target register must *not*
+ %% be one of the source registers.
+
+ %% First allocate the target register.
Int0 = Bef#sr{reg=put_reg(R, Bef#sr.reg)},
Target = fetch_reg(R, Int0#sr.reg),
- Fail = {f,Bfail},
+
+ %% Also allocate a scratch register for size calculations.
Temp = find_scratch_reg(Int0#sr.reg),
+
+ %% First generate the code that constructs each field.
+ Fail = {f,Bfail},
PutCode = cg_bin_put(Segs, Fail, Bef),
{Sis,Int1} =
case InCatch of
@@ -1409,6 +1444,8 @@ set_cg([{var,R}], {binary,Segs}, Le, Vdb, Bef,
end,
MaxRegs = max_reg(Bef#sr.reg),
Aft = clear_dead(Int1, Le#l.i, Vdb),
+
+ %% Now generate the complete code for constructing the binary.
Code = cg_binary(PutCode, Target, Temp, Fail, MaxRegs, Le#l.a),
{Sis++Code,Aft,St};
set_cg([{var,R}], Con, Le, Vdb, Bef, St) ->
@@ -1418,10 +1455,8 @@ set_cg([{var,R}], Con, Le, Vdb, Bef, St) ->
Ais = case Con of
{tuple,Es} ->
[{put_tuple,length(Es),Ret}] ++ cg_build_args(Es, Bef);
- {var,V} -> % Normally removed by kernel optimizer.
- [{move,fetch_var(V, Int),Ret}];
Other ->
- [{move,Other,Ret}]
+ [{move,cg_reg_arg(Other, Int),Ret}]
end,
{Ais,clear_dead(Int, Le#l.i, Vdb),St}.
@@ -1575,8 +1610,7 @@ cg_gen_binsize([], _, _, _, _, Acc) -> Acc.
%% cg_bin_opt(Code0) -> Code
%% Optimize the size calculations for binary construction.
-cg_bin_opt([{move,Size,D},{bs_append,Fail,D,Extra,Regs0,U,Bin,Flags,D}|Is]) ->
- Regs = cg_bo_newregs(Regs0, D),
+cg_bin_opt([{move,Size,D},{bs_append,Fail,D,Extra,Regs,U,Bin,Flags,D}|Is]) ->
cg_bin_opt([{bs_append,Fail,Size,Extra,Regs,U,Bin,Flags,D}|Is]);
cg_bin_opt([{move,Size,D},{bs_private_append,Fail,D,U,Bin,Flags,D}|Is]) ->
cg_bin_opt([{bs_private_append,Fail,Size,U,Bin,Flags,D}|Is]);
@@ -1584,9 +1618,8 @@ cg_bin_opt([{move,{integer,0},D},{bs_add,_,[D,{integer,_}=S,1],Dst}|Is]) ->
cg_bin_opt([{move,S,Dst}|Is]);
cg_bin_opt([{move,{integer,0},D},{bs_add,Fail,[D,S,U],Dst}|Is]) ->
cg_bin_opt([{bs_add,Fail,[{integer,0},S,U],Dst}|Is]);
-cg_bin_opt([{move,{integer,Bytes},D},{Op,Fail,D,Extra,Regs0,Flags,D}|Is])
+cg_bin_opt([{move,{integer,Bytes},D},{Op,Fail,D,Extra,Regs,Flags,D}|Is])
when Op =:= bs_init2; Op =:= bs_init_bits ->
- Regs = cg_bo_newregs(Regs0, D),
cg_bin_opt([{Op,Fail,Bytes,Extra,Regs,Flags,D}|Is]);
cg_bin_opt([{move,Src1,Dst},{bs_add,Fail,[Dst,Src2,U],Dst}|Is]) ->
cg_bin_opt([{bs_add,Fail,[Src1,Src2,U],Dst}|Is]);
@@ -1594,20 +1627,9 @@ cg_bin_opt([I|Is]) ->
[I|cg_bin_opt(Is)];
cg_bin_opt([]) -> [].
-cg_bo_newregs(R, {x,X}) when R-1 =:= X -> R-1;
-cg_bo_newregs(R, _) -> R.
-
-%% Common for new and old binary code generation.
-
cg_bin_put({bin_seg,[],S0,U,T,Fs,[E0,Next]}, Fail, Bef) ->
- S1 = case S0 of
- {var,Sv} -> fetch_var(Sv, Bef);
- _ -> S0
- end,
- E1 = case E0 of
- {var,V} -> fetch_var(V, Bef);
- Other -> Other
- end,
+ S1 = cg_reg_arg(S0, Bef),
+ E1 = cg_reg_arg(E0, Bef),
{Format,Op} = case T of
integer -> {plain,bs_put_integer};
utf8 -> {utf,bs_put_utf8};
@@ -1625,9 +1647,7 @@ cg_bin_put({bin_seg,[],S0,U,T,Fs,[E0,Next]}, Fail, Bef) ->
cg_bin_put({bin_end,[]}, _, _) -> [].
cg_build_args(As, Bef) ->
- map(fun ({var,V}) -> {put,fetch_var(V, Bef)};
- (Other) -> {put,Other}
- end, As).
+ [{put,cg_reg_arg(A, Bef)} || A <- As].
%% return_cg([Val], Le, Vdb, Bef, St) -> {[Ainstr],Aft,St}.
%% break_cg([Val], Le, Vdb, Bef, St) -> {[Ainstr],Aft,St}.
@@ -1906,27 +1926,13 @@ fetch_var(V, Sr) ->
error -> fetch_stack(V, Sr#sr.stk)
end.
-% find_var(V, Sr) ->
-% case find_reg(V, Sr#sr.reg) of
-% {ok,R} -> {ok,R};
-% error ->
-% case find_stack(V, Sr#sr.stk) of
-% {ok,S} -> {ok,S};
-% error -> error
-% end
-% end.
-
load_vars(Vs, Regs) ->
foldl(fun ({var,V}, Rs) -> put_reg(V, Rs) end, Regs, Vs).
%% put_reg(Val, Regs) -> Regs.
-%% free_reg(Val, Regs) -> Regs.
%% find_reg(Val, Regs) -> ok{r{R}} | error.
%% fetch_reg(Val, Regs) -> r{R}.
%% Functions to interface the registers.
-%% put_reg puts a value into a free register,
-%% load_reg loads a value into a fixed register
-%% free_reg frees a register containing a specific value.
% put_regs(Vs, Rs) -> foldl(fun put_reg/2, Rs, Vs).
@@ -1937,10 +1943,6 @@ put_reg_1(V, [{reserved,I,V}|Rs], I) -> [{I,V}|Rs];
put_reg_1(V, [R|Rs], I) -> [R|put_reg_1(V, Rs, I+1)];
put_reg_1(V, [], I) -> [{I,V}].
-% free_reg(V, [{I,V}|Rs]) -> [free|Rs];
-% free_reg(V, [R|Rs]) -> [R|free_reg(V, Rs)];
-% free_reg(V, []) -> [].
-
fetch_reg(V, [{I,V}|_]) -> {x,I};
fetch_reg(V, [_|SRs]) -> fetch_reg(V, SRs).
@@ -1957,9 +1959,6 @@ find_scratch_reg([free|_], I) -> {x,I};
find_scratch_reg([_|Rs], I) -> find_scratch_reg(Rs, I+1);
find_scratch_reg([], I) -> {x,I}.
-%%copy_reg(Val, R, Regs) -> load_reg(Val, R, Regs).
-%%move_reg(Val, R, Regs) -> load_reg(Val, R, free_reg(Val, Regs)).
-
replace_reg_contents(Old, New, [{I,Old}|Rs]) -> [{I,New}|Rs];
replace_reg_contents(Old, New, [R|Rs]) -> [R|replace_reg_contents(Old, New, Rs)].
diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl
index b184987625..b1bff47f69 100644
--- a/lib/compiler/src/v3_kernel.erl
+++ b/lib/compiler/src/v3_kernel.erl
@@ -81,7 +81,7 @@
-export([module/2,format_error/1]).
-import(lists, [map/2,foldl/3,foldr/3,mapfoldl/3,splitwith/2,member/2,
- keymember/3,keyfind/3]).
+ keymember/3,keyfind/3,partition/2]).
-import(ordsets, [add_element/2,del_element/2,union/2,union/1,subtract/2]).
-import(cerl, [c_tuple/1]).
@@ -235,16 +235,8 @@ gexpr_test_add(Ke, St0) ->
%% expr(Cexpr, Sub, State) -> {Kexpr,[PreKexpr],State}.
%% Convert a Core expression, flattening it at the same time.
-expr(#c_var{anno=A,name={_Name,Arity}}=Fname, Sub, St) ->
- %% A local in an expression.
- %% For now, these are wrapped into a fun by reverse
- %% etha-conversion, but really, there should be exactly one
- %% such "lambda function" for each escaping local name,
- %% instead of one for each occurrence as done now.
- Vs = [#c_var{name=list_to_atom("V" ++ integer_to_list(V))} ||
- V <- integers(1, Arity)],
- Fun = #c_fun{anno=A,vars=Vs,body=#c_apply{anno=A,op=Fname,args=Vs}},
- expr(Fun, Sub, St);
+expr(#c_var{anno=A,name={Name,Arity}}, Sub, St) ->
+ {#k_local{anno=A,name=get_fsub(Name, Arity, Sub),arity=Arity},[],St};
expr(#c_var{anno=A,name=V}, Sub, St) ->
{#k_var{anno=A,name=get_vsub(V, Sub)},[],St};
expr(#c_literal{anno=A,val=V}, _Sub, St) ->
@@ -1081,9 +1073,44 @@ select_bin_con(Cs0) ->
end, Cs0),
select_bin_con_1(Cs1).
+
select_bin_con_1(Cs) ->
try
- select_bin_int(Cs)
+ %% The usual way to match literals is to first extract the
+ %% value to a register, and then compare the register to the
+ %% literal value. Extracting the value is good if we need
+ %% compare it more than once.
+ %%
+ %% But we would like to combine the extracting and the
+ %% comparing into a single instruction if we know that
+ %% a binary segment must contain specific integer value
+ %% or the matching will fail, like in this example:
+ %%
+ %% <<42:8,...>> ->
+ %% <<42:8,...>> ->
+ %% .
+ %% .
+ %% .
+ %% <<42:8,...>> ->
+ %% <<>> ->
+ %%
+ %% The first segment must either contain the integer 42
+ %% or the binary must end for the match to succeed.
+ %%
+ %% The way we do is to replace the generic #k_bin_seg{}
+ %% record with a #k_bin_int{} record if all clauses will
+ %% select the same literal integer (except for one or more
+ %% clauses that will end the binary).
+
+ {BinSegs0,BinEnd} =
+ partition(fun (C) ->
+ clause_con(C) =:= k_bin_seg
+ end, Cs),
+ BinSegs = select_bin_int(BinSegs0),
+ case BinEnd of
+ [] -> BinSegs;
+ [_|_] -> BinSegs ++ [{k_bin_end,BinEnd}]
+ end
catch
throw:not_possible ->
select_bin_con_2(Cs)
@@ -1097,7 +1124,7 @@ select_bin_con_2([]) -> [].
%% select_bin_int([Clause]) -> {k_bin_int,[Clause]}
%% If the first pattern in each clause selects the same integer,
-%% rewrite all clauses to use #k_bin_int{} (which will later to
+%% rewrite all clauses to use #k_bin_int{} (which will later be
%% translated to a bs_match_string/4 instruction).
%%
%% If it is not possible to do this rewrite, a 'not_possible'
@@ -1346,7 +1373,7 @@ clause_arg(#iclause{pats=[Arg|_]}) -> Arg.
clause_con(C) -> arg_con(clause_arg(C)).
-clause_val(C) -> arg_val(clause_arg(C)).
+clause_val(C) -> arg_val(clause_arg(C), C).
is_var_clause(C) -> clause_con(C) =:= k_var.
@@ -1377,7 +1404,7 @@ arg_con(Arg) ->
#k_var{} -> k_var
end.
-arg_val(Arg) ->
+arg_val(Arg, C) ->
case arg_arg(Arg) of
#k_literal{val=Lit} -> Lit;
#k_int{val=I} -> I;
@@ -1385,7 +1412,13 @@ arg_val(Arg) ->
#k_atom{val=A} -> A;
#k_tuple{es=Es} -> length(Es);
#k_bin_seg{size=S,unit=U,type=T,flags=Fs} ->
- {set_kanno(S, []),U,T,Fs}
+ case S of
+ #k_var{name=V} ->
+ #iclause{isub=Isub} = C,
+ {#k_var{name=get_vsub(V, Isub)},U,T,Fs};
+ _ ->
+ {set_kanno(S, []),U,T,Fs}
+ end
end.
%% ubody_used_vars(Expr, State) -> [UsedVar]
@@ -1622,6 +1655,19 @@ uexpr(#ifun{anno=A,vars=Vs,body=B0}, {break,Rs}, St0) ->
#k_int{val=Index},#k_int{val=Uniq}|Fvs],
ret=Rs},
Free,add_local_function(Fun, St)};
+uexpr(#k_local{anno=A,name=Name,arity=Arity}, {break,Rs}, St) ->
+ Fs = get_free(Name, Arity, St),
+ FsCount = length(Fs),
+ Free = lit_list_vars(Fs),
+ %% Set dummy values for Index and Uniq -- the real values will
+ %% be assigned by beam_asm.
+ Index = Uniq = 0,
+ Bif = #k_bif{anno=#k{us=Free,ns=lit_list_vars(Rs),a=A},
+ op=#k_internal{name=make_fun,arity=FsCount+3},
+ args=[#k_atom{val=Name},#k_int{val=FsCount+Arity},
+ #k_int{val=Index},#k_int{val=Uniq}|Fs],
+ ret=Rs},
+ {Bif,Free,St};
uexpr(Lit, {break,Rs0}, St0) ->
%% Transform literals to puts here.
%%ok = io:fwrite("uexpr ~w:~p~n", [?LINE,Lit]),
@@ -1802,12 +1848,6 @@ make_list(Es) ->
#c_cons{hd=E,tl=Acc}
end, #c_literal{val=[]}, Es).
-%% List of integers in interval [N,M]. Empty list if N > M.
-
-integers(N, M) when N =< M ->
- [N|integers(N + 1, M)];
-integers(_, _) -> [].
-
%% is_in_guard(State) -> true|false.
is_in_guard(#kern{guard_refc=Refc}) ->
diff --git a/lib/compiler/test/Makefile b/lib/compiler/test/Makefile
index e047166ade..b9c5be09ce 100644
--- a/lib/compiler/test/Makefile
+++ b/lib/compiler/test/Makefile
@@ -10,7 +10,7 @@ MODULES= \
apply_SUITE \
beam_validator_SUITE \
beam_disasm_SUITE \
- beam_expect_SUITE \
+ beam_except_SUITE \
bs_bincomp_SUITE \
bs_bit_binaries_SUITE \
bs_construct_SUITE \
@@ -29,7 +29,6 @@ MODULES= \
match_SUITE \
misc_SUITE \
num_bif_SUITE \
- pmod_SUITE \
receive_SUITE \
record_SUITE \
trycatch_SUITE \
@@ -39,7 +38,7 @@ MODULES= \
NO_OPT= \
andor \
apply \
- beam_expect \
+ beam_except \
bs_construct \
bs_match \
bs_utf \
diff --git a/lib/compiler/test/andor_SUITE.erl b/lib/compiler/test/andor_SUITE.erl
index f7388f1614..fe69aeeb43 100644
--- a/lib/compiler/test/andor_SUITE.erl
+++ b/lib/compiler/test/andor_SUITE.erl
@@ -29,11 +29,12 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [t_case, t_and_or, t_andalso, t_orelse, inside, overlap,
- combined, in_case, before_and_inside_if].
+ [{group,p}].
groups() ->
- [].
+ [{p,test_lib:parallel(),
+ [t_case,t_and_or,t_andalso,t_orelse,inside,overlap,
+ combined,in_case,before_and_inside_if]}].
init_per_suite(Config) ->
Config.
diff --git a/lib/compiler/test/beam_expect_SUITE.erl b/lib/compiler/test/beam_except_SUITE.erl
index 6f216eac4f..6b55224a42 100644
--- a/lib/compiler/test/beam_expect_SUITE.erl
+++ b/lib/compiler/test/beam_except_SUITE.erl
@@ -16,7 +16,7 @@
%%
%% %CopyrightEnd%
%%
--module(beam_expect_SUITE).
+-module(beam_except_SUITE).
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
diff --git a/lib/compiler/test/beam_validator_SUITE.erl b/lib/compiler/test/beam_validator_SUITE.erl
index 902867bc19..c84c83795a 100644
--- a/lib/compiler/test/beam_validator_SUITE.erl
+++ b/lib/compiler/test/beam_validator_SUITE.erl
@@ -47,17 +47,18 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [beam_files, compiler_bug, stupid_but_valid, xrange,
- yrange, stack, call_last, merge_undefined, uninit,
- unsafe_catch, dead_code, mult_labels,
- overwrite_catchtag, overwrite_trytag, accessing_tags,
- bad_catch_try, cons_guard, freg_range, freg_uninit,
- freg_state, bin_match, bin_aligned, bad_dsetel,
- state_after_fault_in_catch, no_exception_in_catch,
- undef_label, illegal_instruction, failing_gc_guard_bif].
+ [beam_files,{group,p}].
groups() ->
- [].
+ [{p,test_lib:parallel(),
+ [compiler_bug,stupid_but_valid,xrange,
+ yrange,stack,call_last,merge_undefined,uninit,
+ unsafe_catch,dead_code,mult_labels,
+ overwrite_catchtag,overwrite_trytag,accessing_tags,
+ bad_catch_try,cons_guard,freg_range,freg_uninit,
+ freg_state,bin_match,bin_aligned,bad_dsetel,
+ state_after_fault_in_catch,no_exception_in_catch,
+ undef_label,illegal_instruction,failing_gc_guard_bif]}].
init_per_suite(Config) ->
Config.
diff --git a/lib/compiler/test/bs_bit_binaries_SUITE.erl b/lib/compiler/test/bs_bit_binaries_SUITE.erl
index 30276f1259..897b4769f1 100644
--- a/lib/compiler/test/bs_bit_binaries_SUITE.erl
+++ b/lib/compiler/test/bs_bit_binaries_SUITE.erl
@@ -34,13 +34,15 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [misc, horrid_match, test_bitstr, test_bit_size,
- asymmetric_tests, big_asymmetric_tests,
- binary_to_and_from_list, big_binary_to_and_from_list,
- send_and_receive, send_and_receive_alot].
+ [{group,p}].
groups() ->
- [].
+ [{p,test_lib:parallel(),
+ [misc,horrid_match,test_bitstr,test_bit_size,
+ asymmetric_tests,big_asymmetric_tests,
+ binary_to_and_from_list,big_binary_to_and_from_list,
+ send_and_receive,send_and_receive_alot]}].
+
init_per_suite(Config) ->
Config.
diff --git a/lib/compiler/test/bs_construct_SUITE.erl b/lib/compiler/test/bs_construct_SUITE.erl
index 9ab76449c7..4ea5235bb6 100644
--- a/lib/compiler/test/bs_construct_SUITE.erl
+++ b/lib/compiler/test/bs_construct_SUITE.erl
@@ -36,12 +36,14 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [two, test1, fail, float_bin, in_guard, in_catch,
- nasty_literals, side_effect, opt, otp_7556, float_arith,
- otp_8054].
+ [{group,p}].
groups() ->
- [].
+ [{p,test_lib:parallel(),
+ [two,test1,fail,float_bin,in_guard,in_catch,
+ nasty_literals,side_effect,opt,otp_7556,float_arith,
+ otp_8054]}].
+
init_per_suite(Config) ->
Config.
@@ -360,6 +362,11 @@ in_catch(Config) when is_list(Config) ->
?line <<255>> = small(255, <<1,2,3,4,5,6,7,8,9>>),
?line <<1,2>> = small(<<7,8,9,10>>, 258),
?line <<>> = small(<<1,2,3,4,5>>, <<7,8,9,10>>),
+
+ <<15,240,0,42>> = small2(255, 42),
+ <<7:20>> = small2(<<1,2,3>>, 7),
+ <<300:12>> = small2(300, <<1,2,3>>),
+ <<>> = small2(<<1>>, <<2>>),
ok.
small(A, B) ->
@@ -381,6 +388,25 @@ small(A, B) ->
end,
<<ResA/binary,ResB/binary>>.
+small2(A, B) ->
+ case begin
+ case catch <<A:12>> of
+ {'EXIT',_} -> <<>>;
+ ResA0 -> ResA0
+ end
+ end of
+ ResA -> ok
+ end,
+ case begin
+ case catch <<B:20>> of
+ {'EXIT',_} -> <<>>;
+ ResB0 -> ResB0
+ end
+ end of
+ ResB -> ok
+ end,
+ <<ResA/binary-unit:1,ResB/binary-unit:1>>.
+
nasty_literals(Config) when is_list(Config) ->
case erlang:system_info(endian) of
big ->
diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl
index 01b7568122..d63d2235d7 100644
--- a/lib/compiler/test/bs_match_SUITE.erl
+++ b/lib/compiler/test/bs_match_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -33,7 +33,7 @@
matching_meets_construction/1,simon/1,matching_and_andalso/1,
otp_7188/1,otp_7233/1,otp_7240/1,otp_7498/1,
match_string/1,zero_width/1,bad_size/1,haystack/1,
- cover_beam_bool/1]).
+ cover_beam_bool/1,matched_out_size/1,follow_fail_branch/1]).
-export([coverage_id/1,coverage_external_ignore/2]).
@@ -44,19 +44,21 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [fun_shadow, int_float, otp_5269, null_fields, wiger,
- bin_tail, save_restore, shadowed_size_var,
- partitioned_bs_match, function_clause, unit,
- shared_sub_bins, bin_and_float, dec_subidentifiers,
- skip_optional_tag, wfbm, degenerated_match, bs_sum,
- coverage, multiple_uses, zero_label, followed_by_catch,
- matching_meets_construction, simon,
- matching_and_andalso, otp_7188, otp_7233, otp_7240,
- otp_7498, match_string, zero_width, bad_size, haystack,
- cover_beam_bool].
+ [{group,p}].
groups() ->
- [].
+ [{p,test_lib:parallel(),
+ [fun_shadow,int_float,otp_5269,null_fields,wiger,
+ bin_tail,save_restore,shadowed_size_var,
+ partitioned_bs_match,function_clause,unit,
+ shared_sub_bins,bin_and_float,dec_subidentifiers,
+ skip_optional_tag,wfbm,degenerated_match,bs_sum,
+ coverage,multiple_uses,zero_label,followed_by_catch,
+ matching_meets_construction,simon,
+ matching_and_andalso,otp_7188,otp_7233,otp_7240,
+ otp_7498,match_string,zero_width,bad_size,haystack,
+ cover_beam_bool,matched_out_size,follow_fail_branch]}].
+
init_per_suite(Config) ->
Config.
@@ -800,12 +802,29 @@ matching_and_andalso(Config) when is_list(Config) ->
?line {'EXIT',{function_clause,_}} = (catch matching_and_andalso_1(<<1,2,3>>, -8)),
?line {'EXIT',{function_clause,_}} = (catch matching_and_andalso_1(<<1,2,3>>, blurf)),
?line {'EXIT',{function_clause,_}} = (catch matching_and_andalso_1(<<1,2,3>>, 19)),
+
+ {"abc",<<"xyz">>} = matching_and_andalso_2("abc", <<"-xyz">>),
+ {"abc",<<"">>} = matching_and_andalso_2("abc", <<($a-1)>>),
+ {"abc",<<"">>} = matching_and_andalso_2("abc", <<($z+1)>>),
+ {"abc",<<"">>} = matching_and_andalso_2("abc", <<($A-1)>>),
+ {"abc",<<"">>} = matching_and_andalso_2("abc", <<($Z+1)>>),
+ error = matching_and_andalso_2([], <<>>),
+ error = matching_and_andalso_2([], <<$A>>),
+ error = matching_and_andalso_2([], <<$Z>>),
+ error = matching_and_andalso_2([], <<$a>>),
+ error = matching_and_andalso_2([], <<$z>>),
ok.
matching_and_andalso_1(<<Bitmap/binary>>, K)
when is_integer(K) andalso size(Bitmap) >= K andalso 0 < K ->
ok.
+matching_and_andalso_2(Datetime, <<H,T/binary>>)
+ when not ((H >= $a) andalso (H =< $z)) andalso
+ not ((H >= $A) andalso (H =< $Z)) ->
+ {Datetime,T};
+matching_and_andalso_2(_, _) -> error.
+
%% Thanks to Tomas Stejskal.
otp_7188(Config) when is_list(Config) ->
MP3 = <<84,65,71,68,117,154,105,232,107,121,0,0,0,0,0,0,0,0,0,0,
@@ -1062,6 +1081,59 @@ do_cover_beam_bool(Bin, X) when X > 0 ->
do_cover_beam_bool(<<_,Bin/binary>>, X) ->
do_cover_beam_bool(Bin, X+1).
+matched_out_size(Config) when is_list(Config) ->
+ {253,16#DEADBEEF} = mos_int(<<8,253,16#DEADBEEF:32>>),
+ {6,16#BEEFDEAD} = mos_int(<<3,6:3,16#BEEFDEAD:32>>),
+ {53,16#CAFEDEADBEEFCAFE} = mos_int(<<16,53:16,16#CAFEDEADBEEFCAFE:64>>),
+ {23,16#CAFEDEADBEEFCAFE} = mos_int(<<5,23:5,16#CAFEDEADBEEFCAFE:64>>),
+
+ {<<1,2,3>>,4} = mos_bin(<<3,1,2,3,4,3>>),
+ {<<1,2,3,7>>,19,42} = mos_bin(<<4,1,2,3,7,19,4,42>>),
+ <<1,2,3,7>> = mos_bin(<<4,1,2,3,7,"abcdefghij">>),
+
+ ok.
+
+mos_int(<<L,I:L,X:32>>) ->
+ {I,X};
+mos_int(<<L,I:L,X:64>>) ->
+ {I,X}.
+
+mos_bin(<<L,Bin:L/binary,X:8,L>>) ->
+ L = byte_size(Bin),
+ {Bin,X};
+mos_bin(<<L,Bin:L/binary,X:8,L,Y:8>>) ->
+ L = byte_size(Bin),
+ {Bin,X,Y};
+mos_bin(<<L,Bin:L/binary,"abcdefghij">>) ->
+ L = byte_size(Bin),
+ Bin.
+
+follow_fail_branch(_) ->
+ 42 = ffb_1(<<0,1>>, <<0>>),
+ 8 = ffb_1(<<0,1>>, [a]),
+ 42 = ffb_2(<<0,1>>, <<0>>, 17),
+ 8 = ffb_2(<<0,1>>, [a], 0),
+ ok.
+
+ffb_1(<<_,T/bitstring>>, List) ->
+ case List of
+ <<_>> ->
+ 42;
+ [_|_] ->
+ %% The fail branch of the bs_start_match2 instruction
+ %% pointing to here would be ignored, making the compiler
+ %% incorrectly assume that the delayed sub-binary
+ %% optimization was safe.
+ bit_size(T)
+ end.
+
+ffb_2(<<_,T/bitstring>>, List, A) ->
+ case List of
+ <<_>> when A =:= 17 -> 42;
+ [_|_] -> bit_size(T)
+ end.
+
+
check(F, R) ->
R = F().
diff --git a/lib/compiler/test/compilation_SUITE.erl b/lib/compiler/test/compilation_SUITE.erl
index fed7bec7d4..f8f74e6f7a 100644
--- a/lib/compiler/test/compilation_SUITE.erl
+++ b/lib/compiler/test/compilation_SUITE.erl
@@ -28,26 +28,29 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [self_compile_old_inliner, self_compile, compiler_1,
- compiler_3, compiler_5, beam_compiler_1,
- beam_compiler_2, beam_compiler_3, beam_compiler_4,
- beam_compiler_5, beam_compiler_6, beam_compiler_7,
- beam_compiler_8, beam_compiler_9, beam_compiler_10,
- beam_compiler_11, beam_compiler_12,
- nested_tuples_in_case_expr, otp_2330, guards,
- {group, vsn}, otp_2380, otp_2141, otp_2173, otp_4790,
- const_list_256, bin_syntax_1, bin_syntax_2,
- bin_syntax_3, bin_syntax_4, bin_syntax_5, bin_syntax_6,
- live_var, convopts, bad_functional_value,
- catch_in_catch, redundant_case, long_string, otp_5076,
- complex_guard, otp_5092, otp_5151, otp_5235, otp_5244,
- trycatch_4, opt_crash, otp_5404, otp_5436, otp_5481,
- otp_5553, otp_5632, otp_5714, otp_5872, otp_6121,
- otp_6121a, otp_6121b, otp_7202, otp_7345, on_load,
- string_table,otp_8949_a,otp_8949_a,split_cases].
+ [self_compile_old_inliner,self_compile,
+ {group,p}].
groups() ->
- [{vsn, [], [vsn_1, vsn_2, vsn_3]}].
+ [{vsn,[parallel],[vsn_1,vsn_2,vsn_3]},
+ {p,test_lib:parallel(),
+ [compiler_1,
+ compiler_3,compiler_5,beam_compiler_1,
+ beam_compiler_2,beam_compiler_3,beam_compiler_4,
+ beam_compiler_5,beam_compiler_6,beam_compiler_7,
+ beam_compiler_8,beam_compiler_9,beam_compiler_10,
+ beam_compiler_11,beam_compiler_12,
+ nested_tuples_in_case_expr,otp_2330,guards,
+ {group,vsn},otp_2380,otp_2141,otp_2173,otp_4790,
+ const_list_256,bin_syntax_1,bin_syntax_2,
+ bin_syntax_3,bin_syntax_4,bin_syntax_5,bin_syntax_6,
+ live_var,convopts,
+ catch_in_catch,redundant_case,long_string,otp_5076,
+ complex_guard,otp_5092,otp_5151,otp_5235,otp_5244,
+ trycatch_4,opt_crash,otp_5404,otp_5436,otp_5481,
+ otp_5553,otp_5632,otp_5714,otp_5872,otp_6121,
+ otp_6121a,otp_6121b,otp_7202,otp_7345,on_load,
+ string_table,otp_8949_a,otp_8949_a,split_cases]}].
init_per_suite(Config) ->
Config.
@@ -140,7 +143,6 @@ split({int, N}, <<N:16,B:N/binary,T/binary>>) ->
?comp(live_var).
?comp(trycatch_4).
-?comp(bad_functional_value).
?comp(catch_in_catch).
@@ -623,7 +625,7 @@ string_table(Config) when is_list(Config) ->
?line File = filename:join(DataDir, "string_table.erl"),
?line {ok,string_table,Beam,[]} = compile:file(File, [return, binary]),
?line {ok,{string_table,[StringTableChunk]}} = beam_lib:chunks(Beam, ["StrT"]),
- ?line {"StrT", <<"stringabletringtable">>} = StringTableChunk,
+ ?line {"StrT", <<"stringtable">>} = StringTableChunk,
ok.
otp_8949_a(Config) when is_list(Config) ->
diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl
index 2cd75944f4..229e5a98a1 100644
--- a/lib/compiler/test/compile_SUITE.erl
+++ b/lib/compiler/test/compile_SUITE.erl
@@ -27,7 +27,7 @@
app_test/1,
file_1/1, forms_2/1, module_mismatch/1, big_file/1, outdir/1,
binary/1, makedep/1, cond_and_ifdef/1, listings/1, listings_big/1,
- other_output/1, package_forms/1, encrypted_abstr/1,
+ other_output/1, encrypted_abstr/1,
bad_record_use1/1, bad_record_use2/1, strict_record/1,
missing_testheap/1, cover/1, env/1, core/1, asm/1,
sys_pre_attributes/1]).
@@ -44,7 +44,7 @@ all() ->
test_lib:recompile(?MODULE),
[app_test, file_1, forms_2, module_mismatch, big_file, outdir,
binary, makedep, cond_and_ifdef, listings, listings_big,
- other_output, package_forms, encrypted_abstr,
+ other_output, encrypted_abstr,
{group, bad_record_use}, strict_record,
missing_testheap, cover, env, core, asm,
sys_pre_attributes].
@@ -410,32 +410,6 @@ other_output(Config) when is_list(Config) ->
?line test_server:timetrap_cancel(Dog),
ok.
-package_forms(Config) when is_list(Config) ->
- Fs = [{attribute,1,file,{"./p.erl",1}},
- {attribute,1,module,[p,p]},
- {attribute,3,compile,export_all},
- {attribute,1,file,
- {"/clearcase/otp/erts/lib/stdlib/include/qlc.hrl",1}},
- {attribute,6,file,{"./p.erl",6}},
- {function,7,q,0,
- [{clause,7,[],[],
- [{call,8,
- {remote,8,{atom,8,qlc},{atom,8,q}},
- [{tuple,-8,
- [{atom,-8,qlc_lc},
- {'fun',-8,
- {clauses,
- [{clause,-8,[],[],
- [{tuple,-8,
- [{atom,-8,simple_v1},
- {atom,-8,'X'},
- {'fun',-8,{clauses,[{clause,-8,[],[],[{nil,8}]}]}},
- {integer,-8,8}]}]}]}},
- {atom,-8,undefined}]}]}]}]},
- {eof,9}],
- {ok,'p.p',_} = compile:forms(Fs, ['S',report]),
- ok.
-
encrypted_abstr(Config) when is_list(Config) ->
?line Dog = test_server:timetrap(test_server:minutes(10)),
?line {Simple,Target} = files(Config, "encrypted_abstr"),
diff --git a/lib/compiler/test/core_SUITE.erl b/lib/compiler/test/core_SUITE.erl
index 06185bfc34..a40dc32d59 100644
--- a/lib/compiler/test/core_SUITE.erl
+++ b/lib/compiler/test/core_SUITE.erl
@@ -43,11 +43,13 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [dehydrated_itracer,nested_tries,seq_in_guard,make_effect_seq,
- eval_is_boolean,unsafe_case,nomatch_shadow,reversed_annos].
+ [{group,p}].
groups() ->
- [].
+ [{p,test_lib:parallel(),
+ [dehydrated_itracer,nested_tries,seq_in_guard,make_effect_seq,
+ eval_is_boolean,unsafe_case,nomatch_shadow,reversed_annos]}].
+
init_per_suite(Config) ->
Config.
diff --git a/lib/compiler/test/core_fold_SUITE.erl b/lib/compiler/test/core_fold_SUITE.erl
index 54bd52947e..2adc71c237 100644
--- a/lib/compiler/test/core_fold_SUITE.erl
+++ b/lib/compiler/test/core_fold_SUITE.erl
@@ -31,11 +31,13 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [t_element, setelement, t_length, append, t_apply, bifs,
- eq, nested_call_in_case, guard_try_catch, coverage].
+ [{group,p}].
groups() ->
- [].
+ [{p,test_lib:parallel(),
+ [t_element,setelement,t_length,append,t_apply,bifs,
+ eq,nested_call_in_case,guard_try_catch,coverage]}].
+
init_per_suite(Config) ->
Config.
diff --git a/lib/compiler/test/error_SUITE.erl b/lib/compiler/test/error_SUITE.erl
index fb51e013ce..859c4571ea 100644
--- a/lib/compiler/test/error_SUITE.erl
+++ b/lib/compiler/test/error_SUITE.erl
@@ -22,16 +22,21 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
- head_mismatch_line/1,warnings_as_errors/1, bif_clashes/1]).
+ head_mismatch_line/1,warnings_as_errors/1, bif_clashes/1,
+ transforms/1]).
+
+%% Used by transforms/1 test case.
+-export([parse_transform/2]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [head_mismatch_line, warnings_as_errors, bif_clashes].
+ [{group,p}].
groups() ->
- [].
+ [{p,test_lib:parallel(),
+ [head_mismatch_line,warnings_as_errors,bif_clashes,transforms]}].
init_per_suite(Config) ->
Config.
@@ -216,6 +221,24 @@ warnings_as_errors(Config) when is_list(Config) ->
ok.
+transforms(Config) ->
+ Ts1 = [{undef_parse_transform,
+ <<"
+ -compile({parse_transform,non_existing}).
+ ">>,
+ [return],
+ {error,[{none,compile,{undef_parse_transform,non_existing}}],[]}}],
+ [] = run(Config, Ts1),
+ Ts2 = <<"
+ -compile({parse_transform,",?MODULE_STRING,"}).
+ ">>,
+ {error,[{none,compile,{parse_transform,?MODULE,{too_bad,_}}}],[]} =
+ run_test(Ts2, test_filename(Config), [], dont_write_beam),
+ ok.
+
+parse_transform(_, _) ->
+ error(too_bad).
+
run(Config, Tests) ->
?line File = test_filename(Config),
@@ -260,12 +283,14 @@ filter(X) ->
%% Compiles a test module and returns the list of errors and warnings.
test_filename(Conf) ->
- Filename = "errors_test.erl",
+ Filename = ["errors_test_",test_lib:uniq(),".erl"],
DataDir = ?config(priv_dir, Conf),
filename:join(DataDir, Filename).
run_test(Test0, File, Warnings, WriteBeam) ->
- ?line Test = ["-module(errors_test). ", Test0],
+ ModName = filename:rootname(filename:basename(File), ".erl"),
+ Mod = list_to_atom(ModName),
+ Test = ["-module(",ModName,"). ",Test0],
?line Opts = case WriteBeam of
dont_write_beam ->
[binary,return_errors|Warnings];
@@ -279,17 +304,17 @@ run_test(Test0, File, Warnings, WriteBeam) ->
%% Test result of compilation.
?line Res = case compile:file(File, Opts) of
- {ok,errors_test,_,[{_File,Ws}]} ->
+ {ok,Mod,_,[{_File,Ws}]} ->
%io:format("compile:file(~s,~p) ->~n~p~n",
% [File,Opts,Ws]),
{warning,Ws};
- {ok,errors_test,_,[]} ->
+ {ok,Mod,_,[]} ->
%io:format("compile:file(~s,~p) ->~n~p~n",
% [File,Opts,Ws]),
[];
- {ok,errors_test,[{_File,Ws}]} ->
+ {ok,Mod,[{_File,Ws}]} ->
{warning,Ws};
- {ok,errors_test,[]} ->
+ {ok,Mod,[]} ->
[];
{error,[{XFile,Es}],Ws} = _ZZ when is_list(XFile) ->
%io:format("compile:file(~s,~p) ->~n~p~n",
diff --git a/lib/compiler/test/guard_SUITE.erl b/lib/compiler/test/guard_SUITE.erl
index 40711783ed..66c0b9a295 100644
--- a/lib/compiler/test/guard_SUITE.erl
+++ b/lib/compiler/test/guard_SUITE.erl
@@ -39,17 +39,18 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [misc, const_cond, basic_not, complex_not, nested_nots,
- semicolon, complex_semicolon, comma, or_guard,
- more_or_guards, complex_or_guards, and_guard, xor_guard,
- more_xor_guards, build_in_guard, old_guard_tests, gbif,
- t_is_boolean, is_function_2, tricky, rel_ops,
- literal_type_tests, basic_andalso_orelse, traverse_dcd,
- check_qlc_hrl, andalso_semi, t_tuple_size, binary_part,
- bad_constants].
+ [{group,p}].
groups() ->
- [].
+ [{p,test_lib:parallel(),
+ [misc,const_cond,basic_not,complex_not,nested_nots,
+ semicolon,complex_semicolon,comma,or_guard,
+ more_or_guards,complex_or_guards,and_guard,xor_guard,
+ more_xor_guards,build_in_guard,old_guard_tests,gbif,
+ t_is_boolean,is_function_2,tricky,rel_ops,
+ literal_type_tests,basic_andalso_orelse,traverse_dcd,
+ check_qlc_hrl,andalso_semi,t_tuple_size,binary_part,
+ bad_constants]}].
init_per_suite(Config) ->
Config.
diff --git a/lib/compiler/test/inline_SUITE.erl b/lib/compiler/test/inline_SUITE.erl
index 2e17d3fde6..6dc7548437 100644
--- a/lib/compiler/test/inline_SUITE.erl
+++ b/lib/compiler/test/inline_SUITE.erl
@@ -32,17 +32,22 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [attribute, bsdecode, bsdes, barnes2, decode1, smith,
- itracer, pseudoknot, comma_splitter, lists, really_inlined, otp_7223,
- coverage].
+ [{group,p}].
groups() ->
- [].
+ [{p,test_lib:parallel(),
+ [attribute,bsdecode,bsdes,barnes2,decode1,smith,
+ itracer,pseudoknot,comma_splitter,lists,really_inlined,otp_7223,
+ coverage]}].
init_per_suite(Config) ->
- Config.
+ Pa = "-pa " ++ filename:dirname(code:which(?MODULE)),
+ {ok,Node} = start_node(compiler, Pa),
+ [{testing_node,Node}|Config].
-end_per_suite(_Config) ->
+end_per_suite(Config) ->
+ Node = ?config(testing_node, Config),
+ ?t:stop_node(Node),
ok.
init_per_group(_GroupName, Config) ->
@@ -81,6 +86,7 @@ attribute(Config) when is_list(Config) ->
?comp(comma_splitter).
try_inline(Mod, Config) ->
+ Node = ?config(testing_node, Config),
?line Src = filename:join(?config(data_dir, Config), atom_to_list(Mod)),
?line Out = ?config(priv_dir,Config),
@@ -89,8 +95,6 @@ try_inline(Mod, Config) ->
?line {ok,Mod} = compile:file(Src, [{outdir,Out},report,bin_opt_info,clint]),
?line Dog = test_server:timetrap(test_server:minutes(10)),
- ?line Pa = "-pa " ++ filename:dirname(code:which(?MODULE)),
- ?line {ok,Node} = start_node(compiler, Pa),
?line NormalResult = rpc:call(Node, ?MODULE, load_and_call, [Out,Mod]),
?line test_server:timetrap_cancel(Dog),
@@ -125,7 +129,6 @@ try_inline(Mod, Config) ->
%% Delete Beam file.
?line ok = file:delete(filename:join(Out, atom_to_list(Mod)++code:objfile_extension())),
- ?line ?t:stop_node(Node),
ok.
compare(Same, Same) -> ok;
@@ -255,6 +258,49 @@ lists(Config) when is_list(Config) ->
%% Cleanup.
erase(?MODULE),
+
+ {'EXIT',{function_clause,[{?MODULE,_,[_,not_a_list],_}|_]}} =
+ (catch lists:map(fun (X) -> X end, not_a_list)),
+ {'EXIT',{function_clause,[{?MODULE,_,[_,not_a_list],_}|_]}} =
+ (catch lists:flatmap(fun (X) -> X end, not_a_list)),
+ {'EXIT',{function_clause,[{?MODULE,_,[_,not_a_list],_}|_]}} =
+ (catch lists:foreach(fun (X) -> X end, not_a_list)),
+ {'EXIT',{function_clause,[{?MODULE,_,[_,not_a_list],_}|_]}} =
+ (catch lists:filter(fun (_) -> true end, not_a_list)),
+ {'EXIT',{function_clause,[{?MODULE,_,[_,not_a_list],_}|_]}} =
+ (catch lists:any(fun (_) -> false end, not_a_list)),
+ {'EXIT',{function_clause,[{?MODULE,_,[_,not_a_list],_}|_]}} =
+ (catch lists:all(fun (_) -> true end, not_a_list)),
+ {'EXIT',{function_clause,[{?MODULE,_,[_,acc,not_a_list],_}|_]}} =
+ (catch lists:foldl(fun (X, Acc) -> {X,Acc} end, acc, not_a_list)),
+ {'EXIT',{function_clause,[{?MODULE,_,[_,acc,not_a_list],_}|_]}} =
+ (catch lists:foldr(fun (X, Acc) -> {X,Acc} end, acc, not_a_list)),
+ {'EXIT',{function_clause,[{?MODULE,_,[_,acc,not_a_list],_}|_]}} =
+ (catch lists:mapfoldl(fun (X, Acc) -> {X,Acc} end, acc, not_a_list)),
+ {'EXIT',{function_clause,[{?MODULE,_,[_,acc,not_a_list],_}|_]}} =
+ (catch lists:mapfoldr(fun (X, Acc) -> {X,Acc} end, acc, not_a_list)),
+
+ {'EXIT',{function_clause,[{?MODULE,_,[not_a_function,[]],_}|_]}} =
+ (catch lists:map(not_a_function, [])),
+ {'EXIT',{function_clause,[{?MODULE,_,[not_a_function,[]],_}|_]}} =
+ (catch lists:flatmap(not_a_function, [])),
+ {'EXIT',{function_clause,[{?MODULE,_,[not_a_function,[]],_}|_]}} =
+ (catch lists:foreach(not_a_function, [])),
+ {'EXIT',{function_clause,[{?MODULE,_,[not_a_function,[]],_}|_]}} =
+ (catch lists:filter(not_a_function, [])),
+ {'EXIT',{function_clause,[{?MODULE,_,[not_a_function,[]],_}|_]}} =
+ (catch lists:any(not_a_function, [])),
+ {'EXIT',{function_clause,[{?MODULE,_,[not_a_function,[]],_}|_]}} =
+ (catch lists:all(not_a_function, [])),
+ {'EXIT',{function_clause,[{?MODULE,_,[not_a_function,acc,[]],_}|_]}} =
+ (catch lists:foldl(not_a_function, acc, [])),
+ {'EXIT',{function_clause,[{?MODULE,_,[not_a_function,acc,[]],_}|_]}} =
+ (catch lists:foldr(not_a_function, acc, [])),
+ {'EXIT',{function_clause,[{?MODULE,_,[not_a_function,acc,[]],_}|_]}} =
+ (catch lists:mapfoldl(not_a_function, acc, [])),
+ {'EXIT',{function_clause,[{?MODULE,_,[not_a_function,acc,[]],_}|_]}} =
+ (catch lists:mapfoldr(not_a_function, acc, [])),
+
ok.
my_apply(M, F, A, Init) ->
@@ -293,9 +339,9 @@ otp_7223_2({a}) ->
1.
coverage(Config) when is_list(Config) ->
- ?line Src = filename:join(?config(data_dir, Config), bsdecode),
- ?line Out = ?config(priv_dir,Config),
- ?line {ok,Mod} = compile:file(Src, [{outdir,Out},report,{inline,0},clint]),
- ?line {ok,Mod} = compile:file(Src, [{outdir,Out},report,{inline,20},verbose,clint]),
- ?line ok = file:delete(filename:join(Out, "bsdecode"++code:objfile_extension())),
+ Mod = bsdecode,
+ Src = filename:join(?config(data_dir, Config), Mod),
+ {ok,Mod,_} = compile:file(Src, [binary,report,{inline,0},clint]),
+ {ok,Mod,_} = compile:file(Src, [binary,report,{inline,20},
+ verbose,clint]),
ok.
diff --git a/lib/compiler/test/match_SUITE.erl b/lib/compiler/test/match_SUITE.erl
index 9406d7de8f..de44926d81 100644
--- a/lib/compiler/test/match_SUITE.erl
+++ b/lib/compiler/test/match_SUITE.erl
@@ -30,11 +30,13 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [pmatch, mixed, aliases, match_in_call, untuplify,
- shortcut_boolean, letify_guard, selectify, underscore, coverage].
+ [{group,p}].
groups() ->
- [].
+ [{p,test_lib:parallel(),
+ [pmatch,mixed,aliases,match_in_call,untuplify,
+ shortcut_boolean,letify_guard,selectify,underscore,coverage]}].
+
init_per_suite(Config) ->
Config.
diff --git a/lib/compiler/test/misc_SUITE.erl b/lib/compiler/test/misc_SUITE.erl
index 0376c7ef3e..44c7161530 100644
--- a/lib/compiler/test/misc_SUITE.erl
+++ b/lib/compiler/test/misc_SUITE.erl
@@ -57,11 +57,12 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
-spec all() -> misc_SUITE_test_cases().
all() ->
test_lib:recompile(?MODULE),
- [tobias, empty_string, md5, silly_coverage,
- confused_literals, integer_encoding, override_bif].
+ [{group,p}].
groups() ->
- [].
+ [{p,[],%%test_lib:parallel(),
+ [tobias,empty_string,md5,silly_coverage,
+ confused_literals,integer_encoding,override_bif]}].
init_per_suite(Config) ->
Config.
@@ -182,6 +183,14 @@ silly_coverage(Config) when is_list(Config) ->
CodegenInput = {?MODULE,[{foo,0}],[],[{function,foo,0,[a|b],a,b,[]}]},
?line expect_error(fun() -> v3_codegen:module(CodegenInput, []) end),
+ %% beam_a
+ BeamAInput = {?MODULE,[{foo,0}],[],
+ [{function,foo,0,2,
+ [{label,1},
+ {func_info,{atom,?MODULE},{atom,foo},0},
+ {label,2}|non_proper_list]}],99},
+ expect_error(fun() -> beam_a:module(BeamAInput, []) end),
+
%% beam_block
BlockInput = {?MODULE,[{foo,0}],[],
[{function,foo,0,2,
@@ -263,6 +272,13 @@ silly_coverage(Config) when is_list(Config) ->
{block,[a|b]}]}],0},
?line expect_error(fun() -> beam_receive:module(ReceiveInput, []) end),
+ BeamZInput = {?MODULE,[{foo,0}],[],
+ [{function,foo,0,2,
+ [{label,1},
+ {func_info,{atom,?MODULE},{atom,foo},0},
+ {label,2}|non_proper_list]}],99},
+ expect_error(fun() -> beam_z:module(BeamZInput, []) end),
+
ok.
expect_error(Fun) ->
diff --git a/lib/compiler/test/pmod_SUITE.erl b/lib/compiler/test/pmod_SUITE.erl
deleted file mode 100644
index 5dd09a7245..0000000000
--- a/lib/compiler/test/pmod_SUITE.erl
+++ /dev/null
@@ -1,121 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
--module(pmod_SUITE).
-
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2,
- init_per_testcase/2,end_per_testcase/2,
- basic/1, otp_8447/1]).
-
--include_lib("test_server/include/test_server.hrl").
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- test_lib:recompile(?MODULE),
- [basic, otp_8447].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
- Dog = test_server:timetrap(?t:minutes(1)),
- [{watchdog,Dog}|Config].
-
-end_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
- Dog = ?config(watchdog, Config),
- ?t:timetrap_cancel(Dog),
- ok.
-
-basic(Config) when is_list(Config) ->
- ?line basic_1(Config, []),
- ?line basic_1(Config, [inline]),
- ?line basic_1(Config, [{inline,500},inline]),
- ok.
-
-basic_1(Config, Opts) ->
- io:format("Options: ~p\n", [Opts]),
- ?line ok = compile_load(pmod_basic, Config, Opts),
-
- ?line Prop1 = pmod_basic:new([{a,xb},{b,true},{c,false}]),
- ?line Prop2 = pmod_basic:new([{y,zz}]),
- ?line io:format("Prop1 = ~p\n", [Prop1]),
- ?line io:format("Prop2 = ~p\n", [Prop2]),
-
- ?line {a,xb} = Prop1:lookup(a),
- ?line none = Prop1:lookup(glurf),
- ?line false = Prop1:or_props([]),
- ?line true = Prop1:or_props([b,c]),
- ?line true = Prop1:or_props([b,d]),
- ?line false = Prop1:or_props([d]),
-
- ?line none = Prop2:lookup(kalle),
- ?line {y,zz} = Prop2:lookup(y),
- ?line {a,xb} = Prop1:lookup(a),
-
- ?line Prop3 = Prop1:prepend({blurf,true}),
- ?line io:format("Prop3 = ~p\n", [Prop3]),
- ?line {blurf,true} = Prop3:lookup(blurf),
-
- Prop4 = Prop3:append(42),
- ?line io:format("Prop4 = ~p\n", [Prop4]),
- ?line {42,5} = Prop4:stupid_sum(),
-
- %% Some record guards.
- ?line ok = Prop4:bar({s,0}),
- ?line ok = Prop4:bar_bar({s,blurf}),
- ?line error = Prop4:bar_bar({s,a,b}),
- ?line error = Prop4:bar_bar([]),
-
- %% Call from a fun.
- Fun = fun(Arg) -> Prop4:bar(Arg) end,
- ?line ok = Fun({s,0}),
-
- [{y,[1,2]},{x,[5,19]}] = Prop4:collapse([{y,[2,1]},{x,[19,5]}]),
- ok.
-
-otp_8447(Config) when is_list(Config) ->
- ?line P = pmod_basic:new(foo),
- ?line [0,0,1,1,1,0,0,1] = P:bc1(),
- ?line <<10:4>> = P:bc2(),
- ok.
-
-compile_load(Module, Conf, Opts) ->
- ?line Dir = ?config(data_dir,Conf),
- ?line Src = filename:join(Dir, atom_to_list(Module)),
- ?line Out = ?config(priv_dir,Conf),
- ?line CompRc = compile:file(Src, [report,{outdir,Out}|Opts]),
- ?line {ok,Module} = CompRc,
- ?line code:purge(Module),
- ?line {module,Module} =
- code:load_abs(filename:join(Out, atom_to_list(Module))),
- ok.
diff --git a/lib/compiler/test/pmod_SUITE_data/pmod_basic.erl b/lib/compiler/test/pmod_SUITE_data/pmod_basic.erl
deleted file mode 100644
index 19cce452dc..0000000000
--- a/lib/compiler/test/pmod_SUITE_data/pmod_basic.erl
+++ /dev/null
@@ -1,83 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
--module(pmod_basic, [Props]).
-
--export([lookup/1,or_props/1,prepend/1,append/1,stupid_sum/0]).
--export([bar/1,bar_bar/1]).
--export([bc1/0, bc2/0]).
--export([collapse/1]).
-
-lookup(Key) ->
- proplists:lookup(Key, Props).
-
-or_props(Keys) ->
- Res = or_props_1(Keys, false),
- true = is_bool(Res), %is_bool/1 does not use Props.
- Res.
-
-prepend(Term) ->
- new([Term|Props]).
-
-append(Term) ->
- pmod_basic:new(Props++[Term]).
-
-or_props_1([K|Ks], Acc) ->
- or_props_1(Ks, proplists:get_bool(K, Props) or Acc);
-or_props_1([], Acc) -> Acc.
-
-is_bool(true) -> true;
-is_bool(false) -> true;
-is_bool(_) -> false.
-
-stupid_sum() ->
- put(counter, 0),
- Res = stupid_sum_1(Props, 0),
- {Res,get(counter)}.
-
-stupid_sum_1([H|T], Sum0) ->
- try add(Sum0, H) of
- Sum -> stupid_sum_1(T, Sum)
- catch
- error:_ -> stupid_sum_1(T, Sum0)
- after
- bump()
- end;
-stupid_sum_1([], Sum) -> Sum.
-
-bump() ->
- put(counter, get(counter)+1).
-
-add(A, B) ->
- A+B.
-
--record(s, {a}).
-
-bar(S) when S#s.a == 0 -> ok.
-
-bar_bar(S) when is_record(S, s) -> ok;
-bar_bar(_) -> error.
-
-bc1() ->
- [A || <<A:1>> <= <<"9">> ].
-
-bc2() ->
- << <<A:1>> || A <- [1,0,1,0] >>.
-
-collapse(L) ->
- lists:keymap(fun lists:sort/1, 2, L).
diff --git a/lib/compiler/test/receive_SUITE.erl b/lib/compiler/test/receive_SUITE.erl
index 2a67615e5e..82c823b789 100644
--- a/lib/compiler/test/receive_SUITE.erl
+++ b/lib/compiler/test/receive_SUITE.erl
@@ -40,10 +40,12 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [recv, coverage, otp_7980, ref_opt, export].
+ [{group,p}].
groups() ->
- [].
+ [{p,test_lib:parallel(),
+ [recv,coverage,otp_7980,ref_opt,export]}].
+
init_per_suite(Config) ->
Config.
diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/no_4.erl b/lib/compiler/test/receive_SUITE_data/ref_opt/no_4.erl
new file mode 100644
index 0000000000..3ce222176b
--- /dev/null
+++ b/lib/compiler/test/receive_SUITE_data/ref_opt/no_4.erl
@@ -0,0 +1,12 @@
+-module(no_4).
+-compile(export_all).
+
+?MODULE() ->
+ ok.
+
+f(X) ->
+ {Pid,Ref} = spawn_monitor(fun() -> ok end),
+ r(Pid, Ref).
+
+r(_, _) ->
+ ok.
diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_10.erl b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_10.erl
new file mode 100644
index 0000000000..7ce6e6103c
--- /dev/null
+++ b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_10.erl
@@ -0,0 +1,13 @@
+-module(yes_10).
+-compile(export_all).
+
+?MODULE() ->
+ ok.
+
+f() ->
+ Ref = make_ref(),
+ receive
+ %% Artifical example to cover more code in beam_receive.
+ {X,Y} when Ref =/= X, Ref =:= Y ->
+ ok
+ end.
diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_11.erl b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_11.erl
new file mode 100644
index 0000000000..62f439fc42
--- /dev/null
+++ b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_11.erl
@@ -0,0 +1,21 @@
+-module(yes_11).
+-compile(export_all).
+
+?MODULE() ->
+ ok.
+
+%% Artifical example to cover more code in beam_receive.
+do_call(Process, Request) ->
+ Mref = erlang:monitor(process, Process),
+ Process ! Request,
+ receive
+ {X,Y,Z} when Mref =/= X, Z =:= 42, Mref =:= Y ->
+ error;
+ {X,Y,_} when Mref =/= X, Mref =:= Y ->
+ error;
+ {Mref, Reply} ->
+ erlang:demonitor(Mref, [flush]),
+ {ok, Reply};
+ {'DOWN', Mref, _, _, _} ->
+ error
+ end.
diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_12.erl b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_12.erl
new file mode 100644
index 0000000000..efcfed6059
--- /dev/null
+++ b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_12.erl
@@ -0,0 +1,12 @@
+-module(yes_12).
+-compile(export_all).
+
+?MODULE() ->
+ ok.
+
+f() ->
+ {_,Ref} = spawn_monitor(fun() -> ok end),
+ receive
+ {'DOWN',Ref,_,_,Reason} ->
+ Reason
+ end.
diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_13.erl b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_13.erl
new file mode 100644
index 0000000000..9e93d12ed6
--- /dev/null
+++ b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_13.erl
@@ -0,0 +1,12 @@
+-module(yes_13).
+-compile(export_all).
+
+?MODULE() ->
+ ok.
+
+f() ->
+ {Pid,Ref} = spawn_monitor(fun() -> ok end),
+ receive
+ {'DOWN',Ref,process,Pid,Reason} ->
+ Reason
+ end.
diff --git a/lib/compiler/test/record_SUITE.erl b/lib/compiler/test/record_SUITE.erl
index 363422ec7e..96f3712be9 100644
--- a/lib/compiler/test/record_SUITE.erl
+++ b/lib/compiler/test/record_SUITE.erl
@@ -42,12 +42,14 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [errors, record_test_2, record_test_3,
- record_access_in_guards, guard_opt, eval_once, foobar,
- missing_test_heap, nested_access, coverage].
+ [{group,p}].
groups() ->
- [].
+ [{p,test_lib:parallel(),
+ [errors,record_test_2,record_test_3,
+ record_access_in_guards,guard_opt,eval_once,foobar,
+ missing_test_heap,nested_access,coverage]}].
+
init_per_suite(Config) ->
Config.
diff --git a/lib/compiler/test/test_lib.erl b/lib/compiler/test/test_lib.erl
index 2295592a38..996c369705 100644
--- a/lib/compiler/test/test_lib.erl
+++ b/lib/compiler/test/test_lib.erl
@@ -20,7 +20,8 @@
-include("test_server.hrl").
-compile({no_auto_import,[binary_part/2]}).
--export([recompile/1,opt_opts/1,get_data_dir/1,smoke_disasm/1,p_run/2,binary_part/2]).
+-export([recompile/1,parallel/0,uniq/0,opt_opts/1,get_data_dir/1,
+ smoke_disasm/1,p_run/2,binary_part/2]).
recompile(Mod) when is_atom(Mod) ->
case whereis(cover_server) of
@@ -43,6 +44,18 @@ smoke_disasm(File) when is_list(File) ->
Res = beam_disasm:file(File),
{beam_file,_Mod} = {element(1, Res),element(2, Res)}.
+parallel() ->
+ case ?t:is_cover() orelse erlang:system_info(schedulers) =:= 1 of
+ true -> [];
+ false -> [parallel]
+ end.
+
+uniq() ->
+ U0 = erlang:ref_to_list(make_ref()),
+ U1 = re:replace(U0, "^#Ref", ""),
+ U = re:replace(U1, "[^[A-Za-z0-9_]+", "_", [global]),
+ re:replace(U, "_*$", "", [{return,list}]).
+
%% Retrieve the "interesting" compiler options (options for optimization
%% and compatibility) for the given module.
diff --git a/lib/compiler/test/trycatch_SUITE.erl b/lib/compiler/test/trycatch_SUITE.erl
index 29119c0f5d..4530d08c77 100644
--- a/lib/compiler/test/trycatch_SUITE.erl
+++ b/lib/compiler/test/trycatch_SUITE.erl
@@ -32,13 +32,15 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [basic, lean_throw, try_of, try_after, catch_oops,
- after_oops, eclectic, rethrow, nested_of, nested_catch,
- nested_after, nested_horrid, last_call_optimization,
- bool, plain_catch_coverage, andalso_orelse, get_in_try].
+ [{group,p}].
groups() ->
- [].
+ [{p,test_lib:parallel(),
+ [basic,lean_throw,try_of,try_after,catch_oops,
+ after_oops,eclectic,rethrow,nested_of,nested_catch,
+ nested_after,nested_horrid,last_call_optimization,
+ bool,plain_catch_coverage,andalso_orelse,get_in_try]}].
+
init_per_suite(Config) ->
Config.
diff --git a/lib/compiler/test/warnings_SUITE.erl b/lib/compiler/test/warnings_SUITE.erl
index f6a572abfa..9ce0df5ec4 100644
--- a/lib/compiler/test/warnings_SUITE.erl
+++ b/lib/compiler/test/warnings_SUITE.erl
@@ -55,12 +55,13 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [pattern, pattern2, pattern3, pattern4, guard,
- bad_arith, bool_cases, bad_apply, files, effect,
- bin_opt_info, bin_construction].
+ [{group,p}].
groups() ->
- [].
+ [{p,test_lib:parallel(),
+ [pattern,pattern2,pattern3,pattern4,guard,
+ bad_arith,bool_cases,bad_apply,files,effect,
+ bin_opt_info,bin_construction]}].
init_per_suite(Config) ->
Config.
@@ -556,9 +557,10 @@ run(Config, Tests) ->
%% Compiles a test module and returns the list of errors and warnings.
run_test(Conf, Test0, Warnings) ->
- Filename = 'warnings_test.erl',
+ Mod = "warnings_"++test_lib:uniq(),
+ Filename = Mod ++ ".erl",
?line DataDir = ?privdir,
- ?line Test = ["-module(warnings_test). ", Test0],
+ Test = ["-module(", Mod, "). ", Test0],
?line File = filename:join(DataDir, Filename),
?line Opts = [binary,export_all,return|Warnings],
?line ok = file:write_file(File, Test),
diff --git a/lib/cosEvent/src/Makefile b/lib/cosEvent/src/Makefile
index 7787fad786..2864ee0538 100644
--- a/lib/cosEvent/src/Makefile
+++ b/lib/cosEvent/src/Makefile
@@ -168,9 +168,9 @@ clean:
rm -f errs core *~
$(APP_TARGET): $(APP_SRC)
- sed -e 's;%VSN%;$(VSN);' $(APP_SRC) > $(APP_TARGET)
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $(APP_SRC) > $(APP_TARGET)
$(APPUP_TARGET): $(APPUP_SRC)
- sed -e 's;%VSN%;$(VSN);' $(APPUP_SRC) > $(APPUP_TARGET)
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $(APPUP_SRC) > $(APPUP_TARGET)
docs:
@@ -179,12 +179,12 @@ docs:
# ----------------------------------------------------
IDL-GENERATED: CosEventChannelAdmin.idl cosEventApp.idl CosEventComm.idl
- erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosEventChannelAdmin.cfg"}' CosEventChannelAdmin.idl
- mv $(GEN_HRL_FILES1) $(EXTERNAL_INC_PATH)
- erlc $(ERL_IDL_FLAGS) +'{cfgfile,"cosEventApp.cfg"}' cosEventApp.idl
- erlc $(ERL_IDL_FLAGS) CosEventComm.idl
- mv $(GEN_HRL_FILES3) $(EXTERNAL_INC_PATH)
- >IDL-GENERATED
+ $(gen_verbose)erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosEventChannelAdmin.cfg"}' CosEventChannelAdmin.idl
+ $(V_at)mv $(GEN_HRL_FILES1) $(EXTERNAL_INC_PATH)
+ $(V_at)erlc $(ERL_IDL_FLAGS) +'{cfgfile,"cosEventApp.cfg"}' cosEventApp.idl
+ $(V_at)erlc $(ERL_IDL_FLAGS) CosEventComm.idl
+ $(V_at)mv $(GEN_HRL_FILES3) $(EXTERNAL_INC_PATH)
+ $(V_at)>IDL-GENERATED
$(GEN_FILES): IDL-GENERATED
diff --git a/lib/cosEventDomain/src/Makefile b/lib/cosEventDomain/src/Makefile
index 213d433c72..b4b74bd192 100644
--- a/lib/cosEventDomain/src/Makefile
+++ b/lib/cosEventDomain/src/Makefile
@@ -141,9 +141,9 @@ clean:
rm -f errs core *~
$(APP_TARGET): $(APP_SRC)
- sed -e 's;%VSN%;$(VSN);' $(APP_SRC) > $(APP_TARGET)
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $(APP_SRC) > $(APP_TARGET)
$(APPUP_TARGET): $(APPUP_SRC)
- sed -e 's;%VSN%;$(VSN);' $(APPUP_SRC) > $(APPUP_TARGET)
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $(APPUP_SRC) > $(APPUP_TARGET)
docs:
@@ -151,9 +151,9 @@ docs:
# Special Build Targets
# ----------------------------------------------------
IDL-GENERATED: CosEventDomainAdmin.idl
- erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosEventDomainAdmin.cfg"}' CosEventDomainAdmin.idl
- mv $(GEN_HRL_FILES) $(EXTERNAL_INC_PATH)
- >IDL-GENERATED
+ $(gen_verbose)erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosEventDomainAdmin.cfg"}' CosEventDomainAdmin.idl
+ $(V_at)mv $(GEN_HRL_FILES) $(EXTERNAL_INC_PATH)
+ $(V_at)>IDL-GENERATED
$(GEN_FILES): IDL-GENERATED
diff --git a/lib/cosFileTransfer/src/Makefile b/lib/cosFileTransfer/src/Makefile
index d552349ede..9d3abb9bba 100644
--- a/lib/cosFileTransfer/src/Makefile
+++ b/lib/cosFileTransfer/src/Makefile
@@ -151,10 +151,10 @@ clean:
rm -f errs core *~
$(APP_TARGET): $(APP_SRC)
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
docs:
@@ -162,9 +162,9 @@ docs:
# Special Build Targets
# ----------------------------------------------------
IDL-GENERATED: CosFileTransfer.idl
- erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosFileTransfer.cfg"}' CosFileTransfer.idl
- mv $(LOCAL_HRL_FILES) $(EXTERNAL_INC_PATH)
- >IDL-GENERATED
+ $(gen_verbose)erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosFileTransfer.cfg"}' CosFileTransfer.idl
+ $(V_at)mv $(LOCAL_HRL_FILES) $(EXTERNAL_INC_PATH)
+ $(V_at)>IDL-GENERATED
$(GEN_FILES): IDL-GENERATED
diff --git a/lib/cosNotification/src/Makefile b/lib/cosNotification/src/Makefile
index decf598bbf..13153bd7a1 100644
--- a/lib/cosNotification/src/Makefile
+++ b/lib/cosNotification/src/Makefile
@@ -332,10 +332,10 @@ clean:
rm -f errs core *~
$(APP_TARGET): $(APP_SRC)
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
docs:
@@ -344,16 +344,16 @@ docs:
# ----------------------------------------------------
IDL-GENERATED: CosNotification.idl CosNotifyChannelAdmin.idl \
CosNotifyFilter.idl cosNotificationAppComm.idl CosNotifyComm.idl
- erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosNotification.cfg"}' CosNotification.idl
- mv $(GEN_NOTIFICATION_HRL_FILES) $(EXTERNAL_INC_PATH)
- erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosNotifyChannelAdmin.cfg"}' CosNotifyChannelAdmin.idl
- mv $(GEN_CHANNELADMIN_HRL_FILES) $(EXTERNAL_INC_PATH)
- erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosNotifyFilter.cfg"}' CosNotifyFilter.idl
- mv $(GEN_NOTIFYFILTER_HRL_FILES) $(EXTERNAL_INC_PATH)
- erlc $(ERL_IDL_FLAGS) +'{cfgfile,"cosNotificationComm.cfg"}' cosNotificationAppComm.idl
- erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosNotifyComm.cfg"}' CosNotifyComm.idl
- mv $(GEN_NOTIFYCOMM_HRL_FILES) $(EXTERNAL_INC_PATH)
- >IDL-GENERATED
+ $(gen_verbose)erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosNotification.cfg"}' CosNotification.idl
+ $(V_at)mv $(GEN_NOTIFICATION_HRL_FILES) $(EXTERNAL_INC_PATH)
+ $(V_at)erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosNotifyChannelAdmin.cfg"}' CosNotifyChannelAdmin.idl
+ $(V_at)mv $(GEN_CHANNELADMIN_HRL_FILES) $(EXTERNAL_INC_PATH)
+ $(V_at)erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosNotifyFilter.cfg"}' CosNotifyFilter.idl
+ $(V_at)mv $(GEN_NOTIFYFILTER_HRL_FILES) $(EXTERNAL_INC_PATH)
+ $(V_at)erlc $(ERL_IDL_FLAGS) +'{cfgfile,"cosNotificationComm.cfg"}' cosNotificationAppComm.idl
+ $(V_at)erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosNotifyComm.cfg"}' CosNotifyComm.idl
+ $(V_at)mv $(GEN_NOTIFYCOMM_HRL_FILES) $(EXTERNAL_INC_PATH)
+ $(V_at)>IDL-GENERATED
$(IDL_GEN_ERL_FILES) $(IDL_GEN_HRL_FILES): IDL-GENERATED
diff --git a/lib/cosProperty/src/Makefile b/lib/cosProperty/src/Makefile
index 54d1b6021c..d7b75d8bc5 100644
--- a/lib/cosProperty/src/Makefile
+++ b/lib/cosProperty/src/Makefile
@@ -151,10 +151,10 @@ clean:
rm -f errs core *~
$(APP_TARGET): $(APP_SRC)
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
docs:
@@ -162,9 +162,9 @@ docs:
# Special Build Targets
# ----------------------------------------------------
IDL-GENERATED: CosProperty.idl
- erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosProperty.cfg"}' CosProperty.idl
- mv $(LOCAL_HRL_FILES) $(EXTERNAL_INC_PATH)
- >IDL-GENERATED
+ $(gen_verbose)erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosProperty.cfg"}' CosProperty.idl
+ $(V_at)mv $(LOCAL_HRL_FILES) $(EXTERNAL_INC_PATH)
+ $(V_at)>IDL-GENERATED
$(GEN_FILES): IDL-GENERATED
diff --git a/lib/cosTime/src/Makefile b/lib/cosTime/src/Makefile
index e8536a3f0a..0ab2b414ce 100644
--- a/lib/cosTime/src/Makefile
+++ b/lib/cosTime/src/Makefile
@@ -166,10 +166,10 @@ clean:
rm -f errs core *~
$(APP_TARGET): $(APP_SRC)
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
docs:
@@ -177,13 +177,13 @@ docs:
# Special Build Targets
# ----------------------------------------------------
IDL-GENERATED: TimeBase.idl CosTime.idl CosTimerEvent.idl
- erlc $(ERL_IDL_FLAGS) TimeBase.idl
- mv $(GEN_TIMEBASE_HRL_FILES) $(EXTERNAL_INC_PATH)
- erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosTime.cfg"}' CosTime.idl
- mv $(GEN_COSTIME_HRL_FILES) $(EXTERNAL_INC_PATH)
- erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosTimerEvent.cfg"}' CosTimerEvent.idl
- mv $(GEN_COSTIMEREVENT_HRL_FILES) $(EXTERNAL_INC_PATH)
- >IDL-GENERATED
+ $(gen_verbose)erlc $(ERL_IDL_FLAGS) TimeBase.idl
+ $(V_at)mv $(GEN_TIMEBASE_HRL_FILES) $(EXTERNAL_INC_PATH)
+ $(V_at)erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosTime.cfg"}' CosTime.idl
+ $(V_at)mv $(GEN_COSTIME_HRL_FILES) $(EXTERNAL_INC_PATH)
+ $(V_at)erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosTimerEvent.cfg"}' CosTimerEvent.idl
+ $(V_at)mv $(GEN_COSTIMEREVENT_HRL_FILES) $(EXTERNAL_INC_PATH)
+ $(V_at)>IDL-GENERATED
$(GEN_FILES): IDL-GENERATED
diff --git a/lib/cosTransactions/src/Makefile b/lib/cosTransactions/src/Makefile
index 1d935c4d1d..7b4a9cf858 100644
--- a/lib/cosTransactions/src/Makefile
+++ b/lib/cosTransactions/src/Makefile
@@ -145,10 +145,10 @@ clean:
rm -f errs core *~
$(APP_TARGET): $(APP_SRC)
- sed -e 's;%VSN%;$(VSN);' $(APP_SRC) > $(APP_TARGET)
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $(APP_SRC) > $(APP_TARGET)
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
docs:
@@ -156,9 +156,9 @@ docs:
# Special Build Targets
# ----------------------------------------------------
IDL-GENERATED: CosTransactions.idl
- erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosTransactions.cfg"}' CosTransactions.idl
- mv $(GEN_HRL_FILES) $(EXTERNAL_INC_PATH)
- >IDL-GENERATED
+ $(gen_verbose)erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosTransactions.cfg"}' CosTransactions.idl
+ $(V_at)mv $(GEN_HRL_FILES) $(EXTERNAL_INC_PATH)
+ $(V_at)>IDL-GENERATED
$(GEN_FILES): IDL-GENERATED
diff --git a/lib/crypto/c_src/Makefile.in b/lib/crypto/c_src/Makefile.in
index ffd556ca1a..a20ddff05c 100644
--- a/lib/crypto/c_src/Makefile.in
+++ b/lib/crypto/c_src/Makefile.in
@@ -59,8 +59,6 @@ TYPE_FLAGS = $(CFLAGS)
endif
endif
-ALL_CFLAGS = $(TYPE_FLAGS) $(INCLUDES)
-
# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
@@ -69,13 +67,16 @@ RELSYSDIR = $(RELEASE_PATH)/lib/crypto-$(VSN)
# ----------------------------------------------------
# Misc Macros
# ----------------------------------------------------
-OBJS = $(OBJDIR)/crypto$(TYPEMARKER).o
+CRYPTO_OBJS = $(OBJDIR)/crypto$(TYPEMARKER).o
+CALLBACK_OBJS = $(OBJDIR)/crypto_callback$(TYPEMARKER).o
NIF_MAKEFILE = $(PRIVDIR)/Makefile
ifeq ($(findstring win32,$(TARGET)), win32)
NIF_LIB = $(LIBDIR)/crypto$(TYPEMARKER).dll
+CALLBACK_LIB = $(LIBDIR)/crypto_callback$(TYPEMARKER).dll
else
NIF_LIB = $(LIBDIR)/crypto$(TYPEMARKER).so
+CALLBACK_LIB = $(LIBDIR)/crypto_callback$(TYPEMARKER).so
endif
ifeq ($(HOST_OS),)
@@ -86,43 +87,69 @@ DYNAMIC_CRYPTO_LIB=@SSL_DYNAMIC_ONLY@
ifeq ($(DYNAMIC_CRYPTO_LIB),yes)
SSL_DED_LD_RUNTIME_LIBRARY_PATH = @SSL_DED_LD_RUNTIME_LIBRARY_PATH@
CRYPTO_LINK_LIB=$(SSL_DED_LD_RUNTIME_LIBRARY_PATH) -L$(SSL_LIBDIR) -l$(SSL_CRYPTO_LIBNAME)
+EXTRA_FLAGS = -DHAVE_DYNAMIC_CRYPTO_LIB
else
SSL_DED_LD_RUNTIME_LIBRARY_PATH=
CRYPTO_LINK_LIB=$(SSL_LIBDIR)/lib$(SSL_CRYPTO_LIBNAME).a
+EXTRA_FLAGS =
+CRYPTO_OBJS := $(CRYPTO_OBJS) $(CALLBACK_OBJS)
+CALLBACK_OBJS =
+CALLBACK_LIB =
endif
+ALL_CFLAGS = $(TYPE_FLAGS) $(EXTRA_FLAGS) $(INCLUDES)
+
# ----------------------------------------------------
# Targets
# ----------------------------------------------------
_create_dirs := $(shell mkdir -p $(OBJDIR) $(LIBDIR))
-debug opt valgrind: $(NIF_LIB)
+debug opt valgrind: $(NIF_LIB) $(CALLBACK_LIB)
$(OBJDIR)/%$(TYPEMARKER).o: %.c
- $(INSTALL_DIR) $(OBJDIR)
- $(CC) -c -o $@ $(ALL_CFLAGS) $<
+ $(V_at)$(INSTALL_DIR) $(OBJDIR)
+ $(V_CC) -c -o $@ $(ALL_CFLAGS) $<
+
+$(LIBDIR)/crypto$(TYPEMARKER).so: $(CRYPTO_OBJS)
+ $(V_at)$(INSTALL_DIR) $(LIBDIR)
+ $(V_LD) $(LDFLAGS) -o $@ $^ $(LDLIBS) $(CRYPTO_LINK_LIB)
-$(LIBDIR)/crypto$(TYPEMARKER).so: $(OBJS)
- $(INSTALL_DIR) $(LIBDIR)
- $(LD) $(LDFLAGS) -o $@ $^ $(LDLIBS) $(CRYPTO_LINK_LIB)
+$(LIBDIR)/crypto$(TYPEMARKER).dll: $(CRYPTO_OBJS)
+ $(V_at)$(INSTALL_DIR) $(LIBDIR)
+ $(V_LD) $(LDFLAGS) -o $@ $(SSL_DED_LD_RUNTIME_LIBRARY_PATH) -L$(SSL_LIBDIR) $(CRYPTO_OBJS) -l$(SSL_CRYPTO_LIBNAME) -l$(SSL_SSL_LIBNAME)
+
+ifeq ($(DYNAMIC_CRYPTO_LIB),yes)
+$(LIBDIR)/crypto_callback$(TYPEMARKER).so: $(CALLBACK_OBJS)
+ $(INSTALL_DIR) $(LIBDIR)
+ $(LD) $(LDFLAGS) -o $@ $^ $(LDLIBS)
-$(LIBDIR)/crypto$(TYPEMARKER).dll: $(OBJS)
+$(LIBDIR)/crypto_callback$(TYPEMARKER).dll: $(CALLBACK_OBJS)
$(INSTALL_DIR) $(LIBDIR)
- $(LD) $(LDFLAGS) -o $@ $(SSL_DED_LD_RUNTIME_LIBRARY_PATH) -L$(SSL_LIBDIR) $(OBJS) -l$(SSL_CRYPTO_LIBNAME) -l$(SSL_SSL_LIBNAME)
+ $(LD) $(LDFLAGS) -o $@ $(CALLBACK_OBJS)
+endif
+
clean:
ifeq ($(findstring win32,$(TARGET)), win32)
rm -f $(LIBDIR)/crypto.dll
rm -f $(LIBDIR)/crypto.debug.dll
+ rm -f $(LIBDIR)/crypto_callback.dll
+ rm -f $(LIBDIR)/crypto_callback.debug.dll
else
rm -f $(LIBDIR)/crypto.so
rm -f $(LIBDIR)/crypto.debug.so
rm -f $(LIBDIR)/crypto.valgrind.so
+ rm -f $(LIBDIR)/crypto_callback.so
+ rm -f $(LIBDIR)/crypto_callback.debug.so
+ rm -f $(LIBDIR)/crypto_callback.valgrind.so
endif
rm -f $(OBJDIR)/crypto.o
rm -f $(OBJDIR)/crypto.debug.o
rm -f $(OBJDIR)/crypto.valgrind.o
+ rm -f $(OBJDIR)/crypto_callback.o
+ rm -f $(OBJDIR)/crypto_callback.debug.o
+ rm -f $(OBJDIR)/crypto_callback.valgrind.o
rm -f core *~
docs:
@@ -136,8 +163,12 @@ release_spec: opt
$(INSTALL_DIR) "$(RELSYSDIR)/priv/obj"
$(INSTALL_DIR) "$(RELSYSDIR)/priv/lib"
$(INSTALL_DATA) $(NIF_MAKEFILE) "$(RELSYSDIR)/priv/obj"
- $(INSTALL_PROGRAM) $(OBJS) "$(RELSYSDIR)/priv/obj"
+ $(INSTALL_PROGRAM) $(CRYPTO_OBJS) "$(RELSYSDIR)/priv/obj"
$(INSTALL_PROGRAM) $(NIF_LIB) "$(RELSYSDIR)/priv/lib"
+ifeq ($(DYNAMIC_CRYPTO_LIB),yes)
+ $(INSTALL_PROGRAM) $(CALLBACK_OBJS) "$(RELSYSDIR)/priv/obj"
+ $(INSTALL_PROGRAM) $(CALLBACK_LIB) "$(RELSYSDIR)/priv/lib"
+endif
release_docs_spec:
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index 91ab244620..e77e5fb8f0 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -44,6 +44,7 @@
#include <openssl/md5.h>
#include <openssl/md4.h>
#include <openssl/sha.h>
+#include <openssl/ripemd.h>
#include <openssl/bn.h>
#include <openssl/objects.h>
#include <openssl/rc4.h>
@@ -53,6 +54,8 @@
#include <openssl/evp.h>
#include <openssl/hmac.h>
+#include "crypto_callback.h"
+
#if OPENSSL_VERSION_NUMBER >= 0x00908000L && !defined(OPENSSL_NO_SHA224) && defined(NID_sha224)\
&& !defined(OPENSSL_NO_SHA256) /* disabled like this in my sha.h (?) */
# define HAVE_SHA224
@@ -67,6 +70,9 @@
#if OPENSSL_VERSION_NUMBER >= 0x00908000L && !defined(OPENSSL_NO_SHA512) && defined(NID_sha512)
# define HAVE_SHA512
#endif
+#if OPENSSL_VERSION_NUMBER >= 0x0090705FL
+# define HAVE_DES_ede3_cfb_encrypt
+#endif
#ifdef VALGRIND
# include <valgrind/memcheck.h>
@@ -125,7 +131,6 @@
/* NIF interface declarations */
static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info);
-static int reload(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);
static void unload(ErlNifEnv* env, void* priv_data);
@@ -135,6 +140,10 @@ static ERL_NIF_TERM md5(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM md5_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM md5_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM md5_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ripemd160(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ripemd160_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ripemd160_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ripemd160_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM sha(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM sha_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM sha_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -172,7 +181,7 @@ static ERL_NIF_TERM des_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
static ERL_NIF_TERM des_cfb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM des_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM des_ede3_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM des_ede3_cfb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM des_ede3_cfb_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM aes_cfb_128_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM aes_ctr_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM aes_ctr_stream_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -204,17 +213,6 @@ static ERL_NIF_TERM bf_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
static ERL_NIF_TERM blowfish_ofb64_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-/* openssl callbacks */
-#ifdef OPENSSL_THREADS
-static void locking_function(int mode, int n, const char *file, int line);
-static unsigned long id_function(void);
-static struct CRYPTO_dynlock_value* dyn_create_function(const char *file,
- int line);
-static void dyn_lock_function(int mode, struct CRYPTO_dynlock_value* ptr,
- const char *file, int line);
-static void dyn_destroy_function(struct CRYPTO_dynlock_value *ptr,
- const char *file, int line);
-#endif /* OPENSSL_THREADS */
/* helpers */
static void init_digest_types(ErlNifEnv* env);
@@ -253,6 +251,10 @@ static ErlNifFunc nif_funcs[] = {
{"md5_init", 0, md5_init},
{"md5_update", 2, md5_update},
{"md5_final", 1, md5_final},
+ {"ripemd160", 1, ripemd160},
+ {"ripemd160_init", 0, ripemd160_init},
+ {"ripemd160_update", 2, ripemd160_update},
+ {"ripemd160_final", 1, ripemd160_final},
{"sha", 1, sha},
{"sha_init", 0, sha_init},
{"sha_update", 2, sha_update},
@@ -291,7 +293,7 @@ static ErlNifFunc nif_funcs[] = {
{"des_cfb_crypt", 4, des_cfb_crypt},
{"des_ecb_crypt", 3, des_ecb_crypt},
{"des_ede3_cbc_crypt", 6, des_ede3_cbc_crypt},
- {"des_ede3_cfb_crypt", 6, des_ede3_cfb_crypt},
+ {"des_ede3_cfb_crypt_nif", 6, des_ede3_cfb_crypt_nif},
{"aes_cfb_128_crypt", 4, aes_cfb_128_crypt},
{"aes_ctr_encrypt", 3, aes_ctr_encrypt},
{"aes_ctr_decrypt", 3, aes_ctr_encrypt},
@@ -325,7 +327,7 @@ static ErlNifFunc nif_funcs[] = {
{"blowfish_ofb64_encrypt", 3, blowfish_ofb64_encrypt}
};
-ERL_NIF_INIT(crypto,nif_funcs,load,reload,upgrade,unload)
+ERL_NIF_INIT(crypto,nif_funcs,load,NULL,upgrade,unload)
#define MD5_CTX_LEN (sizeof(MD5_CTX))
@@ -333,6 +335,8 @@ ERL_NIF_INIT(crypto,nif_funcs,load,reload,upgrade,unload)
#define MD5_LEN_96 12
#define MD4_CTX_LEN (sizeof(MD4_CTX))
#define MD4_LEN 16
+#define RIPEMD160_CTX_LEN (sizeof(RIPEMD160_CTX))
+#define RIPEMD160_LEN 20
#define SHA_CTX_LEN (sizeof(SHA_CTX))
#define SHA_LEN 20
#define SHA_LEN_96 12
@@ -347,7 +351,6 @@ ERL_NIF_INIT(crypto,nif_funcs,load,reload,upgrade,unload)
#define HMAC_OPAD 0x5c
-static ErlNifRWLock** lock_vec = NULL; /* Static locks used by openssl */
static ERL_NIF_TERM atom_true;
static ERL_NIF_TERM atom_false;
static ERL_NIF_TERM atom_sha;
@@ -374,55 +377,60 @@ static ERL_NIF_TERM atom_none;
static ERL_NIF_TERM atom_notsup;
static ERL_NIF_TERM atom_digest;
+/*
+#define PRINTF_ERR0(FMT) enif_fprintf(stderr, FMT "\n")
+#define PRINTF_ERR1(FMT, A1) enif_fprintf(stderr, FMT "\n", A1)
+*/
+#define PRINTF_ERR0(FMT)
+#define PRINTF_ERR1(FMT,A1)
-static int is_ok_load_info(ErlNifEnv* env, ERL_NIF_TERM load_info)
+#ifdef HAVE_DYNAMIC_CRYPTO_LIB
+static int change_basename(char* buf, int bufsz, const char* newfile)
{
- int i;
- return enif_get_int(env,load_info,&i) && i == 101;
-}
-static void* crypto_alloc(size_t size)
-{
- return enif_alloc(size);
+ char* p = strrchr(buf, '/');
+ p = (p == NULL) ? buf : p + 1;
+
+ if ((p - buf) + strlen(newfile) >= bufsz) {
+ PRINTF_ERR0("CRYPTO: lib name too long");
+ return 0;
+ }
+ strcpy(p, newfile);
+ return 1;
}
-static void* crypto_realloc(void* ptr, size_t size)
+
+static void error_handler(void* null, const char* errstr)
{
- return enif_realloc(ptr, size);
-}
-static void crypto_free(void* ptr)
-{
- enif_free(ptr);
+ PRINTF_ERR1("CRYPTO LOADING ERROR: '%s'", errstr);
}
+#endif /* HAVE_DYNAMIC_CRYPTO_LIB */
-static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
+static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
{
ErlNifSysInfo sys_info;
- CRYPTO_set_mem_functions(crypto_alloc, crypto_realloc, crypto_free);
-
- if (!is_ok_load_info(env, load_info)) {
- return -1;
+ get_crypto_callbacks_t* funcp;
+ struct crypto_callbacks* ccb;
+ int nlocks = 0;
+ int tpl_arity;
+ const ERL_NIF_TERM* tpl_array;
+ int vernum;
+ char lib_buf[1000];
+
+ /* load_info: {201, "/full/path/of/this/library"} */
+ if (!enif_get_tuple(env, load_info, &tpl_arity, &tpl_array)
+ || tpl_arity != 2
+ || !enif_get_int(env, tpl_array[0], &vernum)
+ || vernum != 201
+ || enif_get_string(env, tpl_array[1], lib_buf, sizeof(lib_buf), ERL_NIF_LATIN1) <= 0) {
+
+ PRINTF_ERR1("CRYPTO: Invalid load_info '%T'", load_info);
+ return 0;
}
-
-#ifdef OPENSSL_THREADS
- enif_system_info(&sys_info, sizeof(sys_info));
-
- if (sys_info.scheduler_threads > 1) {
- int i;
- lock_vec = enif_alloc(CRYPTO_num_locks()*sizeof(*lock_vec));
- if (lock_vec==NULL) return -1;
- memset(lock_vec,0,CRYPTO_num_locks()*sizeof(*lock_vec));
-
- for (i=CRYPTO_num_locks()-1; i>=0; --i) {
- lock_vec[i] = enif_rwlock_create("crypto_stat");
- if (lock_vec[i]==NULL) return -1;
- }
- CRYPTO_set_locking_callback(locking_function);
- CRYPTO_set_id_callback(id_function);
- CRYPTO_set_dynlock_create_callback(dyn_create_function);
- CRYPTO_set_dynlock_lock_callback(dyn_lock_function);
- CRYPTO_set_dynlock_destroy_callback(dyn_destroy_function);
+ if (library_refc > 0) {
+ /* Repeated loading of this library (module upgrade).
+ * Atoms and callbacks are already set, we are done.
+ */
+ return 1;
}
- /* else no need for locks */
-#endif /* OPENSSL_THREADS */
atom_true = enif_make_atom(env,"true");
atom_false = enif_make_atom(env,"false");
@@ -451,37 +459,75 @@ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
init_digest_types(env);
- *priv_data = NULL;
- library_refc++;
- return 0;
-}
-
-static int reload(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
-{
- if (*priv_data != NULL) {
- return -1; /* Don't know how to do that */
+#ifdef HAVE_DYNAMIC_CRYPTO_LIB
+ {
+ void* handle;
+ if (!change_basename(lib_buf, sizeof(lib_buf), "crypto_callback")) {
+ return 0;
+ }
+ if (!(handle = enif_dlopen(lib_buf, &error_handler, NULL))) {
+ return 0;
+ }
+ if (!(funcp = (get_crypto_callbacks_t*) enif_dlsym(handle, "get_crypto_callbacks",
+ &error_handler, NULL))) {
+ return 0;
+ }
}
- if (library_refc == 0) {
- /* No support for real library upgrade. The tricky thing is to know
- when to (re)set the callbacks for allocation and locking. */
- return -2;
+#else /* !HAVE_DYNAMIC_CRYPTO_LIB */
+ funcp = &get_crypto_callbacks;
+#endif
+
+#ifdef OPENSSL_THREADS
+ enif_system_info(&sys_info, sizeof(sys_info));
+ if (sys_info.scheduler_threads > 1) {
+ nlocks = CRYPTO_num_locks();
}
- if (!is_ok_load_info(env, load_info)) {
+ /* else no need for locks */
+#endif
+
+ ccb = (*funcp)(nlocks);
+
+ if (!ccb || ccb->sizeof_me != sizeof(*ccb)) {
+ PRINTF_ERR0("Invalid 'crypto_callbacks'");
+ return 0;
+ }
+
+ CRYPTO_set_mem_functions(ccb->crypto_alloc, ccb->crypto_realloc, ccb->crypto_free);
+
+#ifdef OPENSSL_THREADS
+ if (nlocks > 0) {
+ CRYPTO_set_locking_callback(ccb->locking_function);
+ CRYPTO_set_id_callback(ccb->id_function);
+ CRYPTO_set_dynlock_create_callback(ccb->dyn_create_function);
+ CRYPTO_set_dynlock_lock_callback(ccb->dyn_lock_function);
+ CRYPTO_set_dynlock_destroy_callback(ccb->dyn_destroy_function);
+ }
+#endif /* OPENSSL_THREADS */
+ return 1;
+}
+
+static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
+{
+ if (!init(env, load_info)) {
return -1;
}
- return 0;
+
+ *priv_data = NULL;
+ library_refc++;
+ return 0;
}
static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data,
ERL_NIF_TERM load_info)
{
- int i;
if (*old_priv_data != NULL) {
return -1; /* Don't know how to do that */
}
- i = reload(env,priv_data,load_info);
- if (i != 0) {
- return i;
+ if (*priv_data != NULL) {
+ return -1; /* Don't know how to do that */
+ }
+ if (!init(env, load_info)) {
+ return -1;
}
library_refc++;
return 0;
@@ -489,20 +535,7 @@ static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data,
static void unload(ErlNifEnv* env, void* priv_data)
{
- if (--library_refc <= 0) {
- CRYPTO_cleanup_all_ex_data();
-
- if (lock_vec != NULL) {
- int i;
- for (i=CRYPTO_num_locks()-1; i>=0; --i) {
- if (lock_vec[i] != NULL) {
- enif_rwlock_destroy(lock_vec[i]);
- }
- }
- enif_free(lock_vec);
- }
- }
- /*else NIF library still used by other (new) module code */
+ --library_refc;
}
static ERL_NIF_TERM info_lib(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
@@ -514,12 +547,21 @@ static ERL_NIF_TERM info_lib(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
const char* ver = SSLeay_version(SSLEAY_VERSION);
unsigned ver_sz = strlen(ver);
ERL_NIF_TERM name_term, ver_term;
+ int ver_num = OPENSSL_VERSION_NUMBER;
+ /* R16:
+ * Ignore library version number from SSLeay() and instead show header
+ * version. Otherwise user might try to call a function that is implemented
+ * by a newer library but not supported by the headers used at compile time.
+ * Example: DES_ede3_cfb_encrypt in 0.9.7i but not in 0.9.7d.
+ *
+ * Version string is still from library though.
+ */
memcpy(enif_make_new_binary(env, name_sz, &name_term), libname, name_sz);
memcpy(enif_make_new_binary(env, ver_sz, &ver_term), ver, ver_sz);
return enif_make_list1(env, enif_make_tuple3(env, name_term,
- enif_make_int(env, SSLeay()),
+ enif_make_int(env, ver_num),
ver_term));
}
@@ -569,6 +611,53 @@ static ERL_NIF_TERM md5_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
return ret;
}
+static ERL_NIF_TERM ripemd160(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Data) */
+ ErlNifBinary ibin;
+ ERL_NIF_TERM ret;
+
+ if (!enif_inspect_iolist_as_binary(env, argv[0], &ibin)) {
+ return enif_make_badarg(env);
+ }
+ RIPEMD160((unsigned char *) ibin.data, ibin.size,
+ enif_make_new_binary(env,RIPEMD160_LEN, &ret));
+ return ret;
+}
+static ERL_NIF_TERM ripemd160_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* () */
+ ERL_NIF_TERM ret;
+ RIPEMD160_Init((RIPEMD160_CTX *) enif_make_new_binary(env, RIPEMD160_CTX_LEN, &ret));
+ return ret;
+}
+static ERL_NIF_TERM ripemd160_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Context, Data) */
+ RIPEMD160_CTX* new_ctx;
+ ErlNifBinary ctx_bin, data_bin;
+ ERL_NIF_TERM ret;
+ if (!enif_inspect_binary(env, argv[0], &ctx_bin)
+ || ctx_bin.size != RIPEMD160_CTX_LEN
+ || !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) {
+ return enif_make_badarg(env);
+ }
+ new_ctx = (RIPEMD160_CTX*) enif_make_new_binary(env,RIPEMD160_CTX_LEN, &ret);
+ memcpy(new_ctx, ctx_bin.data, RIPEMD160_CTX_LEN);
+ RIPEMD160_Update(new_ctx, data_bin.data, data_bin.size);
+ return ret;
+}
+static ERL_NIF_TERM ripemd160_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Context) */
+ ErlNifBinary ctx_bin;
+ RIPEMD160_CTX ctx_clone;
+ ERL_NIF_TERM ret;
+ if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != RIPEMD160_CTX_LEN) {
+ return enif_make_badarg(env);
+ }
+ memcpy(&ctx_clone, ctx_bin.data, RIPEMD160_CTX_LEN); /* writable */
+ RIPEMD160_Final(enif_make_new_binary(env, RIPEMD160_LEN, &ret), &ctx_clone);
+ return ret;
+}
+
+
static ERL_NIF_TERM sha(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Data) */
ErlNifBinary ibin;
@@ -1199,8 +1288,9 @@ static ERL_NIF_TERM des_ede3_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_T
return ret;
}
-static ERL_NIF_TERM des_ede3_cfb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+static ERL_NIF_TERM des_ede3_cfb_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Key1, Key2, Key3, IVec, Text/Cipher, IsEncrypt) */
+#ifdef HAVE_DES_ede3_cfb_encrypt
ErlNifBinary key1, key2, key3, ivec, text;
DES_key_schedule schedule1, schedule2, schedule3;
DES_cblock ivec_clone; /* writable copy */
@@ -1222,6 +1312,9 @@ static ERL_NIF_TERM des_ede3_cfb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_T
8, text.size, &schedule1, &schedule2, &schedule3,
&ivec_clone, (argv[5] == atom_true));
return ret;
+#else
+ return atom_notsup;
+#endif
}
static ERL_NIF_TERM aes_cfb_128_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
@@ -2338,59 +2431,6 @@ static ERL_NIF_TERM blowfish_ofb64_encrypt(ErlNifEnv* env, int argc, const ERL_N
-#ifdef OPENSSL_THREADS /* vvvvvvvvvvvvvvv OPENSSL_THREADS vvvvvvvvvvvvvvvv */
-
-static INLINE void locking(int mode, ErlNifRWLock* lock)
-{
- switch (mode) {
- case CRYPTO_LOCK|CRYPTO_READ:
- enif_rwlock_rlock(lock);
- break;
- case CRYPTO_LOCK|CRYPTO_WRITE:
- enif_rwlock_rwlock(lock);
- break;
- case CRYPTO_UNLOCK|CRYPTO_READ:
- enif_rwlock_runlock(lock);
- break;
- case CRYPTO_UNLOCK|CRYPTO_WRITE:
- enif_rwlock_rwunlock(lock);
- break;
- default:
- ASSERT(!"Invalid lock mode");
- }
-}
-
-/* Callback from openssl for static locking
- */
-static void locking_function(int mode, int n, const char *file, int line)
-{
- ASSERT(n>=0 && n<CRYPTO_num_locks());
-
- locking(mode, lock_vec[n]);
-}
-
-/* Callback from openssl for thread id
- */
-static unsigned long id_function(void)
-{
- return(unsigned long) enif_thread_self();
-}
-
-/* Callbacks for dynamic locking, not used by current openssl version (0.9.8)
- */
-static struct CRYPTO_dynlock_value* dyn_create_function(const char *file, int line) {
- return(struct CRYPTO_dynlock_value*) enif_rwlock_create("crypto_dyn");
-}
-static void dyn_lock_function(int mode, struct CRYPTO_dynlock_value* ptr,const char *file, int line)
-{
- locking(mode, (ErlNifRWLock*)ptr);
-}
-static void dyn_destroy_function(struct CRYPTO_dynlock_value *ptr, const char *file, int line)
-{
- enif_rwlock_destroy((ErlNifRWLock*)ptr);
-}
-
-#endif /* ^^^^^^^^^^^^^^^^^^^^^^ OPENSSL_THREADS ^^^^^^^^^^^^^^^^^^^^^^ */
/* HMAC */
diff --git a/lib/crypto/c_src/crypto_callback.c b/lib/crypto/c_src/crypto_callback.c
new file mode 100644
index 0000000000..81106b4cc2
--- /dev/null
+++ b/lib/crypto/c_src/crypto_callback.c
@@ -0,0 +1,165 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2012. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include <string.h>
+#include <openssl/opensslconf.h>
+
+#include "erl_nif.h"
+#include "crypto_callback.h"
+
+#ifdef DEBUG
+ # define ASSERT(e) \
+ ((void) ((e) ? 1 : (fprintf(stderr,"Assert '%s' failed at %s:%d\n",\
+ #e, __FILE__, __LINE__), abort(), 0)))
+#else
+ # define ASSERT(e) ((void) 1)
+#endif
+
+#ifdef __GNUC__
+ # define INLINE __inline__
+#elif defined(__WIN32__)
+ # define INLINE __forceinline
+#else
+ # define INLINE
+#endif
+
+#ifdef __WIN32__
+# define DLLEXPORT __declspec(dllexport)
+#else
+# define DLLEXPORT
+#endif
+
+/* to be dlsym'ed */
+DLLEXPORT struct crypto_callbacks* get_crypto_callbacks(int nlocks);
+
+
+static ErlNifRWLock** lock_vec = NULL; /* Static locks used by openssl */
+
+static void* crypto_alloc(size_t size)
+{
+ return enif_alloc(size);
+}
+static void* crypto_realloc(void* ptr, size_t size)
+{
+ return enif_realloc(ptr, size);
+}
+static void crypto_free(void* ptr)
+{
+ enif_free(ptr);
+}
+
+
+#ifdef OPENSSL_THREADS /* vvvvvvvvvvvvvvv OPENSSL_THREADS vvvvvvvvvvvvvvvv */
+
+#include <openssl/crypto.h>
+
+static INLINE void locking(int mode, ErlNifRWLock* lock)
+{
+ switch (mode) {
+ case CRYPTO_LOCK|CRYPTO_READ:
+ enif_rwlock_rlock(lock);
+ break;
+ case CRYPTO_LOCK|CRYPTO_WRITE:
+ enif_rwlock_rwlock(lock);
+ break;
+ case CRYPTO_UNLOCK|CRYPTO_READ:
+ enif_rwlock_runlock(lock);
+ break;
+ case CRYPTO_UNLOCK|CRYPTO_WRITE:
+ enif_rwlock_rwunlock(lock);
+ break;
+ default:
+ ASSERT(!"Invalid lock mode");
+ }
+}
+
+static void locking_function(int mode, int n, const char *file, int line)
+{
+ ASSERT(n>=0 && n<CRYPTO_num_locks());
+
+ locking(mode, lock_vec[n]);
+}
+
+static unsigned long id_function(void)
+{
+ return (unsigned long) enif_thread_self();
+}
+
+/* Dynamic locking, not used by current openssl version (0.9.8)
+ */
+static struct CRYPTO_dynlock_value* dyn_create_function(const char *file, int line)
+{
+ return (struct CRYPTO_dynlock_value*) enif_rwlock_create("crypto_dyn");
+}
+static void dyn_lock_function(int mode, struct CRYPTO_dynlock_value* ptr,const char *file, int line)
+{
+ locking(mode, (ErlNifRWLock*)ptr);
+}
+static void dyn_destroy_function(struct CRYPTO_dynlock_value *ptr, const char *file, int line)
+{
+ enif_rwlock_destroy((ErlNifRWLock*)ptr);
+}
+
+#endif /* ^^^^^^^^^^^^^^^^^^^^^^ OPENSSL_THREADS ^^^^^^^^^^^^^^^^^^^^^^ */
+
+DLLEXPORT struct crypto_callbacks* get_crypto_callbacks(int nlocks)
+{
+ static int is_initialized = 0;
+ static struct crypto_callbacks the_struct = {
+ sizeof(struct crypto_callbacks),
+
+ &crypto_alloc,
+ &crypto_realloc,
+ &crypto_free,
+
+#ifdef OPENSSL_THREADS
+ &locking_function,
+ &id_function,
+ &dyn_create_function,
+ &dyn_lock_function,
+ &dyn_destroy_function
+#endif /* OPENSSL_THREADS */
+ };
+
+ if (!is_initialized) {
+#ifdef OPENSSL_THREADS
+ if (nlocks > 0) {
+ int i;
+ lock_vec = enif_alloc(nlocks*sizeof(*lock_vec));
+ if (lock_vec==NULL) return NULL;
+ memset(lock_vec, 0, nlocks*sizeof(*lock_vec));
+
+ for (i=nlocks-1; i>=0; --i) {
+ lock_vec[i] = enif_rwlock_create("crypto_stat");
+ if (lock_vec[i]==NULL) return NULL;
+ }
+ }
+#endif
+ is_initialized = 1;
+ }
+ return &the_struct;
+}
+
+#ifdef HAVE_DYNAMIC_CRYPTO_LIB
+/* This is not really a NIF library, but we use ERL_NIF_INIT in order to
+ * get access to the erl_nif API (on Windows).
+ */
+ERL_NIF_INIT(dummy, (ErlNifFunc*)NULL , NULL, NULL, NULL, NULL)
+#endif
+
diff --git a/lib/crypto/c_src/crypto_callback.h b/lib/crypto/c_src/crypto_callback.h
new file mode 100644
index 0000000000..23ecba3e5d
--- /dev/null
+++ b/lib/crypto/c_src/crypto_callback.h
@@ -0,0 +1,46 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2012. All Rights Reserved.
+ *
+ * The 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%
+ */
+
+struct crypto_callbacks
+{
+ size_t sizeof_me;
+
+ void* (*crypto_alloc)(size_t size);
+ void* (*crypto_realloc)(void* ptr, size_t size);
+ void (*crypto_free)(void* ptr);
+
+ /* openssl callbacks */
+ #ifdef OPENSSL_THREADS
+ void (*locking_function)(int mode, int n, const char *file, int line);
+ unsigned long (*id_function)(void);
+ struct CRYPTO_dynlock_value* (*dyn_create_function)(const char *file,
+ int line);
+ void (*dyn_lock_function)(int mode, struct CRYPTO_dynlock_value* ptr,
+ const char *file, int line);
+ void (*dyn_destroy_function)(struct CRYPTO_dynlock_value *ptr,
+ const char *file, int line);
+ #endif /* OPENSSL_THREADS */
+};
+
+typedef struct crypto_callbacks* get_crypto_callbacks_t(int nlocks);
+
+#ifndef HAVE_DYNAMIC_CRYPTO_LIB
+struct crypto_callbacks* get_crypto_callbacks(int nlocks);
+#endif
+
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index 4dcd6fc4ea..14c77c873f 100644..100755
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -115,6 +115,12 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
> <input>info_lib().</input>
[{&lt;&lt;"OpenSSL"&gt;&gt;,9469983,&lt;&lt;"OpenSSL 0.9.8a 11 Oct 2005"&gt;&gt;}]
</pre>
+ <note><p>
+ From OTP R16 the <em>numeric version</em> represents the version of the OpenSSL
+ <em>header files</em> (<c>openssl/opensslv.h</c>) used when crypto was compiled.
+ The text variant represents the OpenSSL library used at runtime.
+ In earlier OTP versions both numeric and text was taken from the library.
+ </p></note>
</desc>
</func>
<func>
@@ -259,24 +265,28 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
<name>hash(Type, Data) -> Digest</name>
<fsummary></fsummary>
<type>
- <v>Type = md4 | md5 | sha | sha224 | sha256 | sha384 | sha512</v>
+ <v>Type = md4 | md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512</v>
<v>Data = iodata()</v>
<v>Digest = binary()</v>
</type>
<desc>
<p>Computes a message digest of type <c>Type</c> from <c>Data</c>.</p>
+ <p>May throw exception <c>notsup</c> in case the chosen <c>Type</c>
+ is not supported by the underlying OpenSSL implementation.</p>
</desc>
</func>
<func>
<name>hash_init(Type) -> Context</name>
<fsummary></fsummary>
<type>
- <v>Type = md4 | md5 | sha | sha224 | sha256 | sha384 | sha512</v>
+ <v>Type = md4 | md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512</v>
</type>
<desc>
<p>Initializes the context for streaming hash operations. <c>Type</c> determines
which digest to use. The returned context should be used as argument
to <seealso marker="#hash_update/2">hash_update</seealso>.</p>
+ <p>May throw exception <c>notsup</c> in case the chosen <c>Type</c>
+ is not supported by the underlying OpenSSL implementation.</p>
</desc>
</func>
<func>
@@ -333,10 +343,27 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
</desc>
</func>
<func>
+ <name>hmac(Type, Key, Data) -> Mac</name>
+ <name>hmac(Type, Key, Data, MacLength) -> Mac</name>
+ <fsummary></fsummary>
+ <type>
+ <v>Type = md5 | sha | sha224 | sha256 | sha384 | sha512</v>
+ <v>Key = iodata()</v>
+ <v>Data = iodata()</v>
+ <v>MacLength = integer()</v>
+ <v>Mac = binary()</v>
+ </type>
+ <desc>
+ <p>Computes a HMAC of type <c>Type</c> from <c>Data</c> using
+ <c>Key</c> as the authentication key.</p> <c>MacLength</c>
+ will limit the size of the resultant <c>Mac</c>.
+ </desc>
+ </func>
+ <func>
<name>hmac_init(Type, Key) -> Context</name>
<fsummary></fsummary>
<type>
- <v>Type = sha | md5 | ripemd160</v>
+ <v>Type = md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512</v>
<v>Key = iolist() | binary()</v>
<v>Context = binary()</v>
</type>
@@ -548,6 +575,8 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
keys, and <c>IVec</c> is an arbitrary initializing
vector. The lengths of each of <c>Key1</c>, <c>Key2</c>,
<c>Key3</c> and <c>IVec</c> must be 64 bits (8 bytes).</p>
+ <p>May throw exception <c>notsup</c> for old OpenSSL
+ versions (0.9.7) that does not support this encryption mode.</p>
</desc>
</func>
<func>
@@ -565,6 +594,8 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
and <c>IVec</c> must have the same values as those used when
encrypting. The lengths of <c>Key1</c>, <c>Key2</c>,
<c>Key3</c>, and <c>IVec</c> must be 64 bits (8 bytes).</p>
+ <p>May throw exception <c>notsup</c> for old OpenSSL
+ versions (0.9.7) that does not support this encryption mode.</p>
</desc>
</func>
diff --git a/lib/crypto/doc/src/crypto_app.xml b/lib/crypto/doc/src/crypto_app.xml
index 1c01e3f099..6573a56f4c 100644
--- a/lib/crypto/doc/src/crypto_app.xml
+++ b/lib/crypto/doc/src/crypto_app.xml
@@ -62,7 +62,7 @@
<section>
<title>OpenSSL libraries</title>
<p>The current implementation of the Erlang Crypto application is
- based on the <em>OpenSSL</em> package version 0.9.7 or higher.
+ based on the <em>OpenSSL</em> package version 0.9.8 or higher.
There are source and binary releases on the web.
</p>
<p>Source releases of OpenSSL can be downloaded from the <url href="http://www.openssl.org">OpenSSL</url> project home page,
diff --git a/lib/crypto/doc/src/notes.xml b/lib/crypto/doc/src/notes.xml
index a9f8dd84af..4178ca2b08 100644
--- a/lib/crypto/doc/src/notes.xml
+++ b/lib/crypto/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1999</year><year>2011</year>
+ <year>1999</year><year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/crypto/src/Makefile b/lib/crypto/src/Makefile
index 910e89363c..5c200742ac 100644
--- a/lib/crypto/src/Makefile
+++ b/lib/crypto/src/Makefile
@@ -70,10 +70,10 @@ clean:
rm -f errs core *~
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
docs:
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 0089e79a4f..aa89f6cc61 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -35,7 +35,7 @@
-export([sha256_mac/2, sha256_mac/3]).
-export([sha384_mac/2, sha384_mac/3]).
-export([sha512_mac/2, sha512_mac/3]).
--export([hmac_init/2, hmac_update/2, hmac_final/1, hmac_final_n/2]).
+-export([hmac/3, hmac/4, hmac_init/2, hmac_update/2, hmac_final/1, hmac_final_n/2]).
-export([des_cbc_encrypt/3, des_cbc_decrypt/3, des_cbc_ivec/1]).
-export([des_ecb_encrypt/2, des_ecb_decrypt/2]).
-export([des_cfb_encrypt/3, des_cfb_decrypt/3, des_cfb_ivec/2]).
@@ -78,12 +78,11 @@
md5_mac, md5_mac_96,
sha_mac, sha_mac_96,
sha224_mac, sha256_mac, sha384_mac, sha512_mac,
- sha_mac_init, sha_mac_update, sha_mac_final,
des_cbc_encrypt, des_cbc_decrypt,
des_cfb_encrypt, des_cfb_decrypt,
des_ecb_encrypt, des_ecb_decrypt,
- des_ede3_cbc_encrypt, des_ede3_cbc_decrypt,
- des_ede3_cfb_encrypt, des_ede3_cfb_decrypt,
+ des3_cbc_encrypt, des3_cbc_decrypt,
+ des3_cfb_encrypt, des3_cfb_decrypt,
aes_cfb_128_encrypt, aes_cfb_128_decrypt,
rand_bytes,
strong_rand_bytes,
@@ -103,6 +102,13 @@
aes_cbc_256_encrypt, aes_cbc_256_decrypt,
aes_ctr_encrypt, aes_ctr_decrypt,
aes_ctr_stream_init, aes_ctr_stream_encrypt, aes_ctr_stream_decrypt,
+ aes_cbc_ivec, blowfish_cbc_encrypt, blowfish_cbc_decrypt,
+ blowfish_cfb64_encrypt, blowfish_cfb64_decrypt,
+ blowfish_ecb_encrypt, blowfish_ecb_decrypt, blowfish_ofb64_encrypt,
+ des_cbc_ivec, des_cfb_ivec, erlint, mpint,
+ hash, hash_init, hash_update, hash_final,
+ hmac, hmac_init, hmac_update, hmac_final, hmac_final_n, info,
+ rc2_cbc_encrypt, rc2_cbc_decrypt,
info_lib]).
-type rsa_digest_type() :: 'md5' | 'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'.
@@ -114,7 +120,7 @@
-on_load(on_load/0).
--define(CRYPTO_NIF_VSN,101).
+-define(CRYPTO_NIF_VSN,201).
on_load() ->
LibBaseName = "crypto",
@@ -140,7 +146,7 @@ on_load() ->
end
end,
Lib = filename:join([PrivDir, "lib", LibName]),
- Status = case erlang:load_nif(Lib, ?CRYPTO_NIF_VSN) of
+ Status = case erlang:load_nif(Lib, {?CRYPTO_NIF_VSN,Lib}) of
ok -> ok;
{error, {load_failed, _}}=Error1 ->
ArchLibDir =
@@ -152,7 +158,7 @@ on_load() ->
[] -> Error1;
_ ->
ArchLib = filename:join([ArchLibDir, LibName]),
- erlang:load_nif(ArchLib, ?CRYPTO_NIF_VSN)
+ erlang:load_nif(ArchLib, {?CRYPTO_NIF_VSN,ArchLib})
end;
Error1 -> Error1
end,
@@ -191,43 +197,48 @@ version() -> ?CRYPTO_VSN.
%%
-spec hash(_, iodata()) -> binary().
-hash(md5, Data) -> md5(Data);
-hash(md4, Data) -> md4(Data);
-hash(sha, Data) -> sha(Data);
-hash(sha224, Data) -> sha224(Data);
-hash(sha256, Data) -> sha256(Data);
-hash(sha384, Data) -> sha384(Data);
-hash(sha512, Data) -> sha512(Data).
-
--spec hash_init('md5'|'md4'|'sha'|'sha224'|'sha256'|'sha384'|'sha512') -> any().
-
-hash_init(md5) -> {md5, md5_init()};
-hash_init(md4) -> {md4, md4_init()};
-hash_init(sha) -> {sha, sha_init()};
-hash_init(sha224) -> {sha224, sha224_init()};
-hash_init(sha256) -> {sha256, sha256_init()};
-hash_init(sha384) -> {sha384, sha384_init()};
-hash_init(sha512) -> {sha512, sha512_init()}.
+hash(md5, Data) -> md5(Data);
+hash(md4, Data) -> md4(Data);
+hash(sha, Data) -> sha(Data);
+hash(ripemd160, Data) -> ripemd160(Data);
+hash(sha224, Data) -> sha224(Data);
+hash(sha256, Data) -> sha256(Data);
+hash(sha384, Data) -> sha384(Data);
+hash(sha512, Data) -> sha512(Data).
+
+-spec hash_init('md5'|'md4'|'ripemd160'|
+ 'sha'|'sha224'|'sha256'|'sha384'|'sha512') -> any().
+
+hash_init(md5) -> {md5, md5_init()};
+hash_init(md4) -> {md4, md4_init()};
+hash_init(sha) -> {sha, sha_init()};
+hash_init(ripemd160) -> {ripemd160, ripemd160_init()};
+hash_init(sha224) -> {sha224, sha224_init()};
+hash_init(sha256) -> {sha256, sha256_init()};
+hash_init(sha384) -> {sha384, sha384_init()};
+hash_init(sha512) -> {sha512, sha512_init()}.
-spec hash_update(_, iodata()) -> any().
-hash_update({md5,Context}, Data) -> {md5, md5_update(Context,Data)};
-hash_update({md4,Context}, Data) -> {md4, md4_update(Context,Data)};
-hash_update({sha,Context}, Data) -> {sha, sha_update(Context,Data)};
-hash_update({sha224,Context}, Data) -> {sha224, sha224_update(Context,Data)};
-hash_update({sha256,Context}, Data) -> {sha256, sha256_update(Context,Data)};
-hash_update({sha384,Context}, Data) -> {sha384, sha384_update(Context,Data)};
-hash_update({sha512,Context}, Data) -> {sha512, sha512_update(Context,Data)}.
+hash_update({md5,Context}, Data) -> {md5, md5_update(Context,Data)};
+hash_update({md4,Context}, Data) -> {md4, md4_update(Context,Data)};
+hash_update({sha,Context}, Data) -> {sha, sha_update(Context,Data)};
+hash_update({ripemd160,Context}, Data) -> {ripemd160, ripemd160_update(Context,Data)};
+hash_update({sha224,Context}, Data) -> {sha224, sha224_update(Context,Data)};
+hash_update({sha256,Context}, Data) -> {sha256, sha256_update(Context,Data)};
+hash_update({sha384,Context}, Data) -> {sha384, sha384_update(Context,Data)};
+hash_update({sha512,Context}, Data) -> {sha512, sha512_update(Context,Data)}.
-spec hash_final(_) -> binary().
-hash_final({md5,Context}) -> md5_final(Context);
-hash_final({md4,Context}) -> md4_final(Context);
-hash_final({sha,Context}) -> sha_final(Context);
-hash_final({sha224,Context}) -> sha224_final(Context);
-hash_final({sha256,Context}) -> sha256_final(Context);
-hash_final({sha384,Context}) -> sha384_final(Context);
-hash_final({sha512,Context}) -> sha512_final(Context).
+hash_final({md5,Context}) -> md5_final(Context);
+hash_final({md4,Context}) -> md4_final(Context);
+hash_final({sha,Context}) -> sha_final(Context);
+hash_final({ripemd160,Context}) -> ripemd160_final(Context);
+hash_final({sha224,Context}) -> sha224_final(Context);
+hash_final({sha256,Context}) -> sha256_final(Context);
+hash_final({sha384,Context}) -> sha384_final(Context);
+hash_final({sha512,Context}) -> sha512_final(Context).
%%
%% MD5
@@ -257,6 +268,20 @@ md4_update(_Context, _Data) -> ?nif_stub.
md4_final(_Context) -> ?nif_stub.
%%
+%% RIPEMD160
+%%
+
+-spec ripemd160(iodata()) -> binary().
+-spec ripemd160_init() -> binary().
+-spec ripemd160_update(binary(), iodata()) -> binary().
+-spec ripemd160_final(binary()) -> binary().
+
+ripemd160(_Data) -> ?nif_stub.
+ripemd160_init() -> ?nif_stub.
+ripemd160_update(_Context, _Data) -> ?nif_stub.
+ripemd160_final(_Context) -> ?nif_stub.
+
+%%
%% SHA
%%
-spec sha(iodata()) -> binary().
@@ -412,11 +437,28 @@ sha512_final_nif(_Context) -> ?nif_stub.
%%
%% HMAC (multiple hash options)
%%
+
+-spec hmac(_, iodata(), iodata()) -> binary().
+-spec hmac(_, iodata(), iodata(), integer()) -> binary().
-spec hmac_init(atom(), iodata()) -> binary().
-spec hmac_update(binary(), iodata()) -> binary().
-spec hmac_final(binary()) -> binary().
-spec hmac_final_n(binary(), integer()) -> binary().
+hmac(md5, Key, Data) -> md5_mac(Key, Data);
+hmac(sha, Key, Data) -> sha_mac(Key, Data);
+hmac(sha224, Key, Data) -> sha224_mac(Key, Data);
+hmac(sha256, Key, Data) -> sha256_mac(Key, Data);
+hmac(sha384, Key, Data) -> sha384_mac(Key, Data);
+hmac(sha512, Key, Data) -> sha512_mac(Key, Data).
+
+hmac(md5, Key, Data, Size) -> md5_mac_n(Key, Data, Size);
+hmac(sha, Key, Data, Size) -> sha_mac(Key, Data, Size);
+hmac(sha224, Key, Data, Size) -> sha224_mac(Key, Data, Size);
+hmac(sha256, Key, Data, Size) -> sha256_mac(Key, Data, Size);
+hmac(sha384, Key, Data, Size) -> sha384_mac(Key, Data, Size);
+hmac(sha512, Key, Data, Size) -> sha512_mac(Key, Data, Size).
+
hmac_init(_Type, _Key) -> ?nif_stub.
hmac_update(_Context, _Data) -> ? nif_stub.
hmac_final(_Context) -> ? nif_stub.
@@ -597,12 +639,12 @@ des_ecb_crypt(_Key, _Data, _IsEncrypt) -> ?nif_stub.
binary().
des3_cbc_encrypt(Key1, Key2, Key3, IVec, Data) ->
- des_ede3_cbc_encrypt(Key1, Key2, Key3, IVec, Data).
+ des_ede3_cbc_crypt(Key1, Key2, Key3, IVec, Data, true).
des_ede3_cbc_encrypt(Key1, Key2, Key3, IVec, Data) ->
des_ede3_cbc_crypt(Key1, Key2, Key3, IVec, Data, true).
des3_cbc_decrypt(Key1, Key2, Key3, IVec, Data) ->
- des_ede3_cbc_decrypt(Key1, Key2, Key3, IVec, Data).
+ des_ede3_cbc_crypt(Key1, Key2, Key3, IVec, Data, false).
des_ede3_cbc_decrypt(Key1, Key2, Key3, IVec, Data) ->
des_ede3_cbc_crypt(Key1, Key2, Key3, IVec, Data, false).
@@ -617,16 +659,18 @@ des_ede3_cbc_crypt(_Key1, _Key2, _Key3, _IVec, _Data, _IsEncrypt) -> ?nif_stub.
binary().
des3_cfb_encrypt(Key1, Key2, Key3, IVec, Data) ->
- des_ede3_cfb_encrypt(Key1, Key2, Key3, IVec, Data).
-des_ede3_cfb_encrypt(Key1, Key2, Key3, IVec, Data) ->
des_ede3_cfb_crypt(Key1, Key2, Key3, IVec, Data, true).
des3_cfb_decrypt(Key1, Key2, Key3, IVec, Data) ->
- des_ede3_cfb_decrypt(Key1, Key2, Key3, IVec, Data).
-des_ede3_cfb_decrypt(Key1, Key2, Key3, IVec, Data) ->
des_ede3_cfb_crypt(Key1, Key2, Key3, IVec, Data, false).
-des_ede3_cfb_crypt(_Key1, _Key2, _Key3, _IVec, _Data, _IsEncrypt) -> ?nif_stub.
+des_ede3_cfb_crypt(Key1, Key2, Key3, IVec, Data, IsEncrypt) ->
+ case des_ede3_cfb_crypt_nif(Key1,Key2,Key3,IVec,Data,IsEncrypt) of
+ notsup -> erlang:error(notsup);
+ Bin -> Bin
+ end.
+
+des_ede3_cfb_crypt_nif(_Key1, _Key2, _Key3, _IVec, _Data, _IsEncrypt) -> ?nif_stub.
%%
%% Blowfish
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 7ac693f371..142f06677a 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -38,7 +38,10 @@
hmac_update_md5/1,
hmac_update_md5_io/1,
hmac_update_md5_n/1,
+ hmac_rfc2202/1,
hmac_rfc4231/1,
+ ripemd160/1,
+ ripemd160_update/1,
sha256/1,
sha256_update/1,
sha512/1,
@@ -86,11 +89,13 @@ groups() ->
[{info, [sequence],[info, {group, rest}]},
{rest, [],
[md5, md5_update, md4, md4_update, md5_mac,
- md5_mac_io, sha, sha_update,
+ md5_mac_io, ripemd160, ripemd160_update, sha, sha_update,
+ sha256, sha256_update, sha512, sha512_update,
hmac_update_sha, hmac_update_sha_n, hmac_update_sha256, hmac_update_sha512,
hmac_update_md5_n, hmac_update_md5_io, hmac_update_md5,
- hmac_rfc4231,
+ hmac_rfc2202, hmac_rfc4231,
des_cbc, aes_cfb, aes_cbc,
+ des_cfb, des_cfb_iter, des3_cbc, 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,
@@ -192,7 +197,16 @@ info(Config) when is_list(Config) ->
{skip,"Missing crypto application"};
{_,_} ->
?line crypto:start(),
- ?line crypto:info(),
+ ?line Info = crypto:info(),
+ ?line Exports = lists:usort([F || {F,_} <- crypto:module_info(exports)]),
+ ?line [] = Info -- Exports,
+ ?line NotInInfo = Exports -- Info,
+ io:format("NotInInfo = ~p\n", [NotInInfo]),
+ BlackList = lists:sort([des_ede3_cbc_decrypt, des_ede3_cbc_encrypt,
+ dh_check, dh_generate_parameters,
+ module_info, start, stop, version]),
+ ?line BlackList = NotInInfo,
+
?line InfoLib = crypto:info_lib(),
?line [_|_] = InfoLib,
F = fun([{Name,VerN,VerS}|T],Me) ->
@@ -349,12 +363,8 @@ hmac_update_sha256(doc) ->
hmac_update_sha256(suite) ->
[];
hmac_update_sha256(Config) when is_list(Config) ->
- case openssl_version() of
- V when V < 16#908000 ->
- {skipped,"OpenSSL version too old"};
- _ ->
- hmac_update_sha256_do()
- end.
+ if_098(fun() -> hmac_update_sha256_do() end).
+
hmac_update_sha256_do() ->
?line Key = hexstr2bin("00010203101112132021222330313233"
@@ -376,12 +386,7 @@ hmac_update_sha512(doc) ->
hmac_update_sha512(suite) ->
[];
hmac_update_sha512(Config) when is_list(Config) ->
- case openssl_version() of
- V when V < 16#908000 ->
- {skipped,"OpenSSL version too old"};
- _ ->
- hmac_update_sha512_do()
- end.
+ if_098(fun() -> hmac_update_sha512_do() end).
hmac_update_sha512_do() ->
?line Key = hexstr2bin("00010203101112132021222330313233"
@@ -416,18 +421,174 @@ hmac_update_md5(Config) when is_list(Config) ->
?line Exp2 = crypto:md5_mac(Key2, lists:flatten([Long1, Long2, Long3])),
?line m(Exp2, Mac2).
+hmac_rfc2202(doc) ->
+ ["Generate an HMAC using hmac, md5_mac, and sha_mac."
+ "Test vectors are taken from RFC-2202."];
+hmac_rfc2202(suite) ->
+ [];
+hmac_rfc2202(Config) when is_list(Config) ->
+ hmac_rfc2202_md5(),
+ hmac_rfc2202_sha().
+
+hmac_rfc2202_md5() ->
+ %% Test case 1
+ Case1Key = binary:copy(<<16#0b>>, 16),
+ Case1Data = <<"Hi There">>,
+ Case1Exp = hexstr2bin("9294727a3638bb1c13f48ef8158bfc9d"),
+
+ ?line Case1Mac_1 = crypto:md5_mac(Case1Key, Case1Data),
+ ?line Case1Mac_2 = crypto:hmac(md5, Case1Key, Case1Data),
+ ?line m(Case1Exp, Case1Mac_1),
+ ?line m(Case1Exp, Case1Mac_2),
+
+ %% Test case 2
+ Case2Key = <<"Jefe">>,
+ Case2Data = <<"what do ya want for nothing?">>,
+ Case2Exp = hexstr2bin("750c783e6ab0b503eaa86e310a5db738"),
+
+ ?line Case2Mac_1 = crypto:md5_mac(Case2Key, Case2Data),
+ ?line Case2Mac_2 = crypto:hmac(md5, Case2Key, Case2Data),
+ ?line m(Case2Exp, Case2Mac_1),
+ ?line m(Case2Exp, Case2Mac_2),
+
+ %% Test case 3
+ Case3Key = binary:copy(<<16#aa>>, 16),
+ Case3Data = binary:copy(<<16#dd>>, 50),
+ Case3Exp = hexstr2bin("56be34521d144c88dbb8c733f0e8b3f6"),
+
+ ?line Case3Mac_1 = crypto:md5_mac(Case3Key, Case3Data),
+ ?line Case3Mac_2 = crypto:hmac(md5, Case3Key, Case3Data),
+ ?line m(Case3Exp, Case3Mac_1),
+ ?line m(Case3Exp, Case3Mac_2),
+
+ %% Test case 4
+ Case4Key = list_to_binary(lists:seq(1, 16#19)),
+ Case4Data = binary:copy(<<16#cd>>, 50),
+ Case4Exp = hexstr2bin("697eaf0aca3a3aea3a75164746ffaa79"),
+
+ ?line Case4Mac_1 = crypto:md5_mac(Case4Key, Case4Data),
+ ?line Case4Mac_2 = crypto:hmac(md5, Case4Key, Case4Data),
+ ?line m(Case4Exp, Case4Mac_1),
+ ?line m(Case4Exp, Case4Mac_2),
+
+ %% Test case 5
+ Case5Key = binary:copy(<<16#0c>>, 16),
+ Case5Data = "Test With Truncation",
+ Case5Exp = hexstr2bin("56461ef2342edc00f9bab995690efd4c"),
+ Case5Exp96 = hexstr2bin("56461ef2342edc00f9bab995"),
+
+ ?line Case5Mac_1 = crypto:md5_mac(Case5Key, Case5Data),
+ ?line Case5Mac_2 = crypto:hmac(md5, Case5Key, Case5Data),
+ ?line Case5Mac96_1 = crypto:md5_mac_96(Case5Key, Case5Data),
+ ?line Case5Mac96_2 = crypto:hmac(md5, Case5Key, Case5Data, 12),
+ ?line m(Case5Exp, Case5Mac_1),
+ ?line m(Case5Exp, Case5Mac_2),
+ ?line m(Case5Exp96, Case5Mac96_1),
+ ?line m(Case5Exp96, Case5Mac96_2),
+
+ %% Test case 6
+ Case6Key = binary:copy(<<16#aa>>, 80),
+ Case6Data = <<"Test Using Larger Than Block-Size Key - Hash Key First">>,
+ Case6Exp = hexstr2bin("6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd"),
+
+ ?line Case6Mac_1 = crypto:md5_mac(Case6Key, Case6Data),
+ ?line Case6Mac_2 = crypto:hmac(md5, Case6Key, Case6Data),
+ ?line m(Case6Exp, Case6Mac_1),
+ ?line m(Case6Exp, Case6Mac_2),
+
+ %% Test case 7
+ Case7Key = binary:copy(<<16#aa>>, 80),
+ Case7Data = <<"Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data">>,
+ Case7Exp = hexstr2bin("6f630fad67cda0ee1fb1f562db3aa53e"),
+
+ ?line Case7Mac_1 = crypto:md5_mac(Case7Key, Case7Data),
+ ?line Case7Mac_2 = crypto:hmac(md5, Case7Key, Case7Data),
+ ?line m(Case7Exp, Case7Mac_1),
+ ?line m(Case7Exp, Case7Mac_2).
+
+hmac_rfc2202_sha() ->
+ %% Test case 1
+ Case1Key = binary:copy(<<16#0b>>, 20),
+ Case1Data = <<"Hi There">>,
+ Case1Exp = hexstr2bin("b617318655057264e28bc0b6fb378c8ef146be00"),
+
+ ?line Case1Mac_1 = crypto:sha_mac(Case1Key, Case1Data),
+ ?line Case1Mac_2 = crypto:hmac(sha, Case1Key, Case1Data),
+ ?line m(Case1Exp, Case1Mac_1),
+ ?line m(Case1Exp, Case1Mac_2),
+
+ %% Test case 2
+ Case2Key = <<"Jefe">>,
+ Case2Data = <<"what do ya want for nothing?">>,
+ Case2Exp = hexstr2bin("effcdf6ae5eb2fa2d27416d5f184df9c259a7c79"),
+
+ ?line Case2Mac_1 = crypto:sha_mac(Case2Key, Case2Data),
+ ?line Case2Mac_2 = crypto:hmac(sha, Case2Key, Case2Data),
+ ?line m(Case2Exp, Case2Mac_1),
+ ?line m(Case2Exp, Case2Mac_2),
+
+ %% Test case 3
+ Case3Key = binary:copy(<<16#aa>>, 20),
+ Case3Data = binary:copy(<<16#dd>>, 50),
+ Case3Exp = hexstr2bin("125d7342b9ac11cd91a39af48aa17b4f63f175d3"),
+
+ ?line Case3Mac_1 = crypto:sha_mac(Case3Key, Case3Data),
+ ?line Case3Mac_2 = crypto:hmac(sha, Case3Key, Case3Data),
+ ?line m(Case3Exp, Case3Mac_1),
+ ?line m(Case3Exp, Case3Mac_2),
+
+ %% Test case 4
+ Case4Key = list_to_binary(lists:seq(1, 16#19)),
+ Case4Data = binary:copy(<<16#cd>>, 50),
+ Case4Exp = hexstr2bin("4c9007f4026250c6bc8414f9bf50c86c2d7235da"),
+
+ ?line Case4Mac_1 = crypto:sha_mac(Case4Key, Case4Data),
+ ?line Case4Mac_2 = crypto:hmac(sha, Case4Key, Case4Data),
+ ?line m(Case4Exp, Case4Mac_1),
+ ?line m(Case4Exp, Case4Mac_2),
+
+ %% Test case 5
+ Case5Key = binary:copy(<<16#0c>>, 20),
+ Case5Data = "Test With Truncation",
+ Case5Exp = hexstr2bin("4c1a03424b55e07fe7f27be1d58bb9324a9a5a04"),
+ Case5Exp96 = hexstr2bin("4c1a03424b55e07fe7f27be1"),
+
+ ?line Case5Mac_1 = crypto:sha_mac(Case5Key, Case5Data),
+ ?line Case5Mac_2 = crypto:hmac(sha, Case5Key, Case5Data),
+ ?line Case5Mac96_1 = crypto:sha_mac_96(Case5Key, Case5Data),
+ ?line Case5Mac96_2 = crypto:hmac(sha, Case5Key, Case5Data, 12),
+ ?line m(Case5Exp, Case5Mac_1),
+ ?line m(Case5Exp, Case5Mac_2),
+ ?line m(Case5Exp96, Case5Mac96_1),
+ ?line m(Case5Exp96, Case5Mac96_2),
+
+ %% Test case 6
+ Case6Key = binary:copy(<<16#aa>>, 80),
+ Case6Data = <<"Test Using Larger Than Block-Size Key - Hash Key First">>,
+ Case6Exp = hexstr2bin("aa4ae5e15272d00e95705637ce8a3b55ed402112"),
+
+ ?line Case6Mac_1 = crypto:sha_mac(Case6Key, Case6Data),
+ ?line Case6Mac_2 = crypto:hmac(sha, Case6Key, Case6Data),
+ ?line m(Case6Exp, Case6Mac_1),
+ ?line m(Case6Exp, Case6Mac_2),
+
+ %% Test case 7
+ Case7Key = binary:copy(<<16#aa>>, 80),
+ Case7Data = <<"Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data">>,
+ Case7Exp = hexstr2bin("e8e99d0f45237d786d6bbaa7965c7808bbff1a91"),
+
+ ?line Case7Mac_1 = crypto:sha_mac(Case7Key, Case7Data),
+ ?line Case7Mac_2 = crypto:hmac(sha, Case7Key, Case7Data),
+ ?line m(Case7Exp, Case7Mac_1),
+ ?line m(Case7Exp, Case7Mac_2).
+
hmac_rfc4231(doc) ->
- ["Generate an HMAC using crypto:shaXXX_mac and hmac_init, hmac_update, and hmac_final. "
+ ["Generate an HMAC using crypto:shaXXX_mac, hmac, and hmac_init, hmac_update, and hmac_final. "
"Testvectors are take from RFC4231." ];
hmac_rfc4231(suite) ->
[];
hmac_rfc4231(Config) when is_list(Config) ->
- case openssl_version() of
- V when V < 16#908000 ->
- {skipped,"OpenSSL version too old"};
- _ ->
- hmac_rfc4231_do()
- end.
+ if_098(fun() -> hmac_rfc4231_do() end).
hmac_rfc4231_do() ->
%% Test Case 1
@@ -449,29 +610,37 @@ hmac_rfc4231_do() ->
?line Case1Ctx224_2 = crypto:hmac_update(Case1Ctx224, Case1Data),
?line Case1Mac224_1 = crypto:hmac_final(Case1Ctx224_2),
?line Case1Mac224_2 = crypto:sha224_mac(Case1Key, Case1Data),
+ ?line Case1Mac224_3 = crypto:hmac(sha224, Case1Key, Case1Data),
?line m(Case1Exp224, Case1Mac224_1),
?line m(Case1Exp224, Case1Mac224_2),
+ ?line m(Case1Exp224, Case1Mac224_3),
?line Case1Ctx256 = crypto:hmac_init(sha256, Case1Key),
?line Case1Ctx256_2 = crypto:hmac_update(Case1Ctx256, Case1Data),
?line Case1Mac256_1 = crypto:hmac_final(Case1Ctx256_2),
?line Case1Mac256_2 = crypto:sha256_mac(Case1Key, Case1Data),
+ ?line Case1Mac256_3 = crypto:hmac(sha256, Case1Key, Case1Data),
?line m(Case1Exp256, Case1Mac256_1),
?line m(Case1Exp256, Case1Mac256_2),
+ ?line m(Case1Exp256, Case1Mac256_3),
?line Case1Ctx384 = crypto:hmac_init(sha384, Case1Key),
?line Case1Ctx384_2 = crypto:hmac_update(Case1Ctx384, Case1Data),
?line Case1Mac384_1 = crypto:hmac_final(Case1Ctx384_2),
?line Case1Mac384_2 = crypto:sha384_mac(Case1Key, Case1Data),
+ ?line Case1Mac384_3 = crypto:hmac(sha384, Case1Key, Case1Data),
?line m(Case1Exp384, Case1Mac384_1),
?line m(Case1Exp384, Case1Mac384_2),
+ ?line m(Case1Exp384, Case1Mac384_3),
?line Case1Ctx512 = crypto:hmac_init(sha512, Case1Key),
?line Case1Ctx512_2 = crypto:hmac_update(Case1Ctx512, Case1Data),
?line Case1Mac512_1 = crypto:hmac_final(Case1Ctx512_2),
?line Case1Mac512_2 = crypto:sha512_mac(Case1Key, Case1Data),
+ ?line Case1Mac512_3 = crypto:hmac(sha512, Case1Key, Case1Data),
?line m(Case1Exp512, Case1Mac512_1),
?line m(Case1Exp512, Case1Mac512_2),
+ ?line m(Case1Exp512, Case1Mac512_3),
%% Test Case 2
Case2Key = <<"Jefe">>,
@@ -492,29 +661,37 @@ hmac_rfc4231_do() ->
?line Case2Ctx224_2 = crypto:hmac_update(Case2Ctx224, Case2Data),
?line Case2Mac224_1 = crypto:hmac_final(Case2Ctx224_2),
?line Case2Mac224_2 = crypto:sha224_mac(Case2Key, Case2Data),
+ ?line Case2Mac224_3 = crypto:hmac(sha224, Case2Key, Case2Data),
?line m(Case2Exp224, Case2Mac224_1),
?line m(Case2Exp224, Case2Mac224_2),
+ ?line m(Case2Exp224, Case2Mac224_3),
?line Case2Ctx256 = crypto:hmac_init(sha256, Case2Key),
?line Case2Ctx256_2 = crypto:hmac_update(Case2Ctx256, Case2Data),
?line Case2Mac256_1 = crypto:hmac_final(Case2Ctx256_2),
?line Case2Mac256_2 = crypto:sha256_mac(Case2Key, Case2Data),
+ ?line Case2Mac256_3 = crypto:hmac(sha256, Case2Key, Case2Data),
?line m(Case2Exp256, Case2Mac256_1),
?line m(Case2Exp256, Case2Mac256_2),
+ ?line m(Case2Exp256, Case2Mac256_3),
?line Case2Ctx384 = crypto:hmac_init(sha384, Case2Key),
?line Case2Ctx384_2 = crypto:hmac_update(Case2Ctx384, Case2Data),
?line Case2Mac384_1 = crypto:hmac_final(Case2Ctx384_2),
?line Case2Mac384_2 = crypto:sha384_mac(Case2Key, Case2Data),
+ ?line Case2Mac384_3 = crypto:hmac(sha384, Case2Key, Case2Data),
?line m(Case2Exp384, Case2Mac384_1),
?line m(Case2Exp384, Case2Mac384_2),
+ ?line m(Case2Exp384, Case2Mac384_3),
?line Case2Ctx512 = crypto:hmac_init(sha512, Case2Key),
?line Case2Ctx512_2 = crypto:hmac_update(Case2Ctx512, Case2Data),
?line Case2Mac512_1 = crypto:hmac_final(Case2Ctx512_2),
?line Case2Mac512_2 = crypto:sha512_mac(Case2Key, Case2Data),
+ ?line Case2Mac512_3 = crypto:hmac(sha512, Case2Key, Case2Data),
?line m(Case2Exp512, Case2Mac512_1),
?line m(Case2Exp512, Case2Mac512_2),
+ ?line m(Case2Exp512, Case2Mac512_3),
%% Test Case 3
Case3Key = binary:copy(<<16#aa>>, 20),
@@ -535,29 +712,37 @@ hmac_rfc4231_do() ->
?line Case3Ctx224_2 = crypto:hmac_update(Case3Ctx224, Case3Data),
?line Case3Mac224_1 = crypto:hmac_final(Case3Ctx224_2),
?line Case3Mac224_2 = crypto:sha224_mac(Case3Key, Case3Data),
+ ?line Case3Mac224_3 = crypto:hmac(sha224, Case3Key, Case3Data),
?line m(Case3Exp224, Case3Mac224_1),
?line m(Case3Exp224, Case3Mac224_2),
+ ?line m(Case3Exp224, Case3Mac224_3),
?line Case3Ctx256 = crypto:hmac_init(sha256, Case3Key),
?line Case3Ctx256_2 = crypto:hmac_update(Case3Ctx256, Case3Data),
?line Case3Mac256_1 = crypto:hmac_final(Case3Ctx256_2),
?line Case3Mac256_2 = crypto:sha256_mac(Case3Key, Case3Data),
+ ?line Case3Mac256_3 = crypto:hmac(sha256, Case3Key, Case3Data),
?line m(Case3Exp256, Case3Mac256_1),
?line m(Case3Exp256, Case3Mac256_2),
+ ?line m(Case3Exp256, Case3Mac256_3),
?line Case3Ctx384 = crypto:hmac_init(sha384, Case3Key),
?line Case3Ctx384_2 = crypto:hmac_update(Case3Ctx384, Case3Data),
?line Case3Mac384_1 = crypto:hmac_final(Case3Ctx384_2),
?line Case3Mac384_2 = crypto:sha384_mac(Case3Key, Case3Data),
+ ?line Case3Mac384_3 = crypto:hmac(sha384, Case3Key, Case3Data),
?line m(Case3Exp384, Case3Mac384_1),
?line m(Case3Exp384, Case3Mac384_2),
+ ?line m(Case3Exp384, Case3Mac384_3),
?line Case3Ctx512 = crypto:hmac_init(sha512, Case3Key),
?line Case3Ctx512_2 = crypto:hmac_update(Case3Ctx512, Case3Data),
?line Case3Mac512_1 = crypto:hmac_final(Case3Ctx512_2),
?line Case3Mac512_2 = crypto:sha512_mac(Case3Key, Case3Data),
+ ?line Case3Mac512_3 = crypto:hmac(sha512, Case3Key, Case3Data),
?line m(Case3Exp512, Case3Mac512_1),
?line m(Case3Exp512, Case3Mac512_2),
+ ?line m(Case3Exp512, Case3Mac512_3),
%% Test Case 4
Case4Key = list_to_binary(lists:seq(1, 16#19)),
@@ -578,29 +763,81 @@ hmac_rfc4231_do() ->
?line Case4Ctx224_2 = crypto:hmac_update(Case4Ctx224, Case4Data),
?line Case4Mac224_1 = crypto:hmac_final(Case4Ctx224_2),
?line Case4Mac224_2 = crypto:sha224_mac(Case4Key, Case4Data),
+ ?line Case4Mac224_3 = crypto:hmac(sha224, Case4Key, Case4Data),
?line m(Case4Exp224, Case4Mac224_1),
?line m(Case4Exp224, Case4Mac224_2),
+ ?line m(Case4Exp224, Case4Mac224_3),
?line Case4Ctx256 = crypto:hmac_init(sha256, Case4Key),
?line Case4Ctx256_2 = crypto:hmac_update(Case4Ctx256, Case4Data),
?line Case4Mac256_1 = crypto:hmac_final(Case4Ctx256_2),
?line Case4Mac256_2 = crypto:sha256_mac(Case4Key, Case4Data),
+ ?line Case4Mac256_3 = crypto:hmac(sha256, Case4Key, Case4Data),
?line m(Case4Exp256, Case4Mac256_1),
?line m(Case4Exp256, Case4Mac256_2),
+ ?line m(Case4Exp256, Case4Mac256_3),
?line Case4Ctx384 = crypto:hmac_init(sha384, Case4Key),
?line Case4Ctx384_2 = crypto:hmac_update(Case4Ctx384, Case4Data),
?line Case4Mac384_1 = crypto:hmac_final(Case4Ctx384_2),
?line Case4Mac384_2 = crypto:sha384_mac(Case4Key, Case4Data),
+ ?line Case4Mac384_3 = crypto:hmac(sha384, Case4Key, Case4Data),
?line m(Case4Exp384, Case4Mac384_1),
?line m(Case4Exp384, Case4Mac384_2),
+ ?line m(Case4Exp384, Case4Mac384_3),
?line Case4Ctx512 = crypto:hmac_init(sha512, Case4Key),
?line Case4Ctx512_2 = crypto:hmac_update(Case4Ctx512, Case4Data),
?line Case4Mac512_1 = crypto:hmac_final(Case4Ctx512_2),
?line Case4Mac512_2 = crypto:sha512_mac(Case4Key, Case4Data),
+ ?line Case4Mac512_3 = crypto:hmac(sha512, Case4Key, Case4Data),
?line m(Case4Exp512, Case4Mac512_1),
?line m(Case4Exp512, Case4Mac512_2),
+ ?line m(Case4Exp512, Case4Mac512_3),
+
+ %% Test Case 5
+ Case5Key = binary:copy(<<16#0c>>, 20),
+ Case5Data = <<"Test With Truncation">>,
+ Case5Exp224 = hexstr2bin("0e2aea68a90c8d37c988bcdb9fca6fa8"),
+ Case5Exp256 = hexstr2bin("a3b6167473100ee06e0c796c2955552b"),
+ Case5Exp384 = hexstr2bin("3abf34c3503b2a23a46efc619baef897"),
+ Case5Exp512 = hexstr2bin("415fad6271580a531d4179bc891d87a6"),
+
+ ?line Case5Ctx224 = crypto:hmac_init(sha224, Case5Key),
+ ?line Case5Ctx224_2 = crypto:hmac_update(Case5Ctx224, Case5Data),
+ ?line Case5Mac224_1 = crypto:hmac_final_n(Case5Ctx224_2, 16),
+ ?line Case5Mac224_2 = crypto:sha224_mac(Case5Key, Case5Data, 16),
+ ?line Case5Mac224_3 = crypto:hmac(sha224, Case5Key, Case5Data, 16),
+ ?line m(Case5Exp224, Case5Mac224_1),
+ ?line m(Case5Exp224, Case5Mac224_2),
+ ?line m(Case5Exp224, Case5Mac224_3),
+
+ ?line Case5Ctx256 = crypto:hmac_init(sha256, Case5Key),
+ ?line Case5Ctx256_2 = crypto:hmac_update(Case5Ctx256, Case5Data),
+ ?line Case5Mac256_1 = crypto:hmac_final_n(Case5Ctx256_2, 16),
+ ?line Case5Mac256_2 = crypto:sha256_mac(Case5Key, Case5Data, 16),
+ ?line Case5Mac256_3 = crypto:hmac(sha256, Case5Key, Case5Data, 16),
+ ?line m(Case5Exp256, Case5Mac256_1),
+ ?line m(Case5Exp256, Case5Mac256_2),
+ ?line m(Case5Exp256, Case5Mac256_3),
+
+ ?line Case5Ctx384 = crypto:hmac_init(sha384, Case5Key),
+ ?line Case5Ctx384_2 = crypto:hmac_update(Case5Ctx384, Case5Data),
+ ?line Case5Mac384_1 = crypto:hmac_final_n(Case5Ctx384_2, 16),
+ ?line Case5Mac384_2 = crypto:sha384_mac(Case5Key, Case5Data, 16),
+ ?line Case5Mac384_3 = crypto:hmac(sha384, Case5Key, Case5Data, 16),
+ ?line m(Case5Exp384, Case5Mac384_1),
+ ?line m(Case5Exp384, Case5Mac384_2),
+ ?line m(Case5Exp384, Case5Mac384_3),
+
+ ?line Case5Ctx512 = crypto:hmac_init(sha512, Case5Key),
+ ?line Case5Ctx512_2 = crypto:hmac_update(Case5Ctx512, Case5Data),
+ ?line Case5Mac512_1 = crypto:hmac_final_n(Case5Ctx512_2, 16),
+ ?line Case5Mac512_2 = crypto:sha512_mac(Case5Key, Case5Data, 16),
+ ?line Case5Mac512_3 = crypto:hmac(sha512, Case5Key, Case5Data, 16),
+ ?line m(Case5Exp512, Case5Mac512_1),
+ ?line m(Case5Exp512, Case5Mac512_2),
+ ?line m(Case5Exp512, Case5Mac512_3),
%% Test Case 6
Case6Key = binary:copy(<<16#aa>>, 131),
@@ -621,29 +858,37 @@ hmac_rfc4231_do() ->
?line Case6Ctx224_2 = crypto:hmac_update(Case6Ctx224, Case6Data),
?line Case6Mac224_1 = crypto:hmac_final(Case6Ctx224_2),
?line Case6Mac224_2 = crypto:sha224_mac(Case6Key, Case6Data),
+ ?line Case6Mac224_3 = crypto:hmac(sha224, Case6Key, Case6Data),
?line m(Case6Exp224, Case6Mac224_1),
?line m(Case6Exp224, Case6Mac224_2),
+ ?line m(Case6Exp224, Case6Mac224_3),
?line Case6Ctx256 = crypto:hmac_init(sha256, Case6Key),
?line Case6Ctx256_2 = crypto:hmac_update(Case6Ctx256, Case6Data),
?line Case6Mac256_1 = crypto:hmac_final(Case6Ctx256_2),
?line Case6Mac256_2 = crypto:sha256_mac(Case6Key, Case6Data),
+ ?line Case6Mac256_3 = crypto:hmac(sha256, Case6Key, Case6Data),
?line m(Case6Exp256, Case6Mac256_1),
?line m(Case6Exp256, Case6Mac256_2),
+ ?line m(Case6Exp256, Case6Mac256_3),
?line Case6Ctx384 = crypto:hmac_init(sha384, Case6Key),
?line Case6Ctx384_2 = crypto:hmac_update(Case6Ctx384, Case6Data),
?line Case6Mac384_1 = crypto:hmac_final(Case6Ctx384_2),
?line Case6Mac384_2 = crypto:sha384_mac(Case6Key, Case6Data),
+ ?line Case6Mac384_3 = crypto:hmac(sha384, Case6Key, Case6Data),
?line m(Case6Exp384, Case6Mac384_1),
?line m(Case6Exp384, Case6Mac384_2),
+ ?line m(Case6Exp384, Case6Mac384_3),
?line Case6Ctx512 = crypto:hmac_init(sha512, Case6Key),
?line Case6Ctx512_2 = crypto:hmac_update(Case6Ctx512, Case6Data),
?line Case6Mac512_1 = crypto:hmac_final(Case6Ctx512_2),
?line Case6Mac512_2 = crypto:sha512_mac(Case6Key, Case6Data),
+ ?line Case6Mac512_3 = crypto:hmac(sha512, Case6Key, Case6Data),
?line m(Case6Exp512, Case6Mac512_1),
?line m(Case6Exp512, Case6Mac512_2),
+ ?line m(Case6Exp512, Case6Mac512_3),
%% Test Case 7
Case7Key = binary:copy(<<16#aa>>, 131),
@@ -666,29 +911,37 @@ hmac_rfc4231_do() ->
?line Case7Ctx224_2 = crypto:hmac_update(Case7Ctx224, Case7Data),
?line Case7Mac224_1 = crypto:hmac_final(Case7Ctx224_2),
?line Case7Mac224_2 = crypto:sha224_mac(Case7Key, Case7Data),
+ ?line Case7Mac224_3 = crypto:hmac(sha224, Case7Key, Case7Data),
?line m(Case7Exp224, Case7Mac224_1),
?line m(Case7Exp224, Case7Mac224_2),
+ ?line m(Case7Exp224, Case7Mac224_3),
?line Case7Ctx256 = crypto:hmac_init(sha256, Case7Key),
?line Case7Ctx256_2 = crypto:hmac_update(Case7Ctx256, Case7Data),
?line Case7Mac256_1 = crypto:hmac_final(Case7Ctx256_2),
?line Case7Mac256_2 = crypto:sha256_mac(Case7Key, Case7Data),
+ ?line Case7Mac256_3 = crypto:hmac(sha256, Case7Key, Case7Data),
?line m(Case7Exp256, Case7Mac256_1),
?line m(Case7Exp256, Case7Mac256_2),
+ ?line m(Case7Exp256, Case7Mac256_3),
?line Case7Ctx384 = crypto:hmac_init(sha384, Case7Key),
?line Case7Ctx384_2 = crypto:hmac_update(Case7Ctx384, Case7Data),
?line Case7Mac384_1 = crypto:hmac_final(Case7Ctx384_2),
?line Case7Mac384_2 = crypto:sha384_mac(Case7Key, Case7Data),
+ ?line Case7Mac384_3 = crypto:hmac(sha384, Case7Key, Case7Data),
?line m(Case7Exp384, Case7Mac384_1),
?line m(Case7Exp384, Case7Mac384_2),
+ ?line m(Case7Exp384, Case7Mac384_3),
?line Case7Ctx512 = crypto:hmac_init(sha512, Case7Key),
?line Case7Ctx512_2 = crypto:hmac_update(Case7Ctx512, Case7Data),
?line Case7Mac512_1 = crypto:hmac_final(Case7Ctx512_2),
?line Case7Mac512_2 = crypto:sha512_mac(Case7Key, Case7Data),
+ ?line Case7Mac512_3 = crypto:hmac(sha512, Case7Key, Case7Data),
?line m(Case7Exp512, Case7Mac512_1),
- ?line m(Case7Exp512, Case7Mac512_2).
+ ?line m(Case7Exp512, Case7Mac512_2),
+ ?line m(Case7Exp512, Case7Mac512_3).
hmac_update_md5_io(doc) ->
["Generate an MD5 HMAC using hmac_init, hmac_update, and hmac_final. "
@@ -722,7 +975,33 @@ hmac_update_md5_n(Config) when is_list(Config) ->
?line Mac = crypto:hmac_final_n(Ctx3, 12),
?line Exp = crypto:md5_mac_96(Key, lists:flatten([Data, Data2])),
?line m(Exp, Mac).
-
+%%
+%%
+ripemd160(doc) ->
+ ["Generate RIPEMD160 message digests and check the result."];
+ripemd160(suite) ->
+ [];
+ripemd160(Config) when is_list(Config) ->
+ ?line m(crypto:hash(ripemd160,"abc"),
+ hexstr2bin("8EB208F7E05D987A9B044A8E98C6B087F15A0BFC")),
+ ?line m(crypto:hash(ripemd160,"abcdbcdecdefdefgefghfghighijhijkijkljklmklm"
+ "nlmnomnopnopq"),
+ hexstr2bin("12A053384A9C0C88E405A06C27DCF49ADA62EB2B")).
+
+
+%%
+%%
+ripemd160_update(doc) ->
+ ["Generate RIPEMD160 message digests by using ripemd160_init,"
+ "ripemd160_update, and ripemd160_final and check the result."];
+ripemd160_update(suite) ->
+ [];
+ripemd160_update(Config) when is_list(Config) ->
+ ?line Ctx = crypto:hash_init(ripemd160),
+ ?line Ctx1 = crypto:hash_update(Ctx, "abcdbcdecdefdefgefghfghighi"),
+ ?line Ctx2 = crypto:hash_update(Ctx1, "jhijkijkljklmklmnlmnomnopnopq"),
+ ?line m(crypto:hash_final(Ctx2),
+ hexstr2bin("12A053384A9C0C88E405A06C27DCF49ADA62EB2B")).
%%
%%
@@ -746,6 +1025,9 @@ sha256(doc) ->
sha256(suite) ->
[];
sha256(Config) when is_list(Config) ->
+ if_098(fun() -> sha256_do() end).
+
+sha256_do() ->
?line m(crypto:sha256("abc"),
hexstr2bin("BA7816BF8F01CFEA4141"
"40DE5DAE2223B00361A396177A9CB410FF61F20015AD")),
@@ -762,6 +1044,9 @@ sha256_update(doc) ->
sha256_update(suite) ->
[];
sha256_update(Config) when is_list(Config) ->
+ if_098(fun() -> sha256_update_do() end).
+
+sha256_update_do() ->
?line Ctx = crypto:sha256_init(),
?line Ctx1 = crypto:sha256_update(Ctx, "abcdbcdecdefdefgefghfghighi"),
?line Ctx2 = crypto:sha256_update(Ctx1, "jhijkijkljklmklmnlmnomnopnopq"),
@@ -778,6 +1063,9 @@ sha512(doc) ->
sha512(suite) ->
[];
sha512(Config) when is_list(Config) ->
+ if_098(fun() -> sha512_do() end).
+
+sha512_do() ->
?line m(crypto:sha512("abc"),
hexstr2bin("DDAF35A193617ABACC417349AE20413112E6FA4E89A97EA2"
"0A9EEEE64B55D39A2192992A274FC1A836BA3C23A3FEEBBD"
@@ -796,6 +1084,9 @@ sha512_update(doc) ->
sha512_update(suite) ->
[];
sha512_update(Config) when is_list(Config) ->
+ if_098(fun() -> sha512_update_do() end).
+
+sha512_update_do() ->
?line Ctx = crypto:sha512_init(),
?line Ctx1 = crypto:sha512_update(Ctx, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"),
?line Ctx2 = crypto:sha512_update(Ctx1, "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"),
@@ -996,6 +1287,12 @@ des3_cfb(doc) ->
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()
+ end.
+
+des3_cfb_do() ->
?line Key1 = hexstr2bin("0123456789abcdef"),
?line Key2 = hexstr2bin("fedcba9876543210"),
?line Key3 = hexstr2bin("0f2d4b6987a5c3e1"),
@@ -1823,7 +2120,7 @@ worker_loop(N, Config) ->
aes_cfb, aes_cbc, des_cbc_iter, rand_uniform_test, strong_rand_test,
rsa_verify_test, exor_test, rc4_test, rc4_stream_test, mod_exp_test,
hmac_update_md5, hmac_update_sha, hmac_update_sha256, hmac_update_sha512,
- hmac_rfc4231,
+ hmac_rfc2202, hmac_rfc4231,
aes_ctr_stream },
F = element(random:uniform(size(Funcs)),Funcs),
@@ -1959,3 +2256,10 @@ openssl_version() ->
undefined
end.
+if_098(Fun) ->
+ case openssl_version() of
+ V when V < 16#908000 ->
+ {skipped,"OpenSSL version too old"};
+ _ ->
+ Fun()
+ end.
diff --git a/lib/debugger/src/Makefile b/lib/debugger/src/Makefile
index e8b350c0c7..cadde8cd1b 100644
--- a/lib/debugger/src/Makefile
+++ b/lib/debugger/src/Makefile
@@ -112,10 +112,10 @@ clean:
rm -f errs core *~
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
docs:
diff --git a/lib/debugger/src/dbg_debugged.erl b/lib/debugger/src/dbg_debugged.erl
index 4d9ffc4f3b..c21ad486e8 100644
--- a/lib/debugger/src/dbg_debugged.erl
+++ b/lib/debugger/src/dbg_debugged.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -104,7 +104,8 @@ handle_command(Command) ->
reply({apply,M,F,As}) ->
{value, erlang:apply(M,F,As)};
reply({eval,Expr,Bs}) ->
- erl_eval:expr(Expr, Bs). % {value, Value, Bs2}
+ %% Bindings is an orddict (sort them)
+ erl_eval:expr(Expr, lists:sort(Bs)). % {value, Value, Bs2}
%% Demonitor and delete message from inbox
%%
diff --git a/lib/debugger/src/dbg_ieval.erl b/lib/debugger/src/dbg_ieval.erl
index 2e88c35741..3c084c53ac 100644
--- a/lib/debugger/src/dbg_ieval.erl
+++ b/lib/debugger/src/dbg_ieval.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -249,7 +249,7 @@ meta_loop(Debugged, Bs, #ieval{level=Le} = Ieval) ->
{sys, Debugged, {value,Val}} ->
{value, Val, Bs};
{sys, Debugged, {value,Val,Bs2}} ->
- {value, Val, Bs2};
+ {value, Val, merge_bindings(Bs2, Bs, Ieval)};
{sys, Debugged, {exception,{Class,Reason,Stk}}} ->
case get(exit_info) of
@@ -1248,7 +1248,7 @@ if_clauses([], Bs, Ieval) ->
exception(error, if_clause, Bs, Ieval).
%% case_clauses(Value, Clauses, Bindings, Error, Ieval)
-%% Error = try_clause � case_clause
+%% Error = try_clause | case_clause
case_clauses(Val, [{clause,_,[P],G,B}|Cs], Bs0, Error, Ieval) ->
case match(P, Val, Bs0) of
{match,Bs} ->
diff --git a/lib/debugger/src/dbg_ui_trace.erl b/lib/debugger/src/dbg_ui_trace.erl
index d318987f60..8017069c50 100644
--- a/lib/debugger/src/dbg_ui_trace.erl
+++ b/lib/debugger/src/dbg_ui_trace.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -31,10 +31,10 @@
pid, % pid() Debugged process
meta, % pid() Meta process
- status, % {Status,Mod,Line} � {exit,Where,Reason}
- % Status = init � idle | break
- % | wait_break � wait_running
- % � running
+ status, % {Status,Mod,Line} | {exit,Where,Reason}
+ % Status = init | idle | break
+ % | wait_break | wait_running
+ % | running
% Where={Mod,Line} | null
cm, % atom() | undefined Current module
@@ -718,7 +718,7 @@ menus() ->
%% enable(Status) -> [MenuItem]
%% Status = init % when first message from Meta has arrived
-%% | idle | break | exit | wait_break � wait_running | running
+%% | idle | break | exit | wait_break | wait_running | running
enable(init) -> [];
enable(idle) -> ['Stop','Kill'];
enable(break) -> ['Step','Next','Continue','Finish','Skip',
diff --git a/lib/debugger/src/dbg_ui_trace_win.erl b/lib/debugger/src/dbg_ui_trace_win.erl
index 1b439cbf18..beb3fbd71e 100644
--- a/lib/debugger/src/dbg_ui_trace_win.erl
+++ b/lib/debugger/src/dbg_ui_trace_win.erl
@@ -418,8 +418,8 @@ clear_breaks(WinInfo, Mod) ->
%%--------------------------------------------------------------------
%% display(Arg)
%% Arg = idle | {Status,Mod,Line} | {running,Mod}
-%% � {exit,Where,Reason} | {text,Text}
-%% Status = break | wait � Level
+%% | {exit,Where,Reason} | {text,Text}
+%% Status = break | wait | Level
%% Level = int()
%% Mod = atom()
%% Line = integer()
diff --git a/lib/debugger/src/dbg_wx_code.erl b/lib/debugger/src/dbg_wx_code.erl
index 99826d9bdb..9853a5dbae 100644
--- a/lib/debugger/src/dbg_wx_code.erl
+++ b/lib/debugger/src/dbg_wx_code.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -30,6 +30,21 @@
-define(stc, wxStyledTextCtrl).
+%% For wx-2.9 usage
+-ifndef(wxSTC_ERLANG_COMMENT_FUNCTION).
+-define(wxSTC_ERLANG_COMMENT_FUNCTION, 14).
+-define(wxSTC_ERLANG_COMMENT_MODULE, 15).
+-define(wxSTC_ERLANG_COMMENT_DOC, 16).
+-define(wxSTC_ERLANG_COMMENT_DOC_MACRO, 17).
+-define(wxSTC_ERLANG_ATOM_QUOTED, 18).
+-define(wxSTC_ERLANG_MACRO_QUOTED, 19).
+-define(wxSTC_ERLANG_RECORD_QUOTED, 20).
+-define(wxSTC_ERLANG_NODE_NAME_QUOTED, 21).
+-define(wxSTC_ERLANG_BIFS, 22).
+-define(wxSTC_ERLANG_MODULES, 23).
+-define(wxSTC_ERLANG_MODULES_ATT, 24).
+-endif.
+
code_area(Parent) ->
FixedFont = wxFont:new(10, ?wxFONTFAMILY_TELETYPE, ?wxNORMAL, ?wxNORMAL,[]),
%%Ed = wxStyledTextCtrl:new(Parent, [{size, {700, 500}}]),
@@ -58,7 +73,21 @@ code_area(Parent) ->
{?wxSTC_ERLANG_MACRO, {40,144,170}},
{?wxSTC_ERLANG_RECORD, {40,100,20}},
{?wxSTC_ERLANG_SEPARATOR,{0,0,0}},
- {?wxSTC_ERLANG_NODE_NAME,{0,0,0}}],
+ {?wxSTC_ERLANG_NODE_NAME,{0,0,0}},
+ %% Optional 2.9 stuff
+ {?wxSTC_ERLANG_COMMENT_FUNCTION, {160,53,35}},
+ {?wxSTC_ERLANG_COMMENT_MODULE, {160,53,35}},
+ {?wxSTC_ERLANG_COMMENT_DOC, {160,53,35}},
+ {?wxSTC_ERLANG_COMMENT_DOC_MACRO, {160,53,35}},
+ {?wxSTC_ERLANG_ATOM_QUOTED, {0,0,0}},
+ {?wxSTC_ERLANG_MACRO_QUOTED, {40,144,170}},
+ {?wxSTC_ERLANG_RECORD_QUOTED, {40,100,20}},
+ {?wxSTC_ERLANG_NODE_NAME_QUOTED, {0,0,0}},
+ {?wxSTC_ERLANG_BIFS, {130,40,172}},
+ {?wxSTC_ERLANG_MODULES, {64,102,244}},
+ {?wxSTC_ERLANG_MODULES_ATT, {64,102,244}}
+ ],
+
SetStyle = fun({Style, Color}) ->
?stc:styleSetFont(Ed, Style, FixedFont),
?stc:styleSetForeground(Ed, Style, Color)
diff --git a/lib/debugger/src/dbg_wx_filedialog_win.erl b/lib/debugger/src/dbg_wx_filedialog_win.erl
index f109652a70..c8ecb7b5d4 100644
--- a/lib/debugger/src/dbg_wx_filedialog_win.erl
+++ b/lib/debugger/src/dbg_wx_filedialog_win.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -381,7 +381,6 @@ show_completion(Wanted, State = #state{text=TC, win=Win, list=LC, completion=Com
Last = wxTextCtrl:getLastPosition(TC),
wxTextCtrl:setSelection(TC, Start, Last),
destroy_completion(Comp),
- wxWindow:setFocus(TC),
State#state{ptext=Path, completion=undefined};
Paths when Comp =:= undefined ->
{PosX,PosY} = wxListCtrl:getPosition(LC),
@@ -406,14 +405,16 @@ show_completion(Wanted, State = #state{text=TC, win=Win, list=LC, completion=Com
%% wxListBox:connect(LB, command_listbox_doubleclicked),
wxListBox:connect(LB, command_listbox_selected),
wxWindow:show(Temp),
+ %% setFocus does a select all on 2.9 sigh..
+ {Start, Last} = wxTextCtrl:getSelection(TC),
wxWindow:setFocus(TC),
+ wxTextCtrl:setSelection(TC, Start, Last),
State#state{completion = {Temp, LB}, ptext=Wanted};
Paths ->
{_Temp, LB} = Comp,
wxListBox:clear(LB),
Files = [filename:basename(File) || File <- Paths],
- wxListBox:insertItems(LB,Files,0),
- wxWindow:setFocus(TC),
+ Files /= [] andalso wxListBox:insertItems(LB,Files,0),
State#state{ptext=Wanted}
end.
diff --git a/lib/debugger/src/dbg_wx_settings.erl b/lib/debugger/src/dbg_wx_settings.erl
index 3be93c495c..94ecc5781d 100644
--- a/lib/debugger/src/dbg_wx_settings.erl
+++ b/lib/debugger/src/dbg_wx_settings.erl
@@ -49,31 +49,35 @@ save(Win, Pos, SFile) ->
open_win(Win, Pos, SFile, Str, What) ->
{SDir, SFileName} =
- if
- %% If settings are saved for the first time, and to
- %% the default directory HOME/erlang.tools/debugger,
- %% make sure the directory exists, or create it if
- %% desired and possible
- SFile==default -> {default_settings_dir(Win), "NoName.state"};
- true -> {filename:dirname(SFile), filename:basename(SFile)}
- end,
-
+ if
+ %% If settings are saved for the first time, and to
+ %% the default directory HOME/erlang.tools/debugger,
+ %% make sure the directory exists, or create it if
+ %% desired and possible
+ SFile==default -> {default_settings_dir(Win), "NoName.state"};
+ true -> {filename:dirname(SFile), filename:basename(SFile)}
+ end,
+
FD = wxFileDialog:new(Win, [{message,Str},{pos, Pos},
- {defaultDir,SDir},
- {defaultFile,SFileName},
- {wildCard, "*.state"},
- {style,What}]),
+ {defaultDir,SDir},
+ {defaultFile,SFileName},
+ {wildCard, "*.state"},
+ {style,What}]),
case wxFileDialog:showModal(FD) of
- ?wxID_OK ->
- File = wxFileDialog:getFilename(FD),
- Dir = wxFileDialog:getDirectory(FD),
- wxFileDialog:destroy(FD),
- {ok, filename:join(Dir,File)};
- _ ->
- wxFileDialog:destroy(FD),
- cancel
+ ?wxID_OK ->
+ case wxFileDialog:getPaths(FD) of
+ [NewFile] ->
+ wxFileDialog:destroy(FD),
+ {ok, NewFile};
+ _ ->
+ wxFileDialog:destroy(FD),
+ cancel
+ end;
+ _ ->
+ wxFileDialog:destroy(FD),
+ cancel
end.
-
+
default_settings_dir(Win) ->
{ok, [[Home]]} = init:get_argument(home),
DefDir = filename:join([Home, ".erlang_tools", "debugger"]),
diff --git a/lib/debugger/src/dbg_wx_trace.erl b/lib/debugger/src/dbg_wx_trace.erl
index 2fdf39ba5a..0a3cac905f 100644
--- a/lib/debugger/src/dbg_wx_trace.erl
+++ b/lib/debugger/src/dbg_wx_trace.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -32,10 +32,10 @@
pid, % pid() Debugged process
meta, % pid() Meta process
- status, % {Status,Mod,Line} � {exit,Where,Reason}
- % Status = init � idle | break
- % | wait_break � wait_running
- % � running
+ status, % {Status,Mod,Line} | {exit,Where,Reason}
+ % Status = init | idle | break
+ % | wait_break | wait_running
+ % | running
% Where={Mod,Line} | null
cm, % atom() | undefined Current module
@@ -513,7 +513,7 @@ gui_cmd({edit, {Var, Val}}, State) ->
cancel ->
State;
{Var, Term} ->
- Cmd = atom_to_list(Var)++"="++io_lib:format("~p", [Term]),
+ Cmd = atom_to_list(Var)++"="++io_lib:format("~w", [Term]),
gui_cmd({user_command, lists:flatten(Cmd)}, State)
end.
@@ -740,7 +740,7 @@ menus() ->
%% enable(Status) -> [MenuItem]
%% Status = init % when first message from Meta has arrived
-%% | idle | break | exit | wait_break � wait_running | running
+%% | idle | break | exit | wait_break | wait_running | running
enable(init) -> [];
enable(idle) -> ['Stop','Kill'];
enable(break) -> ['Step','Next','Continue','Finish','Skip',
diff --git a/lib/debugger/src/dbg_wx_trace_win.erl b/lib/debugger/src/dbg_wx_trace_win.erl
index 68e8e0b844..8b206ccd78 100644
--- a/lib/debugger/src/dbg_wx_trace_win.erl
+++ b/lib/debugger/src/dbg_wx_trace_win.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -19,7 +19,6 @@
%%
-module(dbg_wx_trace_win).
--compile([{nowarn_deprecated_function,{gs,config,2}}]).
%% External exports
-export([init/0, stop/1]).
@@ -431,8 +430,8 @@ clear_breaks(WinInfo, Mod) ->
%%--------------------------------------------------------------------
%% display(Arg)
%% Arg = idle | {Status,Mod,Line} | {running,Mod}
-%% � {exit,Where,Reason} | {text,Text}
-%% Status = break | wait � Level
+%% | {exit,Where,Reason} | {text,Text}
+%% Status = break | wait | Level
%% Level = int()
%% Mod = atom()
%% Line = integer()
@@ -481,13 +480,9 @@ display(#winInfo{window=Win, sb=Sb},Arg) ->
%% Contents = string()
%% Note: remove_code/2 should not be used for currently shown module.
%%--------------------------------------------------------------------
-is_shown(WinInfo, Mod) ->
- case lists:keyfind(Mod, 1, WinInfo#winInfo.editors) of
- {Mod, Editor} ->
- gs:config(Editor, raise), %% BUGBUG
- {true, WinInfo#winInfo{editor={Mod, Editor}}};
- false -> false
- end.
+is_shown(_WinInfo, _Mod) ->
+ %% Previously cached modules here, nyi so return false
+ false.
show_code(WinInfo = #winInfo{editor={_, Ed}}, Mod, Contents) ->
%% Insert code and update breakpoints, if any
@@ -572,7 +567,7 @@ update_bindings(#winInfo{bind=#sub{out=BA}}, Bs) ->
wx:foldl(fun({Var,Val},Row) ->
wxListCtrl:insertItem(BA, Row, ""),
wxListCtrl:setItem(BA, Row, 0, dbg_wx_win:to_string(Var)),
- wxListCtrl:setItem(BA, Row, 1, dbg_wx_win:to_string("~500P",[Val, 80])),
+ wxListCtrl:setItem(BA, Row, 1, dbg_wx_win:to_string("~99999tP",[Val, 20])),
Row+1
end, 0, Bs),
put(bindings,Bs),
diff --git a/lib/debugger/src/dbg_wx_win.erl b/lib/debugger/src/dbg_wx_win.erl
index faf3cc178f..3cb6edd953 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-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -252,9 +252,9 @@ notify(Win,Message) ->
%%--------------------------------------------------------------------
entry(Parent, Title, Prompt, {Type, Value}) ->
- Ted = wxTextEntryDialog:new(Parent, to_string(Prompt),
- [{caption, to_string(Title)},
- {value, to_string(Value)}]),
+ Ted = wxTextEntryDialog:new(Parent, to_string(Prompt),
+ [{caption, to_string(Title)},
+ {value, to_string("~999999tp",Value)}]),
case wxDialog:showModal(Ted) of
?wxID_OK ->
@@ -306,7 +306,7 @@ to_string([]) -> "";
to_string(List) when is_list(List) ->
List;
to_string(Term) ->
- io_lib:format("~p",[Term]).
+ io_lib:format("~tp",[Term]).
to_string(Format,Args) ->
io_lib:format(Format, Args).
diff --git a/lib/debugger/src/int.erl b/lib/debugger/src/int.erl
index b3a8a07f03..1c9f2eddd1 100644
--- a/lib/debugger/src/int.erl
+++ b/lib/debugger/src/int.erl
@@ -626,18 +626,18 @@ find_src(Beam) ->
find_beam(Mod, Src) ->
SrcDir = filename:dirname(Src),
- BeamFile = packages:last(Mod) ++ code:objfile_extension(),
+ BeamFile = atom_to_list(Mod) ++ code:objfile_extension(),
File = filename:join(SrcDir, BeamFile),
case is_file(File) of
true -> File;
- false -> find_beam_1(Mod, SrcDir)
+ false -> find_beam_1(Mod, BeamFile, SrcDir)
end.
-find_beam_1(Mod, SrcDir) ->
- RootDir = find_root_dir(SrcDir, packages:first(Mod)),
+find_beam_1(Mod, BeamFile, SrcDir) ->
+ RootDir = filename:dirname(SrcDir),
EbinDir = filename:join(RootDir, "ebin"),
CodePath = [EbinDir | code:get_path()],
- BeamFile = to_path(Mod) ++ code:objfile_extension(),
+ BeamFile = atom_to_list(Mod) ++ code:objfile_extension(),
lists:foldl(fun(_, Beam) when is_list(Beam) -> Beam;
(Dir, error) ->
File = filename:join(Dir, BeamFile),
@@ -649,14 +649,6 @@ find_beam_1(Mod, SrcDir) ->
error,
CodePath).
-to_path(X) ->
- filename:join(packages:split(X)).
-
-find_root_dir(Dir, [_|Ss]) ->
- find_root_dir(filename:dirname(Dir), Ss);
-find_root_dir(Dir, []) ->
- filename:dirname(Dir).
-
check_beam(BeamBin) when is_binary(BeamBin) ->
case beam_lib:chunks(BeamBin, [abstract_code,exports]) of
{ok,{_Mod,[{abstract_code,no_abstract_code}|_]}} ->
@@ -711,14 +703,11 @@ scan_module_name_2(_, _) ->
scan_module_name_3(Ts) ->
case erl_parse:parse_form(Ts) of
- {ok, {attribute,_,module,{M,_}}} -> module_atom(M);
- {ok, {attribute,_,module,M}} -> module_atom(M);
+ {ok, {attribute,_,module,{M,_}}} -> M;
+ {ok, {attribute,_,module,M}} -> M;
_ -> error
end.
-module_atom(A) when is_atom(A) -> A;
-module_atom(L) when is_list(L) -> list_to_atom(packages:concat(L)).
-
%%--Stop interpreting modules-----------------------------------------
del_mod(AbsMod, Dist) ->
diff --git a/lib/dialyzer/doc/src/dialyzer.xml b/lib/dialyzer/doc/src/dialyzer.xml
index 4080dfdf77..5e0c9b51e3 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>2011</year>
+ <year>2006</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -288,7 +288,11 @@ Option :: {files, [Filename :: string()]}
| {include_dirs, [DirName :: string()]}
| {output_file, FileName :: string()}
| {output_plt, FileName :: string()}
- | {analysis_type, 'succ_typings' | 'plt_add' | 'plt_build' | 'plt_check' | 'plt_remove'}
+ | {analysis_type, 'succ_typings' |
+ 'plt_add' |
+ 'plt_build' |
+ 'plt_check' |
+ 'plt_remove'}
| {warnings, [WarnOpts]}
| {get_warnings, bool()}
diff --git a/lib/dialyzer/doc/src/dialyzer_chapter.xml b/lib/dialyzer/doc/src/dialyzer_chapter.xml
index d15069991e..be75f1cc65 100644
--- a/lib/dialyzer/doc/src/dialyzer_chapter.xml
+++ b/lib/dialyzer/doc/src/dialyzer_chapter.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2006</year><year>2009</year>
+ <year>2006</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -140,7 +140,9 @@
<code type="none">
- dialyzer --build_plt -r $ERL_TOP/lib/stdlib/ebin $ERL_TOP/lib/kernel/ebin $ERL_TOP/lib/mnesia/ebin
+ dialyzer --build_plt -r $ERL_TOP/lib/stdlib/ebin\
+ $ERL_TOP/lib/kernel/ebin \
+ $ERL_TOP/lib/mnesia/ebin
</code>
<p>Dialyzer will look if there is an environment variable called
diff --git a/lib/dialyzer/doc/src/notes.xml b/lib/dialyzer/doc/src/notes.xml
index 0c1556308c..f485e4d03b 100644
--- a/lib/dialyzer/doc/src/notes.xml
+++ b/lib/dialyzer/doc/src/notes.xml
@@ -31,6 +31,24 @@
<p>This document describes the changes made to the Dialyzer
application.</p>
+<section><title>Dialyzer 2.5.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fix a crash in race condition detection</p> <p>Remove
+ old untested experimental extension</p> <p>Respect
+ {plt_check,false} option when using dialyzer:run/1</p>
+ <p>Fix handling of tuple set remote types appearing in
+ tuple sets</p>
+ <p>
+ Own Id: OTP-10464</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Dialyzer 2.5.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/dialyzer/src/Makefile b/lib/dialyzer/src/Makefile
index 63cc1c98f1..bb2edd419a 100644
--- a/lib/dialyzer/src/Makefile
+++ b/lib/dialyzer/src/Makefile
@@ -108,22 +108,22 @@ clean:
# ----------------------------------------------------
$(EBIN)/dialyzer_cl_parse.$(EMULATOR): dialyzer_cl_parse.erl ../vsn.mk
- erlc -W $(ERL_COMPILE_FLAGS) -DVSN="\"v$(VSN)\"" -o$(EBIN) dialyzer_cl_parse.erl
+ $(erlc_verbose)erlc -W $(ERL_COMPILE_FLAGS) -DVSN="\"v$(VSN)\"" -o$(EBIN) dialyzer_cl_parse.erl
$(EBIN)/dialyzer_plt.$(EMULATOR): dialyzer_plt.erl ../vsn.mk
- erlc -W $(ERL_COMPILE_FLAGS) -DVSN="\"v$(VSN)\"" -o$(EBIN) dialyzer_plt.erl
+ $(erlc_verbose)erlc -W $(ERL_COMPILE_FLAGS) -DVSN="\"v$(VSN)\"" -o$(EBIN) dialyzer_plt.erl
$(EBIN)/dialyzer_gui.$(EMULATOR): dialyzer_gui.erl ../vsn.mk
- erlc -W $(ERL_COMPILE_FLAGS) -DVSN="\"v$(VSN)\"" -o$(EBIN) dialyzer_gui.erl
+ $(erlc_verbose)erlc -W $(ERL_COMPILE_FLAGS) -DVSN="\"v$(VSN)\"" -o$(EBIN) dialyzer_gui.erl
$(EBIN)/dialyzer_gui_wx.$(EMULATOR): dialyzer_gui_wx.erl ../vsn.mk
- erlc -W $(ERL_COMPILE_FLAGS) -DVSN="\"v$(VSN)\"" -o$(EBIN) dialyzer_gui_wx.erl
+ $(erlc_verbose)erlc -W $(ERL_COMPILE_FLAGS) -DVSN="\"v$(VSN)\"" -o$(EBIN) dialyzer_gui_wx.erl
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
# ---------------------------------------------------------------------
# dependencies -- I wish they were somehow automatically generated
diff --git a/lib/dialyzer/src/dialyzer.erl b/lib/dialyzer/src/dialyzer.erl
index d875c45c4a..63c51e219a 100644
--- a/lib/dialyzer/src/dialyzer.erl
+++ b/lib/dialyzer/src/dialyzer.erl
@@ -162,14 +162,17 @@ run(Opts) ->
{error, Msg} ->
throw({dialyzer_error, Msg});
OptsRecord ->
- case cl_check_init(OptsRecord) of
- {ok, ?RET_NOTHING_SUSPICIOUS} ->
- case dialyzer_cl:start(OptsRecord) of
- {?RET_DISCREPANCIES, Warnings} -> Warnings;
- {?RET_NOTHING_SUSPICIOUS, []} -> []
- end;
- {error, ErrorMsg1} ->
- throw({dialyzer_error, ErrorMsg1})
+ case OptsRecord#options.check_plt of
+ true ->
+ case cl_check_init(OptsRecord) of
+ {ok, ?RET_NOTHING_SUSPICIOUS} -> ok;
+ {error, ErrorMsg1} -> throw({dialyzer_error, ErrorMsg1})
+ end;
+ false -> ok
+ end,
+ case dialyzer_cl:start(OptsRecord) of
+ {?RET_DISCREPANCIES, Warnings} -> Warnings;
+ {?RET_NOTHING_SUSPICIOUS, []} -> []
end
catch
throw:{dialyzer_error, ErrorMsg} ->
diff --git a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
index c237d4e0e9..86618a4915 100644
--- a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
+++ b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
@@ -326,13 +326,6 @@ cleanup_callgraph(#analysis_state{plt = InitPlt, parent = Parent,
ModuleDeps = dialyzer_callgraph:module_deps(Callgraph),
send_mod_deps(Parent, ModuleDeps),
{Callgraph1, ExtCalls} = dialyzer_callgraph:remove_external(Callgraph),
- RelevantAPICalls =
- dialyzer_behaviours:get_behaviour_apis([gen_server]),
- BehaviourAPICalls = [Call || {_From, To} = Call <- ExtCalls,
- lists:member(To, RelevantAPICalls)],
- Callgraph2 =
- dialyzer_callgraph:put_behaviour_api_calls(BehaviourAPICalls,
- Callgraph1),
ExtCalls1 = [Call || Call = {_From, To} <- ExtCalls,
not dialyzer_plt:contains_mfa(InitPlt, To)],
{BadCalls1, RealExtCalls} =
@@ -355,7 +348,7 @@ cleanup_callgraph(#analysis_state{plt = InitPlt, parent = Parent,
true ->
send_ext_calls(Parent, lists:usort([To || {_From, To} <- RealExtCalls]))
end,
- Callgraph2.
+ Callgraph1.
compile_src(File, Includes, Defines, Callgraph, CServer, UseContracts) ->
DefaultIncludes = default_includes(filename:dirname(File)),
diff --git a/lib/dialyzer/src/dialyzer_behaviours.erl b/lib/dialyzer/src/dialyzer_behaviours.erl
index b84071b95c..36aef2a37f 100644
--- a/lib/dialyzer/src/dialyzer_behaviours.erl
+++ b/lib/dialyzer/src/dialyzer_behaviours.erl
@@ -30,11 +30,9 @@
-module(dialyzer_behaviours).
--export([check_callbacks/5, get_behaviour_apis/1,
- translate_behaviour_api_call/5, translatable_behaviours/1,
- translate_callgraph/3]).
+-export([check_callbacks/5]).
--export_type([behaviour/0, behaviour_api_dict/0]).
+-export_type([behaviour/0]).
%%--------------------------------------------------------------------
@@ -224,103 +222,3 @@ get_line([]) -> -1.
get_file([{file, File}|_]) -> File;
get_file([_|Tail]) -> get_file(Tail).
-
-%%-----------------------------------------------------------------------------
-
--spec translatable_behaviours(cerl:c_module()) -> behaviour_api_dict().
-
-translatable_behaviours(Tree) ->
- Attrs = cerl:module_attrs(Tree),
- {Behaviours, _BehLines} = get_behaviours(Attrs),
- [{B, Calls} || B <- Behaviours, (Calls = behaviour_api_calls(B)) =/= []].
-
--spec get_behaviour_apis([behaviour()]) -> [mfa()].
-
-get_behaviour_apis(Behaviours) ->
- get_behaviour_apis(Behaviours, []).
-
--spec translate_behaviour_api_call(dialyzer_callgraph:mfa_or_funlbl(),
- [erl_types:erl_type()],
- [dialyzer_races:core_vars()],
- module(),
- behaviour_api_dict()) ->
- {dialyzer_callgraph:mfa_or_funlbl(),
- [erl_types:erl_type()],
- [dialyzer_races:core_vars()]}
- | 'plain_call'.
-
-translate_behaviour_api_call(_Fun, _ArgTypes, _Args, _Module, []) ->
- plain_call;
-translate_behaviour_api_call({Module, Fun, Arity}, ArgTypes, Args,
- CallbackModule, BehApiInfo) ->
- case lists:keyfind(Module, 1, BehApiInfo) of
- false -> plain_call;
- {Module, Calls} ->
- case lists:keyfind({Fun, Arity}, 1, Calls) of
- false -> plain_call;
- {{Fun, Arity}, {CFun, CArity, COrder}} ->
- {{CallbackModule, CFun, CArity},
- [nth_or_0(N, ArgTypes, erl_types:t_any()) || N <-COrder],
- [nth_or_0(N, Args, bypassed) || N <-COrder]}
- end
- end;
-translate_behaviour_api_call(_Fun, _ArgTypes, _Args, _Module, _BehApiInfo) ->
- plain_call.
-
--spec translate_callgraph(behaviour_api_dict(), atom(),
- dialyzer_callgraph:callgraph()) ->
- dialyzer_callgraph:callgraph().
-
-translate_callgraph([{Behaviour,_}|Behaviours], Module, Callgraph) ->
- UsedCalls = [Call || {_From, {M, _F, _A}} = Call <-
- dialyzer_callgraph:get_behaviour_api_calls(Callgraph),
- M =:= Behaviour],
- Calls = [{{Behaviour, API, Arity}, Callback} ||
- {{API, Arity}, Callback} <- behaviour_api_calls(Behaviour)],
- DirectCalls = [{From, {Module, Fun, Arity}} ||
- {From, To} <- UsedCalls,{API, {Fun, Arity, _Ord}} <- Calls,
- To =:= API],
- dialyzer_callgraph:add_edges(DirectCalls, Callgraph),
- translate_callgraph(Behaviours, Module, Callgraph);
-translate_callgraph([], _Module, Callgraph) ->
- Callgraph.
-
-get_behaviour_apis([], Acc) ->
- Acc;
-get_behaviour_apis([Behaviour | Rest], Acc) ->
- MFAs = [{Behaviour, Fun, Arity} ||
- {{Fun, Arity}, _} <- behaviour_api_calls(Behaviour)],
- get_behaviour_apis(Rest, MFAs ++ Acc).
-
-%------------------------------------------------------------------------------
-
-nth_or_0(0, _List, Zero) ->
- Zero;
-nth_or_0(N, List, _Zero) ->
- lists:nth(N, List).
-
-%------------------------------------------------------------------------------
-
--type behaviour_api_dict()::[{behaviour(), behaviour_api_info()}].
--type behaviour_api_info()::[{original_fun(), replacement_fun()}].
--type original_fun()::{atom(), arity()}.
--type replacement_fun()::{atom(), arity(), arg_list()}.
--type arg_list()::[byte()].
-
--spec behaviour_api_calls(behaviour()) -> behaviour_api_info().
-
-behaviour_api_calls(gen_server) ->
- [{{start_link, 3}, {init, 1, [2]}},
- {{start_link, 4}, {init, 1, [3]}},
- {{start, 3}, {init, 1, [2]}},
- {{start, 4}, {init, 1, [3]}},
- {{call, 2}, {handle_call, 3, [2, 0, 0]}},
- {{call, 3}, {handle_call, 3, [2, 0, 0]}},
- {{multi_call, 2}, {handle_call, 3, [2, 0, 0]}},
- {{multi_call, 3}, {handle_call, 3, [3, 0, 0]}},
- {{multi_call, 4}, {handle_call, 3, [3, 0, 0]}},
- {{cast, 2}, {handle_cast, 2, [2, 0]}},
- {{abcast, 2}, {handle_cast, 2, [2, 0]}},
- {{abcast, 3}, {handle_cast, 2, [3, 0]}}];
-behaviour_api_calls(_Other) ->
- [].
diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl
index f40bb2d395..6956850f1a 100644
--- a/lib/dialyzer/src/dialyzer_dataflow.erl
+++ b/lib/dialyzer/src/dialyzer_dataflow.erl
@@ -91,9 +91,8 @@
warning_mode = false :: boolean(),
warnings = [] :: [dial_warning()],
work :: {[_], [_], set()},
- module :: module(),
- behaviour_api_dict = [] ::
- dialyzer_behaviours:behaviour_api_dict()}).
+ module :: module()
+ }).
-record(map, {dict = dict:new() :: dict(),
subst = dict:new() :: dict(),
@@ -135,38 +134,15 @@ get_fun_types(Tree, Plt, Callgraph, Records) ->
analyze_module(Tree, Plt, Callgraph, Records, GetWarnings) ->
debug_pp(Tree, false),
Module = cerl:atom_val(cerl:module_name(Tree)),
- RaceDetection = dialyzer_callgraph:get_race_detection(Callgraph),
- BehaviourTranslations =
- case RaceDetection of
- true -> dialyzer_behaviours:translatable_behaviours(Tree);
- false -> []
- end,
TopFun = cerl:ann_c_fun([{label, top}], [], Tree),
- State =
- state__new(Callgraph, TopFun, Plt, Module, Records, BehaviourTranslations),
+ State = state__new(Callgraph, 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),
-
- %% EXPERIMENTAL: Turn all behaviour API calls into calls to the
- %% respective callback module's functions.
-
- case BehaviourTranslations of
- [] -> dialyzer_races:race(State4);
- Behaviours ->
- Digraph = dialyzer_callgraph:get_digraph(State4#state.callgraph),
- TranslatedCallgraph =
- dialyzer_behaviours:translate_callgraph(Behaviours, Module,
- Callgraph),
- St =
- dialyzer_races:race(State4#state{callgraph = TranslatedCallgraph}),
- FinalCallgraph = dialyzer_callgraph:put_digraph(Digraph,
- St#state.callgraph),
- St#state{callgraph = FinalCallgraph}
- end;
+ dialyzer_races:race(State4);
false ->
State2
end.
@@ -530,21 +506,8 @@ handle_apply_or_call([{TypeOfApply, {Fun, Sig, Contr, LocalRet}}|Left],
Ann = cerl:get_ann(Tree),
File = get_file(Ann),
Line = abs(get_line(Ann)),
-
- %% EXPERIMENTAL: Turn a behaviour's API call into a call to the
- %% respective callback module's function.
-
- Module = State#state.module,
- BehApiDict = State#state.behaviour_api_dict,
- {RealFun, RealArgTypes, RealArgs} =
- case dialyzer_behaviours:translate_behaviour_api_call(Fun, ArgTypes,
- Args, Module,
- BehApiDict) of
- plain_call -> {Fun, ArgTypes, Args};
- BehaviourAPI -> BehaviourAPI
- end,
- dialyzer_races:store_race_call(RealFun, RealArgTypes, RealArgs,
- {File, Line}, State);
+ dialyzer_races:store_race_call(Fun, ArgTypes, Args,
+ {File, Line}, State);
false -> State
end,
FailedConj = any_none([RetWithoutLocal|NewArgTypes]),
@@ -2711,7 +2674,7 @@ determine_mode(Type, Opaques) ->
%%%
%%% ===========================================================================
-state__new(Callgraph, Tree, Plt, Module, Records, BehaviourTranslations) ->
+state__new(Callgraph, Tree, Plt, Module, Records) ->
Opaques = erl_types:module_builtin_opaques(Module) ++
erl_types:t_opaque_from_records(Records),
TreeMap = build_tree_map(Tree),
@@ -2725,7 +2688,7 @@ state__new(Callgraph, Tree, Plt, Module, Records, BehaviourTranslations) ->
#state{callgraph = Callgraph, envs = Env, fun_tab = FunTab, opaques = Opaques,
plt = Plt, races = dialyzer_races:new(), records = Records,
warning_mode = false, warnings = [], work = Work, tree_map = TreeMap,
- module = Module, behaviour_api_dict = BehaviourTranslations}.
+ module = Module}.
state__warning_mode(#state{warning_mode = WM}) ->
WM.
diff --git a/lib/dialyzer/src/dialyzer_races.erl b/lib/dialyzer/src/dialyzer_races.erl
index cdb9f25999..2aa8343bce 100644
--- a/lib/dialyzer/src/dialyzer_races.erl
+++ b/lib/dialyzer/src/dialyzer_races.erl
@@ -1758,7 +1758,10 @@ compare_var_list(Var, VarList, RaceVarMap) ->
ets_list_args(MaybeList) ->
case is_list(MaybeList) of
- true -> [ets_tuple_args(T) || T <- MaybeList];
+ true ->
+ try [ets_tuple_args(T) || T <- MaybeList]
+ catch _:_ -> [?no_label]
+ end;
false -> [ets_tuple_args(MaybeList)]
end.
diff --git a/lib/dialyzer/test/options1_SUITE_data/src/compiler/core_scan.erl b/lib/dialyzer/test/options1_SUITE_data/src/compiler/core_scan.erl
index a97270b9f3..f4e609bf5b 100644
--- a/lib/dialyzer/test/options1_SUITE_data/src/compiler/core_scan.erl
+++ b/lib/dialyzer/test/options1_SUITE_data/src/compiler/core_scan.erl
@@ -1,3 +1,4 @@
+%% -*- coding: utf-8 -*-
%% ``The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
@@ -30,16 +31,16 @@
%% 173 - 176 { - ~ punctuation
%% 177 DEL control
%% 200 - 237 control
-%% 240 - 277 NBSP - � punctuation
-%% 300 - 326 � - � uppercase
-%% 327 � punctuation
-%% 330 - 336 � - � uppercase
-%% 337 - 366 � - � lowercase
-%% 367 � punctuation
-%% 370 - 377 � - � lowercase
+%% 240 - 277 NBSP - ¿ punctuation
+%% 300 - 326 À - Ö uppercase
+%% 327 × punctuation
+%% 330 - 336 Ø - Þ uppercase
+%% 337 - 366 ß - ö lowercase
+%% 367 ÷ punctuation
+%% 370 - 377 ø - ÿ lowercase
%%
%% Many punctuation characters region have special meaning. Must
-%% watch using � \327, bvery close to x \170
+%% watch using × \327, bvery close to x \170
-module(core_scan).
@@ -266,11 +267,11 @@ scan1([C|Cs], Toks, Pos) when C >= $\200, C =< $\240 ->
scan1(Cs, Toks, Pos);
scan1([C|Cs], Toks, Pos) when C >= $a, C =< $z -> %Keywords
scan_key_word(C, Cs, Toks, Pos);
-scan1([C|Cs], Toks, Pos) when C >= $�, C =< $�, C /= $� ->
+scan1([C|Cs], Toks, Pos) when C >= $ß, C =< $ÿ, C /= $÷ ->
scan_key_word(C, Cs, Toks, Pos);
scan1([C|Cs], Toks, Pos) when C >= $A, C =< $Z -> %Variables
scan_variable(C, Cs, Toks, Pos);
-scan1([C|Cs], Toks, Pos) when C >= $�, C =< $�, C /= $� ->
+scan1([C|Cs], Toks, Pos) when C >= $À, C =< $Þ, C /= $× ->
scan_variable(C, Cs, Toks, Pos);
scan1([C|Cs], Toks, Pos) when C >= $0, C =< $9 -> %Numbers
scan_number(C, Cs, Toks, Pos);
@@ -335,9 +336,9 @@ scan_name([], Ncs) ->
{Ncs,[]}.
name_char(C) when C >= $a, C =< $z -> true;
-name_char(C) when C >= $�, C =< $�, C /= $� -> true;
+name_char(C) when C >= $ß, C =< $ÿ, C /= $÷ -> true;
name_char(C) when C >= $A, C =< $Z -> true;
-name_char(C) when C >= $�, C =< $�, C /= $� -> true;
+name_char(C) when C >= $À, C =< $Þ, C /= $× -> true;
name_char(C) when C >= $0, C =< $9 -> true;
name_char($_) -> true;
name_char($@) -> true;
diff --git a/lib/dialyzer/test/options1_SUITE_data/src/compiler/sys_pre_expand.erl b/lib/dialyzer/test/options1_SUITE_data/src/compiler/sys_pre_expand.erl
index 08bc6cb147..41b7cb248d 100644
--- a/lib/dialyzer/test/options1_SUITE_data/src/compiler/sys_pre_expand.erl
+++ b/lib/dialyzer/test/options1_SUITE_data/src/compiler/sys_pre_expand.erl
@@ -149,14 +149,12 @@ forms([], St) -> {[],St}.
%% Process an attribute, this just affects the state.
attribute(module, {Module, As}, St) ->
- M = package_to_string(Module),
- St#expand{module=list_to_atom(M),
- package = packages:strip_last(M),
+ true = is_atom(Module),
+ St#expand{module=Module,
parameters=As};
attribute(module, Module, St) ->
- M = package_to_string(Module),
- St#expand{module=list_to_atom(M),
- package = packages:strip_last(M)};
+ true = is_atom(Module),
+ St#expand{module=Module};
attribute(export, Es, St) ->
St#expand{exports=union(from_list(Es), St#expand.exports)};
attribute(import, Is, St) ->
@@ -226,8 +224,6 @@ pattern({tuple,Line,Ps}, St0) ->
%%pattern({struct,Line,Tag,Ps}, St0) ->
%% {TPs,TPsvs,St1} = pattern_list(Ps, St0),
%% {{tuple,Line,[{atom,Line,Tag}|TPs]},TPsvs,St1};
-pattern({record_field,_,_,_}=M, St) ->
- {expand_package(M, St), [], [], St}; % must be a package name
pattern({record_index,Line,Name,Field}, St) ->
{index_expr(Line, Field, Name, record_fields(Name, St)),[],[],St};
pattern({record,Line,Name,Pfs}, St0) ->
@@ -401,8 +397,6 @@ expr({tuple,Line,Es0}, Vs, St0) ->
%%expr({struct,Line,Tag,Es0}, Vs, St0) ->
%% {Es1,Esvs,Esus,St1} = expr_list(Es0, Vs, St0),
%% {{tuple,Line,[{atom,Line,Tag}|Es1]},Esvs,Esus,St1};
-expr({record_field,_,_,_}=M, _Vs, St) ->
- {expand_package(M, St), [], [], St}; % must be a package name
expr({record_index,Line,Name,F}, Vs, St) ->
I = index_expr(Line, F, Name, record_fields(Name, St)),
expr(I, Vs, St);
@@ -483,10 +477,7 @@ expr({call,Line,{atom,La,N},As0}, Vs, St0) ->
end
end
end;
-expr({call,Line,{record_field,_,_,_}=M,As0}, Vs, St0) ->
- expr({call,Line,expand_package(M, St0),As0}, Vs, St0);
-expr({call,Line,{remote,Lr,M,F},As0}, Vs, St0) ->
- M1 = expand_package(M, St0),
+expr({call,Line,{remote,Lr,M1,F},As0}, Vs, St0) ->
{[M2,F1|As1],Asvs,Asus,St1} = expr_list([M1,F|As0], Vs, St0),
{{call,Line,{remote,Lr,M2,F1},As1},Asvs,Asus,St1};
expr({call,Line,{tuple,_,[{atom,_,_}=M,{atom,_,_}=F]},As}, Vs, St) ->
@@ -922,32 +913,6 @@ string_to_conses(Line, Cs, Tail) ->
foldr(fun (C, T) -> {cons,Line,{char,Line,C},T} end, Tail, Cs).
-%% In syntax trees, module/package names are atoms or lists of atoms.
-
-package_to_string(A) when atom(A) -> atom_to_list(A);
-package_to_string(L) when list(L) -> packages:concat(L).
-
-expand_package({atom,L,A} = M, St) ->
- case dict:find(A, St#expand.mod_imports) of
- {ok, A1} ->
- {atom,L,A1};
- error ->
- case packages:is_segmented(A) of
- true ->
- M;
- false ->
- M1 = packages:concat(St#expand.package, A),
- {atom,L,list_to_atom(M1)}
- end
- end;
-expand_package(M, _St) ->
- case erl_parse:package_segments(M) of
- error ->
- M;
- M1 ->
- {atom,element(2,M),list_to_atom(package_to_string(M1))}
- end.
-
%% Create a case-switch on true/false, generating badarg for all other
%% values.
@@ -1005,15 +970,10 @@ new_in_all(Before, Region) ->
%% Handle import declarations and est for imported functions. No need to
%% check when building imports as code is correct.
-import({Mod0,Fs}, St) ->
- Mod = list_to_atom(package_to_string(Mod0)),
+import({Mod,Fs}, St) ->
+ true = is_atom(Mod),
Mfs = from_list(Fs),
- St#expand{imports=add_imports(Mod, Mfs, St#expand.imports)};
-import(Mod0, St) ->
- Mod = package_to_string(Mod0),
- Key = list_to_atom(packages:last(Mod)),
- St#expand{mod_imports=dict:store(Key, list_to_atom(Mod),
- St#expand.mod_imports)}.
+ St#expand{imports=add_imports(Mod, Mfs, St#expand.imports)}.
add_imports(Mod, [F|Fs], Is) ->
add_imports(Mod, Fs, orddict:store(F, Mod, Is));
diff --git a/lib/dialyzer/test/r9c_SUITE_data/results/mnesia b/lib/dialyzer/test/r9c_SUITE_data/results/mnesia
index b397d37523..1aac46f5b2 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/results/mnesia
+++ b/lib/dialyzer/test/r9c_SUITE_data/results/mnesia
@@ -1,13 +1,12 @@
mnesia.erl:1319: Guard test size(Spec::[{_,_,_},...]) can never succeed
mnesia.erl:1498: The call mnesia:bad_info_reply(Tab::atom(),Item::'type') will never return since it differs in the 2nd argument from the success typing arguments: (atom(),'memory' | 'size')
-mnesia.erl:331: Function mod2abs/1 has no local return
mnesia_backup.erl:49: Callback info about the mnesia_backup behaviour is not available
mnesia_bup.erl:111: The created fun has no local return
mnesia_bup.erl:574: Function fallback_receiver/2 has no local return
mnesia_bup.erl:967: Function uninstall_fallback_master/2 has no local return
mnesia_checkpoint.erl:1014: The variable Error can never match since previous clauses completely covered the type {'ok',#checkpoint_args{nodes::[any()],retainers::[any(),...]}}
-mnesia_checkpoint.erl:894: The call sys:handle_system_msg(Msg::any(),From::any(),'no_parent','mnesia_checkpoint',[],Cp::#checkpoint_args{}) breaks the contract (Msg,From,Parent,Module,Debug,Misc) -> Void when is_subtype(Msg,term()), is_subtype(From,{pid(),Tag::_}), is_subtype(Parent,pid()), is_subtype(Module,module()), is_subtype(Debug,[dbg_opt()]), is_subtype(Misc,term()), is_subtype(Void,term())
+mnesia_checkpoint.erl:894: The call sys:handle_system_msg(Msg::any(),From::any(),'no_parent','mnesia_checkpoint',[],Cp::#checkpoint_args{}) breaks the contract (Msg,From,Parent,Module,Debug,Misc) -> no_return() when is_subtype(Msg,term()), is_subtype(From,{pid(),Tag::_}), is_subtype(Parent,pid()), is_subtype(Module,module()), is_subtype(Debug,[dbg_opt()]), is_subtype(Misc,term())
mnesia_controller.erl:1666: The variable Tab can never match since previous clauses completely covered the type [any()]
mnesia_controller.erl:1679: The pattern {'stop', Reason, Reply, State2} can never match the type {'noreply',_} | {'reply',_,_} | {'stop','shutdown',#state{}}
mnesia_controller.erl:1685: The pattern {'noreply', State2, _Timeout} can never match the type {'reply',_,_}
diff --git a/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_check.erl b/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_check.erl
index 2f0ada122e..4335d8efae 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_check.erl
+++ b/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_check.erl
@@ -4599,7 +4599,7 @@ get_simple_table_info1(S,#'ComponentType'{typespec=TS},[],Path) ->
%% o.w. the asn1 code is wrong.
#type{def=OCFT,constraint=Cnstr} = TS,
case Cnstr of
- [{simpletable,_OSRef}]�->
+ [{simpletable,_OSRef}] ->
#'ObjectClassFieldType'{classname=ClRef,
class=ObjectClass,
fieldname=FieldName} = OCFT,
diff --git a/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen.erl b/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen.erl
index 5d2f7a13bd..5b33be9eff 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen.erl
+++ b/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen.erl
@@ -148,7 +148,7 @@ pgen_partial_inc_dec(Erules,Module) ->
% io:format("Start partial incomplete decode gen?~n"),
case asn1ct:get_gen_state_field(inc_type_pattern) of
undefined ->
-% io:format("Partial incomplete decode gen not started:�~w~n",[asn1ct:get_gen_state_field(active)]),
+% io:format("Partial incomplete decode gen not started: ~w~n",[asn1ct:get_gen_state_field(active)]),
ok;
% [] ->
% ok;
@@ -295,7 +295,7 @@ gen_part_decode_funcs([_H|T],N) ->
gen_part_decode_funcs([],N) ->
if
N > 0 ->
- .emit([".",nl]);
+ emit([".",nl]);
true ->
ok
end.
diff --git a/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1rt_ber_bin.erl b/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1rt_ber_bin.erl
index 6064515a7e..b0786200fc 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1rt_ber_bin.erl
+++ b/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1rt_ber_bin.erl
@@ -276,7 +276,7 @@ encode_tag_val({Class, Form, TagNo}) ->
<<(Class bsr 6):2, (Form bsr 5):1, 31:5,BinOct/binary>>;
%% asumes whole correct tag bitpattern, multiple of 8
-encode_tag_val(Tag) when (Tag =< 255) -> Tag; %% anv�nds denna funktion??!!
+encode_tag_val(Tag) when (Tag =< 255) -> Tag; %% is this function used??!!
%% asumes correct bitpattern of 0-5
encode_tag_val(Tag) -> encode_tag_val2(Tag,[]).
diff --git a/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1rt_ber_bin_v2.erl b/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1rt_ber_bin_v2.erl
index 50a91cf201..2f25e35cd3 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1rt_ber_bin_v2.erl
+++ b/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1rt_ber_bin_v2.erl
@@ -531,7 +531,7 @@ encode_tag_val({Class, Form, TagNo}) ->
<<(Class bsr 6):2, (Form bsr 5):1, 31:5,BinOct/binary>>;
%% asumes whole correct tag bitpattern, multiple of 8
-encode_tag_val(Tag) when (Tag =< 255) -> Tag; %% anv�nds denna funktion??!!
+encode_tag_val(Tag) when (Tag =< 255) -> Tag; %% is this function used??!!
%% asumes correct bitpattern of 0-5
encode_tag_val(Tag) -> encode_tag_val2(Tag,[]).
diff --git a/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1rt_per_bin_rt2ct.erl b/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1rt_per_bin_rt2ct.erl
index 9f02ad4466..4781c81955 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1rt_per_bin_rt2ct.erl
+++ b/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1rt_per_bin_rt2ct.erl
@@ -1198,7 +1198,7 @@ encode_bin_bit_string(C,UnusedAndBin={_,_},NamedBitList) ->
% case get_constraint(C,'SizeConstraint') of
% 0 ->
-% []; % borde avg�ras i compile-time
+% []; % should be dont in compile time
% V when integer(V),V=<16 ->
% {Unused2,Bin2} = pad_list(V,UnusedAndBin1),
% <<BitVal:V,_:Unused2>> = Bin2,
diff --git a/lib/dialyzer/test/race_SUITE_data/results/ets_insert_args10 b/lib/dialyzer/test/race_SUITE_data/results/ets_insert_args10
new file mode 100644
index 0000000000..c3c9b12bdd
--- /dev/null
+++ b/lib/dialyzer/test/race_SUITE_data/results/ets_insert_args10
@@ -0,0 +1,2 @@
+
+ets_insert_args10.erl:9: The call ets:insert(T::'foo',[{'counter',number()},...]) might have an unintended effect due to a possible race condition caused by its combination with the ets:lookup(T::'foo','counter') call in ets_insert_args10.erl on line 8
diff --git a/lib/dialyzer/test/race_SUITE_data/src/ets_insert_args10.erl b/lib/dialyzer/test/race_SUITE_data/src/ets_insert_args10.erl
new file mode 100644
index 0000000000..c897a34af0
--- /dev/null
+++ b/lib/dialyzer/test/race_SUITE_data/src/ets_insert_args10.erl
@@ -0,0 +1,19 @@
+%% This tests the presence of possible races due to an ets:lookup/ets:insert
+%% combination. It takes into account the argument types of the calls.
+
+-module(ets_insert_args10).
+-export([start/0]).
+
+start() ->
+ F = fun(T) -> [{_, N}] = ets:lookup(T, counter),
+ ets:insert(T, [{counter, N+1}])
+ end,
+ io:format("Created ~w\n", [ets:new(foo, [named_table, public])]),
+ A = {counter, 0},
+ B = [],
+ ets:insert(foo, [A|B]),
+ io:format("Inserted ~w\n", [{counter, 0}]),
+ F(foo),
+ io:format("Update complete\n", []),
+ ObjectList = ets:lookup(foo, counter),
+ io:format("Counter: ~w\n", [ObjectList]).
diff --git a/lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes b/lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes
index 8dc0361b0d..4850f3ff0c 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes
+++ b/lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes
@@ -6,7 +6,7 @@ contracts_with_subtypes.erl:109: The call contracts_with_subtypes:rec_arg({'b',{
contracts_with_subtypes.erl:110: The call contracts_with_subtypes:rec_arg({'a',{'b',{'a','b'}}}) breaks the contract (Arg) -> 'ok' when is_subtype(Arg,{'a',A} | {'b',B}), is_subtype(A,'a' | {'b',B}), is_subtype(B,'b' | {'a',A})
contracts_with_subtypes.erl:111: The call contracts_with_subtypes:rec_arg({'b',{'a',{'b','a'}}}) breaks the contract (Arg) -> 'ok' when is_subtype(Arg,{'a',A} | {'b',B}), is_subtype(A,'a' | {'b',B}), is_subtype(B,'b' | {'a',A})
contracts_with_subtypes.erl:142: The pattern 1 can never match the type binary() | string()
-contracts_with_subtypes.erl:145: The pattern 'alpha' can never match the type {'ok',X} | {'ok',X,binary() | string()}
+contracts_with_subtypes.erl:145: The pattern 'alpha' can never match the type {'ok',_} | {'ok',_,binary() | string()}
contracts_with_subtypes.erl:147: The pattern 42 can never match the type {'ok',_} | {'ok',_,binary() | string()}
contracts_with_subtypes.erl:163: The pattern 'alpha' can never match the type {'ok',X}
contracts_with_subtypes.erl:165: The pattern 42 can never match the type {'ok',X}
diff --git a/lib/dialyzer/test/small_SUITE_data/results/port_info_test b/lib/dialyzer/test/small_SUITE_data/results/port_info_test
index 863a3d61df..53d20a415b 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/port_info_test
+++ b/lib/dialyzer/test/small_SUITE_data/results/port_info_test
@@ -1,7 +1,7 @@
port_info_test.erl:10: The pattern {'connected', 42} can never match the type 'undefined' | {'connected',pid()}
-port_info_test.erl:14: The pattern {'registered_name', "42"} can never match the type 'undefined' | {'registered_name',atom()}
+port_info_test.erl:14: The pattern {'registered_name', "42"} can never match the type 'undefined' | [] | {'registered_name',atom()}
port_info_test.erl:19: The pattern {'output', 42} can never match the type 'undefined' | {'connected',pid()}
port_info_test.erl:24: Guard test 'links' =:= Atom::'connected' can never succeed
-port_info_test.erl:28: The pattern {'gazonk', _} can never match the type 'undefined' | {'connected' | 'id' | 'input' | 'links' | 'name' | 'os_pid' | 'output' | 'registered_name',atom() | pid() | [pid() | char()] | integer()}
+port_info_test.erl:28: The pattern {'gazonk', _} can never match the type 'undefined' | [] | {'connected' | 'id' | 'input' | 'links' | 'locking' | 'memory' | 'monitors' | 'name' | 'os_pid' | 'output' | 'parallelism' | 'queue_size' | 'registered_name',atom() | pid() | [pid() | char() | {'process',pid()}] | non_neg_integer()}
port_info_test.erl:32: The pattern {'os_pid', "42"} can never match the type 'undefined' | {'os_pid','undefined' | non_neg_integer()}
diff --git a/lib/dialyzer/test/small_SUITE_data/results/record_creation_diffs b/lib/dialyzer/test/small_SUITE_data/results/record_creation_diffs
new file mode 100644
index 0000000000..f00c4b10ff
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/record_creation_diffs
@@ -0,0 +1,3 @@
+
+record_creation_diffs.erl:10: Function foo/1 has no local return
+record_creation_diffs.erl:11: Record construction #bar{some_list::{'this','is','a','tuple'}} violates the declared type of field some_list::'undefined' | [any()]
diff --git a/lib/dialyzer/test/small_SUITE_data/src/comm_layer/comm_connection.erl b/lib/dialyzer/test/small_SUITE_data/src/comm_layer/comm_connection.erl
index 48cc50ae21..5a8f9710d6 100644
--- a/lib/dialyzer/test/small_SUITE_data/src/comm_layer/comm_connection.erl
+++ b/lib/dialyzer/test/small_SUITE_data/src/comm_layer/comm_connection.erl
@@ -1,4 +1,5 @@
-% Copyright 2008 Konrad-Zuse-Zentrum f�r Informationstechnik Berlin
+%% -*- coding: utf-8 -*-
+% Copyright 2008 Konrad-Zuse-Zentrum für Informationstechnik Berlin
%
% Licensed under the Apache License, Version 2.0 (the "License");
% you may not use this file except in compliance with the License.
@@ -21,7 +22,7 @@
%%% Created : 18 Apr 2008 by Thorsten Schuett <[email protected]>
%%%-------------------------------------------------------------------
%% @author Thorsten Schuett <[email protected]>
-%% @copyright 2008 Konrad-Zuse-Zentrum f�r Informationstechnik Berlin
+%% @copyright 2008 Konrad-Zuse-Zentrum für Informationstechnik Berlin
%% @version $Id $
-module(comm_layer_dir.comm_connection).
diff --git a/lib/dialyzer/test/small_SUITE_data/src/comm_layer/comm_port.erl b/lib/dialyzer/test/small_SUITE_data/src/comm_layer/comm_port.erl
index e8169b4673..d9fcb5e625 100644
--- a/lib/dialyzer/test/small_SUITE_data/src/comm_layer/comm_port.erl
+++ b/lib/dialyzer/test/small_SUITE_data/src/comm_layer/comm_port.erl
@@ -1,4 +1,5 @@
-% Copyright 2008 Konrad-Zuse-Zentrum f�r Informationstechnik Berlin
+%% -*- coding: utf-8 -*-
+% Copyright 2008 Konrad-Zuse-Zentrum für Informationstechnik Berlin
%
% Licensed under the Apache License, Version 2.0 (the "License");
% you may not use this file except in compliance with the License.
@@ -20,7 +21,7 @@
%%% Created : 18 Apr 2008 by Thorsten Schuett <[email protected]>
%%%-------------------------------------------------------------------
%% @author Thorsten Schuett <[email protected]>
-%% @copyright 2008 Konrad-Zuse-Zentrum f�r Informationstechnik Berlin
+%% @copyright 2008 Konrad-Zuse-Zentrum für Informationstechnik Berlin
%% @version $Id $
-module(comm_layer_dir.comm_port).
diff --git a/lib/dialyzer/test/small_SUITE_data/src/record_creation_diffs.erl b/lib/dialyzer/test/small_SUITE_data/src/record_creation_diffs.erl
new file mode 100644
index 0000000000..e813459f8e
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/record_creation_diffs.erl
@@ -0,0 +1,11 @@
+-module(record_creation_diffs).
+
+-export([foo/1]).
+
+-record(bar, {
+ some_atom :: atom(),
+ some_list :: list()
+ }).
+
+foo(Input) ->
+ #bar{some_atom = Input, some_list = {this,is,a,tuple}}.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/remote_tuple_set.erl b/lib/dialyzer/test/small_SUITE_data/src/remote_tuple_set.erl
new file mode 100644
index 0000000000..6c440ed04c
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/remote_tuple_set.erl
@@ -0,0 +1,8 @@
+-module(remote_tuple_set).
+
+-export([parse_cidr/0]).
+
+-spec parse_cidr() -> {inet:address_family(),1,2} | {error}.
+
+parse_cidr() ->
+ {inet,1,2}.
diff --git a/lib/dialyzer/vsn.mk b/lib/dialyzer/vsn.mk
index 64d05156b1..f344fe0604 100644
--- a/lib/dialyzer/vsn.mk
+++ b/lib/dialyzer/vsn.mk
@@ -1 +1 @@
-DIALYZER_VSN = 2.5.2
+DIALYZER_VSN = 2.5.3
diff --git a/lib/diameter/.gitignore b/lib/diameter/.gitignore
index 5afcbedc23..8b13789179 100644
--- a/lib/diameter/.gitignore
+++ b/lib/diameter/.gitignore
@@ -1,58 +1 @@
-# Match at any level.
-*~
-autom4te.cache
-
-# Compiler derivatives
-#
-# Do not use too creative wildcards.
-# Those might ignore files that should not be ignored.
-
-i686-pc-linux-gnu
-x86_64-unknown-linux-gnu
-i386-apple-darwin[0-9]*.[0-9]*.[0-9]*
-sparc-sun-solaris[0-9]*.[0-9]*
-i386-pc-solaris[0-9]*.[0-9]*
-i386-unknown-freebsd[0-9]*.[0-9]*
-tile-tilera-linux-gnu
-powerpc-unknown-linux-gnu
-
-# Mac OS X
-a.out.dSYM/
-
-# Anchored from $DIAMETER_TOP
-/config.log
-/config.status
-
-/Makefile
-/configure
-
-
-# General patterns for applications in lib.
-#
-# Assume that all test/Emakefiles are generated.
-#
-# Any application with a checked-in test/Emakefile should
-# use a negative pattern in its own .gitignore.
-
-#
-# Files generated by configure.
-#
-
-/configure
-/config.log
-/config.status
-
-
-#
-# Generated documentation. (ie. not doc/src)
-#
-
-/doc/[^s]*
-
-
-#
-# Files generated when building/running tests
-#
-
-/test/*.log
diff --git a/lib/diameter/Makefile b/lib/diameter/Makefile
new file mode 100644
index 0000000000..9961d627cf
--- /dev/null
+++ b/lib/diameter/Makefile
@@ -0,0 +1,32 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2010-2012. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+include vsn.mk
+include subdirs.mk
+
+SUB_DIRECTORIES = $(SUB_DIRS) doc/src
+SPECIAL_TARGETS =
+
+include $(ERL_TOP)/make/otp_subdir.mk
+
+info:
+ @echo "APP_VSN = $(APP_VSN)"
+
+.PHONY: info
diff --git a/lib/diameter/Makefile.in b/lib/diameter/Makefile.in
deleted file mode 100644
index cf38c26045..0000000000
--- a/lib/diameter/Makefile.in
+++ /dev/null
@@ -1,88 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2010-2011. All Rights Reserved.
-#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
-#
-# %CopyrightEnd%
-
-ifneq ($(ERL_TOP),)
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-else
-include $(DIAMETER_TOP)/make/target.mk
-include $(DIAMETER_TOP)/make/$(TARGET)/rules.mk
-endif
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include vsn.mk
-VSN=$(DIAMETER_VSN)
-
-DIAMETER_TOP = @DIAMETER_TOP@
-
-
-# ----------------------------------------------------
-# Common Macros
-# ----------------------------------------------------
-
-include subdirs.mk
-
-SUB_DIRECTORIES = $(SUB_DIRS) doc/src
-
-SPECIAL_TARGETS =
-
-ifneq ($(ERL_TOP),)
-ifneq ($(PREFIX),)
-CONFIGURE_OPTS += --prefix=$(PREFIX)
-endif
-endif
-
-
-# ----------------------------------------------------
-# Default Subdir Targets
-# ----------------------------------------------------
-ifneq ($(ERL_TOP),)
-include $(ERL_TOP)/make/otp_subdir.mk
-else
-include $(DIAMETER_TOP)/make/subdir.mk
-endif
-
-.PHONY: reconf conf info version dialyzer
-
-reconf:
- autoconf
-
-conf: do_configure
-
-do_configure: configure
- ./configure $(CONFIGURE_OPTS)
-
-configure: configure.in
- autoconf
-
-info:
- @echo "APP_VSN: $(APP_VSN)"
- @echo "DIAMETER_VSN: $(DIAMETER_VSN)"
-
-version:
- @echo "$(VSN)"
-
-
-dialyzer:
- (cd ./ebin; \
- dialyzer --build_plt \
- --output_plt ../priv/diameter.plt \
- -r ../../diameter/ebin \
- --verbose)
diff --git a/lib/diameter/aclocal.m4 b/lib/diameter/aclocal.m4
deleted file mode 100644
index 2abb47dba2..0000000000
--- a/lib/diameter/aclocal.m4
+++ /dev/null
@@ -1,65 +0,0 @@
-dnl
-dnl %CopyrightBegin%
-dnl
-dnl Copyright Ericsson AB 1998-2011. All Rights Reserved.
-dnl
-dnl The contents of this file are subject to the Erlang Public License,
-dnl Version 1.1, (the "License"); you may not use this file except in
-dnl compliance with the License. You should have received a copy of the
-dnl Erlang Public License along with this software. If not, it can be
-dnl retrieved online at http://www.erlang.org/.
-dnl
-dnl Software distributed under the License is distributed on an "AS IS"
-dnl basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-dnl the License for the specific language governing rights and limitations
-dnl under the License.
-dnl
-dnl %CopyrightEnd%
-dnl
-
-dnl
-dnl aclocal.m4
-dnl
-dnl Local macros used in configure.in. The Local Macros which
-dnl could/should be part of autoconf are prefixed LM_, macros specific
-dnl to the Erlang system are prefixed ERL_.
-dnl
-
-dnl ----------------------------------------------------------------------
-dnl
-dnl LM_PROG_INSTALL_DIR
-dnl
-dnl Figure out how to create directories with parents.
-dnl (In my opinion INSTALL_DIR is a bad name, MKSUBDIRS or something is better)
-dnl
-dnl We prefer 'install -d', but use 'mkdir -p' if it exists.
-dnl If none of these methods works, we give up.
-dnl
-
-
-AC_DEFUN(LM_PROG_INSTALL_DIR,
-[AC_CACHE_CHECK(how to create a directory including parents,
-ac_cv_prog_mkdir_p,
-[
-temp_name_base=config.$$
-temp_name=$temp_name_base/x/y/z
-$INSTALL -d $temp_name >/dev/null 2>&1
-ac_cv_prog_mkdir_p=none
-if test -d $temp_name; then
- ac_cv_prog_mkdir_p="$INSTALL -d"
-else
- mkdir -p $temp_name >/dev/null 2>&1
- if test -d $temp_name; then
- ac_cv_prog_mkdir_p="mkdir -p"
- fi
-fi
-rm -fr $temp_name_base
-])
-
-case "${ac_cv_prog_mkdir_p}" in
- none) AC_MSG_ERROR(don't know how create directories with parents) ;;
- *) INSTALL_DIR="$ac_cv_prog_mkdir_p" AC_SUBST(INSTALL_DIR) ;;
-esac
-])
-
-
diff --git a/lib/diameter/autoconf/config.guess b/lib/diameter/autoconf/config.guess
deleted file mode 100755
index 38a833903b..0000000000
--- a/lib/diameter/autoconf/config.guess
+++ /dev/null
@@ -1,1519 +0,0 @@
-#! /bin/sh
-# Attempt to guess a canonical system name.
-# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
-# Inc.
-
-timestamp='2007-05-17'
-
-# This file is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
-# 02110-1301, USA.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-
-# Originally written by Per Bothner <[email protected]>.
-# Please send patches to <[email protected]>. Submit a context
-# diff and a properly formatted ChangeLog entry.
-#
-# This script attempts to guess a canonical system name similar to
-# config.sub. If it succeeds, it prints the system name on stdout, and
-# exits with 0. Otherwise, it exits with 1.
-#
-# The plan is that this can be called by configure scripts if you
-# don't specify an explicit build system type.
-
-me=`echo "$0" | sed -e 's,.*/,,'`
-
-usage="\
-Usage: $0 [OPTION]
-
-Output the configuration name of the system \`$me' is run on.
-
-Operation modes:
- -h, --help print this help, then exit
- -t, --time-stamp print date of last modification, then exit
- -v, --version print version number, then exit
-
-Report bugs and patches to <[email protected]>."
-
-version="\
-GNU config.guess ($timestamp)
-
-Originally written by Per Bothner.
-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
-Free Software Foundation, Inc.
-
-This is free software; see the source for copying conditions. There is NO
-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
-
-help="
-Try \`$me --help' for more information."
-
-# Parse command line
-while test $# -gt 0 ; do
- case $1 in
- --time-stamp | --time* | -t )
- echo "$timestamp" ; exit ;;
- --version | -v )
- echo "$version" ; exit ;;
- --help | --h* | -h )
- echo "$usage"; exit ;;
- -- ) # Stop option processing
- shift; break ;;
- - ) # Use stdin as input.
- break ;;
- -* )
- echo "$me: invalid option $1$help" >&2
- exit 1 ;;
- * )
- break ;;
- esac
-done
-
-if test $# != 0; then
- echo "$me: too many arguments$help" >&2
- exit 1
-fi
-
-trap 'exit 1' 1 2 15
-
-# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
-# compiler to aid in system detection is discouraged as it requires
-# temporary files to be created and, as you can see below, it is a
-# headache to deal with in a portable fashion.
-
-# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
-# use `HOST_CC' if defined, but it is deprecated.
-
-# Portable tmp directory creation inspired by the Autoconf team.
-
-set_cc_for_build='
-trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
-trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
-: ${TMPDIR=/tmp} ;
- { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
- { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
- { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
- { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
-dummy=$tmp/dummy ;
-tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
-case $CC_FOR_BUILD,$HOST_CC,$CC in
- ,,) echo "int x;" > $dummy.c ;
- for c in cc gcc c89 c99 ; do
- if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
- CC_FOR_BUILD="$c"; break ;
- fi ;
- done ;
- if test x"$CC_FOR_BUILD" = x ; then
- CC_FOR_BUILD=no_compiler_found ;
- fi
- ;;
- ,,*) CC_FOR_BUILD=$CC ;;
- ,*,*) CC_FOR_BUILD=$HOST_CC ;;
-esac ; set_cc_for_build= ;'
-
-# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
-# ([email protected] 1994-08-24)
-if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
- PATH=$PATH:/.attbin ; export PATH
-fi
-
-UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
-UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
-UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
-UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
-
-# Note: order is significant - the case branches are not exclusive.
-
-case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
- *:NetBSD:*:*)
- # NetBSD (nbsd) targets should (where applicable) match one or
- # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
- # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
- # switched to ELF, *-*-netbsd* would select the old
- # object file format. This provides both forward
- # compatibility and a consistent mechanism for selecting the
- # object file format.
- #
- # Note: NetBSD doesn't particularly care about the vendor
- # portion of the name. We always set it to "unknown".
- sysctl="sysctl -n hw.machine_arch"
- UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
- /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
- case "${UNAME_MACHINE_ARCH}" in
- armeb) machine=armeb-unknown ;;
- arm*) machine=arm-unknown ;;
- sh3el) machine=shl-unknown ;;
- sh3eb) machine=sh-unknown ;;
- sh5el) machine=sh5le-unknown ;;
- *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
- esac
- # The Operating System including object format, if it has switched
- # to ELF recently, or will in the future.
- case "${UNAME_MACHINE_ARCH}" in
- arm*|i386|m68k|ns32k|sh3*|sparc|vax)
- eval $set_cc_for_build
- if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
- | grep __ELF__ >/dev/null
- then
- # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
- # Return netbsd for either. FIX?
- os=netbsd
- else
- os=netbsdelf
- fi
- ;;
- *)
- os=netbsd
- ;;
- esac
- # The OS release
- # Debian GNU/NetBSD machines have a different userland, and
- # thus, need a distinct triplet. However, they do not need
- # kernel version information, so it can be replaced with a
- # suitable tag, in the style of linux-gnu.
- case "${UNAME_VERSION}" in
- Debian*)
- release='-gnu'
- ;;
- *)
- release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
- ;;
- esac
- # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
- # contains redundant information, the shorter form:
- # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
- echo "${machine}-${os}${release}"
- exit ;;
- *:OpenBSD:*:*)
- UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
- echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
- exit ;;
- *:ekkoBSD:*:*)
- echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
- exit ;;
- *:SolidBSD:*:*)
- echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
- exit ;;
- macppc:MirBSD:*:*)
- echo powerpc-unknown-mirbsd${UNAME_RELEASE}
- exit ;;
- *:MirBSD:*:*)
- echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
- exit ;;
- alpha:OSF1:*:*)
- case $UNAME_RELEASE in
- *4.0)
- UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
- ;;
- *5.*)
- UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
- ;;
- esac
- # According to Compaq, /usr/sbin/psrinfo has been available on
- # OSF/1 and Tru64 systems produced since 1995. I hope that
- # covers most systems running today. This code pipes the CPU
- # types through head -n 1, so we only detect the type of CPU 0.
- ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
- case "$ALPHA_CPU_TYPE" in
- "EV4 (21064)")
- UNAME_MACHINE="alpha" ;;
- "EV4.5 (21064)")
- UNAME_MACHINE="alpha" ;;
- "LCA4 (21066/21068)")
- UNAME_MACHINE="alpha" ;;
- "EV5 (21164)")
- UNAME_MACHINE="alphaev5" ;;
- "EV5.6 (21164A)")
- UNAME_MACHINE="alphaev56" ;;
- "EV5.6 (21164PC)")
- UNAME_MACHINE="alphapca56" ;;
- "EV5.7 (21164PC)")
- UNAME_MACHINE="alphapca57" ;;
- "EV6 (21264)")
- UNAME_MACHINE="alphaev6" ;;
- "EV6.7 (21264A)")
- UNAME_MACHINE="alphaev67" ;;
- "EV6.8CB (21264C)")
- UNAME_MACHINE="alphaev68" ;;
- "EV6.8AL (21264B)")
- UNAME_MACHINE="alphaev68" ;;
- "EV6.8CX (21264D)")
- UNAME_MACHINE="alphaev68" ;;
- "EV6.9A (21264/EV69A)")
- UNAME_MACHINE="alphaev69" ;;
- "EV7 (21364)")
- UNAME_MACHINE="alphaev7" ;;
- "EV7.9 (21364A)")
- UNAME_MACHINE="alphaev79" ;;
- esac
- # A Pn.n version is a patched version.
- # A Vn.n version is a released version.
- # A Tn.n version is a released field test version.
- # A Xn.n version is an unreleased experimental baselevel.
- # 1.2 uses "1.2" for uname -r.
- echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
- exit ;;
- Alpha\ *:Windows_NT*:*)
- # How do we know it's Interix rather than the generic POSIX subsystem?
- # Should we change UNAME_MACHINE based on the output of uname instead
- # of the specific Alpha model?
- echo alpha-pc-interix
- exit ;;
- 21064:Windows_NT:50:3)
- echo alpha-dec-winnt3.5
- exit ;;
- Amiga*:UNIX_System_V:4.0:*)
- echo m68k-unknown-sysv4
- exit ;;
- *:[Aa]miga[Oo][Ss]:*:*)
- echo ${UNAME_MACHINE}-unknown-amigaos
- exit ;;
- *:[Mm]orph[Oo][Ss]:*:*)
- echo ${UNAME_MACHINE}-unknown-morphos
- exit ;;
- *:OS/390:*:*)
- echo i370-ibm-openedition
- exit ;;
- *:z/VM:*:*)
- echo s390-ibm-zvmoe
- exit ;;
- *:OS400:*:*)
- echo powerpc-ibm-os400
- exit ;;
- arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
- echo arm-acorn-riscix${UNAME_RELEASE}
- exit ;;
- arm:riscos:*:*|arm:RISCOS:*:*)
- echo arm-unknown-riscos
- exit ;;
- SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
- echo hppa1.1-hitachi-hiuxmpp
- exit ;;
- Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
- # [email protected] (Earle F. Ake) contributed MIS and NILE.
- if test "`(/bin/universe) 2>/dev/null`" = att ; then
- echo pyramid-pyramid-sysv3
- else
- echo pyramid-pyramid-bsd
- fi
- exit ;;
- NILE*:*:*:dcosx)
- echo pyramid-pyramid-svr4
- exit ;;
- DRS?6000:unix:4.0:6*)
- echo sparc-icl-nx6
- exit ;;
- DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
- case `/usr/bin/uname -p` in
- sparc) echo sparc-icl-nx7; exit ;;
- esac ;;
- sun4H:SunOS:5.*:*)
- echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit ;;
- sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
- echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit ;;
- i86pc:SunOS:5.*:* | ix86xen:SunOS:5.*:*)
- echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit ;;
- sun4*:SunOS:6*:*)
- # According to config.sub, this is the proper way to canonicalize
- # SunOS6. Hard to guess exactly what SunOS6 will be like, but
- # it's likely to be more like Solaris than SunOS4.
- echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit ;;
- sun4*:SunOS:*:*)
- case "`/usr/bin/arch -k`" in
- Series*|S4*)
- UNAME_RELEASE=`uname -v`
- ;;
- esac
- # Japanese Language versions have a version number like `4.1.3-JL'.
- echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
- exit ;;
- sun3*:SunOS:*:*)
- echo m68k-sun-sunos${UNAME_RELEASE}
- exit ;;
- sun*:*:4.2BSD:*)
- UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
- test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
- case "`/bin/arch`" in
- sun3)
- echo m68k-sun-sunos${UNAME_RELEASE}
- ;;
- sun4)
- echo sparc-sun-sunos${UNAME_RELEASE}
- ;;
- esac
- exit ;;
- aushp:SunOS:*:*)
- echo sparc-auspex-sunos${UNAME_RELEASE}
- exit ;;
- # The situation for MiNT is a little confusing. The machine name
- # can be virtually everything (everything which is not
- # "atarist" or "atariste" at least should have a processor
- # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
- # to the lowercase version "mint" (or "freemint"). Finally
- # the system name "TOS" denotes a system which is actually not
- # MiNT. But MiNT is downward compatible to TOS, so this should
- # be no problem.
- atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
- echo m68k-atari-mint${UNAME_RELEASE}
- exit ;;
- atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
- echo m68k-atari-mint${UNAME_RELEASE}
- exit ;;
- *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
- echo m68k-atari-mint${UNAME_RELEASE}
- exit ;;
- milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
- echo m68k-milan-mint${UNAME_RELEASE}
- exit ;;
- hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
- echo m68k-hades-mint${UNAME_RELEASE}
- exit ;;
- *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
- echo m68k-unknown-mint${UNAME_RELEASE}
- exit ;;
- m68k:machten:*:*)
- echo m68k-apple-machten${UNAME_RELEASE}
- exit ;;
- powerpc:machten:*:*)
- echo powerpc-apple-machten${UNAME_RELEASE}
- exit ;;
- RISC*:Mach:*:*)
- echo mips-dec-mach_bsd4.3
- exit ;;
- RISC*:ULTRIX:*:*)
- echo mips-dec-ultrix${UNAME_RELEASE}
- exit ;;
- VAX*:ULTRIX*:*:*)
- echo vax-dec-ultrix${UNAME_RELEASE}
- exit ;;
- 2020:CLIX:*:* | 2430:CLIX:*:*)
- echo clipper-intergraph-clix${UNAME_RELEASE}
- exit ;;
- mips:*:*:UMIPS | mips:*:*:RISCos)
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
-#ifdef __cplusplus
-#include <stdio.h> /* for printf() prototype */
- int main (int argc, char *argv[]) {
-#else
- int main (argc, argv) int argc; char *argv[]; {
-#endif
- #if defined (host_mips) && defined (MIPSEB)
- #if defined (SYSTYPE_SYSV)
- printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
- #endif
- #if defined (SYSTYPE_SVR4)
- printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
- #endif
- #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
- printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
- #endif
- #endif
- exit (-1);
- }
-EOF
- $CC_FOR_BUILD -o $dummy $dummy.c &&
- dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
- SYSTEM_NAME=`$dummy $dummyarg` &&
- { echo "$SYSTEM_NAME"; exit; }
- echo mips-mips-riscos${UNAME_RELEASE}
- exit ;;
- Motorola:PowerMAX_OS:*:*)
- echo powerpc-motorola-powermax
- exit ;;
- Motorola:*:4.3:PL8-*)
- echo powerpc-harris-powermax
- exit ;;
- Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
- echo powerpc-harris-powermax
- exit ;;
- Night_Hawk:Power_UNIX:*:*)
- echo powerpc-harris-powerunix
- exit ;;
- m88k:CX/UX:7*:*)
- echo m88k-harris-cxux7
- exit ;;
- m88k:*:4*:R4*)
- echo m88k-motorola-sysv4
- exit ;;
- m88k:*:3*:R3*)
- echo m88k-motorola-sysv3
- exit ;;
- AViiON:dgux:*:*)
- # DG/UX returns AViiON for all architectures
- UNAME_PROCESSOR=`/usr/bin/uname -p`
- if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
- then
- if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
- [ ${TARGET_BINARY_INTERFACE}x = x ]
- then
- echo m88k-dg-dgux${UNAME_RELEASE}
- else
- echo m88k-dg-dguxbcs${UNAME_RELEASE}
- fi
- else
- echo i586-dg-dgux${UNAME_RELEASE}
- fi
- exit ;;
- M88*:DolphinOS:*:*) # DolphinOS (SVR3)
- echo m88k-dolphin-sysv3
- exit ;;
- M88*:*:R3*:*)
- # Delta 88k system running SVR3
- echo m88k-motorola-sysv3
- exit ;;
- XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
- echo m88k-tektronix-sysv3
- exit ;;
- Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
- echo m68k-tektronix-bsd
- exit ;;
- *:IRIX*:*:*)
- echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
- exit ;;
- ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
- echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
- exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
- i*86:AIX:*:*)
- echo i386-ibm-aix
- exit ;;
- ia64:AIX:*:*)
- if [ -x /usr/bin/oslevel ] ; then
- IBM_REV=`/usr/bin/oslevel`
- else
- IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
- fi
- echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
- exit ;;
- *:AIX:2:3)
- if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
- #include <sys/systemcfg.h>
-
- main()
- {
- if (!__power_pc())
- exit(1);
- puts("powerpc-ibm-aix3.2.5");
- exit(0);
- }
-EOF
- if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
- then
- echo "$SYSTEM_NAME"
- else
- echo rs6000-ibm-aix3.2.5
- fi
- elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
- echo rs6000-ibm-aix3.2.4
- else
- echo rs6000-ibm-aix3.2
- fi
- exit ;;
- *:AIX:*:[45])
- IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
- if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
- IBM_ARCH=rs6000
- else
- IBM_ARCH=powerpc
- fi
- if [ -x /usr/bin/oslevel ] ; then
- IBM_REV=`/usr/bin/oslevel`
- else
- IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
- fi
- echo ${IBM_ARCH}-ibm-aix${IBM_REV}
- exit ;;
- *:AIX:*:*)
- echo rs6000-ibm-aix
- exit ;;
- ibmrt:4.4BSD:*|romp-ibm:BSD:*)
- echo romp-ibm-bsd4.4
- exit ;;
- ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
- echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
- exit ;; # report: romp-ibm BSD 4.3
- *:BOSX:*:*)
- echo rs6000-bull-bosx
- exit ;;
- DPX/2?00:B.O.S.:*:*)
- echo m68k-bull-sysv3
- exit ;;
- 9000/[34]??:4.3bsd:1.*:*)
- echo m68k-hp-bsd
- exit ;;
- hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
- echo m68k-hp-bsd4.4
- exit ;;
- 9000/[34678]??:HP-UX:*:*)
- HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
- case "${UNAME_MACHINE}" in
- 9000/31? ) HP_ARCH=m68000 ;;
- 9000/[34]?? ) HP_ARCH=m68k ;;
- 9000/[678][0-9][0-9])
- if [ -x /usr/bin/getconf ]; then
- sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
- sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
- case "${sc_cpu_version}" in
- 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
- 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
- 532) # CPU_PA_RISC2_0
- case "${sc_kernel_bits}" in
- 32) HP_ARCH="hppa2.0n" ;;
- 64) HP_ARCH="hppa2.0w" ;;
- '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
- esac ;;
- esac
- fi
- if [ "${HP_ARCH}" = "" ]; then
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
-
- #define _HPUX_SOURCE
- #include <stdlib.h>
- #include <unistd.h>
-
- int main ()
- {
- #if defined(_SC_KERNEL_BITS)
- long bits = sysconf(_SC_KERNEL_BITS);
- #endif
- long cpu = sysconf (_SC_CPU_VERSION);
-
- switch (cpu)
- {
- case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
- case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
- case CPU_PA_RISC2_0:
- #if defined(_SC_KERNEL_BITS)
- switch (bits)
- {
- case 64: puts ("hppa2.0w"); break;
- case 32: puts ("hppa2.0n"); break;
- default: puts ("hppa2.0"); break;
- } break;
- #else /* !defined(_SC_KERNEL_BITS) */
- puts ("hppa2.0"); break;
- #endif
- default: puts ("hppa1.0"); break;
- }
- exit (0);
- }
-EOF
- (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
- test -z "$HP_ARCH" && HP_ARCH=hppa
- fi ;;
- esac
- if [ ${HP_ARCH} = "hppa2.0w" ]
- then
- eval $set_cc_for_build
-
- # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
- # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
- # generating 64-bit code. GNU and HP use different nomenclature:
- #
- # $ CC_FOR_BUILD=cc ./config.guess
- # => hppa2.0w-hp-hpux11.23
- # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
- # => hppa64-hp-hpux11.23
-
- if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
- grep __LP64__ >/dev/null
- then
- HP_ARCH="hppa2.0w"
- else
- HP_ARCH="hppa64"
- fi
- fi
- echo ${HP_ARCH}-hp-hpux${HPUX_REV}
- exit ;;
- ia64:HP-UX:*:*)
- HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
- echo ia64-hp-hpux${HPUX_REV}
- exit ;;
- 3050*:HI-UX:*:*)
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
- #include <unistd.h>
- int
- main ()
- {
- long cpu = sysconf (_SC_CPU_VERSION);
- /* The order matters, because CPU_IS_HP_MC68K erroneously returns
- true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
- results, however. */
- if (CPU_IS_PA_RISC (cpu))
- {
- switch (cpu)
- {
- case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
- case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
- case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
- default: puts ("hppa-hitachi-hiuxwe2"); break;
- }
- }
- else if (CPU_IS_HP_MC68K (cpu))
- puts ("m68k-hitachi-hiuxwe2");
- else puts ("unknown-hitachi-hiuxwe2");
- exit (0);
- }
-EOF
- $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
- { echo "$SYSTEM_NAME"; exit; }
- echo unknown-hitachi-hiuxwe2
- exit ;;
- 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
- echo hppa1.1-hp-bsd
- exit ;;
- 9000/8??:4.3bsd:*:*)
- echo hppa1.0-hp-bsd
- exit ;;
- *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
- echo hppa1.0-hp-mpeix
- exit ;;
- hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
- echo hppa1.1-hp-osf
- exit ;;
- hp8??:OSF1:*:*)
- echo hppa1.0-hp-osf
- exit ;;
- i*86:OSF1:*:*)
- if [ -x /usr/sbin/sysversion ] ; then
- echo ${UNAME_MACHINE}-unknown-osf1mk
- else
- echo ${UNAME_MACHINE}-unknown-osf1
- fi
- exit ;;
- parisc*:Lites*:*:*)
- echo hppa1.1-hp-lites
- exit ;;
- C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
- echo c1-convex-bsd
- exit ;;
- C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
- if getsysinfo -f scalar_acc
- then echo c32-convex-bsd
- else echo c2-convex-bsd
- fi
- exit ;;
- C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
- echo c34-convex-bsd
- exit ;;
- C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
- echo c38-convex-bsd
- exit ;;
- C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
- echo c4-convex-bsd
- exit ;;
- CRAY*Y-MP:*:*:*)
- echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
- exit ;;
- CRAY*[A-Z]90:*:*:*)
- echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
- | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
- -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
- -e 's/\.[^.]*$/.X/'
- exit ;;
- CRAY*TS:*:*:*)
- echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
- exit ;;
- CRAY*T3E:*:*:*)
- echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
- exit ;;
- CRAY*SV1:*:*:*)
- echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
- exit ;;
- *:UNICOS/mp:*:*)
- echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
- exit ;;
- F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
- FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
- FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
- FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
- echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
- exit ;;
- 5000:UNIX_System_V:4.*:*)
- FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
- FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
- echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
- exit ;;
- i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
- echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
- exit ;;
- sparc*:BSD/OS:*:*)
- echo sparc-unknown-bsdi${UNAME_RELEASE}
- exit ;;
- *:BSD/OS:*:*)
- echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
- exit ;;
- *:FreeBSD:*:*)
- case ${UNAME_MACHINE} in
- pc98)
- echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
- amd64)
- echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
- *)
- echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
- esac
- exit ;;
- i*:CYGWIN*:*)
- echo ${UNAME_MACHINE}-pc-cygwin
- exit ;;
- *:MINGW*:*)
- echo ${UNAME_MACHINE}-pc-mingw32
- exit ;;
- i*:windows32*:*)
- # uname -m includes "-pc" on this system.
- echo ${UNAME_MACHINE}-mingw32
- exit ;;
- i*:PW*:*)
- echo ${UNAME_MACHINE}-pc-pw32
- exit ;;
- *:Interix*:[3456]*)
- case ${UNAME_MACHINE} in
- x86)
- echo i586-pc-interix${UNAME_RELEASE}
- exit ;;
- EM64T | authenticamd)
- echo x86_64-unknown-interix${UNAME_RELEASE}
- exit ;;
- esac ;;
- [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
- echo i${UNAME_MACHINE}-pc-mks
- exit ;;
- i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
- # How do we know it's Interix rather than the generic POSIX subsystem?
- # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
- # UNAME_MACHINE based on the output of uname instead of i386?
- echo i586-pc-interix
- exit ;;
- i*:UWIN*:*)
- echo ${UNAME_MACHINE}-pc-uwin
- exit ;;
- amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
- echo x86_64-unknown-cygwin
- exit ;;
- p*:CYGWIN*:*)
- echo powerpcle-unknown-cygwin
- exit ;;
- prep*:SunOS:5.*:*)
- echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit ;;
- *:GNU:*:*)
- # the GNU system
- echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
- exit ;;
- *:GNU/*:*:*)
- # other systems with GNU libc and userland
- echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
- exit ;;
- i*86:Minix:*:*)
- echo ${UNAME_MACHINE}-pc-minix
- exit ;;
- arm*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit ;;
- avr32*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit ;;
- cris:Linux:*:*)
- echo cris-axis-linux-gnu
- exit ;;
- crisv32:Linux:*:*)
- echo crisv32-axis-linux-gnu
- exit ;;
- frv:Linux:*:*)
- echo frv-unknown-linux-gnu
- exit ;;
- ia64:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit ;;
- m32r*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit ;;
- m68*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit ;;
- mips:Linux:*:*)
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
- #undef CPU
- #undef mips
- #undef mipsel
- #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
- CPU=mipsel
- #else
- #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
- CPU=mips
- #else
- CPU=
- #endif
- #endif
-EOF
- eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
- /^CPU/{
- s: ::g
- p
- }'`"
- test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
- ;;
- mips64:Linux:*:*)
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
- #undef CPU
- #undef mips64
- #undef mips64el
- #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
- CPU=mips64el
- #else
- #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
- CPU=mips64
- #else
- CPU=
- #endif
- #endif
-EOF
- eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
- /^CPU/{
- s: ::g
- p
- }'`"
- test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
- ;;
- or32:Linux:*:*)
- echo or32-unknown-linux-gnu
- exit ;;
- ppc:Linux:*:*)
- echo powerpc-unknown-linux-gnu
- exit ;;
- ppc64:Linux:*:*)
- echo powerpc64-unknown-linux-gnu
- exit ;;
- alpha:Linux:*:*)
- case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
- EV5) UNAME_MACHINE=alphaev5 ;;
- EV56) UNAME_MACHINE=alphaev56 ;;
- PCA56) UNAME_MACHINE=alphapca56 ;;
- PCA57) UNAME_MACHINE=alphapca56 ;;
- EV6) UNAME_MACHINE=alphaev6 ;;
- EV67) UNAME_MACHINE=alphaev67 ;;
- EV68*) UNAME_MACHINE=alphaev68 ;;
- esac
- objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
- if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
- echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
- exit ;;
- parisc:Linux:*:* | hppa:Linux:*:*)
- # Look for CPU level
- case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
- PA7*) echo hppa1.1-unknown-linux-gnu ;;
- PA8*) echo hppa2.0-unknown-linux-gnu ;;
- *) echo hppa-unknown-linux-gnu ;;
- esac
- exit ;;
- parisc64:Linux:*:* | hppa64:Linux:*:*)
- echo hppa64-unknown-linux-gnu
- exit ;;
- s390:Linux:*:* | s390x:Linux:*:*)
- echo ${UNAME_MACHINE}-ibm-linux
- exit ;;
- sh64*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit ;;
- sh*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit ;;
- sparc:Linux:*:* | sparc64:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit ;;
- tile:Linux:*:*)
- echo tile-unknown-linux-gnu
- exit ;;
- vax:Linux:*:*)
- echo ${UNAME_MACHINE}-dec-linux-gnu
- exit ;;
- x86_64:Linux:*:*)
- echo x86_64-unknown-linux-gnu
- exit ;;
- xtensa:Linux:*:*)
- echo xtensa-unknown-linux-gnu
- exit ;;
- i*86:Linux:*:*)
- # The BFD linker knows what the default object file format is, so
- # first see if it will tell us. cd to the root directory to prevent
- # problems with other programs or directories called `ld' in the path.
- # Set LC_ALL=C to ensure ld outputs messages in English.
- ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
- | sed -ne '/supported targets:/!d
- s/[ ][ ]*/ /g
- s/.*supported targets: *//
- s/ .*//
- p'`
- case "$ld_supported_targets" in
- elf32-i386)
- TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
- ;;
- a.out-i386-linux)
- echo "${UNAME_MACHINE}-pc-linux-gnuaout"
- exit ;;
- coff-i386)
- echo "${UNAME_MACHINE}-pc-linux-gnucoff"
- exit ;;
- "")
- # Either a pre-BFD a.out linker (linux-gnuoldld) or
- # one that does not give us useful --help.
- echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
- exit ;;
- esac
- # Determine whether the default compiler is a.out or elf
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
- #include <features.h>
- #ifdef __ELF__
- # ifdef __GLIBC__
- # if __GLIBC__ >= 2
- LIBC=gnu
- # else
- LIBC=gnulibc1
- # endif
- # else
- LIBC=gnulibc1
- # endif
- #else
- #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
- LIBC=gnu
- #else
- LIBC=gnuaout
- #endif
- #endif
- #ifdef __dietlibc__
- LIBC=dietlibc
- #endif
-EOF
- eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
- /^LIBC/{
- s: ::g
- p
- }'`"
- test x"${LIBC}" != x && {
- echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
- exit
- }
- test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
- ;;
- i*86:DYNIX/ptx:4*:*)
- # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
- # earlier versions are messed up and put the nodename in both
- # sysname and nodename.
- echo i386-sequent-sysv4
- exit ;;
- i*86:UNIX_SV:4.2MP:2.*)
- # Unixware is an offshoot of SVR4, but it has its own version
- # number series starting with 2...
- # I am not positive that other SVR4 systems won't match this,
- # I just have to hope. -- rms.
- # Use sysv4.2uw... so that sysv4* matches it.
- echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
- exit ;;
- i*86:OS/2:*:*)
- # If we were able to find `uname', then EMX Unix compatibility
- # is probably installed.
- echo ${UNAME_MACHINE}-pc-os2-emx
- exit ;;
- i*86:XTS-300:*:STOP)
- echo ${UNAME_MACHINE}-unknown-stop
- exit ;;
- i*86:atheos:*:*)
- echo ${UNAME_MACHINE}-unknown-atheos
- exit ;;
- i*86:syllable:*:*)
- echo ${UNAME_MACHINE}-pc-syllable
- exit ;;
- i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
- echo i386-unknown-lynxos${UNAME_RELEASE}
- exit ;;
- i*86:*DOS:*:*)
- echo ${UNAME_MACHINE}-pc-msdosdjgpp
- exit ;;
- i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
- UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
- if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
- echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
- else
- echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
- fi
- exit ;;
- i*86:*:5:[678]*)
- # UnixWare 7.x, OpenUNIX and OpenServer 6.
- case `/bin/uname -X | grep "^Machine"` in
- *486*) UNAME_MACHINE=i486 ;;
- *Pentium) UNAME_MACHINE=i586 ;;
- *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
- esac
- echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
- exit ;;
- i*86:*:3.2:*)
- if test -f /usr/options/cb.name; then
- UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
- echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
- elif /bin/uname -X 2>/dev/null >/dev/null ; then
- UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
- (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
- (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
- && UNAME_MACHINE=i586
- (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
- && UNAME_MACHINE=i686
- (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
- && UNAME_MACHINE=i686
- echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
- else
- echo ${UNAME_MACHINE}-pc-sysv32
- fi
- exit ;;
- pc:*:*:*)
- # Left here for compatibility:
- # uname -m prints for DJGPP always 'pc', but it prints nothing about
- # the processor, so we play safe by assuming i386.
- echo i386-pc-msdosdjgpp
- exit ;;
- Intel:Mach:3*:*)
- echo i386-pc-mach3
- exit ;;
- paragon:*:*:*)
- echo i860-intel-osf1
- exit ;;
- i860:*:4.*:*) # i860-SVR4
- if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
- echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
- else # Add other i860-SVR4 vendors below as they are discovered.
- echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
- fi
- exit ;;
- mini*:CTIX:SYS*5:*)
- # "miniframe"
- echo m68010-convergent-sysv
- exit ;;
- mc68k:UNIX:SYSTEM5:3.51m)
- echo m68k-convergent-sysv
- exit ;;
- M680?0:D-NIX:5.3:*)
- echo m68k-diab-dnix
- exit ;;
- M68*:*:R3V[5678]*:*)
- test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
- 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
- OS_REL=''
- test -r /etc/.relid \
- && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
- /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
- && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
- /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
- && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
- 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
- /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
- && { echo i486-ncr-sysv4; exit; } ;;
- m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
- echo m68k-unknown-lynxos${UNAME_RELEASE}
- exit ;;
- mc68030:UNIX_System_V:4.*:*)
- echo m68k-atari-sysv4
- exit ;;
- TSUNAMI:LynxOS:2.*:*)
- echo sparc-unknown-lynxos${UNAME_RELEASE}
- exit ;;
- rs6000:LynxOS:2.*:*)
- echo rs6000-unknown-lynxos${UNAME_RELEASE}
- exit ;;
- PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
- echo powerpc-unknown-lynxos${UNAME_RELEASE}
- exit ;;
- SM[BE]S:UNIX_SV:*:*)
- echo mips-dde-sysv${UNAME_RELEASE}
- exit ;;
- RM*:ReliantUNIX-*:*:*)
- echo mips-sni-sysv4
- exit ;;
- RM*:SINIX-*:*:*)
- echo mips-sni-sysv4
- exit ;;
- *:SINIX-*:*:*)
- if uname -p 2>/dev/null >/dev/null ; then
- UNAME_MACHINE=`(uname -p) 2>/dev/null`
- echo ${UNAME_MACHINE}-sni-sysv4
- else
- echo ns32k-sni-sysv
- fi
- exit ;;
- PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
- echo i586-unisys-sysv4
- exit ;;
- *:UNIX_System_V:4*:FTX*)
- # From Gerald Hewes <[email protected]>.
- # How about differentiating between stratus architectures? -djm
- echo hppa1.1-stratus-sysv4
- exit ;;
- *:*:*:FTX*)
- echo i860-stratus-sysv4
- exit ;;
- i*86:VOS:*:*)
- echo ${UNAME_MACHINE}-stratus-vos
- exit ;;
- *:VOS:*:*)
- echo hppa1.1-stratus-vos
- exit ;;
- mc68*:A/UX:*:*)
- echo m68k-apple-aux${UNAME_RELEASE}
- exit ;;
- news*:NEWS-OS:6*:*)
- echo mips-sony-newsos6
- exit ;;
- R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
- if [ -d /usr/nec ]; then
- echo mips-nec-sysv${UNAME_RELEASE}
- else
- echo mips-unknown-sysv${UNAME_RELEASE}
- fi
- exit ;;
- BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
- echo powerpc-be-beos
- exit ;;
- BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
- echo powerpc-apple-beos
- exit ;;
- BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
- echo i586-pc-beos
- exit ;;
- SX-4:SUPER-UX:*:*)
- echo sx4-nec-superux${UNAME_RELEASE}
- exit ;;
- SX-5:SUPER-UX:*:*)
- echo sx5-nec-superux${UNAME_RELEASE}
- exit ;;
- SX-6:SUPER-UX:*:*)
- echo sx6-nec-superux${UNAME_RELEASE}
- exit ;;
- SX-7:SUPER-UX:*:*)
- echo sx7-nec-superux${UNAME_RELEASE}
- exit ;;
- SX-8:SUPER-UX:*:*)
- echo sx8-nec-superux${UNAME_RELEASE}
- exit ;;
- SX-8R:SUPER-UX:*:*)
- echo sx8r-nec-superux${UNAME_RELEASE}
- exit ;;
- Power*:Rhapsody:*:*)
- echo powerpc-apple-rhapsody${UNAME_RELEASE}
- exit ;;
- *:Rhapsody:*:*)
- echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
- exit ;;
- *:Darwin:*:*)
- UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
- case $UNAME_PROCESSOR in
- unknown) UNAME_PROCESSOR=powerpc ;;
- esac
- echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
- exit ;;
- *:procnto*:*:* | *:QNX:[0123456789]*:*)
- UNAME_PROCESSOR=`uname -p`
- if test "$UNAME_PROCESSOR" = "x86"; then
- UNAME_PROCESSOR=i386
- UNAME_MACHINE=pc
- fi
- echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
- exit ;;
- *:QNX:*:4*)
- echo i386-pc-qnx
- exit ;;
- NSE-?:NONSTOP_KERNEL:*:*)
- echo nse-tandem-nsk${UNAME_RELEASE}
- exit ;;
- NSR-?:NONSTOP_KERNEL:*:*)
- echo nsr-tandem-nsk${UNAME_RELEASE}
- exit ;;
- *:NonStop-UX:*:*)
- echo mips-compaq-nonstopux
- exit ;;
- BS2000:POSIX*:*:*)
- echo bs2000-siemens-sysv
- exit ;;
- DS/*:UNIX_System_V:*:*)
- echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
- exit ;;
- *:Plan9:*:*)
- # "uname -m" is not consistent, so use $cputype instead. 386
- # is converted to i386 for consistency with other x86
- # operating systems.
- if test "$cputype" = "386"; then
- UNAME_MACHINE=i386
- else
- UNAME_MACHINE="$cputype"
- fi
- echo ${UNAME_MACHINE}-unknown-plan9
- exit ;;
- *:TOPS-10:*:*)
- echo pdp10-unknown-tops10
- exit ;;
- *:TENEX:*:*)
- echo pdp10-unknown-tenex
- exit ;;
- KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
- echo pdp10-dec-tops20
- exit ;;
- XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
- echo pdp10-xkl-tops20
- exit ;;
- *:TOPS-20:*:*)
- echo pdp10-unknown-tops20
- exit ;;
- *:ITS:*:*)
- echo pdp10-unknown-its
- exit ;;
- SEI:*:*:SEIUX)
- echo mips-sei-seiux${UNAME_RELEASE}
- exit ;;
- *:DragonFly:*:*)
- echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
- exit ;;
- *:*VMS:*:*)
- UNAME_MACHINE=`(uname -p) 2>/dev/null`
- case "${UNAME_MACHINE}" in
- A*) echo alpha-dec-vms ; exit ;;
- I*) echo ia64-dec-vms ; exit ;;
- V*) echo vax-dec-vms ; exit ;;
- esac ;;
- *:XENIX:*:SysV)
- echo i386-pc-xenix
- exit ;;
- i*86:skyos:*:*)
- echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
- exit ;;
- i*86:rdos:*:*)
- echo ${UNAME_MACHINE}-pc-rdos
- exit ;;
-esac
-
-#echo '(No uname command or uname output not recognized.)' 1>&2
-#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
-
-eval $set_cc_for_build
-cat >$dummy.c <<EOF
-#ifdef _SEQUENT_
-# include <sys/types.h>
-# include <sys/utsname.h>
-#endif
-main ()
-{
-#if defined (sony)
-#if defined (MIPSEB)
- /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
- I don't know.... */
- printf ("mips-sony-bsd\n"); exit (0);
-#else
-#include <sys/param.h>
- printf ("m68k-sony-newsos%s\n",
-#ifdef NEWSOS4
- "4"
-#else
- ""
-#endif
- ); exit (0);
-#endif
-#endif
-
-#if defined (__arm) && defined (__acorn) && defined (__unix)
- printf ("arm-acorn-riscix\n"); exit (0);
-#endif
-
-#if defined (hp300) && !defined (hpux)
- printf ("m68k-hp-bsd\n"); exit (0);
-#endif
-
-#if defined (NeXT)
-#if !defined (__ARCHITECTURE__)
-#define __ARCHITECTURE__ "m68k"
-#endif
- int version;
- version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
- if (version < 4)
- printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
- else
- printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
- exit (0);
-#endif
-
-#if defined (MULTIMAX) || defined (n16)
-#if defined (UMAXV)
- printf ("ns32k-encore-sysv\n"); exit (0);
-#else
-#if defined (CMU)
- printf ("ns32k-encore-mach\n"); exit (0);
-#else
- printf ("ns32k-encore-bsd\n"); exit (0);
-#endif
-#endif
-#endif
-
-#if defined (__386BSD__)
- printf ("i386-pc-bsd\n"); exit (0);
-#endif
-
-#if defined (sequent)
-#if defined (i386)
- printf ("i386-sequent-dynix\n"); exit (0);
-#endif
-#if defined (ns32000)
- printf ("ns32k-sequent-dynix\n"); exit (0);
-#endif
-#endif
-
-#if defined (_SEQUENT_)
- struct utsname un;
-
- uname(&un);
-
- if (strncmp(un.version, "V2", 2) == 0) {
- printf ("i386-sequent-ptx2\n"); exit (0);
- }
- if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
- printf ("i386-sequent-ptx1\n"); exit (0);
- }
- printf ("i386-sequent-ptx\n"); exit (0);
-
-#endif
-
-#if defined (vax)
-# if !defined (ultrix)
-# include <sys/param.h>
-# if defined (BSD)
-# if BSD == 43
- printf ("vax-dec-bsd4.3\n"); exit (0);
-# else
-# if BSD == 199006
- printf ("vax-dec-bsd4.3reno\n"); exit (0);
-# else
- printf ("vax-dec-bsd\n"); exit (0);
-# endif
-# endif
-# else
- printf ("vax-dec-bsd\n"); exit (0);
-# endif
-# else
- printf ("vax-dec-ultrix\n"); exit (0);
-# endif
-#endif
-
-#if defined (alliant) && defined (i860)
- printf ("i860-alliant-bsd\n"); exit (0);
-#endif
-
- exit (1);
-}
-EOF
-
-$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
- { echo "$SYSTEM_NAME"; exit; }
-
-# Apollos put the system type in the environment.
-
-test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
-
-# Convex versions that predate uname can use getsysinfo(1)
-
-if [ -x /usr/convex/getsysinfo ]
-then
- case `getsysinfo -f cpu_type` in
- c1*)
- echo c1-convex-bsd
- exit ;;
- c2*)
- if getsysinfo -f scalar_acc
- then echo c32-convex-bsd
- else echo c2-convex-bsd
- fi
- exit ;;
- c34*)
- echo c34-convex-bsd
- exit ;;
- c38*)
- echo c38-convex-bsd
- exit ;;
- c4*)
- echo c4-convex-bsd
- exit ;;
- esac
-fi
-
-cat >&2 <<EOF
-$0: unable to guess system type
-
-This script, last modified $timestamp, has failed to recognize
-the operating system you are using. It is advised that you
-download the most up to date version of the config scripts from
-
- http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess
-and
- http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub
-
-If the version you run ($0) is already up to date, please
-send the following data and any information you think might be
-pertinent to <[email protected]> in order to provide the needed
-information to handle your system.
-
-config.guess timestamp = $timestamp
-
-uname -m = `(uname -m) 2>/dev/null || echo unknown`
-uname -r = `(uname -r) 2>/dev/null || echo unknown`
-uname -s = `(uname -s) 2>/dev/null || echo unknown`
-uname -v = `(uname -v) 2>/dev/null || echo unknown`
-
-/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
-/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
-
-hostinfo = `(hostinfo) 2>/dev/null`
-/bin/universe = `(/bin/universe) 2>/dev/null`
-/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
-/bin/arch = `(/bin/arch) 2>/dev/null`
-/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
-/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
-
-UNAME_MACHINE = ${UNAME_MACHINE}
-UNAME_RELEASE = ${UNAME_RELEASE}
-UNAME_SYSTEM = ${UNAME_SYSTEM}
-UNAME_VERSION = ${UNAME_VERSION}
-EOF
-
-exit 1
-
-# Local variables:
-# eval: (add-hook 'write-file-hooks 'time-stamp)
-# time-stamp-start: "timestamp='"
-# time-stamp-format: "%:y-%02m-%02d"
-# time-stamp-end: "'"
-# End:
diff --git a/lib/diameter/autoconf/config.sub b/lib/diameter/autoconf/config.sub
deleted file mode 100755
index f43233b104..0000000000
--- a/lib/diameter/autoconf/config.sub
+++ /dev/null
@@ -1,1630 +0,0 @@
-#! /bin/sh
-# Configuration validation subroutine script.
-# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
-# Inc.
-
-timestamp='2007-04-29'
-
-# This file is (in principle) common to ALL GNU software.
-# The presence of a machine in this file suggests that SOME GNU software
-# can handle that machine. It does not imply ALL GNU software can.
-#
-# This file is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
-# 02110-1301, USA.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-
-# Please send patches to <[email protected]>. Submit a context
-# diff and a properly formatted ChangeLog entry.
-#
-# Configuration subroutine to validate and canonicalize a configuration type.
-# Supply the specified configuration type as an argument.
-# If it is invalid, we print an error message on stderr and exit with code 1.
-# Otherwise, we print the canonical config type on stdout and succeed.
-
-# This file is supposed to be the same for all GNU packages
-# and recognize all the CPU types, system types and aliases
-# that are meaningful with *any* GNU software.
-# Each package is responsible for reporting which valid configurations
-# it does not support. The user should be able to distinguish
-# a failure to support a valid configuration from a meaningless
-# configuration.
-
-# The goal of this file is to map all the various variations of a given
-# machine specification into a single specification in the form:
-# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
-# or in some cases, the newer four-part form:
-# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
-# It is wrong to echo any other type of specification.
-
-me=`echo "$0" | sed -e 's,.*/,,'`
-
-usage="\
-Usage: $0 [OPTION] CPU-MFR-OPSYS
- $0 [OPTION] ALIAS
-
-Canonicalize a configuration name.
-
-Operation modes:
- -h, --help print this help, then exit
- -t, --time-stamp print date of last modification, then exit
- -v, --version print version number, then exit
-
-Report bugs and patches to <[email protected]>."
-
-version="\
-GNU config.sub ($timestamp)
-
-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
-Free Software Foundation, Inc.
-
-This is free software; see the source for copying conditions. There is NO
-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
-
-help="
-Try \`$me --help' for more information."
-
-# Parse command line
-while test $# -gt 0 ; do
- case $1 in
- --time-stamp | --time* | -t )
- echo "$timestamp" ; exit ;;
- --version | -v )
- echo "$version" ; exit ;;
- --help | --h* | -h )
- echo "$usage"; exit ;;
- -- ) # Stop option processing
- shift; break ;;
- - ) # Use stdin as input.
- break ;;
- -* )
- echo "$me: invalid option $1$help"
- exit 1 ;;
-
- *local*)
- # First pass through any local machine types.
- echo $1
- exit ;;
-
- * )
- break ;;
- esac
-done
-
-case $# in
- 0) echo "$me: missing argument$help" >&2
- exit 1;;
- 1) ;;
- *) echo "$me: too many arguments$help" >&2
- exit 1;;
-esac
-
-# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
-# Here we must recognize all the valid KERNEL-OS combinations.
-maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
-case $maybe_os in
- nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
- uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
- storm-chaos* | os2-emx* | rtmk-nova*)
- os=-$maybe_os
- basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
- ;;
- *)
- basic_machine=`echo $1 | sed 's/-[^-]*$//'`
- if [ $basic_machine != $1 ]
- then os=`echo $1 | sed 's/.*-/-/'`
- else os=; fi
- ;;
-esac
-
-### Let's recognize common machines as not being operating systems so
-### that things like config.sub decstation-3100 work. We also
-### recognize some manufacturers as not being operating systems, so we
-### can provide default operating systems below.
-case $os in
- -sun*os*)
- # Prevent following clause from handling this invalid input.
- ;;
- -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
- -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
- -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
- -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
- -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
- -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
- -apple | -axis | -knuth | -cray)
- os=
- basic_machine=$1
- ;;
- -sim | -cisco | -oki | -wec | -winbond)
- os=
- basic_machine=$1
- ;;
- -scout)
- ;;
- -wrs)
- os=-vxworks
- basic_machine=$1
- ;;
- -chorusos*)
- os=-chorusos
- basic_machine=$1
- ;;
- -chorusrdb)
- os=-chorusrdb
- basic_machine=$1
- ;;
- -hiux*)
- os=-hiuxwe2
- ;;
- -sco6)
- os=-sco5v6
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco5)
- os=-sco3.2v5
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco4)
- os=-sco3.2v4
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco3.2.[4-9]*)
- os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco3.2v[4-9]*)
- # Don't forget version if it is 3.2v4 or newer.
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco5v6*)
- # Don't forget version if it is 3.2v4 or newer.
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco*)
- os=-sco3.2v2
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -udk*)
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -isc)
- os=-isc2.2
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -clix*)
- basic_machine=clipper-intergraph
- ;;
- -isc*)
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -lynx*)
- os=-lynxos
- ;;
- -ptx*)
- basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
- ;;
- -windowsnt*)
- os=`echo $os | sed -e 's/windowsnt/winnt/'`
- ;;
- -psos*)
- os=-psos
- ;;
- -mint | -mint[0-9]*)
- basic_machine=m68k-atari
- os=-mint
- ;;
-esac
-
-# Decode aliases for certain CPU-COMPANY combinations.
-case $basic_machine in
- # Recognize the basic CPU types without company name.
- # Some are omitted here because they have special meanings below.
- 1750a | 580 \
- | a29k \
- | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
- | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
- | am33_2.0 \
- | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
- | bfin \
- | c4x | clipper \
- | d10v | d30v | dlx | dsp16xx \
- | fido | fr30 | frv \
- | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
- | i370 | i860 | i960 | ia64 \
- | ip2k | iq2000 \
- | m32c | m32r | m32rle | m68000 | m68k | m88k \
- | maxq | mb | microblaze | mcore | mep \
- | mips | mipsbe | mipseb | mipsel | mipsle \
- | mips16 \
- | mips64 | mips64el \
- | mips64vr | mips64vrel \
- | mips64orion | mips64orionel \
- | mips64vr4100 | mips64vr4100el \
- | mips64vr4300 | mips64vr4300el \
- | mips64vr5000 | mips64vr5000el \
- | mips64vr5900 | mips64vr5900el \
- | mipsisa32 | mipsisa32el \
- | mipsisa32r2 | mipsisa32r2el \
- | mipsisa64 | mipsisa64el \
- | mipsisa64r2 | mipsisa64r2el \
- | mipsisa64sb1 | mipsisa64sb1el \
- | mipsisa64sr71k | mipsisa64sr71kel \
- | mipstx39 | mipstx39el \
- | mn10200 | mn10300 \
- | mt \
- | msp430 \
- | nios | nios2 \
- | ns16k | ns32k \
- | or32 \
- | pdp10 | pdp11 | pj | pjl \
- | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
- | pyramid \
- | score \
- | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
- | sh64 | sh64le \
- | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
- | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
- | spu | strongarm \
- | tahoe | thumb | tic4x | tic80 | tron \
- | v850 | v850e \
- | we32k \
- | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
- | z8k)
- basic_machine=$basic_machine-unknown
- ;;
- m6811 | m68hc11 | m6812 | m68hc12)
- # Motorola 68HC11/12.
- basic_machine=$basic_machine-unknown
- os=-none
- ;;
- m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
- ;;
- ms1)
- basic_machine=mt-unknown
- ;;
-
- # We use `pc' rather than `unknown'
- # because (1) that's what they normally are, and
- # (2) the word "unknown" tends to confuse beginning users.
- i*86 | x86_64)
- basic_machine=$basic_machine-pc
- ;;
- # Object if more than one company name word.
- *-*-*)
- echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
- exit 1
- ;;
- # Recognize the basic CPU types with company name.
- 580-* \
- | a29k-* \
- | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
- | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
- | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
- | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
- | avr-* | avr32-* \
- | bfin-* | bs2000-* \
- | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
- | clipper-* | craynv-* | cydra-* \
- | d10v-* | d30v-* | dlx-* \
- | elxsi-* \
- | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
- | h8300-* | h8500-* \
- | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
- | i*86-* | i860-* | i960-* | ia64-* \
- | ip2k-* | iq2000-* \
- | m32c-* | m32r-* | m32rle-* \
- | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
- | m88110-* | m88k-* | maxq-* | mcore-* \
- | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
- | mips16-* \
- | mips64-* | mips64el-* \
- | mips64vr-* | mips64vrel-* \
- | mips64orion-* | mips64orionel-* \
- | mips64vr4100-* | mips64vr4100el-* \
- | mips64vr4300-* | mips64vr4300el-* \
- | mips64vr5000-* | mips64vr5000el-* \
- | mips64vr5900-* | mips64vr5900el-* \
- | mipsisa32-* | mipsisa32el-* \
- | mipsisa32r2-* | mipsisa32r2el-* \
- | mipsisa64-* | mipsisa64el-* \
- | mipsisa64r2-* | mipsisa64r2el-* \
- | mipsisa64sb1-* | mipsisa64sb1el-* \
- | mipsisa64sr71k-* | mipsisa64sr71kel-* \
- | mipstx39-* | mipstx39el-* \
- | mmix-* \
- | mt-* \
- | msp430-* \
- | nios-* | nios2-* \
- | none-* | np1-* | ns16k-* | ns32k-* \
- | orion-* \
- | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
- | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
- | pyramid-* \
- | romp-* | rs6000-* \
- | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
- | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
- | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
- | sparclite-* \
- | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
- | tahoe-* | thumb-* \
- | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
- | tron-* \
- | v850-* | v850e-* | vax-* \
- | we32k-* \
- | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
- | xstormy16-* | xtensa-* \
- | ymp-* \
- | z8k-*)
- ;;
- # Recognize the various machine names and aliases which stand
- # for a CPU type and a company and sometimes even an OS.
- 386bsd)
- basic_machine=i386-unknown
- os=-bsd
- ;;
- 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
- basic_machine=m68000-att
- ;;
- 3b*)
- basic_machine=we32k-att
- ;;
- a29khif)
- basic_machine=a29k-amd
- os=-udi
- ;;
- abacus)
- basic_machine=abacus-unknown
- ;;
- adobe68k)
- basic_machine=m68010-adobe
- os=-scout
- ;;
- alliant | fx80)
- basic_machine=fx80-alliant
- ;;
- altos | altos3068)
- basic_machine=m68k-altos
- ;;
- am29k)
- basic_machine=a29k-none
- os=-bsd
- ;;
- amd64)
- basic_machine=x86_64-pc
- ;;
- amd64-*)
- basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- amdahl)
- basic_machine=580-amdahl
- os=-sysv
- ;;
- amiga | amiga-*)
- basic_machine=m68k-unknown
- ;;
- amigaos | amigados)
- basic_machine=m68k-unknown
- os=-amigaos
- ;;
- amigaunix | amix)
- basic_machine=m68k-unknown
- os=-sysv4
- ;;
- apollo68)
- basic_machine=m68k-apollo
- os=-sysv
- ;;
- apollo68bsd)
- basic_machine=m68k-apollo
- os=-bsd
- ;;
- aux)
- basic_machine=m68k-apple
- os=-aux
- ;;
- balance)
- basic_machine=ns32k-sequent
- os=-dynix
- ;;
- c90)
- basic_machine=c90-cray
- os=-unicos
- ;;
- convex-c1)
- basic_machine=c1-convex
- os=-bsd
- ;;
- convex-c2)
- basic_machine=c2-convex
- os=-bsd
- ;;
- convex-c32)
- basic_machine=c32-convex
- os=-bsd
- ;;
- convex-c34)
- basic_machine=c34-convex
- os=-bsd
- ;;
- convex-c38)
- basic_machine=c38-convex
- os=-bsd
- ;;
- cray | j90)
- basic_machine=j90-cray
- os=-unicos
- ;;
- craynv)
- basic_machine=craynv-cray
- os=-unicosmp
- ;;
- cr16c)
- basic_machine=cr16c-unknown
- os=-elf
- ;;
- crds | unos)
- basic_machine=m68k-crds
- ;;
- crisv32 | crisv32-* | etraxfs*)
- basic_machine=crisv32-axis
- ;;
- cris | cris-* | etrax*)
- basic_machine=cris-axis
- ;;
- crx)
- basic_machine=crx-unknown
- os=-elf
- ;;
- da30 | da30-*)
- basic_machine=m68k-da30
- ;;
- decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
- basic_machine=mips-dec
- ;;
- decsystem10* | dec10*)
- basic_machine=pdp10-dec
- os=-tops10
- ;;
- decsystem20* | dec20*)
- basic_machine=pdp10-dec
- os=-tops20
- ;;
- delta | 3300 | motorola-3300 | motorola-delta \
- | 3300-motorola | delta-motorola)
- basic_machine=m68k-motorola
- ;;
- delta88)
- basic_machine=m88k-motorola
- os=-sysv3
- ;;
- djgpp)
- basic_machine=i586-pc
- os=-msdosdjgpp
- ;;
- dpx20 | dpx20-*)
- basic_machine=rs6000-bull
- os=-bosx
- ;;
- dpx2* | dpx2*-bull)
- basic_machine=m68k-bull
- os=-sysv3
- ;;
- ebmon29k)
- basic_machine=a29k-amd
- os=-ebmon
- ;;
- elxsi)
- basic_machine=elxsi-elxsi
- os=-bsd
- ;;
- encore | umax | mmax)
- basic_machine=ns32k-encore
- ;;
- es1800 | OSE68k | ose68k | ose | OSE)
- basic_machine=m68k-ericsson
- os=-ose
- ;;
- fx2800)
- basic_machine=i860-alliant
- ;;
- genix)
- basic_machine=ns32k-ns
- ;;
- gmicro)
- basic_machine=tron-gmicro
- os=-sysv
- ;;
- go32)
- basic_machine=i386-pc
- os=-go32
- ;;
- h3050r* | hiux*)
- basic_machine=hppa1.1-hitachi
- os=-hiuxwe2
- ;;
- h8300hms)
- basic_machine=h8300-hitachi
- os=-hms
- ;;
- h8300xray)
- basic_machine=h8300-hitachi
- os=-xray
- ;;
- h8500hms)
- basic_machine=h8500-hitachi
- os=-hms
- ;;
- harris)
- basic_machine=m88k-harris
- os=-sysv3
- ;;
- hp300-*)
- basic_machine=m68k-hp
- ;;
- hp300bsd)
- basic_machine=m68k-hp
- os=-bsd
- ;;
- hp300hpux)
- basic_machine=m68k-hp
- os=-hpux
- ;;
- hp3k9[0-9][0-9] | hp9[0-9][0-9])
- basic_machine=hppa1.0-hp
- ;;
- hp9k2[0-9][0-9] | hp9k31[0-9])
- basic_machine=m68000-hp
- ;;
- hp9k3[2-9][0-9])
- basic_machine=m68k-hp
- ;;
- hp9k6[0-9][0-9] | hp6[0-9][0-9])
- basic_machine=hppa1.0-hp
- ;;
- hp9k7[0-79][0-9] | hp7[0-79][0-9])
- basic_machine=hppa1.1-hp
- ;;
- hp9k78[0-9] | hp78[0-9])
- # FIXME: really hppa2.0-hp
- basic_machine=hppa1.1-hp
- ;;
- hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
- # FIXME: really hppa2.0-hp
- basic_machine=hppa1.1-hp
- ;;
- hp9k8[0-9][13679] | hp8[0-9][13679])
- basic_machine=hppa1.1-hp
- ;;
- hp9k8[0-9][0-9] | hp8[0-9][0-9])
- basic_machine=hppa1.0-hp
- ;;
- hppa-next)
- os=-nextstep3
- ;;
- hppaosf)
- basic_machine=hppa1.1-hp
- os=-osf
- ;;
- hppro)
- basic_machine=hppa1.1-hp
- os=-proelf
- ;;
- i370-ibm* | ibm*)
- basic_machine=i370-ibm
- ;;
-# I'm not sure what "Sysv32" means. Should this be sysv3.2?
- i*86v32)
- basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
- os=-sysv32
- ;;
- i*86v4*)
- basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
- os=-sysv4
- ;;
- i*86v)
- basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
- os=-sysv
- ;;
- i*86sol2)
- basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
- os=-solaris2
- ;;
- i386mach)
- basic_machine=i386-mach
- os=-mach
- ;;
- i386-vsta | vsta)
- basic_machine=i386-unknown
- os=-vsta
- ;;
- iris | iris4d)
- basic_machine=mips-sgi
- case $os in
- -irix*)
- ;;
- *)
- os=-irix4
- ;;
- esac
- ;;
- isi68 | isi)
- basic_machine=m68k-isi
- os=-sysv
- ;;
- m88k-omron*)
- basic_machine=m88k-omron
- ;;
- magnum | m3230)
- basic_machine=mips-mips
- os=-sysv
- ;;
- merlin)
- basic_machine=ns32k-utek
- os=-sysv
- ;;
- mingw32)
- basic_machine=i386-pc
- os=-mingw32
- ;;
- mingw32ce)
- basic_machine=arm-unknown
- os=-mingw32ce
- ;;
- miniframe)
- basic_machine=m68000-convergent
- ;;
- *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
- basic_machine=m68k-atari
- os=-mint
- ;;
- mips3*-*)
- basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
- ;;
- mips3*)
- basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
- ;;
- monitor)
- basic_machine=m68k-rom68k
- os=-coff
- ;;
- morphos)
- basic_machine=powerpc-unknown
- os=-morphos
- ;;
- msdos)
- basic_machine=i386-pc
- os=-msdos
- ;;
- ms1-*)
- basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
- ;;
- mvs)
- basic_machine=i370-ibm
- os=-mvs
- ;;
- ncr3000)
- basic_machine=i486-ncr
- os=-sysv4
- ;;
- netbsd386)
- basic_machine=i386-unknown
- os=-netbsd
- ;;
- netwinder)
- basic_machine=armv4l-rebel
- os=-linux
- ;;
- news | news700 | news800 | news900)
- basic_machine=m68k-sony
- os=-newsos
- ;;
- news1000)
- basic_machine=m68030-sony
- os=-newsos
- ;;
- news-3600 | risc-news)
- basic_machine=mips-sony
- os=-newsos
- ;;
- necv70)
- basic_machine=v70-nec
- os=-sysv
- ;;
- next | m*-next )
- basic_machine=m68k-next
- case $os in
- -nextstep* )
- ;;
- -ns2*)
- os=-nextstep2
- ;;
- *)
- os=-nextstep3
- ;;
- esac
- ;;
- nh3000)
- basic_machine=m68k-harris
- os=-cxux
- ;;
- nh[45]000)
- basic_machine=m88k-harris
- os=-cxux
- ;;
- nindy960)
- basic_machine=i960-intel
- os=-nindy
- ;;
- mon960)
- basic_machine=i960-intel
- os=-mon960
- ;;
- nonstopux)
- basic_machine=mips-compaq
- os=-nonstopux
- ;;
- np1)
- basic_machine=np1-gould
- ;;
- nsr-tandem)
- basic_machine=nsr-tandem
- ;;
- op50n-* | op60c-*)
- basic_machine=hppa1.1-oki
- os=-proelf
- ;;
- openrisc | openrisc-*)
- basic_machine=or32-unknown
- ;;
- os400)
- basic_machine=powerpc-ibm
- os=-os400
- ;;
- OSE68000 | ose68000)
- basic_machine=m68000-ericsson
- os=-ose
- ;;
- os68k)
- basic_machine=m68k-none
- os=-os68k
- ;;
- pa-hitachi)
- basic_machine=hppa1.1-hitachi
- os=-hiuxwe2
- ;;
- paragon)
- basic_machine=i860-intel
- os=-osf
- ;;
- pbd)
- basic_machine=sparc-tti
- ;;
- pbb)
- basic_machine=m68k-tti
- ;;
- pc532 | pc532-*)
- basic_machine=ns32k-pc532
- ;;
- pc98)
- basic_machine=i386-pc
- ;;
- pc98-*)
- basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- pentium | p5 | k5 | k6 | nexgen | viac3)
- basic_machine=i586-pc
- ;;
- pentiumpro | p6 | 6x86 | athlon | athlon_*)
- basic_machine=i686-pc
- ;;
- pentiumii | pentium2 | pentiumiii | pentium3)
- basic_machine=i686-pc
- ;;
- pentium4)
- basic_machine=i786-pc
- ;;
- pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
- basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- pentiumpro-* | p6-* | 6x86-* | athlon-*)
- basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
- basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- pentium4-*)
- basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- pn)
- basic_machine=pn-gould
- ;;
- power) basic_machine=power-ibm
- ;;
- ppc) basic_machine=powerpc-unknown
- ;;
- ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- ppcle | powerpclittle | ppc-le | powerpc-little)
- basic_machine=powerpcle-unknown
- ;;
- ppcle-* | powerpclittle-*)
- basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- ppc64) basic_machine=powerpc64-unknown
- ;;
- ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- ppc64le | powerpc64little | ppc64-le | powerpc64-little)
- basic_machine=powerpc64le-unknown
- ;;
- ppc64le-* | powerpc64little-*)
- basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- ps2)
- basic_machine=i386-ibm
- ;;
- pw32)
- basic_machine=i586-unknown
- os=-pw32
- ;;
- rdos)
- basic_machine=i386-pc
- os=-rdos
- ;;
- rom68k)
- basic_machine=m68k-rom68k
- os=-coff
- ;;
- rm[46]00)
- basic_machine=mips-siemens
- ;;
- rtpc | rtpc-*)
- basic_machine=romp-ibm
- ;;
- s390 | s390-*)
- basic_machine=s390-ibm
- ;;
- s390x | s390x-*)
- basic_machine=s390x-ibm
- ;;
- sa29200)
- basic_machine=a29k-amd
- os=-udi
- ;;
- sb1)
- basic_machine=mipsisa64sb1-unknown
- ;;
- sb1el)
- basic_machine=mipsisa64sb1el-unknown
- ;;
- sde)
- basic_machine=mipsisa32-sde
- os=-elf
- ;;
- sei)
- basic_machine=mips-sei
- os=-seiux
- ;;
- sequent)
- basic_machine=i386-sequent
- ;;
- sh)
- basic_machine=sh-hitachi
- os=-hms
- ;;
- sh5el)
- basic_machine=sh5le-unknown
- ;;
- sh64)
- basic_machine=sh64-unknown
- ;;
- sparclite-wrs | simso-wrs)
- basic_machine=sparclite-wrs
- os=-vxworks
- ;;
- sps7)
- basic_machine=m68k-bull
- os=-sysv2
- ;;
- spur)
- basic_machine=spur-unknown
- ;;
- st2000)
- basic_machine=m68k-tandem
- ;;
- stratus)
- basic_machine=i860-stratus
- os=-sysv4
- ;;
- sun2)
- basic_machine=m68000-sun
- ;;
- sun2os3)
- basic_machine=m68000-sun
- os=-sunos3
- ;;
- sun2os4)
- basic_machine=m68000-sun
- os=-sunos4
- ;;
- sun3os3)
- basic_machine=m68k-sun
- os=-sunos3
- ;;
- sun3os4)
- basic_machine=m68k-sun
- os=-sunos4
- ;;
- sun4os3)
- basic_machine=sparc-sun
- os=-sunos3
- ;;
- sun4os4)
- basic_machine=sparc-sun
- os=-sunos4
- ;;
- sun4sol2)
- basic_machine=sparc-sun
- os=-solaris2
- ;;
- sun3 | sun3-*)
- basic_machine=m68k-sun
- ;;
- sun4)
- basic_machine=sparc-sun
- ;;
- sun386 | sun386i | roadrunner)
- basic_machine=i386-sun
- ;;
- sv1)
- basic_machine=sv1-cray
- os=-unicos
- ;;
- symmetry)
- basic_machine=i386-sequent
- os=-dynix
- ;;
- t3e)
- basic_machine=alphaev5-cray
- os=-unicos
- ;;
- t90)
- basic_machine=t90-cray
- os=-unicos
- ;;
- tic54x | c54x*)
- basic_machine=tic54x-unknown
- os=-coff
- ;;
- tic55x | c55x*)
- basic_machine=tic55x-unknown
- os=-coff
- ;;
- tic6x | c6x*)
- basic_machine=tic6x-unknown
- os=-coff
- ;;
- tx39)
- basic_machine=mipstx39-unknown
- ;;
- tx39el)
- basic_machine=mipstx39el-unknown
- ;;
- tile*)
- basic_machine=tile-tilera
- os=-linux-gnu
- ;;
- toad1)
- basic_machine=pdp10-xkl
- os=-tops20
- ;;
- tower | tower-32)
- basic_machine=m68k-ncr
- ;;
- tpf)
- basic_machine=s390x-ibm
- os=-tpf
- ;;
- udi29k)
- basic_machine=a29k-amd
- os=-udi
- ;;
- ultra3)
- basic_machine=a29k-nyu
- os=-sym1
- ;;
- v810 | necv810)
- basic_machine=v810-nec
- os=-none
- ;;
- vaxv)
- basic_machine=vax-dec
- os=-sysv
- ;;
- vms)
- basic_machine=vax-dec
- os=-vms
- ;;
- vpp*|vx|vx-*)
- basic_machine=f301-fujitsu
- ;;
- vxworks960)
- basic_machine=i960-wrs
- os=-vxworks
- ;;
- vxworks68)
- basic_machine=m68k-wrs
- os=-vxworks
- ;;
- vxworks29k)
- basic_machine=a29k-wrs
- os=-vxworks
- ;;
- w65*)
- basic_machine=w65-wdc
- os=-none
- ;;
- w89k-*)
- basic_machine=hppa1.1-winbond
- os=-proelf
- ;;
- xbox)
- basic_machine=i686-pc
- os=-mingw32
- ;;
- xps | xps100)
- basic_machine=xps100-honeywell
- ;;
- ymp)
- basic_machine=ymp-cray
- os=-unicos
- ;;
- z8k-*-coff)
- basic_machine=z8k-unknown
- os=-sim
- ;;
- none)
- basic_machine=none-none
- os=-none
- ;;
-
-# Here we handle the default manufacturer of certain CPU types. It is in
-# some cases the only manufacturer, in others, it is the most popular.
- w89k)
- basic_machine=hppa1.1-winbond
- ;;
- op50n)
- basic_machine=hppa1.1-oki
- ;;
- op60c)
- basic_machine=hppa1.1-oki
- ;;
- romp)
- basic_machine=romp-ibm
- ;;
- mmix)
- basic_machine=mmix-knuth
- ;;
- rs6000)
- basic_machine=rs6000-ibm
- ;;
- vax)
- basic_machine=vax-dec
- ;;
- pdp10)
- # there are many clones, so DEC is not a safe bet
- basic_machine=pdp10-unknown
- ;;
- pdp11)
- basic_machine=pdp11-dec
- ;;
- we32k)
- basic_machine=we32k-att
- ;;
- sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
- basic_machine=sh-unknown
- ;;
- sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
- basic_machine=sparc-sun
- ;;
- cydra)
- basic_machine=cydra-cydrome
- ;;
- orion)
- basic_machine=orion-highlevel
- ;;
- orion105)
- basic_machine=clipper-highlevel
- ;;
- mac | mpw | mac-mpw)
- basic_machine=m68k-apple
- ;;
- pmac | pmac-mpw)
- basic_machine=powerpc-apple
- ;;
- *-unknown)
- # Make sure to match an already-canonicalized machine name.
- ;;
- *)
- echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
- exit 1
- ;;
-esac
-
-# Here we canonicalize certain aliases for manufacturers.
-case $basic_machine in
- *-digital*)
- basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
- ;;
- *-commodore*)
- basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
- ;;
- *)
- ;;
-esac
-
-# Decode manufacturer-specific aliases for certain operating systems.
-
-if [ x"$os" != x"" ]
-then
-case $os in
- # First match some system type aliases
- # that might get confused with valid system types.
- # -solaris* is a basic system type, with this one exception.
- -solaris1 | -solaris1.*)
- os=`echo $os | sed -e 's|solaris1|sunos4|'`
- ;;
- -solaris)
- os=-solaris2
- ;;
- -svr4*)
- os=-sysv4
- ;;
- -unixware*)
- os=-sysv4.2uw
- ;;
- -gnu/linux*)
- os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
- ;;
- # First accept the basic system types.
- # The portable systems comes first.
- # Each alternative MUST END IN A *, to match a version number.
- # -sysv* is not here because it comes later, after sysvr4.
- -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
- | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
- | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
- | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
- | -aos* \
- | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
- | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
- | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
- | -openbsd* | -solidbsd* \
- | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
- | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
- | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
- | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
- | -chorusos* | -chorusrdb* \
- | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
- | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
- | -uxpv* | -beos* | -mpeix* | -udk* \
- | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
- | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
- | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
- | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
- | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
- | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
- | -skyos* | -haiku* | -rdos* | -toppers* | -drops*)
- # Remember, each alternative MUST END IN *, to match a version number.
- ;;
- -qnx*)
- case $basic_machine in
- x86-* | i*86-*)
- ;;
- *)
- os=-nto$os
- ;;
- esac
- ;;
- -nto-qnx*)
- ;;
- -nto*)
- os=`echo $os | sed -e 's|nto|nto-qnx|'`
- ;;
- -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
- | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
- | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
- ;;
- -mac*)
- os=`echo $os | sed -e 's|mac|macos|'`
- ;;
- -linux-dietlibc)
- os=-linux-dietlibc
- ;;
- -linux*)
- os=`echo $os | sed -e 's|linux|linux-gnu|'`
- ;;
- -sunos5*)
- os=`echo $os | sed -e 's|sunos5|solaris2|'`
- ;;
- -sunos6*)
- os=`echo $os | sed -e 's|sunos6|solaris3|'`
- ;;
- -opened*)
- os=-openedition
- ;;
- -os400*)
- os=-os400
- ;;
- -wince*)
- os=-wince
- ;;
- -osfrose*)
- os=-osfrose
- ;;
- -osf*)
- os=-osf
- ;;
- -utek*)
- os=-bsd
- ;;
- -dynix*)
- os=-bsd
- ;;
- -acis*)
- os=-aos
- ;;
- -atheos*)
- os=-atheos
- ;;
- -syllable*)
- os=-syllable
- ;;
- -386bsd)
- os=-bsd
- ;;
- -ctix* | -uts*)
- os=-sysv
- ;;
- -nova*)
- os=-rtmk-nova
- ;;
- -ns2 )
- os=-nextstep2
- ;;
- -nsk*)
- os=-nsk
- ;;
- # Preserve the version number of sinix5.
- -sinix5.*)
- os=`echo $os | sed -e 's|sinix|sysv|'`
- ;;
- -sinix*)
- os=-sysv4
- ;;
- -tpf*)
- os=-tpf
- ;;
- -triton*)
- os=-sysv3
- ;;
- -oss*)
- os=-sysv3
- ;;
- -svr4)
- os=-sysv4
- ;;
- -svr3)
- os=-sysv3
- ;;
- -sysvr4)
- os=-sysv4
- ;;
- # This must come after -sysvr4.
- -sysv*)
- ;;
- -ose*)
- os=-ose
- ;;
- -es1800*)
- os=-ose
- ;;
- -xenix)
- os=-xenix
- ;;
- -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
- os=-mint
- ;;
- -aros*)
- os=-aros
- ;;
- -kaos*)
- os=-kaos
- ;;
- -zvmoe)
- os=-zvmoe
- ;;
- -none)
- ;;
- *)
- # Get rid of the `-' at the beginning of $os.
- os=`echo $os | sed 's/[^-]*-//'`
- echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
- exit 1
- ;;
-esac
-else
-
-# Here we handle the default operating systems that come with various machines.
-# The value should be what the vendor currently ships out the door with their
-# machine or put another way, the most popular os provided with the machine.
-
-# Note that if you're going to try to match "-MANUFACTURER" here (say,
-# "-sun"), then you have to tell the case statement up towards the top
-# that MANUFACTURER isn't an operating system. Otherwise, code above
-# will signal an error saying that MANUFACTURER isn't an operating
-# system, and we'll never get to this point.
-
-case $basic_machine in
- score-*)
- os=-elf
- ;;
- spu-*)
- os=-elf
- ;;
- *-acorn)
- os=-riscix1.2
- ;;
- arm*-rebel)
- os=-linux
- ;;
- arm*-semi)
- os=-aout
- ;;
- c4x-* | tic4x-*)
- os=-coff
- ;;
- # This must come before the *-dec entry.
- pdp10-*)
- os=-tops20
- ;;
- pdp11-*)
- os=-none
- ;;
- *-dec | vax-*)
- os=-ultrix4.2
- ;;
- m68*-apollo)
- os=-domain
- ;;
- i386-sun)
- os=-sunos4.0.2
- ;;
- m68000-sun)
- os=-sunos3
- # This also exists in the configure program, but was not the
- # default.
- # os=-sunos4
- ;;
- m68*-cisco)
- os=-aout
- ;;
- mep-*)
- os=-elf
- ;;
- mips*-cisco)
- os=-elf
- ;;
- mips*-*)
- os=-elf
- ;;
- or32-*)
- os=-coff
- ;;
- *-tti) # must be before sparc entry or we get the wrong os.
- os=-sysv3
- ;;
- sparc-* | *-sun)
- os=-sunos4.1.1
- ;;
- *-be)
- os=-beos
- ;;
- *-haiku)
- os=-haiku
- ;;
- *-ibm)
- os=-aix
- ;;
- *-knuth)
- os=-mmixware
- ;;
- *-wec)
- os=-proelf
- ;;
- *-winbond)
- os=-proelf
- ;;
- *-oki)
- os=-proelf
- ;;
- *-hp)
- os=-hpux
- ;;
- *-hitachi)
- os=-hiux
- ;;
- i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
- os=-sysv
- ;;
- *-cbm)
- os=-amigaos
- ;;
- *-dg)
- os=-dgux
- ;;
- *-dolphin)
- os=-sysv3
- ;;
- m68k-ccur)
- os=-rtu
- ;;
- m88k-omron*)
- os=-luna
- ;;
- *-next )
- os=-nextstep
- ;;
- *-sequent)
- os=-ptx
- ;;
- *-crds)
- os=-unos
- ;;
- *-ns)
- os=-genix
- ;;
- i370-*)
- os=-mvs
- ;;
- *-next)
- os=-nextstep3
- ;;
- *-gould)
- os=-sysv
- ;;
- *-highlevel)
- os=-bsd
- ;;
- *-encore)
- os=-bsd
- ;;
- *-sgi)
- os=-irix
- ;;
- *-siemens)
- os=-sysv4
- ;;
- *-masscomp)
- os=-rtu
- ;;
- f30[01]-fujitsu | f700-fujitsu)
- os=-uxpv
- ;;
- *-rom68k)
- os=-coff
- ;;
- *-*bug)
- os=-coff
- ;;
- *-apple)
- os=-macos
- ;;
- *-atari*)
- os=-mint
- ;;
- *)
- os=-none
- ;;
-esac
-fi
-
-# Here we handle the case where we know the os, and the CPU type, but not the
-# manufacturer. We pick the logical manufacturer.
-vendor=unknown
-case $basic_machine in
- *-unknown)
- case $os in
- -riscix*)
- vendor=acorn
- ;;
- -sunos*)
- vendor=sun
- ;;
- -aix*)
- vendor=ibm
- ;;
- -beos*)
- vendor=be
- ;;
- -hpux*)
- vendor=hp
- ;;
- -mpeix*)
- vendor=hp
- ;;
- -hiux*)
- vendor=hitachi
- ;;
- -unos*)
- vendor=crds
- ;;
- -dgux*)
- vendor=dg
- ;;
- -luna*)
- vendor=omron
- ;;
- -genix*)
- vendor=ns
- ;;
- -mvs* | -opened*)
- vendor=ibm
- ;;
- -os400*)
- vendor=ibm
- ;;
- -ptx*)
- vendor=sequent
- ;;
- -tpf*)
- vendor=ibm
- ;;
- -vxsim* | -vxworks* | -windiss*)
- vendor=wrs
- ;;
- -aux*)
- vendor=apple
- ;;
- -hms*)
- vendor=hitachi
- ;;
- -mpw* | -macos*)
- vendor=apple
- ;;
- -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
- vendor=atari
- ;;
- -vos*)
- vendor=stratus
- ;;
- esac
- basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
- ;;
-esac
-
-echo $basic_machine$os
-exit
-
-# Local variables:
-# eval: (add-hook 'write-file-hooks 'time-stamp)
-# time-stamp-start: "timestamp='"
-# time-stamp-format: "%:y-%02m-%02d"
-# time-stamp-end: "'"
-# End:
diff --git a/lib/diameter/autoconf/install-sh b/lib/diameter/autoconf/install-sh
deleted file mode 100755
index a5897de6ea..0000000000
--- a/lib/diameter/autoconf/install-sh
+++ /dev/null
@@ -1,519 +0,0 @@
-#!/bin/sh
-# install - install a program, script, or datafile
-
-scriptversion=2006-12-25.00
-
-# This originates from X11R5 (mit/util/scripts/install.sh), which was
-# later released in X11R6 (xc/config/util/install.sh) with the
-# following copyright and license.
-#
-# Copyright (C) 1994 X Consortium
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to
-# deal in the Software without restriction, including without limitation the
-# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-# sell copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
-# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
-# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-# Except as contained in this notice, the name of the X Consortium shall not
-# be used in advertising or otherwise to promote the sale, use or other deal-
-# ings in this Software without prior written authorization from the X Consor-
-# tium.
-#
-#
-# FSF changes to this file are in the public domain.
-#
-# Calling this script install-sh is preferred over install.sh, to prevent
-# `make' implicit rules from creating a file called install from it
-# when there is no Makefile.
-#
-# This script is compatible with the BSD install script, but was written
-# from scratch.
-
-nl='
-'
-IFS=" "" $nl"
-
-# set DOITPROG to echo to test this script
-
-# Don't use :- since 4.3BSD and earlier shells don't like it.
-doit=${DOITPROG-}
-if test -z "$doit"; then
- doit_exec=exec
-else
- doit_exec=$doit
-fi
-
-# Put in absolute file names if you don't have them in your path;
-# or use environment vars.
-
-chgrpprog=${CHGRPPROG-chgrp}
-chmodprog=${CHMODPROG-chmod}
-chownprog=${CHOWNPROG-chown}
-cmpprog=${CMPPROG-cmp}
-cpprog=${CPPROG-cp}
-mkdirprog=${MKDIRPROG-mkdir}
-mvprog=${MVPROG-mv}
-rmprog=${RMPROG-rm}
-stripprog=${STRIPPROG-strip}
-
-posix_glob='?'
-initialize_posix_glob='
- test "$posix_glob" != "?" || {
- if (set -f) 2>/dev/null; then
- posix_glob=
- else
- posix_glob=:
- fi
- }
-'
-
-posix_mkdir=
-
-# Desired mode of installed file.
-mode=0755
-
-chgrpcmd=
-chmodcmd=$chmodprog
-chowncmd=
-mvcmd=$mvprog
-rmcmd="$rmprog -f"
-stripcmd=
-
-src=
-dst=
-dir_arg=
-dst_arg=
-
-copy_on_change=false
-no_target_directory=
-
-usage="\
-Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
- or: $0 [OPTION]... SRCFILES... DIRECTORY
- or: $0 [OPTION]... -t DIRECTORY SRCFILES...
- or: $0 [OPTION]... -d DIRECTORIES...
-
-In the 1st form, copy SRCFILE to DSTFILE.
-In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
-In the 4th, create DIRECTORIES.
-
-Options:
- --help display this help and exit.
- --version display version info and exit.
-
- -c (ignored)
- -C install only if different (preserve the last data modification time)
- -d create directories instead of installing files.
- -g GROUP $chgrpprog installed files to GROUP.
- -m MODE $chmodprog installed files to MODE.
- -o USER $chownprog installed files to USER.
- -s $stripprog installed files.
- -t DIRECTORY install into DIRECTORY.
- -T report an error if DSTFILE is a directory.
-
-Environment variables override the default commands:
- CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
- RMPROG STRIPPROG
-"
-
-while test $# -ne 0; do
- case $1 in
- -c) ;;
-
- -C) copy_on_change=true;;
-
- -d) dir_arg=true;;
-
- -g) chgrpcmd="$chgrpprog $2"
- shift;;
-
- --help) echo "$usage"; exit $?;;
-
- -m) mode=$2
- case $mode in
- *' '* | *' '* | *'
-'* | *'*'* | *'?'* | *'['*)
- echo "$0: invalid mode: $mode" >&2
- exit 1;;
- esac
- shift;;
-
- -o) chowncmd="$chownprog $2"
- shift;;
-
- -s) stripcmd=$stripprog;;
-
- -t) dst_arg=$2
- shift;;
-
- -T) no_target_directory=true;;
-
- --version) echo "$0 $scriptversion"; exit $?;;
-
- --) shift
- break;;
-
- -*) echo "$0: invalid option: $1" >&2
- exit 1;;
-
- *) break;;
- esac
- shift
-done
-
-if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
- # When -d is used, all remaining arguments are directories to create.
- # When -t is used, the destination is already specified.
- # Otherwise, the last argument is the destination. Remove it from $@.
- for arg
- do
- if test -n "$dst_arg"; then
- # $@ is not empty: it contains at least $arg.
- set fnord "$@" "$dst_arg"
- shift # fnord
- fi
- shift # arg
- dst_arg=$arg
- done
-fi
-
-if test $# -eq 0; then
- if test -z "$dir_arg"; then
- echo "$0: no input file specified." >&2
- exit 1
- fi
- # It's OK to call `install-sh -d' without argument.
- # This can happen when creating conditional directories.
- exit 0
-fi
-
-if test -z "$dir_arg"; then
- trap '(exit $?); exit' 1 2 13 15
-
- # Set umask so as not to create temps with too-generous modes.
- # However, 'strip' requires both read and write access to temps.
- case $mode in
- # Optimize common cases.
- *644) cp_umask=133;;
- *755) cp_umask=22;;
-
- *[0-7])
- if test -z "$stripcmd"; then
- u_plus_rw=
- else
- u_plus_rw='% 200'
- fi
- cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
- *)
- if test -z "$stripcmd"; then
- u_plus_rw=
- else
- u_plus_rw=,u+rw
- fi
- cp_umask=$mode$u_plus_rw;;
- esac
-fi
-
-for src
-do
- # Protect names starting with `-'.
- case $src in
- -*) src=./$src;;
- esac
-
- if test -n "$dir_arg"; then
- dst=$src
- dstdir=$dst
- test -d "$dstdir"
- dstdir_status=$?
- else
-
- # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
- # might cause directories to be created, which would be especially bad
- # if $src (and thus $dsttmp) contains '*'.
- if test ! -f "$src" && test ! -d "$src"; then
- echo "$0: $src does not exist." >&2
- exit 1
- fi
-
- if test -z "$dst_arg"; then
- echo "$0: no destination specified." >&2
- exit 1
- fi
-
- dst=$dst_arg
- # Protect names starting with `-'.
- case $dst in
- -*) dst=./$dst;;
- esac
-
- # If destination is a directory, append the input filename; won't work
- # if double slashes aren't ignored.
- if test -d "$dst"; then
- if test -n "$no_target_directory"; then
- echo "$0: $dst_arg: Is a directory" >&2
- exit 1
- fi
- dstdir=$dst
- dst=$dstdir/`basename "$src"`
- dstdir_status=0
- else
- # Prefer dirname, but fall back on a substitute if dirname fails.
- dstdir=`
- (dirname "$dst") 2>/dev/null ||
- expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
- X"$dst" : 'X\(//\)[^/]' \| \
- X"$dst" : 'X\(//\)$' \| \
- X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
- echo X"$dst" |
- sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
- s//\1/
- q
- }
- /^X\(\/\/\)[^/].*/{
- s//\1/
- q
- }
- /^X\(\/\/\)$/{
- s//\1/
- q
- }
- /^X\(\/\).*/{
- s//\1/
- q
- }
- s/.*/./; q'
- `
-
- test -d "$dstdir"
- dstdir_status=$?
- fi
- fi
-
- obsolete_mkdir_used=false
-
- if test $dstdir_status != 0; then
- case $posix_mkdir in
- '')
- # Create intermediate dirs using mode 755 as modified by the umask.
- # This is like FreeBSD 'install' as of 1997-10-28.
- umask=`umask`
- case $stripcmd.$umask in
- # Optimize common cases.
- *[2367][2367]) mkdir_umask=$umask;;
- .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
-
- *[0-7])
- mkdir_umask=`expr $umask + 22 \
- - $umask % 100 % 40 + $umask % 20 \
- - $umask % 10 % 4 + $umask % 2
- `;;
- *) mkdir_umask=$umask,go-w;;
- esac
-
- # With -d, create the new directory with the user-specified mode.
- # Otherwise, rely on $mkdir_umask.
- if test -n "$dir_arg"; then
- mkdir_mode=-m$mode
- else
- mkdir_mode=
- fi
-
- posix_mkdir=false
- case $umask in
- *[123567][0-7][0-7])
- # POSIX mkdir -p sets u+wx bits regardless of umask, which
- # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
- ;;
- *)
- tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
- trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
-
- if (umask $mkdir_umask &&
- exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
- then
- if test -z "$dir_arg" || {
- # Check for POSIX incompatibilities with -m.
- # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
- # other-writeable bit of parent directory when it shouldn't.
- # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
- ls_ld_tmpdir=`ls -ld "$tmpdir"`
- case $ls_ld_tmpdir in
- d????-?r-*) different_mode=700;;
- d????-?--*) different_mode=755;;
- *) false;;
- esac &&
- $mkdirprog -m$different_mode -p -- "$tmpdir" && {
- ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
- test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
- }
- }
- then posix_mkdir=:
- fi
- rmdir "$tmpdir/d" "$tmpdir"
- else
- # Remove any dirs left behind by ancient mkdir implementations.
- rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
- fi
- trap '' 0;;
- esac;;
- esac
-
- if
- $posix_mkdir && (
- umask $mkdir_umask &&
- $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
- )
- then :
- else
-
- # The umask is ridiculous, or mkdir does not conform to POSIX,
- # or it failed possibly due to a race condition. Create the
- # directory the slow way, step by step, checking for races as we go.
-
- case $dstdir in
- /*) prefix='/';;
- -*) prefix='./';;
- *) prefix='';;
- esac
-
- eval "$initialize_posix_glob"
-
- oIFS=$IFS
- IFS=/
- $posix_glob set -f
- set fnord $dstdir
- shift
- $posix_glob set +f
- IFS=$oIFS
-
- prefixes=
-
- for d
- do
- test -z "$d" && continue
-
- prefix=$prefix$d
- if test -d "$prefix"; then
- prefixes=
- else
- if $posix_mkdir; then
- (umask=$mkdir_umask &&
- $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
- # Don't fail if two instances are running concurrently.
- test -d "$prefix" || exit 1
- else
- case $prefix in
- *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
- *) qprefix=$prefix;;
- esac
- prefixes="$prefixes '$qprefix'"
- fi
- fi
- prefix=$prefix/
- done
-
- if test -n "$prefixes"; then
- # Don't fail if two instances are running concurrently.
- (umask $mkdir_umask &&
- eval "\$doit_exec \$mkdirprog $prefixes") ||
- test -d "$dstdir" || exit 1
- obsolete_mkdir_used=true
- fi
- fi
- fi
-
- if test -n "$dir_arg"; then
- { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
- { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
- { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
- test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
- else
-
- # Make a couple of temp file names in the proper directory.
- dsttmp=$dstdir/_inst.$$_
- rmtmp=$dstdir/_rm.$$_
-
- # Trap to clean up those temp files at exit.
- trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
-
- # Copy the file name to the temp name.
- (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
-
- # and set any options; do chmod last to preserve setuid bits.
- #
- # If any of these fail, we abort the whole thing. If we want to
- # ignore errors from any of these, just make sure not to ignore
- # errors from the above "$doit $cpprog $src $dsttmp" command.
- #
- { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
- { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
- { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
- { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
-
- # If -C, don't bother to copy if it wouldn't change the file.
- if $copy_on_change &&
- old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
- new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
-
- eval "$initialize_posix_glob" &&
- $posix_glob set -f &&
- set X $old && old=:$2:$4:$5:$6 &&
- set X $new && new=:$2:$4:$5:$6 &&
- $posix_glob set +f &&
-
- test "$old" = "$new" &&
- $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
- then
- rm -f "$dsttmp"
- else
- # Rename the file to the real destination.
- $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
-
- # The rename failed, perhaps because mv can't rename something else
- # to itself, or perhaps because mv is so ancient that it does not
- # support -f.
- {
- # Now remove or move aside any old file at destination location.
- # We try this two ways since rm can't unlink itself on some
- # systems and the destination file might be busy for other
- # reasons. In this case, the final cleanup might fail but the new
- # file should still install successfully.
- {
- test ! -f "$dst" ||
- $doit $rmcmd -f "$dst" 2>/dev/null ||
- { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
- { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
- } ||
- { echo "$0: cannot unlink or rename $dst" >&2
- (exit 1); exit 1
- }
- } &&
-
- # Now rename the file to the real destination.
- $doit $mvcmd "$dsttmp" "$dst"
- }
- fi || exit 1
-
- trap '' 0
- fi
-done
-
-# Local variables:
-# eval: (add-hook 'write-file-hooks 'time-stamp)
-# time-stamp-start: "scriptversion="
-# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-end: "$"
-# End:
diff --git a/lib/diameter/configure.in b/lib/diameter/configure.in
deleted file mode 100644
index 8acfb28fed..0000000000
--- a/lib/diameter/configure.in
+++ /dev/null
@@ -1,137 +0,0 @@
-dnl Process this file with autoconf to produce a configure script.
-
-dnl %CopyrightBegin%
-dnl
-dnl Copyright Ericsson AB 1998-2011. All Rights Reserved.
-dnl
-dnl The contents of this file are subject to the Erlang Public License,
-dnl Version 1.1, (the "License"); you may not use this file except in
-dnl compliance with the License. You should have received a copy of the
-dnl Erlang Public License along with this software. If not, it can be
-dnl retrieved online at http://www.erlang.org/.
-dnl
-dnl Software distributed under the License is distributed on an "AS IS"
-dnl basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-dnl the License for the specific language governing rights and limitations
-dnl under the License.
-dnl
-dnl %CopyrightEnd%
-
-if test "x$no_recursion" != "xyes" -a "x$OVERRIDE_CONFIG_CACHE" = "x"; then
- # We do not want to use a common cache!
- cache_file=/dev/null
-fi
-
-AC_INIT(vsn.mk)
-
-dnl <STANDALONE DIAMETER>
-dnl This is needed for diameters own environment to rock,
-dnl but since we are now integrated into OTP, we skip it.
-dnl In order to build stand-alone we need atleast 2.63...
-dnl AC_PREREQ(2.63)
-dnl </STANDALONE DIAMETER>
-
-dnl LM_PRECIOUS_VARS
-
-
-dnl The OTP source tree is the default "top",
-dnl but we can also define our own top: DIAMETER_TOP
-
-if test -n "$ERL_TOP" || test -d $ERL_TOP ; then
- erl_top=${ERL_TOP}
- AC_CONFIG_AUX_DIRS($erl_top/erts/autoconf)
- DIAMETER_TOP=${ERL_TOP}/lib/diameter
-else
- AC_ARG_VAR(DIAMETER_TOP, [Diameter top source directory])
- if test -n "$DIAMETER_TOP" || test -d $DIAMETER_TOP ; then
- AC_CONFIG_AUX_DIRS(autoconf)
- fi
-
- dnl <STANDALONE DIAMETER>
- dnl AC_ERLANG_SUBST_ROOT_DIR
- dnl AC_ERLANG_SUBST_LIB_DIR
- dnl AC_ERLANG_CHECK_LIB([erl_docgen],
- dnl [echo "erl_docgen version \"$ERLANG_LIB_VER_erl_docgen\""
- dnl echo "is installed in \"$ERLANG_LIB_DIR_erl_docgen\""],
- dnl [AC_MSG_ERROR([erl_docgen was not found!])])
- dnl AC_ERLANG_CHECK_LIB([test_server],
- dnl [echo "test_server version \"$ERLANG_LIB_VER_test_server\""
- dnl echo "is installed in \"$ERLANG_LIB_DIR_test_server\""],
- dnl [AC_MSG_ERROR([test_server was not found!])])
- dnl </STANDALONE DIAMETER>
-
-fi
-
-AC_SUBST(DIAMETER_TOP)
-export DIAMETER_TOP
-
-if test "X$host" != "Xfree_source" -a "X$host" != "Xwin32"; then
- AC_CANONICAL_HOST
-fi
-
-TARGET=$host
-AC_SUBST(TARGET)
-
-if test "x$erl_top" = "x"; then
- dnl STANDALONE DIAMETER
- AC_CHECK_PROGS(XSLTPROC, xsltproc)
- if test -z "$XSLTPROC"; then
- echo "xsltproc" >> doc/CONF_INFO
- AC_MSG_WARN([No 'xsltproc' command found: the documentation can not be built])
- fi
-
- AC_CHECK_PROGS(FOP, fop)
- if test -z "$FOP"; then
- AC_MSG_ERROR([No 'fop' command found: the documentation can not be built])
- fi
-fi
-
-dnl
-dnl We can live with Solaris /usr/ucb/install
-dnl
-case $host in
- *-*-solaris*|free_source)
- if test -x /usr/ucb/install; then
- INSTALL="/usr/ucb/install -c"
- fi
- ;;
- *)
- ;;
-esac
-AC_PROG_INSTALL
-LM_PROG_INSTALL_DIR
-
-case $host_os in
- darwin*)
- dnl Need to preserve modification time on archives;
- dnl otherwise, ranlib has to be run on archives
- dnl again after installation.
- INSTALL_DATA="$INSTALL_DATA -p";;
- *)
- ;;
-esac
-
-dnl
-dnl Fix for Tilera install permissions
-dnl
-
-case $build in
- *tile*)
- INSTALL_PROGRAM="$INSTALL_PROGRAM -m755"
- INSTALL_SCRIPT="$INSTALL_SCRIPT -m755"
- ;;
- *)
- ;;
-esac
-
-
-dnl <STANDALONE DIAMETER>
-dnl AC_ERLANG_NEED_ERL([$PATH])
-dnl AC_ERLANG_NEED_ERLC([$PATH])
-dnl </STANDALONE DIAMETER>
-
-AC_OUTPUT(
- Makefile:Makefile.in
- make/$host/rules.mk:make/rules.mk.in
- )
-
diff --git a/lib/diameter/doc/.gitignore b/lib/diameter/doc/.gitignore
new file mode 100644
index 0000000000..b634bdd7ba
--- /dev/null
+++ b/lib/diameter/doc/.gitignore
@@ -0,0 +1,4 @@
+
+/html/
+/man*/
+/pdf/
diff --git a/lib/diameter/doc/src/.gitignore b/lib/diameter/doc/src/.gitignore
index feeb378fd8..5776e1cc76 100644
--- a/lib/diameter/doc/src/.gitignore
+++ b/lib/diameter/doc/src/.gitignore
@@ -1,2 +1,3 @@
/depend.mk
+/seehere.ent
diff --git a/lib/diameter/doc/src/Makefile b/lib/diameter/doc/src/Makefile
index 59ca660797..0cbe1f000f 100644
--- a/lib/diameter/doc/src/Makefile
+++ b/lib/diameter/doc/src/Makefile
@@ -16,13 +16,8 @@
#
# %CopyrightEnd%
-ifneq ($(ERL_TOP),)
include $(ERL_TOP)/make/target.mk
include $(ERL_TOP)/make/$(TARGET)/otp.mk
-else
-include $(DIAMETER_TOP)/make/target.mk
-include $(DIAMETER_TOP)/make/$(TARGET)/rules.mk
-endif
include ../../vsn.mk
@@ -39,7 +34,8 @@ XML_REF_FILES = $(XML_REF1_FILES) $(XML_REF3_FILES) $(XML_REF4_FILES)
XML_FILES = $(BOOK_FILES) $(XML_APPLICATION_FILES) \
$(XML_REF_FILES) \
- $(XML_PART_FILES) $(XML_CHAPTER_FILES)
+ $(XML_PART_FILES) $(XML_CHAPTER_FILES) \
+ seealso.ent
INTERNAL_HTML_FILES = $(TECHNICAL_DESCR_FILES:%.xml=$(HTMLDIR)/%.html)
@@ -98,7 +94,7 @@ html: gifs $(HTML_REF_MAN_FILE)
clean clean_docs: clean_pdf clean_html clean_man
rm -f errs core *~
- rm -f depend.mk
+ rm -f depend.mk seehere.ent
clean_pdf:
rm -f $(PDFDIR)/*
@@ -155,11 +151,8 @@ info:
# ----------------------------------------------------
# Release Target
# ----------------------------------------------------
-ifneq ($(ERL_TOP),)
+
include $(ERL_TOP)/make/otp_release_targets.mk
-else
-include $(DIAMETER_TOP)/make/release_targets.mk
-endif
release_docs_spec: $(LOCAL)docs
$(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
@@ -178,8 +171,10 @@ release_docs_spec: $(LOCAL)docs
release_spec:
-depend.mk: depend.sed $(XML_REF_FILES) $(XML_CHAPTER_FILES) Makefile
- (for f in $(XML_REF_FILES) $(XML_CHAPTER_FILES); do \
+depend.mk: depend.sed Makefile seealso.ent \
+ $(XML_REF_FILES) $(XML_CHAPTER_FILES)
+ $(gen_verbose)sed -f seehere.sed seealso.ent > seehere.ent
+ $(V_at)(for f in $(XML_REF_FILES) $(XML_CHAPTER_FILES); do \
sed -f $< $$f | sed "s@%FILE%@`basename $$f .xml`@g"; \
done) \
> $@
diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml
index b8652a7482..b7669b760b 100644
--- a/lib/diameter/doc/src/diameter.xml
+++ b/lib/diameter/doc/src/diameter.xml
@@ -1,5 +1,16 @@
<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
+<!DOCTYPE erlref SYSTEM "erlref.dtd" [
+ <!ENTITY make_ref
+ '<seealso marker="erts:erlang#make_ref-0">erlang:make_ref/0</seealso>'>
+ <!ENTITY transport_module
+ '<seealso marker="diameter_transport">transport module</seealso>'>
+ <!ENTITY dictionary
+ '<seealso marker="diameter_dict">dictionary</seealso>'>
+ <!ENTITY % also SYSTEM "seealso.ent" >
+ <!ENTITY % here SYSTEM "seehere.ent" >
+ %also;
+ %here;
+]>
<erlref>
<header>
@@ -45,19 +56,16 @@ under the License.
<p>
This module provides the interface with which a user can
implement a Diameter node that sends and receives messages using the
-Diameter protocol as defined in RFC 3588.</p>
+Diameter protocol as defined in &the_rfc;.</p>
<p>
Basic usage consists of creating a representation of a
-locally implemented Diameter node and its capabilities with <seealso
-marker="#start_service">start_service/2</seealso>, adding transport
-capability using <seealso
-marker="#add_transport">add_transport/2</seealso> and sending Diameter
-requests and receiving Diameter answers with <seealso
-marker="#call">call/4</seealso>.
+locally implemented Diameter node and its capabilities with
+&start_service;, adding transport capability using
+&add_transport; and sending Diameter
+requests and receiving Diameter answers with &call;.
Incoming Diameter requests are communicated as callbacks to a
-<seealso
-marker="diameter_app">diameter_app(3)</seealso> callback modules as
+&man_app; callback modules as
specified in the service configuration.</p>
<p>
@@ -65,7 +73,7 @@ Beware the difference between <em>diameter</em> (not capitalised) and
<em>Diameter</em> (capitalised).
The former refers to the Erlang application named diameter whose main
api is defined here, the latter to Diameter protocol in the sense of
-RFC 3588.</p>
+&the_rfc;.</p>
<p>
The diameter application must be started before calling most functions
@@ -89,8 +97,8 @@ in this module.</p>
<tag><c>UTF8String()</c></tag>
<item>
<p>
-Types corresponding to RFC 3588 AVP Data Formats.
-Defined in <seealso marker="diameter_dict#DATA_TYPES">diameter_dict(4)</seealso>.</p>
+Types corresponding to &the_rfc; AVP Data Formats.
+Defined in &dict_data_types;.</p>
<marker id="application_alias"/>
</item>
@@ -100,7 +108,7 @@ Defined in <seealso marker="diameter_dict#DATA_TYPES">diameter_dict(4)</seealso>
<p>
A name identifying a Diameter application in
service configuration.
-Passed to <seealso marker="#call">call/4</seealso> when sending requests
+Passed to &call; when sending requests
defined by the application.</p>
<marker id="application_module"/>
@@ -110,23 +118,22 @@ defined by the application.</p>
| [Mod | ExtraArgs]
| #diameter_callback{}</c></tag>
<item>
-<code>
+<pre>
Mod = atom()
ExtraArgs = list()
-</code>
+</pre>
<p>
-A module implementing the callback interface defined in <seealso
-marker="diameter_app">diameter_app(3)</seealso>, along with any
+A module implementing the callback interface defined in &man_app;,
+along with any
extra arguments to be appended to those documented for the interface.
Note that extra arguments specific to an outgoing request can be
-specified to <seealso marker="#call">call/4</seealso>, in which case
+specified to &call;, in which case
those are are appended to any module-specific extra arguments.</p>
<p>
Specifying a <c>#diameter_callback{}</c> record allows individual
-functions to be configured in place of the usual <seealso
-marker="diameter_app">diameter_app(3)</seealso> callbacks.
+functions to be configured in place of the usual &man_app; callbacks.
See that module for details.</p>
<marker id="application_opt"/>
@@ -141,7 +148,7 @@ Has one the following types.</p>
<taglist>
-<tag><c>{alias, <seealso marker="#application_alias">application_alias()</seealso>}</c></tag>
+<tag><c>{alias, &application_alias;}</c></tag>
<item>
<p>
An unique identifier for the application in the scope of the
@@ -156,17 +163,15 @@ unspecified.</p>
The name of an encode/decode module for the Diameter
messages defined by the application.
These modules are generated from a specification file whose format is
-documented in <seealso
-marker="diameter_dict">diameter_dict(4)</seealso>.</p>
+documented in &man_dict;.</p>
</item>
-<tag><c>{module, <seealso marker="#application_module">application_module()</seealso>}</c></tag>
+<tag><c>{module, &application_module;}</c></tag>
<item>
<p>
The callback module with which messages of the Diameter application are
handled.
-See <seealso marker="diameter_app">diameter_app(3)</seealso> for
-the required interface and semantics.</p>
+See &man_app; for the required interface and semantics.</p>
</item>
<tag><c>{state, term()}</c></tag>
@@ -174,7 +179,7 @@ the required interface and semantics.</p>
<p>
The initial callback state.
The prevailing state is passed to some
-<seealso marker="diameter_app">diameter_app(3)</seealso>
+&man_app;
callbacks, which can then return a new state.
Defaults to the value of the <c>alias</c> option if unspecified.</p>
</item>
@@ -182,14 +187,13 @@ Defaults to the value of the <c>alias</c> option if unspecified.</p>
<tag><c>{call_mutates_state, true|false}</c></tag>
<item>
<p>
-Specifies whether or not the <seealso
-marker="diameter_app#pick_peer">pick_peer/4</seealso>
+Specifies whether or not the &app_pick_peer;
application callback can modify the application state,
Defaults to <c>false</c> if unspecified.</p>
<note>
<p>
-<seealso marker="diameter_app#pick_peer">pick_peer</seealso> callbacks
+&app_pick_peer; callbacks
are serialized when these are allowed to modify state, which is a
potential performance bottleneck.
A simple Diameter client may suffer no ill effects from using mutable
@@ -203,10 +207,8 @@ probably avoid it.</p>
<p>
Determines the manner in which incoming answer messages containing
decode errors are handled.
-If <c>callback</c> then errors result in a <seealso
-marker="diameter_app#handle_answer">handle_answer/4</seealso>
-callback in the same fashion as for <seealso
-marker="diameter_app#handle_request">handle_request/3</seealso>, with
+If <c>callback</c> then errors result in a &app_handle_answer;
+callback in the same fashion as for &app_handle_request;, with
errors communicated in the <c>errors</c> field of the
<c>#diameter_packet{}</c> record passed to the callback.
If <c>report</c> then an answer containing errors is discarded
@@ -214,7 +216,7 @@ without a callback and a warning report is written to the log.
If <c>discard</c> then an answer containing errors is silently
discarded without a callback.
In both the <c>report</c> and <c>discard</c> cases the return value
-for the <seealso marker="#call">call/4</seealso> invocation in
+for the &call; invocation in
question is as if a callback had taken place and returned
<c>{error, failure}</c>.</p>
@@ -231,7 +233,7 @@ Defaults to <c>report</c> if unspecified.</p>
<item>
<p>
-Options available to <seealso marker="#call">call/4</seealso> when
+Options available to &call; when
sending an outgoing Diameter request.
Has one of the following types.</p>
@@ -247,18 +249,18 @@ itself.
Multiple options append to the argument list.</p>
</item>
-<tag><c>{filter, <seealso marker="#peer_filter">peer_filter()</seealso>}</c></tag>
+<tag><c>{filter, &peer_filter;}</c></tag>
<item>
<p>
A filter to apply to the list of available peers before passing them to
-the <seealso marker="diameter_app#pick_peer">pick_peer/4</seealso>
+the &app_pick_peer;
callback for the application in question.
Multiple options are equivalent a single <c>all</c> filter on the
corresponding list of filters.
Defaults to <c>none</c>.</p>
</item>
-<tag><c>{timeout, <seealso marker="diameter_dict#DATA_TYPES">Unsigned32()</seealso>}</c></tag>
+<tag><c>{timeout, &dict_Unsigned32;}</c></tag>
<item>
<p>
The number of milliseconds after which the request should
@@ -269,21 +271,17 @@ Defaults to 5000.</p>
<tag><c>detach</c></tag>
<item>
<p>
-Causes <seealso marker="#call">call/4</seealso> to return <c>ok</c> as
+Causes &call; to return <c>ok</c> as
soon as the request in
question has been encoded instead of waiting for and returning
-the result from a subsequent
-<seealso marker="diameter_app#handle_answer">handle_answer/4</seealso>
-or <seealso
-marker="diameter_app#handle_error">handle_error/4</seealso>
-callback.</p>
+the result from a subsequent &app_handle_answer; or
+&app_handle_error; callback.</p>
</item>
</taglist>
<p>
-An invalid option will cause <seealso marker="#call">call/4</seealso>
-to fail.</p>
+An invalid option will cause &call; to fail.</p>
<marker id="capability"/>
</item>
@@ -300,36 +298,35 @@ Has one of the following types.</p>
<taglist>
-<tag><c>{'Origin-Host', <seealso marker="diameter_dict#DATA_TYPES">DiameterIdentity()</seealso>}</c></tag>
-<tag><c>{'Origin-Realm', <seealso marker="diameter_dict#DATA_TYPES">DiameterIdentity()</seealso>}</c></tag>
-<tag><c>{'Host-IP-Address', [<seealso marker="diameter_dict#DATA_TYPES">Address()</seealso>]}</c></tag>
+<tag><c>{'Origin-Host', &dict_DiameterIdentity;}</c></tag>
+<tag><c>{'Origin-Realm', &dict_DiameterIdentity;}</c></tag>
+<tag><c>{'Host-IP-Address', [&dict_Address;]}</c></tag>
<item>
<p>
An address list is available to the start function of a
-<seealso marker="diameter_transport">transport module</seealso>, which
+&transport_module;, which
can return a new list for use in the subsequent CER or CEA.
Host-IP-Address need not be specified if the transport start function
returns an address list.</p>
</item>
-<tag><c>{'Vendor-Id', <seealso marker="diameter_dict#DATA_TYPES">Unsigned32()</seealso>}</c></tag>
-<tag><c>{'Product-Name', <seealso marker="diameter_dict#DATA_TYPES">UTF8String()</seealso>}</c></tag>
-<tag><c>{'Origin-State-Id', <seealso marker="diameter_dict#DATA_TYPES">Unsigned32()</seealso>}</c></tag>
+<tag><c>{'Vendor-Id', &dict_Unsigned32;}</c></tag>
+<tag><c>{'Product-Name', &dict_UTF8String;}</c></tag>
+<tag><c>{'Origin-State-Id', &dict_Unsigned32;}</c></tag>
<item>
<p>
Origin-State-Id is optional but will be included in outgoing messages
sent by diameter itself: CER/CEA, DWR/DWA and DPR/DPA.
Setting a value of <c>0</c> (zero) is equivalent to not setting a
-value as documented in RFC 3588.
-The function <seealso
-marker="#origin_state_id">origin_state_id/0</seealso>
+value as documented in &the_rfc;.
+The function &origin_state_id;
can be used as to retrieve a value that is computed when the diameter
application is started.</p>
</item>
-<tag><c>{'Supported-Vendor-Id', [<seealso marker="diameter_dict#DATA_TYPES">Unsigned32()</seealso>]}</c></tag>
-<tag><c>{'Auth-Application-Id', [<seealso marker="diameter_dict#DATA_TYPES">Unsigned32()</seealso>]}</c></tag>
-<tag><c>{'Inband-Security-Id', [<seealso marker="diameter_dict#DATA_TYPES">Unsigned32()</seealso>]}</c></tag>
+<tag><c>{'Supported-Vendor-Id', [&dict_Unsigned32;]}</c></tag>
+<tag><c>{'Auth-Application-Id', [&dict_Unsigned32;]}</c></tag>
+<tag><c>{'Inband-Security-Id', [&dict_Unsigned32;]}</c></tag>
<item>
<p>
Inband-Security-Id defaults to the empty list, which is equivalent to a
@@ -338,9 +335,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', [<seealso marker="diameter_dict#DATA_TYPES">Unsigned32()</seealso>]}</c></tag>
-<tag><c>{'Vendor-Specific-Application-Id', [<seealso marker="diameter_dict#DATA_TYPES">Grouped()</seealso>]}</c></tag>
-<tag><c>{'Firmware-Revision', <seealso marker="diameter_dict#DATA_TYPES">Unsigned32()</seealso>}</c></tag>
+<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>
</taglist>
@@ -357,7 +354,7 @@ It is an error to specify duplicate tuples.</p>
An expression that can be evaluated as a function in the following
sense.</p>
-<code>
+<pre>
eval([{M,F,A} | T]) ->
apply(M, F, T ++ A);
eval([[F|A] | T]) ->
@@ -366,19 +363,21 @@ eval([F|A]) ->
apply(F, A);
eval(F) ->
eval([F]).
-</code>
+</pre>
<p>
-Applying an <c><seealso marker="#evaluable">evaluable()</seealso></c>
+Applying an <c>&evaluable;</c>
<c>E</c> to an argument list <c>A</c>
is meant in the sense of <c>eval([E|A])</c>.</p>
<warning>
<p>
-Beware of using fun expressions of the form <c>fun Name/Arity</c> (not
-fun Mod:Name/Arity) in situations in which the fun is not short-lived
+Beware of using fun expressions of the form <c>fun Name/Arity</c> in
+situations in which the fun is not short-lived
and code is to be upgraded at runtime since any processes retaining
-such a fun will have a reference to old code.</p>
+such a fun will have a reference to old code.
+In particular, such a value is typically inappropriate in
+configuration passed to &start_service; or &add_transport;.</p>
</warning>
<marker id="peer_filter"/>
@@ -387,10 +386,8 @@ such a fun will have a reference to old code.</p>
<tag><c>peer_filter() = term()</c></tag>
<item>
<p>
-A filter passed to <seealso marker="#call">call/4</seealso>
-in order to select candidate peers for a
-<seealso marker="diameter_app#pick_peer">pick_peer/4</seealso>
-callback.
+A filter passed to &call; in order to select candidate peers for a
+&app_pick_peer; callback.
Has one of the following types.</p>
<taglist>
@@ -421,42 +418,42 @@ or any peer if the request does not contain
a <c>Destination-Realm</c> AVP.</p>
</item>
-<tag><c>{host, any|<seealso marker="diameter_dict#DATA_TYPES">DiameterIdentity()</seealso>}</c></tag>
+<tag><c>{host, any|&dict_DiameterIdentity;}</c></tag>
<item>
<p>
Matches only those peers whose <c>Origin-Host</c> has the
specified value, or all peers if the atom <c>any</c>.</p>
</item>
-<tag><c>{realm, any|<seealso marker="diameter_dict#DATA_TYPES">DiameterIdentity()</seealso></c></tag>
+<tag><c>{realm, any|&dict_DiameterIdentity;</c></tag>
<item>
<p>
Matches only those peers whose <c>Origin-Realm</c> has the
specified value, or all peers if the atom <c>any</c>.</p>
</item>
-<tag><c>{eval, <seealso marker="#evaluable">evaluable()</seealso>}</c></tag>
+<tag><c>{eval, &evaluable;}</c></tag>
<item>
<p>
-Matches only those peers for which the specified <c><seealso
-marker="#evaluable">evaluable()</seealso></c> returns
+Matches only those peers for which the specified
+<c>&evaluable;</c> returns
<c>true</c> on the connection's <c>diameter_caps</c> record.
Any other return value or exception is equivalent to <c>false</c>.</p>
</item>
-<tag><c>{neg, <seealso marker="#peer_filter">peer_filter()</seealso>}</c></tag>
+<tag><c>{neg, &peer_filter;}</c></tag>
<item>
<p>
Matches only those peers not matched by the specified filter.</p>
</item>
-<tag><c>{all, [<seealso marker="#peer_filter">peer_filter()</seealso>]}</c></tag>
+<tag><c>{all, [&peer_filter;]}</c></tag>
<item>
<p>
Matches only those peers matched by each filter in the specified list.</p>
</item>
-<tag><c>{any, [<seealso marker="#peer_filter">peer_filter()</seealso>]}</c></tag>
+<tag><c>{any, [&peer_filter;]}</c></tag>
<item>
<p>
Matches only those peers matched by at least one filter in the
@@ -472,15 +469,12 @@ that matches no peer.</p>
<note>
<p>
The <c>host</c> and <c>realm</c> filters examine the
-outgoing request as passed to <seealso marker="#call">call/4</seealso>,
-assuming that this is a record- or list-valued <c><seealso
-marker="diameter_app#message">diameter_app:message()</seealso></c>,
+outgoing request as passed to &call;,
+assuming that this is a record- or list-valued <c>&codec_message;</c>,
and that the message contains at most one of each AVP.
-If this is not the case then the <c>{host|realm, <seealso
-marker="diameter_dict#DATA_TYPES">DiameterIdentity()</seealso>}</c>
+If this is not the case then the <c>{host|realm, &dict_DiameterIdentity;}</c>
filters must be used to achieve the desired result.
-An empty <c><seealso
-marker="diameter_dict#DATA_TYPES">DiameterIdentity()</seealso></c>
+An empty <c>&dict_DiameterIdentity;</c>
(which should not be typical)
matches all hosts/realms for the purposes of filtering.</p>
</note>
@@ -499,7 +493,7 @@ candidates list.</p>
<item>
<p>
An event message sent to processes that have subscribed to these using
-<seealso marker="#subscribe">subscribe/1</seealso>.</p>
+&subscribe;.</p>
<p>
The <c>info</c> field of the event record can have one of the
@@ -507,16 +501,27 @@ following types.</p>
<taglist>
+<tag><c>start</c></tag>
+<tag><c>stop</c></tag>
+
+<item>
+<p>
+The service is being started or stopped.
+No event precedes a <c>start</c> event.
+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>{down, Ref, Peer, Config}</c></tag>
<item>
-<code>
-Ref = <seealso marker="#transport_ref">transport_ref()</seealso>
-Peer = <seealso marker="diameter_app#peer">diameter_app:peer()</seealso>
-Config = {connect|listen, [<seealso marker="#transport_opt">transport_opt()</seealso>]}
+<pre>
+Ref = &transport_ref;
+Peer = &app_peer;
+Config = {connect|listen, [&transport_opt;]}
Pkt = #diameter_packet{}
-</code>
+</pre>
<p>
The RFC 3539 watchdog state machine has
@@ -530,7 +535,7 @@ connectivity.</p>
<p>
Note that a single <c>up</c>/<c>down</c> event for a given peer
-corresponds to one <seealso marker="diameter_app#peer_up">peer_up/peer_down</seealso>
+corresponds to one &app_peer_up;/&app_peer_down;
callback for each of the Diameter applications negotiated during
capablilities exchange.
That is, the event communicates connectivity with the
@@ -540,25 +545,23 @@ respect to individual Diameter applications.</p>
<tag><c>{reconnect, Ref, Opts}</c></tag>
<item>
-<code>
-Ref = <seealso marker="#transport_ref">transport_ref()</seealso>
-Opts = [<seealso marker="#transport_opt">transport_opt()</seealso>]
-</code>
+<pre>
+Ref = &transport_ref;
+Opts = [&transport_opt;]
+</pre>
<p>
A connecting transport is attempting to establish/reestablish a
-transport connection with a peer following <seealso
-marker="#reconnect_timer">reconnect_timer</seealso> or
-<seealso marker="#watchdog_timer">watchdog_timer</seealso>
-expiry.</p>
+transport connection with a peer following &reconnect_timer; or
+&watchdog_timer; expiry.</p>
</item>
<tag><c>{closed, Ref, Reason, Config}</c></tag>
<item>
-<code>
-Ref = <seealso marker="#transport_ref">transport_ref()</seealso>
-Config = {connect|listen, [<seealso marker="#transport_opt">transport_opt()</seealso>]}
-</code>
+<pre>
+Ref = &transport_ref;
+Config = {connect|listen, [&transport_opt;]}
+</pre>
<p>
Capabilities exchange has failed.
@@ -568,13 +571,13 @@ Capabilities exchange has failed.
<tag><c>{'CER', Result, Caps, Pkt}</c></tag>
<item>
-<code>
+<pre>
Result = ResultCode | {capabilities_cb, CB, ResultCode|discard}
Caps = #diameter_caps{}
Pkt = #diameter_packet{}
ResultCode = integer()
-CB = <seealso marker="#evaluable">evaluable()</seealso>
-</code>
+CB = &evaluable;
+</pre>
<p>
An incoming CER has been answered with the indicated result code or
@@ -588,11 +591,11 @@ contains the rejecting callback.</p>
<tag><c>{'CER', Caps, {ResultCode, Pkt}}</c></tag>
<item>
-<code>
+<pre>
ResultCode = integer()
Caps = #diameter_caps{}
Pkt = #diameter_packet{}
-</code>
+</pre>
<p>
An incoming CER contained errors and has been answered with the
@@ -601,14 +604,21 @@ indicated result code.
<c>Pkt</c> contains the CER in question.</p>
</item>
+<tag><c>{'CER', timeout}</c></tag>
+<item>
+<p>
+An expected CER was not received within &capx_timeout; of
+connection establishment.</p>
+</item>
+
<tag><c>{'CEA', Result, Caps, Pkt}</c></tag>
<item>
-<code>
+<pre>
Result = integer() | atom() | {capabilities_cb, CB, ResultCode|discard}
Caps = #diameter_caps{}
Pkt = #diameter_packet{}
ResultCode = integer()
-</code>
+</pre>
<p>
An incoming CEA has been rejected for the indicated reason.
@@ -623,10 +633,10 @@ contains the rejecting callback.</p>
<tag><c>{'CEA', Caps, Pkt}</c></tag>
<item>
-<code>
+<pre>
Caps = #diameter_caps{}
Pkt = #diameter_packet{}
-</code>
+</pre>
<p>
An incoming CEA contained errors and has been rejected.
@@ -634,17 +644,24 @@ An incoming CEA contained errors and has been rejected.
<c>Pkt</c> contains the CEA in question.</p>
</item>
+<tag><c>{'CEA', timeout}</c></tag>
+<item>
+<p>
+An expected CEA was not received within &capx_timeout;
+of connection establishment.</p>
+</item>
+
</taglist>
</item>
<tag><c>{watchdog, Ref, PeerRef, {From, To}, Config}</c></tag>
<item>
-<code>
-Ref = <seealso marker="#transport_ref">transport_ref()</seealso>
-PeerRef = <seealso marker="diameter_app#peer_ref">diameter_app:peer_ref()</seealso>
+<pre>
+Ref = &transport_ref;
+PeerRef = &app_peer_ref;
From, To = initial | okay | suspect | down | reopen
Config = {connect|listen, [transport_opt()]}
-</code>
+</pre>
<p>
An RFC 3539 watchdog state machine has changed state.</p>
@@ -662,11 +679,10 @@ info fields of forms other than the above.</p>
<tag><c>service_name() = term()</c></tag>
<item>
<p>
-The name of a service as passed to <seealso
-marker="#start_service">start_service/2</seealso> and with which the
+The name of a service as passed to &start_service; and with which the
service is identified.
There can be at most one service with a given name on a given node.
-Note that <seealso marker="erts:erlang#make_ref-0">erlang:make_ref/0</seealso>
+Note that &make_ref;
can be used to generate a service name that is somewhat unique.</p>
<marker id="service_opt"/>
@@ -675,91 +691,96 @@ can be used to generate a service name that is somewhat unique.</p>
<tag><c>service_opt()</c></tag>
<item>
<p>
-An option passed to <seealso
-marker="#start_service">start_service/2</seealso>.
-Can be any <c><seealso marker="#capability">capability()</seealso></c> as
-well as the following.</p>
+An option passed to &start_service;.
+Can be any <c>&capability;</c> as well as the following.</p>
<taglist>
-<tag><c>{application, [<seealso marker="#application_opt">application_opt()</seealso>]}</c></tag>
+<tag><c>{application, [&application_opt;]}</c></tag>
<item>
<p>
Defines a Diameter application supported by the service.</p>
<p>
-A service must configure one <c>application</c> for each Diameter
+A service must configure one tuple for each Diameter
application it intends to support.
-For an outgoing Diameter request, the relevant <c><seealso
-marker="#application_alias">application_alias()</seealso></c> is
-passed to <seealso marker="#call">call/4</seealso>, while for an
+For an outgoing Diameter request, the relevant <c>&application_alias;</c> is
+passed to &call;, while for an
incoming request the application identifier in the message
header determines the application, the identifier being specified in
-the application's <seealso marker="diameter_dict">dictionary</seealso>
-file.</p>
+the application's &dictionary; file.</p>
</item>
-</taglist>
-
-<marker id="transport_opt"/>
-</item>
-
-<tag><c>transport_opt()</c></tag>
+<tag><c>{restrict_connections, false
+ | node
+ | nodes
+ | [node()]
+ | evaluable()}</c></tag>
<item>
<p>
-An option passed to <seealso
-marker="#add_transport">add_transport/2</seealso>.
-Has one of the following types.</p>
+Specifies the degree to which multiple transport connections to the
+same peer are accepted by the service.</p>
-<taglist>
-<tag><c>{transport_module, atom()}</c></tag>
-<item>
<p>
-A module implementing a transport process as defined in <seealso
-marker="diameter_transport">diameter_transport(3)</seealso>.
-Defaults to <c>diameter_tcp</c> if unspecified.</p>
+If type <c>[node()]</c> then a connection is rejected if another already
+exists on any of the specified nodes.
+Values of type <c>false</c>, <c>node</c>, <c>nodes</c> or
+&evaluable; are equivalent to
+values <c>[]</c>, <c>[node()]</c>, <c>[node()|nodes()]</c> and the
+evaluated value, respectively, evaluation of each expression taking
+place whenever a new connection is to be established.
+Note that <c>false</c> allows an unlimited number of connections to be
+established with the same peer.</p>
<p>
-Multiple <c>transport_module</c> and <c>transport_config</c>
-options are allowed.
-The order of these is significant in this case (and only in this case),
-a <c>transport_module</c> being paired with the first
-<c>transport_config</c> following it in the options list, or the
-default value for trailing modules.
-Transport starts will be attempted with each of the
-modules in order until one establishes a connection within the
-corresponding timeout (see below) or all fail.</p>
+Multiple connections are independent and governed
+by their own peer and watchdog state machines.</p>
+
+<p>
+Defaults to <c>nodes</c>.</p>
</item>
-<tag><c>{transport_config, term()}</c></tag>
-<tag><c>{transport_config, term(), <seealso marker="diameter_dict#DATA_TYPES">Unsigned32()</seealso>}</c></tag>
+<tag><c>{sequence, {H,N} | &evaluable;}</c></tag>
<item>
<p>
-A term passed as the third argument to the <seealso
-marker="diameter_transport#start">start/3</seealso> function of
-the relevant <c>transport_module</c> in order to start a transport process.
-Defaults to the empty list if unspecified.</p>
-
+Specifies a constant value <c>H</c> for the topmost <c>32-N</c> bits of
+of 32-bit End-to-End and Hop-by-Hop identifiers generated
+by the service, either explicity or as a return value of a function
+to be evaluated at &start_service;.
+In particular, an identifier <c>Id</c> is mapped to a new identifier
+as follows.</p>
+<pre>
+(H bsl N) bor (Id band ((1 bsl N) - 1))
+</pre>
<p>
-The 3-tuple form additionally specifies an interval, in milliseconds,
-after which a started transport process should be terminated if it has
-not yet established a connection.
-For example, the following options on a connecting transport
-request a connection with one peer over SCTP or another
-(typically the same) over TCP.</p>
+Note that &the_rfc; requires that End-to-End identifiers remain unique
+for a period of at least 4 minutes and that this and the call rate
+places a lower bound on the appropriate values of <c>N</c>:
+at a rate of <c>R</c> requests per second an <c>N</c>-bit counter
+traverses all of its values in <c>(1 bsl N) div (R*60)</c> minutes so
+the bound is <c>4*R*60 =&lt; 1 bsl N</c>.</p>
-<code>
-{transport_module, diameter_sctp}
-{transport_config, SctpOpts, 5000}
-{transport_module, diameter_tcp}
-{transport_config, TcpOpts}
-</code>
+<p><c>N</c> must lie in the range <c>0..32</c> and <c>H</c> must be a
+non-negative integer less than <c>1 bsl (32-N)</c>.</p>
<p>
-To listen on both SCTP and TCP, define one transport for each.</p>
+Defaults to <c>{0,32}</c>.</p>
+</item>
+
+</taglist>
+
+<marker id="transport_opt"/>
</item>
-<tag><c>{applications, [<seealso marker="#application_alias">application_alias()</seealso>]}</c></tag>
+<tag><c>transport_opt()</c></tag>
+<item>
+<p>
+An option passed to &add_transport;.
+Has one of the following types.</p>
+
+<taglist>
+<marker id="applications"/>
+<tag><c>{applications, [&application_alias;]}</c></tag>
<item>
<p>
The list of Diameter applications to which the transport should be
@@ -768,7 +789,8 @@ Defaults to all applications configured on the service in question.
Applications not configured on the service in question are ignored.</p>
</item>
-<tag><c>{capabilities, [<seealso marker="#capability">capability()</seealso>]}</c></tag>
+<marker id="capabilities"/>
+<tag><c>{capabilities, [&capability;]}</c></tag>
<item>
<p>
AVP's used to construct outgoing CER/CEA messages.
@@ -778,98 +800,260 @@ question.</p>
<p>
Specifying a capability as a transport option
may be particularly appropriate for Inband-Security-Id, in case
-TLS is desired over TCP as implemented by
-<seealso marker="diameter_tcp">diameter_tcp(3)</seealso>.</p>
+TLS is desired over TCP as implemented by &man_tcp;.</p>
</item>
-<tag><c>{capabilities_cb, <seealso marker="#evaluable">evaluable()</seealso>}</c></tag>
+<marker id="capabilities_cb"/>
+<tag><c>{capabilities_cb, &evaluable;}</c></tag>
<item>
<p>
A callback invoked upon reception of CER/CEA during capabilities
exchange in order to ask whether or not the connection should
be accepted.
-Applied to the relevant <c><seealso
-marker="#transport_ref">transport_ref()</seealso></c> and the
-<c>#diameter_caps{}</c> record of the connection.
-Returning <c>ok</c> accepts the connection.
-Returning <c>integer()</c> causes an incoming
-CER to be answered with the specified Result-Code.
-Returning <c>discard</c> causes an incoming CER to
-be discarded.
-Returning <c>unknown</c> is equivalent to returning <c>3010</c>,
-DIAMETER_UNKNOWN_PEER.
-Returning anything but <c>ok</c> or a 2xxx series result
-code causes the transport connection to be broken.</p>
+Applied to the <c>&transport_ref;</c> and
+<c>#diameter_caps{}</c> record of the connection.</p>
+
+<p>
+The return value can have one of the following types.</p>
+
+<taglist>
+<tag><c>ok</c></tag>
+<item>
+<p>
+Accept the connection.</p>
+</item>
+
+<tag><c>integer()</c></tag>
+<item>
+<p>
+Causes an incoming CER to be answered with the specified Result-Code.</p>
+</item>
+
+<tag><c>discard</c></tag>
+<item>
+<p>
+Causes an incoming CER to be discarded without CEA being sent.</p>
+</item>
+
+<tag><c>unknown</c></tag>
+<item>
+<p>
+Equivalent to returning <c>3010</c>, DIAMETER_UNKNOWN_PEER.</p>
+</item>
+</taglist>
<p>
-Multiple <c>capabilities_cb</c> options can be specified, in which
+Returning anything but <c>ok</c> or a 2xxx series result
+code causes the transport connection to be broken.
+Multiple &capabilities_cb;
+options can be specified, in which
case the corresponding callbacks are applied until either all return
<c>ok</c> or one does not.</p>
+</item>
-<marker id="watchdog_timer"/>
+<marker id="capx_timeout"/>
+<tag><c>{capx_timeout, &dict_Unsigned32;}</c></tag>
+<item>
+<p>
+The number of milliseconds after which a transport process having an
+established transport connection will be terminated if the expected
+capabilities exchange message (CER or CEA) is not received from the peer.
+For a connecting transport, the timing reconnection attempts is
+governed by &watchdog_timer; or
+&reconnect_timer; expiry.
+For a listening transport, the peer determines the timing.</p>
+
+<p>
+Defaults to 10000.</p>
</item>
-<tag><c>{watchdog_timer, TwInit}</c></tag>
+<marker id="disconnect_cb"/>
+<tag><c>{disconnect_cb, &evaluable;}</c></tag>
+
<item>
-<code>
-TwInit = <seealso marker="diameter_dict#DATA_TYPES">Unsigned32()</seealso>
- | {M,F,A}
-</code>
+<p>
+A callback invoked prior to terminating the transport process of a
+transport connection having watchdog state <c>OKAY</c>.
+Applied to <c>Reason=transport|service|application</c> and the
+<c>&transport_ref;</c> and
+<c>&app_peer;</c>
+in question, <c>Reason</c> indicating whether the the diameter
+application is being stopped, the service in question is being stopped
+at &stop_service; or
+the transport in question is being removed at &remove_transport;,
+respectively.</p>
<p>
-The RFC 3539 watchdog timer.
-An integer value is interpreted as the RFC's TwInit in milliseconds,
-a jitter of &plusmn; 2 seconds being added at each rearming of the
-timer to compute the RFC's Tw.
-An MFA is expected to return the RFC's Tw directly, with jitter
-applied, allowing the jitter calculation to be performed by
-the callback.</p>
+The return value can have one of the following types.</p>
+<taglist>
+<tag><c>{dpr, [option()]}</c></tag>
+<item>
<p>
-An integer value must be at least 6000 as required by RFC 3539.
-Defaults to 30000 if unspecified.</p>
+Causes Disconnect-Peer-Request to be sent to the peer, the transport
+process being terminated following reception of
+Disconnect-Peer-Answer or timeout.
+An <c>option()</c> can be one of the following.</p>
-<marker id="reconnect_timer"/>
+<taglist>
+<tag><c>{cause, 0|rebooting|1|busy|2|goaway}</c></tag>
+<item>
+<p>
+The Disconnect-Cause to send, <c>REBOOTING</c>, <c>BUSY</c> and
+<c>DO_NOT_WANT_TO_TALK_TO_YOU</c> respectively.
+Defaults to <c>rebooting</c> for <c>Reason=service|application</c> and
+<c>goaway</c> for <c>Reason=transport</c>.</p>
+</item>
+
+<tag><c>{timeout, &dict_Unsigned32;}</c></tag>
+<item>
+<p>
+The number of milliseconds after which the transport process is
+terminated if DPA has not been received.
+Defaults to 1000.</p>
+</item>
+</taglist>
+</item>
+
+<tag><c>dpr</c></tag>
+<item>
+<p>
+Equivalent to <c>{dpr, []}</c>.</p>
+</item>
+
+<tag><c>close</c></tag>
+<item>
+<p>
+Causes the transport process to be terminated without
+Disconnect-Peer-Request being sent to the peer.</p>
+</item>
+
+<tag><c>ignore</c></tag>
+<item>
+<p>
+Equivalent to not having configured the callback.</p>
+</item>
+</taglist>
+
+<p>
+Multiple &disconnect_cb;
+options can be specified, in which
+case the corresponding callbacks are applied until one of them returns
+a value other than <c>ignore</c>.
+All callbacks returning <c>ignore</c> is equivalent to not having
+configured them.</p>
+
+<p>
+Defaults to a single callback returning <c>dpr</c>.</p>
</item>
+<marker id="reconnect_timer"/>
<tag><c>{reconnect_timer, Tc}</c></tag>
<item>
-<code>
-Tc = <seealso marker="diameter_dict#DATA_TYPES">Unsigned32()</seealso>
-</code>
+<pre>
+Tc = &dict_Unsigned32;
+</pre>
<p>
-For a connecting transport, the RFC 3588 Tc timer, in milliseconds.
+For a connecting transport, the &the_rfc; Tc timer, in milliseconds.
Note that this timer determines the frequency with which a transport
will attempt to establish a connection with its peer only <em>before</em>
an initial connection is established: once there is an initial
-connection it's watchdog_timer that determines the frequency of
-reconnection attempts, as required by RFC 3539.</p>
+connection it's &watchdog_timer; that determines the
+frequency of reconnection attempts, as required by RFC 3539.</p>
<p>
For a listening transport, the timer specifies the time after which a
previously connected peer will be forgotten: a connection after this time is
regarded as an initial connection rather than a reestablishment,
-causing the RFC 3539 state machine to pass to state OPEN rather than
+causing the RFC 3539 state machine to pass to state OKAY rather than
REOPEN.
-Note that these semantics are not goverened by the RFC and
-that a listening transport's <c>reconnect_timer</c> should be greater
+Note that these semantics are not governed by the RFC and
+that a listening transport's &reconnect_timer; should be greater
than its peer's Tw plus jitter.</p>
<p>
Defaults to 30000 for a connecting transport and 60000 for a listening
transport.</p>
+</item>
+
+<marker id="transport_config"/>
+<tag><c>{transport_config, term()}</c></tag>
+<tag><c>{transport_config, term(), &dict_Unsigned32;}</c></tag>
+<item>
+<p>
+A 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>
+
+<p>
+The 3-tuple form additionally specifies an interval, in milliseconds,
+after which a started transport process should be terminated if it has
+not yet established a connection.
+For example, the following options on a connecting transport
+request a connection with one peer over SCTP or another
+(typically the same) over TCP.</p>
+
+<pre>
+{transport_module, diameter_sctp}
+{transport_config, SctpOpts, 5000}
+{transport_module, diameter_tcp}
+{transport_config, TcpOpts}
+</pre>
+
+<p>
+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>
+<item>
+<p>
+A module implementing a transport process as defined in &man_transport;.
+Defaults to <c>diameter_tcp</c> if unspecified.</p>
+
+<p>
+Multiple <c>transport_module</c> and &transport_config;
+options are allowed.
+The order of these is significant in this case (and only in this case),
+a <c>transport_module</c> being paired with the first
+&transport_config;
+following it in the options list, or the default value for trailing
+modules.
+Transport starts will be attempted with each of the
+modules in order until one establishes a connection within the
+corresponding timeout (see below) or all fail.</p>
+</item>
+
+<marker id="watchdog_timer"/>
+<tag><c>{watchdog_timer, TwInit}</c></tag>
+<item>
+<pre>
+TwInit = &dict_Unsigned32;
+ | {M,F,A}
+</pre>
+
+<p>
+The RFC 3539 watchdog timer.
+An integer value is interpreted as the RFC's TwInit in milliseconds,
+a jitter of &plusmn; 2 seconds being added at each rearming of the
+timer to compute the RFC's Tw.
+An MFA is expected to return the RFC's Tw directly, with jitter
+applied, allowing the jitter calculation to be performed by
+the callback.</p>
+<p>
+An integer value must be at least 6000 as required by RFC 3539.
+Defaults to 30000 if unspecified.</p>
</item>
</taglist>
<p>
Unrecognized options are silently ignored but are returned unmodified
-by <seealso
-marker="#service_info">service_info/2</seealso> and can be referred to
-in predicate functions passed to <seealso
-marker="#remove_transport">remove_transport/2</seealso>.</p>
+by &service_info; and can be referred to
+in predicate functions passed to &remove_transport;.</p>
<marker id="transport_ref"/>
</item>
@@ -877,8 +1061,7 @@ marker="#remove_transport">remove_transport/2</seealso>.</p>
<tag><c>transport_ref() = reference()</c></tag>
<item>
<p>
-An reference returned by <seealso
-marker="#add_transport">add_transport/2</seealso> that
+An reference returned by &add_transport; that
identifies the configuration.</p>
</item>
@@ -886,7 +1069,6 @@ identifies the configuration.</p>
</section>
-<marker id="add_transport"/>
<funcs>
<!-- ===================================================================== -->
@@ -896,9 +1078,9 @@ identifies the configuration.</p>
-> {ok, Ref} | {error, Reason}</name>
<fsummary>Add transport capability to a service.</fsummary>
<type>
-<v>SvcName = <seealso marker="#service_name">service_name()</seealso></v>
-<v>Opt = <seealso marker="#transport_opt">transport_opt()</seealso></v>
-<v>Ref = <seealso marker="#transport_ref">transport_ref()</seealso></v>
+<v>SvcName = &service_name;</v>
+<v>Opt = &transport_opt;</v>
+<v>Ref = &transport_ref;</v>
<v>Reason = term()</v>
</type>
<desc>
@@ -917,8 +1099,7 @@ one peer, an listening transport potentially with many.</p>
The diameter application takes responsibility for exchanging
CER/CEA with the peer.
Upon successful completion of capabilities exchange the service
-calls each relevant application module's <seealso
-marker="diameter_app#peer_up">peer_up/3</seealso> callback
+calls each relevant application module's &app_peer_up; callback
after which the caller can exchange Diameter messages with the peer over
the transport.
In addition to CER/CEA, the service takes responsibility for the
@@ -937,7 +1118,6 @@ been configured: a service can be started after configuring
its transports.</p>
</note>
-<marker id="call"/>
</desc>
</func>
@@ -947,11 +1127,11 @@ its transports.</p>
<name>call(SvcName, App, Request, [Opt]) -> Answer | ok | {error, Reason}</name>
<fsummary>Send a Diameter request message.</fsummary>
<type>
-<v>SvcName = <seealso marker="#service_name">service_name()</seealso></v>
-<v>App = <seealso marker="#application_alias">application_alias()</seealso></v>
-<v>Request = <seealso marker="diameter_app#message">diameter_app:message()</seealso></v>
+<v>SvcName = &service_name;</v>
+<v>App = &application_alias;</v>
+<v>Request = &codec_message;</v>
<v>Answer = term()</v>
-<v>Opt = <seealso marker="#call_opt">call_opt()</seealso></v>
+<v>Opt = &call_opt;</v>
</type>
<desc>
<p>
@@ -960,37 +1140,29 @@ Send a Diameter request message.</p>
<p>
<c>App</c> specifies the Diameter application in which the request is
defined and callbacks to the corresponding callback module
-will follow as described below and in <seealso
-marker="diameter_app">diameter_app(3)</seealso>.
+will follow as described below and in &man_app;.
Unless the <c>detach</c> option is specified, the call returns either
when an answer message is received from the peer or an error occurs.
In the answer case, the return value is as returned by a
-<seealso
-marker="diameter_app#handle_answer">handle_answer/4</seealso>
-callback.
+&app_handle_answer; callback.
In the error case, whether or not the error is returned directly
-by diameter or from a <seealso
-marker="diameter_app#handle_error">handle_error/4</seealso>
+by diameter or from a &app_handle_error;
callback depends on whether or not the outgoing request is
successfully encoded for transmission to the peer, the cases being
documented below.</p>
<p>
If there are no suitable peers, or if
-<seealso marker="diameter_app#pick_peer">pick_peer/4</seealso>
+&app_pick_peer;
rejects them by returning <c>false</c>, then <c>{error,no_connection}</c>
is returned.
-Otherwise <seealso marker="diameter_app#pick_peer">pick_peer/4</seealso>
-is followed by a
-<seealso
-marker="diameter_app#prepare_request">prepare_request/3</seealso>
-callback, the message is encoded and then sent.</p>
+Otherwise &app_pick_peer; is followed by a
+&app_prepare_request; callback, the message is encoded and then sent.</p>
<p>
There are several error cases which may prevent an
answer from being received and passed to a
-<seealso marker="diameter_app#handle_answer">handle_answer/4</seealso>
-callback:</p>
+&app_handle_answer; callback:</p>
<list>
@@ -1005,16 +1177,14 @@ is returned.</p>
<p>
If the request is successfully encoded and sent but
the answer times out then a
-<seealso marker="diameter_app#handle_error">handle_error/4</seealso>
-callback takes place with <c>Reason = timeout</c>.</p>
+&app_handle_error; callback takes place with <c>Reason = timeout</c>.</p>
</item>
<item>
<p>
If the request is successfully encoded and sent but the service in
question is stopped before an answer is received then a
-<seealso marker="diameter_app#handle_error">handle_error/4</seealso>
-callback takes place with <c>Reason = cancel</c>.</p>
+&app_handle_error; callback takes place with <c>Reason = cancel</c>.</p>
</item>
<item>
@@ -1023,18 +1193,11 @@ If the transport connection with the peer goes down after the request
has been sent but before an answer has been received then an attempt
is made to resend the request to an alternate peer.
If no such peer is available, or if the subsequent
-<seealso marker="diameter_app#pick_peer">pick_peer/4</seealso>
-callback rejects the candidates, then a
-<seealso marker="diameter_app#handle_error">handle_error/4</seealso>
-callback takes place with <c>Reason = failover</c>.
-If a peer is selected then a
-<seealso
-marker="diameter_app#prepare_retransmit">prepare_retransmit/3</seealso>
+&app_pick_peer; callback rejects the candidates, then a
+&app_handle_error; callback takes place with <c>Reason = failover</c>.
+If a peer is selected then a &app_prepare_retransmit;
callback takes place, after which the semantics are the same as
-following an initial
-<seealso marker="diameter_app#prepare_request">
-prepare_request/3</seealso>
-callback.</p>
+following an initial &app_prepare_request; callback.</p>
</item>
<item>
@@ -1061,14 +1224,13 @@ Note that <c>{error,encode}</c> is the only return value which
guarantees that the request has <em>not</em> been sent over the
transport connection.</p>
-<marker id="origin_state_id"/>
</desc>
</func>
<!-- ===================================================================== -->
<func>
-<name>origin_state_id() -> <seealso marker="diameter_dict#DATA_TYPES">Unsigned32()</seealso></name>
+<name>origin_state_id() -> &dict_Unsigned32;</name>
<fsummary>Returns a reasonable Origin-State-Id.</fsummary>
<desc>
<p>
@@ -1077,26 +1239,26 @@ outgoing messages.</p>
<p>
The value returned is the number of seconds since 19680120T031408Z,
-the first value that can be encoded as a Diameter <c><seealso marker="diameter_dict#DATA_TYPES">Time()</seealso></c>,
+the first value that can be encoded as a Diameter <c>&dict_Time;</c>,
at the time the diameter application was started.</p>
-<marker id="remove_transport"/>
</desc>
</func>
<!-- ===================================================================== -->
<func>
-<name>remove_transport(SvcName, Pred) -> ok</name>
+<name>remove_transport(SvcName, Pred) -> ok | {error, Reason}</name>
<fsummary>Remove previously added transports.</fsummary>
<type>
-<v>SvcName = <seealso marker="#service_name">service_name()</seealso></v>
-<v>Pred = Fun | MFA | <seealso marker="#transport_ref">transport_ref()</seealso> | list() | true | false</v>
+<v>SvcName = &service_name;</v>
+<v>Pred = Fun | MFA | &transport_ref; | list() | true | false</v>
<v></v>
-<v>Fun = fun((<seealso marker="#transport_ref">transport_ref()</seealso>, connect|listen, list()) -> boolean())</v>
-<v>&nbsp;&nbsp;&nbsp; | fun((<seealso marker="#transport_ref">transport_ref()</seealso>, list()) -> boolean())</v>
+<v>Fun = fun((&transport_ref;, connect|listen, list()) -> boolean())</v>
+<v>&nbsp;&nbsp;&nbsp; | fun((&transport_ref;, list()) -> boolean())</v>
<v>&nbsp;&nbsp;&nbsp; | fun((list()) -> boolean())</v>
<v>MFA = {atom(), atom(), list()}</v>
+<v>Reason = term()</v>
</type>
<desc>
<p>
@@ -1106,12 +1268,11 @@ Remove previously added transports.</p>
<c>Pred</c> determines which transports to remove.
An arity-3-valued <c>Pred</c> removes all transports for which
<c>Pred(Ref, Type, Opts)</c> returns <c>true</c>, where <c>Type</c> and
-<c>Opts</c> are as passed to <seealso
-marker="#add_transport">add_transport/2</seealso> and <c>Ref</c> is
+<c>Opts</c> are as passed to &add_transport; and <c>Ref</c> is
as returned by it.
The remaining forms are equivalent to an arity-3 fun as follows.</p>
-<code>
+<pre>
Pred = fun(transport_ref(), list()): fun(Ref, _, Opts) -> Pred(Ref, Opts) end
Pred = fun(list()): fun(_, _, Opts) -> Pred(Opts) end
Pred = transport_ref(): fun(Ref, _, _) -> Pred == Ref end
@@ -1119,20 +1280,15 @@ Pred = list(): fun(_, _, Opts) -> [] == Pred -- Opts end
Pred = true: fun(_, _, _) -> true end
Pred = false: fun(_, _, _) -> false end
Pred = {M,F,A}: fun(Ref, Type, Opts) -> apply(M, F, [Ref, Type, Opts | A]) end
-</code>
+</pre>
<p>
-Removing a transport causes all associated transport connections to
-be broken.
-A DPR message with
-Disconnect-Cause <c>DO_NOT_WANT_TO_TALK_TO_YOU</c> will be sent
-to each connected peer before disassociating the transport configuration
-from the service and terminating the transport upon reception of
-DPA or timeout.</p>
-
-<!-- TODO: document the timeout value, possibly make configurable. -->
+Removing a transport causes the corresponding transport processes to
+be terminated.
+Whether or not a DPR message is sent to a peer is
+controlled by value of &disconnect_cb;
+configured on the transport.</p>
-<marker id="service_info"/>
</desc>
</func>
@@ -1142,13 +1298,19 @@ DPA or timeout.</p>
<name>service_info(SvcName, Info) -> term()</name>
<fsummary>Return information about a started service.</fsummary>
<type>
-<v>SvcName = <seealso marker="#service_name">service_name()</seealso></v>
+<v>SvcName = &service_name;</v>
<v>Info = Item | [Info]</v>
<v>Item = atom()</v>
</type>
<desc>
<p>
Return information about a started service.
+Requesting info for an unknown service causes <c>undefined</c> to be
+returned.
+Requesting a list of items causes a tagged list to be
+returned.</p>
+
+<p>
<c>Item</c> can be one of the following.</p>
<taglist>
@@ -1167,15 +1329,13 @@ Return information about a started service.
<tag><c>'Firmware-Revision'</c></tag>
<item>
<p>
-Return a capability value as configured with <seealso
-marker="#start_service">start_service/2</seealso>.</p>
+Return a capability value as configured with &start_service;.</p>
</item>
<tag><c>applications</c></tag>
<item>
<p>
-Return the list of applications as configured with <seealso
-marker="#start_service">start_service/2</seealso>.
+Return the list of applications as configured with &start_service;.
</p>
</item>
@@ -1183,23 +1343,21 @@ marker="#start_service">start_service/2</seealso>.
<item>
<p>
Return a tagged list of all capabilities values as configured with
-<seealso
-marker="#start_service">start_service/2</seealso>.</p>
+&start_service;.</p>
</item>
<tag><c>transport</c></tag>
<item>
<p>
Return a list containing one entry for each of the service's transport
-as configured with <seealso
-marker="#add_transport">add_transport/2</seealso>.
+as configured with &add_transport;.
Each entry is a tagged list containing both configuration and
information about established peer connections.
An example return value with for a client service with Origin-Host
"client.example.com" configured with a single transport connected to
"server.example.com" might look as follows.</p>
-<code>
+<pre>
[[{ref,#Ref&lt;0.0.0.93>},
{type,connect},
{options,[{transport_module,diameter_tcp},
@@ -1244,23 +1402,18 @@ An example return value with for a client service with Origin-Host
{{{0,258,0},recv,{'Result-Code',2001}},3},
{{{0,280,1},recv},2},
{{{0,280,0},send},2}]}]]
-</code>
+</pre>
<p>
-Here <c>ref</c> is a <c><seealso
-marker="#transport_ref">transport_ref()</seealso></c> and <c>options</c>
-the corresponding <c><seealso
-marker="#transport_opt">transport_opt()</seealso></c> list passed to <seealso
-marker="#add_transport">add_transport/2</seealso>.
+Here <c>ref</c> is a <c>&transport_ref;</c> and <c>options</c>
+the corresponding <c>&transport_opt;</c> list passed to
+&add_transport;.
The <c>watchdog</c> entry shows the state of a connection's RFC 3539 watchdog
state machine.
-The <c>peer</c> entry identifies the <c><seealso
-marker="diameter_app#peer_ref">diameter_app:peer_ref()</seealso></c> for
-which there will have been <seealso
-marker="diameter_app#peer_up">peer_up</seealso> callbacks for the
+The <c>peer</c> entry identifies the <c>&app_peer_ref;</c> for
+which there will have been &app_peer_up; callbacks for the
Diameter applications identified by the <c>apps</c> entry,
-<c>common</c> being the <c><seealso
-marker="#application_alias">application_alias()</seealso></c>.
+<c>common</c> being the <c>&application_alias;</c>.
The <c>caps</c> entry identifies the capabilities sent by the local
node and received from the peer during capabilities exchange.
The <c>port</c> entry displays socket-level information about the
@@ -1279,12 +1432,12 @@ during the lifetime of the transport configuration.</p>
<p>
A listening transport presents its information slightly differently
-since there may be multiple accepted connections for the same <c><seealso
-marker="#transport_ref">transport_ref()</seealso></c>.
+since there may be multiple accepted connections for the same
+<c>&transport_ref;</c>.
The <c>transport</c> info returned by a server with a single client
connection might look as follows.</p>
-<code>
+<pre>
[[{ref,#Ref&lt;0.0.0.61>},
{type,listen},
{options,[{transport_module,diameter_tcp},
@@ -1331,7 +1484,7 @@ connection might look as follows.</p>
{{{0,280,0},send},5},
{{{0,257,1},recv},1},
{{{0,257,0},send},1}]}]]
-</code>
+</pre>
<p>
The information presented here is as in the <c>connect</c> case except
@@ -1350,7 +1503,7 @@ connections and for which Diameter-level statistics are accumulated
only for the lifetime of the transport connection.
A return value for the server above might look as follows.</p>
-<code>
+<pre>
[[{ref,#Ref&lt;0.0.0.61>},
{type,accept},
{options,[{transport_module,diameter_tcp},
@@ -1396,7 +1549,7 @@ A return value for the server above might look as follows.</p>
{{{0,280,0},send},66},
{{{0,257,1},recv},1},
{{{0,257,0},send},1}]}]]
-</code>
+</pre>
<p>
Note that there may be multiple entries with the same <c>ref</c>, in
@@ -1407,27 +1560,37 @@ contrast to <c>transport</c> info.</p>
<item>
<p>
Return a <c>{{Counter, Ref}, non_neg_integer()}</c> list of counter values.
-<c>Ref</c> can be either a <c><seealso
-marker="#transport_ref">transport_ref()</seealso></c>
-or a <c><seealso
-marker="diameter_app#peer_ref">diameter_app:peer_ref()</seealso></c>.
+<c>Ref</c> can be either a <c>&transport_ref;</c>
+or a <c>&app_peer_ref;</c>.
Entries for the latter are folded into corresponding entries for the
former as peer connections go down.
-Entries for both are removed at <seealso
-marker="#remove_transport">remove_transport/2</seealso>.
+Entries for both are removed at &remove_transport;.
The Diameter-level statistics returned by <c>transport</c> and
<c>connections</c> info are based upon these entries.</p>
</item>
-</taglist>
-
+<tag><c>&app_peer_ref;</c></tag>
+<item>
<p>
-Requesting info for an unknown service causes <c>undefined</c> to be
-returned.
-Requesting a list of items causes a tagged list to be
-returned.</p>
+Return transport configuration associated with a single peer, as
+passed to &add_transport;.
+The returned list is empty if the peer is unknown.
+Otherwise it contains the <c>ref</c>, <c>type</c> and <c>options</c>
+tuples as in <c>transport</c> and <c>connections</c> info above.
+For example:</p>
+
+<pre>
+[{ref,#Ref&lt;0.0.0.61>},
+ {type,accept},
+ {options,[{transport_module,diameter_tcp},
+ {transport_config,[{reuseaddr,true},
+ {ip,{127,0,0,1}},
+ {port,3868}]}]}]
+</pre>
+</item>
+
+</taglist>
-<marker id="services"/>
</desc>
</func>
@@ -1437,34 +1600,32 @@ returned.</p>
<name>services() -> [SvcName]</name>
<fsummary>Return the list of started services.</fsummary>
<type>
-<v>SvcName = <seealso marker="#service_name">service_name()</seealso></v>
+<v>SvcName = &service_name;</v>
</type>
<desc>
<p>
Return the list of started services.</p>
-<marker id="session_id"/>
</desc>
</func>
<!-- ===================================================================== -->
<func>
-<name>session_id(Ident) -> <seealso marker="diameter_dict#DATA_TYPES">OctetString()</seealso></name>
+<name>session_id(Ident) -> &dict_OctetString;</name>
<fsummary>Return a value for a Session-Id AVP.</fsummary>
<type>
-<v>Ident = <seealso marker="diameter_dict#DATA_TYPES">DiameterIdentity()</seealso></v>
+<v>Ident = &dict_DiameterIdentity;</v>
</type>
<desc>
<p>
Return a value for a Session-Id AVP.</p>
<p>
-The value has the form required by section 8.8 of RFC 3588.
+The value has the form required by section 8.8 of &the_rfc;.
Ident should be the Origin-Host of the peer from which
the message containing the returned value will be sent.</p>
-<marker id="start"/>
</desc>
</func>
@@ -1481,7 +1642,6 @@ The diameter application must be started before starting a service.
In a production system this is typically accomplished by a boot
file, not by calling <c>start/0</c> explicitly.</p>
-<marker id="start_service"/>
</desc>
</func>
@@ -1490,8 +1650,8 @@ file, not by calling <c>start/0</c> explicitly.</p>
<name>start_service(SvcName, Options) -> ok | {error, Reason}</name>
<fsummary>Start a Diameter service.</fsummary>
<type>
-<v>SvcName = <seealso marker="#service_name">service_name()</seealso></v>
-<v>Options = [<seealso marker="#service_opt">service_opt()</seealso>]</v>
+<v>SvcName = &service_name;</v>
+<v>Options = [&service_opt;]</v>
<v>Reason = term()</v>
</type>
<desc>
@@ -1501,8 +1661,7 @@ Start a diameter service.</p>
<p>
A service defines a locally-implemented Diameter node, specifying the
capabilities to be advertised during capabilities exchange.
-Transports are added to a service using <seealso
-marker="#add_transport">add_transport/2</seealso>.
+Transports are added to a service using &add_transport;.
</p>
<note>
@@ -1513,7 +1672,6 @@ capabilities and restrict its supported Diameter applications so
necessarily the case.</p>
</note>
-<marker id="stop_service"/>
</desc>
</func>
@@ -1528,7 +1686,6 @@ Stop the diameter application.</p>
<p>
</p>
-<marker id="stop_service"/>
</desc>
</func>
@@ -1537,7 +1694,7 @@ Stop the diameter application.</p>
<name>stop_service(SvcName) -> ok | {error, Reason}</name>
<fsummary>Stop a Diameter service.</fsummary>
<type>
-<v>SvcName = <seealso marker="#service_name">service_name()</seealso></v>
+<v>SvcName = &service_name;</v>
<v>Reason = term()</v>
</type>
<desc>
@@ -1547,17 +1704,15 @@ Stop a diameter service.</p>
<p>
Stopping a service causes all associated transport connections to be
broken.
-A DPR message with be sent as in the case of <seealso
-marker="#remove_transport">remove_transport/2</seealso>.</p>
+A DPR message with be sent as in the case of &remove_transport;.</p>
<note>
<p>
-Stopping a transport does not remove any associated transports:
-<seealso marker="#remove_transport">remove_transport/2</seealso> must
+Stopping a service does not remove any associated transports:
+&remove_transport; must
be called to remove transport configuration.</p>
</note>
-<marker id="subscribe"/>
</desc>
</func>
@@ -1567,12 +1722,11 @@ be called to remove transport configuration.</p>
<name>subscribe(SvcName) -> true</name>
<fsummary>Subscribe to event messages.</fsummary>
<type>
-<v>SvcName = <seealso marker="#service_name">service_name()</seealso></v>
+<v>SvcName = &service_name;</v>
</type>
<desc>
<p>
-Subscribe to <c><seealso
-marker="#service_event">service_event()</seealso></c> messages from
+Subscribe to <c>&service_event;</c> messages from
a service.</p>
<p>
@@ -1581,7 +1735,6 @@ that does not yet exist.
Doing so before adding transports is required to guarantee the
reception of all related events.</p>
-<marker id="unsubscribe"/>
</desc>
</func>
@@ -1591,7 +1744,7 @@ reception of all related events.</p>
<name>unsubscribe(SvcName) -> true</name>
<fsummary>Unsubscribe to event messages.</fsummary>
<type>
-<v>SvcName = <seealso marker="#service_name">service_name()</seealso></v>
+<v>SvcName = &service_name;</v>
</type>
<desc>
<p>
@@ -1608,9 +1761,7 @@ Unsubscribe to event messages from a service.</p>
<title>SEE ALSO</title>
<p>
-<seealso marker="diameter_app">diameter_app(3)</seealso>,
-<seealso marker="diameter_transport">diameter_transport(3)</seealso>,
-<seealso marker="diameter_dict">diameter_dict(4)</seealso></p>
+&man_app;, &man_transport;, &man_dict;</p>
</section>
diff --git a/lib/diameter/doc/src/diameter_app.xml b/lib/diameter/doc/src/diameter_app.xml
index 4a4b212787..f4db625c71 100644
--- a/lib/diameter/doc/src/diameter_app.xml
+++ b/lib/diameter/doc/src/diameter_app.xml
@@ -1,5 +1,13 @@
<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
+<!DOCTYPE erlref SYSTEM "erlref.dtd" [
+ <!ENTITY message '<seealso marker="#message">message()</seealso>'>
+ <!ENTITY dict
+ '<seealso marker="diameter_dict#MESSAGE_RECORDS">diameter_dict(4)</seealso>'>
+ <!ENTITY % also SYSTEM "seealso.ent" >
+ <!ENTITY % here SYSTEM "seehere.ent" >
+ %also;
+ %here;
+]>
<erlref>
<header>
@@ -41,15 +49,13 @@ Callback module of a Diameter application.</modulesummary>
<description>
<p>
-A diameter service as started by <seealso
-marker="diameter#start_service">diameter:start_service/2</seealso>
+A diameter service as started by &mod_start_service;
configures one of more Diameter applications, each of whose
configuration specifies a callback that handles messages specific to
the application.
The messages and AVPs of the application are defined in a
dictionary file whose format is documented in
-<seealso marker="diameter_dict">diameter_dict(4)</seealso>
-while the callback module is documented here.
+&man_dict; while the callback module is documented here.
The callback module implements the Diameter application-specific
functionality of a service.</p>
@@ -60,26 +66,24 @@ The functions themselves are of three distinct flavours:</p>
<list>
<item>
<p>
-<seealso marker="#peer_up">peer_up/3</seealso> and
-<seealso marker="#peer_down">peer_down/3</seealso> signal the
+&peer_up; and &peer_down; signal the
attainment or loss of connectivity with a Diameter peer.</p>
</item>
<item>
<p>
-<seealso marker="#pick_peer">pick_peer/4</seealso>,
-<seealso marker="#prepare_request">prepare_request/3</seealso>,
-<seealso marker="#prepare_retransmit">prepare_retransmit/3</seealso>,
-<seealso marker="#handle_answer">handle_answer/4</seealso>
-and <seealso marker="#handle_error">handle_error/4</seealso> are (or may
-be) called as a consequence of a call to <seealso
-marker="diameter#call">diameter:call/4</seealso> to send an outgoing
+&pick_peer;,
+&prepare_request;,
+&prepare_retransmit;,
+&handle_answer;
+and &handle_error; are (or may be) called as a consequence of a call
+to &mod_call; to send an outgoing
Diameter request message.</p>
</item>
<item>
<p>
-<seealso marker="#handle_request">handle_request/3</seealso>
+&handle_request;
is called in response to an incoming Diameter request message.</p>
</item>
@@ -92,10 +96,9 @@ is called in response to an incoming Diameter request message.</p>
The arities given 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 <seealso
-marker="diameter#start_service">diameter:start_service/2</seealso>
+the callback module itself when calling &mod_start_service;
and, for the call-specific callbacks, any extra arguments passed to
-<seealso marker="diameter#call">diameter:call/4</seealso>.</p>
+&mod_call;.</p>
</note>
<!-- ===================================================================== -->
@@ -112,7 +115,8 @@ and, for the call-specific callbacks, any extra arguments passed to
<item>
<p>
A record containing the identities of
-the local Diameter node and the remote Diameter peer having an established transport
+the local Diameter node and the remote Diameter peer having an
+established transport
connection, as well as the capabilities as
determined by capabilities exchange.
Each field of the record is a 2-tuple consisting of
@@ -123,39 +127,17 @@ mandatory values as the bare value.</p>
<marker id="message"/>
-<tag><c>message() = record() | list()</c></tag>
+<tag><c>message() = &codec_message;</c></tag>
<item>
<p>
The representation of a Diameter message as passed to
-<seealso marker="diameter#call">diameter:call/4</seealso>.
-The record representation is as outlined in
-<seealso
-marker="diameter_dict#MESSAGE_RECORDS">diameter_dict(4)</seealso>:
-a message as defined in a dictionary file is encoded as a record with
-one field for each component AVP.
-Equivalently, a message can also be encoded as a list whose head is
-the atom-valued message name (the record name minus any
-prefix specified in the relevant dictionary file) and whose tail is a
-list of <c>{FieldName, FieldValue}</c> pairs.</p>
-
-<p>
-A third representation allows a message to be specified as a list
-whose head is a <c>#diameter_header{}</c> record and whose tail is a list
-of <c>#diameter_avp{}</c> records.
-This representation is used by diameter itself when relaying requests
-as directed by the return value of a
-<seealso marker="#handle_request">handle_request/3</seealso>
-callback.
-It differs from the other other two in that it bypasses the checks for
-messages that do not agree with their definitions in the dictionary in
-question (since relays agents must handle arbitrary request): messages
-are sent exactly as specified.</p>
+&mod_call; or returned from a &handle_request; callback.</p>
</item>
<marker id="packet"/>
-<tag><c>packet() = #diameter_packet{}</c></tag>
+<tag><c>packet() = &codec_packet;</c></tag>
<item>
<p>
A container for incoming and outgoing Diameter messages that's passed
@@ -168,13 +150,12 @@ Fields should not be set in return values except as documented.</p>
<tag><c>peer_ref() = term()</c></tag>
<item>
<p>
-A term identifying a transport connection with a Diameter peer.
-Should be treated opaquely.</p>
+A term identifying a transport connection with a Diameter peer.</p>
</item>
<marker id="peer"/>
-<tag><c>peer() = {<seealso marker="#peer_ref">peer_ref()</seealso>, <seealso marker="#capabilities">capabilities()</seealso>}</c></tag>
+<tag><c>peer() = {&peer_ref;, &capabilities;}</c></tag>
<item>
<p>
A tuple representing a Diameter peer connection.</p>
@@ -186,13 +167,9 @@ A tuple representing a Diameter peer connection.</p>
<item>
<p>
The state maintained by the application callback functions
-<seealso marker="#peer_up">peer_up/3</seealso>,
-<seealso marker="#peer_down">peer_down/3</seealso> and (optionally)
-<seealso marker="#pick_peer">pick_peer/4</seealso>.
+&peer_up;, &peer_down; and (optionally) &pick_peer;.
The initial state is configured in the call to
-<seealso
-marker="diameter#start_service">diameter:start_service/2</seealso>
-that configures the application on a service.
+&mod_start_service; that configures the application on a service.
Callback functions returning a state are evaluated in a common
service-specific process while
those not returning state are evaluated in a request-specific
@@ -213,18 +190,33 @@ process.</p>
<name>Mod:peer_up(SvcName, Peer, State) -> NewState</name>
<fsummary>Invoked when a transport connection has been established</fsummary>
<type>
-<v>SvcName = <seealso marker="diameter#service_name">diameter:service_name()</seealso></v>
-<v>Peer = <seealso marker="#peer">peer()</seealso></v>
-<v>State = NewState = <seealso marker="#state">state()</seealso></v>
+<v>SvcName = &mod_service_name;</v>
+<v>Peer = &peer;</v>
+<v>State = NewState = &state;</v>
</type>
<desc>
<p>
-Invoked when a transport connection has been established
-and a successful capabilities exchange has indicated that the peer
-supports the Diameter application of the application on which
-the callback module in question has been configured.</p>
+Invoked to signal the availability of a peer connection.
+In particular, capabilities exchange with the peer has indicated
+support for the application in question, the RFC 3539 watchdog state
+machine for the connection has reached state <c>OKAY</c> and Diameter
+messages can be both sent and received.</p>
+
+<note>
+<p>
+A watchdog state machine can reach state <c>OKAY</c> from state
+<c>SUSPECT</c> without a new capabilities exchange taking place.
+A new transport connection (and capabilities exchange) results in a
+new peer_ref().</p>
+</note>
+
+<note>
+<p>
+There is no requirement that a callback return before incoming
+requests are received: &handle_request; callbacks must be
+handled independently of &peer_up; and &peer_down;.</p>
+</note>
-<marker id="peer_down"/>
</desc>
</func>
@@ -232,88 +224,87 @@ the callback module in question has been configured.</p>
<name>Mod:peer_down(SvcName, Peer, State) -> NewState</name>
<fsummary>Invoked when a transport connection has been lost.</fsummary>
<type>
-<v>SvcName = <seealso marker="diameter#service_name">diameter:service_name()</seealso></v>
-<v>Peer = <seealso marker="#peer">peer()</seealso></v>
-<v>State = NewState = <seealso marker="#state">state()</seealso></v>
+<v>SvcName = &mod_service_name;</v>
+<v>Peer = &peer;</v>
+<v>State = NewState = &state;</v>
</type>
<desc>
<p>
-Invoked when a transport connection has been lost following a previous
-call to <seealso marker="#peer_up">peer_up/3</seealso>.</p>
+Invoked to signal that a peer connection is no longer available
+following a previous call to &peer_up;.
+In particular, that the RFC 3539 watchdog state machine for the
+connection has left state <c>OKAY</c> and the peer will no longer be a
+candidate in &pick_peer; callbacks.</p>
-<marker id="pick_peer"/>
</desc>
</func>
<func>
-<name>Mod:pick_peer(Candidates, Reserved, SvcName, State)
- -> {ok, Peer} | {Peer, NewState} | false</name>
+<name>Mod:pick_peer(Candidates, _Reserved, SvcName, State)
+ -> Selection | false</name>
<fsummary>Select a target peer for an outgoing request.</fsummary>
<type>
-<v>Candidates = [<seealso marker="#peer">peer()</seealso>]</v>
-<v>Peer = <seealso marker="#peer">peer()</seealso> | false</v>
-<v>SvcName = <seealso marker="diameter#service_name">diameter:service_name()</seealso></v>
-<v>State = NewState = <seealso marker="#state">state()</seealso></v>
+<v>Candidates = [&peer;]</v>
+<v>SvcName = &mod_service_name;</v>
+<v>State = NewState = &state;</v>
+<v>Selection = {ok, Peer} | {Peer, NewState}</v>
+<v>Peer = &peer; | false</v>
</type>
<desc>
<p>
-Invoked as a consequence of a call to <seealso
-marker="diameter#call">diameter:call/4</seealso> to select a destination
-peer for an outgoing request, the return value indicating the selected
-peer.</p>
+Invoked as a consequence of a call to &mod_call; to select a destination
+peer for an outgoing request.
+The return value indicates the selected peer.</p>
<p>
-The candidate peers list will only include those
-which are selected by any <c>filter</c> option specified in the call to
-<seealso marker="diameter#call">diameter:call/4</seealso>, and only
-those which have indicated support for the Diameter application in
-question.
+The candidate list contains only those peers that have advertised
+support for the Diameter application in question during capabilities
+exchange, that have not be excluded by a <c>filter</c> option in
+the call to &mod_call;
+and whose watchdog state machine is in the <c>OKAY</c> state.
The order of the elements is unspecified except that any
peers whose Origin-Host and Origin-Realm matches that of the
outgoing request (in the sense of a <c>{filter, {all, [host, realm]}}</c>
-option to <seealso marker="diameter#call">diameter:call/4</seealso>)
+option to &mod_call;)
will be placed at the head of the list.</p>
<p>
-The return values <c>false</c> and <c>{false, State}</c> are
-equivalent when callback state is mutable, as are
-<c>{ok, Peer}</c> and <c>{Peer, State}</c>.
-Returning a peer as <c>false</c> causes <c>{error, no_connection}</c>
-to be returned from <seealso marker="diameter#call">diameter:call/4</seealso>.
-Returning a <seealso marker="#peer">peer()</seealso> from an initial
-pick_peer/4 callback will result in a
-<seealso marker="#prepare_request">prepare_request/3</seealso> callback
-followed by either <seealso
-marker="#handle_answer">handle_answer/4</seealso>
-or <seealso marker="#handle_error">handle_error/4</seealso> depending
+A callback that returns a peer() will be followed by a
+&prepare_request;
+callback and, if the latter indicates that the request should be sent,
+by either &handle_answer;
+or &handle_error; depending
on whether or not an answer message is received from the peer.
-If transport with the peer is lost before this then a new <seealso
-marker="#pick_peer">pick_peer/4</seealso> callback takes place to
-select an alternate peer.</p>
-
-<p>
-Note that there is no guarantee that a <seealso
-marker="#pick_peer">pick_peer/4</seealso> callback to select
-an alternate peer will be followed by any additional callbacks, only
-that the initial <seealso
-marker="#pick_peer">pick_peer/4</seealso> will be, since a
+If the transport becomes unavailable after &prepare_request; then a
+new &pick_peer; callback may take place to
+failover to an alternate peer, after which &prepare_retransmit; takes the
+place of &prepare_request; in resending the
+request.
+There is no guarantee that a &pick_peer; callback to select
+an alternate peer will be followed by any additional callbacks since a
retransmission to an alternate peer is abandoned if an answer is
received from a previously selected peer.</p>
+<p>
+Returning <c>false</c> or <c>{false, NewState}</c> causes <c>{error,
+no_connection}</c> to be returned from &mod_call;.</p>
+
+<p>
+The return values <c>false</c> and <c>{false, State}</c> (that is,
+<c>NewState = State</c>) are equivalent, as are <c>{ok, Peer}</c> and
+<c>{Peer, State}</c>.</p>
+
<note>
<p>
-<c>{Peer, NewState}</c> and its equivalents can only be returned if
-the Diameter application in question was
-configured with the <seealso
-marker="diameter#application_opt">diameter:application_opt()</seealso>
-<c>{call_mutates_state, true}</c>.
+The return value <c>{Peer, NewState}</c> is only allowed if
+the Diameter application in question was configured with the
+&mod_application_opt; <c>{call_mutates_state, true}</c>.
Otherwise, the <c>State</c> argument is always
the intial value as configured on the application, not any subsequent
-value returned by a <seealso marker="#peer_up">peer_up/3</seealso>
-or <seealso marker="#peer_down">peer_down/3</seealso> callback.</p>
+value returned by a &peer_up;
+or &peer_down; callback.</p>
</note>
-<marker id="prepare_request"/>
</desc>
</func>
@@ -322,74 +313,81 @@ or <seealso marker="#peer_down">peer_down/3</seealso> callback.</p>
<name>Mod:prepare_request(Packet, SvcName, Peer) -> Action</name>
<fsummary>Return a request for encoding and transport.</fsummary>
<type>
-<v>Packet = <seealso marker="#packet">packet()</seealso></v>
-<v>SvcName = <seealso marker="diameter#service_name">diameter:service_name()</seealso></v>
-<v>Peer = <seealso marker="#peer">peer()</seealso></v>
-<v>Action = {send, <seealso marker="#packet">packet()</seealso> | <seealso marker="#message">message()</seealso>} | {discard, Reason} | discard</v>
+<v>Packet = &packet;</v>
+<v>SvcName = &mod_service_name;</v>
+<v>Peer = &peer;</v>
+<v>Action = Send | Discard | {eval_packet, Action, PostF}</v>
+<v>Send = {send, &packet; | &message;}</v>
+<v>Discard = {discard, Reason} | discard</v>
+<v>PostF = &mod_evaluable;}</v>
</type>
<desc>
<p>
Invoked to return a request for encoding and transport.
-Allows the sender to access the selected peer's capabilities
-in order to set (for example) <c>Destination-Host</c> and/or
-<c>Destination-Realm</c> in the outgoing request, although the
-callback need not be limited to this usage.
+Allows the sender to use the selected peer's capabilities
+to modify the outgoing request.
Many implementations may simply want to return <c>{send, Packet}</c></p>
<p>
-A returned <seealso marker="#packet">packet()</seealso> should set the request to be encoded in its
+A returned &packet; should set the
+request to be encoded in its
<c>msg</c> field and can set the <c>transport_data</c> field in order
-to pass information to the transport module.
-Extra arguments passed to <seealso
-marker="diameter#call">diameter:call/4</seealso> can be used to
-communicate transport data to the callback.
-A returned <seealso marker="#packet">packet()</seealso> can also set the <c>header</c> field to a
-<c>#diameter_header{}</c> record in order to specify values that should
-be preserved in the outgoing request, although this should typically
-not be necessary and allows the callback to set header values
-inappropriately.
+to pass information to the transport process.
+Extra arguments passed to &mod_call; can be used to
+communicate transport (or any other) data to the callback.</p>
+
+<p>
+A returned &packet; can set
+the <c>header</c> field to a
+<c>#diameter_header{}</c> to specify values that should
+be preserved in the outgoing request, values otherwise being those in
+the header record contained in <c>Packet</c>.
A returned <c>length</c>, <c>cmd_code</c> or <c>application_id</c> is
ignored.</p>
<p>
+A returned <c>PostF</c> will be evaluated on any encoded
+<c>#diameter_packet{}</c> prior to transmission, the <c>bin</c> field
+containing the encoded binary.
+The return value is ignored.</p>
+
+<p>
Returning <c>{discard, Reason}</c> causes the request to be aborted
-and the <seealso
-marker="diameter#call">diameter:call/4</seealso> for which the
+and the &mod_call; for which the
callback has taken place to return <c>{error, Reason}</c>.
Returning <c>discard</c> is equivalent to returning <c>{discard,
discarded}</c>.</p>
-<marker id="prepare_retransmit"/>
</desc>
</func>
<func>
-<name>Mod:prepare_retransmit(Packet, SvcName, Peer) -> Result</name>
+<name>Mod:prepare_retransmit(Packet, SvcName, Peer) -> Action</name>
<fsummary>Return a request for encoding and retransmission.</fsummary>
<type>
-<v>Packet = <seealso marker="#packet">packet()</seealso></v>
-<v>SvcName = <seealso marker="diameter#service_name">diameter:service_name()</seealso></v>
-<v>Peer = <seealso marker="#peer">peer()</seealso></v>
-<v>Result = {send, <seealso marker="#packet">packet()</seealso> | <seealso marker="#message">message()</seealso>} | {discard, Reason} | discard</v>
+<v>Packet = &packet;</v>
+<v>SvcName = &mod_service_name;</v>
+<v>Peer = &peer;</v>
+<v>Action = Send | Discard | {eval_packet, Action, PostF}</v>
+<v>Send = {send, &packet; | &message;}</v>
+<v>Discard = {discard, Reason} | discard</v>
+<v>PostF = &mod_evaluable;}</v>
</type>
<desc>
<p>
Invoked to return a request for encoding and retransmission.
-Has the same role as <seealso
-marker="#prepare_request">prepare_request/3</seealso> in the case that
+Has the same role as &prepare_request; in the case that
a peer connection is lost an an alternate peer selected but the
-argument <seealso marker="#packet">packet()</seealso> is as returned by the initial
-<c>prepare_request/3</c>.</p>
+argument &packet; is as returned
+by the initial &prepare_request;.</p>
<p>
Returning <c>{discard, Reason}</c> causes the request to be aborted
-and a <seealso
-marker="#handle_error">handle_error/4</seealso> callback to
+and a &handle_error; callback to
take place with <c>Reason</c> as initial argument.
Returning <c>discard</c> is equivalent to returning <c>{discard,
discarded}</c>.</p>
-<marker id="handle_answer"/>
</desc>
</func>
@@ -397,51 +395,43 @@ discarded}</c>.</p>
<name>Mod:handle_answer(Packet, Request, SvcName, Peer) -> Result</name>
<fsummary>Receive an answer message from a peer.</fsummary>
<type>
-<v>Packet = <seealso marker="#packet">packet()</seealso></v>
-<v>Request = <seealso marker="#message">message()</seealso></v>
-<v>SvcName = <seealso marker="diameter#service_name">diameter:service_name()</seealso></v>
-<v>Peer = <seealso marker="#peer">peer()</seealso></v>
+<v>Packet = &packet;</v>
+<v>Request = &message;</v>
+<v>SvcName = &mod_service_name;</v>
+<v>Peer = &peer;</v>
<v>Result = term()</v>
</type>
<desc>
<p>
Invoked when an answer message is received from a peer.
-The return value is returned from the call to <seealso
-marker="diameter#call">diameter:call/4</seealso> for which the
-callback takes place unless the <c>detach</c> option was
-specified.</p>
+The return value is returned from &mod_call; unless the
+<c>detach</c> option was specified.</p>
<p>
-The decoded answer record is in the <c>msg</c> field of the argument
-<seealso marker="#packet">packet()</seealso>,
-the undecoded binary in the <c>packet</c> field.
+The decoded answer record and undecoded binary are in the <c>msg</c>
+and <c>bin</c> fields of the argument
+&packet; respectively.
<c>Request</c> is the outgoing request message as was returned from
-<seealso marker="#prepare_request">prepare_request/3</seealso> or
-<seealso marker="#prepare_retransmit">prepare_retransmit/3</seealso>
-before the request was passed to the transport.</p>
+&prepare_request; or &prepare_retransmit;.</p>
<p>
-For any given call to <seealso
-marker="diameter#call">diameter:call/4</seealso> there is at most one
-call to the handle_answer callback of the application in question: any
+For any given call to &mod_call; there is at most one
+&handle_answer; callback: any
duplicate answer (due to retransmission or otherwise) is discarded.
-Similarly, only one of <c>handle_answer/4</c> or <c>handle_error/4</c> is
-called for any given request.</p>
+Similarly, only one of &handle_answer; or
+&handle_error; is called.</p>
<p>
By default, an incoming answer message that cannot be successfully
-decoded causes the request process in question to fail, causing the
-relevant call to <seealso
-marker="diameter#call">diameter:call/4</seealso>
-to return <c>{error, failure} (unless the <c>detach</c> option was
-specified)</c>.
-In particular, there is no <c>handle_error/4</c> callback in this
+decoded causes the request process to fail, causing
+&mod_call;
+to return <c>{error, failure}</c> unless the <c>detach</c> option was
+specified.
+In particular, there is no &handle_error; callback in this
case.
-Application configuration may change this behaviour as described for
-<seealso
-marker="diameter#start_service">diameter:start_service/2</seealso>.</p>
+The &mod_application_opt;
+<c>answer_errors</c> can be set to change this behaviour.</p>
-<marker id="handle_error"/>
</desc>
</func>
@@ -450,30 +440,26 @@ marker="diameter#start_service">diameter:start_service/2</seealso>.</p>
<fsummary>Return an error from a outgoing request.</fsummary>
<type>
<v>Reason = timeout | failover | term()</v>
-<v>Request = <seealso marker="#message">message()</seealso></v>
-<v>SvcName = <seealso marker="diameter#service_name">diameter:service_name()</seealso></v>
-<v>Peer = <seealso marker="#peer">peer()</seealso></v>
+<v>Request = &message;</v>
+<v>SvcName = &mod_service_name;</v>
+<v>Peer = &peer;</v>
<v>Result = term()</v>
</type>
<desc>
<p>
-Invoked when an error occurs before an answer message is received from
-a peer in response to an outgoing request.
-The return value is returned from the call to <seealso
-marker="diameter#call">diameter:call/4</seealso> for which the
-callback takes place (unless the <c>detach</c> option was
-specified).</p>
+Invoked when an error occurs before an answer message is received
+in response to an outgoing request.
+The return value is returned from &mod_call; unless the
+<c>detach</c> option was specified.</p>
<p>
Reason <c>timeout</c> indicates that an answer message has not been
-received within the required time.
+received within the time specified with the corresponding &mod_call_opt;.
Reason <c>failover</c> indicates
that the transport connection to the peer to which the request has
-been sent has been lost but that not alternate node was available,
-possibly because a <seealso marker="#pick_peer">pick_peer/4</seealso>
-callback returned false.</p>
+been sent has become unavailable and that not alternate peer was
+not selected.</p>
-<marker id="handle_request"/>
</desc>
</func>
@@ -481,54 +467,54 @@ callback returned false.</p>
<name>Mod:handle_request(Packet, SvcName, Peer) -> Action</name>
<fsummary>Receive an incoming request.</fsummary>
<type>
-<v>Packet = <seealso marker="#packet">packet()</seealso></v>
+<v>Packet = &packet;</v>
<v>SvcName = term()</v>
-<v>Peer = <seealso marker="#peer">peer()</seealso></v>
-<v>Action = Reply | {relay, [Opt]} | discard | {eval, Action, PostF}</v>
-<v>Reply = {reply, <seealso marker="#message">message()</seealso>}
+<v>Peer = &peer;</v>
+<v>Action = Reply
+ | {relay, [Opt]}
+ | discard
+ | {eval|eval_packet, Action, PostF}</v>
+<v>Reply = {reply, &packet; | &message;}
| {protocol_error, 3000..3999}</v>
-<v>Opt = <seealso marker="diameter#call_opt">diameter:call_opt()</seealso></v>
-<v>PostF = <seealso marker="diameter#evaluable">diameter:evaluable()</seealso></v>
+<v>Opt = &mod_call_opt;</v>
+<v>PostF = &mod_evaluable;</v>
</type>
<desc>
<p>
Invoked when a request message is received from a peer.
The application in which the callback takes place (that is, the
-callback module as configured with <seealso
-marker="diameter#start_service">diameter:start_service/2</seealso>)
+callback module as configured with &mod_start_service;)
is determined by the Application Identifier in the header of the
incoming request message, the selected module being the one
-whose corresponding <seealso
-marker="diameter_dict#MESSAGE_RECORDS">dictionary</seealso> declares
+whose corresponding dictionary declares
itself as defining either the application in question or the Relay
application.</p>
<p>
-The argument <seealso marker="#packet">packet()</seealso> has the following signature.</p>
+The argument &packet; has the following signature.</p>
-<code>
+<pre>
#diameter_packet{header = #diameter_header{},
avps = [#diameter_avp{}],
msg = record() | undefined,
- errors = [<seealso marker="diameter_dict#DATA_TYPES">Unsigned32()</seealso> | {<seealso marker="diameter_dict#DATA_TYPES">Unsigned32()</seealso>, #diameter_avp{}}],
+ errors = [&dict_Unsigned32; | {&dict_Unsigned32;, #diameter_avp{}}],
bin = binary(),
transport_data = term()}
-</code>
+</pre>
<p>
-The <c>msg</c> field will be <c>undefined</c> only in case the request has
+The <c>msg</c> field will be <c>undefined</c> in case the request has
been received in the relay application.
Otherwise it contains the record representing the request as outlined
-in <seealso
-marker="diameter_dict#MESSAGE_RECORDS">diameter_dict(4)</seealso>.</p>
+in &dict;.</p>
<p>
The <c>errors</c> field specifies any Result-Code's identifying errors
that were encountered in decoding the request.
In this case diameter will set both Result-Code and
Failed-AVP AVP's in a returned
-answer <seealso marker="#message">message()</seealso> before sending it to the peer:
-the returned <seealso marker="#message">message()</seealso> need only set any other required AVP's.
+answer &message; before sending it to the peer:
+the returned &message; need only set any other required AVP's.
Note that the errors detected by diameter are all of the 5xxx series
(Permanent Failures).
The <c>errors</c> list is empty if the request has been received in
@@ -538,19 +524,24 @@ the relay application.</p>
The <c>transport_data</c> field contains an arbitrary term passed into
diameter from the transport module in question, or the atom
<c>undefined</c> if the transport specified no data.
-The term is preserved in the <seealso marker="#packet">packet()</seealso> containing any answer message
-sent back to the transport process unless another value is explicitly
-specified.</p>
+The term is preserved if a &message; is returned but must be set
+explicitly in a returned &packet;.</p>
<p>
The semantics of each of the possible return values are as follows.</p>
<taglist>
-<tag><c>{reply, <seealso marker="#message">message()</seealso>}</c></tag>
+<tag><c>{reply, &packet; | &message;}</c></tag>
<item>
<p>
-Send the specified answer message to the peer.</p>
+Send the specified answer message to the peer.
+In the case of a &packet;, the
+message to be sent must be set in the
+<c>msg</c> field and the <c>header</c> field can be set to a
+<c>#diameter_header{}</c> to specify values that should be
+preserved in the outgoing answer, appropriate values otherwise
+being set by diameter.</p>
</item>
<tag><c>{protocol_error, 3000..3999}</c></tag>
@@ -559,15 +550,15 @@ Send the specified answer message to the peer.</p>
Send an answer message to the peer containing the specified
protocol error.
Equivalent to</p>
-<code>
+<pre>
{reply, ['answer-message' | Avps]
-</code>
+</pre>
<p>
where <c>Avps</c> sets the Origin-Host, Origin-Realm, the specified
Result-Code and (if the request sent one) Session-Id AVP's.</p>
<p>
-Note that RFC 3588 mandates that only answers with a 3xxx series
+Note that &the_rfc; mandates that only answers with a 3xxx series
Result-Code (protocol errors) may set the E bit.
Returning a non-3xxx value in a <c>protocol_error</c> tuple
will cause the request process in question to fail.</p>
@@ -580,37 +571,47 @@ Relay a request to another peer in the role of a Diameter relay agent.
If a routing loop is detected then the request is answered with
3005 (DIAMETER_LOOP_DETECTED).
Otherwise a Route-Record AVP (containing the sending peer's Origin-Host) is
-added to the request and <seealso marker="#pick_peer">pick_peer/4</seealso>
-and subsequent callbacks take place just as if <seealso
-marker="diameter#call">diameter:call/4</seealso> had been called
+added to the request and &pick_peer;
+and subsequent callbacks take place just as if &mod_call; had been called
explicitly.
The End-to-End Identifier of the incoming request is preserved in the
header of the relayed request.</p>
<p>
The returned <c>Opts</c> should not specify <c>detach</c>.
-A subsequent <seealso marker="#handle_answer">handle_answer/4</seealso>
+A subsequent &handle_answer;
callback for the relayed request must return its first
argument, the <c>#diameter_packet{}</c> record containing the answer
message.
Note that the <c>extra</c> option can be specified to supply arguments
that can distinguish the relay case from others if so desired.
Any other return value (for example, from a
-<seealso marker="#handle_error">handle_error/4</seealso> callback)
+&handle_error; callback)
causes the request to be answered with 3002 (DIAMETER_UNABLE_TO_DELIVER).</p>
</item>
<tag><c>discard</c></tag>
<item>
<p>
-Discard the request.</p>
+Discard the request.
+No answer message is sent to the peer.</p>
</item>
<tag><c>{eval, Action, PostF}</c></tag>
<item>
<p>
Handle the request as if <c>Action</c> has been returned and then
-evaluate <c>PostF</c> in the request process.</p>
+evaluate <c>PostF</c> in the request process.
+The return value is ignored.</p>
+</item>
+
+<tag><c>{eval_packet, Action, PostF}</c></tag>
+<item>
+<p>
+Like <c>eval</c> but evaluate <c>PostF</c> on any encoded
+<c>#diameter_packet{}</c> prior to transmission, the <c>bin</c> field
+containing the encoded binary.
+The return value is ignored.</p>
</item>
</taglist>
diff --git a/lib/diameter/doc/src/diameter_codec.xml b/lib/diameter/doc/src/diameter_codec.xml
new file mode 100644
index 0000000000..4a77d5435b
--- /dev/null
+++ b/lib/diameter/doc/src/diameter_codec.xml
@@ -0,0 +1,389 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd" [
+ <!ENTITY records
+ '<seealso marker="diameter_dict#MESSAGE_RECORDS">diameter_dict(4)</seealso>'>
+ <!ENTITY types
+ '<seealso marker="diameter_dict#DATA_TYPES">diameter_dict(4)</seealso>'>
+ <!ENTITY % also SYSTEM "seealso.ent" >
+ <!ENTITY % here SYSTEM "seehere.ent" >
+ %also;
+ %here;
+]>
+
+<erlref>
+<header>
+<copyright>
+<year>2012</year>
+<holder>Ericsson AB. All Rights Reserved.</holder>
+</copyright>
+<legalnotice>
+The contents of this file are subject to the Erlang Public License,
+Version 1.1, (the "License"); you may not use this file except in
+compliance with the License. You should have received a copy of the
+Erlang Public License along with this software. If not, it can be
+retrieved online at http://www.erlang.org/.
+
+Software distributed under the License is distributed on an "AS IS"
+basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+the License for the specific language governing rights and limitations
+under the License.
+
+</legalnotice>
+
+<title>diameter_codec(3)</title>
+<prepared>Anders Svensson</prepared>
+<responsible></responsible>
+<docno></docno>
+<approved></approved>
+<checked></checked>
+<date></date>
+<rev></rev>
+<file>diameter_codec.xml</file>
+</header>
+
+<module>diameter_codec</module>
+<modulesummary>Decode and encode of Diameter messages.</modulesummary>
+
+<description>
+
+<p>
+Incoming Diameter messages are decoded from binary() before being
+communicated to &man_app; callbacks.
+Similarly, outgoing Diameter messages are encoded into binary() before
+being passed to the appropriate &man_transport; module for
+transmission.
+The functions in this module implement this encode/decode.</p>
+
+<note>
+<p>
+Calls to this module are made by diameter itself as a consequence of
+configuration passed to &mod_start_service;.
+The encode/decode functions may also be useful for other purposes (eg.
+test) but the diameter user does not need to call them explicitly when
+sending and receiving messages using &mod_call; and the callback
+interface documented in &man_app;.</p>
+</note>
+
+<p>
+The &header; and &packet; records below
+are defined in diameter.hrl, which can be included as follows.</p>
+
+<pre>
+-include_lib("diameter/include/diameter.hrl").
+</pre>
+
+<p>
+Application-specific records are definied in the hrl
+files resulting from dictionary file compilation.</p>
+
+</description>
+
+<!-- ===================================================================== -->
+
+<section>
+<title>DATA TYPES</title>
+
+<p></p>
+
+<taglist>
+
+<marker id="integers"/>
+
+<tag><c>uint8()&nbsp; = 0..255</c></tag>
+<tag><c>uint24() = 0..16777215</c></tag>
+<tag><c>uint32() = 0..4294967295</c></tag>
+<item>
+<p>
+8-bit, 24-bit and 32-bit integers occurring in Diameter and AVP
+headers.</p>
+</item>
+
+<marker id="avp"/>
+
+<tag><c>avp() = #diameter_avp{}</c></tag>
+<item>
+<p>
+The application-neutral representation of an AVP.
+Primarily intended for use by relay applications that need to handle
+arbitrary Diameter applications.
+A service implementing a specific Diameter application
+(for which it configures a dictionary) can manipulate values of type
+&message; instead.</p>
+
+<p>
+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>vendor_id = uint32() | undefined</c></tag>
+<item>
+<p>
+Values in the AVP header, corresponding to AVP Code, the M flag, P
+flags and Vendor-ID respectivelty.
+A Vendor-ID other than <c>undefined</c> implies a set V flag.</p>
+</item>
+
+<tag><c>data = iolist()</c></tag>
+<item>
+<p>
+The data bytes of the AVP.</p>
+</item>
+
+<tag><c>name = atom()</c></tag>
+<item>
+<p>
+The name of the AVP as defined in the dictionary file in question, or
+<c>undefined</c> if the AVP is unknown to the dictionary file in
+question.</p>
+</item>
+
+<tag><c>value = term()</c></tag>
+<item>
+<p>
+The decoded value of an AVP.
+Will be <c>undefined</c> on decode if the data bytes could
+not be decoded or the AVP is unknown.
+The type of a decoded value is as document in &types;.</p>
+</item>
+
+<tag><c>type = atom()</c></tag>
+<item>
+<p>
+The type of the AVP as specified in the dictionary file in question
+(or one it inherits).
+Possible types are <c>undefined</c> and the Diameter types:
+<c>OctetString</c>, <c>Integer32</c>, <c>Integer64</c>,
+<c>Unsigned32</c>, <c>Unsigned64</c>, <c>Float32</c>, <c>Float64</c>,
+<c>Grouped</c>, <c>Enumerated</c>, <c>Address</c>, <c>Time</c>,
+<c>UTF8String</c>, <c>DiameterIdentity</c>, <c>DiameterURI</c>,
+<c>IPFilterRule</c> and <c>QoSFilterRule</c>.</p>
+</item>
+
+</taglist>
+
+</item>
+
+<marker id="dictionary"/>
+
+<tag><c>dictionary() = module()</c></tag>
+<item>
+
+<p>
+The name of a generated dictionary module as generated by &man_compile;
+or &make_codec;.
+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>
+<item>
+<p>
+The record representation of the Diameter header.
+Values in a &packet; returned by &decode; are as extracted from the
+incoming message.
+Values set in an &packet; passed to &encode; are preserved in the
+encoded binary(), with the exception of <c>length</c>, <c>cmd_code</c>
+and <c>application_id</c>, all of which are determined by the
+&dictionary; in question.</p>
+
+<note>
+<p>
+It is not necessary to set header fields explicitly in outgoing
+messages as diameter itself will set appropriate values.
+Setting inappropriate values can be useful for test purposes.</p>
+</note>
+
+<p>
+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>end_to_end_id = uint32()</c></tag>
+<item>
+<p>
+Values of the Version, Message Length, Command-Code, Application-ID,
+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_retransmitted = boolean()</c></tag>
+<item>
+<p>
+Values correspoding to the R(equest), P(roxiable), E(rror)
+and T(Potentially re-transmitted message) flags of the Diameter
+header.</p>
+</item>
+
+</taglist>
+
+</item>
+
+<marker id="message"/>
+
+<tag><c>message() = record() | list()</c></tag>
+<item>
+<p>
+The representation of a Diameter message as passed to
+&mod_call; or returned from a &app_handle_request; callback.
+The record representation is as outlined in &records;:
+a message as defined in a dictionary file is encoded as a record with
+one field for each component AVP.
+Equivalently, a message can also be encoded as a list whose head is
+the atom-valued message name (as specified in the relevant dictionary
+file) and whose tail is a list of <c>{AvpName, AvpValue}</c> pairs.</p>
+
+<p>
+Another list-valued representation allows a message to be specified
+as a list whose head is a &header; and whose tail is an &avp; list.
+This representation is used by diameter itself when relaying requests
+as directed by the return value of a &app_handle_request; callback.
+It differs from the other other two in that it bypasses the checks for
+messages that do not agree with their definitions in the dictionary in
+question: messages are sent exactly as specified.</p>
+
+</item>
+
+<marker id="packet"/>
+
+<tag><c>packet() = #diameter_packet{}</c></tag>
+<item>
+<p>
+A container for incoming and outgoing Diameter messages.
+Fields have the following types.</p>
+
+<taglist>
+
+<tag><c>header = &header; | undefined</c></tag>
+<item>
+<p>
+The Diameter header of the message.
+Can be (and typically should be) <c>undefined</c> for an outgoing
+message in a non-relay application, in which case diameter provides
+appropriate values.</p>
+</item>
+
+<tag><c>avps = [&avp;] | undefined</c></tag>
+<item>
+<p>
+The AVPs of the message.
+Ignored for an outgoing message if the <c>msg</c> field is set to a
+value other than <c>undefined</c>.</p>
+</item>
+
+<tag><c>msg = &message; | undefined</c></tag>
+<item>
+<p>
+The incoming/outgoing message.
+For an incoming message, a record if the message can be
+decoded in a non-relay application, <c>undefined</c> otherwise.
+For an outgoing message, setting a <c>[&header; | &avp;]</c> list is
+equivalent to setting the <c>header</c> and <c>avps</c> fields to the
+corresponding values.</p>
+
+<warning>
+<p>
+A record-valued <c>msg</c> field does <b>not</b> imply an absence of
+decode errors.
+The <c>errors</c> field should also be examined.</p>
+</warning>
+
+</item>
+
+<tag><c>bin = binary()</c></tag>
+<item>
+<p>
+The incoming message prior to encode or the outgoing message after
+encode.</p>
+</item>
+
+<tag><c>errors = [5000..5999 | {5000..5999, avp()}]</c></tag>
+<item>
+<p>
+Errors detected at decode of an incoming message, as identified by
+a corresponding 5xxx series Result-Code (Permanent Failures).
+For an incoming request, these should be used to formulate an
+appropriate answer as documented for the &app_handle_request;
+callback in &man_app;.
+For an incoming answer, the &mod_application_opt;
+<c>answer_errors</c> determines the behaviour.</p>
+</item>
+
+<tag><c>transport_data = term()</c></tag>
+<item>
+<p>
+An arbitrary term of meaning only to the transport process in
+question, as documented in &man_transport;.</p>
+</item>
+
+</taglist>
+
+</item>
+
+</taglist>
+
+</section>
+
+<!-- ===================================================================== -->
+
+<funcs>
+
+<func>
+<name>decode(Mod, Bin) -> Pkt</name>
+<fsummary>Decode a Diameter message.</fsummary>
+<type>
+<v>Mod = &dictionary;</v>
+<v>Bin = binary()</v>
+<v>Pkt = &packet;</v>
+</type>
+<desc>
+
+<p>
+Decode a Diameter message.</p>
+
+</desc>
+</func>
+
+<func>
+<name>encode(Mod, Msg) -> Pkt</name>
+<fsummary>Encode a Diameter message.</fsummary>
+<type>
+<v>Mod = &dictionary;</v>
+<v>Msg = &message; | &packet;</v>
+<v>Pkt = &packet;</v>
+</type>
+<desc>
+
+<p>
+Encode a Diameter message.
+</p>
+
+</desc>
+</func>
+
+</funcs>
+
+<!-- ===================================================================== -->
+<!-- ===================================================================== -->
+
+<section>
+<title>SEE ALSO</title>
+
+<p>
+&man_compile;, &man_app;, &man_dict;, &man_make;</p>
+
+</section>
+
+</erlref>
diff --git a/lib/diameter/doc/src/diameter_compile.xml b/lib/diameter/doc/src/diameter_compile.xml
index 7a6ca48798..0bd7ad1789 100644
--- a/lib/diameter/doc/src/diameter_compile.xml
+++ b/lib/diameter/doc/src/diameter_compile.xml
@@ -1,5 +1,12 @@
<?xml version="1.0" encoding="iso-8859-1" ?>
-<!DOCTYPE comref SYSTEM "comref.dtd">
+<!DOCTYPE comref SYSTEM "comref.dtd" [
+ <!ENTITY dictionary
+ '<seealso marker="diameter_dict">dictionary file</seealso>'>
+ <!ENTITY % also SYSTEM "seealso.ent" >
+ <!ENTITY % here SYSTEM "seehere.ent" >
+ %also;
+ %here;
+]>
<comref>
<header>
@@ -31,12 +38,14 @@ supplied.
<description>
<p>
-The diameterc utility is used to compile diameter
-<seealso marker="diameter_dict">dictionary files</seealso>
-into Erlang source.
-The resulting source implements the interface diameter requires
+The diameterc utility is used to compile a diameter
+&dictionary; into Erlang source.
+The resulting source implements the interface diameter required
to encode and decode the dictionary's messages and AVP's.</p>
+<p>
+The module &man_make; provides an alternate compilation interface.</p>
+
</description>
<section>
@@ -47,53 +56,52 @@ to encode and decode the dictionary's messages and AVP's.</p>
<tag><![CDATA[diameterc [<options>] <file>]]></tag>
<item>
<p>
-Compiles a single dictionary file. Valid options are as follows.</p>
-
-<!-- Leave -h/d/v undocumented, except for the usage message from the
- utility itself. -->
-
-<taglist>
-<tag><![CDATA[-o <dir>]]></tag>
-<item>
-<p>
-Specifies the directory into which the generated source should be written.
-Defaults to the current working directory.</p>
-</item>
+Compile a single dictionary file to Erlang source.
+Valid options are as follows.</p>
<tag><![CDATA[-i <dir>]]></tag>
<item>
<p>
-Specifies a directory to add to the code path.
+Prepend the specified directory to the code path.
Use to point at beam files compiled from inherited dictionaries,
-<c>@inherits</c> in a dictionary file creating a beam dependency, not
-an erl/hrl dependency.</p>
+<c>&dict_inherits;</c> in a dictionary file creating a beam
+dependency, not an erl/hrl dependency.</p>
<p>
Multiple <c>-i</c> options can be specified.</p>
</item>
+<taglist>
+<tag><![CDATA[-o <dir>]]></tag>
+<item>
+<p>
+Write generated source to the specified directory.
+Defaults to the current working directory.</p>
+</item>
+
<tag><![CDATA[-E]]></tag>
<tag><![CDATA[-H]]></tag>
<item>
<p>
-Supresses erl and hrl generation, respectively.</p>
+Supress erl and hrl generation, respectively.</p>
</item>
<tag><![CDATA[--name <name>]]></tag>
<tag><![CDATA[--prefix <prefix>]]></tag>
<item>
<p>
-Set <c>@name</c> and <c>@prefix</c> in the dictionary,
-respectively.
+Set <c>&dict_name;</c> or <c>&dict_prefix;</c> to the specified
+string.
Overrides any setting in the file itself.</p>
</item>
<tag><![CDATA[--inherits <dict>]]></tag>
<item>
<p>
-Append an <c>@inherits</c> to the dictionary before compiling.
-Specifying <c>'-'</c> as the dictionary has the effect of clearing any
-previous inherits, causing them to be ignored.</p>
+Append &dict_inherits; of the specified module.
+Specifying <c>"-"</c> has the effect of discarding clearing any
+previous inherits, both in the dictionary file and on the options
+list.</p>
<p>
Multiple <c>--inherits</c> options can be specified.</p>
@@ -122,7 +130,7 @@ Returns 0 on success, non-zero on failure.</p>
<title>SEE ALSO</title>
<p>
-<seealso marker="diameter_dict">diameter_dict(4)</seealso></p>
+&man_make;, &man_dict;</p>
</section>
diff --git a/lib/diameter/doc/src/diameter_dict.xml b/lib/diameter/doc/src/diameter_dict.xml
index 98adebf145..8b0687a22e 100644
--- a/lib/diameter/doc/src/diameter_dict.xml
+++ b/lib/diameter/doc/src/diameter_dict.xml
@@ -1,5 +1,16 @@
<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE erlref SYSTEM "fileref.dtd">
+<!DOCTYPE erlref SYSTEM "fileref.dtd" [
+ <!ENTITY format
+ '<seealso marker="#FILE_FORMAT">FILE FORMAT</seealso>'>
+ <!ENTITY records
+ '<seealso marker="#MESSAGE_RECORDS">MESSAGE RECORDS</seealso>'>
+ <!ENTITY types
+ '<seealso marker="#DATA_TYPES">DATA TYPES</seealso>'>
+ <!ENTITY % also SYSTEM "seealso.ent" >
+ <!ENTITY % here SYSTEM "seehere.ent" >
+ %also;
+ %here;
+]>
<fileref>
<header>
@@ -40,36 +51,33 @@ under the License.
<description>
<p>
-A diameter service as configured with <seealso
-marker="diameter#start_service">diameter:start_service/2</seealso>
+A diameter service, as configured with &mod_start_service;,
specifies one or more supported Diameter applications.
Each Diameter application specifies a dictionary module that knows how
to encode and decode its messages and AVPs.
The dictionary module is in turn generated from a file that defines
these messages and AVPs.
-The format of such a file is defined in
-<seealso marker="#FILE_FORMAT">FILE FORMAT</seealso> below.
+The format of such a file is defined in &format; below.
Users add support for their specific applications by creating
dictionary files, compiling them to Erlang modules using
-<seealso marker="diameterc">diameterc</seealso> and configuring the
+either &man_compile; or &man_make; and configuring the
resulting dictionaries modules on a service.</p>
<p>
-The codec generation also results in a hrl file that defines records
-for the messages and grouped AVPs defined for the application, these
-records being what a user of the diameter application sends and receives.
-(Modulo other available formats as discussed in <seealso
-marker="diameter_app">diameter_app(3)</seealso>.)
+Dictionary module generation also results in a hrl file that defines
+records for the messages and Grouped AVPs defined by the
+dictionary, these records being what a user of the diameter
+application sends and receives, modulo other possible formats as
+discussed in &man_app;.
These records and the underlying Erlang data types corresponding to
-Diameter data formats are discussed in <seealso
-marker="#MESSAGE_RECORDS">MESSAGE RECORDS</seealso> and <seealso
-marker="#DATA_TYPES">DATA TYPES</seealso> respectively.
-The generated hrl also contains defines for the possible values of
+Diameter data formats are discussed in &records; and &types;
+respectively.
+The generated hrl also contains macro definitions for the possible values of
AVPs of type Enumerated.</p>
<p>
The diameter application includes three dictionary modules
-corresponding to applications defined in section 2.4 of RFC 3588:
+corresponding to applications defined in section 2.4 of &the_rfc;:
<c>diameter_gen_base_rfc3588</c> for the Diameter Common Messages
application with application identifier 0,
<c>diameter_gen_accounting</c> for the Diameter Base Accounting
@@ -108,6 +116,8 @@ The order in which sections are specified is unimportant.</p>
<taglist>
+<marker id="id"/>
+
<tag><c>@id Number</c></tag>
<item>
<p>
@@ -125,12 +135,14 @@ is used to identify the relevant dictionary module.</p>
<p>
Example:</p>
-<code>
+<pre>
@id 16777231
-</code>
+</pre>
</item>
+<marker id="name"/>
+
<tag><c>@name Mod</c></tag>
<item>
<p>
@@ -146,12 +158,14 @@ with existing modules in the system.</p>
<p>
Example:</p>
-<code>
+<pre>
@name etsi_e2
-</code>
+</pre>
</item>
+<marker id="prefix"/>
+
<tag><c>@prefix Name</c></tag>
<item>
<p>
@@ -169,12 +183,14 @@ different Diameter applications.</p>
<p>
Example:</p>
-<code>
+<pre>
@prefix etsi_e2
-</code>
+</pre>
</item>
+<marker id="vendor"/>
+
<tag><c>@vendor Number Name</c></tag>
<item>
<p>
@@ -189,12 +205,14 @@ The section has empty content.</p>
<p>
Example:</p>
-<code>
+<pre>
@vendor 13019 ETSI
-</code>
+</pre>
</item>
+<marker id="avp_vendor_id"/>
+
<tag><c>@avp_vendor_id Number</c></tag>
<item>
<p>
@@ -205,16 +223,18 @@ The section content consists of AVP names.</p>
<p>
Example:</p>
-<code>
+<pre>
@avp_vendor_id 2937
WWW-Auth
Domain-Index
Region-Set
-</code>
+</pre>
</item>
+<marker id="inherits"/>
+
<tag><c>@inherits Mod</c></tag>
<item>
<p>
@@ -238,18 +258,20 @@ is equivalent to using <c>@avp_vendor_id</c> with a copy of the
dictionary's definitions but the former makes for easier reuse.</p>
<p>
-All dictionaries should typically inherit RFC3588 AVPs from
+All dictionaries should typically inherit &the_rfc; AVPs from
<c>diameter_gen_base_rfc3588</c>.</p>
<p>
Example:</p>
-<code>
+<pre>
@inherits diameter_gen_base_rfc3588
-</code>
+</pre>
</item>
+<marker id="avp_types"/>
+
<tag><c>@avp_types</c></tag>
<item>
<p>
@@ -260,7 +282,7 @@ The section consists of definitions of the form</p>
<p>
where Code is the integer AVP code, Type identifies an AVP Data Format
-as defined in <seealso marker="#DATA_TYPES">DATA TYPES</seealso> below,
+as defined in section &types; below,
and Flags is a string of V, M and P characters indicating the flags to be
set on an outgoing AVP or a single <c>'-'</c> (minus) character if
none are to be set.</p>
@@ -268,22 +290,22 @@ none are to be set.</p>
<p>
Example:</p>
-<code>
+<pre>
@avp_types
Location-Information 350 Grouped MV
Requested-Information 353 Enumerated V
-</code>
+</pre>
<warning>
<p>
-The P flag has been deprecated by the Diameter Maintenance
-and Extensions Working Group of the IETF and should be omitted
-to conform to the current draft standard.</p>
+The P flag has been deprecated by &the_rfc;.</p>
</warning>
</item>
+<marker id="custom_types"/>
+
<tag><c>@custom_types Mod</c></tag>
<item>
<p>
@@ -298,13 +320,15 @@ encode/decode.</p>
<p>
Example:</p>
-<code>
+<pre>
@custom_types rfc4005_avps
Framed-IP-Address
-</code>
+</pre>
</item>
+<marker id="codecs"/>
+
<tag><c>@codecs Mod</c></tag>
<item>
<p>
@@ -315,22 +339,24 @@ Like <c>@custom_types</c> but requires the specified module to export
<p>
Example:</p>
-<code>
+<pre>
@codecs rfc4005_avps
Framed-IP-Address
-</code>
+</pre>
</item>
+<marker id="messages"/>
+
<tag><c>@messages</c></tag>
<item>
<p>
Defines the messages of the application.
The section content consists of definitions of the form specified in
-section 3.2 of RFC 3588, "Command Code ABNF specification".</p>
+section 3.2 of &the_rfc;, "Command Code Format Specification".</p>
<!-- RFC 4740 RTR/RTA -->
-<code>
+<pre>
@messages
RTR ::= &lt; Diameter Header: 287, REQ, PXY >
@@ -363,35 +389,39 @@ RTA ::= &lt; Diameter Header: 287, PXY >
* [ Proxy-Info ]
* [ Route-Record ]
* [ AVP ]
-</code>
+</pre>
</item>
+<marker id="grouped"/>
+
<tag><c>@grouped</c></tag>
<item>
<p>
Defines the contents of the AVPs of the application having type
Grouped.
The section content consists of definitions of the form specified in
-section 4.4 of RFC 3588, "Grouped AVP Values".</p>
+section 4.4 of &the_rfc;, "Grouped AVP Values".</p>
<p>
Example:</p>
-<code>
+<pre>
@grouped
SIP-Deregistration-Reason ::= &lt; AVP Header: 383 >
{ SIP-Reason-Code }
[ SIP-Reason-Info ]
* [ AVP ]
-</code>
+</pre>
<p>
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>
<item>
<p>
@@ -408,16 +438,18 @@ otherwise defined in another dictionary.</p>
<p>
Example:</p>
-<code>
+<pre>
@enum SIP-Reason-Code
PERMANENT_TERMINATION 0
NEW_SIP_SERVER_ASSIGNED 1
SIP_SERVER_CHANGE 2
REMOVE_SIP_SERVER 3
-</code>
+</pre>
</item>
+<marker id="end"/>
+
<tag><c>@end</c></tag>
<item>
<p>
@@ -444,28 +476,28 @@ The hrl generated from a dictionary specification defines records for the
messages and grouped AVPs defined in <c>@messages</c> and
<c>@grouped</c> sections.
For each message or grouped AVP definition, a record is defined whose
-name is the message or AVP name prefixed with any dictionary prefix
-defined with <c>@prefix</c> and whose fields are the names of the AVPs
+name is the message or AVP name, prefixed with any dictionary prefix
+defined with <c>@prefix</c>, and whose fields are the names of the AVPs
contained in the message or grouped AVP in the order specified in the
definition in question.
For example, the grouped AVP</p>
-<code>
+<pre>
SIP-Deregistration-Reason ::= &lt; AVP Header: 383 >
{ SIP-Reason-Code }
[ SIP-Reason-Info ]
* [ AVP ]
-</code>
+</pre>
<p>
will result in the following record definition given an empty
prefix.</p>
-<code>
+<pre>
-record('SIP-Deregistration-Reason' {'SIP-Reason-Code',
'SIP-Reason-Info',
'AVP'}).
-</code>
+</pre>
<p>
The values encoded in the fields of generated records depends on the
@@ -473,7 +505,7 @@ type and number of times the AVP can occur.
In particular, an AVP which is specified as occurring exactly once is
encoded as a value of the AVP's type while an AVP with any other
specification is encoded as a list of values of the AVP's type.
-The AVP's type is as specified in the AVP definition, the RFC 3588
+The AVP's type is as specified in the AVP definition, the &the_rfc;
types being described below.</p>
<marker id="DATA_TYPES"/>
@@ -486,13 +518,11 @@ types being described below.</p>
<p>
The data formats defined in sections 4.2 ("Basic AVP Data
-Formats") and 4.3 ("Derived AVP Data Formats") of RFC 3588 are encoded
+Formats") and 4.3 ("Derived AVP Data Formats") of &the_rfc; are encoded
as values of the types defined here.
-Values are passed to <seealso
-marker="diameter#call">diameter:call/4</seealso>
+Values are passed to &mod_call;
in a request record when sending a request, returned in a resulting
-answer record and passed to a <seealso
-marker="diameter_app#handle_request">handle_request</seealso>
+answer record and passed to a &app_handle_request;
callback upon reception of an incoming request.</p>
<p>
@@ -507,7 +537,7 @@ callback upon reception of an incoming request.</p>
<marker id="Float64"/>
<marker id="Grouped"/>
-<code>
+<pre>
OctetString() = [0..255]
Integer32() = -2147483647..2147483647
Integer64() = -9223372036854775807..9223372036854775807
@@ -516,7 +546,7 @@ Unsigned64() = 0..18446744073709551615
Float32() = '-infinity' | float() | infinity
Float64() = '-infinity' | float() | infinity
Grouped() = record()
-</code>
+</pre>
<p>
On encode, an OctetString() can be specified as an iolist(),
@@ -530,10 +560,10 @@ section.</p>
<em>Derived AVP Data Formats</em></p>
<marker id="Address"/>
-<code>
+<pre>
Address() = OctetString()
| tuple()
-</code>
+</pre>
<p>
On encode, an OctetString() IPv4 address is parsed in the usual
@@ -545,7 +575,7 @@ An IPv6 tuple() has length 8 and contains values of type 0..65535.
The tuple representation is used on decode.</p>
<marker id="Time"/>
-<code>
+<pre>
Time() = {date(), time()}
where
@@ -559,19 +589,19 @@ where
Hour = 0..23
Minute = 0..59
Second = 0..59
-</code>
+</pre>
<p>
Additionally, values that can be encoded are
-limited by way of their encoding as four octets as required by RFC
-3588 with the required extension from RFC 2030.
+limited by way of their encoding as four octets as required by
+&the_rfc; with the required extension from RFC 2030.
In particular, only values between <c>{{1968,1,20},{3,14,8}}</c>
and <c>{{2104,2,26},{9,42,23}}</c> (both inclusive) can be encoded.</p>
<marker id="UTF8String"/>
-<code>
+<pre>
UTF8String() = [integer()]
-</code>
+</pre>
<p>
List elements are the UTF-8 encodings of the individual characters
@@ -579,15 +609,15 @@ in the string.
Invalid codepoints will result in encode/decode failure.</p>
<marker id="DiameterIdentity"/>
-<code>
+<pre>
DiameterIdentity() = OctetString()
-</code>
+</pre>
<p>
A value must have length at least 1.</p>
<marker id="DiameterURI"/>
-<code>
+<pre>
DiameterURI() = OctetString()
| #diameter_URI{type = Type,
fqdn = FQDN,
@@ -602,19 +632,19 @@ where
Port = integer()
Transport = sctp | tcp
Protocol = diameter | radius | 'tacacs+'
-</code>
+</pre>
<p>
On encode, fields port, transport and protocol default to 3868, sctp
and diameter respectively.
The grammar of an OctetString-valued DiameterURI() is as specified in
-section 4.3 of RFC 3588.
+section 4.3 of &the_rfc;.
The record representation is used on decode.</p>
<marker id="Enumerated"/>
-<code>
+<pre>
Enumerated() = Integer32()
-</code>
+</pre>
<p>
On encode, values can be specified using the macros defined in a
@@ -622,10 +652,10 @@ dictionary's hrl file.</p>
<marker id="IPFilterRule"/>
<marker id="QoSFilterRule"/>
-<code>
+<pre>
IPFilterRule() = OctetString()
QoSFilterRule() = OctetString()
-</code>
+</pre>
<p>
Values of these types are not currently parsed by diameter.</p>
@@ -639,9 +669,7 @@ Values of these types are not currently parsed by diameter.</p>
<title>SEE ALSO</title>
<p>
-<seealso marker="diameterc">diameterc(1)</seealso>,
-<seealso marker="diameter">diameter(3)</seealso>,
-<seealso marker="diameter_app">diameter_app(3)</seealso></p>
+&man_compile;, &man_main;, &man_app;, &man_codec;, &man_make;</p>
</section>
diff --git a/lib/diameter/doc/src/diameter_intro.xml b/lib/diameter/doc/src/diameter_intro.xml
index bc2afbd453..fd578ccf45 100644
--- a/lib/diameter/doc/src/diameter_intro.xml
+++ b/lib/diameter/doc/src/diameter_intro.xml
@@ -1,5 +1,8 @@
<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
+<!DOCTYPE chapter SYSTEM "chapter.dtd" [
+ <!ENTITY % also SYSTEM "seealso.ent">
+ %also;
+]>
<chapter>
<header>
@@ -35,7 +38,7 @@ under the License.
<p>
The diameter application is an implementation of the Diameter protocol
-as defined by RFC 3588.
+as defined by &the_rfc;.
It supports arbitrary Diameter applications by way of a
<em>dictionary</em> interface that allows messages and AVP's to be
defined and input into diameter as configuration.
@@ -86,9 +89,9 @@ dictionary module
that provide encode/decode functionality for outgoing/incoming
Diameter messages belonging to the application.
A dictionary module is generated from a <seealso
-marker="diameter_dict">specification file</seealso> using the <seealso
+marker="diameter_dict">dictionary file</seealso> using the <seealso
marker="diameterc">diameterc</seealso> utility.
-Dictionaries for the RFC 3588 Diameter Common Messages, Base
+Dictionaries for the &the_rfc; Diameter Common Messages, Base
Accounting and Relay applications are provided with the diameter
application.</p>
diff --git a/lib/diameter/doc/src/diameter_make.xml b/lib/diameter/doc/src/diameter_make.xml
new file mode 100644
index 0000000000..da6124310e
--- /dev/null
+++ b/lib/diameter/doc/src/diameter_make.xml
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd" [
+ <!ENTITY filename
+ '<seealso marker="kernel:file#type-name">file:name()</seealso>'>
+ <!ENTITY dictionary
+ '<seealso marker="diameter_dict">dictionary file</seealso>'>
+ <!ENTITY % also SYSTEM "seealso.ent" >
+ <!ENTITY % here SYSTEM "seehere.ent" >
+ %also;
+ %here;
+]>
+
+<erlref>
+<header>
+<copyright>
+<year>2012</year>
+<holder>Ericsson AB. All Rights Reserved.</holder>
+</copyright>
+<legalnotice>
+The contents of this file are subject to the Erlang Public License,
+Version 1.1, (the "License"); you may not use this file except in
+compliance with the License. You should have received a copy of the
+Erlang Public License along with this software. If not, it can be
+retrieved online at http://www.erlang.org/.
+
+Software distributed under the License is distributed on an "AS IS"
+basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+the License for the specific language governing rights and limitations
+under the License.
+
+</legalnotice>
+
+<title>diameter_make(3)</title>
+<prepared>Anders Svensson</prepared>
+<responsible></responsible>
+<docno></docno>
+<approved></approved>
+<checked></checked>
+<date></date>
+<rev></rev>
+<file>diameter_make.xml</file>
+</header>
+
+<module>diameter_make</module>
+<modulesummary>Diameter dictionary compilation.</modulesummary>
+
+<description>
+
+<p>
+The function &codec; is used to compile a diameter
+&dictionary; into Erlang source.
+The resulting source implements the interface diameter required
+to encode and decode the dictionary's messages and AVP's.</p>
+
+<p>
+The utility &man_compile; provides an alternate compilation
+interface.</p>
+
+</description>
+
+<!-- ===================================================================== -->
+
+<funcs>
+
+<func>
+<name>codec(Path::string(), [Opt]) -> ok | {error, Reason}</name>
+<fsummary>Compile a dictionary file into Erlang source.</fsummary>
+<desc>
+
+<p>
+Compile a single dictionary file to Erlang source.
+<c>Opt</c> can have the following types.</p>
+
+<taglist>
+
+<tag><c>{include, Dir::string()}</c></tag>
+<item>
+<p>
+Prepend the specified directory to the code path.
+Use to point at beam files compiled from inherited dictionaries,
+<c>&dict_inherits;</c> in a dictionary file creating a beam
+dependency, not an erl/hrl dependency.</p>
+
+<p>
+Multiple <c>include</c> options can be specified.</p>
+</item>
+
+<tag><c>{outdir, Dir::string()}</c></tag>
+<item>
+<p>
+Write generated source to the specified directory.
+Defaults to the current working directory.</p>
+</item>
+
+<tag><c>{name|prefix, string()}</c></tag>
+<item>
+<p>
+Set <c>&dict_name;</c> or <c>&dict_prefix;</c> to the specified
+string.
+Overrides any setting in the file itself.</p>
+</item>
+
+<tag><c>{inherits, Mod::string()}</c></tag>
+<item>
+<p>
+Append &dict_inherits; of the specified module.
+Specifying <c>"-"</c> has the effect of discarding clearing any
+previous inherits, both in the dictionary file and on the options
+list.</p>
+
+<p>
+Multiple <c>inherits</c> options can be specified.</p>
+</item>
+
+</taglist>
+
+</desc>
+</func>
+
+</funcs>
+
+<!-- ===================================================================== -->
+
+<section>
+<title>BUGS</title>
+
+<p>
+All options are string-valued.
+In particular, it is not currently possible to
+an &dict_inherits; module as an atom() or a path as a &filename;</p>
+
+</section>
+
+<!-- ===================================================================== -->
+
+<section>
+<title>SEE ALSO</title>
+
+<p>
+&man_compile;, &man_dict;</p>
+
+</section>
+
+</erlref>
diff --git a/lib/diameter/doc/src/diameter_sctp.xml b/lib/diameter/doc/src/diameter_sctp.xml
index 955169349c..5e3fd5eaf1 100644
--- a/lib/diameter/doc/src/diameter_sctp.xml
+++ b/lib/diameter/doc/src/diameter_sctp.xml
@@ -1,5 +1,16 @@
<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
+<!DOCTYPE erlref SYSTEM "erlref.dtd" [
+ <!ENTITY gen_sctp '<seealso marker="kernel:gen_sctp">gen_sctp(3)</seealso>'>
+ <!ENTITY gen_sctp_open1
+ '<seealso marker="kernel:gen_sctp#open-1">gen_sctp:open/1</seealso>'>
+ <!ENTITY ip_address
+ '<seealso marker="kernel:inet#type-ip_address">inet:ip_address()</seealso>'>
+ <!ENTITY inet '<seealso marker="kernel:inet">inet(3)</seealso>'>
+ <!ENTITY % also SYSTEM "seealso.ent" >
+ <!ENTITY % here SYSTEM "seehere.ent" >
+ %also;
+ %here;
+]>
<erlref>
<header>
@@ -38,12 +49,11 @@ under the License.
<description>
<p>
-This module implements diameter transport over SCTP using gen_sctp.
+This module implements diameter transport over SCTP using &gen_sctp;.
It can be specified as the value of a transport_module option to
-<seealso
-marker="diameter#add_transport">diameter:add_transport/2</seealso>
+&mod_add_transport;
and implements the behaviour documented in
-<seealso marker="diameter_transport">diameter_transport(3)</seealso>.</p>
+&man_transport;.</p>
<marker id="start"/>
</description>
@@ -58,18 +68,17 @@ and implements the behaviour documented in
<fsummary>Start a transport process.</fsummary>
<type>
<v>Type = connect | accept</v>
-<v>Ref = <seealso marker="diameter#transport_ref">diameter:transport_ref()</seealso></v>
+<v>Ref = &mod_transport_ref;</v>
<v>Svc = #diameter_service{}</v>
-<v>Opt = {raddr, <seealso marker="kernel:inet#type-ip_address">inet:ip_address()</seealso>} | {rport, integer()} | term()</v>
+<v>Opt = {raddr, &ip_address;} | {rport, integer()} | term()</v>
<v>Pid = pid()</v>
-<v>LAddr = <seealso marker="kernel:inet#type-ip_address">inet:ip_address()</seealso></v>
+<v>LAddr = &ip_address;</v>
<v>Reason = term()</v>
</type>
<desc>
<p>
-The start function required by <seealso
-marker="diameter_transport#start">diameter_transport(3)</seealso>.</p>
+The start function required by &man_transport;.</p>
<p>
The only diameter_sctp-specific argument is the options list.
@@ -80,8 +89,7 @@ unspecified.
More than one <c>raddr</c> option can be specified, in which case the
connecting transport in question attempts each in sequence until
an association is established.
-Remaining options are any accepted by <seealso
-marker="kernel:gen_sctp#open-1">gen_sctp:open/1</seealso>, with the exception
+Remaining options are any accepted by &gen_sctp_open1;, with the exception
of options <c>mode</c>, <c>binary</c>, <c>list</c>, <c>active</c>
and <c>sctp_events</c>.
Note that options <c>ip</c> and <c>port</c> specify the local address
@@ -98,14 +106,12 @@ connecting transport.</p>
<warning>
<p>
An insufficiently large receive buffer may result in a peer having to
-resend incoming messages: set the <seealso
-marker="kernel:inet">inet(3)</seealso> option <c>recbuf</c> to increase
+resend incoming messages: set the &inet; option <c>recbuf</c> to increase
the buffer size.</p>
<p>
An insufficiently large send buffer may result in outgoing messages
-being discarded: set the <seealso
-marker="kernel:inet">inet(3)</seealso> option <c>sndbuf</c> to increase
+being discarded: set the &inet; option <c>sndbuf</c> to increase
the buffer size.</p>
</warning>
@@ -114,16 +120,13 @@ diameter_sctp uses the <c>transport_data</c> field of
the <c>#diameter_packet{}</c> record to communicate the stream on which an
inbound message has been received, or on which an outbound message
should be sent: the value will be of the form <c>{stream, Id}</c>
-on an inbound message passed to a <seealso
-marker="diameter_app#handle_request">handle_request</seealso> or <seealso
-marker="diameter_app#handle_answer">handle_answer</seealso> callback.
+on an inbound message passed to a &app_handle_request; or
+&app_handle_answer; callback.
For an outbound message, either <c>undefined</c> (explicitly or
by receiving the outbound message as a <c>binary()</c>) or a tuple
-should be set in the return value of <seealso
-marker="diameter_app#handle_request">handle_request</seealso>
+should be set in the return value of &app_handle_request;
(typically by retaining the value passed into this function)
-or <seealso
-marker="diameter_app#prepare_request">prepare_request</seealso>.
+or &app_prepare_request;.
The value <c>undefined</c> uses a "next outbound stream" id and
increments this modulo the total number outbound streams.
That is, successive values of <c>undefined</c> cycle through all
@@ -144,9 +147,7 @@ outbound streams.</p>
<title>SEE ALSO</title>
<p>
-<seealso marker="diameter_transport">diameter_transport(3)</seealso>,
-<seealso marker="kernel:gen_sctp">gen_sctp(3)</seealso>,
-<seealso marker="kernel:inet">inet(3)</seealso></p>
+&man_main;, &man_transport;, &gen_sctp;, &inet;</p>
</section>
diff --git a/lib/diameter/doc/src/diameter_soc.xml b/lib/diameter/doc/src/diameter_soc.xml
index 6b9ef9f756..16f6b9d5bb 100644
--- a/lib/diameter/doc/src/diameter_soc.xml
+++ b/lib/diameter/doc/src/diameter_soc.xml
@@ -1,11 +1,15 @@
<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
+<!DOCTYPE chapter SYSTEM "chapter.dtd" [
+ <!ENTITY % also SYSTEM "seealso.ent" >
+ %also;
+]>
<chapter>
<header>
<copyright>
<year>2011</year>
+<year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
@@ -41,38 +45,20 @@ Known points of questionable or non-compliance.</p>
<!-- ===================================================================== -->
<section>
-<title>RFC 3588</title>
+<title>&the_rfc;</title>
<list>
<item>
<p>
-The End-to-End Security framework (section 2.9) isn't implemented
-since it is largely unspecified.
-The document that was to describe it
-(reference [AAACMS]) was abandoned in an uncompleted state several
-years ago and the current draft RFC deprecates the framework,
-including the P Flag in the AVP header.</p>
-</item>
-
-<item>
-<p>
-There is no TLS support over SCTP.
-RFC 3588 requires that a Diameter server support TLS but in
-practise this seems to mean TLS over SCTP since there are limitations
-with running over SCTP: see RFC 6083 (DTLS over SCTP), which is a
-response to RFC 3436 (TLS over SCTP).
-The current RFC 3588 draft acknowledges this by equating
-TLS with TLS/TCP and DTLS/SCTP but we do not yet support DTLS.</p>
+There is no support for DTLS over SCTP.</p>
</item>
<item>
<p>
There is no explicit support for peer discovery (section 5.2).
It can possibly be implemented on top of diameter as is but this is
-probably something that diameter should do.
-The current draft deprecates portions of the original RFC's mechanisms
-however.</p>
+probably something that diameter should do.</p>
</item>
<item>
diff --git a/lib/diameter/doc/src/diameter_tcp.xml b/lib/diameter/doc/src/diameter_tcp.xml
index 3ffcebfd90..e3b8c733b7 100644
--- a/lib/diameter/doc/src/diameter_tcp.xml
+++ b/lib/diameter/doc/src/diameter_tcp.xml
@@ -1,5 +1,27 @@
<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
+<!DOCTYPE erlref SYSTEM "erlref.dtd" [
+ <!ENTITY gen_tcp_connect3
+ '<seealso marker="kernel:gen_tcp#connect-3">gen_tcp:connect/3</seealso>'>
+ <!ENTITY gen_tcp_listen2
+ '<seealso marker="kernel:gen_tcp#listen-2">gen_tcp:listen/2</seealso>'>
+ <!ENTITY ip_address
+ '<seealso marker="kernel:inet#type-ip_address">inet:ip_address()</seealso>'>
+ <!ENTITY ssl_connect2
+ '<seealso marker="ssl:ssl#connect-2">ssl:connect/2</seealso>'>
+ <!ENTITY ssl_connect3
+ '<seealso marker="ssl:ssl#connect-3">ssl:connect/3</seealso>'>
+ <!ENTITY ssl_accept2
+ '<seealso marker="ssl:ssl#ssl_accept-2">ssl:ssl_accept/2</seealso>'>
+ <!ENTITY ssl_listen2
+ '<seealso marker="ssl:ssl#listen-2">ssl:listen/2</seealso>'>
+ <!ENTITY gen_tcp '<seealso marker="kernel:gen_tcp">gen_tcp(3)</seealso>'>
+ <!ENTITY inet '<seealso marker="kernel:inet">inet(3)</seealso>'>
+ <!ENTITY ssl '<seealso marker="ssl:ssl">ssl(3)</seealso>'>
+ <!ENTITY % also SYSTEM "seealso.ent" >
+ <!ENTITY % here SYSTEM "seehere.ent" >
+ %also;
+ %here;
+]>
<erlref>
<header>
@@ -38,15 +60,13 @@ under the License.
<description>
<p>
-This module implements diameter transport over TCP using <seealso
-marker="kernel:gen_tcp">gen_tcp</seealso>.
+This module implements diameter transport over TCP using &gen_tcp;.
It can be specified as the value of a <c>transport_module</c> option to
-<seealso
-marker="diameter#add_transport">diameter:add_transport/2</seealso>
+&mod_add_transport;
and implements the behaviour documented in
-<seealso marker="diameter_transport">diameter_transport(3)</seealso>.
+&man_transport;.
TLS security is supported, both as an upgrade following
-capabilities exchange as specified by RFC 3588 and
+capabilities exchange as specified by &the_rfc; and
at connection establishment as in the current draft standard.</p>
<p>
@@ -66,13 +86,13 @@ before configuring TLS capability on diameter transports.</p>
<fsummary>Start a transport process.</fsummary>
<type>
<v>Type = connect | accept</v>
-<v>Ref = <seealso marker="diameter#transport_ref">diameter:transport_ref()</seealso></v>
+<v>Ref = &mod_transport_ref;</v>
<v>Svc = #diameter_service{}</v>
<v>Opt = OwnOpt | SslOpt | TcpOpt</v>
<v>Pid = pid()</v>
-<v>LAddr = <seealso marker="kernel:inet#type-ip_address">inet:ip_address()</seealso></v>
+<v>LAddr = &ip_address;</v>
<v>Reason = term()</v>
-<v>OwnOpt = {raddr, <seealso marker="kernel:inet#type-ip_address">inet:ip_address()</seealso>}
+<v>OwnOpt = {raddr, &ip_address;}
| {rport, integer()}
| {port, integer()}</v>
<v>SslOpt = {ssl_options, true | list()}</v>
@@ -81,8 +101,7 @@ before configuring TLS capability on diameter transports.</p>
<desc>
<p>
-The start function required by <seealso
-marker="diameter_transport#start">diameter_transport(3)</seealso>.</p>
+The start function required by &man_transport;.</p>
<p>
The only diameter_tcp-specific argument is the options list.
@@ -92,16 +111,12 @@ transport.
Option <c>ssl_options</c> must be specified for a transport
that should support TLS: a value of <c>true</c> results in a
TLS handshake immediately upon connection establishment while
-<c>list()</c> specifies options to be passed to <seealso
-marker="ssl:ssl#connect-2">ssl:connect/2</seealso> or
-<seealso marker="ssl:ssl#ssl_accept-2">ssl:ssl_accept/2</seealso>
+<c>list()</c> specifies options to be passed to &ssl_connect2; or
+&ssl_accept2;
after capabilities exchange if TLS is negotiated.
-Remaining options are any accepted by <seealso
-marker="ssl:ssl#connect-3">ssl:connect/3</seealso> or <seealso
-marker="kernel:gen_tcp#connect-3">gen_tcp:connect/3</seealso> for
-a connecting transport, or <seealso
-marker="ssl:ssl#listen-2">ssl:listen/2</seealso> or <seealso
-marker="kernel:gen_tcp#listen-2">gen_tcp:listen/2</seealso> for
+Remaining options are any accepted by &ssl_connect3; or
+&gen_tcp_connect3; for
+a connecting transport, or &ssl_listen2; or &gen_tcp_listen2; for
a listening transport, depending on whether or not <c>{ssl_options, true}</c>
has been specified.
Options <c>binary</c>,
@@ -115,10 +130,8 @@ Note that the option <c>ip</c> specifies the local address.</p>
An <c>ssl_options</c> list must be specified if and only if
the transport in question has set <c>Inband-Security-Id</c> to
1 (<c>TLS</c>), as
-specified to either <seealso
-marker="diameter#start_service">start_service/2</seealso> or
-<seealso
-marker="diameter#add_transport">add_transport/2</seealso>,
+specified to either &mod_start_service; or
+&mod_add_transport;,
so that the transport process will receive notification of
whether or not to commence with a TLS handshake following capabilities
exchange.
@@ -149,11 +162,7 @@ The returned local address list has length one.</p>
<title>SEE ALSO</title>
<p>
-<seealso marker="diameter">diameter(3)</seealso>,
-<seealso marker="diameter_transport">diameter_transport(3)</seealso>,
-<seealso marker="kernel:gen_tcp">gen_tcp(3)</seealso>,
-<seealso marker="kernel:inet">inet(3)</seealso>,
-<seealso marker="ssl:ssl">ssl(3)</seealso></p>
+&man_main;, &man_transport;, &gen_tcp;, &inet;, &ssl;</p>
</section>
diff --git a/lib/diameter/doc/src/diameter_transport.xml b/lib/diameter/doc/src/diameter_transport.xml
index 9ab750e560..55b531155f 100644
--- a/lib/diameter/doc/src/diameter_transport.xml
+++ b/lib/diameter/doc/src/diameter_transport.xml
@@ -1,5 +1,13 @@
<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
+<!DOCTYPE erlref SYSTEM "erlref.dtd" [
+ <!ENTITY message '<seealso marker="#message">message()</seealso>'>
+ <!ENTITY ip_address
+ '<seealso marker="kernel:inet#type-ip_address">inet:ip_address()</seealso>'>
+ <!ENTITY % also SYSTEM "seealso.ent" >
+ <!ENTITY % here SYSTEM "seehere.ent" >
+ %also;
+ %here;
+]>
<erlref>
<header>
@@ -38,82 +46,116 @@ under the License.
<description>
<p>
-A module specified as a <c>transport_module</c> to <seealso
-marker="diameter#add_transport">diameter:add_transport/2</seealso>
+A module specified as a <c>transport_module</c> to &mod_add_transport;
must implement the interface documented here.
The interface consists of a function with which
diameter starts a transport process and a message interface with which
the transport process communicates with the process that starts it (aka its
parent).</p>
-<marker id="start"/>
</description>
<!-- ===================================================================== -->
+<section>
+<title>DATA TYPES</title>
+
+<taglist>
+
+<marker id="message"/>
+
+<tag><c>message() = binary() | &codec_packet;</c></tag>
+<item>
+<p>
+A Diameter message as passed over the transport interface.</p>
+
+<p>
+For an inbound message from a transport process, a &codec_packet; must
+contain the received message in its <c>bin</c> field.
+In the case of an inbound request, any value set in the
+<c>transport_data</c> field will passed back to the transport module
+in the corresponding answer message, unless the sender supplies
+another value.</p>
+
+<p>
+For an outbound message to a transport process, a &codec_packet; has a
+value other than <c>undefined</c> in its <c>transport_data</c> field
+and has the binary() to send in its <c>bin</c> field.</p>
+</item>
+
+</taglist>
+
+</section>
+
+<!-- ===================================================================== -->
+
<funcs>
<func>
-<name>Mod:start({Type, Ref}, Svc, Opts)
- -> {ok, Pid} | {ok, Pid, LAddrs} | {error, Reason}</name>
+<name>Mod:start({Type, Ref}, Svc, Config)
+ -> {ok, Pid}
+ | {ok, Pid, LAddrs}
+ | {error, Reason}</name>
<fsummary>Start a transport process.</fsummary>
<type>
<v>Type = connect | accept</v>
-<v>Ref = <seealso marker="diameter#transport_ref">diameter:transport_ref()</seealso></v>
+<v>Ref = &mod_transport_ref;</v>
<v>Svc = #diameter_service{}</v>
-<v>Opts = term()</v>
+<v>Config = term()</v>
<v>Pid = pid()</v>
-<v>LAddrs = [<seealso marker="kernel:inet#type-ip_address">inet:ip_address()</seealso>]</v>
+<v>LAddrs = [&ip_address;]</v>
<v>Reason = term()</v>
</type>
<desc>
<p>
Start a transport process.
-Called by diameter as a consequence of a call to <seealso
-marker="diameter#add_transport">diameter:add_transport/2</seealso> in
+Called by diameter as a consequence of a call to &mod_add_transport; in
order to establish or accept a transport connection respectively.
A transport process maintains a connection with a single remote peer.</p>
<p>
-The first argument indicates whether the transport process in question
-is being started for a connecting (<c>connect</c>) or listening
-(<c>accept</c>) transport.
+<c>Type</c> indicates whether the transport process in question
+is being started for a connecting (<c>Type=connect</c>) or listening
+(<c>Type=accept</c>) transport.
In the latter case, transport processes are started as required to
-accept connections from multiple peers.
-Ref is in each case the same value that was returned from the
-call to <seealso
-marker="diameter#add_transport">diameter:add_transport/2</seealso>
+accept connections from multiple peers.</p>
+
+<p>
+Ref is the value that was returned from the call to &mod_add_transport;
that has lead to starting of a transport process.</p>
<p>
-A transport process must implement the message interface documented below.
-It should retain the pid of its parent, monitor the parent and terminate if
-it dies.
-It should not link to the parent.
-It should exit if its transport connection with its peer is lost.</p>
+<c>Svc</c> contains the capabilities passed to &mod_start_service; and
+&mod_add_transport;, values passed to the latter overriding those
+passed to the former.</p>
+
+<p>
+<c>Config</c> is as passed in <c>transport_config</c> tuple in the
+&mod_transport_opt; list passed to &mod_add_transport;.</p>
<p>
-The capabilities in the <c>#diameter_service{}</c> record are as
-passed to <seealso
-marker="diameter#start_service">diameter:start_service/2</seealso> and
-<seealso
-marker="diameter#add_transport">diameter:add_transport/2</seealso>,
-values passed to the latter overriding those passed to the former.
The start function should use the <c>Host-IP-Address</c> list and/or
-<c>Opts</c> to select an appropriate list of local IP addresses,
+<c>Config</c> to select an appropriate list of local IP addresses,
and should return this list if different from the
<c>#diameter_service{}</c> addresses.
The returned list is used to populate <c>Host-IP-Address</c> AVPs in
outgoing capabilities exchange messages, the
<c>#diameter_service{}</c> addresses being used otherwise.</p>
-<marker id="MESSAGES"/>
+<p>
+A transport process must implement the message interface documented below.
+It should retain the pid of its parent, monitor the parent and terminate if
+it dies.
+It should not link to the parent.
+It should exit if its transport connection with its peer is lost.</p>
+
</desc>
</func>
</funcs>
<!-- ===================================================================== -->
+<marker id="MESSAGES"/>
<section>
<title>MESSAGES</title>
@@ -123,27 +165,23 @@ All messages sent over the transport interface are of the
form <c>{diameter, term()}</c>.</p>
<p>
-A transport process can expect the following messages from
-diameter.</p>
+A transport process can expect messages of the following types from
+its parent.</p>
<taglist>
-<tag><c>{diameter, {send, Packet}}</c></tag>
+<tag><c>{diameter, {send, &message;}}</c></tag>
<item>
<p>
-An outbound Diameter message.
-<c>Packet</c> can be either binary() (the message to be sent)
-or a <c>#diameter_packet{}</c> record whose <c>transport_data</c>
-field contains a value other than undefined and whose <c>bin</c> field
-contains the binary to send.</p>
+An outbound Diameter message.</p>
</item>
<tag><c>{diameter, {close, Pid}}</c></tag>
<item>
<p>
-A request to close the transport connection.
-The transport process should terminate after closing the
-connection.
+A request to terminate the transport process after having received DPA
+in response to DPR.
+The transport process should exit.
<c>Pid</c> is the pid() of the parent process.</p>
</item>
@@ -178,7 +216,7 @@ TLS.</p>
</taglist>
<p>
-A transport process should send the following messages
+A transport process should send messages of the following types
to its parent.</p>
<taglist>
@@ -201,19 +239,10 @@ Not sent if the transport process has <c>Type=accept</c>.
endpoint to which the transport has connected.</p>
</item>
-<tag><c>{diameter, {recv, Packet}}</c></tag>
+<tag><c>{diameter, {recv, &message;}}</c></tag>
<item>
<p>
-An inbound Diameter message.
-<c>Packet</c> can be either binary() (the received message)
-or a <c>#diameter_packet{}</c> record
-whose <c>bin</c> field contains the received binary().
-Any value (other than <c>undefined</c>) set in
-the <c>transport_data</c> field will be passed back with a
-corresponding answer message in the case that the inbound message is a
-request unless the sender sets another value.
-How <c>transport_data</c> is used/interpreted is up to the
-transport module.</p>
+An inbound Diameter message.</p>
</item>
<tag><c>{diameter, {tls, Ref}}</c></tag>
@@ -237,8 +266,7 @@ A transport must exit if a handshake is not successful.</p>
<title>SEE ALSO</title>
<p>
-<seealso marker="diameter_tcp">diameter_tcp(3)</seealso>,
-<seealso marker="diameter_sctp">diameter_sctp(3)</seealso></p>
+&man_tcp;, &man_sctp;</p>
</section>
diff --git a/lib/diameter/doc/src/files.mk b/lib/diameter/doc/src/files.mk
index 79d53abceb..00ced3d91e 100644
--- a/lib/diameter/doc/src/files.mk
+++ b/lib/diameter/doc/src/files.mk
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2010-2011. All Rights Reserved.
+# Copyright Ericsson AB 2010-2012. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -26,6 +26,8 @@ XML_REF1_FILES = \
XML_REF3_FILES = \
diameter.xml \
diameter_app.xml \
+ diameter_codec.xml \
+ diameter_make.xml \
diameter_transport.xml \
diameter_tcp.xml \
diameter_sctp.xml
diff --git a/lib/diameter/doc/src/notes.xml b/lib/diameter/doc/src/notes.xml
index e57958ac09..d241e2bd19 100644
--- a/lib/diameter/doc/src/notes.xml
+++ b/lib/diameter/doc/src/notes.xml
@@ -1,11 +1,17 @@
<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
+<!DOCTYPE chapter SYSTEM "chapter.dtd" [
+ <!ENTITY % also SYSTEM "seealso.ent" >
+ <!ENTITY % here SYSTEM "seehere.ent" >
+ %also;
+ %here;
+]>
<chapter>
<header>
<copyright>
<year>2011</year>
+<year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -36,6 +42,179 @@ first.</p>
<!-- ===================================================================== -->
+<section><title>Diameter 1.3.1</title>
+
+ <section><title>Known Bugs and Problems</title>
+ <list>
+ <item>
+ <p>
+ Fix function clause resulting from use of an eval
+ callback.</p>
+ <p>
+ Own Id: OTP-10685</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Diameter 1.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix faulty handling of Origin-State-Id and faulty config
+ values.</p>
+ <p>
+ The former was expected in a list despite the
+ documentation requiring (correctly) an integer. A bare
+ value for a list-valued capability was not handled.</p>
+ <p>
+ Own Id: OTP-10440</p>
+ </item>
+ <item>
+ <p>
+ Fix timing of up/down events.</p>
+ <p>
+ Previously, a call to diameter:call/4 following a peer_up
+ callback might incorrectly return {error, no_connection},
+ depending on timing. Both events now follow the
+ corresponding callbacks.</p>
+ <p>
+ Own Id: OTP-10459</p>
+ </item>
+ <item>
+ <p>
+ Make diameter:service_info/2 usable in peer_up, peer_down
+ and pick_peer callbacks.</p>
+ <p>
+ Except for in pick_peer when {call_mutates_state, false},
+ it would previously hang indefinitely.</p>
+ <p>
+ Own Id: OTP-10460</p>
+ </item>
+ <item>
+ <p>
+ Verify that End-to-End and Hop-by-Hop Identifiers in an
+ incoming CEA/DPA match those sent in the corresponding
+ CER/DPR.</p>
+ <p>
+ The values were previously ignored. Answers whose
+ identifiers do not match are handled as unexpected.</p>
+ <p>
+ Own Id: OTP-10565</p>
+ </item>
+ <item>
+ <p>
+ Fix formatting problems in PDF documentation.</p>
+ <p>
+ In particular, text corresponding to links in HTML was
+ omitted in preformatted blocks. There are still issues
+ with indentation but this is not diameter-specific.</p>
+ <p>
+ Own Id: OTP-10583</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Let prepare_request, prepare_retransmit and
+ handle_request callbacks return a function to be invoked
+ on outgoing messages after encode.</p>
+ <p>
+ This allows encoded messages to be logged for example.</p>
+ <p>
+ Own Id: OTP-10441</p>
+ </item>
+ <item>
+ <p>
+ Add service_opt() 'restrict_connections' to allow
+ multiple transport connections with the same peer.</p>
+ <p>
+ Own Id: OTP-10443</p>
+ </item>
+ <item>
+ <p>
+ Add service_opt() 'sequence' to allow the masking of a
+ constant onto the topmost bits of End-to-End and
+ Hop-by-Hop identifiers.</p>
+ <p>
+ This allows the same service on different nodes to use
+ distinct values in outgoing request messages.</p>
+ <p>
+ Own Id: OTP-10445</p>
+ </item>
+ <item>
+ <p>
+ Add diameter:service_info(PeerRef) to return the
+ transport_ref() and transport_opt() list of the
+ corresponding transport.</p>
+ <p>
+ This allows easy access to these from diameter_app
+ callbacks that only get peer_ref() as an argument.</p>
+ <p>
+ Own Id: OTP-10470</p>
+ </item>
+ <item>
+ <p>
+ Add reference pages diameter_codec(3) and
+ diameter_make(3).</p>
+ <p>
+ Own Id: OTP-10471</p>
+ </item>
+ <item>
+ <p>
+ Add events for service start and stop.</p>
+ <p>
+ Own Id: OTP-10492</p>
+ </item>
+ <item>
+ <p>
+ Add transport_opt() 'disconnect_cb' to make the sending
+ of DPR configurable.</p>
+ <p>
+ Whether or not DPR should be sent at application stop,
+ service stop or transport removal is determined by the
+ value returned by the callback, as is the
+ Disconnect-Cause and timeout if DPA is not received.</p>
+ <p>
+ Own Id: OTP-10493</p>
+ </item>
+ <item>
+ <p>
+ Add transport_opt() 'capx_timeout' for the timeout
+ associated with non-reception of CER/CEA.</p>
+ <p>
+ Own Id: OTP-10554</p>
+ </item>
+ <item>
+ <p>
+ Allow a handle_request callback to return a
+ #diameter_packet{}.</p>
+ <p>
+ This allows an answer to set transport_data and header
+ fields.</p>
+ <p>
+ Own Id: OTP-10566</p>
+ </item>
+ <item>
+ <p>
+ Update documentation for RFC 6733.</p>
+ <p>
+ RFC 3588 is now obsolete.</p>
+ <p>
+ Own Id: OTP-10568</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Diameter 1.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -136,6 +315,33 @@ first.</p>
</section>
+<section><title>Diameter 1.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix fault in sending of 'closed' events.</p>
+ <p>
+ The fault made it possible for the 'closed' event not to
+ be sent following a failed capabilities exchange.</p>
+ <p>
+ Own Id: OTP-9824</p>
+ </item>
+ <item>
+ <p>
+ Fix faulty diameterc -name/-prefix.</p>
+ <p>
+ A minor blunder when introducing the new dictionary
+ parser in diameter-1.0 broke these options.</p>
+ <p>
+ Own Id: OTP-9826</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Diameter 1.0</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -395,8 +601,7 @@ Known issues or limitations:</p>
Some agent-related functionality is not entirely complete.
In particular, support for proxy agents, that advertise specific
Diameter applications but otherwise relay messages in much the same
-way as relay agents (for which a <seealso
-marker="diameter_app#handle_request">handle_request/3</seealso>
+way as relay agents (for which a handle_request
callback can return a <c>relay</c> tuple), will be completed in an
upcoming release.
There may also be more explicit support for redirect agents, although
@@ -428,8 +633,7 @@ could likely be expanded upon.</p>
<item>
<p>
-The function <seealso
-marker="diameter#service_info">diameter:service_info/2</seealso>
+The function diameter:service_info/2
can be used to retrieve information about a started service
(statistics, information about connected peers, etc) but
this is not yet documented and both the input and output may change
diff --git a/lib/diameter/doc/src/ref_man.xml b/lib/diameter/doc/src/ref_man.xml
index 137ce79094..4b99fe716d 100644
--- a/lib/diameter/doc/src/ref_man.xml
+++ b/lib/diameter/doc/src/ref_man.xml
@@ -6,6 +6,7 @@
<header>
<copyright>
<year>2011</year>
+<year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -40,7 +41,9 @@ applications on top of the Diameter protocol. </p>
<xi:include href="diameter.xml"/>
<xi:include href="diameter_compile.xml"/>
<xi:include href="diameter_app.xml"/>
+<xi:include href="diameter_codec.xml"/>
<xi:include href="diameter_dict.xml"/>
+<xi:include href="diameter_make.xml"/>
<xi:include href="diameter_transport.xml"/>
<xi:include href="diameter_tcp.xml"/>
<xi:include href="diameter_sctp.xml"/>
diff --git a/lib/diameter/doc/src/seealso.ent b/lib/diameter/doc/src/seealso.ent
new file mode 100644
index 0000000000..4647c42f85
--- /dev/null
+++ b/lib/diameter/doc/src/seealso.ent
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="iso-8859-1" ?>
+
+<!--
+
+%CopyrightBegin%
+
+Copyright Ericsson AB 2012. All Rights Reserved.
+
+The 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%
+
+-->
+
+<!--
+
+Entities for cross references: less to type, easier to read and
+less error prone.
+
+Additional intra-document entities are generated by seehere.sed.
+That each definition is on a single (hideously long) line is
+significant.
+
+-->
+
+<!ENTITY the_rfc 'RFC 6733'>
+
+<!-- diameter -->
+
+<!ENTITY mod_add_transport '<seealso marker="diameter#add_transport-2">diameter:add_transport/2</seealso>'>
+<!ENTITY mod_call '<seealso marker="diameter#call-4">diameter:call/4</seealso>'>
+<!ENTITY mod_origin_state_id '<seealso marker="diameter#origin_state_id-0">diameter:origin_state_id/0</seealso>'>
+<!ENTITY mod_remove_transport '<seealso marker="diameter#remove_transport-2">diameter:remove_transport/2</seealso>'>
+<!ENTITY mod_service_info '<seealso marker="diameter#service_info-2">diameter:service_info/2</seealso>'>
+<!ENTITY mod_services '<seealso marker="diameter#services-0">diameter:services/0</seealso>'>
+<!ENTITY mod_start_service '<seealso marker="diameter#start_service-2">diameter:start_service/2</seealso>'>
+<!ENTITY mod_stop_service '<seealso marker="diameter#stop_service-1">diameter:stop_service/1</seealso>'>
+<!ENTITY mod_subscribe '<seealso marker="diameter#subscribe-1">diameter:subscribe/1</seealso>'>
+
+<!ENTITY mod_application_alias '<seealso marker="diameter#application_alias">diameter:application_alias()</seealso>'>
+<!ENTITY mod_application_module '<seealso marker="diameter#application_module">diameter:application_module()</seealso>'>
+<!ENTITY mod_application_opt '<seealso marker="diameter#application_opt">diameter:application_opt()</seealso>'>
+<!ENTITY mod_call_opt '<seealso marker="diameter#call_opt">diameter:call_opt()</seealso>'>
+<!ENTITY mod_capability '<seealso marker="diameter#capability">diameter:capability()</seealso>'>
+<!ENTITY mod_evaluable '<seealso marker="diameter#evaluable">diameter:evaluable()</seealso>'>
+<!ENTITY mod_peer_filter '<seealso marker="diameter#peer_filter">diameter:peer_filter()</seealso>'>
+<!ENTITY mod_service_event '<seealso marker="diameter#service_event">diameter:service_event()</seealso>'>
+<!ENTITY mod_service_name '<seealso marker="diameter#service_name">diameter:service_name()</seealso>'>
+<!ENTITY mod_service_opt '<seealso marker="diameter#service_opt">diameter:service_opt()</seealso>'>
+<!ENTITY mod_transport_opt '<seealso marker="diameter#transport_opt">diameter:transport_opt()</seealso>'>
+<!ENTITY mod_transport_ref '<seealso marker="diameter#transport_ref">diameter:transport_ref()</seealso>'>
+
+<!ENTITY capabilities_cb '<seealso marker="#capabilities_cb">capabilities_cb</seealso>'>
+<!ENTITY capx_timeout '<seealso marker="#capx_timeout">capx_timeout</seealso>'>
+<!ENTITY disconnect_cb '<seealso marker="#disconnect_cb">disconnect_cb</seealso>'>
+<!ENTITY transport_config '<seealso marker="#transport_config">transport_config</seealso>'>
+<!ENTITY transport_module '<seealso marker="#transport_module">transport_module</seealso>'>
+<!ENTITY reconnect_timer '<seealso marker="#reconnect_timer">reconnect_timer</seealso>'>
+<!ENTITY watchdog_timer '<seealso marker="#watchdog_timer">watchdog_timer</seealso>'>
+
+<!-- diameter_app -->
+
+<!ENTITY app_handle_answer '<seealso marker="diameter_app#Mod:handle_answer-4">handle_answer/4</seealso>'>
+<!ENTITY app_handle_request '<seealso marker="diameter_app#Mod:handle_request-3">handle_request/3</seealso>'>
+<!ENTITY app_handle_error '<seealso marker="diameter_app#Mod:handle_error-4">handle_error/4</seealso>'>
+<!ENTITY app_peer_down '<seealso marker="diameter_app#Mod:peer_down-3">peer_up/3</seealso>'>
+<!ENTITY app_peer_up '<seealso marker="diameter_app#Mod:peer_up-3">peer_up/3</seealso>'>
+<!ENTITY app_pick_peer '<seealso marker="diameter_app#Mod:pick_peer-4">pick_peer/4</seealso>'>
+<!ENTITY app_prepare_retransmit '<seealso marker="diameter_app#Mod:prepare_retransmit-3">prepare_retransmit/3</seealso>'>
+<!ENTITY app_prepare_request '<seealso marker="diameter_app#Mod:prepare_request-3">prepare_request/3</seealso>'>
+
+<!ENTITY app_capabilities '<seealso marker="diameter_app#capabilities">diameter_app:capabilities()</seealso>'>
+<!ENTITY app_peer '<seealso marker="diameter_app#peer">diameter_app:peer()</seealso>'>
+<!ENTITY app_peer_ref '<seealso marker="diameter_app#peer_ref">diameter_app:peer_ref()</seealso>'>
+<!ENTITY app_state '<seealso marker="diameter_app#state">diameter_app:state()</seealso>'>
+
+<!-- diameter_codec -->
+
+<!ENTITY codec_encode '<seealso marker="diameter_codec#encode-2">diameter_codec:encode/2</seealso>'>
+<!ENTITY codec_decode '<seealso marker="diameter_codec#decode-2">diameter_codec:decode/2</seealso>'>
+
+<!ENTITY codec_avp '<seealso marker="diameter_codec#avp">diameter_codec:avp()</seealso>'>
+<!ENTITY codec_header '<seealso marker="diameter_codec#header">diameter_codec:header()</seealso>'>
+<!ENTITY codec_dictionary '<seealso marker="diameter_codec#dictionary">diameter_codec:dictionary()</seealso>'>
+<!ENTITY codec_message '<seealso marker="diameter_codec#message">diameter_codec:message()</seealso>'>
+<!ENTITY codec_packet '<seealso marker="diameter_codec#packet">diameter_codec:packet()</seealso>'>
+
+<!-- diameter_dict -->
+
+<!ENTITY dict_data_types '<seealso marker="diameter_dict#DATA_TYPES">diameter_dict(4)</seealso>'>
+
+<!ENTITY dict_Address '<seealso marker="diameter_dict#DATA_TYPES">Address()</seealso>'>
+<!ENTITY dict_DiameterIdentity '<seealso marker="diameter_dict#DATA_TYPES">DiameterIdentity()</seealso>'>
+<!ENTITY dict_Grouped '<seealso marker="diameter_dict#DATA_TYPES">Grouped()</seealso>'>
+<!ENTITY dict_OctetString '<seealso marker="diameter_dict#DATA_TYPES">OctetString()</seealso>'>
+<!ENTITY dict_Time '<seealso marker="diameter_dict#DATA_TYPES">Time()</seealso>'>
+<!ENTITY dict_UTF8String '<seealso marker="diameter_dict#DATA_TYPES">UTF8String()</seealso>'>
+<!ENTITY dict_Unsigned32 '<seealso marker="diameter_dict#DATA_TYPES">Unsigned32()</seealso>'>
+
+<!ENTITY dict_name '<seealso marker="diameter_dict#name">@name</seealso>'>
+<!ENTITY dict_prefix '<seealso marker="diameter_dict#prefix">@prefix</seealso>'>
+<!ENTITY dict_inherits '<seealso marker="diameter_dict#inherits">@inherits</seealso>'>
+
+<!-- diameter_make -->
+
+<!ENTITY make_codec '<seealso marker="diameter_make#codec-2">diameter_make:codec/2</seealso>'>
+
+<!-- diameter_transport -->
+
+<!ENTITY transport_start
+ '<seealso marker="diameter_transport#Mod:start-3">start/3</seealso>'>
+
+<!-- reference pages -->
+
+<!ENTITY man_compile '<seealso marker="diameterc">diameterc(1)</seealso>'>
+<!ENTITY man_main '<seealso marker="diameter">diameter(3)</seealso>'>
+<!ENTITY man_app '<seealso marker="diameter_app">diameter_app(3)</seealso>'>
+<!ENTITY man_codec '<seealso marker="diameter_codec">diameter_codec(3)</seealso>'>
+<!ENTITY man_dict '<seealso marker="diameter_dict">diameter_dict(4)</seealso>'>
+<!ENTITY man_make '<seealso marker="diameter_make">diameter_make(3)</seealso>'>
+<!ENTITY man_transport '<seealso marker="diameter_transport">diameter_transport(3)</seealso>'>
+<!ENTITY man_sctp '<seealso marker="diameter_sctp">diameter_sctp(3)</seealso>'>
+<!ENTITY man_tcp '<seealso marker="diameter_tcp">diameter_tcp(3)</seealso>'>
diff --git a/lib/diameter/doc/src/seehere.sed b/lib/diameter/doc/src/seehere.sed
new file mode 100644
index 0000000000..c62a783d40
--- /dev/null
+++ b/lib/diameter/doc/src/seehere.sed
@@ -0,0 +1,35 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2012. All Rights Reserved.
+#
+# The 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%
+
+#
+# Map entities for inter-document references to ones for
+# intra-document references like this:
+#
+# <!ENTITY aaa_xxx '<seealso marker="bbb#yyy">ccc:zzz</seealso>'>
+#
+# ===>
+#
+# <!ENTITY xxx '<seealso marker="#yyy">zzz</seealso>'>
+#
+
+/<!ENTITY/!d
+/#/!d
+/"#/d
+s@ [^_]*_@ @
+s@"[^#]*#@"#@
+s@>[^:]*:@>@
diff --git a/lib/diameter/doc/standard/draft-ietf-dime-capablities-update-07.txt b/lib/diameter/doc/standard/draft-ietf-dime-capablities-update-07.txt
deleted file mode 100644
index bb7ec2d08c..0000000000
--- a/lib/diameter/doc/standard/draft-ietf-dime-capablities-update-07.txt
+++ /dev/null
@@ -1,392 +0,0 @@
-
-
-
-Network Working Group K. Jiao
-Internet-Draft Huawei
-Intended status: Standards Track G. Zorn
-Expires: April 27, 2011 Network Zen
- October 24, 2010
-
-
- The Diameter Capabilities Update Application
- draft-ietf-dime-capablities-update-07
-
-Abstract
-
- This document defines a new Diameter application and associated
- command codes. The Capabilities Update application is intended to
- allow the dynamic update of certain Diameter peer capabilities while
- the peer-to-peer connection is in the open state.
-
-Status of this Memo
-
- This Internet-Draft is submitted in full conformance with the
- provisions of BCP 78 and BCP 79.
-
- Internet-Drafts are working documents of the Internet Engineering
- Task Force (IETF). Note that other groups may also distribute
- working documents as Internet-Drafts. The list of current Internet-
- Drafts is at http://datatracker.ietf.org/drafts/current/.
-
- Internet-Drafts are draft documents valid for a maximum of six months
- and may be updated, replaced, or obsoleted by other documents at any
- time. It is inappropriate to use Internet-Drafts as reference
- material or to cite them other than as "work in progress."
-
- This Internet-Draft will expire on April 27, 2011.
-
-Copyright Notice
-
- Copyright (c) 2010 IETF Trust and the persons identified as the
- document authors. All rights reserved.
-
- This document is subject to BCP 78 and the IETF Trust's Legal
- Provisions Relating to IETF Documents
- (http://trustee.ietf.org/license-info) in effect on the date of
- publication of this document. Please review these documents
- carefully, as they describe your rights and restrictions with respect
- to this document. Code Components extracted from this document must
- include Simplified BSD License text as described in Section 4.e of
- the Trust Legal Provisions and are provided without warranty as
- described in the Simplified BSD License.
-
-
-
-Jiao & Zorn Expires April 27, 2011 [Page 1]
-
-Internet-Draft Diameter Capabilities Update October 2010
-
-
-Table of Contents
-
- 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 3
- 2. Specification of Requirements . . . . . . . . . . . . . . . . . 3
- 3. Diameter Protocol Considerations . . . . . . . . . . . . . . . 3
- 4. Capabilities Update . . . . . . . . . . . . . . . . . . . . . . 3
- 4.1. Command-Code Values . . . . . . . . . . . . . . . . . . . . 4
- 4.1.1. Capabilities-Update-Request . . . . . . . . . . . . . . 5
- 4.1.2. Capabilities-Update-Answer . . . . . . . . . . . . . . 5
- 5. Security Considerations . . . . . . . . . . . . . . . . . . . . 6
- 6. IANA Considerations . . . . . . . . . . . . . . . . . . . . . . 6
- 6.1. Application Identifier . . . . . . . . . . . . . . . . . . 6
- 6.2. Command Codes . . . . . . . . . . . . . . . . . . . . . . . 6
- 7. Contributors . . . . . . . . . . . . . . . . . . . . . . . . . 6
- 8. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 6
- 9. References . . . . . . . . . . . . . . . . . . . . . . . . . . 6
- 9.1. Normative References . . . . . . . . . . . . . . . . . . . 6
- 9.2. Informative References . . . . . . . . . . . . . . . . . . 7
- Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 7
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Jiao & Zorn Expires April 27, 2011 [Page 2]
-
-Internet-Draft Diameter Capabilities Update October 2010
-
-
-1. Introduction
-
- Capabilities exchange is an important component of the Diameter Base
- Protocol [I-D.ietf-dime-rfc3588bis], allowing peers to exchange
- identities and Diameter capabilities (protocol version number,
- supported Diameter applications, security mechanisms, etc.). As
- defined in RFC 3588, however, the capabilities exchange process takes
- place only once, at the inception of a transport connection between a
- given pair of peers. Therefore, if a peer's capabilities change (due
- to software update, for example), the existing connection(s) must be
- torn down (along with all of the associated user sessions) and
- restarted before the modified capabilities can be advertised.
-
- This document defines a new Diameter application intended to allow
- the dynamic update of a subset of Diameter peer capabilities over an
- existing connection. Because the Capabilities Update application
- specified herein operates over an existing transport connection,
- modification of certain capabilities is prohibited. Specifically,
- modifying the security mechanism in use is not allowed; if the
- security method used between a pair of peers is changed the affected
- connection MUST be restarted.
-
-
-2. Specification of Requirements
-
- The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
- "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
- document are to be interpreted as described in RFC 2119 [RFC2119].
-
-
-3. Diameter Protocol Considerations
-
- This section details the relationship of the Diameter Capabilities
- Update application to the Diameter Base Protocol.
-
- This document specifies Diameter Application-ID <TBD1>. Diameter
- nodes conforming to this specification MUST advertise support by
- including the value <TBD1> in the Auth-Application-Id of the
- Capabilities-Exchange-Request (CER) and Capabilities-Exchange-Answer
- (CEA) commands [I-D.ietf-dime-rfc3588bis].
-
-
-4. Capabilities Update
-
- When the capabilities of a Diameter node conforming to this
- specification change, it MUST notify all of the nodes with which it
- has an open transport connection and which have also advertised
- support for the Capabilities Update application using the
-
-
-
-Jiao & Zorn Expires April 27, 2011 [Page 3]
-
-Internet-Draft Diameter Capabilities Update October 2010
-
-
- Capabilities-Update-Request (CUR) message (Section 4.1.1). This
- message allows the update of a peer's capabilities (supported
- Diameter applications, etc.).
-
- A Diameter node only issues a given command to those peers that have
- advertised support for the Diameter application that defines the
- command; a Diameter node must cache the supported applications in
- order to ensure that unrecognized commands and/or Attribute-Value
- Pairs (AVPs) are not unnecessarily sent to a peer.
-
- The receiver of the CUR MUST determine common applications by
- computing the intersection of its own set of supported Application Id
- against all of the application identifier AVPs (Auth-Application-Id,
- Acct-Application-Id and Vendor-Specific- Application-Id) present in
- the CUR. The value of the Vendor-Id AVP in the Vendor-Specific-
- Application-Id MUST NOT be used during computation.
-
- If the receiver of a CUR does not have any applications in common
- with the sender then it MUST return a Capabilities-Update-Answer
- (CUA) (Section 4.1.2) with the Result-Code AVP set to
- DIAMETER_NO_COMMON_APPLICATION [I-D.ietf-dime-rfc3588bis], and SHOULD
- disconnect the transport layer connection; however, if active
- sessions are using the connection, peers MAY delay disconnection
- until the sessions can be redirected or gracefully terminated. Note
- that receiving a CUA from a peer advertising itself as a Relay (see
- [I-D.ietf-dime-rfc3588bis], Section 2.4) MUST be interpreted as
- having common applications with the peer.
-
- As for CER/CEA messages, the CUR and CUA messages MUST NOT be
- proxied, redirected or relayed.
-
- Even though the CUR/CUA messages cannot be proxied, it is still
- possible for an upstream agent to receive a message for which there
- are no peers available to handle the application that corresponds to
- the Command-Code. This could happen if, for example, the peers are
- too busy or down. In such instances, the 'E' bit MUST be set in the
- answer message with the Result-Code AVP set to
- DIAMETER_UNABLE_TO_DELIVER to inform the downstream peer to take
- action (e.g., re-routing requests to an alternate peer).
-
-4.1. Command-Code Values
-
- This section defines Command-Code [I-D.ietf-dime-rfc3588bis] values
- that MUST be supported by all Diameter implementations conforming to
- this specification. The following Command Codes are defined (using
- modified ABNF [I-D.ietf-dime-rfc3588bis]) in this document:
- Capabilities-Update-Request (CUR, Section 4.1.1) and Capabilities-
- Update-Answer (CUA, Section 4.1.2).
-
-
-
-Jiao & Zorn Expires April 27, 2011 [Page 4]
-
-Internet-Draft Diameter Capabilities Update October 2010
-
-
-4.1.1. Capabilities-Update-Request
-
- The Capabilities-Update-Request (CUR), indicated by the Command-Code
- set to <CUCC> and the Command Flags' 'R' bit set, is sent to update
- local capabilities. Upon detection of a transport failure, this
- message MUST NOT be sent to an alternate peer.
-
- When Diameter is run over the Stream Control Transmission Protocol
- [RFC4960], which allows connections to span multiple interfaces and
- multiple IP addresses, the Capabilities-Update-Request message MUST
- contain one Host-IP-Address AVP for each potential IP address that
- may be locally used when transmitting Diameter messages.
-
- Message Format
-
- <CUR> ::= < Diameter Header: <CUCC>, REQ >
- { Origin-Host }
- { Origin-Realm }
- 1* { Host-IP-Address }
- { Vendor-Id }
- { Product-Name }
- [ Origin-State-Id ]
- * [ Supported-Vendor-Id ]
- * [ Auth-Application-Id ]
- * [ Acct-Application-Id ]
- * [ Vendor-Specific-Application-Id ]
- [ Firmware-Revision ]
- * [ AVP ]
-
-4.1.2. Capabilities-Update-Answer
-
- The Capabilities-Update-Answer, indicated by the Command-Code set to
- <CUCC> and the Command Flags' 'R' bit cleared, is sent in response to
- a CUR message.
-
- Message Format
-
- <CUA> ::= < Diameter Header: <CUCC> >
- { Origin-Host }
- { Origin-Realm }
- { Result-Code }
- [ Error-Message ]
- * [ AVP ]
-
-
-
-
-
-
-
-
-Jiao & Zorn Expires April 27, 2011 [Page 5]
-
-Internet-Draft Diameter Capabilities Update October 2010
-
-
-5. Security Considerations
-
- The security considerations applicable to the Diameter Base Protocol
- [I-D.ietf-dime-rfc3588bis] are also applicable to this document.
-
-
-6. IANA Considerations
-
- This section explains the criteria to be used by the IANA for
- assignment of numbers within namespaces used within this document.
-
-6.1. Application Identifier
-
- This specification assigns the value <TBD1> from the Application
- Identifiers namespace [I-D.ietf-dime-rfc3588bis]. See Section 3 for
- the assignment of the namespace in this specification.
-
-6.2. Command Codes
-
- This specification assigns the value <CUCC> from the Command Codes
- namespace [I-D.ietf-dime-rfc3588bis]. See Section 4.1 for the
- assignment of the namespace in this specification.
-
-
-7. Contributors
-
- This document is based upon work done by Tina Tsou.
-
-
-8. Acknowledgements
-
- Thanks to Sebastien Decugis, Niklas Neumann, Subash Comerica, Lionel
- Morand, Dan Romascanu, Dan Harkins and Ravi for helpful review and
- discussion.
-
-
-9. References
-
-9.1. Normative References
-
- [I-D.ietf-dime-rfc3588bis]
- Fajardo, V., Arkko, J., Loughney, J., and G. Zorn,
- "Diameter Base Protocol", draft-ietf-dime-rfc3588bis-25
- (work in progress), September 2010.
-
- [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
- Requirement Levels", BCP 14, RFC 2119, March 1997.
-
-
-
-
-Jiao & Zorn Expires April 27, 2011 [Page 6]
-
-Internet-Draft Diameter Capabilities Update October 2010
-
-
-9.2. Informative References
-
- [RFC4960] Stewart, R., "Stream Control Transmission Protocol",
- RFC 4960, September 2007.
-
-
-Authors' Addresses
-
- Jiao Kang
- Huawei Technologies
- Section B1, Huawei Industrial Base
- Bantian, Longgang District
- Shenzhen 518129
- P.R. China
-
- Phone: +86 755 2878-6690
-
-
- Glen Zorn
- Network Zen
- 227/358 Thanon Sanphawut
- Bang Na, Bangkok 10260
- Thailand
-
- Phone: +66 (0) 87-040-4617
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Jiao & Zorn Expires April 27, 2011 [Page 7]
-
diff --git a/lib/diameter/doc/standard/draft-ietf-dime-rfc3588bis-26.txt b/lib/diameter/doc/standard/rfc6733.txt
index 87b9562f93..2f5a477347 100644
--- a/lib/diameter/doc/standard/draft-ietf-dime-rfc3588bis-26.txt
+++ b/lib/diameter/doc/standard/rfc6733.txt
@@ -1,62 +1,72 @@
-DIME V. Fajardo, Ed.
-Internet-Draft Telcordia Technologies
-Obsoletes: 3588 (if approved) J. Arkko
-Intended status: Standards Track Ericsson Research
-Expires: July 24, 2011 J. Loughney
+
+
+
+Internet Engineering Task Force (IETF) V. Fajardo, Ed.
+Request for Comments: 6733 Telcordia Technologies
+Obsoletes: 3588, 5719 J. Arkko
+Category: Standards Track Ericsson Research
+ISSN: 2070-1721 J. Loughney
Nokia Research Center
- G. Zorn
+ G. Zorn, Ed.
Network Zen
- January 20, 2011
+ October 2012
Diameter Base Protocol
- draft-ietf-dime-rfc3588bis-26.txt
Abstract
The Diameter base protocol is intended to provide an Authentication,
- Authorization and Accounting (AAA) framework for applications such as
- network access or IP mobility in both local and roaming situations.
- This document specifies the message format, transport, error
- reporting, accounting and security services used by all Diameter
- applications. The Diameter base protocol as defined in this document
- must be supported by all Diameter implementations.
+ Authorization, and Accounting (AAA) framework for applications such
+ as network access or IP mobility in both local and roaming
+ situations. This document specifies the message format, transport,
+ error reporting, accounting, and security services used by all
+ Diameter applications. The Diameter base protocol as defined in this
+ document obsoletes RFC 3588 and RFC 5719, and it must be supported by
+ all new Diameter implementations.
-Status of this Memo
+Status of This Memo
- This Internet-Draft is submitted in full conformance with the
- provisions of BCP 78 and BCP 79.
+ This is an Internet Standards Track document.
- Internet-Drafts are working documents of the Internet Engineering
- Task Force (IETF). Note that other groups may also distribute
- working documents as Internet-Drafts. The list of current Internet-
- Drafts is at http://datatracker.ietf.org/drafts/current/.
+ This document is a product of the Internet Engineering Task Force
+ (IETF). It represents the consensus of the IETF community. It has
+ received public review and has been approved for publication by the
+ Internet Engineering Steering Group (IESG). Further information on
+ Internet Standards is available in Section 2 of RFC 5741.
+
+ Information about the current status of this document, any errata,
+ and how to provide feedback on it may be obtained at
+ http://www.rfc-editor.org/info/rfc6733.
- Internet-Drafts are draft documents valid for a maximum of six months
- and may be updated, replaced, or obsoleted by other documents at any
- time. It is inappropriate to use Internet-Drafts as reference
- material or to cite them other than as "work in progress."
- This Internet-Draft will expire on July 24, 2011.
-Copyright Notice
- Copyright (c) 2011 IETF Trust and the persons identified as the
- document authors. All rights reserved.
- This document is subject to BCP 78 and the IETF Trust's Legal
- Provisions Relating to IETF Documents
-Fajardo, et al. Expires July 24, 2011 [Page 1]
+
+
+
+
+
+
+Fajardo, et al. Standards Track [Page 1]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
+Copyright Notice
+
+ Copyright (c) 2012 IETF Trust and the persons identified as the
+ document authors. All rights reserved.
+
+ This document is subject to BCP 78 and the IETF Trust's Legal
+ Provisions Relating to IETF Documents
(http://trustee.ietf.org/license-info) in effect on the date of
publication of this document. Please review these documents
carefully, as they describe your rights and restrictions with respect
@@ -65,256 +75,303 @@ Internet-Draft Diameter Base Protocol January 2011
the Trust Legal Provisions and are provided without warranty as
described in the Simplified BSD License.
+ This document may contain material from IETF Documents or IETF
+ Contributions published or made publicly available before November
+ 10, 2008. The person(s) controlling the copyright in some of this
+ material may not have granted the IETF Trust the right to allow
+ modifications of such material outside the IETF Standards Process.
+ Without obtaining an adequate license from the person(s) controlling
+ the copyright in such materials, this document may not be modified
+ outside the IETF Standards Process, and derivative works of it may
+ not be created outside the IETF Standards Process, except to format
+ it for publication as an RFC or to translate it into languages other
+ than English.
Table of Contents
- 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 6
- 1.1. Diameter Protocol . . . . . . . . . . . . . . . . . . . . 8
- 1.1.1. Description of the Document Set . . . . . . . . . . . 9
- 1.1.2. Conventions Used in This Document . . . . . . . . . . 10
- 1.1.3. Changes from RFC3588 . . . . . . . . . . . . . . . . 10
- 1.2. Terminology . . . . . . . . . . . . . . . . . . . . . . . 12
- 1.3. Approach to Extensibility . . . . . . . . . . . . . . . . 17
- 1.3.1. Defining New AVP Values . . . . . . . . . . . . . . . 18
- 1.3.2. Creating New AVPs . . . . . . . . . . . . . . . . . . 18
- 1.3.3. Creating New Commands . . . . . . . . . . . . . . . . 18
- 1.3.4. Creating New Diameter Applications . . . . . . . . . 19
- 2. Protocol Overview . . . . . . . . . . . . . . . . . . . . . . 21
- 2.1. Transport . . . . . . . . . . . . . . . . . . . . . . . . 22
- 2.1.1. SCTP Guidelines . . . . . . . . . . . . . . . . . . . 23
- 2.2. Securing Diameter Messages . . . . . . . . . . . . . . . 24
- 2.3. Diameter Application Compliance . . . . . . . . . . . . . 24
- 2.4. Application Identifiers . . . . . . . . . . . . . . . . . 24
- 2.5. Connections vs. Sessions . . . . . . . . . . . . . . . . 25
- 2.6. Peer Table . . . . . . . . . . . . . . . . . . . . . . . 26
- 2.7. Routing Table . . . . . . . . . . . . . . . . . . . . . . 27
- 2.8. Role of Diameter Agents . . . . . . . . . . . . . . . . . 28
- 2.8.1. Relay Agents . . . . . . . . . . . . . . . . . . . . 29
- 2.8.2. Proxy Agents . . . . . . . . . . . . . . . . . . . . 30
- 2.8.3. Redirect Agents . . . . . . . . . . . . . . . . . . . 31
- 2.8.4. Translation Agents . . . . . . . . . . . . . . . . . 32
- 2.9. Diameter Path Authorization . . . . . . . . . . . . . . . 33
- 3. Diameter Header . . . . . . . . . . . . . . . . . . . . . . . 35
- 3.1. Command Codes . . . . . . . . . . . . . . . . . . . . . . 38
- 3.2. Command Code ABNF specification . . . . . . . . . . . . . 38
- 3.3. Diameter Command Naming Conventions . . . . . . . . . . . 41
- 4. Diameter AVPs . . . . . . . . . . . . . . . . . . . . . . . . 42
- 4.1. AVP Header . . . . . . . . . . . . . . . . . . . . . . . 42
- 4.1.1. Optional Header Elements . . . . . . . . . . . . . . 43
- 4.2. Basic AVP Data Formats . . . . . . . . . . . . . . . . . 44
- 4.3. Derived AVP Data Formats . . . . . . . . . . . . . . . . 45
- 4.3.1. Common Derived AVPs . . . . . . . . . . . . . . . . . 45
- 4.4. Grouped AVP Values . . . . . . . . . . . . . . . . . . . 52
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 2]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
- 4.4.1. Example AVP with a Grouped Data type . . . . . . . . 53
- 4.5. Diameter Base Protocol AVPs . . . . . . . . . . . . . . . 56
- 5. Diameter Peers . . . . . . . . . . . . . . . . . . . . . . . 59
- 5.1. Peer Connections . . . . . . . . . . . . . . . . . . . . 59
- 5.2. Diameter Peer Discovery . . . . . . . . . . . . . . . . . 60
- 5.3. Capabilities Exchange . . . . . . . . . . . . . . . . . . 61
- 5.3.1. Capabilities-Exchange-Request . . . . . . . . . . . . 63
- 5.3.2. Capabilities-Exchange-Answer . . . . . . . . . . . . 63
- 5.3.3. Vendor-Id AVP . . . . . . . . . . . . . . . . . . . . 64
- 5.3.4. Firmware-Revision AVP . . . . . . . . . . . . . . . . 64
- 5.3.5. Host-IP-Address AVP . . . . . . . . . . . . . . . . . 64
- 5.3.6. Supported-Vendor-Id AVP . . . . . . . . . . . . . . . 65
- 5.3.7. Product-Name AVP . . . . . . . . . . . . . . . . . . 65
- 5.4. Disconnecting Peer connections . . . . . . . . . . . . . 65
- 5.4.1. Disconnect-Peer-Request . . . . . . . . . . . . . . . 66
- 5.4.2. Disconnect-Peer-Answer . . . . . . . . . . . . . . . 66
- 5.4.3. Disconnect-Cause AVP . . . . . . . . . . . . . . . . 66
- 5.5. Transport Failure Detection . . . . . . . . . . . . . . . 67
- 5.5.1. Device-Watchdog-Request . . . . . . . . . . . . . . . 67
- 5.5.2. Device-Watchdog-Answer . . . . . . . . . . . . . . . 67
- 5.5.3. Transport Failure Algorithm . . . . . . . . . . . . . 68
- 5.5.4. Failover and Failback Procedures . . . . . . . . . . 68
- 5.6. Peer State Machine . . . . . . . . . . . . . . . . . . . 69
- 5.6.1. Incoming connections . . . . . . . . . . . . . . . . 71
- 5.6.2. Events . . . . . . . . . . . . . . . . . . . . . . . 72
- 5.6.3. Actions . . . . . . . . . . . . . . . . . . . . . . . 73
- 5.6.4. The Election Process . . . . . . . . . . . . . . . . 75
- 6. Diameter message processing . . . . . . . . . . . . . . . . . 76
- 6.1. Diameter Request Routing Overview . . . . . . . . . . . . 76
- 6.1.1. Originating a Request . . . . . . . . . . . . . . . . 77
- 6.1.2. Sending a Request . . . . . . . . . . . . . . . . . . 77
- 6.1.3. Receiving Requests . . . . . . . . . . . . . . . . . 78
- 6.1.4. Processing Local Requests . . . . . . . . . . . . . . 78
- 6.1.5. Request Forwarding . . . . . . . . . . . . . . . . . 78
- 6.1.6. Request Routing . . . . . . . . . . . . . . . . . . . 78
- 6.1.7. Predictive Loop Avoidance . . . . . . . . . . . . . . 79
- 6.1.8. Redirecting Requests . . . . . . . . . . . . . . . . 79
- 6.1.9. Relaying and Proxying Requests . . . . . . . . . . . 80
- 6.2. Diameter Answer Processing . . . . . . . . . . . . . . . 82
- 6.2.1. Processing received Answers . . . . . . . . . . . . . 82
- 6.2.2. Relaying and Proxying Answers . . . . . . . . . . . . 82
- 6.3. Origin-Host AVP . . . . . . . . . . . . . . . . . . . . . 83
- 6.4. Origin-Realm AVP . . . . . . . . . . . . . . . . . . . . 83
- 6.5. Destination-Host AVP . . . . . . . . . . . . . . . . . . 83
- 6.6. Destination-Realm AVP . . . . . . . . . . . . . . . . . . 84
- 6.7. Routing AVPs . . . . . . . . . . . . . . . . . . . . . . 84
- 6.7.1. Route-Record AVP . . . . . . . . . . . . . . . . . . 84
- 6.7.2. Proxy-Info AVP . . . . . . . . . . . . . . . . . . . 84
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 3]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
- 6.7.3. Proxy-Host AVP . . . . . . . . . . . . . . . . . . . 85
- 6.7.4. Proxy-State AVP . . . . . . . . . . . . . . . . . . . 85
- 6.8. Auth-Application-Id AVP . . . . . . . . . . . . . . . . . 85
- 6.9. Acct-Application-Id AVP . . . . . . . . . . . . . . . . . 85
- 6.10. Inband-Security-Id AVP . . . . . . . . . . . . . . . . . 85
- 6.11. Vendor-Specific-Application-Id AVP . . . . . . . . . . . 86
- 6.12. Redirect-Host AVP . . . . . . . . . . . . . . . . . . . . 87
- 6.13. Redirect-Host-Usage AVP . . . . . . . . . . . . . . . . . 87
- 6.14. Redirect-Max-Cache-Time AVP . . . . . . . . . . . . . . . 88
- 7. Error Handling . . . . . . . . . . . . . . . . . . . . . . . 90
- 7.1. Result-Code AVP . . . . . . . . . . . . . . . . . . . . . 92
- 7.1.1. Informational . . . . . . . . . . . . . . . . . . . . 92
- 7.1.2. Success . . . . . . . . . . . . . . . . . . . . . . . 93
- 7.1.3. Protocol Errors . . . . . . . . . . . . . . . . . . . 93
- 7.1.4. Transient Failures . . . . . . . . . . . . . . . . . 94
- 7.1.5. Permanent Failures . . . . . . . . . . . . . . . . . 95
- 7.2. Error Bit . . . . . . . . . . . . . . . . . . . . . . . . 98
- 7.3. Error-Message AVP . . . . . . . . . . . . . . . . . . . . 99
- 7.4. Error-Reporting-Host AVP . . . . . . . . . . . . . . . . 99
- 7.5. Failed-AVP AVP . . . . . . . . . . . . . . . . . . . . . 99
- 7.6. Experimental-Result AVP . . . . . . . . . . . . . . . . . 100
- 7.7. Experimental-Result-Code AVP . . . . . . . . . . . . . . 100
- 8. Diameter User Sessions . . . . . . . . . . . . . . . . . . . 101
- 8.1. Authorization Session State Machine . . . . . . . . . . . 102
- 8.2. Accounting Session State Machine . . . . . . . . . . . . 107
- 8.3. Server-Initiated Re-Auth . . . . . . . . . . . . . . . . 112
- 8.3.1. Re-Auth-Request . . . . . . . . . . . . . . . . . . . 112
- 8.3.2. Re-Auth-Answer . . . . . . . . . . . . . . . . . . . 113
- 8.4. Session Termination . . . . . . . . . . . . . . . . . . . 114
- 8.4.1. Session-Termination-Request . . . . . . . . . . . . . 115
- 8.4.2. Session-Termination-Answer . . . . . . . . . . . . . 115
- 8.5. Aborting a Session . . . . . . . . . . . . . . . . . . . 116
- 8.5.1. Abort-Session-Request . . . . . . . . . . . . . . . . 116
- 8.5.2. Abort-Session-Answer . . . . . . . . . . . . . . . . 117
- 8.6. Inferring Session Termination from Origin-State-Id . . . 118
- 8.7. Auth-Request-Type AVP . . . . . . . . . . . . . . . . . . 118
- 8.8. Session-Id AVP . . . . . . . . . . . . . . . . . . . . . 119
- 8.9. Authorization-Lifetime AVP . . . . . . . . . . . . . . . 120
- 8.10. Auth-Grace-Period AVP . . . . . . . . . . . . . . . . . . 121
- 8.11. Auth-Session-State AVP . . . . . . . . . . . . . . . . . 121
- 8.12. Re-Auth-Request-Type AVP . . . . . . . . . . . . . . . . 121
- 8.13. Session-Timeout AVP . . . . . . . . . . . . . . . . . . . 122
- 8.14. User-Name AVP . . . . . . . . . . . . . . . . . . . . . . 122
- 8.15. Termination-Cause AVP . . . . . . . . . . . . . . . . . . 122
- 8.16. Origin-State-Id AVP . . . . . . . . . . . . . . . . . . . 124
- 8.17. Session-Binding AVP . . . . . . . . . . . . . . . . . . . 124
- 8.18. Session-Server-Failover AVP . . . . . . . . . . . . . . . 125
- 8.19. Multi-Round-Time-Out AVP . . . . . . . . . . . . . . . . 126
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 4]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
- 8.20. Class AVP . . . . . . . . . . . . . . . . . . . . . . . . 126
- 8.21. Event-Timestamp AVP . . . . . . . . . . . . . . . . . . . 126
- 9. Accounting . . . . . . . . . . . . . . . . . . . . . . . . . 127
- 9.1. Server Directed Model . . . . . . . . . . . . . . . . . . 127
- 9.2. Protocol Messages . . . . . . . . . . . . . . . . . . . . 128
- 9.3. Accounting Application Extension and Requirements . . . . 128
- 9.4. Fault Resilience . . . . . . . . . . . . . . . . . . . . 129
- 9.5. Accounting Records . . . . . . . . . . . . . . . . . . . 129
- 9.6. Correlation of Accounting Records . . . . . . . . . . . . 130
- 9.7. Accounting Command-Codes . . . . . . . . . . . . . . . . 131
- 9.7.1. Accounting-Request . . . . . . . . . . . . . . . . . 131
- 9.7.2. Accounting-Answer . . . . . . . . . . . . . . . . . . 132
- 9.8. Accounting AVPs . . . . . . . . . . . . . . . . . . . . . 133
- 9.8.1. Accounting-Record-Type AVP . . . . . . . . . . . . . 133
- 9.8.2. Acct-Interim-Interval AVP . . . . . . . . . . . . . . 134
- 9.8.3. Accounting-Record-Number AVP . . . . . . . . . . . . 135
- 9.8.4. Acct-Session-Id AVP . . . . . . . . . . . . . . . . . 135
- 9.8.5. Acct-Multi-Session-Id AVP . . . . . . . . . . . . . . 135
- 9.8.6. Accounting-Sub-Session-Id AVP . . . . . . . . . . . . 135
- 9.8.7. Accounting-Realtime-Required AVP . . . . . . . . . . 136
- 10. AVP Occurrence Table . . . . . . . . . . . . . . . . . . . . 137
- 10.1. Base Protocol Command AVP Table . . . . . . . . . . . . . 137
- 10.2. Accounting AVP Table . . . . . . . . . . . . . . . . . . 138
- 11. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 140
- 11.1. Changes to AVP Header Allocation . . . . . . . . . . . . 140
- 11.2. Diameter Header . . . . . . . . . . . . . . . . . . . . . 140
- 11.3. AVP Values . . . . . . . . . . . . . . . . . . . . . . . 140
- 11.3.1. Experimental-Result-Code AVP . . . . . . . . . . . . 140
- 11.4. Diameter TCP, SCTP, TLS/TCP and DTLS/SCTP Port Numbers . 141
- 11.5. S-NAPTR Parameters . . . . . . . . . . . . . . . . . . . 141
- 12. Diameter protocol related configurable parameters . . . . . . 142
- 13. Security Considerations . . . . . . . . . . . . . . . . . . . 143
- 13.1. TLS/TCP and DTLS/SCTP Usage . . . . . . . . . . . . . . . 143
- 13.2. Peer-to-Peer Considerations . . . . . . . . . . . . . . . 144
- 14. References . . . . . . . . . . . . . . . . . . . . . . . . . 145
- 14.1. Normative References . . . . . . . . . . . . . . . . . . 145
- 14.2. Informational References . . . . . . . . . . . . . . . . 147
- Appendix A. Acknowledgements . . . . . . . . . . . . . . . . . . 149
- A.1. RFC3588bis . . . . . . . . . . . . . . . . . . . . . . . 149
- A.2. RFC3588 . . . . . . . . . . . . . . . . . . . . . . . . . 150
- Appendix B. S-NAPTR Example . . . . . . . . . . . . . . . . . . 151
- Appendix C. Duplicate Detection . . . . . . . . . . . . . . . . 152
- Appendix D. Internationalized Domain Names . . . . . . . . . . . 154
- Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 155
-
-
-
-
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 5]
-
-Internet-Draft Diameter Base Protocol January 2011
+ 1. Introduction ....................................................7
+ 1.1. Diameter Protocol ..........................................9
+ 1.1.1. Description of the Document Set ....................10
+ 1.1.2. Conventions Used in This Document ..................11
+ 1.1.3. Changes from RFC 3588 ..............................11
+ 1.2. Terminology ...............................................12
+ 1.3. Approach to Extensibility .................................17
+ 1.3.1. Defining New AVP Values ............................18
+ 1.3.2. Creating New AVPs ..................................18
+ 1.3.3. Creating New Commands ..............................18
+ 1.3.4. Creating New Diameter Applications .................19
+ 2. Protocol Overview ..............................................20
+ 2.1. Transport .................................................22
+ 2.1.1. SCTP Guidelines ....................................23
+ 2.2. Securing Diameter Messages ................................24
+ 2.3. Diameter Application Compliance ...........................24
+ 2.4. Application Identifiers ...................................24
+ 2.5. Connections vs. Sessions ..................................25
+ 2.6. Peer Table ................................................26
+
+
+
+Fajardo, et al. Standards Track [Page 2]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
+ 2.7. Routing Table .............................................27
+ 2.8. Role of Diameter Agents ...................................28
+ 2.8.1. Relay Agents .......................................30
+ 2.8.2. Proxy Agents .......................................31
+ 2.8.3. Redirect Agents ....................................31
+ 2.8.4. Translation Agents .................................32
+ 2.9. Diameter Path Authorization ...............................33
+ 3. Diameter Header ................................................34
+ 3.1. Command Codes .............................................37
+ 3.2. Command Code Format Specification .........................38
+ 3.3. Diameter Command Naming Conventions .......................40
+ 4. Diameter AVPs ..................................................40
+ 4.1. AVP Header ................................................41
+ 4.1.1. Optional Header Elements ...........................42
+ 4.2. Basic AVP Data Formats ....................................43
+ 4.3. Derived AVP Data Formats ..................................44
+ 4.3.1. Common Derived AVP Data Formats ....................44
+ 4.4. Grouped AVP Values ........................................51
+ 4.4.1. Example AVP with a Grouped Data Type ...............52
+ 4.5. Diameter Base Protocol AVPs ...............................55
+ 5. Diameter Peers .................................................58
+ 5.1. Peer Connections ..........................................58
+ 5.2. Diameter Peer Discovery ...................................59
+ 5.3. Capabilities Exchange .....................................60
+ 5.3.1. Capabilities-Exchange-Request ......................62
+ 5.3.2. Capabilities-Exchange-Answer .......................63
+ 5.3.3. Vendor-Id AVP ......................................63
+ 5.3.4. Firmware-Revision AVP ..............................64
+ 5.3.5. Host-IP-Address AVP ................................64
+ 5.3.6. Supported-Vendor-Id AVP ............................64
+ 5.3.7. Product-Name AVP ...................................64
+ 5.4. Disconnecting Peer Connections ............................64
+ 5.4.1. Disconnect-Peer-Request ............................65
+ 5.4.2. Disconnect-Peer-Answer .............................65
+ 5.4.3. Disconnect-Cause AVP ...............................66
+ 5.5. Transport Failure Detection ...............................66
+ 5.5.1. Device-Watchdog-Request ............................67
+ 5.5.2. Device-Watchdog-Answer .............................67
+ 5.5.3. Transport Failure Algorithm ........................67
+ 5.5.4. Failover and Failback Procedures ...................67
+ 5.6. Peer State Machine ........................................68
+ 5.6.1. Incoming Connections ...............................71
+ 5.6.2. Events .............................................71
+ 5.6.3. Actions ............................................72
+ 5.6.4. The Election Process ...............................74
+
+
+
+
+
+
+Fajardo, et al. Standards Track [Page 3]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
+ 6. Diameter Message Processing ....................................74
+ 6.1. Diameter Request Routing Overview .........................74
+ 6.1.1. Originating a Request ..............................75
+ 6.1.2. Sending a Request ..................................76
+ 6.1.3. Receiving Requests .................................76
+ 6.1.4. Processing Local Requests ..........................76
+ 6.1.5. Request Forwarding .................................77
+ 6.1.6. Request Routing ....................................77
+ 6.1.7. Predictive Loop Avoidance ..........................77
+ 6.1.8. Redirecting Requests ...............................78
+ 6.1.9. Relaying and Proxying Requests .....................79
+ 6.2. Diameter Answer Processing ................................80
+ 6.2.1. Processing Received Answers ........................81
+ 6.2.2. Relaying and Proxying Answers ......................81
+ 6.3. Origin-Host AVP ...........................................81
+ 6.4. Origin-Realm AVP ..........................................82
+ 6.5. Destination-Host AVP ......................................82
+ 6.6. Destination-Realm AVP .....................................82
+ 6.7. Routing AVPs ..............................................83
+ 6.7.1. Route-Record AVP ...................................83
+ 6.7.2. Proxy-Info AVP .....................................83
+ 6.7.3. Proxy-Host AVP .....................................83
+ 6.7.4. Proxy-State AVP ....................................83
+ 6.8. Auth-Application-Id AVP ...................................83
+ 6.9. Acct-Application-Id AVP ...................................84
+ 6.10. Inband-Security-Id AVP ...................................84
+ 6.11. Vendor-Specific-Application-Id AVP .......................84
+ 6.12. Redirect-Host AVP ........................................85
+ 6.13. Redirect-Host-Usage AVP ..................................85
+ 6.14. Redirect-Max-Cache-Time AVP ..............................87
+ 7. Error Handling .................................................87
+ 7.1. Result-Code AVP ...........................................89
+ 7.1.1. Informational ......................................90
+ 7.1.2. Success ............................................90
+ 7.1.3. Protocol Errors ....................................90
+ 7.1.4. Transient Failures .................................92
+ 7.1.5. Permanent Failures .................................92
+ 7.2. Error Bit .................................................95
+ 7.3. Error-Message AVP .........................................96
+ 7.4. Error-Reporting-Host AVP ..................................96
+ 7.5. Failed-AVP AVP ............................................96
+ 7.6. Experimental-Result AVP ...................................97
+ 7.7. Experimental-Result-Code AVP ..............................97
+ 8. Diameter User Sessions .........................................98
+ 8.1. Authorization Session State Machine .......................99
+ 8.2. Accounting Session State Machine .........................104
+
+
+
+
+
+Fajardo, et al. Standards Track [Page 4]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
+ 8.3. Server-Initiated Re-Auth .................................110
+ 8.3.1. Re-Auth-Request ...................................110
+ 8.3.2. Re-Auth-Answer ....................................110
+ 8.4. Session Termination ......................................111
+ 8.4.1. Session-Termination-Request .......................112
+ 8.4.2. Session-Termination-Answer ........................113
+ 8.5. Aborting a Session .......................................113
+ 8.5.1. Abort-Session-Request .............................114
+ 8.5.2. Abort-Session-Answer ..............................114
+ 8.6. Inferring Session Termination from Origin-State-Id .......115
+ 8.7. Auth-Request-Type AVP ....................................116
+ 8.8. Session-Id AVP ...........................................116
+ 8.9. Authorization-Lifetime AVP ...............................117
+ 8.10. Auth-Grace-Period AVP ...................................118
+ 8.11. Auth-Session-State AVP ..................................118
+ 8.12. Re-Auth-Request-Type AVP ................................118
+ 8.13. Session-Timeout AVP .....................................119
+ 8.14. User-Name AVP ...........................................119
+ 8.15. Termination-Cause AVP ...................................120
+ 8.16. Origin-State-Id AVP .....................................120
+ 8.17. Session-Binding AVP .....................................120
+ 8.18. Session-Server-Failover AVP .............................121
+ 8.19. Multi-Round-Time-Out AVP ................................122
+ 8.20. Class AVP ...............................................122
+ 8.21. Event-Timestamp AVP .....................................122
+ 9. Accounting ....................................................123
+ 9.1. Server Directed Model ....................................123
+ 9.2. Protocol Messages ........................................124
+ 9.3. Accounting Application Extension and Requirements ........124
+ 9.4. Fault Resilience .........................................125
+ 9.5. Accounting Records .......................................125
+ 9.6. Correlation of Accounting Records ........................126
+ 9.7. Accounting Command Codes .................................127
+ 9.7.1. Accounting-Request ................................127
+ 9.7.2. Accounting-Answer .................................128
+ 9.8. Accounting AVPs ..........................................129
+ 9.8.1. Accounting-Record-Type AVP ........................129
+ 9.8.2. Acct-Interim-Interval AVP .........................130
+ 9.8.3. Accounting-Record-Number AVP ......................131
+ 9.8.4. Acct-Session-Id AVP ...............................131
+ 9.8.5. Acct-Multi-Session-Id AVP .........................131
+ 9.8.6. Accounting-Sub-Session-Id AVP .....................131
+ 9.8.7. Accounting-Realtime-Required AVP ..................132
+ 10. AVP Occurrence Tables ........................................132
+ 10.1. Base Protocol Command AVP Table .........................133
+ 10.2. Accounting AVP Table ....................................134
+
+
+
+
+
+Fajardo, et al. Standards Track [Page 5]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
+ 11. IANA Considerations ..........................................135
+ 11.1. AVP Header ..............................................135
+ 11.1.1. AVP Codes ........................................136
+ 11.1.2. AVP Flags ........................................136
+ 11.2. Diameter Header .........................................136
+ 11.2.1. Command Codes ....................................136
+ 11.2.2. Command Flags ....................................137
+ 11.3. AVP Values ..............................................137
+ 11.3.1. Experimental-Result-Code AVP .....................137
+ 11.3.2. Result-Code AVP Values ...........................137
+ 11.3.3. Accounting-Record-Type AVP Values ................137
+ 11.3.4. Termination-Cause AVP Values .....................137
+ 11.3.5. Redirect-Host-Usage AVP Values ...................137
+ 11.3.6. Session-Server-Failover AVP Values ...............137
+ 11.3.7. Session-Binding AVP Values .......................137
+ 11.3.8. Disconnect-Cause AVP Values ......................138
+ 11.3.9. Auth-Request-Type AVP Values .....................138
+ 11.3.10. Auth-Session-State AVP Values ...................138
+ 11.3.11. Re-Auth-Request-Type AVP Values .................138
+ 11.3.12. Accounting-Realtime-Required AVP Values .........138
+ 11.3.13. Inband-Security-Id AVP (code 299) ...............138
+ 11.4. _diameters Service Name and Port Number Registration ....138
+ 11.5. SCTP Payload Protocol Identifiers .......................139
+ 11.6. S-NAPTR Parameters ......................................139
+ 12. Diameter Protocol-Related Configurable Parameters ............139
+ 13. Security Considerations ......................................140
+ 13.1. TLS/TCP and DTLS/SCTP Usage .............................140
+ 13.2. Peer-to-Peer Considerations .............................141
+ 13.3. AVP Considerations ......................................141
+ 14. References ...................................................142
+ 14.1. Normative References ....................................142
+ 14.2. Informative References ..................................144
+ Appendix A. Acknowledgements .....................................147
+ A.1. This Document .............................................147
+ A.2. RFC 3588 ..................................................148
+ Appendix B. S-NAPTR Example ......................................148
+ Appendix C. Duplicate Detection ..................................149
+ Appendix D. Internationalized Domain Names .......................151
+
+
+
+
+
+
+
+
+
+
+
+
+
+Fajardo, et al. Standards Track [Page 6]
+
+RFC 6733 Diameter Base Protocol October 2012
1. Introduction
- Authentication, Authorization and Accounting (AAA) protocols such as
+ Authentication, Authorization, and Accounting (AAA) protocols such as
TACACS [RFC1492] and RADIUS [RFC2865] were initially deployed to
provide dial-up PPP [RFC1661] and terminal server access. Over time,
AAA support was needed on many new access technologies, the scale and
complexity of AAA networks grew, and AAA was also used on new
- applications (such as voice over IP). This lead to new demands on
- AAA protocols.
+ applications (such as voice over IP). This led to new demands on AAA
+ protocols.
Network access requirements for AAA protocols are summarized in
- [RFC2989]. These include:
-
+ Aboba, et al. [RFC2989]. These include:
Failover
- [RFC2865] does not define failover mechanisms, and as a result,
+ [RFC2865] does not define failover mechanisms and, as a result,
failover behavior differs between implementations. In order to
provide well-defined failover behavior, Diameter supports
- application-layer acknowledgements, and defines failover
- algorithms and the associated state machine. This is described in
- Section 5.5 and [RFC3539].
+ application-layer acknowledgements and defines failover algorithms
+ and the associated state machine.
Transmission-level security
- [RFC2865] defines an application-layer authentication and
- integrity scheme that is required only for use with Response
+ RADIUS [RFC2865] defines an application-layer authentication and
+ integrity scheme that is required only for use with response
packets. While [RFC2869] defines an additional authentication and
integrity mechanism, use is only required during Extensible
- Authentication Protocol (EAP) sessions. While attribute-hiding is
- supported, [RFC2865] does not provide support for per-packet
- confidentiality. In accounting, [RFC2866] assumes that replay
- protection is provided by the backend billing server, rather than
- within the protocol itself.
+ Authentication Protocol (EAP) [RFC3748] sessions. While attribute
+ hiding is supported, [RFC2865] does not provide support for per-
+ packet confidentiality. In accounting, [RFC2866] assumes that
+ replay protection is provided by the backend billing server rather
+ than within the protocol itself.
While [RFC3162] defines the use of IPsec with RADIUS, support for
IPsec is not required. In order to provide universal support for
@@ -322,50 +379,48 @@ Internet-Draft Diameter Base Protocol January 2011
domain AAA deployments, Diameter provides support for TLS/TCP and
DTLS/SCTP. Security is discussed in Section 13.
-
Reliable transport
-
RADIUS runs over UDP, and does not define retransmission behavior;
as a result, reliability varies between implementations. As
described in [RFC2975], this is a major issue in accounting, where
+ packet loss may translate directly into revenue loss. In order to
-Fajardo, et al. Expires July 24, 2011 [Page 6]
-
-Internet-Draft Diameter Base Protocol January 2011
- packet loss may translate directly into revenue loss. In order to
- provide well defined transport behavior, Diameter runs over
- reliable transport mechanisms (TCP, SCTP) as defined in [RFC3539].
+Fajardo, et al. Standards Track [Page 7]
+
+RFC 6733 Diameter Base Protocol October 2012
- Agent support
- [RFC2865] does not provide for explicit support for agents,
- including Proxies, Redirects and Relays. Since the expected
- behavior is not defined, it varies between implementations.
- Diameter defines agent behavior explicitly; this is described in
- Section 2.8.
+ provide well-defined transport behavior, Diameter runs over
+ reliable transport mechanisms (TCP, Stream Control Transmission
+ Protocol (SCTP)) as defined in [RFC3539].
+
+ Agent support
+ RADIUS does not provide for explicit support for agents, including
+ proxies, redirects, and relays. Since the expected behavior is
+ not defined, it varies between implementations. Diameter defines
+ agent behavior explicitly; this is described in Section 2.8.
Server-initiated messages
- While RADIUS server-initiated messages are defined in [RFC5176],
+ While server-initiated messages are defined in RADIUS [RFC5176],
support is optional. This makes it difficult to implement
features such as unsolicited disconnect or re-authentication/
re-authorization on demand across a heterogeneous deployment. To
- tackle this issue, support for server-initiated messages is
+ address this issue, support for server-initiated messages is
mandatory in Diameter.
-
Transition support
While Diameter does not share a common protocol data unit (PDU)
with RADIUS, considerable effort has been expended in enabling
- backward compatibility with RADIUS, so that the two protocols may
+ backward compatibility with RADIUS so that the two protocols may
be deployed in the same network. Initially, it is expected that
Diameter will be deployed within new network devices, as well as
within gateways enabling communication between legacy RADIUS
@@ -373,9 +428,8 @@ Internet-Draft Diameter Base Protocol January 2011
support to be added to legacy networks, by addition of a gateway
or server speaking both RADIUS and Diameter.
- In addition to addressing the above requirements, Diameter also
- provides support for the following:
-
+ In addition to addressing the above requirements, Diameter also
+ provides support for the following:
Capability negotiation
@@ -383,19 +437,19 @@ Internet-Draft Diameter Base Protocol January 2011
a mandatory/non-mandatory flag for attributes. Since RADIUS
clients and servers are not aware of each other's capabilities,
they may not be able to successfully negotiate a mutually
- acceptable service, or in some cases, even be aware of what
+ acceptable service or, in some cases, even be aware of what
service has been implemented. Diameter includes support for error
+ handling (Section 7), capability negotiation (Section 5.3), and
+ mandatory/non-mandatory Attribute-Value Pairs (AVPs)
+ (Section 4.1).
-Fajardo, et al. Expires July 24, 2011 [Page 7]
-
-Internet-Draft Diameter Base Protocol January 2011
- handling (Section 7), capability negotiation (Section 5.3), and
- mandatory/non-mandatory Attribute-Value Pairs (AVPs) (Section
- 4.1).
+Fajardo, et al. Standards Track [Page 8]
+
+RFC 6733 Diameter Base Protocol October 2012
Peer discovery and configuration
@@ -403,7 +457,7 @@ Internet-Draft Diameter Base Protocol January 2011
RADIUS implementations typically require that the name or address
of servers or clients be manually configured, along with the
corresponding shared secrets. This results in a large
- administrative burden, and creates the temptation to reuse the
+ administrative burden and creates the temptation to reuse the
RADIUS shared secret, which can result in major security
vulnerabilities if the Request Authenticator is not globally and
temporally unique as required in [RFC2865]. Through DNS, Diameter
@@ -411,7 +465,6 @@ Internet-Draft Diameter Base Protocol January 2011
of dynamic session keys is enabled via transmission-level
security.
-
Over time, the capabilities of Network Access Server (NAS) devices
have increased substantially. As a result, while Diameter is a
considerably more sophisticated protocol than RADIUS, it remains
@@ -427,42 +480,41 @@ Internet-Draft Diameter Base Protocol January 2011
o Error notification
- o Extensibility, through addition of new applications, commands and
- AVPs (required in [RFC2989]).
+ o Extensibility, required in [RFC2989], through addition of new
+ applications, commands, and AVPs
- o Basic services necessary for applications, such as handling of
+ o Basic services necessary for applications, such as the handling of
user sessions or accounting
All data delivered by the protocol is in the form of AVPs. Some of
these AVP values are used by the Diameter protocol itself, while
others deliver data associated with particular applications that
employ Diameter. AVPs may be arbitrarily added to Diameter messages,
- the only restriction being that the Augmented Backus-Naur Form (ABNF,
- [RFC5234]) Command Code syntax specification (Section 3.2) is
- satisfied. AVPs are used by the base Diameter protocol to support
- the following required features:
+ the only restriction being that the Command Code Format (CCF)
+ specification (Section 3.2) be satisfied. AVPs are used by the base
+ Diameter protocol to support the following required features:
+ o Transporting of user authentication information, for the purposes
+ of enabling the Diameter server to authenticate the user
+ o Transporting of service-specific authorization information,
+ between client and servers, allowing the peers to decide whether a
+ user's access request should be granted
-Fajardo, et al. Expires July 24, 2011 [Page 8]
-
-Internet-Draft Diameter Base Protocol January 2011
- o Transporting of user authentication information, for the purposes
- of enabling the Diameter server to authenticate the user.
+Fajardo, et al. Standards Track [Page 9]
+
+RFC 6733 Diameter Base Protocol October 2012
- o Transporting of service-specific authorization information,
- between client and servers, allowing the peers to decide whether a
- user's access request should be granted.
o Exchanging resource usage information, which may be used for
accounting purposes, capacity planning, etc.
- o Routing, relaying, proxying and redirecting of Diameter messages
- through a server hierarchy.
+ o Routing, relaying, proxying, and redirecting of Diameter messages
+ through a server hierarchy
- The Diameter base protocol satisfies the minimum requirements for an
+ The Diameter base protocol satisfies the minimum requirements for a
AAA protocol, as specified by [RFC2989]. The base protocol may be
used by itself for accounting purposes only, or it may be used with a
Diameter application, such as Mobile IPv4 [RFC4004], or network
@@ -473,16 +525,16 @@ Internet-Draft Diameter Base Protocol January 2011
many applications might provide functionality not provided by
Diameter. Therefore, it is imperative that the designers of new
applications understand their requirements before using Diameter.
- See Section 2.4 for more information on Diameter applications.
+ See Section 1.3.4 for more information on Diameter applications.
Any node can initiate a request. In that sense, Diameter is a peer-
- to-peer protocol. In this document, a Diameter Client is a device at
+ to-peer protocol. In this document, a Diameter client is a device at
the edge of the network that performs access control, such as a
Network Access Server (NAS) or a Foreign Agent (FA). A Diameter
client generates Diameter messages to request authentication,
authorization, and accounting services for the user. A Diameter
agent is a node that does not provide local user authentication or
- authorization services; agents include proxies, redirects and relay
+ authorization services; agents include proxies, redirects, and relay
agents. A Diameter server performs authentication and/or
authorization of the user. A Diameter node may act as an agent for
certain requests while acting as a server for others.
@@ -494,33 +546,33 @@ Internet-Draft Diameter Base Protocol January 2011
The Diameter specification consists of an updated version of the base
protocol specification (this document) and the Transport Profile
- [RFC3539]. This document obsoletes RFC 3588. A summary of the base
- protocol updates included in this document can be found in
- Section 1.1.3.
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 9]
-
-Internet-Draft Diameter Base Protocol January 2011
-
+ [RFC3539]. This document obsoletes both RFC 3588 and RFC 5719. A
+ summary of the base protocol updates included in this document can be
+ found in Section 1.1.3.
This document defines the base protocol specification for AAA, which
includes support for accounting. There are also a myriad of
applications documents describing applications that use this base
- specification for Authentication, Authorization and Accounting.
+ specification for Authentication, Authorization, and Accounting.
These application documents specify how to use the Diameter protocol
within the context of their application.
+
+
+Fajardo, et al. Standards Track [Page 10]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
The Transport Profile document [RFC3539] discusses transport layer
issues that arise with AAA protocols and recommendations on how to
overcome these issues. This document also defines the Diameter
failover algorithm and state machine.
- Clarifications on the Routing of Diameter Request based on Username
- and the Realm [RFC5729] defines specific behavior on how to route
- request based on the content of the User-Name AVP (Attribute Value
- Pair).
+ "Clarifications on the Routing of Diameter Request Based on the
+ Username and the Realm" [RFC5729] defines specific behavior on how to
+ route requests based on the content of the User-Name AVP (Attribute
+ Value Pair).
1.1.2. Conventions Used in This Document
@@ -528,100 +580,100 @@ Internet-Draft Diameter Base Protocol January 2011
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
document are to be interpreted as described in [RFC2119].
-1.1.3. Changes from RFC3588
+1.1.3. Changes from RFC 3588
This document obsoletes RFC 3588 but is fully backward compatible
with that document. The changes introduced in this document focus on
- fixing issues that have surfaced during implementation of [RFC3588].
- An overview of some the major changes are given below.
-
- o Deprecated the use of Inband-Security AVP for negotiating
- transport layer security. It has been generally considered that
- bootstrapping of TLS via Inband-Security AVP creates certain
- security risk because it does not completely protect the
- information carried in the CER (Capabilities Exchange Request)/CEA
- (Capabilities Exchange Answer). This version of Diameter adopted
- a common approach of defining a well-known secured port that peers
- should use when communicating via TLS/TCP and DTLS/SCTP. This new
- approach augments the existing Inband-Security negotiation but
- does not completely replace it. The old method is kept for
- backwards compatibility reasons.
+ fixing issues that have surfaced during the implementation of
+ Diameter (RFC 3588). An overview of some the major changes are given
+ below.
+
+ o Deprecated the use of the Inband-Security AVP for negotiating
+ Transport Layer Security (TLS) [RFC5246]. It has been generally
+ considered that bootstrapping of TLS via Inband-Security AVP
+ creates certain security risks because it does not completely
+ protect the information carried in the CER/CEA (Capabilities-
+ Exchange-Request/Capabilities-Exchange-Answer). This version of
+ Diameter adopts the common approach of defining a well-known
+ secured port that peers should use when communicating via TLS/TCP
+ and DTLS/SCTP. This new approach augments the existing in-band
+ security negotiation, but it does not completely replace it. The
+ old method is kept for backward compatibility reasons.
o Deprecated the exchange of CER/CEA messages in the open state.
- This feature was implied in the peer state machine table of
- [RFC3588] but it was not clearly defined anywhere else in that
+ This feature was implied in the peer state machine table of RFC
+ 3588, but it was not clearly defined anywhere else in that
document. As work on this document progressed, it became clear
- that the multiplicity of meaning and use of Application Id AVPs in
+ that the multiplicity of meaning and use of Application-Id AVPs in
the CER/CEA messages (and the messages themselves) is seen as an
+ abuse of the Diameter extensibility rules and thus required
+ simplification. Capabilities exchange in the open state has been
+ re-introduced in a separate specification [RFC6737], which clearly
+ defines new commands for this feature.
-Fajardo, et al. Expires July 24, 2011 [Page 10]
-
-Internet-Draft Diameter Base Protocol January 2011
- abuse of the Diameter extensibility rules and thus required
- simplification. It is assumed that the capabilities exchange in
- the open state will be re-introduced in a separate specification
- which clearly defines new commands for this feature.
+Fajardo, et al. Standards Track [Page 11]
+
+RFC 6733 Diameter Base Protocol October 2012
+
- o Simplified Security Requirements. The use of a secured transport
+ o Simplified security requirements. The use of a secured transport
for exchanging Diameter messages remains mandatory. However, TLS/
- TCP and DTLS/SCTP has become the primary method of securing
- Diameter and IPsec is a secondary alternative. See Section 13 for
- details. The support for the End-to-End security framework
- (E2ESequence AVP and 'P'-bit in the AVP header) has also been
+ TCP and DTLS/SCTP have become the primary methods of securing
+ Diameter with IPsec as a secondary alternative. See Section 13
+ for details. The support for the End-to-End security framework
+ (E2E-Sequence AVP and 'P'-bit in the AVP header) has also been
deprecated.
- o Diameter Extensibility Changes. This includes fixes to the
+ o Changed Diameter extensibility. This includes fixes to the
Diameter extensibility description (Section 1.3 and others) to
better aid Diameter application designers; in addition, the new
specification relaxes the policy with respect to the allocation of
- command codes for vendor-specific uses.
-
- o Application Id Usage. Clarify the proper use of Application Id
- information which can be found in multiple places within a
- Diameter message. This includes correlating Application Ids found
- in the message headers and AVPs. These changes also clearly
- specify the proper Application Id value to use for specific base
- protocol messages (ASR/ASA, STR/STA) as well as clarifying the
- content and use of Vendor-Specific-Application-Id.
-
- o Routing Fixes. This document more clearly specifies what
- information (AVPs and Application Id) can be used for making
+ Command Codes for vendor-specific uses.
+
+ o Clarified Application Id usage. Clarify the proper use of
+ Application Id information, which can be found in multiple places
+ within a Diameter message. This includes correlating Application
+ Ids found in the message headers and AVPs. These changes also
+ clearly specify the proper Application Id value to use for
+ specific base protocol messages (ASR/ASA, STR/STA) as well as
+ clarify the content and use of Vendor-Specific-Application-Id.
+
+ o Clarified routing fixes. This document more clearly specifies
+ what information (AVPs and Application Ids) can be used for making
general routing decisions. A rule for the prioritization of
redirect routing criteria when multiple route entries are found
- via redirects has also been added (See Section 6.13 for details).
+ via redirects has also been added (see Section 6.13).
- o Simplification of Diameter Peer Discovery. The Diameter discovery
+ o Simplified Diameter peer discovery. The Diameter discovery
process now supports only widely used discovery schemes; the rest
have been deprecated (see Section 5.2 for details).
- There are many other many miscellaneous fixes that have been
- introduced in this document that may not be considered significant
- but they are important nonetheless. Examples are removal of obsolete
- types, fixes to command ABNFs, fixes to the state machine,
- clarification of the election process, message validation, fixes to
- Failed-AVP and Result-Code AVP values, etc. A comprehensive list of
- changes is not shown here for practical reasons.
-
-
-
+ There are many other miscellaneous fixes that have been introduced in
+ this document that may not be considered significant, but they have
+ value nonetheless. Examples are removal of obsolete types, fixes to
+ the state machine, clarification of the election process, message
+ validation, fixes to Failed-AVP and Result-Code AVP values, etc. All
+ of the errata filed against RFC 3588 prior to the publication of this
+ document have been addressed. A comprehensive list of changes is not
+ shown here for practical reasons.
+1.2. Terminology
+ AAA
+ Authentication, Authorization, and Accounting.
-Fajardo, et al. Expires July 24, 2011 [Page 11]
-
-Internet-Draft Diameter Base Protocol January 2011
-1.2. Terminology
- AAA
- Authentication, Authorization and Accounting.
+Fajardo, et al. Standards Track [Page 12]
+
+RFC 6733 Diameter Base Protocol October 2012
ABNF
@@ -631,14 +683,12 @@ Internet-Draft Diameter Base Protocol January 2011
is used to define message exchanges in a bi-directional
communications protocol.
-
Accounting
The act of collecting information on resource usage for the
- purpose of capacity planning, auditing, billing or cost
+ purpose of capacity planning, auditing, billing, or cost
allocation.
-
Accounting Record
An accounting record represents a summary of the resource
@@ -647,114 +697,102 @@ Internet-Draft Diameter Base Protocol January 2011
accounting events or accounting events from several devices
serving the same user.
-
Authentication
The act of verifying the identity of an entity (subject).
-
Authorization
The act of determining whether a requesting entity (subject) will
be allowed access to a resource (object).
-
- AVP
+ Attribute-Value Pair (AVP)
The Diameter protocol consists of a header followed by one or more
Attribute-Value-Pairs (AVPs). An AVP includes a header and is
used to encapsulate protocol-specific data (e.g., routing
- information) as well as authentication, authorization or
+ information) as well as authentication, authorization, or
+ accounting information.
+ Command Code Format (CCF)
+ A modified form of ABNF used to define Diameter commands (see
+ Section 3.2).
-Fajardo, et al. Expires July 24, 2011 [Page 12]
-
-Internet-Draft Diameter Base Protocol January 2011
+ Diameter Agent
+ A Diameter Agent is a Diameter node that provides relay, proxy,
+ redirect, or translation services.
- accounting information.
- Diameter Agent
- A Diameter Agent is a Diameter Node that provides either relay,
- proxy, redirect or translation services.
+Fajardo, et al. Standards Track [Page 13]
+
+RFC 6733 Diameter Base Protocol October 2012
Diameter Client
- A Diameter Client is a Diameter Node that supports Diameter client
- applications as well as the base protocol. Diameter Clients are
+ A Diameter client is a Diameter node that supports Diameter client
+ applications as well as the base protocol. Diameter clients are
often implemented in devices situated at the edge of a network and
provide access control services for that network. Typical
- examples of Diameter Clients include the Network Access Server
+ examples of Diameter clients include the Network Access Server
(NAS) and the Mobile IP Foreign Agent (FA).
-
Diameter Node
- A Diameter Node is a host process that implements the Diameter
- protocol, and acts either as a Client, Agent or Server.
-
+ A Diameter node is a host process that implements the Diameter
+ protocol and acts as either a client, an agent, or a server.
Diameter Peer
- If a Diameter Node shares a direct transport connection with
- another Diameter Node, it is a Diameter Peer to that Diameter
- Node.
-
+ Two Diameter nodes sharing a direct TCP or SCTP transport
+ connection are called Diameter peers.
Diameter Server
- A Diameter Server is a Diameter Node that handles authentication,
- authorization and accounting requests for a particular realm. By
- its very nature, a Diameter Server must support Diameter server
+ A Diameter server is a Diameter node that handles authentication,
+ authorization, and accounting requests for a particular realm. By
+ its very nature, a Diameter server must support Diameter server
applications in addition to the base protocol.
-
Downstream
Downstream is used to identify the direction of a particular
- Diameter message from the Home Server towards the Diameter Client.
-
-
-
-
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 13]
-
-Internet-Draft Diameter Base Protocol January 2011
-
+ Diameter message from the home server towards the Diameter client.
Home Realm
A Home Realm is the administrative domain with which the user
maintains an account relationship.
-
Home Server
- A Diameter Server which serves the Home Realm.
-
+ A Diameter server that serves the Home Realm.
- Interim accounting
+ Interim Accounting
An interim accounting message provides a snapshot of usage during
- a user's session. It is typically implemented in order to provide
- for partial accounting of a user's session in the case a device
- reboot or other network problem prevents the delivery of a session
- summary message or session record.
+ a user's session. Typically, it is implemented in order to
+ provide for partial accounting of a user's session in case a
+ device reboot or other network problem prevents the delivery of a
+ session summary message or session record.
+
+
+
+
+Fajardo, et al. Standards Track [Page 14]
+
+RFC 6733 Diameter Base Protocol October 2012
Local Realm
A local realm is the administrative domain providing services to a
user. An administrative domain may act as a local realm for
- certain users, while being a home realm for others.
-
+ certain users while being a home realm for others.
Multi-session
@@ -764,60 +802,56 @@ Internet-Draft Diameter Base Protocol January 2011
leg of the bundle would be a session while the entire bundle would
be a multi-session.
-
Network Access Identifier
The Network Access Identifier, or NAI [RFC4282], is used in the
Diameter protocol to extract a user's identity and realm. The
identity is used to identify the user during authentication and/or
- authorization, while the realm is used for message routing
+ authorization while the realm is used for message routing
purposes.
-
-
-
-
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 14]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
Proxy Agent or Proxy
In addition to forwarding requests and responses, proxies make
policy decisions relating to resource usage and provisioning.
- This is typically accomplished by tracking the state of NAS
- devices. While proxies typically do not respond to client
- Requests prior to receiving a Response from the server, they may
- originate Reject messages in cases where policies are violated.
- As a result, proxies need to understand the semantics of the
- messages passing through them, and may not support all Diameter
+ Typically, this is accomplished by tracking the state of NAS
+ devices. While proxies usually do not respond to client requests
+ prior to receiving a response from the server, they may originate
+ Reject messages in cases where policies are violated. As a
+ result, proxies need to understand the semantics of the messages
+ passing through them, and they may not support all Diameter
applications.
-
Realm
The string in the NAI that immediately follows the '@' character.
- NAI realm names are required to be unique, and are piggybacked on
+ NAI realm names are required to be unique and are piggybacked on
the administration of the DNS namespace. Diameter makes use of
the realm, also loosely referred to as domain, to determine
- whether messages can be satisfied locally, or whether they must be
+ whether messages can be satisfied locally or whether they must be
routed or redirected. In RADIUS, realm names are not necessarily
piggybacked on the DNS namespace but may be independent of it.
- Real-time Accounting
+
+
+
+
+
+
+Fajardo, et al. Standards Track [Page 15]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
+ Real-Time Accounting
Real-time accounting involves the processing of information on
- resource usage within a defined time window. Time constraints are
- typically imposed in order to limit financial risk. The Diameter
- Credit Control Application [RFC4006] is an example of an
+ resource usage within a defined time window. Typically, time
+ constraints are imposed in order to limit financial risk. The
+ Diameter Credit-Control Application [RFC4006] is an example of an
application that defines real-time accounting functionality.
-
Relay Agent or Relay
Relays forward requests and responses based on routing-related
@@ -827,20 +861,9 @@ Internet-Draft Diameter Base Protocol January 2011
the semantics of messages or non-routing AVPs, and are capable of
handling any Diameter application or message type. Since relays
make decisions based on information in routing AVPs and realm
- forwarding tables they do not keep state on NAS resource usage or
+ forwarding tables, they do not keep state on NAS resource usage or
sessions in progress.
-
-
-
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 15]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
Redirect Agent
Rather than forwarding requests and responses between clients and
@@ -850,11 +873,10 @@ Internet-Draft Diameter Base Protocol January 2011
client and server. Redirect agents do not originate messages and
are capable of handling any message type, although they may be
configured only to redirect messages of certain types, while
- acting as relay or proxy agents for other types. As with proxy
+ acting as relay or proxy agents for other types. As with relay
agents, redirect agents do not keep state with respect to sessions
or NAS resources.
-
Session
A session is a related progression of events devoted to a
@@ -863,14 +885,19 @@ Internet-Draft Diameter Base Protocol January 2011
packets with the same Session-Id are considered to be part of the
same session.
-
Stateful Agent
A stateful agent is one that maintains session state information,
by keeping track of all authorized active sessions. Each
authorized session is bound to a particular service, and its state
- is considered active either until it is notified otherwise, or by
- expiration.
+ is considered active either until it is notified otherwise or
+ until expiration.
+
+
+
+Fajardo, et al. Standards Track [Page 16]
+
+RFC 6733 Diameter Base Protocol October 2012
Sub-session
@@ -881,53 +908,33 @@ Internet-Draft Diameter Base Protocol January 2011
during the same session) or serially. These changes in sessions
are tracked with the Accounting-Sub-Session-Id.
-
- Transaction state
+ Transaction State
The Diameter protocol requires that agents maintain transaction
state, which is used for failover purposes. Transaction state
- implies that upon forwarding a request, the Hop-by-Hop identifier
+ implies that upon forwarding a request, the Hop-by-Hop Identifier
is saved; the field is replaced with a locally unique identifier,
which is restored to its original value when the corresponding
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 16]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
answer is received. The request's state is released upon receipt
of the answer. A stateless agent is one that only maintains
transaction state.
-
Translation Agent
- A translation agent is a stateful Diameter node that performs
- protocol translation between Diameter and another AAA protocol,
- such as RADIUS.
-
-
- Transport Connection
-
- A transport connection is a TCP or SCTP connection existing
- directly between two Diameter peers, otherwise known as a Peer-to-
- Peer Connection.
-
+ A translation agent (TLA in Figure 4) is a stateful Diameter node
+ that performs protocol translation between Diameter and another
+ AAA protocol, such as RADIUS.
Upstream
Upstream is used to identify the direction of a particular
- Diameter message from the Diameter Client towards the Home Server.
-
+ Diameter message from the Diameter client towards the home server.
User
The entity or device requesting or using some resource, in support
of which a Diameter client has generated a request.
-
1.3. Approach to Extensibility
The Diameter protocol is designed to be extensible, using several
@@ -941,107 +948,108 @@ Internet-Draft Diameter Base Protocol January 2011
o Creating new applications
- From the point of view of extensibility Diameter authentication,
- authorization and accounting applications are treated in the same
- way.
-
-Fajardo, et al. Expires July 24, 2011 [Page 17]
+Fajardo, et al. Standards Track [Page 17]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
- Note: Protocol designers should try to re-use existing functionality,
+ From the point of view of extensibility, Diameter authentication,
+ authorization, and accounting applications are treated in the same
+ way.
+
+ Note: Protocol designers should try to reuse existing functionality,
namely AVP values, AVPs, commands, and Diameter applications. Reuse
simplifies standardization and implementation. To avoid potential
- interoperability issues it is important to ensure that the semantics
- of the re-used features are well understood. Given that Diameter can
- also carry RADIUS attributes as Diameter AVPs, such re-use
- considerations apply also to existing RADIUS attributes that may be
+ interoperability issues, it is important to ensure that the semantics
+ of the reused features are well understood. Given that Diameter can
+ also carry RADIUS attributes as Diameter AVPs, such reuse
+ considerations also apply to existing RADIUS attributes that may be
useful in a Diameter application.
-1.3.1. Defining New AVP Values
+1.3.1. Defining New AVP Values
In order to allocate a new AVP value for AVPs defined in the Diameter
- Base protocol, the IETF needs to approve a new RFC that describes the
+ base protocol, the IETF needs to approve a new RFC that describes the
AVP value. IANA considerations for these AVP values are discussed in
- Section 11.4.
+ Section 11.3.
The allocation of AVP values for other AVPs is guided by the IANA
considerations of the document that defines those AVPs. Typically,
- allocation of new values for an AVP defined in an IETF RFC should
- require IETF Review [RFC5226], whereas values for vendor-specific
- AVPs can be allocated by the vendor.
+ allocation of new values for an AVP defined in an RFC would require
+ IETF Review [RFC5226], whereas values for vendor-specific AVPs can be
+ allocated by the vendor.
-1.3.2. Creating New AVPs
+1.3.2. Creating New AVPs
A new AVP being defined MUST use one of the data types listed in
- Section 4.2 or Section 4.3. If an appropriate derived data type is
- already defined, it SHOULD be used instead of a base data type to
- encourage reusability and good design practice.
+ Sections 4.2 or 4.3. If an appropriate derived data type is already
+ defined, it SHOULD be used instead of a base data type to encourage
+ reusability and good design practice.
In the event that a logical grouping of AVPs is necessary, and
multiple "groups" are possible in a given command, it is recommended
that a Grouped AVP be used (see Section 4.4).
The creation of new AVPs can happen in various ways. The recommended
- approach is to define a new general-purpose AVP in a standards track
- RFC approved by the IETF. However, as described in Section 11.1.1
- there are also other mechanisms.
+ approach is to define a new general-purpose AVP in a Standards Track
+ RFC approved by the IETF. However, as described in Section 11.1.1,
+ there are other mechanisms.
-1.3.3. Creating New Commands
+1.3.3. Creating New Commands
A new Command Code MUST be allocated when required AVPs (those
- indicated as {AVP} in the ABNF definition) are added to, deleted from
+ indicated as {AVP} in the CCF definition) are added to, deleted from,
or redefined in (for example, by changing a required AVP into an
optional one) an existing command.
- Furthermore, if the transport characteristics of a command are
- changed (for example, with respect to the number of round trips
- required) a new Command Code MUST be registered.
-
-Fajardo, et al. Expires July 24, 2011 [Page 18]
+Fajardo, et al. Standards Track [Page 18]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
+
+ Furthermore, if the transport characteristics of a command are
+ changed (for example, with respect to the number of round trips
+ required), a new Command Code MUST be registered.
- A change to the ABNF of a command, such as described above, MUST
+ A change to the CCF of a command, such as described above, MUST
result in the definition of a new Command Code. This subsequently
- leads to the need to define a new Diameter Application for any
- application that will use that new Command.
-
- The IANA considerations for commands are discussed in Section 11.2.1.
-
-1.3.4. Creating New Diameter Applications
-
- Every Diameter application specification MUST have an IANA assigned
- Application Id (see Section 2.4 and Section 11.3). The managed
- Application Id space is flat and there is no relationship between
- different Diameter applications with respect to their Application
- Ids. As such, there is no versioning support provided by these
- application Ids itself; every Diameter application is a standalone
- application. If the application has a relationship with other
- Diameter applications, such a relationship is not known to Diameter.
-
- Before describing the rules for creating new Diameter applications it
- is important to discuss the semantics of the AVPs occurrences as
- stated in the ABNF and the M-bit flag (Section 4.1) for an AVP.
- There is no relationship imposed between the two; they are set
+ leads to the need to define a new Diameter application for any
+ application that will use that new command.
+
+ The IANA considerations for Command Codes are discussed in
+ Section 3.1.
+
+1.3.4. Creating New Diameter Applications
+
+ Every Diameter application specification MUST have an IANA-assigned
+ Application Id (see Section 2.4). The managed Application ID space
+ is flat, and there is no relationship between different Diameter
+ applications with respect to their Application Ids. As such, there
+ is no versioning support provided by these Application Ids
+ themselves; every Diameter application is a standalone application.
+ If the application has a relationship with other Diameter
+ applications, such a relationship is not known to Diameter.
+
+ Before describing the rules for creating new Diameter applications,
+ it is important to discuss the semantics of the AVP occurrences as
+ stated in the CCF and the M-bit flag (Section 4.1) for an AVP. There
+ is no relationship imposed between the two; they are set
independently.
- o The ABNF indicates what AVPs are placed into a Diameter Command by
- the sender of that Command. Often, since there are multiple modes
- of protocol interactions many of the AVPs are indicated as
+ o The CCF indicates what AVPs are placed into a Diameter command by
+ the sender of that command. Often, since there are multiple modes
+ of protocol interactions, many of the AVPs are indicated as
optional.
o The M-bit allows the sender to indicate to the receiver whether or
not understanding the semantics of an AVP and its content is
mandatory. If the M-bit is set by the sender and the receiver
- does not understand the AVP or the values carried within that AVP
+ does not understand the AVP or the values carried within that AVP,
then a failure is generated (see Section 7).
It is the decision of the protocol designer when to develop a new
@@ -1050,77 +1058,48 @@ Internet-Draft Diameter Base Protocol January 2011
of the following criteria are met:
- M-bit Setting
- An AVP with the M-bit in the MUST column of the AVP flag table is
- added to an existing Command/Application.
- An AVP with the M-bit in the MAY column of the AVP flag table is
- added to an existing Command/Application.
-Fajardo, et al. Expires July 24, 2011 [Page 19]
+Fajardo, et al. Standards Track [Page 19]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
+
+ M-bit Setting
+
+ An AVP with the M-bit in the MUST column of the AVP flag table is
+ added to an existing Command/Application. An AVP with the M-bit
+ in the MAY column of the AVP flag table is added to an existing
+ Command/Application.
Note: The M-bit setting for a given AVP is relevant to an
- Application and each command within that application which
- includes the AVP. That is, if an AVP appears in two commands for
+ Application and each command within that application that includes
+ the AVP. That is, if an AVP appears in two commands for
application Foo and the M-bit settings are different in each
command, then there should be two AVP flag tables describing when
to set the M-bit.
Commands
- A new command is used within the existing application either
- because an additional command is added, an existing command has
+ A new command is used within the existing application because
+ either an additional command is added, an existing command has
been modified so that a new Command Code had to be registered, or
a command has been deleted.
- If the ABNF definition of a command allows it, an implementation may
+ AVP Flag bits
+
+ If an existing application changes the meaning/semantics of its
+ AVP Flags or adds new flag bits, then a new Diameter application
+ MUST be created.
+
+ If the CCF definition of a command allows it, an implementation may
add arbitrary optional AVPs with the M-bit cleared (including vendor-
specific AVPs) to that command without needing to define a new
application. Please refer to Section 11.1.1 for details.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 20]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
2. Protocol Overview
The base Diameter protocol concerns itself with establishing
@@ -1137,9 +1116,17 @@ Internet-Draft Diameter Base Protocol January 2011
The initial request for authentication and/or authorization of a user
would include the Session-Id AVP. The Session-Id is then used in all
subsequent messages to identify the user's session (see Section 8 for
- more information). The communicating party may accept the request,
- or reject it by returning an answer message with the Result-Code AVP
- set to indicate an error occurred. The specific behavior of the
+
+
+
+Fajardo, et al. Standards Track [Page 20]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
+ more information). The communicating party may accept the request or
+ reject it by returning an answer message with the Result-Code AVP set
+ to indicate that an error occurred. The specific behavior of the
Diameter server or client receiving a request depends on the Diameter
application employed.
@@ -1153,30 +1140,23 @@ Internet-Draft Diameter Base Protocol January 2011
applications. For authentication and authorization, it is always
extended for a particular application.
- Diameter Clients MUST support the base protocol, which includes
+ Diameter clients MUST support the base protocol, which includes
accounting. In addition, they MUST fully support each Diameter
application that is needed to implement the client's service, e.g.,
- NASREQ and/or Mobile IPv4. A Diameter Client MUST be referred to as
- "Diameter X Client" where X is the application which it supports, and
- not a "Diameter Client".
+ Network Access Server Requirements (NASREQ) [RFC2881] and/or Mobile
+ IPv4. A Diameter client MUST be referred to as "Diameter X Client"
+ where X is the application that it supports and not a "Diameter
+ Client".
- Diameter Servers MUST support the base protocol, which includes
+ Diameter servers MUST support the base protocol, which includes
accounting. In addition, they MUST fully support each Diameter
application that is needed to implement the intended service, e.g.,
- NASREQ and/or Mobile IPv4. A Diameter Server MUST be referred to as
- "Diameter X Server" where X is the application which it supports, and
+ NASREQ and/or Mobile IPv4. A Diameter server MUST be referred to as
+ "Diameter X Server" where X is the application that it supports, and
not a "Diameter Server".
- Diameter Relays and redirect agents are transparent to the Diameter
- applications but they MUST support the Diameter base protocol, which
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 21]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
+ Diameter relays and redirect agents are transparent to the Diameter
+ applications, but they MUST support the Diameter base protocol, which
includes accounting, and all Diameter applications.
Diameter proxies MUST support the base protocol, which includes
@@ -1186,55 +1166,75 @@ Internet-Draft Diameter Base Protocol January 2011
"Diameter X Proxy" where X is the application which it supports, and
not a "Diameter Proxy".
+
+
+
+
+
+
+
+
+
+Fajardo, et al. Standards Track [Page 21]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
2.1. Transport
The Diameter Transport profile is defined in [RFC3539].
- The base Diameter protocol is run on port 3868 for both TCP [RFC793]
- and SCTP [RFC4960]. For TLS [RFC5246] and DTLS [RFC4347], a Diameter
- node that initiate a connection prior to any message exchanges MUST
- run on port [TBD]. It is assumed that TLS is run on top of TCP when
- it is used and DTLS is run on top of SCTP when it is used.
+ The base Diameter protocol is run on port 3868 for both TCP [RFC0793]
+ and SCTP [RFC4960]. For TLS [RFC5246] and Datagram Transport Layer
+ Security (DTLS) [RFC6347], a Diameter node that initiates a
+ connection prior to any message exchanges MUST run on port 5658. It
+ is assumed that TLS is run on top of TCP when it is used, and DTLS is
+ run on top of SCTP when it is used.
If the Diameter peer does not support receiving TLS/TCP and DTLS/SCTP
- connections on port [TBD], i.e. the peer complies only with
- [RFC3588], then the initiator MAY revert to using TCP or SCTP and on
- port 3868. Note that this scheme is kept for the purpose of
- backwards compatibility only and that there are inherent security
- vulnerabilities when the initial CER/CEA messages are sent un-
- protected (see Section 5.6).
+ connections on port 5658 (i.e., the peer complies only with RFC
+ 3588), then the initiator MAY revert to using TCP or SCTP on port
+ 3868. Note that this scheme is kept only for the purpose of backward
+ compatibility and that there are inherent security vulnerabilities
+ when the initial CER/CEA messages are sent unprotected (see
+ Section 5.6).
- Diameter clients MUST support either TCP or SCTP, while agents and
- servers SHOULD support both.
+ Diameter clients MUST support either TCP or SCTP; agents and servers
+ SHOULD support both.
A Diameter node MAY initiate connections from a source port other
than the one that it declares it accepts incoming connections on, and
- MUST be prepared to receive connections on port 3868 for TCP or SCTP
- and port [TBD] for TLS/TCP and DTLS/SCTP connections. A given
- Diameter instance of the peer state machine MUST NOT use more than
- one transport connection to communicate with a given peer, unless
- multiple instances exist on the peer in which case a separate
- connection per process is allowed.
+ it MUST always be prepared to receive connections on port 3868 for
+ TCP or SCTP and port 5658 for TLS/TCP and DTLS/SCTP connections.
+ When DNS-based peer discovery (Section 5.2) is used, the port numbers
+ received from SRV records take precedence over the default ports
+ (3868 and 5658).
+
+ A given Diameter instance of the peer state machine MUST NOT use more
+ than one transport connection to communicate with a given peer,
+ unless multiple instances exist on the peer, in which, case a
+ separate connection per process is allowed.
When no transport connection exists with a peer, an attempt to
- connect SHOULD be periodically made. This behavior is handled via
+ connect SHOULD be made periodically. This behavior is handled via
the Tc timer (see Section 12 for details), whose recommended value is
30 seconds. There are certain exceptions to this rule, such as when
a peer has terminated the transport connection stating that it does
not wish to communicate.
When connecting to a peer and either zero or more transports are
- specified, TLS SHOULD be tried first, followed by DTLS, then by TCP
+ specified, TLS SHOULD be tried first, followed by DTLS, then by TCP,
+ and finally by SCTP. See Section 5.2 for more information on peer
+ discovery.
-Fajardo, et al. Expires July 24, 2011 [Page 22]
-
-Internet-Draft Diameter Base Protocol January 2011
- and finally by SCTP. See Section 5.2 for more information on peer
- discovery.
+Fajardo, et al. Standards Track [Page 22]
+
+RFC 6733 Diameter Base Protocol October 2012
+
Diameter implementations SHOULD be able to interpret ICMP protocol
port unreachable messages as explicit indications that the server is
@@ -1253,18 +1253,18 @@ Internet-Draft Diameter Base Protocol January 2011
Diameter messages SHOULD be mapped into SCTP streams in a way that
avoids head-of-the-line (HOL) blocking. Among different ways of
performing the mapping that fulfill this requirement it is
- RECOMMENDED that a Diameter node sends every Diameter message
- (request or response) over the stream zero with the unordered flag
- set. However, Diameter nodes MAY select and implement other design
- alternatives for avoiding HOL blocking such as using multiple streams
- with the unordered flag cleared (as originally instructed in
- RFC3588). On the receiving side, a Diameter entity MUST be ready to
- receive Diameter messages over any stream and it is free to return
- responses over a different stream. This way, both sides manage the
- available streams in the sending direction, independently of the
- streams chosen by the other side to send a particular Diameter
- message. These messages can be out-of-order and belong to different
- Diameter sessions.
+ RECOMMENDED that a Diameter node send every Diameter message (request
+ or response) over stream zero with the unordered flag set. However,
+ Diameter nodes MAY select and implement other design alternatives for
+ avoiding HOL blocking such as using multiple streams with the
+ unordered flag cleared (as originally instructed in RFC 3588). On
+ the receiving side, a Diameter entity MUST be ready to receive
+ Diameter messages over any stream, and it is free to return responses
+ over a different stream. This way, both sides manage the available
+ streams in the sending direction, independently of the streams chosen
+ by the other side to send a particular Diameter message. These
+ messages can be out-of-order and belong to different Diameter
+ sessions.
Out-of-order delivery has special concerns during a connection
establishment and termination. When a connection is established, the
@@ -1275,30 +1275,37 @@ Internet-Draft Diameter Base Protocol January 2011
the connection. In order to avoid this race condition, the receiver
side SHOULD NOT use out-of-order delivery methods until the first
message has been received from the initiator, proving that it has
- moved to I-Open state. To trigger such message, the receiver side
- could send a DWR immediatly after sending CEA. Upon reception of the
- corresponding DWA, the receiver side should start using out-of-order
- delivery methods to counter the HOL blocking.
+ moved to I-Open state. To trigger such a message, the receiver side
+ could send a DWR immediately after sending a CEA. Upon reception of
+ the corresponding DWA, the receiver side should start using out-of-
+ order delivery methods to counter the HOL blocking.
Another race condition may occur when DPR and DPA messages are used.
+ Both DPR and DPA are small in size; thus, they may be delivered to
+ the peer faster than application messages when an out-of-order
+ delivery mechanism is used. Therefore, it is possible that a DPR/DPA
-Fajardo, et al. Expires July 24, 2011 [Page 23]
+Fajardo, et al. Standards Track [Page 23]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
+
+ exchange completes while application messages are still in transit,
+ resulting in a loss of these messages. An implementation could
+ mitigate this race condition, for example, using timers, and wait for
+ a short period of time for pending application level messages to
+ arrive before proceeding to disconnect the transport connection.
+ Eventually, lost messages are handled by the retransmission mechanism
+ described in Section 5.5.4.
- Both DPR and DPA are small in size, thus they may be delivered faster
- to the peer than application messages when out-of-order delivery
- mechanism is used. Therefore, it is possible that a DPR/DPA exchange
- completes while application messages are still in transit, resulting
- to a loss of these messages. An implementation could mitigate this
- race condition, for example, using timers and wait for a short period
- of time for pending application level messages to arrive before
- proceeding to disconnect the transport connection. Eventually, lost
- messages are handled by the retransmission mechanism described in
- Section 5.5.4.
+ A Diameter agent SHOULD use dedicated payload protocol identifiers
+ (PPIDs) for clear text and encrypted SCTP DATA chunks instead of only
+ using the unspecified payload protocol identifier (value 0). For
+ this purpose, two PPID values are allocated: the PPID value 46 is for
+ Diameter messages in clear text SCTP DATA chunks, and the PPID value
+ 47 is for Diameter messages in protected DTLS/SCTP DATA chunks.
2.2. Securing Diameter Messages
@@ -1307,7 +1314,7 @@ Internet-Draft Diameter Base Protocol January 2011
the use of TLS/TCP and DTLS/SCTP. If desired, alternative security
mechanisms that are independent of Diameter, such as IPsec [RFC4301],
can be deployed to secure connections between peers. The Diameter
- protocol MUST NOT be used without any security mechanism.
+ protocol MUST NOT be used without one of TLS, DTLS, or IPsec.
2.3. Diameter Application Compliance
@@ -1318,37 +1325,40 @@ Internet-Draft Diameter Base Protocol January 2011
Implementations MAY add arbitrary optional AVPs with the M-bit
cleared (including vendor-specific AVPs) to a command defined in an
- application, but only if the command's ABNF syntax specification
+ application, but only if the command's CCF syntax specification
allows for it. Please refer to Section 11.1.1 for details.
2.4. Application Identifiers
- Each Diameter application MUST have an IANA assigned Application Id
- (see Section 11.3). The base protocol does not require an
- Application Id since its support is mandatory. During the
- capabilities exchange, Diameter nodes inform their peers of locally
- supported applications. Furthermore, all Diameter messages contain
- an Application Id, which is used in the message forwarding process.
+ Each Diameter application MUST have an IANA-assigned Application ID.
+ The base protocol does not require an Application Id since its
+ support is mandatory. During the capabilities exchange, Diameter
+ nodes inform their peers of locally supported applications.
+ Furthermore, all Diameter messages contain an Application Id, which
+ is used in the message forwarding process.
- The following Application Id values are defined:
- Diameter Common Messages 0
- Diameter Base Accounting 3
- Relay 0xffffffff
- Relay and redirect agents MUST advertise the Relay Application
-Fajardo, et al. Expires July 24, 2011 [Page 24]
+
+Fajardo, et al. Standards Track [Page 24]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
+
+ The following Application Id values are defined:
+
+ Diameter common message 0
+ Diameter base accounting 3
+ Relay 0xffffffff
- Identifier, while all other Diameter nodes MUST advertise locally
- supported applications. The receiver of a Capabilities Exchange
- message advertising Relay service MUST assume that the sender
- supports all current and future applications.
+ Relay and redirect agents MUST advertise the Relay Application ID,
+ while all other Diameter nodes MUST advertise locally supported
+ applications. The receiver of a Capabilities Exchange message
+ advertising relay service MUST assume that the sender supports all
+ current and future applications.
Diameter relay and proxy agents are responsible for finding an
upstream server that supports the application of a particular
@@ -1358,16 +1368,15 @@ Internet-Draft Diameter Base Protocol January 2011
2.5. Connections vs. Sessions
This section attempts to provide the reader with an understanding of
- the difference between connection and session, which are terms used
- extensively throughout this document.
+ the difference between "connection" and "session", which are terms
+ used extensively throughout this document.
- A connection refers to a transport level connection between two peers
+ A connection refers to a transport-level connection between two peers
that is used to send and receive Diameter messages. A session is a
- logical concept at the application layer existing between the
+ logical concept at the application layer that exists between the
Diameter client and the Diameter server; it is identified via the
Session-Id AVP.
-
+--------+ +-------+ +--------+
| Client | | Relay | | Server |
+--------+ +-------+ +--------+
@@ -1377,100 +1386,93 @@ Internet-Draft Diameter Base Protocol January 2011
<----------------------------->
User session x
- Figure 1: Diameter connections and sessions
+ Figure 1: Diameter Connections and Sessions
In the example provided in Figure 1, peer connection A is established
- between the Client and the Relay. Peer connection B is established
- between the Relay and the Server. User session X spans from the
- Client via the Relay to the Server. Each "user" of a service causes
+ between the client and the relay. Peer connection B is established
+ between the relay and the server. User session X spans from the
+ client via the relay to the server. Each "user" of a service causes
an auth request to be sent, with a unique session identifier. Once
accepted by the server, both the client and the server are aware of
the session.
- It is important to note that there is no relationship between a
- connection and a session, and that Diameter messages for multiple
- sessions are all multiplexed through a single connection. Also note
- that Diameter messages pertaining to the session, both application
- specific and those that are defined in this document such as ASR/ASA,
- RAR/RAA and STR/STA MUST carry the Application Id of the application.
-Fajardo, et al. Expires July 24, 2011 [Page 25]
+Fajardo, et al. Standards Track [Page 25]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
- Diameter messages pertaining to peer connection establishment and
- maintenance such as CER/CEA, DWR/DWA and DPR/DPA MUST carry an
- Application Id of zero (0).
+ It is important to note that there is no relationship between a
+ connection and a session, and that Diameter messages for multiple
+ sessions are all multiplexed through a single connection. Also, note
+ that Diameter messages pertaining to the session, both application-
+ specific and those that are defined in this document such as ASR/ASA,
+ RAR/RAA, and STR/STA, MUST carry the Application Id of the
+ application. Diameter messages pertaining to peer connection
+ establishment and maintenance such as CER/CEA, DWR/DWA, and DPR/DPA
+ MUST carry an Application Id of zero (0).
2.6. Peer Table
- The Diameter Peer Table is used in message forwarding, and referenced
- by the Routing Table. A Peer Table entry contains the following
- fields:
+ The Diameter peer table is used in message forwarding and is
+ referenced by the routing table. A peer table entry contains the
+ following fields:
- Host identity
+ Host Identity
- Following the conventions described for the DiameterIdentity
- derived AVP data format in Section 4.3. This field contains the
+ Following the conventions described for the DiameterIdentity-
+ derived AVP data format in Section 4.3.1, this field contains the
contents of the Origin-Host (Section 6.3) AVP found in the CER or
CEA message.
-
StatusT
- This is the state of the peer entry, and MUST match one of the
+ This is the state of the peer entry, and it MUST match one of the
values listed in Section 5.6.
-
Static or Dynamic
Specifies whether a peer entry was statically configured or
dynamically discovered.
-
- Expiration time
+ Expiration Time
Specifies the time at which dynamically discovered peer table
- entries are to be either refreshed, or expired.
-
+ entries are to be either refreshed or expired. If public key
+ certificates are used for Diameter security (e.g., with TLS), this
+ value MUST NOT be greater than the expiry times in the relevant
+ certificates.
TLS/TCP and DTLS/SCTP Enabled
Specifies whether TLS/TCP and DTLS/SCTP is to be used when
communicating with the peer.
-
Additional security information, when needed (e.g., keys,
- certificates)
-
-
+ certificates).
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 26]
+Fajardo, et al. Standards Track [Page 26]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
2.7. Routing Table
All Realm-Based routing lookups are performed against what is
- commonly known as the Routing Table (see Section 12). A Routing
- Table Entry contains the following fields:
+ commonly known as the routing table (see Section 12). Each routing
+ table entry contains the following fields:
Realm Name
- This is the field that is MUST be used as a primary key in the
+ This is the field that MUST be used as a primary key in the
routing table lookups. Note that some implementations perform
their lookups based on longest-match-from-the-right on the realm
rather than requiring an exact match.
-
Application Identifier
An application is identified by an Application Id. A route entry
@@ -1478,21 +1480,19 @@ Internet-Draft Diameter Base Protocol January 2011
the message header. This field MUST be used as a secondary key
field in routing table lookups.
-
Local Action
The Local Action field is used to identify how a message should be
treated. The following actions are supported:
-
- 1. LOCAL - Diameter messages that can be satisfied locally, and
- do not need to be routed to another Diameter entity.
+ 1. LOCAL - Diameter messages that can be satisfied locally and do
+ not need to be routed to another Diameter entity.
2. RELAY - All Diameter messages that fall within this category
- MUST be routed to a next hop Diameter entity that is indicated
+ MUST be routed to a next-hop Diameter entity that is indicated
by the identifier described below. Routing is done without
modifying any non-routing AVPs. See Section 6.1.9 for
- relaying guidelines
+ relaying guidelines.
3. PROXY - All Diameter messages that fall within this category
MUST be routed to a next Diameter entity that is indicated by
@@ -1504,47 +1504,53 @@ Internet-Draft Diameter Base Protocol January 2011
4. REDIRECT - Diameter messages that fall within this category
MUST have the identity of the home Diameter server(s)
appended, and returned to the sender of the message. See
- Section 6.1.8 for redirect guidelines.
+ Section 6.1.8 for redirection guidelines.
+
+
+
-Fajardo, et al. Expires July 24, 2011 [Page 27]
+Fajardo, et al. Standards Track [Page 27]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
Server Identifier
- One or more servers to which the message is to be routed. These
- servers MUST also be present in the Peer table. When the Local
- Action is set to RELAY or PROXY, this field contains the identity
- of the server(s) the message MUST be routed to. When the Local
+ The identity of one or more servers to which the message is to be
+ routed. This identity MUST also be present in the Host Identity
+ field of the peer table (Section 2.6). When the Local Action is
+ set to RELAY or PROXY, this field contains the identity of the
+ server(s) to which the message MUST be routed. When the Local
Action field is set to REDIRECT, this field contains the identity
- of one or more servers the message MUST be redirected to.
+ of one or more servers to which the message MUST be redirected.
Static or Dynamic
Specifies whether a route entry was statically configured or
dynamically discovered.
- Expiration time
+ Expiration Time
Specifies the time at which a dynamically discovered route table
- entry expires.
+ entry expires. If public key certificates are used for Diameter
+ security (e.g., with TLS), this value MUST NOT be greater than the
+ expiry time in the relevant certificates.
It is important to note that Diameter agents MUST support at least
- one of the LOCAL, RELAY, PROXY or REDIRECT modes of operation.
+ one of the LOCAL, RELAY, PROXY, or REDIRECT modes of operation.
Agents do not need to support all modes of operation in order to
- conform with the protocol specification, but MUST follow the protocol
- compliance guidelines in Section 2. Relay agents and proxies MUST
- NOT reorder AVPs.
+ conform with the protocol specification, but they MUST follow the
+ protocol compliance guidelines in Section 2. Relay agents and
+ proxies MUST NOT reorder AVPs.
The routing table MAY include a default entry that MUST be used for
any requests not matching any of the other entries. The routing
table MAY consist of only such an entry.
When a request is routed, the target server MUST have advertised the
- Application Id (see Section 2.4) for the given message, or have
+ Application Id (see Section 2.4) for the given message or have
advertised itself as a relay or proxy agent. Otherwise, an error is
returned with the Result-Code AVP set to DIAMETER_UNABLE_TO_DELIVER.
@@ -1552,23 +1558,24 @@ Internet-Draft Diameter Base Protocol January 2011
In addition to clients and servers, the Diameter protocol introduces
relay, proxy, redirect, and translation agents, each of which is
- defined in Section 1.3. These Diameter agents are useful for several
+ defined in Section 1.2. Diameter agents are useful for several
reasons:
o They can distribute administration of systems to a configurable
grouping, including the maintenance of security associations.
- o They can be used for concentration of requests from an number of
- co-located or distributed NAS equipment sets to a set of like user
- groups.
-Fajardo, et al. Expires July 24, 2011 [Page 28]
+Fajardo, et al. Standards Track [Page 28]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
+ o They can be used for concentration of requests from a number of
+ co-located or distributed NAS equipment sets to a set of like user
+ groups.
+
o They can do value-added processing to the requests or responses.
o They can be used for load balancing.
@@ -1578,7 +1585,7 @@ Internet-Draft Diameter Base Protocol January 2011
The Diameter protocol requires that agents maintain transaction
state, which is used for failover purposes. Transaction state
- implies that upon forwarding a request, its Hop-by-Hop identifier is
+ implies that upon forwarding a request, its Hop-by-Hop Identifier is
saved; the field is replaced with a locally unique identifier, which
is restored to its original value when the corresponding answer is
received. The request's state is released upon receipt of the
@@ -1593,7 +1600,7 @@ Internet-Draft Diameter Base Protocol January 2011
A stateful agent is one that maintains session state information by
keeping track of all authorized active sessions. Each authorized
session is bound to a particular service, and its state is considered
- active either until the agent is notified otherwise, or the session
+ active until either the agent is notified otherwise or the session
expires. Each authorized session has an expiration, which is
communicated by Diameter servers via the Session-Timeout AVP.
@@ -1604,40 +1611,43 @@ Internet-Draft Diameter Base Protocol January 2011
o Limiting resources authorized to a particular user
- o Per user or transaction auditing
+ o Per-user or per-transaction auditing
A Diameter agent MAY act in a stateful manner for some requests and
be stateless for others. A Diameter implementation MAY act as one
- type of agent for some requests, and as another type of agent for
+ type of agent for some requests and as another type of agent for
others.
-2.8.1. Relay Agents
- Relay Agents are Diameter agents that accept requests and route
- messages to other Diameter nodes based on information found in the
- messages (e.g., Destination-Realm). This routing decision is
- performed using a list of supported realms, and known peers. This is
-Fajardo, et al. Expires July 24, 2011 [Page 29]
+
+Fajardo, et al. Standards Track [Page 29]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
+
+2.8.1. Relay Agents
- known as the Routing Table, as is defined further in Section 2.7.
+ Relay agents are Diameter agents that accept requests and route
+ messages to other Diameter nodes based on information found in the
+ messages (e.g., the value of the Destination-Realm AVP Section 6.6).
+ This routing decision is performed using a list of supported realms
+ and known peers. This is known as the routing table, as is defined
+ further in Section 2.7.
Relays may, for example, be used to aggregate requests from multiple
Network Access Servers (NASes) within a common geographical area
- (POP). The use of Relays is advantageous since it eliminates the
- need for NASes to be configured with the necessary security
- information they would otherwise require to communicate with Diameter
- servers in other realms. Likewise, this reduces the configuration
- load on Diameter servers that would otherwise be necessary when NASes
- are added, changed or deleted.
+ (Point of Presence, POP). The use of relays is advantageous since it
+ eliminates the need for NASes to be configured with the necessary
+ security information they would otherwise require to communicate with
+ Diameter servers in other realms. Likewise, this reduces the
+ configuration load on Diameter servers that would otherwise be
+ necessary when NASes are added, changed, or deleted.
Relays modify Diameter messages by inserting and removing routing
- information, but do not modify any other portion of a message.
+ information, but they do not modify any other portion of a message.
Relays SHOULD NOT maintain session state but MUST maintain
transaction state.
@@ -1650,44 +1660,46 @@ Internet-Draft Diameter Base Protocol January 2011
Figure 2: Relaying of Diameter messages
- The example provided in Figure 2 depicts a request issued from NAS,
+ The example provided in Figure 2 depicts a request issued from a NAS,
which is an access device, for the user [email protected]. Prior to
- issuing the request, NAS performs a Diameter route lookup, using
+ issuing the request, the NAS performs a Diameter route lookup, using
"example.com" as the key, and determines that the message is to be
- relayed to DRL, which is a Diameter Relay. DRL performs the same
- route lookup as NAS, and relays the message to HMS, which is
- example.com's Home Diameter Server. HMS identifies that the request
- can be locally supported (via the realm), processes the
+ relayed to a DRL, which is a Diameter relay. The DRL performs the
+ same route lookup as the NAS, and relays the message to the HMS,
+ which is example.com's home server. The HMS identifies that the
+ request can be locally supported (via the realm), processes the
authentication and/or authorization request, and replies with an
- answer, which is routed back to NAS using saved transaction state.
-
- Since Relays do not perform any application level processing, they
- provide relaying services for all Diameter applications, and
- therefore MUST advertise the Relay Application Id.
+ answer, which is routed back to the NAS using saved transaction
+ state.
-2.8.2. Proxy Agents
+ Since relays do not perform any application-level processing, they
+ provide relaying services for all Diameter applications; therefore,
+ they MUST advertise the Relay Application Id.
- Similarly to relays, proxy agents route Diameter messages using the
- Diameter Routing Table. However, they differ since they modify
- messages to implement policy enforcement. This requires that proxies
- maintain the state of their downstream peers (e.g., access devices)
- to enforce resource usage, provide admission control, and
- provisioning.
-Fajardo, et al. Expires July 24, 2011 [Page 30]
+Fajardo, et al. Standards Track [Page 30]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
+
+2.8.2. Proxy Agents
+
+ Similar to relays, proxy agents route Diameter messages using the
+ Diameter routing table. However, they differ since they modify
+ messages to implement policy enforcement. This requires that proxies
+ maintain the state of their downstream peers (e.g., access devices)
+ to enforce resource usage, provide admission control, and provide
+ provisioning.
Proxies may, for example, be used in call control centers or access
- ISPs that provide outsourced connections, they can monitor the number
- and types of ports in use, and make allocation and admission
- decisions according to their configuration.
+ ISPs that provide outsourced connections; they can monitor the number
+ and type of ports in use and make allocation and admission decisions
+ according to their configuration.
Since enforcing policies requires an understanding of the service
- being provided, Proxies MUST only advertise the Diameter applications
+ being provided, proxies MUST only advertise the Diameter applications
they support.
2.8.3. Redirect Agents
@@ -1709,18 +1721,12 @@ Internet-Draft Diameter Base Protocol January 2011
The example provided in Figure 3 depicts a request issued from the
access device, NAS, for the user [email protected]. The message is
forwarded by the NAS to its relay, DRL, which does not have a routing
- entry in its Diameter Routing Table for example.com. DRL has a
+ entry in its Diameter routing table for example.com. The DRL has a
default route configured to DRD, which is a redirect agent that
- returns a redirect notification to DRL, as well as HMS' contact
- information. Upon receipt of the redirect notification, DRL
- establishes a transport connection with HMS, if one doesn't already
- exist, and forwards the request to it.
-
-
-
-
-
-
+ returns a redirect notification to DRL, as well as the HMS' contact
+ information. Upon receipt of the redirect notification, the DRL
+ establishes a transport connection with the HMS, if one doesn't
+ already exist, and forwards the request to it.
@@ -1729,12 +1735,9 @@ Internet-Draft Diameter Base Protocol January 2011
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 31]
+Fajardo, et al. Standards Track [Page 31]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
+------+
@@ -1755,10 +1758,10 @@ Internet-Draft Diameter Base Protocol January 2011
Figure 3: Redirecting a Diameter Message
- Since redirect agents do not perform any application level
+ Since redirect agents do not perform any application-level
processing, they provide relaying services for all Diameter
- applications, and therefore MUST advertise the Relay Application
- Identifier.
+ applications; therefore, they MUST advertise the Relay Application
+ ID.
2.8.4. Translation Agents
@@ -1773,7 +1776,7 @@ Internet-Draft Diameter Base Protocol January 2011
MUST maintain transaction state.
Translation of messages can only occur if the agent recognizes the
- application of a particular request, and therefore translation agents
+ application of a particular request; therefore, translation agents
MUST only advertise their locally supported applications.
+------+ ---------> +------+ ---------> +------+
@@ -1788,23 +1791,24 @@ Internet-Draft Diameter Base Protocol January 2011
-Fajardo, et al. Expires July 24, 2011 [Page 32]
+Fajardo, et al. Standards Track [Page 32]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
2.9. Diameter Path Authorization
- As noted in Section 2.2, Diameter provides transmission level
+ As noted in Section 2.2, Diameter provides transmission-level
security for each connection using TLS/TCP and DTLS/SCTP. Therefore,
- each connection can be authenticated, replay and integrity protected.
+ each connection can be authenticated and can be replay and integrity
+ protected.
- In addition to authenticating each connection, each connection as
- well as the entire session MUST also be authorized. Before
- initiating a connection, a Diameter Peer MUST check that its peers
- are authorized to act in their roles. For example, a Diameter peer
- may be authentic, but that does not mean that it is authorized to act
- as a Diameter Server advertising a set of Diameter applications.
+ In addition to authenticating each connection, the entire session
+ MUST also be authorized. Before initiating a connection, a Diameter
+ peer MUST check that its peers are authorized to act in their roles.
+ For example, a Diameter peer may be authentic, but that does not mean
+ that it is authorized to act as a Diameter server advertising a set
+ of Diameter applications.
Prior to bringing up a connection, authorization checks are performed
at each connection along the path. Diameter capabilities negotiation
@@ -1815,7 +1819,7 @@ Internet-Draft Diameter Base Protocol January 2011
As noted in Section 6.1.9, a relay or proxy agent MUST append a
Route-Record AVP to all requests forwarded. The AVP contains the
- identity of the peer the request was received from.
+ identity of the peer from which the request was received.
The home Diameter server, prior to authorizing a session, MUST check
the Route-Record AVPs to make sure that the route traversed by the
@@ -1823,7 +1827,7 @@ Internet-Draft Diameter Base Protocol January 2011
realm may not wish to honor requests that have been routed through an
untrusted realm. By authorizing a request, the home Diameter server
is implicitly indicating its willingness to engage in the business
- transaction as specified by the contractual relationship between the
+ transaction as specified by any contractual relationship between the
server and the previous hop. A DIAMETER_AUTHORIZATION_REJECTED error
message (see Section 7.1.5) is sent if the route traversed by the
request is unacceptable.
@@ -1839,72 +1843,24 @@ Internet-Draft Diameter Base Protocol January 2011
willingness to take on financial risk relative to the session. A
local realm may wish to limit this exposure, for example, by
establishing credit limits for intermediate realms and refusing to
- accept responses which would violate those limits. By issuing an
- accounting request corresponding to the authorization response, the
+ accept responses that would violate those limits. By issuing an
-Fajardo, et al. Expires July 24, 2011 [Page 33]
+Fajardo, et al. Standards Track [Page 33]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
+ accounting request corresponding to the authorization response, the
local realm implicitly indicates its agreement to provide the service
indicated in the authorization response. If the service cannot be
provided by the local realm, then a DIAMETER_UNABLE_TO_COMPLY error
message MUST be sent within the accounting request; a Diameter client
receiving an authorization response for a service that it cannot
- perform MUST NOT substitute an alternate service, and then send
+ perform MUST NOT substitute an alternate service and then send
accounting requests for the alternate service instead.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 34]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
3. Diameter Header
A summary of the Diameter header format is shown below. The fields
@@ -1915,7 +1871,7 @@ Internet-Draft Diameter Base Protocol January 2011
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Version | Message Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | command flags | Command-Code |
+ | Command Flags | Command Code |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Application-ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -1935,13 +1891,23 @@ Internet-Draft Diameter Base Protocol January 2011
The Message Length field is three octets and indicates the length
of the Diameter message including the header fields and the padded
- AVPs. Thus the message length field is always a multiple of 4.
+ AVPs. Thus, the Message Length field is always a multiple of 4.
Command Flags
The Command Flags field is eight bits. The following bits are
assigned:
+
+
+
+
+
+Fajardo, et al. Standards Track [Page 34]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+
|R P E T r r r r|
@@ -1952,127 +1918,113 @@ Internet-Draft Diameter Base Protocol January 2011
If set, the message is a request. If cleared, the message is
an answer.
-
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 35]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
P(roxiable)
- If set, the message MAY be proxied, relayed or redirected. If
+ If set, the message MAY be proxied, relayed, or redirected. If
cleared, the message MUST be locally processed.
-
E(rror)
If set, the message contains a protocol error, and the message
- will not conform to the ABNF described for this command.
+ will not conform to the CCF described for this command.
Messages with the 'E' bit set are commonly referred to as error
- messages. This bit MUST NOT be set in request messages. See
- Section 7.2.
+ messages. This bit MUST NOT be set in request messages (see
+ Section 7.2).
-
- T(Potentially re-transmitted message)
+ T(Potentially retransmitted message)
This flag is set after a link failover procedure, to aid the
removal of duplicate requests. It is set when resending
requests not yet acknowledged, as an indication of a possible
duplicate due to a link failure. This bit MUST be cleared when
- sending a request for the first time, otherwise the sender MUST
- set this flag. Diameter agents only need to be concerned about
- the number of requests they send based on a single received
- request; retransmissions by other entities need not be tracked.
- Diameter agents that receive a request with the T flag set,
- MUST keep the T flag set in the forwarded request. This flag
- MUST NOT be set if an error answer message (e.g., a protocol
- error) has been received for the earlier message. It can be
- set only in cases where no answer has been received from the
- server for a request and the request is sent again. This flag
- MUST NOT be set in answer messages.
-
+ sending a request for the first time; otherwise, the sender
+ MUST set this flag. Diameter agents only need to be concerned
+ about the number of requests they send based on a single
+ received request; retransmissions by other entities need not be
+ tracked. Diameter agents that receive a request with the T
+ flag set, MUST keep the T flag set in the forwarded request.
+ This flag MUST NOT be set if an error answer message (e.g., a
+ protocol error) has been received for the earlier message. It
+ can be set only in cases where no answer has been received from
+ the server for a request, and the request has been sent again.
+ This flag MUST NOT be set in answer messages.
r(eserved)
- These flag bits are reserved for future use, and MUST be set to
- zero, and ignored by the receiver.
+ These flag bits are reserved for future use; they MUST be set
+ to zero and ignored by the receiver.
- Command-Code
- The Command-Code field is three octets, and is used in order to
- communicate the command associated with the message. The 24-bit
- address space is managed by IANA (see Section 11.2.1).
- Command-Code values 16,777,214 and 16,777,215 (hexadecimal values
- FFFFFE -FFFFFF) are reserved for experimental use (See Section
- 11.3).
-Fajardo, et al. Expires July 24, 2011 [Page 36]
+Fajardo, et al. Standards Track [Page 35]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
+
+
+ Command Code
+ The Command Code field is three octets and is used in order to
+ communicate the command associated with the message. The 24-bit
+ address space is managed by IANA (see Section 3.1). Command Code
+ values 16,777,214 and 16,777,215 (hexadecimal values FFFFFE-
+ FFFFFF) are reserved for experimental use (see Section 11.2).
- Application-ID
+ Application-ID
- Application-ID is four octets and is used to identify to which
- application the message is applicable for. The application can be
- an authentication application, an accounting application or a
- vendor specific application. See Section 11.3 for the possible
- values that the application-id may use.
+ Application-ID is four octets and is used to identify for which
+ application the message is applicable. The application can be an
+ authentication application, an accounting application, or a
+ vendor-specific application.
- The value of the application-id field in the header MUST be the
- same as any relevant application-id AVPs contained in the message.
+ The value of the Application-ID field in the header MUST be the
+ same as any relevant Application-Id AVPs contained in the message.
Hop-by-Hop Identifier
The Hop-by-Hop Identifier is an unsigned 32-bit integer field (in
- network byte order) and aids in matching requests and replies.
- The sender MUST ensure that the Hop-by-Hop identifier in a request
- is unique on a given connection at any given time, and MAY attempt
- to ensure that the number is unique across reboots. The sender of
- an Answer message MUST ensure that the Hop-by-Hop Identifier field
- contains the same value that was found in the corresponding
- request. The Hop-by-Hop identifier is normally a monotonically
- increasing number, whose start value was randomly generated. An
- answer message that is received with an unknown Hop-by-Hop
- Identifier MUST be discarded.
-
+ network byte order) that aids in matching requests and replies.
+ The sender MUST ensure that the Hop-by-Hop Identifier in a request
+ is unique on a given connection at any given time, and it MAY
+ attempt to ensure that the number is unique across reboots. The
+ sender of an answer message MUST ensure that the Hop-by-Hop
+ Identifier field contains the same value that was found in the
+ corresponding request. The Hop-by-Hop Identifier is normally a
+ monotonically increasing number, whose start value was randomly
+ generated. An answer message that is received with an unknown
+ Hop-by-Hop Identifier MUST be discarded.
End-to-End Identifier
The End-to-End Identifier is an unsigned 32-bit integer field (in
- network byte order) and is used to detect duplicate messages.
- Upon reboot implementations MAY set the high order 12 bits to
+ network byte order) that is used to detect duplicate messages.
+ Upon reboot, implementations MAY set the high order 12 bits to
contain the low order 12 bits of current time, and the low order
20 bits to a random value. Senders of request messages MUST
insert a unique identifier on each message. The identifier MUST
remain locally unique for a period of at least 4 minutes, even
- across reboots. The originator of an Answer message MUST ensure
+ across reboots. The originator of an answer message MUST ensure
that the End-to-End Identifier field contains the same value that
was found in the corresponding request. The End-to-End Identifier
MUST NOT be modified by Diameter agents of any kind. The
- combination of the Origin-Host (see Section 6.3) and this field is
+ combination of the Origin-Host AVP (Section 6.3) and this field is
used to detect duplicates. Duplicate requests SHOULD cause the
- same answer to be transmitted (modulo the hop-by-hop Identifier
- field and any routing AVPs that may be present), and MUST NOT
- affect any state that was set when the original request was
- processed. Duplicate answer messages that are to be locally
- consumed (see Section 6.2) SHOULD be silently discarded.
-
-
+ same answer to be transmitted (modulo the Hop-by-Hop Identifier
-Fajardo, et al. Expires July 24, 2011 [Page 37]
+Fajardo, et al. Standards Track [Page 36]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
+ field and any routing AVPs that may be present), and they MUST NOT
+ affect any state that was set when the original request was
+ processed. Duplicate answer messages that are to be locally
+ consumed (see Section 6.2) SHOULD be silently discarded.
+
AVPs
AVPs are a method of encapsulating information relevant to the
@@ -2080,17 +2032,17 @@ Internet-Draft Diameter Base Protocol January 2011
3.1. Command Codes
- Each command Request/Answer pair is assigned a command code, and the
+ Each command Request/Answer pair is assigned a Command Code, and the
sub-type (i.e., request or answer) is identified via the 'R' bit in
the Command Flags field of the Diameter header.
-
- Every Diameter message MUST contain a command code in its header's
- Command-Code field, which is used to determine the action that is to
+ Every Diameter message MUST contain a Command Code in its header's
+ Command Code field, which is used to determine the action that is to
be taken for a particular message. The following Command Codes are
defined in the Diameter base protocol:
- Command-Name Abbrev. Code Reference
+ Section
+ Command Name Abbrev. Code Reference
--------------------------------------------------------
Abort-Session-Request ASR 274 8.5.1
Abort-Session-Answer ASA 274 8.5.2
@@ -2111,140 +2063,142 @@ Internet-Draft Diameter Base Protocol January 2011
Session-Termination- STA 275 8.4.2
Answer
-3.2. Command Code ABNF specification
- Every Command Code defined MUST include a corresponding ABNF
- specification, which is used to define the AVPs that MUST or MAY be
- present when sending the message. The following format is used in
- the definition:
- command-def = <command-name> "::=" diameter-message
- command-name = diameter-name
-Fajardo, et al. Expires July 24, 2011 [Page 38]
-
-Internet-Draft Diameter Base Protocol January 2011
- diameter-name = ALPHA *(ALPHA / DIGIT / "-")
+Fajardo, et al. Standards Track [Page 37]
+
+RFC 6733 Diameter Base Protocol October 2012
- diameter-message = header [ *fixed] [ *required] [ *optional]
- header = "<" "Diameter Header:" command-id
- [r-bit] [p-bit] [e-bit] [application-id] ">"
+3.2. Command Code Format Specification
- application-id = 1*DIGIT
+ Every Command Code defined MUST include a corresponding Command Code
+ Format (CCF) specification, which is used to define the AVPs that
+ MUST or MAY be present when sending the message. The following ABNF
+ specifies the CCF used in the definition:
- command-id = 1*DIGIT
- ; The Command Code assigned to the command
+ command-def = "<" command-name ">" "::=" diameter-message
- r-bit = ", REQ"
- ; If present, the 'R' bit in the Command
- ; Flags is set, indicating that the message
- ; is a request, as opposed to an answer.
+ command-name = diameter-name
- p-bit = ", PXY"
- ; If present, the 'P' bit in the Command
- ; Flags is set, indicating that the message
- ; is proxiable.
+ diameter-name = ALPHA *(ALPHA / DIGIT / "-")
- e-bit = ", ERR"
- ; If present, the 'E' bit in the Command
- ; Flags is set, indicating that the answer
- ; message contains a Result-Code AVP in
- ; the "protocol error" class.
+ diameter-message = header *fixed *required *optional
- fixed = [qual] "<" avp-spec ">"
- ; Defines the fixed position of an AVP
+ header = "<Diameter-Header:" command-id
+ [r-bit] [p-bit] [e-bit] [application-id]">"
- required = [qual] "{" avp-spec "}"
- ; The AVP MUST be present and can appear
- ; anywhere in the message.
+ application-id = 1*DIGIT
+ command-id = 1*DIGIT
+ ; The Command Code assigned to the command.
- optional = [qual] "[" avp-name "]"
- ; The avp-name in the 'optional' rule cannot
- ; evaluate to any AVP Name which is included
- ; in a fixed or required rule. The AVP can
- ; appear anywhere in the message.
- ;
- ; NOTE: "[" and "]" have a slightly different
- ; meaning than in ABNF (RFC 5234]). These braces
- ; cannot be used to express optional fixed rules
- ; (such as an optional ICV at the end). To do this,
- ; the convention is '0*1fixed'.
+ r-bit = ", REQ"
+ ; If present, the 'R' bit in the Command
+ ; Flags is set, indicating that the message
+ ; is a request as opposed to an answer.
+ p-bit = ", PXY"
+ ; If present, the 'P' bit in the Command
+ ; Flags is set, indicating that the message
+ ; is proxiable.
+ e-bit = ", ERR"
+ ; If present, the 'E' bit in the Command
+ ; Flags is set, indicating that the answer
+ ; message contains a Result-Code AVP in
+ ; the "protocol error" class.
+ fixed = [qual] "<" avp-spec ">"
+ ; Defines the fixed position of an AVP.
-Fajardo, et al. Expires July 24, 2011 [Page 39]
-
-Internet-Draft Diameter Base Protocol January 2011
+ required = [qual] "{" avp-spec "}"
+ ; The AVP MUST be present and can appear
+ ; anywhere in the message.
- qual = [min] "*" [max]
- ; See ABNF conventions, RFC 5234 Section 4.
- ; The absence of any qualifiers depends on
- ; whether it precedes a fixed, required, or
- ; optional rule. If a fixed or required rule has
- ; no qualifier, then exactly one such AVP MUST
- ; be present. If an optional rule has no
- ; qualifier, then 0 or 1 such AVP may be
- ; present. If an optional rule has a qualifier,
- ; then the value of min MUST be 0 if present.
- min = 1*DIGIT
- ; The minimum number of times the element may
- ; be present. If absent, the default value is zero
- ; for fixed and optional rules and one for required
- ; rules. The value MUST be at least one for for
- ; required rules.
- max = 1*DIGIT
- ; The maximum number of times the element may
- ; be present. If absent, the default value is
- ; infinity. A value of zero implies the AVP MUST
- ; NOT be present.
- avp-spec = diameter-name
- ; The avp-spec has to be an AVP Name, defined
- ; in the base or extended Diameter
- ; specifications.
-
- avp-name = avp-spec / "AVP"
- ; The string "AVP" stands for *any* arbitrary AVP
- ; Name, not otherwise listed in that command code
- ; definition. Addition this AVP is recommended for
- ; all command ABNFs to allow for extensibility.
+Fajardo, et al. Standards Track [Page 38]
+
+RFC 6733 Diameter Base Protocol October 2012
- The following is a definition of a fictitious command code:
+ optional = [qual] "[" avp-name "]"
+ ; The avp-name in the 'optional' rule cannot
+ ; evaluate to any AVP Name that is included
+ ; in a fixed or required rule. The AVP can
+ ; appear anywhere in the message.
+ ;
+ ; NOTE: "[" and "]" have a slightly different
+ ; meaning than in ABNF. These braces
+ ; cannot be used to express optional fixed rules
+ ; (such as an optional ICV at the end). To do
+ ; this, the convention is '0*1fixed'.
- Example-Request ::= < Diameter Header: 9999999, REQ, PXY >
- { User-Name }
- * { Origin-Host }
- * [ AVP ]
+ qual = [min] "*" [max]
+ ; See ABNF conventions, RFC 5234, Section 4.
+ ; The absence of any qualifier depends on
+ ; whether it precedes a fixed, required, or
+ ; optional rule. If a fixed or required rule has
+ ; no qualifier, then exactly one such AVP MUST
+ ; be present. If an optional rule has no
+ ; qualifier, then 0 or 1 such AVP may be
+ ; present. If an optional rule has a qualifier,
+ ; then the value of min MUST be 0 if present.
+ min = 1*DIGIT
+ ; The minimum number of times the element may
+ ; be present. If absent, the default value is 0
+ ; for fixed and optional rules and 1 for
+ ; required rules. The value MUST be at least 1
+ ; for required rules.
+ max = 1*DIGIT
+ ; The maximum number of times the element may
+ ; be present. If absent, the default value is
+ ; infinity. A value of 0 implies the AVP MUST
+ ; NOT be present.
+ avp-spec = diameter-name
+ ; The avp-spec has to be an AVP Name, defined
+ ; in the base or extended Diameter
+ ; specifications.
+ avp-name = avp-spec / "AVP"
+ ; The string "AVP" stands for *any* arbitrary AVP
+ ; Name, not otherwise listed in that Command Code
+ ; definition. The inclusion of this string
+ ; is recommended for all CCFs to allow for
+ ; extensibility.
-Fajardo, et al. Expires July 24, 2011 [Page 40]
+Fajardo, et al. Standards Track [Page 39]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
+
+
+ The following is a definition of a fictitious Command Code:
+ Example-Request ::= < Diameter Header: 9999999, REQ, PXY >
+ { User-Name }
+ 1* { Origin-Host }
+ * [ AVP ]
3.3. Diameter Command Naming Conventions
Diameter command names typically includes one or more English words
- followed by the verb Request or Answer. Each English word is
+ followed by the verb "Request" or "Answer". Each English word is
delimited by a hyphen. A three-letter acronym for both the request
and answer is also normally provided.
@@ -2253,10 +2207,10 @@ Internet-Draft Diameter Base Protocol January 2011
the acronyms are STR and STA, respectively.
Both the request and the answer for a given command share the same
- command code. The request is identified by the R(equest) bit in the
+ Command Code. The request is identified by the R(equest) bit in the
Diameter header set to one (1), to ask that a particular action be
performed, such as authorizing a user or terminating a session. Once
- the receiver has completed the request it issues the corresponding
+ the receiver has completed the request, it issues the corresponding
answer, which includes a result code that communicates one of the
following:
@@ -2274,38 +2228,25 @@ Internet-Draft Diameter Base Protocol January 2011
Additional information, encoded within AVPs, may also be included in
answer messages.
+4. Diameter AVPs
+ Diameter AVPs carry specific authentication, accounting,
+ authorization, and routing information as well as configuration
+ details for the request and reply.
-
-
-
-
-
-
-
-
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 41]
+Fajardo, et al. Standards Track [Page 40]
-Internet-Draft Diameter Base Protocol January 2011
-
-
-4. Diameter AVPs
+RFC 6733 Diameter Base Protocol October 2012
- Diameter AVPs carry specific authentication, accounting,
- authorization and routing information as well as configuration
- details for the request and reply.
Each AVP of type OctetString MUST be padded to align on a 32-bit
boundary, while other AVP types align naturally. A number of zero-
- valued bytes are added to the end of the AVP Data field till a word
+ valued bytes are added to the end of the AVP Data field until a word
boundary is reached. The length of the padding is not reflected in
the AVP Length field.
@@ -2330,92 +2271,96 @@ Internet-Draft Diameter Base Protocol January 2011
The AVP Code, combined with the Vendor-Id field, identifies the
attribute uniquely. AVP numbers 1 through 255 are reserved for
- re-use of RADIUS attributes, without setting the Vendor-Id field.
+ reuse of RADIUS attributes, without setting the Vendor-Id field.
AVP numbers 256 and above are used for Diameter, which are
- allocated by IANA (see Section 11.1).
-
+ allocated by IANA (see Section 11.1.1).
AVP Flags
The AVP Flags field informs the receiver how each attribute must
- be handled. The 'r' (reserved) bits are unused and SHOULD be set
- to 0. Note that subsequent Diameter applications MAY define
- additional bits within the AVP Header, and an unrecognized bit
- SHOULD be considered an error. The 'P' bit has been reserved for
- future usage of end-to-end security. At the time of writing there
- are no end-to-end security mechanisms specified therefore the 'P'
- bit SHOULD be set to 0.
+ be handled. New Diameter applications SHOULD NOT define
+ additional AVP Flag bits. However, note that new Diameter
+ applications MAY define additional bits within the AVP header, and
+ an unrecognized bit SHOULD be considered an error. The sender of
+ the AVP MUST set 'R' (reserved) bits to 0 and the receiver SHOULD
+ ignore all 'R' (reserved) bits. The 'P' bit has been reserved for
+ future usage of end-to-end security. At the time of writing,
+ there are no end-to-end security mechanisms specified; therefore,
+ the 'P' bit SHOULD be set to 0.
+
+ The 'M' bit, known as the Mandatory bit, indicates whether the
+ receiver of the AVP MUST parse and understand the semantics of the
+ AVP including its content. The receiving entity MUST return an
+ appropriate error message if it receives an AVP that has the M-bit
-Fajardo, et al. Expires July 24, 2011 [Page 42]
+Fajardo, et al. Standards Track [Page 41]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
- The 'M' Bit, known as the Mandatory bit, indicates whether the
- receiver of the AVP MUST parse and understand the semantic of the
- AVP including its content. The receiving entity MUST return an
- appropriate error message if it receives an AVP that has the M-bit
set but does not understand it. An exception applies when the AVP
is embedded within a Grouped AVP. See Section 4.4 for details.
- Diameter Relay and redirect agents MUST NOT reject messages with
+ Diameter relay and redirect agents MUST NOT reject messages with
unrecognized AVPs.
The 'M' bit MUST be set according to the rules defined in the
- application specification which introduces or re-uses this AVP.
- Within a given application, the M-bit setting for an AVP is either
- defined for all command types or for each command type.
+ application specification that introduces or reuses this AVP.
+ Within a given application, the M-bit setting for an AVP is
+ defined either for all command types or for each command type.
- AVPs with the 'M' bit cleared are informational only and a
- receiver that receives a message with such an AVP that is not
- supported, or whose value is not supported, MAY simply ignore the
- AVP.
+ AVPs with the 'M' bit cleared are informational only; a receiver
+ that receives a message with such an AVP that is not supported, or
+ whose value is not supported, MAY simply ignore the AVP.
The 'V' bit, known as the Vendor-Specific bit, indicates whether
the optional Vendor-ID field is present in the AVP header. When
- set the AVP Code belongs to the specific vendor code address
+ set, the AVP Code belongs to the specific vendor code address
space.
AVP Length
The AVP Length field is three octets, and indicates the number of
- octets in this AVP including the AVP Code, AVP Length, AVP Flags,
- Vendor-ID field (if present) and the AVP data. If a message is
- received with an invalid attribute length, the message MUST be
- rejected.
+ octets in this AVP including the AVP Code field, AVP Length field,
+ AVP Flags field, Vendor-ID field (if present), and the AVP Data
+ field. If a message is received with an invalid attribute length,
+ the message MUST be rejected.
4.1.1. Optional Header Elements
- The AVP Header contains one optional field. This field is only
+ The AVP header contains one optional field. This field is only
present if the respective bit-flag is enabled.
-
Vendor-ID
The Vendor-ID field is present if the 'V' bit is set in the AVP
Flags field. The optional four-octet Vendor-ID field contains the
- IANA assigned "SMI Network Management Private Enterprise Codes"
- [RFC3232] value, encoded in network byte order. Any vendor or
- standardization organization that are also treated like vendors in
- the IANA managed "SMI Network Management Private Enterprise Codes"
- space wishing to implement a vendor-specific Diameter AVP MUST use
- their own Vendor-ID along with their privately managed AVP address
+ IANA-assigned "SMI Network Management Private Enterprise Codes"
+ [ENTERPRISE] value, encoded in network byte order. Any vendors or
+ standardization organizations that are also treated like vendors
+ in the IANA-managed "SMI Network Management Private Enterprise
+ Codes" space wishing to implement a vendor-specific Diameter AVP
+ MUST use their own Vendor-ID along with their privately managed
+ AVP address space, guaranteeing that they will not collide with
+ any other vendor's vendor-specific AVP(s) or with future IETF
+ AVPs.
-Fajardo, et al. Expires July 24, 2011 [Page 43]
-
-Internet-Draft Diameter Base Protocol January 2011
- space, guaranteeing that they will not collide with any other
- vendor's vendor-specific AVP(s), nor with future IETF AVPs.
- A vendor ID value of zero (0) corresponds to the IETF adopted AVP
- values, as managed by the IANA. Since the absence of the vendor
- ID field implies that the AVP in question is not vendor specific,
- implementations MUST NOT use the zero (0) vendor ID.
+Fajardo, et al. Standards Track [Page 42]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
+ A Vendor-ID value of zero (0) corresponds to the IETF-adopted AVP
+ values, as managed by IANA. Since the absence of the Vendor-ID
+ field implies that the AVP in question is not vendor specific,
+ implementations MUST NOT use the value of zero (0) for the
+ Vendor-ID field.
4.2. Basic AVP Data Formats
@@ -2426,49 +2371,45 @@ Internet-Draft Diameter Base Protocol January 2011
type derived from the base data types. In the event that a new Basic
AVP Data Format is needed, a new version of this RFC MUST be created.
-
OctetString
The data contains arbitrary data of variable length. Unless
otherwise noted, the AVP Length field MUST be set to at least 8
- (12 if the 'V' bit is enabled). AVP Values of this type that are
- not a multiple of four-octets in length is followed by the
- necessary padding so that the next AVP (if any) will start on a
- 32-bit boundary.
-
+ (12 if the 'V' bit is enabled). AVP values of this type that are
+ not a multiple of 4 octets in length are followed by the necessary
+ padding so that the next AVP (if any) will start on a 32-bit
+ boundary.
Integer32
- 32 bit signed value, in network byte order. The AVP Length field
+ 32-bit signed value, in network byte order. The AVP Length field
MUST be set to 12 (16 if the 'V' bit is enabled).
-
Integer64
- 64 bit signed value, in network byte order. The AVP Length field
+ 64-bit signed value, in network byte order. The AVP Length field
MUST be set to 16 (20 if the 'V' bit is enabled).
-
Unsigned32
- 32 bit unsigned value, in network byte order. The AVP Length
+ 32-bit unsigned value, in network byte order. The AVP Length
field MUST be set to 12 (16 if the 'V' bit is enabled).
+ Unsigned64
+ 64-bit unsigned value, in network byte order. The AVP Length
+ field MUST be set to 16 (20 if the 'V' bit is enabled).
-Fajardo, et al. Expires July 24, 2011 [Page 44]
-
-Internet-Draft Diameter Base Protocol January 2011
- Unsigned64
- 64 bit unsigned value, in network byte order. The AVP Length
- field MUST be set to 16 (20 if the 'V' bit is enabled).
+Fajardo, et al. Standards Track [Page 43]
+
+RFC 6733 Diameter Base Protocol October 2012
Float32
@@ -2478,7 +2419,6 @@ Internet-Draft Diameter Base Protocol January 2011
network byte order. The AVP Length field MUST be set to 12 (16 if
the 'V' bit is enabled).
-
Float64
This represents floating point values of double precision as
@@ -2486,73 +2426,69 @@ Internet-Draft Diameter Base Protocol January 2011
network byte order. The AVP Length field MUST be set to 16 (20 if
the 'V' bit is enabled).
-
Grouped
- The Data field is specified as a sequence of AVPs. Each of these
- AVPs follows - in the order in which they are specified -
- including their headers and padding. The AVP Length field is set
- to 8 (12 if the 'V' bit is enabled) plus the total length of all
- included AVPs, including their headers and padding. Thus the AVP
- length field of an AVP of type Grouped is always a multiple of 4.
-
+ The Data field is specified as a sequence of AVPs. These AVPs are
+ concatenated -- including their headers and padding -- in the
+ order in which they are specified and the result encapsulated in
+ the Data field. The AVP Length field is set to 8 (12 if the 'V'
+ bit is enabled) plus the total length of all included AVPs,
+ including their headers and padding. Thus, the AVP Length field
+ of an AVP of type Grouped is always a multiple of 4.
4.3. Derived AVP Data Formats
In addition to using the Basic AVP Data Formats, applications may
define data formats derived from the Basic AVP Data Formats. An
application that defines new Derived AVP Data Formats MUST include
- them in a section entitled "Derived AVP Data Formats", using the same
+ them in a section titled "Derived AVP Data Formats", using the same
format as the definitions below. Each new definition MUST be either
defined or listed with a reference to the RFC that defines the
format.
-4.3.1. Common Derived AVPs
+4.3.1. Common Derived AVP Data Formats
The following are commonly used Derived AVP Data Formats.
+ Address
+ The Address format is derived from the OctetString Basic AVP
+ Format. It is a discriminated union representing, for example, a
+ 32-bit (IPv4) [RFC0791] or 128-bit (IPv6) [RFC4291] address, most
+ significant octet first. The first two octets of the Address AVP
+ represent the AddressType, which contains an Address Family,
+ defined in [IANAADFAM]. The AddressType is used to discriminate
+ the content and format of the remaining octets.
-Fajardo, et al. Expires July 24, 2011 [Page 45]
+Fajardo, et al. Standards Track [Page 44]
-Internet-Draft Diameter Base Protocol January 2011
-
-
- Address
-
- The Address format is derived from the OctetString AVP Base
- Format. It is a discriminated union, representing, for example a
- 32-bit (IPv4) [RFC791] or 128-bit (IPv6) [RFC4291] address, most
- significant octet first. The first two octets of the Address AVP
- represents the AddressType, which contains an Address Family
- defined in [IANAADFAM]. The AddressType is used to discriminate
- the content and format of the remaining octets.
+RFC 6733 Diameter Base Protocol October 2012
Time
- The Time format is derived from the OctetString AVP Base Format.
+ The Time format is derived from the OctetString Basic AVP Format.
The string MUST contain four octets, in the same format as the
first four bytes are in the NTP timestamp format. The NTP
- Timestamp format is defined in Chapter 3 of [RFC5905].
+ timestamp format is defined in Section 3 of [RFC5905].
This represents the number of seconds since 0h on 1 January 1900
with respect to the Coordinated Universal Time (UTC).
- On 6h 28m 16s UTC, 7 February 2036 the time value will overflow.
- SNTP [RFC5905] describes a procedure to extend the time to 2104.
- This procedure MUST be supported by all Diameter nodes.
-
+ On 6h 28m 16s UTC, 7 February 2036, the time value will overflow.
+ Simple Network Time Protocol (SNTP) [RFC5905] describes a
+ procedure to extend the time to 2104. This procedure MUST be
+ supported by all Diameter nodes.
UTF8String
- The UTF8String format is derived from the OctetString AVP Base
- Format. This is a human readable string represented using the
+ The UTF8String format is derived from the OctetString Basic AVP
+ Format. This is a human-readable string represented using the
ISO/IEC IS 10646-1 character set, encoded as an OctetString using
- the UTF-8 [RFC3629] transformation format described in RFC 3629.
+ the UTF-8 transformation format [RFC3629].
Since additional code points are added by amendments to the 10646
standard from time to time, implementations MUST be prepared to
@@ -2570,78 +2506,79 @@ Internet-Draft Diameter Base Protocol January 2011
or software, an alternative means of entry and display, such as
hexadecimal, MAY be provided.
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 46]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
For information encoded in 7-bit US-ASCII, the UTF-8 charset is
identical to the US-ASCII charset.
UTF-8 may require multiple bytes to represent a single character /
- code point; thus the length of an UTF8String in octets may be
+ code point; thus, the length of a UTF8String in octets may be
different from the number of characters encoded.
Note that the AVP Length field of an UTF8String is measured in
- octets, not characters.
+ octets not characters.
+
+
+
+
+Fajardo, et al. Standards Track [Page 45]
+
+RFC 6733 Diameter Base Protocol October 2012
+
DiameterIdentity
- The DiameterIdentity format is derived from the OctetString AVP
- Base Format.
+ The DiameterIdentity format is derived from the OctetString Basic
+ AVP Format.
DiameterIdentity = FQDN/Realm
-
- DiameterIdentity value is used to uniquely identify either:
+ The DiameterIdentity value is used to uniquely identify either:
* A Diameter node for purposes of duplicate connection and
routing loop detection.
- * A Realm to determine whether messages can be satisfied locally,
+ * A Realm to determine whether messages can be satisfied locally
or whether they must be routed or redirected.
+ When a DiameterIdentity value is used to identify a Diameter node,
+ the contents of the string MUST be the Fully Qualified Domain Name
+ (FQDN) of the Diameter node. If multiple Diameter nodes run on
+ the same host, each Diameter node MUST be assigned a unique
+ DiameterIdentity. If a Diameter node can be identified by several
+ FQDNs, a single FQDN should be picked at startup and used as the
+ only DiameterIdentity for that node, whatever the connection on
+ which it is sent. In this document, note that DiameterIdentity is
+ in ASCII form in order to be compatible with existing DNS
+ infrastructure. See Appendix D for interactions between the
+ Diameter protocol and Internationalized Domain Names (IDNs).
- When a DiameterIdentity is used to identify a Diameter node the
- contents of the string MUST be the FQDN of the Diameter node. If
- multiple Diameter nodes run on the same host, each Diameter node
- MUST be assigned a unique DiameterIdentity. If a Diameter node
- can be identified by several FQDNs, a single FQDN should be picked
- at startup, and used as the only DiameterIdentity for that node,
- whatever the connection it is sent on. Note that in this
- document, DiameterIdentity is in ASCII form in order to be
- compatible with existing DNS infrastructure. See Appendix D for
- interactions between the Diameter protocol and Internationalized
- Domain Name (IDNs).
+ DiameterURI
+ The DiameterURI MUST follow the Uniform Resource Identifiers (RFC
+ 3986) syntax [RFC3986] rules specified below:
- DiameterURI
+ "aaa://" FQDN [ port ] [ transport ] [ protocol ]
- The DiameterURI MUST follow the Uniform Resource Identifiers (URI)
- syntax [RFC3986] rules specified below:
+ ; No transport security
+ "aaas://" FQDN [ port ] [ transport ] [ protocol ]
+ ; Transport security used
+ FQDN = < Fully Qualified Domain Name >
-Fajardo, et al. Expires July 24, 2011 [Page 47]
-
-Internet-Draft Diameter Base Protocol January 2011
- "aaa://" FQDN [ port ] [ transport ] [ protocol ]
- ; No transport security
- "aaas://" FQDN [ port ] [ transport ] [ protocol ]
- ; Transport security used
- FQDN = Fully Qualified Host Name
+Fajardo, et al. Standards Track [Page 46]
+
+RFC 6733 Diameter Base Protocol October 2012
+
port = ":" 1*DIGIT
@@ -2649,8 +2586,9 @@ Internet-Draft Diameter Base Protocol January 2011
; incoming connections.
; If absent, the default Diameter port
; (3868) is assumed if no transport
- ; security is used and port (TBD) when
- ; transport security (TLS/TCP and DTLS/SCTP) is used.
+ ; security is used and port 5658 when
+ ; transport security (TLS/TCP and DTLS/SCTP)
+ ; is used.
transport = ";transport=" transport-protocol
@@ -2660,46 +2598,47 @@ Internet-Draft Diameter Base Protocol January 2011
; UDP MUST NOT be used when the aaa-protocol
; field is set to diameter.
- transport-protocol = ( "tcp" / "sctp" / "udp" )
+ transport-protocol = ( "tcp" / "sctp" / "udp" )
- protocol = ";protocol=" aaa-protocol
+ protocol = ";protocol=" aaa-protocol
; If absent, the default AAA protocol
; is Diameter.
- aaa-protocol = ( "diameter" / "radius" / "tacacs+" )
+ aaa-protocol = ( "diameter" / "radius" / "tacacs+" )
- The following are examples of valid Diameter host identities:
+ The following are examples of valid Diameter host identities:
- aaa://host.example.com;transport=tcp
- aaa://host.example.com:6666;transport=tcp
- aaa://host.example.com;protocol=diameter
- aaa://host.example.com:6666;protocol=diameter
- aaa://host.example.com:6666;transport=tcp;protocol=diameter
- aaa://host.example.com:1813;transport=udp;protocol=radius
+ aaa://host.example.com;transport=tcp
+ aaa://host.example.com:6666;transport=tcp
+ aaa://host.example.com;protocol=diameter
+ aaa://host.example.com:6666;protocol=diameter
+ aaa://host.example.com:6666;transport=tcp;protocol=diameter
+ aaa://host.example.com:1813;transport=udp;protocol=radius
+ Enumerated
+ The Enumerated format is derived from the Integer32 Basic AVP
+ Format. The definition contains a list of valid values and their
+ interpretation and is described in the Diameter application
+ introducing the AVP.
-Fajardo, et al. Expires July 24, 2011 [Page 48]
-
-Internet-Draft Diameter Base Protocol January 2011
- Enumerated
- Enumerated is derived from the Integer32 AVP Base Format. The
- definition contains a list of valid values and their
- interpretation and is described in the Diameter application
- introducing the AVP.
+
+Fajardo, et al. Standards Track [Page 47]
+
+RFC 6733 Diameter Base Protocol October 2012
IPFilterRule
- The IPFilterRule format is derived from the OctetString AVP Base
+ The IPFilterRule format is derived from the OctetString Basic AVP
Format and uses the ASCII charset. The rule syntax is a modified
subset of ipfw(8) from FreeBSD. Packets may be filtered based on
the following information that is associated with it:
@@ -2713,13 +2652,13 @@ Internet-Draft Diameter Base Protocol January 2011
IP options
ICMP types
- Rules for the appropriate direction are evaluated in order, with
- the first matched rule terminating the evaluation. Each packet is
- evaluated once. If no rule matches, the packet is dropped if the
- last rule evaluated was a permit, and passed if the last rule was
- a deny.
+ Rules for the appropriate direction are evaluated in order, with the
+ first matched rule terminating the evaluation. Each packet is
+ evaluated once. If no rule matches, the packet is dropped if the
+ last rule evaluated was a permit, and passed if the last rule was a
+ deny.
- IPFilterRule filters MUST follow the format:
+ IPFilterRule filters MUST follow the format:
action dir proto from src to dst [options]
@@ -2737,22 +2676,28 @@ Internet-Draft Diameter Base Protocol January 2011
The <address/mask> may be specified as:
ipno An IPv4 or IPv6 number in dotted-
quad or canonical IPv6 form. Only
+ this exact IP number will match the
+ rule.
+
+
+
+
+
+
-Fajardo, et al. Expires July 24, 2011 [Page 49]
+Fajardo, et al. Standards Track [Page 48]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
- this exact IP number will match the
- rule.
ipno/bits An IP number as above with a mask
width of the form 192.0.2.10/24. In
this case, all IP numbers from
192.0.2.0 to 192.0.2.255 will match.
The bit width MUST be valid for the
- IP version and the IP number MUST
+ IP version, and the IP number MUST
NOT have bits set beyond the mask.
For a match to occur, the same IP
version must be present in the
@@ -2765,7 +2710,7 @@ Internet-Draft Diameter Base Protocol January 2011
is the address or set of addresses
assigned to the terminal. For IPv4,
a typical first rule is often "deny
- in ip! assigned"
+ in ip! assigned".
The sense of the match can be inverted by
preceding an address with the not modifier (!),
@@ -2773,7 +2718,7 @@ Internet-Draft Diameter Base Protocol January 2011
instead. This does not affect the selection of
port numbers.
- With the TCP, UDP and SCTP protocols, optional
+ With the TCP, UDP, and SCTP protocols, optional
ports may be specified as:
{port/port-port}[,ports[,...]]
@@ -2796,33 +2741,35 @@ Internet-Draft Diameter Base Protocol January 2011
-Fajardo, et al. Expires July 24, 2011 [Page 50]
+
+
+Fajardo, et al. Standards Track [Page 49]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
- ipoptions spec
- Match if the IP header contains the comma
- separated list of options specified in spec. The
+ ipoptions spec
+ Match if the IP header contains the comma-separated
+ list of options specified in spec. The
supported IP options are:
ssrr (strict source route), lsrr (loose source
- route), rr (record packet route) and ts
+ route), rr (record packet route), and ts
(timestamp). The absence of a particular option
may be denoted with a '!'.
tcpoptions spec
- Match if the TCP header contains the comma
- separated list of options specified in spec. The
+ Match if the TCP header contains the comma-separated
+ list of options specified in spec. The
supported TCP options are:
mss (maximum segment size), window (tcp window
advertisement), sack (selective ack), ts (rfc1323
- timestamp) and cc (rfc1644 t/tcp connection
+ timestamp), and cc (rfc1644 t/tcp connection
count). The absence of a particular option may
be denoted with a '!'.
- established
+ established
TCP packets only. Match packets that have the RST
or ACK bits set.
@@ -2832,10 +2779,10 @@ Internet-Draft Diameter Base Protocol January 2011
tcpflags spec
TCP packets only. Match if the TCP header
- contains the comma separated list of flags
+ contains the comma-separated list of flags
specified in spec. The supported TCP flags are:
- fin, syn, rst, psh, ack and urg. The absence of a
+ fin, syn, rst, psh, ack, and urg. The absence of a
particular flag may be denoted with a '!'. A rule
that contains a tcpflags specification can never
match a fragmented packet that has a non-zero
@@ -2852,9 +2799,9 @@ Internet-Draft Diameter Base Protocol January 2011
-Fajardo, et al. Expires July 24, 2011 [Page 51]
+Fajardo, et al. Standards Track [Page 50]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
echo reply (0), destination unreachable (3),
@@ -2863,21 +2810,20 @@ Internet-Draft Diameter Base Protocol January 2011
solicitation (10), time-to-live exceeded (11), IP
header bad (12), timestamp request (13),
timestamp reply (14), information request (15),
- information reply (16), address mask request (17)
+ information reply (16), address mask request (17),
and address mask reply (18).
- There is one kind of packet that the access device MUST always
- discard, that is an IP fragment with a fragment offset of one.
- This is a valid packet, but it only has one use, to try to
- circumvent firewalls.
-
- An access device that is unable to interpret or apply a deny rule
- MUST terminate the session. An access device that is unable to
- interpret or apply a permit rule MAY apply a more restrictive
- rule. An access device MAY apply deny rules of its own before the
- supplied rules, for example to protect the access device owner's
- infrastructure.
+ There is one kind of packet that the access device MUST always
+ discard, that is an IP fragment with a fragment offset of one. This
+ is a valid packet, but it only has one use, to try to circumvent
+ firewalls.
+ An access device that is unable to interpret or apply a deny rule
+ MUST terminate the session. An access device that is unable to
+ interpret or apply a permit rule MAY apply a more restrictive rule.
+ An access device MAY apply deny rules of its own before the supplied
+ rules, for example to protect the access device owner's
+ infrastructure.
4.4. Grouped AVP Values
@@ -2885,75 +2831,76 @@ Internet-Draft Diameter Base Protocol January 2011
implies that the Data field is actually a sequence of AVPs. It is
possible to include an AVP with a Grouped type within a Grouped type,
that is, to nest them. AVPs within an AVP of type Grouped have the
- same padding requirements as non-Grouped AVPs, as defined in Section
- 4.
+ same padding requirements as non-Grouped AVPs, as defined in
+ Section 4.4.
The AVP Code numbering space of all AVPs included in a Grouped AVP is
- the same as for non-grouped AVPs. Receivers of a Grouped AVP that
+ the same as for non-Grouped AVPs. 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 AVP itself is unrecognized. The
rule applies even if the encapsulated AVP with its 'M' (mandatory)
- bit set is further encapsulated within other sub-groups; i.e. other
+ bit set is further encapsulated within other sub-groups, i.e., other
Grouped AVPs embedded within the Grouped AVP.
- Every Grouped AVP defined MUST include a corresponding grammar, using
- ABNF [RFC5234] (with modifications), as defined below.
-
+ Every Grouped AVP definition MUST include a corresponding grammar,
+ using ABNF [RFC5234] (with modifications), as defined below.
+ grouped-avp-def = "<" name ">" "::=" avp
+ name-fmt = ALPHA *(ALPHA / DIGIT / "-")
-Fajardo, et al. Expires July 24, 2011 [Page 52]
+Fajardo, et al. Standards Track [Page 51]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
- grouped-avp-def = <name> "::=" avp
-
- name-fmt = ALPHA *(ALPHA / DIGIT / "-")
-
name = name-fmt
; The name has to be the name of an AVP,
; defined in the base or extended Diameter
; specifications.
- avp = header [ *fixed] [ *required] [ *optional]
+ avp = header *fixed *required *optional
header = "<" "AVP-Header:" avpcode [vendor] ">"
avpcode = 1*DIGIT
- ; The AVP Code assigned to the Grouped AVP
+ ; The AVP Code assigned to the Grouped AVP.
vendor = 1*DIGIT
; The Vendor-ID assigned to the Grouped AVP.
; If absent, the default value of zero is
; used.
-4.4.1. Example AVP with a Grouped Data type
+4.4.1. Example AVP with a Grouped Data Type
The Example-AVP (AVP Code 999999) is of type Grouped and is used to
clarify how Grouped AVP values work. The Grouped Data field has the
- following ABNF grammar:
-
-
-
-
-
-
-
-
+ following CCF grammar:
+ Example-AVP ::= < AVP Header: 999999 >
+ { Origin-Host }
+ 1*{ Session-Id }
+ *[ AVP ]
+ An Example-AVP with Grouped Data follows.
+ The Origin-Host AVP (Section 6.3) is required. In this case:
+ Origin-Host = "example.com".
+ One or more Session-Ids must follow. Here there are two:
+ Session-Id =
+ "grump.example.com:33041;23432;893;0AF3B81"
+ Session-Id =
+ "grump.example.com:33054;23561;2358;0AF3B82"
@@ -2964,31 +2911,11 @@ Internet-Draft Diameter Base Protocol January 2011
-Fajardo, et al. Expires July 24, 2011 [Page 53]
+Fajardo, et al. Standards Track [Page 52]
-Internet-Draft Diameter Base Protocol January 2011
-
-
- Example-AVP ::= < AVP Header: 999999 >
- { Origin-Host }
- 1*{ Session-Id }
- *[ AVP ]
-
- An Example-AVP with Grouped Data follows.
-
- The Origin-Host AVP is required (Section 6.3). In this case:
-
- Origin-Host = "example.com".
+RFC 6733 Diameter Base Protocol October 2012
- One or more Session-Ids must follow. Here there are two:
-
- Session-Id =
- "grump.example.com:33041;23432;893;0AF3B81"
-
- Session-Id =
- "grump.example.com:33054;23561;2358;0AF3B82"
-
optional AVPs included are
Recovery-Policy = <binary>
@@ -3007,25 +2934,42 @@ Internet-Draft Diameter Base Protocol January 2011
41d018d56fe938f3cbf089aac12a912a2f0d1923a9390e5f789cb2e5067
d3427475e49968f841
- The data for the optional AVPs is represented in hex since the format
- of these AVPs is neither known at the time of definition of the
- Example-AVP group, nor (likely) at the time when the example instance
- of this AVP is interpreted - except by Diameter implementations which
- support the same set of AVPs. The encoding example illustrates how
- padding is used and how length fields are calculated. Also note that
- AVPs may be present in the Grouped AVP value which the receiver
- cannot interpret (here, the Recover-Policy and Futuristic-Acct-Record
- AVPs). The length of the Example-AVP is the sum of all the length of
- the member AVPs including their padding plus the Example-AVP header
+ The data for the optional AVPs is represented in hexadecimal form
+ since the format of these AVPs is not known at the time of definition
+ of the Example-AVP group nor (likely) at the time when the example
+ instance of this AVP is interpreted -- except by Diameter
+ implementations that support the same set of AVPs. The encoding
+ example illustrates how padding is used and how length fields are
+ calculated. Also, note that AVPs may be present in the Grouped AVP
+ value that the receiver cannot interpret (here, the Recover-Policy
+ and Futuristic-Acct-Record AVPs). The length of the Example-AVP is
+ the sum of all the length of the member AVPs, including their
+ padding, plus the Example-AVP header size.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-Fajardo, et al. Expires July 24, 2011 [Page 54]
-
-Internet-Draft Diameter Base Protocol January 2011
- size.
+
+Fajardo, et al. Standards Track [Page 53]
+
+RFC 6733 Diameter Base Protocol October 2012
This AVP would be encoded as follows:
@@ -3076,15 +3020,18 @@ Internet-Draft Diameter Base Protocol January 2011
-Fajardo, et al. Expires July 24, 2011 [Page 55]
+
+
+
+Fajardo, et al. Standards Track [Page 54]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
4.5. Diameter Base Protocol AVPs
The following table describes the Diameter AVPs defined in the base
- protocol, their AVP Code values, types, possible flag values.
+ protocol, their AVP Code values, types, and possible flag values.
Due to space constraints, the short form DiamIdent is used to
represent DiameterIdentity.
@@ -3132,9 +3079,9 @@ Internet-Draft Diameter Base Protocol January 2011
-Fajardo, et al. Expires July 24, 2011 [Page 56]
+Fajardo, et al. Standards Track [Page 55]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
+----------+
@@ -3154,7 +3101,7 @@ Internet-Draft Diameter Base Protocol January 2011
Record-Number | | |
Accounting- 480 9.8.1 Enumerated | M | V |
Record-Type | | |
- Accounting- 44 9.8.4 OctetString| M | V |
+ Acct- 44 9.8.4 OctetString| M | V |
Session-Id | | |
Accounting- 287 9.8.6 Unsigned64 | M | V |
Sub-Session-Id | | |
@@ -3188,9 +3135,9 @@ Internet-Draft Diameter Base Protocol January 2011
-Fajardo, et al. Expires July 24, 2011 [Page 57]
+Fajardo, et al. Standards Track [Page 56]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
+----------+
@@ -3244,9 +3191,9 @@ Internet-Draft Diameter Base Protocol January 2011
-Fajardo, et al. Expires July 24, 2011 [Page 58]
+Fajardo, et al. Standards Track [Page 57]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
5. Diameter Peers
@@ -3258,25 +3205,25 @@ Internet-Draft Diameter Base Protocol January 2011
Connections between diameter peers are established using their valid
DiameterIdentity. A Diameter node initiating a connection to a peer
- MUST know the peers DiameterIdentity. Methods for discovering a
+ MUST know the peer's DiameterIdentity. Methods for discovering a
Diameter peer can be found in Section 5.2.
- Although a Diameter node may have many possible peers that it is able
- to communicate with, it may not be economical to have an established
- connection to all of them. At a minimum, a Diameter node SHOULD have
- an established connection with two peers per realm, known as the
- primary and secondary peers. Of course, a node MAY have additional
- connections, if it is deemed necessary. Typically, all messages for
- a realm are sent to the primary peer, but in the event that failover
- procedures are invoked, any pending requests are sent to the
- secondary peer. However, implementations are free to load balance
- requests between a set of peers.
-
- Note that a given peer MAY act as a primary for a given realm, while
+ Although a Diameter node may have many possible peers with which it
+ is able to communicate, it may not be economical to have an
+ established connection to all of them. At a minimum, a Diameter node
+ SHOULD have an established connection with two peers per realm, known
+ as the primary and secondary peers. Of course, a node MAY have
+ additional connections, if it is deemed necessary. Typically, all
+ messages for a realm are sent to the primary peer but, in the event
+ that failover procedures are invoked, any pending requests are sent
+ to the secondary peer. However, implementations are free to load
+ balance requests between a set of peers.
+
+ Note that a given peer MAY act as a primary for a given realm while
acting as a secondary for another realm.
When a peer is deemed suspect, which could occur for various reasons,
- including not receiving a DWA within an allotted timeframe, no new
+ including not receiving a DWA within an allotted time frame, no new
requests should be forwarded to the peer, but failover procedures are
invoked. When an active peer is moved to this mode, additional
connections SHOULD be established to ensure that the necessary number
@@ -3284,15 +3231,14 @@ Internet-Draft Diameter Base Protocol January 2011
There are two ways that a peer is removed from the suspect peer list:
-
1. The peer is no longer reachable, causing the transport connection
- to be shutdown. The peer is moved to the closed state.
+ to be shut down. The peer is moved to the closed state.
- 2. Three watchdog messages are exchanged with accepted round trip
+ 2. Three watchdog messages are exchanged with accepted round-trip
times, and the connection to the peer is considered stabilized.
In the event the peer being removed is either the primary or
- secondary, an alternate peer SHOULD replace the deleted peer, and
+ secondary, an alternate peer SHOULD replace the deleted peer and
assume the role of either primary or secondary.
@@ -3300,99 +3246,106 @@ Internet-Draft Diameter Base Protocol January 2011
-Fajardo, et al. Expires July 24, 2011 [Page 59]
+
+Fajardo, et al. Standards Track [Page 58]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
5.2. Diameter Peer Discovery
- Allowing for dynamic Diameter agent discovery will make it possible
- for simpler and more robust deployment of Diameter services. In
- order to promote interoperable implementations of Diameter peer
- discovery, the following mechanisms are described. These are based
- on existing IETF standards. The first option (manual configuration)
- MUST be supported by all Diameter nodes, while the latter option
- (DNS) MAY be supported.
+ Allowing for dynamic Diameter agent discovery makes possible simpler
+ and more robust deployment of Diameter services. In order to promote
+ interoperable implementations of Diameter peer discovery, the
+ following mechanisms (manual configuration and DNS) are described.
+ These are based on existing IETF standards. Both mechanisms MUST be
+ supported by all Diameter implementations; either MAY be used.
There are two cases where Diameter peer discovery may be performed.
The first is when a Diameter client needs to discover a first-hop
Diameter agent. The second case is when a Diameter agent needs to
- discover another agent - for further handling of a Diameter
- operation. In both cases, the following 'search order' is
- recommended:
-
+ discover another agent for further handling of a Diameter operation.
+ In both cases, the following 'search order' is recommended:
- 1. The Diameter implementation consults its list of static
+ 1. The Diameter implementation consults its list of statically
(manually) configured Diameter agent locations. These will be
used if they exist and respond.
-
2. The Diameter implementation performs a NAPTR query for a server
- in a particular realm. The Diameter implementation has to know
- in advance which realm to look for a Diameter agent. This could
- be deduced, for example, from the 'realm' in a NAI that a
- Diameter implementation needed to perform a Diameter operation
- on.
+ in a particular realm. The Diameter implementation has to know,
+ in advance, in which realm to look for a Diameter agent. This
+ could be deduced, for example, from the 'realm' in an NAI on
+ which a Diameter implementation needed to perform a Diameter
+ operation.
The NAPTR usage in Diameter follows the S-NAPTR DDDS application
[RFC3958] in which the SERVICE field includes tags for the
desired application and supported application protocol. The
application service tag for a Diameter application is 'aaa' and
the supported application protocol tags are 'diameter.tcp',
- 'diameter.sctp', 'diameter.dtls' or 'diameter.tls.tcp'.
+ 'diameter.sctp', 'diameter.dtls', or 'diameter.tls.tcp'
+ [RFC6408].
The client can follow the resolution process defined by the
- S-NAPTR DDDS [RFC3958] application to find a matching SRV, A or
+ S-NAPTR DDDS [RFC3958] application to find a matching SRV, A, or
AAAA record of a suitable peer. The domain suffixes in the NAPTR
replacement field SHOULD match the domain of the original query.
An example can be found in Appendix B.
3. If no NAPTR records are found, the requester directly queries for
- SRV records '_diameter._sctp'.realm, '_diameter._dtls'.realm,
- '_diameter._tcp'.realm and '_diameter._tls'.realm depending on
- the requesters network protocol capabilities. If SRV records are
- found then the requester can perform address record query (A RR's
+ one of the following SRV records: for Diameter over TCP, use
+ "_diameter._tcp.realm"; for Diameter over TLS, use
+ "_diameters._tcp.realm"; for Diameter over SCTP, use
+ "_diameter._sctp.realm"; for Diameter over DTLS, use
+ "_diameters._sctp.realm". If SRV records are found, then the
+ requester can perform address record query (A RR's and/or AAAA
+
-Fajardo, et al. Expires July 24, 2011 [Page 60]
+Fajardo, et al. Standards Track [Page 59]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
- and/or AAAA RR's) for the target hostname specified in the SRV
- records. If no SRV records are found, the requester gives up.
+ RR's) for the target hostname specified in the SRV records
+ following the rules given in [RFC2782]. If no SRV records are
+ found, the requester gives up.
If the server is using a site certificate, the domain name in the
NAPTR query and the domain name in the replacement field MUST both be
valid based on the site certificate handed out by the server in the
- TLS/TCP and DTLS/SCTP or IKE exchange. Similarly, the domain name in
- the SRV query and the domain name in the target in the SRV record
- MUST both be valid based on the same site certificate. Otherwise, an
- attacker could modify the DNS records to contain replacement values
- in a different domain, and the client could not validate that this
- was the desired behavior, or the result of an attack.
-
- Also, the Diameter Peer MUST check to make sure that the discovered
+ TLS/TCP and DTLS/SCTP or Internet Key Exchange Protocol (IKE)
+ exchange. Similarly, the domain name in the SRV query and the domain
+ name in the target in the SRV record MUST both be valid based on the
+ same site certificate. Otherwise, an attacker could modify the DNS
+ records to contain replacement values in a different domain, and the
+ client could not validate whether this was the desired behavior or
+ the result of an attack.
+
+ Also, the Diameter peer MUST check to make sure that the discovered
peers are authorized to act in its role. Authentication via IKE or
TLS/TCP and DTLS/SCTP, or validation of DNS RRs via DNSSEC is not
sufficient to conclude this. For example, a web server may have
obtained a valid TLS/TCP and DTLS/SCTP certificate, and secured RRs
may be included in the DNS, but this does not imply that it is
- authorized to act as a Diameter Server.
-
- Authorization can be achieved for example, by configuration of a
- Diameter Server CA. Alternatively this can be achieved by definition
- of OIDs within TLS/TCP and DTLS/SCTP or IKE certificates so as to
- signify Diameter Server authorization.
-
- A dynamically discovered peer causes an entry in the Peer Table (see
+ authorized to act as a Diameter server.
+
+ Authorization can be achieved, for example, by the configuration of a
+ Diameter server Certification Authority (CA). The server CA issues a
+ certificate to the Diameter server, which includes an Object
+ Identifier (OID) to indicate the subject is a Diameter server in the
+ Extended Key Usage extension [RFC5280]. This certificate is then
+ used during TLS/TCP, DTLS/SCTP, or IKE security negotiation.
+ However, note that, at the time of writing, no Diameter server
+ Certification Authorities exist.
+
+ A dynamically discovered peer causes an entry in the peer table (see
Section 2.6) to be created. Note that entries created via DNS MUST
- expire (or be refreshed) within the DNS TTL. If a peer is discovered
- outside of the local realm, a routing table entry (see Section 2.7)
- for the peer's realm is created. The routing table entry's
- expiration MUST match the peer's expiration value.
+ expire (or be refreshed) within the DNS Time to Live (TTL). If a
+ peer is discovered outside of the local realm, a routing table entry
+ (see Section 2.7) for the peer's realm is created. The routing table
+ entry's expiration MUST match the peer's expiration value.
5.3. Capabilities Exchange
@@ -3400,35 +3353,36 @@ Internet-Draft Diameter Base Protocol January 2011
exchange the Capabilities Exchange messages, as specified in the peer
state machine (see Section 5.6). This message allows the discovery
of a peer's identity and its capabilities (protocol version number,
- supported Diameter applications, security mechanisms, etc.)
+ the identifiers of supported Diameter applications, security
+ mechanisms, etc.).
- The receiver only issues commands to its peers that have advertised
- support for the Diameter application that defines the command. A
- Diameter node MUST cache the supported applications in order to
- ensure that unrecognized commands and/or AVPs are not unnecessarily
- sent to a peer.
-
- A receiver of a Capabilities-Exchange-Req (CER) message that does not
-Fajardo, et al. Expires July 24, 2011 [Page 61]
+Fajardo, et al. Standards Track [Page 60]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
- have any applications in common with the sender MUST return a
+ The receiver only issues commands to its peers that have advertised
+ support for the Diameter application that defines the command. A
+ Diameter node MUST cache the supported Application Ids in order to
+ ensure that unrecognized commands and/or AVPs are not unnecessarily
+ sent to a peer.
+
+ A receiver of a Capabilities-Exchange-Request (CER) message that does
+ not have any applications in common with the sender MUST return a
Capabilities-Exchange-Answer (CEA) with the Result-Code AVP set to
- DIAMETER_NO_COMMON_APPLICATION, and SHOULD disconnect the transport
+ DIAMETER_NO_COMMON_APPLICATION and SHOULD disconnect the transport
layer connection. Note that receiving a CER or CEA from a peer
- advertising itself as a Relay (see Section 2.4) MUST be interpreted
+ advertising itself as a relay (see Section 2.4) MUST be interpreted
as having common applications with the peer.
The receiver of the Capabilities-Exchange-Request (CER) MUST
determine common applications by computing the intersection of its
- own set of supported Application Id against all of the application
- identifier AVPs (Auth-Application-Id, Acct-Application-Id and Vendor-
- Specific-Application-Id) present in the CER. The value of the
+ own set of supported Application Ids against all of the
+ Application-Id AVPs (Auth-Application-Id, Acct-Application-Id, and
+ Vendor-Specific-Application-Id) present in the CER. The value of the
Vendor-Id AVP in the Vendor-Specific-Application-Id MUST NOT be used
during computation. The sender of the Capabilities-Exchange-Answer
(CEA) SHOULD include all of its supported applications as a hint to
@@ -3438,12 +3392,13 @@ Internet-Draft Diameter Base Protocol January 2011
and DTLS/SCTP connection prior to the CER/CEA exchange. This
protects the capabilities information of both peers. To support
older Diameter implementations that do not fully conform to this
- document, the transport security MAY still be negotiated via Inband-
- Security AVP. In this case, the receiver of a Capabilities-Exchange-
- Req (CER) message that does not have any security mechanisms in
- common with the sender MUST return a Capabilities-Exchange-Answer
- (CEA) with the Result-Code AVP set to DIAMETER_NO_COMMON_SECURITY,
- and SHOULD disconnect the transport layer connection.
+ document, the transport security MAY still be negotiated via an
+ Inband-Security AVP. In this case, the receiver of a Capabilities-
+ Exchange-Request (CER) message that does not have any security
+ mechanisms in common with the sender MUST return a Capabilities-
+ Exchange-Answer (CEA) with the Result-Code AVP set to
+ DIAMETER_NO_COMMON_SECURITY and SHOULD disconnect the transport layer
+ connection.
CERs received from unknown peers MAY be silently discarded, or a CEA
MAY be issued with the Result-Code AVP set to DIAMETER_UNKNOWN_PEER.
@@ -3455,34 +3410,34 @@ Internet-Draft Diameter Base Protocol January 2011
failure, all the pending transactions destined to the unknown peer
can be discarded.
- The CER and CEA messages MUST NOT be proxied, redirected or relayed.
+ The CER and CEA messages MUST NOT be proxied, redirected, or relayed.
- Since the CER/CEA messages cannot be proxied, it is still possible
- that an upstream agent receives a message for which it has no
- available peers to handle the application that corresponds to the
- Command-Code. In such instances, the 'E' bit is set in the answer
- message (see Section 7.) with the Result-Code AVP set to
- DIAMETER_UNABLE_TO_DELIVER to inform the downstream to take action
- (e.g., re-routing request to an alternate peer).
-
-Fajardo, et al. Expires July 24, 2011 [Page 62]
+Fajardo, et al. Standards Track [Page 61]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
+ Since the CER/CEA messages cannot be proxied, it is still possible
+ that an upstream agent will receive a message for which it has no
+ available peers to handle the application that corresponds to the
+ Command Code. In such instances, the 'E' bit is set in the answer
+ message (Section 7) with the Result-Code AVP set to
+ DIAMETER_UNABLE_TO_DELIVER to inform the downstream agent to take
+ action (e.g., re-routing request to an alternate peer).
+
With the exception of the Capabilities-Exchange-Request message, a
message of type Request that includes the Auth-Application-Id or
Acct-Application-Id AVPs, or a message with an application-specific
- command code, MAY only be forwarded to a host that has explicitly
+ Command Code MAY only be forwarded to a host that has explicitly
advertised support for the application (or has advertised the Relay
Application Id).
5.3.1. Capabilities-Exchange-Request
- The Capabilities-Exchange-Request (CER), indicated by the Command-
+ The Capabilities-Exchange-Request (CER), indicated by the Command
Code set to 257 and the Command Flags' 'R' bit set, is sent to
exchange local capabilities. Upon detection of a transport failure,
this message MUST NOT be sent to an alternate peer.
@@ -3490,7 +3445,7 @@ Internet-Draft Diameter Base Protocol January 2011
When Diameter is run over SCTP [RFC4960] or DTLS/SCTP [RFC6083],
which allow for connections to span multiple interfaces and multiple
IP addresses, the Capabilities-Exchange-Request message MUST contain
- one Host-IP- Address AVP for each potential IP address that MAY be
+ one Host-IP-Address AVP for each potential IP address that MAY be
locally used when transmitting Diameter messages.
Message Format
@@ -3510,9 +3465,20 @@ Internet-Draft Diameter Base Protocol January 2011
[ Firmware-Revision ]
* [ AVP ]
+
+
+
+
+
+
+Fajardo, et al. Standards Track [Page 62]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
5.3.2. Capabilities-Exchange-Answer
- The Capabilities-Exchange-Answer (CEA), indicated by the Command-Code
+ The Capabilities-Exchange-Answer (CEA), indicated by the Command Code
set to 257 and the Command Flags' 'R' bit cleared, is sent in
response to a CER message.
@@ -3522,13 +3488,6 @@ Internet-Draft Diameter Base Protocol January 2011
one Host-IP-Address AVP for each potential IP address that MAY be
locally used when transmitting Diameter messages.
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 63]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
Message Format
<CEA> ::= < Diameter Header: 257 >
@@ -3552,22 +3511,34 @@ Internet-Draft Diameter Base Protocol January 2011
5.3.3. Vendor-Id AVP
The Vendor-Id AVP (AVP Code 266) is of type Unsigned32 and contains
- the IANA "SMI Network Management Private Enterprise Codes" [RFC3232]
- value assigned to the vendor of the Diameter device. It is
+ the IANA "SMI Network Management Private Enterprise Codes"
+ [ENTERPRISE] value assigned to the Diameter Software vendor. It is
envisioned that the combination of the Vendor-Id, Product-Name
- (Section 5.3.7) and the Firmware-Revision (Section 5.3.4) AVPs may
+ (Section 5.3.7), and Firmware-Revision (Section 5.3.4) AVPs may
provide useful debugging information.
- A Vendor-Id value of zero in the CER or CEA messages is reserved and
+ A Vendor-Id value of zero in the CER or CEA message is reserved and
indicates that this field is ignored.
+
+
+
+
+
+
+
+Fajardo, et al. Standards Track [Page 63]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
5.3.4. Firmware-Revision AVP
The Firmware-Revision AVP (AVP Code 267) is of type Unsigned32 and is
used to inform a Diameter peer of the firmware revision of the
issuing device.
- For devices that do not have a firmware revision (general purpose
+ For devices that do not have a firmware revision (general-purpose
computers running Diameter software modules, for instance), the
revision of the Diameter software module may be reported instead.
@@ -3577,77 +3548,70 @@ Internet-Draft Diameter Base Protocol January 2011
to inform a Diameter peer of the sender's IP address. All source
addresses that a Diameter node expects to use with SCTP [RFC4960] or
DTLS/SCTP [RFC6083] MUST be advertised in the CER and CEA messages by
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 64]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
including a Host-IP-Address AVP for each address.
5.3.6. Supported-Vendor-Id AVP
The Supported-Vendor-Id AVP (AVP Code 265) is of type Unsigned32 and
contains the IANA "SMI Network Management Private Enterprise Codes"
- [RFC3232] value assigned to a vendor other than the device vendor but
- including the application vendor. This is used in the CER and CEA
- messages in order to inform the peer that the sender supports (a
- subset of) the vendor-specific AVPs defined by the vendor identified
+ [ENTERPRISE] value assigned to a vendor other than the device vendor
+ but including the application vendor. This is used in the CER and
+ CEA messages in order to inform the peer that the sender supports (a
+ subset of) the Vendor-Specific AVPs defined by the vendor identified
in this AVP. The value of this AVP MUST NOT be set to zero.
Multiple instances of this AVP containing the same value SHOULD NOT
be sent.
5.3.7. Product-Name AVP
- The Product-Name AVP (AVP Code 269) is of type UTF8String, and
- contains the vendor assigned name for the product. The Product-Name
+ The Product-Name AVP (AVP Code 269) is of type UTF8String and
+ contains the vendor-assigned name for the product. The Product-Name
AVP SHOULD remain constant across firmware revisions for the same
product.
-5.4. Disconnecting Peer connections
+5.4. Disconnecting Peer Connections
When a Diameter node disconnects one of its transport connections,
- its peer cannot know the reason for the disconnect, and will most
- likely assume that a connectivity problem occurred, or that the peer
+ its peer cannot know the reason for the disconnect and will most
+ likely assume that a connectivity problem occurred or that the peer
has rebooted. In these cases, the peer may periodically attempt to
reconnect, as stated in Section 2.1. In the event that the
- disconnect was a result of either a shortage of internal resources,
- or simply that the node in question has no intentions of forwarding
- any Diameter messages to the peer in the foreseeable future, a
- periodic connection request would not be welcomed. The
- Disconnection-Reason AVP contains the reason the Diameter node issued
- the Disconnect-Peer-Request message.
+ disconnect was a result of either a shortage of internal resources or
+ simply that the node in question has no intentions of forwarding any
+ Diameter messages to the peer in the foreseeable future, a periodic
- The Disconnect-Peer-Request message is used by a Diameter node to
- inform its peer of its intent to disconnect the transport layer, and
- that the peer shouldn't reconnect unless it has a valid reason to do
- so (e.g., message to be forwarded). Upon receipt of the message, the
- Disconnect-Peer-Answer is returned, which SHOULD contain an error if
- messages have recently been forwarded, and are likely in flight,
- which would otherwise cause a race condition.
- The receiver of the Disconnect-Peer-Answer initiates the transport
- disconnect. The sender of the Disconnect-Peer-Answer should be able
- to detect the transport closure and cleanup the connection.
+Fajardo, et al. Standards Track [Page 64]
+
+RFC 6733 Diameter Base Protocol October 2012
+ connection request would not be welcomed. The Disconnection-Reason
+ AVP contains the reason the Diameter node issued the Disconnect-Peer-
+ Request message.
-Fajardo, et al. Expires July 24, 2011 [Page 65]
-
-Internet-Draft Diameter Base Protocol January 2011
+ The Disconnect-Peer-Request message is used by a Diameter node to
+ inform its peer of its intent to disconnect the transport layer and
+ that the peer shouldn't reconnect unless it has a valid reason to do
+ so (e.g., message to be forwarded). Upon receipt of the message, the
+ Disconnect-Peer-Answer message is returned, which SHOULD contain an
+ error if messages have recently been forwarded, and are likely in
+ flight, which would otherwise cause a race condition.
+ The receiver of the Disconnect-Peer-Answer message initiates the
+ transport disconnect. The sender of the Disconnect-Peer-Answer
+ message should be able to detect the transport closure and clean up
+ the connection.
5.4.1. Disconnect-Peer-Request
- The Disconnect-Peer-Request (DPR), indicated by the Command-Code set
+ The Disconnect-Peer-Request (DPR), indicated by the Command Code set
to 282 and the Command Flags' 'R' bit set, is sent to a peer to
- inform its intentions to shutdown the transport connection. Upon
- detection of a transport failure, this message MUST NOT be sent to an
- alternate peer.
+ inform it of its intentions to shut down the transport connection.
+ Upon detection of a transport failure, this message MUST NOT be sent
+ to an alternate peer.
Message Format
@@ -3659,28 +3623,14 @@ Internet-Draft Diameter Base Protocol January 2011
5.4.2. Disconnect-Peer-Answer
- The Disconnect-Peer-Answer (DPA), indicated by the Command-Code set
+ The Disconnect-Peer-Answer (DPA), indicated by the Command Code set
to 282 and the Command Flags' 'R' bit cleared, is sent as a response
to the Disconnect-Peer-Request message. Upon receipt of this
- message, the transport connection is shutdown.
+ message, the transport connection is shut down.
- Message Format
- <DPA> ::= < Diameter Header: 282 >
- { Result-Code }
- { Origin-Host }
- { Origin-Realm }
- [ Error-Message ]
- [ Failed-AVP ]
- * [ AVP ]
-5.4.3. Disconnect-Cause AVP
- The Disconnect-Cause AVP (AVP Code 273) is of type Enumerated. A
- Diameter node MUST include this AVP in the Disconnect-Peer-Request
- message to inform the peer of the reason for its intention to
- shutdown the transport connection. The following values are
- supported:
@@ -3689,29 +3639,44 @@ Internet-Draft Diameter Base Protocol January 2011
+Fajardo, et al. Standards Track [Page 65]
+
+RFC 6733 Diameter Base Protocol October 2012
+ Message Format
+
+ <DPA> ::= < Diameter Header: 282 >
+ { Result-Code }
+ { Origin-Host }
+ { Origin-Realm }
+ [ Error-Message ]
+ [ Failed-AVP ]
+ * [ AVP ]
-Fajardo, et al. Expires July 24, 2011 [Page 66]
-
-Internet-Draft Diameter Base Protocol January 2011
+5.4.3. Disconnect-Cause AVP
+
+ The Disconnect-Cause AVP (AVP Code 273) is of type Enumerated. A
+ Diameter node MUST include this AVP in the Disconnect-Peer-Request
+ message to inform the peer of the reason for its intention to shut
+ down the transport connection. The following values are supported:
- REBOOTING 0
- A scheduled reboot is imminent. Receiver of DPR with above result
- code MAY attempt reconnection.
+ REBOOTING 0
+ A scheduled reboot is imminent. A receiver of a DPR with
+ above result code MAY attempt reconnection.
- BUSY 1
- The peer's internal resources are constrained, and it has
- determined that the transport connection needs to be closed.
- Receiver of DPR with above result code SHOULD NOT attempt
- reconnection.
+ BUSY 1
+ The peer's internal resources are constrained, and it has
+ determined that the transport connection needs to be closed.
+ A receiver of a DPR with above result code SHOULD NOT attempt
+ reconnection.
- DO_NOT_WANT_TO_TALK_TO_YOU 2
- The peer has determined that it does not see a need for the
- transport connection to exist, since it does not expect any
- messages to be exchanged in the near future. Receiver of DPR
- with above result code SHOULD NOT attempt reconnection.
+ DO_NOT_WANT_TO_TALK_TO_YOU 2
+ The peer has determined that it does not see a need for the
+ transport connection to exist, since it does not expect any
+ messages to be exchanged in the near future. A receiver of a
+ DPR with above result code SHOULD NOT attempt reconnection.
5.5. Transport Failure Detection
@@ -3723,9 +3688,21 @@ Internet-Draft Diameter Base Protocol January 2011
Watchdog-Answer messages, defined in this section, are used to pro-
actively detect transport failures.
+
+
+
+
+
+
+
+Fajardo, et al. Standards Track [Page 66]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
5.5.1. Device-Watchdog-Request
- The Device-Watchdog-Request (DWR), indicated by the Command-Code set
+ The Device-Watchdog-Request (DWR), indicated by the Command Code set
to 280 and the Command Flags' 'R' bit set, is sent to a peer when no
traffic has been exchanged between two peers (see Section 5.5.3).
Upon detection of a transport failure, this message MUST NOT be sent
@@ -3741,18 +3718,10 @@ Internet-Draft Diameter Base Protocol January 2011
5.5.2. Device-Watchdog-Answer
- The Device-Watchdog-Answer (DWA), indicated by the Command-Code set
+ The Device-Watchdog-Answer (DWA), indicated by the Command Code set
to 280 and the Command Flags' 'R' bit cleared, is sent as a response
to the Device-Watchdog-Request message.
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 67]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
Message Format
<DWA> ::= < Diameter Header: 280 >
@@ -3767,7 +3736,7 @@ Internet-Draft Diameter Base Protocol January 2011
5.5.3. Transport Failure Algorithm
The transport failure algorithm is defined in [RFC3539]. All
- Diameter implementations MUST support the algorithm defined in the
+ Diameter implementations MUST support the algorithm defined in that
specification in order to be compliant to the Diameter base protocol.
5.5.4. Failover and Failback Procedures
@@ -3775,7 +3744,17 @@ Internet-Draft Diameter Base Protocol January 2011
In the event that a transport failure is detected with a peer, it is
necessary for all pending request messages to be forwarded to an
alternate agent, if possible. This is commonly referred to as
- failover.
+ "failover".
+
+
+
+
+
+
+Fajardo, et al. Standards Track [Page 67]
+
+RFC 6733 Diameter Base Protocol October 2012
+
In order for a Diameter node to perform failover procedures, it is
necessary for the node to maintain a pending message queue for a
@@ -3783,16 +3762,16 @@ Internet-Draft Diameter Base Protocol January 2011
request is removed from the queue. The Hop-by-Hop Identifier field
is used to match the answer with the queued request.
- When a transport failure is detected, if possible all messages in the
- queue are sent to an alternate agent with the T flag set. On booting
- a Diameter client or agent, the T flag is also set on any records
- still remaining to be transmitted in non-volatile storage. An
- example of a case where it is not possible to forward the message to
- an alternate server is when the message has a fixed destination, and
- the unavailable peer is the message's final destination (see
- Destination-Host AVP). Such an error requires that the agent return
- an answer message with the 'E' bit set and the Result-Code AVP set to
- DIAMETER_UNABLE_TO_DELIVER.
+ When a transport failure is detected, if possible, all messages in
+ the queue are sent to an alternate agent with the T flag set. On
+ booting a Diameter client or agent, the T flag is also set on any
+ remaining records in non-volatile storage that are still waiting to
+ be transmitted. An example of a case where it is not possible to
+ forward the message to an alternate server is when the message has a
+ fixed destination, and the unavailable peer is the message's final
+ destination (see Destination-Host AVP). Such an error requires that
+ the agent return an answer message with the 'E' bit set and the
+ Result-Code AVP set to DIAMETER_UNABLE_TO_DELIVER.
It is important to note that multiple identical requests or answers
MAY be received as a result of a failover. The End-to-End Identifier
@@ -3801,17 +3780,9 @@ Internet-Draft Diameter Base Protocol January 2011
As described in Section 2.1, a connection request should be
periodically attempted with the failed peer in order to re-establish
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 68]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
the transport connection. Once a connection has been successfully
established, messages can once again be forwarded to the peer. This
- is commonly referred to as failback.
+ is commonly referred to as "failback".
5.6. Peer State Machine
@@ -3824,16 +3795,24 @@ Internet-Draft Diameter Base Protocol January 2011
This state machine is closely coupled with the state machine
described in [RFC3539], which is used to open, close, failover,
- probe, and reopen transport connections. Note in particular that
+ probe, and reopen transport connections. In particular, note that
[RFC3539] requires the use of watchdog messages to probe connections.
For Diameter, DWR and DWA messages are to be used.
- I- is used to represent the initiator (connecting) connection, while
- the R- is used to represent the responder (listening) connection.
- The lack of a prefix indicates that the event or action is the same
- regardless of the connection on which the event occurred.
+ The I- prefix is used to represent the initiator (connecting)
+ connection, while the R- prefix is used to represent the responder
+ (listening) connection. The lack of a prefix indicates that the
+ event or action is the same regardless of the connection on which the
+ event occurred.
+
+
+
+Fajardo, et al. Standards Track [Page 68]
+
+RFC 6733 Diameter Base Protocol October 2012
+
- The stable states that a state machine may be in are Closed, I-Open
+ The stable states that a state machine may be in are Closed, I-Open,
and R-Open; all other states are intermediate. Note that I-Open and
R-Open are equivalent except for whether the initiator or responder
transport connection is used for communication.
@@ -3848,23 +3827,15 @@ Internet-Draft Diameter Base Protocol January 2011
the results of an election on one peer are guaranteed to be the
inverse of the results on the other.
- For TLS/TCP and DTLS/SCTP usage, TLS/TCP and DTLS/SCTP handshake
+ For TLS/TCP and DTLS/SCTP usage, a TLS/TCP and DTLS/SCTP handshake
SHOULD begin when both ends are in the closed state prior to any
Diameter message exchanges. The TLS/TCP and DTLS/SCTP connection
SHOULD be established before sending any CER or CEA message to secure
and protect the capabilities information of both peers. The TLS/TCP
and DTLS/SCTP connection SHOULD be disconnected when the state
machine moves to the closed state. When connecting to responders
- that do not conform to this document (i.e. older Diameter
+ that do not conform to this document (i.e., older Diameter
implementations that are not prepared to received TLS/TCP and DTLS/
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 69]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
SCTP connections in the closed state), the initial TLS/TCP and DTLS/
SCTP connection attempt will fail. The initiator MAY then attempt to
connect via TCP or SCTP and initiate the TLS/TCP and DTLS/SCTP
@@ -3878,6 +3849,25 @@ Internet-Draft Diameter Base Protocol January 2011
Any implementation that produces equivalent results is considered
compliant.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Fajardo, et al. Standards Track [Page 69]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
state event action next state
-----------------------------------------------------------------
Closed Start I-Snd-Conn-Req Wait-Conn-Ack
@@ -3914,13 +3904,6 @@ Internet-Draft Diameter Base Protocol January 2011
R-Conn-CER R-Reject Wait-Returns
Timeout Error Closed
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 70]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
R-Open Send-Message R-Snd-Message R-Open
R-Rcv-Message Process R-Open
R-Rcv-DWR Process-DWR, R-Open
@@ -3928,10 +3911,19 @@ Internet-Draft Diameter Base Protocol January 2011
R-Rcv-DWA Process-DWA R-Open
R-Conn-CER R-Reject R-Open
Stop R-Snd-DPR Closing
- R-Rcv-DPR R-Snd-DPA, Closed
- R-Disc
+ R-Rcv-DPR R-Snd-DPA Closing
R-Peer-Disc R-Disc Closed
+
+
+
+
+
+Fajardo, et al. Standards Track [Page 70]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
I-Open Send-Message I-Snd-Message I-Open
I-Rcv-Message Process I-Open
I-Rcv-DWR Process-DWR, I-Open
@@ -3939,8 +3931,7 @@ Internet-Draft Diameter Base Protocol January 2011
I-Rcv-DWA Process-DWA I-Open
R-Conn-CER R-Reject I-Open
Stop I-Snd-DPR Closing
- I-Rcv-DPR I-Snd-DPA, Closed
- I-Disc
+ I-Rcv-DPR I-Snd-DPA Closing
I-Peer-Disc I-Disc Closed
Closing I-Rcv-DPA I-Disc Closed
@@ -3949,88 +3940,44 @@ Internet-Draft Diameter Base Protocol January 2011
I-Peer-Disc I-Disc Closed
R-Peer-Disc R-Disc Closed
-5.6.1. Incoming connections
+5.6.1. Incoming Connections
When a connection request is received from a Diameter peer, it is
not, in the general case, possible to know the identity of that peer
until a CER is received from it. This is because host and port
- determine the identity of a Diameter peer; and the source port of an
- incoming connection is arbitrary. Upon receipt of CER, the identity
- of the connecting peer can be uniquely determined from Origin-Host.
+ determine the identity of a Diameter peer; the source port of an
+ incoming connection is arbitrary. Upon receipt of a CER, the
+ identity of the connecting peer can be uniquely determined from the
+ Origin-Host.
For this reason, a Diameter peer must employ logic separate from the
state machine to receive connection requests, accept them, and await
- CER. Once CER arrives on a new connection, the Origin-Host that
- identifies the peer is used to locate the state machine associated
- with that peer, and the new connection and CER are passed to the
- state machine as an R-Conn-CER event.
+ the CER. Once the CER arrives on a new connection, the Origin-Host
+ that identifies the peer is used to locate the state machine
+ associated with that peer, and the new connection and CER are passed
+ to the state machine as an R-Conn-CER event.
The logic that handles incoming connections SHOULD close and discard
- the connection if any message other than CER arrives, or if an
+ the connection if any message other than a CER arrives or if an
implementation-defined timeout occurs prior to receipt of CER.
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 71]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
Because handling of incoming connections up to and including receipt
- of CER requires logic, separate from that of any individual state
+ of a CER requires logic, separate from that of any individual state
machine associated with a particular peer, it is described separately
in this section rather than in the state machine above.
5.6.2. Events
Transitions and actions in the automaton are caused by events. In
- this section, we will ignore the -I and -R prefix, since the actual
- event would be identical, but would occur on one of two possible
+ this section, we will ignore the I- and R- prefixes, since the actual
+ event would be identical, but it would occur on one of two possible
connections.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 72]
+Fajardo, et al. Standards Track [Page 71]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
Start The Diameter application has signaled that a
@@ -4053,7 +4000,8 @@ Internet-Draft Diameter Base Protocol January 2011
Rcv-CEA A CEA message from the peer was received.
- Rcv-Non-CEA A message other than CEA from the peer was received.
+ Rcv-Non-CEA A message, other than a CEA, from the peer was
+ received.
Peer-Disc A disconnection indication from the peer was received.
@@ -4066,7 +4014,7 @@ Internet-Draft Diameter Base Protocol January 2011
Send-Message A message is to be sent.
- Rcv-Message A message other than CER, CEA, DPR, DPA, DWR or DWA
+ Rcv-Message A message other than CER, CEA, DPR, DPA, DWR, or DWA
was received.
Stop The Diameter application has signaled that a
@@ -4077,16 +4025,15 @@ Internet-Draft Diameter Base Protocol January 2011
Actions in the automaton are caused by events and typically indicate
the transmission of packets and/or an action to be taken on the
- connection. In this section we will ignore the I- and R-prefix,
- since the actual action would be identical, but would occur on one of
- two possible connections.
-
+ connection. In this section, we will ignore the I- and R- prefixes,
+ since the actual action would be identical, but it would occur on one
+ of two possible connections.
-Fajardo, et al. Expires July 24, 2011 [Page 73]
+Fajardo, et al. Standards Track [Page 72]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
Snd-Conn-Req A transport connection is initiated with the peer.
@@ -4098,11 +4045,12 @@ Internet-Draft Diameter Base Protocol January 2011
is disconnected.
Process-CER The CER associated with the R-Conn-CER is processed.
+
Snd-CER A CER message is sent to the peer.
Snd-CEA A CEA message is sent to the peer.
- Cleanup If necessary, the connection is shutdown, and any
+ Cleanup If necessary, the connection is shut down, and any
local resources are freed.
Error The transport layer connection is disconnected,
@@ -4139,10 +4087,9 @@ Internet-Draft Diameter Base Protocol January 2011
-
-Fajardo, et al. Expires July 24, 2011 [Page 74]
+Fajardo, et al. Standards Track [Page 73]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
5.6.4. The Election Process
@@ -4150,134 +4097,97 @@ Internet-Draft Diameter Base Protocol January 2011
The election is performed on the responder. The responder compares
the Origin-Host received in the CER with its own Origin-Host as two
streams of octets. If the local Origin-Host lexicographically
- succeeds the received Origin-Host a Win-Election event is issued
- locally. Diameter identities are in ASCII form therefore the lexical
- comparison is consistent with DNS case insensitivity where octets
- that fall in the ASCII range 'a' through 'z' MUST compare equally to
- their upper-case counterparts between 'A' and 'Z'. See Appendix D
- for interactions between the Diameter protocol and Internationalized
- Domain Name (IDNs).
+ succeeds the received Origin-Host, a Win-Election event is issued
+ locally. Diameter identities are in ASCII form; therefore, the
+ lexical comparison is consistent with DNS case insensitivity, where
+ octets that fall in the ASCII range 'a' through 'z' MUST compare
+ equally to their uppercase counterparts between 'A' and 'Z'. See
+ Appendix D for interactions between the Diameter protocol and
+ Internationalized Domain Name (IDNs).
The winner of the election MUST close the connection it initiated.
Historically, maintaining the responder side of a connection was more
efficient than maintaining the initiator side. However, current
practices makes this distinction irrelevant.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 75]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
-6. Diameter message processing
+6. Diameter Message Processing
This section describes how Diameter requests and answers are created
and processed.
6.1. Diameter Request Routing Overview
- A request is sent towards its final destination using a combination
- of the Destination-Realm and Destination-Host AVPs, in one of these
- three combinations:
+ A request is sent towards its final destination using one of the
+ following three combinations of the Destination-Realm and
+ Destination-Host AVPs:
- o a request that is not able to be proxied (such as CER) MUST NOT
+ o A request that is not able to be proxied (such as a CER) MUST NOT
contain either Destination-Realm or Destination-Host AVPs.
- o a request that needs to be sent to a home server serving a
+ o A request that needs to be sent to a home server serving a
specific realm, but not to a specific server (such as the first
- request of a series of round-trips), MUST contain a Destination-
- Realm AVP, but MUST NOT contain a Destination-Host AVP. For
+ request of a series of round trips), MUST contain a Destination-
+ Realm AVP but MUST NOT contain a Destination-Host AVP. For
Diameter clients, the value of the Destination-Realm AVP MAY be
extracted from the User-Name AVP, or other methods.
- o otherwise, a request that needs to be sent to a specific home
- server among those serving a given realm, MUST contain both the
+ o Otherwise, a request that needs to be sent to a specific home
+ server among those serving a given realm MUST contain both the
Destination-Realm and Destination-Host AVPs.
The Destination-Host AVP is used as described above when the
destination of the request is fixed, which includes:
- o Authentication requests that span multiple round trips
+ o Authentication requests that span multiple round trips.
+
+
+
+
+Fajardo, et al. Standards Track [Page 74]
+
+RFC 6733 Diameter Base Protocol October 2012
+
o A Diameter message that uses a security mechanism that makes use
of a pre-established session key shared between the source and the
final destination of the message.
- o Server initiated messages that MUST be received by a specific
+ o Server-initiated messages that MUST be received by a specific
Diameter client (e.g., access device), such as the Abort-Session-
Request message, which is used to request that a particular user's
session be terminated.
- Note that an agent can forward a request to a host described in the
- Destination-Host AVP only if the host in question is included in its
- peer table (see Section 2.7). Otherwise, the request is routed based
- on the Destination-Realm only (see Sections 6.1.6).
+ Note that an agent can only forward a request to a host described in
+ the Destination-Host AVP if the host in question is included in its
+ peer table (see Section 2.6). Otherwise, the request is routed based
+ on the Destination-Realm only (see Section 6.1.6).
When a message is received, the message is processed in the following
order:
-
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 76]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
o If the message is destined for the local host, the procedures
listed in Section 6.1.4 are followed.
o If the message is intended for a Diameter peer with whom the local
host is able to directly communicate, the procedures listed in
- Section 6.1.5 are followed. This is known as Request Forwarding.
+ Section 6.1.5 are followed. This is known as "Request
+ Forwarding".
- o The procedures listed in Section 6.1.6 are followed, which is
- known as Request Routing.
+ o The procedure listed in Section 6.1.6 is followed, which is known
+ as "Request Routing".
- o If none of the above is successful, an answer is returned with the
- Result-Code set to DIAMETER_UNABLE_TO_DELIVER, with the E-bit set.
+ o If none of the above are successful, an answer is returned with
+ the Result-Code set to DIAMETER_UNABLE_TO_DELIVER, with the 'E'
+ bit set.
For routing of Diameter messages to work within an administrative
domain, all Diameter nodes within the realm MUST be peers.
- Note the processing rules contained in this section are intended to
- be used as general guidelines to Diameter developers. Certain
- implementations MAY use different methods than the ones described
- here, and still comply with the protocol specification. See Section
- 7 for more detail on error handling.
+ The overview contained in this section (6.1) is intended to provide
+ general guidelines to Diameter developers. Implementations are free
+ to use different methods than the ones described here as long as they
+ conform to the requirements specified in Sections 6.1.1 through
+ 6.1.9. See Section 7 for more details on error handling.
6.1.1. Originating a Request
@@ -4285,33 +4195,35 @@ Internet-Draft Diameter Base Protocol January 2011
described in the application definition for that specific request,
the following procedures MUST be followed:
- o the Command-Code is set to the appropriate value
- o the 'R' bit is set
- o the End-to-End Identifier is set to a locally unique value
- o the Origin-Host and Origin-Realm AVPs MUST be set to the
- appropriate values, used to identify the source of the message
- o the Destination-Host and Destination-Realm AVPs MUST be set to the
- appropriate values as described in Section 6.1.
+Fajardo, et al. Standards Track [Page 75]
+
+RFC 6733 Diameter Base Protocol October 2012
-6.1.2. Sending a Request
- When sending a request, originated either locally, or as the result
- of a forwarding or routing operation, the following procedures SHOULD
- be followed:
+ o the Command Code is set to the appropriate value;
- o The Hop-by-Hop Identifier SHOULD be set to a locally unique value.
+ o the 'R' bit is set;
+ o the End-to-End Identifier is set to a locally unique value;
+ o the Origin-Host and Origin-Realm AVPs MUST be set to the
+ appropriate values, used to identify the source of the message;
+ and
+ o the Destination-Host and Destination-Realm AVPs MUST be set to the
+ appropriate values, as described in Section 6.1.
-Fajardo, et al. Expires July 24, 2011 [Page 77]
-
-Internet-Draft Diameter Base Protocol January 2011
+6.1.2. Sending a Request
+ When sending a request, originated either locally or as the result of
+ a forwarding or routing operation, the following procedures SHOULD be
+ followed:
+
+ o The Hop-by-Hop Identifier SHOULD be set to a locally unique value.
o The message SHOULD be saved in the list of pending requests.
@@ -4328,25 +4240,34 @@ Internet-Draft Diameter Base Protocol January 2011
6.1.4. Processing Local Requests
A request is known to be for local consumption when one of the
- following conditions occur:
+ following conditions occurs:
- o The Destination-Host AVP contains the local host's identity,
+ o The Destination-Host AVP contains the local host's identity;
o The Destination-Host AVP is not present, the Destination-Realm AVP
contains a realm the server is configured to process locally, and
- the Diameter application is locally supported, or
+ the Diameter application is locally supported; or
o Both the Destination-Host and the Destination-Realm are not
present.
+
+
+
+
+Fajardo, et al. Standards Track [Page 76]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
When a request is locally processed, the rules in Section 6.2 should
be used to generate the corresponding answer.
6.1.5. Request Forwarding
- Request forwarding is done using the Diameter Peer Table. The
- Diameter peer table contains all of the peers that the local node is
- able to directly communicate with.
+ Request forwarding is done using the Diameter peer table. The
+ Diameter peer table contains all of the peers with which the local
+ node is able to directly communicate.
When a request is received, and the host encoded in the Destination-
Host AVP is one that is present in the peer table, the message SHOULD
@@ -4354,29 +4275,21 @@ Internet-Draft Diameter Base Protocol January 2011
6.1.6. Request Routing
- Diameter request message routing is done via realms and application
- identifiers. A Diameter message that may be forwarded by Diameter
- agents (proxies, redirect or relay agents) MUST include the target
+ Diameter request message routing is done via realms and Application
+ Ids. A Diameter message that may be forwarded by Diameter agents
+ (proxies, redirect agents, or relay agents) MUST include the target
realm in the Destination-Realm AVP. Request routing SHOULD rely on
the Destination-Realm AVP and the Application Id present in the
request message header to aid in the routing decision. The realm MAY
be retrieved from the User-Name AVP, which is in the form of a
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 78]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
Network Access Identifier (NAI). The realm portion of the NAI is
inserted in the Destination-Realm AVP.
Diameter agents MAY have a list of locally supported realms and
- applications, and MAY have a list of externally supported realms and
- applications. When a request is received that includes a realm
+ applications, and they MAY have a list of externally supported realms
+ and applications. When a request is received that includes a realm
and/or application that is not locally supported, the message is
- routed to the peer configured in the Routing Table (see Section 2.7).
+ routed to the peer configured in the routing table (see Section 2.7).
Realm names and Application Ids are the minimum supported routing
criteria, additional information may be needed to support redirect
@@ -4385,13 +4298,23 @@ Internet-Draft Diameter Base Protocol January 2011
6.1.7. Predictive Loop Avoidance
Before forwarding or routing a request, Diameter agents, in addition
- to processing done in Section 6.1.3, SHOULD check for the presence of
- candidate route's peer identity in any of the Route-Record AVPs. In
- an event of the agent detecting the presence of a candidate route's
- peer identity in a Route-Record AVP, the agent MUST ignore such route
- for the Diameter request message and attempt alternate routes if any.
- In case all the candidate routes are eliminated by the above
- criteria, the agent SHOULD return DIAMETER_UNABLE_TO_DELIVER message.
+ to performing the processing described in Section 6.1.3, SHOULD check
+ for the presence of a candidate route's peer identity in any of the
+ Route-Record AVPs. In the event of the agent detecting the presence
+ of a candidate route's peer identity in a Route-Record AVP, the agent
+ MUST ignore such a route for the Diameter request message and attempt
+ alternate routes if any exist. In case all the candidate routes are
+ eliminated by the above criteria, the agent SHOULD return a
+ DIAMETER_UNABLE_TO_DELIVER message.
+
+
+
+
+
+Fajardo, et al. Standards Track [Page 77]
+
+RFC 6733 Diameter Base Protocol October 2012
+
6.1.8. Redirecting Requests
@@ -4399,7 +4322,7 @@ Internet-Draft Diameter Base Protocol January 2011
to REDIRECT, it MUST reply with an answer message with the 'E' bit
set, while maintaining the Hop-by-Hop Identifier in the header, and
include the Result-Code AVP to DIAMETER_REDIRECT_INDICATION. Each of
- the servers associated with the routing entry are added in separate
+ the servers associated with the routing entry are added in a separate
Redirect-Host AVP.
+------------------+
@@ -4417,21 +4340,13 @@ Internet-Draft Diameter Base Protocol January 2011
| Agent |<-------------| Server |
+-------------+ 4. Answer +-------------+
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 79]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
Figure 5: Diameter Redirect Agent
- The receiver of the answer message with the 'E' bit set, and the
- Result-Code AVP set to DIAMETER_REDIRECT_INDICATION uses the hop-by-
- hop field in the Diameter header to identify the request in the
- pending message queue (see Section 5.3) that is to be redirected. If
- no transport connection exists with the new agent, one is created,
+ The receiver of an answer message with the 'E' bit set and the
+ Result-Code AVP set to DIAMETER_REDIRECT_INDICATION uses the Hop-by-
+ Hop Identifier in the Diameter header to identify the request in the
+ pending message queue (see Section 5.5.4) that is to be redirected.
+ If no transport connection exists with the new peer, one is created,
and the request is sent directly to it.
Multiple Redirect-Host AVPs are allowed. The receiver of the answer
@@ -4440,17 +4355,26 @@ Internet-Draft Diameter Base Protocol January 2011
When the Redirect-Host-Usage AVP included in the answer message has a
non-zero value, a route entry for the redirect indications is created
- and cached by the receiver. The redirect usage for such route entry
- is set by the value of Redirect-Host-Usage AVP and the lifetime of
- the cached route entry is set by Redirect-Max-Cache-Time AVP value.
+ and cached by the receiver. The redirect usage for such a route
+ entry is set by the value of Redirect-Host-Usage AVP and the lifetime
+ of the cached route entry is set by Redirect-Max-Cache-Time AVP
+ value.
It is possible that multiple redirect indications can create multiple
cached route entries differing only in their redirect usage and the
peer to forward messages to. As an example, two(2) route entries
that are created by two(2) redirect indications results in two(2)
+
+
+
+Fajardo, et al. Standards Track [Page 78]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
cached routes for the same realm and Application Id. However, one
- has a redirect usage of ALL_SESSION where matching request will be
- forwarded to one peer and the other has a redirect usage of ALL_REALM
+ has a redirect usage of ALL_SESSION, where matching requests will be
+ forwarded to one peer; the other has a redirect usage of ALL_REALM,
where request are forwarded to another peer. Therefore, an incoming
request that matches the realm and Application Id of both routes will
need additional resolution. In such a case, a routing precedence
@@ -4460,32 +4384,24 @@ Internet-Draft Diameter Base Protocol January 2011
6.1.9. Relaying and Proxying Requests
A relay or proxy agent MUST append a Route-Record AVP to all requests
- forwarded. The AVP contains the identity of the peer the request was
- received from.
+ forwarded. The AVP contains the identity of the peer from which the
+ request was received.
- The Hop-by-Hop identifier in the request is saved, and replaced with
- a locally unique value. The source of the request is also saved,
- which includes the IP address, port and protocol.
+ The Hop-by-Hop Identifier in the request is saved and replaced with a
+ locally unique value. The source of the request is also saved, which
+ includes the IP address, port, and protocol.
A relay or proxy agent MAY include the Proxy-Info AVP in requests if
it requires access to any local state information when the
corresponding response is received. The Proxy-Info AVP has security
- implications as state information is distribute to other entities.
- As such, it is RECOMMMENDED to protect the content of the Proxy-Info
- AVP with cryptographic mechanisms, for example by using a keyed
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 80]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
- message digest. Such a mechanism, however, requires the management
- of keys, although only locally at the Diameter server. Still, a full
- description of the management of the keys used to protect the Proxy-
- Info AVP is beyond the scope of this document. Below is a list of
- commonly recommended:
+ implications as state information is distributed to other entities.
+ As such, it is RECOMMENDED that the content of the Proxy-Info AVP be
+ protected with cryptographic mechanisms, for example, by using a
+ keyed message digest such as HMAC-SHA1 [RFC2104]. Such a mechanism,
+ however, requires the management of keys, although only locally at
+ the Diameter server. Still, a full description of the management of
+ the keys used to protect the Proxy-Info AVP is beyond the scope of
+ this document. Below is a list of common recommendations:
o The keys should be generated securely following the randomness
recommendations in [RFC4086].
@@ -4494,32 +4410,39 @@ Internet-Draft Diameter Base Protocol January 2011
least 128 bits in strength.
o The keys should not be used for any other purpose than generating
- and verifying tickets.
+ and verifying instances of the Proxy-Info AVP.
o The keys should be changed regularly.
- o The keys should be changed if the ticket format or cryptographic
+ o The keys should be changed if the AVP format or cryptographic
protection algorithms change.
The message is then forwarded to the next hop, as identified in the
- Routing Table.
+ routing table.
+
+
+
+
+Fajardo, et al. Standards Track [Page 79]
+
+RFC 6733 Diameter Base Protocol October 2012
+
Figure 6 provides an example of message routing using the procedures
listed in these sections.
- (Origin-Host=nas.example.net) (Origin-Host=nas.example.net)
- (Origin-Realm=example.net) (Origin-Realm=example.net)
- (Destination-Realm=example.com) (Destination-
- Realm=example.com)
+ (Origin-Host=nas.example.net) (Origin-Host=nas.example.net)
+ (Origin-Realm=example.net) (Origin-Realm=example.net)
+ (Destination-Realm=example.com) (Destination-Realm=example.com)
(Route-Record=nas.example.net)
- +------+ ------> +------+ ------> +------+
- | | (Request) | | (Request) | |
- | NAS +-------------------+ DRL +-------------------+ HMS |
- | | | | | |
- +------+ <------ +------+ <------ +------+
- example.net (Answer) example.net (Answer) example.com
- (Origin-Host=hms.example.com) (Origin-Host=hms.example.com)
- (Origin-Realm=example.com) (Origin-Realm=example.com)
+ +------+ ------> +------+ ------> +------+
+ | | (Request) | | (Request) | |
+ | NAS +-------------------+ DRL +-------------------+ HMS |
+ | | | | | |
+ +------+ <------ +------+ <------ +------+
+ example.net (Answer) example.net (Answer) example.com
+ (Origin-Host=hms.example.com) (Origin-Host=hms.example.com)
+ (Origin-Realm=example.com) (Origin-Realm=example.com)
Figure 6: Routing of Diameter messages
@@ -4527,15 +4450,7 @@ Internet-Draft Diameter Base Protocol January 2011
incoming messages. At a minimum, validation of the message header
and relevant routing AVPs has to be done when relaying messages.
Proxy agents may optionally perform more in-depth message validation
- for applications it is interested in.
-
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 81]
-
-Internet-Draft Diameter Base Protocol January 2011
-
+ for applications in which it is interested.
6.2. Diameter Answer Processing
@@ -4544,7 +4459,7 @@ Internet-Draft Diameter Base Protocol January 2011
additional procedures that MAY be discussed in the Diameter
application defining the command:
- o The same Hop-by-Hop identifier in the request is used in the
+ o The same Hop-by-Hop Identifier in the request is used in the
answer.
o The local host's identity is encoded in the Origin-Host AVP.
@@ -4561,15 +4476,23 @@ Internet-Draft Diameter Base Protocol January 2011
o Any Proxy-Info AVPs in the request MUST be added to the answer
message, in the same order they were present in the request.
+
+
+
+Fajardo, et al. Standards Track [Page 80]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
o The 'P' bit is set to the same value as the one in the request.
o The same End-to-End identifier in the request is used in the
answer.
- Note that the error messages (see Section 7.3) are also subjected to
+ Note that the error messages (see Section 7) are also subjected to
the above processing rules.
-6.2.1. Processing received Answers
+6.2.1. Processing Received Answers
A Diameter client or proxy MUST match the Hop-by-Hop Identifier in an
answer received against the list of pending requests. The
@@ -4579,31 +4502,23 @@ Internet-Draft Diameter Base Protocol January 2011
6.2.2. Relaying and Proxying Answers
- If the answer is for a request which was proxied or relayed, the
- agent MUST restore the original value of the Diameter header's Hop-
- by-Hop Identifier field.
+ If the answer is for a request that was proxied or relayed, the agent
+ MUST restore the original value of the Diameter header's Hop-by-Hop
+ Identifier field.
If the last Proxy-Info AVP in the message is targeted to the local
Diameter server, the AVP MUST be removed before the answer is
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 82]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
forwarded.
If a relay or proxy agent receives an answer with a Result-Code AVP
indicating a failure, it MUST NOT modify the contents of the AVP.
- Any additional local errors detected SHOULD be logged, but not
+ Any additional local errors detected SHOULD be logged but not
reflected in the Result-Code AVP. If the agent receives an answer
message with a Result-Code AVP indicating success, and it wishes to
modify the AVP to indicate an error, it MUST modify the Result-Code
AVP to contain the appropriate error in the message destined towards
- the access device as well as include the Error-Reporting-Host AVP and
- it MUST issue an STR on behalf of the access device towards the
+ the access device as well as include the Error-Reporting-Host AVP; it
+ MUST also issue an STR on behalf of the access device towards the
Diameter server.
The agent MUST then send the answer to the host that it received the
@@ -4612,10 +4527,19 @@ Internet-Draft Diameter Base Protocol January 2011
6.3. Origin-Host AVP
The Origin-Host AVP (AVP Code 264) is of type DiameterIdentity, and
- MUST be present in all Diameter messages. This AVP identifies the
+ it MUST be present in all Diameter messages. This AVP identifies the
endpoint that originated the Diameter message. Relay agents MUST NOT
modify this AVP.
+
+
+
+
+Fajardo, et al. Standards Track [Page 81]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
The value of the Origin-Host AVP is guaranteed to be unique within a
single host.
@@ -4638,17 +4562,9 @@ Internet-Draft Diameter Base Protocol January 2011
The Destination-Host AVP (AVP Code 293) is of type DiameterIdentity.
This AVP MUST be present in all unsolicited agent initiated messages,
- MAY be present in request messages, and MUST NOT be present in Answer
+ MAY be present in request messages, and MUST NOT be present in answer
messages.
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 83]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
The absence of the Destination-Host AVP will cause a message to be
sent to any Diameter server supporting the application within the
realm specified in Destination-Realm AVP.
@@ -4658,20 +4574,28 @@ Internet-Draft Diameter Base Protocol January 2011
6.6. Destination-Realm AVP
- The Destination-Realm AVP (AVP Code 283) is of type DiameterIdentity,
- and contains the realm the message is to be routed to. The
- Destination-Realm AVP MUST NOT be present in Answer messages.
- Diameter Clients insert the realm portion of the User-Name AVP.
+ The Destination-Realm AVP (AVP Code 283) is of type DiameterIdentity
+ and contains the realm to which the message is to be routed. The
+ Destination-Realm AVP MUST NOT be present in answer messages.
+ Diameter clients insert the realm portion of the User-Name AVP.
Diameter servers initiating a request message use the value of the
Origin-Realm AVP from a previous message received from the intended
target host (unless it is known a priori). When present, the
Destination-Realm AVP is used to perform message routing decisions.
- An ABNF for a request message that includes the Destination-Realm AVP
+ The CCF for a request message that includes the Destination-Realm AVP
SHOULD list the Destination-Realm AVP as a required AVP (an AVP
- indicated as {AVP}) otherwise the message is inherently a non-
+ indicated as {AVP}); otherwise, the message is inherently a non-
routable message.
+
+
+
+Fajardo, et al. Standards Track [Page 82]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
This AVP SHOULD be placed as close to the Diameter header as
possible.
@@ -4692,19 +4616,11 @@ Internet-Draft Diameter Base Protocol January 2011
The Proxy-Info AVP (AVP Code 284) is of type Grouped. This AVP
contains the identity and local state information of the Diameter
node that creates and adds it to a message. The Grouped Data field
- has the following ABNF grammar:
+ has the following CCF grammar:
Proxy-Info ::= < AVP Header: 284 >
{ Proxy-Host }
{ Proxy-State }
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 84]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
* [ AVP ]
6.7.3. Proxy-Host AVP
@@ -4728,10 +4644,18 @@ Internet-Draft Diameter Base Protocol January 2011
Application-Id AVP MUST match the Application Id present in the
Diameter message header.
+
+
+
+Fajardo, et al. Standards Track [Page 83]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
6.9. Acct-Application-Id AVP
The Acct-Application-Id AVP (AVP Code 259) is of type Unsigned32 and
- is used in order to advertise support of the Accounting portion of an
+ is used in order to advertise support of the accounting portion of an
application (see Section 2.4). If present in a message other than
CER and CEA, the value of the Acct-Application-Id AVP MUST match the
Application Id present in the Diameter message header.
@@ -4740,10 +4664,10 @@ Internet-Draft Diameter Base Protocol January 2011
The Inband-Security-Id AVP (AVP Code 299) is of type Unsigned32 and
is used in order to advertise support of the security portion of the
- application. The use of this AVP in CER and CEA messages is no
- longer recommended. Instead, discovery of a Diameter entities
- security capabilities can be done either through static configuration
- or via Diameter Peer Discovery described in Section 5.2.
+ application. The use of this AVP in CER and CEA messages is NOT
+ RECOMMENDED. Instead, discovery of a Diameter entity's security
+ capabilities can be done either through static configuration or via
+ Diameter Peer Discovery as described in Section 5.2.
The following values are supported:
@@ -4753,36 +4677,37 @@ Internet-Draft Diameter Base Protocol January 2011
This peer does not support TLS/TCP and DTLS/SCTP. This is the
default value, if the AVP is omitted.
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 85]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
TLS 1
- This node supports TLS/TCP and DTLS/SCTP security, as defined by
- [RFC5246].
+ This node supports TLS/TCP [RFC5246] and DTLS/SCTP [RFC6083]
+ security.
6.11. Vendor-Specific-Application-Id AVP
The Vendor-Specific-Application-Id AVP (AVP Code 260) is of type
Grouped and is used to advertise support of a vendor-specific
- Diameter Application. Exactly one instance of either Auth-
+ Diameter application. Exactly one instance of either Auth-
Application-Id or Acct-Application-Id AVP MUST be present. The
Application Id carried by either Auth-Application-Id or Acct-
- Application-Id AVP MUST comply with vendor specific Application Id
- assignment described in Sec 11.3. It MUST also match the Application
- Id present in the Diameter header except when used in a CER or CEA
- message.
+ Application-Id AVP MUST comply with vendor-specific Application Id
+ assignment described in Section 11.3. It MUST also match the
+ Application Id present in the Diameter header except when used in a
+ CER or CEA message.
The Vendor-Id AVP is an informational AVP pertaining to the vendor
who may have authorship of the vendor-specific Diameter application.
It MUST NOT be used as a means of defining a completely separate
vendor-specific Application Id space.
+
+
+
+
+Fajardo, et al. Standards Track [Page 84]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
The Vendor-Specific-Application-Id AVP SHOULD be placed as close to
the Diameter header as possible.
@@ -4795,9 +4720,9 @@ Internet-Draft Diameter Base Protocol January 2011
A Vendor-Specific-Application-Id AVP MUST contain exactly one of
either Auth-Application-Id or Acct-Application-Id. If a Vendor-
- Specific-Application-Id is received without any of these two AVPs,
+ Specific-Application-Id is received without one of these two AVPs,
then the recipient SHOULD issue an answer with a Result-Code set to
- DIAMETER_MISSING_AVP. The answer SHOULD also include a Failed-AVP
+ DIAMETER_MISSING_AVP. The answer SHOULD also include a Failed-AVP,
which MUST contain an example of an Auth-Application-Id AVP and an
Acct-Application-Id AVP.
@@ -4805,22 +4730,13 @@ Internet-Draft Diameter Base Protocol January 2011
Auth-Application-Id and Acct-Application-Id, then the recipient MUST
issue an answer with Result-Code set to
DIAMETER_AVP_OCCURS_TOO_MANY_TIMES. The answer MUST also include a
- Failed-AVP which MUST contain the received Auth-Application-Id AVP
+ Failed-AVP, which MUST contain the received Auth-Application-Id AVP
and Acct-Application-Id AVP.
-
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 86]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
6.12. Redirect-Host AVP
The Redirect-Host AVP (AVP Code 292) is of type DiameterURI. One or
- more of instances of this AVP MUST be present if the answer message's
+ more instances of this AVP MUST be present if the answer message's
'E' bit is set and the Result-Code AVP is set to
DIAMETER_REDIRECT_INDICATION.
@@ -4836,63 +4752,55 @@ Internet-Draft Diameter Base Protocol January 2011
This AVP MAY be present in answer messages whose 'E' bit is set and
the Result-Code AVP is set to DIAMETER_REDIRECT_INDICATION.
- When present, this AVP provides a hints about how the routing entry
+ When present, this AVP provides hints about how the routing entry
resulting from the Redirect-Host is to be used. The following values
are supported:
+
+
+Fajardo, et al. Standards Track [Page 85]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
DONT_CACHE 0
The host specified in the Redirect-Host AVP SHOULD NOT be cached.
This is the default value.
-
ALL_SESSION 1
All messages within the same session, as defined by the same value
of the Session-ID AVP SHOULD be sent to the host specified in the
Redirect-Host AVP.
-
ALL_REALM 2
All messages destined for the realm requested SHOULD be sent to
the host specified in the Redirect-Host AVP.
-
REALM_AND_APPLICATION 3
All messages for the application requested to the realm specified
SHOULD be sent to the host specified in the Redirect-Host AVP.
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 87]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
ALL_APPLICATION 4
All messages for the application requested SHOULD be sent to the
host specified in the Redirect-Host AVP.
-
ALL_HOST 5
All messages that would be sent to the host that generated the
Redirect-Host SHOULD be sent to the host specified in the
- Redirect- Host AVP.
-
+ Redirect-Host AVP.
ALL_USER 6
All messages for the user requested SHOULD be sent to the host
specified in the Redirect-Host AVP.
-
-
When multiple cached routes are created by redirect indications and
they differ only in redirect usage and peers to forward requests to
(see Section 6.1.8), a precedence rule MUST be applied to the
@@ -4902,6 +4810,16 @@ Internet-Draft Diameter Base Protocol January 2011
other as they appear. The order is as follows:
+
+
+
+
+
+Fajardo, et al. Standards Track [Page 86]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
1. ALL_SESSION
2. ALL_USER
@@ -4917,58 +4835,31 @@ Internet-Draft Diameter Base Protocol January 2011
6.14. Redirect-Max-Cache-Time AVP
The Redirect-Max-Cache-Time AVP (AVP Code 262) is of type Unsigned32.
- This AVP MUST be present in answer messages whose 'E' bit is set, the
- Result-Code AVP is set to DIAMETER_REDIRECT_INDICATION and the
- Redirect-Host-Usage AVP set to a non-zero value.
-
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 88]
-
-Internet-Draft Diameter Base Protocol January 2011
-
+ This AVP MUST be present in answer messages whose 'E' bit is set,
+ whose Result-Code AVP is set to DIAMETER_REDIRECT_INDICATION, and
+ whose Redirect-Host-Usage AVP set to a non-zero value.
This AVP contains the maximum number of seconds the peer and route
table entries, created as a result of the Redirect-Host, SHOULD be
cached. Note that once a host is no longer reachable, any associated
- cache, peer and routing table entries MUST be deleted.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ cache, peer, and routing table entries MUST be deleted.
+7. Error Handling
+ There are two different types of errors in Diameter; protocol errors
+ and application errors. A protocol error is one that occurs at the
+ base protocol level and MAY require per-hop attention (e.g., a
+ message routing error). Application errors, on the other hand,
+ generally occur due to a problem with a function specified in a
+ Diameter application (e.g., user authentication, missing AVP).
+ Result-Code AVP values that are used to report protocol errors MUST
+ only be present in answer messages whose 'E' bit is set. When a
+ request message is received that causes a protocol error, an answer
+ message is returned with the 'E' bit set, and the Result-Code AVP is
+ set to the appropriate protocol error value. As the answer is sent
+ back towards the originator of the request, each proxy or relay agent
+ MAY take action on the message.
@@ -4980,27 +4871,10 @@ Internet-Draft Diameter Base Protocol January 2011
-Fajardo, et al. Expires July 24, 2011 [Page 89]
+Fajardo, et al. Standards Track [Page 87]
-Internet-Draft Diameter Base Protocol January 2011
-
-
-7. Error Handling
+RFC 6733 Diameter Base Protocol October 2012
- There are two different types of errors in Diameter; protocol and
- application errors. A protocol error is one that occurs at the base
- protocol level, and MAY require per hop attention (e.g., message
- routing error). Application errors, on the other hand, generally
- occur due to a problem with a function specified in a Diameter
- application (e.g., user authentication, missing AVP).
-
- Result-Code AVP values that are used to report protocol errors MUST
- only be present in answer messages whose 'E' bit is set. When a
- request message is received that causes a protocol error, an answer
- message is returned with the 'E' bit set, and the Result-Code AVP is
- set to the appropriate protocol error value. As the answer is sent
- back towards the originator of the request, each proxy or relay agent
- MAY take action on the message.
1. Request +---------+ Link Broken
+-------------------------->|Diameter |----///----+
@@ -5014,7 +4888,7 @@ Internet-Draft Diameter Base Protocol January 2011
| Relay 3 |-----------+
+---------+
- Figure 7: Example of Protocol Error causing answer message
+ Figure 7: Example of Protocol Error Causing Answer Message
Figure 7 provides an example of a message forwarded upstream by a
Diameter relay. When the message is received by Relay 2, and it
@@ -5032,40 +4906,40 @@ Internet-Draft Diameter Base Protocol January 2011
+---------+ 4. Answer +---------+ 3. Answer +---------+
(Missing AVP) (Missing AVP)
- Figure 8: Example of Application Error Answer message
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 90]
-
-Internet-Draft Diameter Base Protocol January 2011
-
+ Figure 8: Example of Application Error Answer Message
Figure 8 provides an example of a Diameter message that caused an
application error. When application errors occur, the Diameter
- entity reporting the error clears the 'R' bit in the Command Flags,
+ entity reporting the error clears the 'R' bit in the Command Flags
and adds the Result-Code AVP with the proper value. Application
- errors do not require any proxy or relay agent involvement, and
- therefore the message would be forwarded back to the originator of
+ errors do not require any proxy or relay agent involvement;
+ therefore, the message would be forwarded back to the originator of
the request.
In the case where the answer message itself contains errors, any
related session SHOULD be terminated by sending an STR or ASR
message. The Termination-Cause AVP in the STR MAY be filled with the
appropriate value to indicate the cause of the error. An application
- MAY also send an application-specific request instead of STR or ASR
- to signal the error in the case where no state is maintained or to
- allow for some form of error recovery with the corresponding Diameter
- entity.
+ MAY also send an application-specific request instead of an STR or
+ ASR message to signal the error in the case where no state is
+ maintained or to allow for some form of error recovery with the
+ corresponding Diameter entity.
+
+
+
+Fajardo, et al. Standards Track [Page 88]
+
+RFC 6733 Diameter Base Protocol October 2012
+
There are certain Result-Code AVP application errors that require
additional AVPs to be present in the answer. In these cases, the
Diameter node that sets the Result-Code AVP to indicate the error
- MUST add the AVPs. Examples are:
+ MUST add the AVPs. Examples are as follows:
o A request with an unrecognized AVP is received with the 'M' bit
- (Mandatory bit) set, causes an answer to be sent with the Result-
- Code AVP set to DIAMETER_AVP_UNSUPPORTED, and the Failed-AVP AVP
+ (Mandatory bit) set causes an answer to be sent with the Result-
+ Code AVP set to DIAMETER_AVP_UNSUPPORTED and the Failed-AVP AVP
containing the offending AVP.
o A request with an AVP that is received with an unrecognized value
@@ -5073,46 +4947,46 @@ Internet-Draft Diameter Base Protocol January 2011
DIAMETER_INVALID_AVP_VALUE, with the Failed-AVP AVP containing the
AVP causing the error.
- o A received command which is missing AVP(s) that are defined as
- required in the commands ABNF; examples are AVPs indicated as
+ o A received command that is missing AVPs that are defined as
+ required in the commands CCF; examples are AVPs indicated as
{AVP}. The receiver issues an answer with the Result-Code set to
- DIAMETER_MISSING_AVP, and creates an AVP with the AVP Code and
+ DIAMETER_MISSING_AVP and creates an AVP with the AVP Code and
other fields set as expected in the missing AVP. The created AVP
- is then added to the Failed- AVP AVP.
+ is then added to the Failed-AVP AVP.
The Result-Code AVP describes the error that the Diameter node
encountered in its processing. In case there are multiple errors,
the Diameter node MUST report only the first error it encountered
- (detected possibly in some implementation dependent order). The
+ (detected possibly in some implementation-dependent order). The
specific errors that can be described by this AVP are described in
the following section.
+7.1. Result-Code AVP
+ The Result-Code AVP (AVP Code 268) is of type Unsigned32 and
+ indicates whether a particular request was completed successfully or
+ an error occurred. All Diameter answer messages in IETF-defined
+ Diameter application specifications MUST include one Result-Code AVP.
+ A non-successful Result-Code AVP (one containing a non-2xxx value
+ other than DIAMETER_REDIRECT_INDICATION) MUST include the Error-
+ Reporting-Host AVP if the host setting the Result-Code AVP is
+ different from the identity encoded in the Origin-Host AVP.
+ The Result-Code data field contains an IANA-managed 32-bit address
+ space representing errors (see Section 11.3.2). Diameter provides
+ the following classes of errors, all identified by the thousands
+ digit in the decimal notation:
-Fajardo, et al. Expires July 24, 2011 [Page 91]
-
-Internet-Draft Diameter Base Protocol January 2011
-7.1. Result-Code AVP
- The Result-Code AVP (AVP Code 268) is of type Unsigned32 and
- indicates whether a particular request was completed successfully or
- whether an error occurred. All Diameter answer messages in IETF
- defined Diameter application specification MUST include one Result-
- Code AVP. A non-successful Result-Code AVP (one containing a non
- 2xxx value other than DIAMETER_REDIRECT_INDICATION) MUST include the
- Error-Reporting-Host AVP if the host setting the Result-Code AVP is
- different from the identity encoded in the Origin-Host AVP.
+Fajardo, et al. Standards Track [Page 89]
+
+RFC 6733 Diameter Base Protocol October 2012
- The Result-Code data field contains an IANA-managed 32-bit address
- space representing errors (see Section 11.4). Diameter provides the
- following classes of errors, all identified by the thousands digit in
- the decimal notation:
o 1xxx (Informational)
@@ -5124,7 +4998,7 @@ Internet-Draft Diameter Base Protocol January 2011
o 5xxx (Permanent Failure)
- A non-recognized class (one whose first digit is not defined in this
+ An unrecognized class (one whose first digit is not defined in this
section) MUST be handled as a permanent failure.
7.1.1. Informational
@@ -5133,7 +5007,6 @@ Internet-Draft Diameter Base Protocol January 2011
requester that a request could not be satisfied, and additional
action is required on its part before access is granted.
-
DIAMETER_MULTI_ROUND_AUTH 1001
This informational error is returned by a Diameter server to
@@ -5141,24 +5014,11 @@ Internet-Draft Diameter Base Protocol January 2011
used requires multiple round trips, and a subsequent request needs
to be issued in order for access to be granted.
-
-
-
-
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 92]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
7.1.2. Success
Errors that fall within the Success category are used to inform a
peer that a request has been successfully completed.
-
DIAMETER_SUCCESS 2001
The request was successfully completed.
@@ -5174,27 +5034,33 @@ Internet-Draft Diameter Base Protocol January 2011
Errors that fall within the Protocol Error category SHOULD be treated
on a per-hop basis, and Diameter proxies MAY attempt to correct the
error, if it is possible. Note that these errors MUST only be used
- in answer messages whose 'E' bit is set. This document omits some
- error codes defined in [RFC3588]. To provide backward compatibility
- with [RFC3588] implementations these error code values are not re-
- used and hence the error codes values enumerated below are non-
- sequential.
+ in answer messages whose 'E' bit is set.
+
+
+Fajardo, et al. Standards Track [Page 90]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
+ DIAMETER_COMMAND_UNSUPPORTED 3001
+
+ This error code is used when a Diameter entity receives a message
+ with a Command Code that it does not support.
+
DIAMETER_UNABLE_TO_DELIVER 3002
- This error is given when Diameter can not deliver the message to
+ This error is given when Diameter cannot deliver the message to
the destination, either because no host within the realm
supporting the required application was available to process the
- request, or because Destination-Host AVP was given without the
+ request or because the Destination-Host AVP was given without the
associated Destination-Realm AVP.
-
DIAMETER_REALM_NOT_SERVED 3003
The intended realm of the request is not recognized.
-
DIAMETER_TOO_BUSY 3004
When returned, a Diameter node SHOULD attempt to send the message
@@ -5202,13 +5068,6 @@ Internet-Draft Diameter Base Protocol January 2011
specific server is requested, and it cannot provide the requested
service.
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 93]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
DIAMETER_LOOP_DETECTED 3005
An agent detected a loop while trying to get the message to the
@@ -5216,121 +5075,110 @@ Internet-Draft Diameter Base Protocol January 2011
if one is available, but the peer reporting the error has
identified a configuration problem.
-
DIAMETER_REDIRECT_INDICATION 3006
A redirect agent has determined that the request could not be
- satisfied locally and the initiator of the request SHOULD direct
+ satisfied locally, and the initiator of the request SHOULD direct
the request directly to the server, whose contact information has
been added to the response. When set, the Redirect-Host AVP MUST
be present.
-
DIAMETER_APPLICATION_UNSUPPORTED 3007
A request was sent for an application that is not supported.
+ DIAMETER_INVALID_HDR_BITS 3008
- DIAMETER_INVALID_BIT_IN_HEADER 3011
+ A request was received whose bits in the Diameter header were set
+ either to an invalid combination or to a value that is
+ inconsistent with the Command Code's definition.
- This error is returned when a reserved bit in the Diameter header
- is set to one (1) or the bits in the Diameter header defined in
- Section 3 are set incorrectly.
- DIAMETER_INVALID_MESSAGE_LENGTH 3012
+Fajardo, et al. Standards Track [Page 91]
+
+RFC 6733 Diameter Base Protocol October 2012
- This error is returned when a request is received with an invalid
- message length.
+ DIAMETER_INVALID_AVP_BITS 3009
+
+ A request was received that included an AVP whose flag bits are
+ set to an unrecognized value or that is inconsistent with the
+ AVP's definition.
+
+ DIAMETER_UNKNOWN_PEER 3010
+
+ A CER was received from an unknown peer.
7.1.4. Transient Failures
Errors that fall within the transient failures category are used to
inform a peer that the request could not be satisfied at the time it
- was received, but MAY be able to satisfy the request in the future.
+ was received but MAY be able to satisfy the request in the future.
Note that these errors MUST be used in answer messages whose 'E' bit
is not set.
-
DIAMETER_AUTHENTICATION_REJECTED 4001
The authentication process for the user failed, most likely due to
an invalid password used by the user. Further attempts MUST only
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 94]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
be tried after prompting the user for a new password.
-
DIAMETER_OUT_OF_SPACE 4002
A Diameter node received the accounting request but was unable to
commit it to stable storage due to a temporary lack of space.
-
ELECTION_LOST 4003
The peer has determined that it has lost the election process and
has therefore disconnected the transport connection.
-
7.1.5. Permanent Failures
Errors that fall within the permanent failures category are used to
- inform the peer that the request failed, and should not be attempted
+ inform the peer that the request failed and should not be attempted
again. Note that these errors SHOULD be used in answer messages
whose 'E' bit is not set. In error conditions where it is not
- possible or efficient to compose application-specific answer grammar
- then answer messages with E-bit set and complying to the grammar
- described in 7.2 MAY also be used for permanent errors.
+ possible or efficient to compose application-specific answer grammar,
+ answer messages with the 'E' bit set and which comply to the grammar
+ described in Section 7.2 MAY also be used for permanent errors.
- To provide backward compatibility with existing implementations that
- follow [RFC3588], some of the error values that have previously been
- used in this category by [RFC3588] will not be re-used. Therefore
- the error values enumerated here may be non-sequential.
- DIAMETER_AVP_UNSUPPORTED 5001
- The peer received a message that contained an AVP that is not
- recognized or supported and was marked with the Mandatory bit. A
- Diameter message with this error MUST contain one or more Failed-
- AVP AVP containing the AVPs that caused the failure.
- DIAMETER_UNKNOWN_SESSION_ID 5002
- The request contained an unknown Session-Id.
+Fajardo, et al. Standards Track [Page 92]
+
+RFC 6733 Diameter Base Protocol October 2012
- DIAMETER_AUTHORIZATION_REJECTED 5003
- A request was received for which the user could not be authorized.
- This error could occur if the service requested is not permitted
+ DIAMETER_AVP_UNSUPPORTED 5001
+ The peer received a message that contained an AVP that is not
+ recognized or supported and was marked with the 'M' (Mandatory)
+ bit. A Diameter message with this error MUST contain one or more
+ Failed-AVP AVPs containing the AVPs that caused the failure.
+ DIAMETER_UNKNOWN_SESSION_ID 5002
-Fajardo, et al. Expires July 24, 2011 [Page 95]
-
-Internet-Draft Diameter Base Protocol January 2011
+ The request contained an unknown Session-Id.
+ DIAMETER_AUTHORIZATION_REJECTED 5003
+ A request was received for which the user could not be authorized.
+ This error could occur if the service requested is not permitted
to the user.
-
DIAMETER_INVALID_AVP_VALUE 5004
The request contained an AVP with an invalid value in its data
portion. A Diameter message indicating this error MUST include
the offending AVPs within a Failed-AVP AVP.
-
DIAMETER_MISSING_AVP 5005
The request did not contain an AVP that is required by the Command
@@ -5340,21 +5188,28 @@ Internet-Draft Diameter Base Protocol January 2011
Vendor-Id if applicable. The value field of the missing AVP
should be of correct minimum length and contain zeroes.
-
DIAMETER_RESOURCES_EXCEEDED 5006
A request was received that cannot be authorized because the user
has already expended allowed resources. An example of this error
- condition is a user that is restricted to one dial-up PPP port,
- attempts to establish a second PPP connection.
-
+ condition is when a user that is restricted to one dial-up PPP
+ port attempts to establish a second PPP connection.
DIAMETER_CONTRADICTING_AVPS 5007
The Home Diameter server has detected AVPs in the request that
- contradicted each other, and is not willing to provide service to
- the user. The Failed-AVP AVPs MUST be present which contains the
- AVPs that contradicted each other.
+ contradicted each other, and it is not willing to provide service
+ to the user. The Failed-AVP AVP MUST be present, which contain
+ the AVPs that contradicted each other.
+
+
+
+
+
+
+Fajardo, et al. Standards Track [Page 93]
+
+RFC 6733 Diameter Base Protocol October 2012
DIAMETER_AVP_NOT_ALLOWED 5008
@@ -5363,22 +5218,12 @@ Internet-Draft Diameter Base Protocol January 2011
Failed-AVP AVP MUST be included and contain a copy of the
offending AVP.
-
DIAMETER_AVP_OCCURS_TOO_MANY_TIMES 5009
A message was received that included an AVP that appeared more
often than permitted in the message definition. The Failed-AVP
AVP MUST be included and contain a copy of the first instance of
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 96]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
- the offending AVP that exceeded the maximum number of occurrences
-
+ the offending AVP that exceeded the maximum number of occurrences.
DIAMETER_NO_COMMON_APPLICATION 5010
@@ -5386,18 +5231,21 @@ Internet-Draft Diameter Base Protocol January 2011
whereby no applications are common between the CER sending peer
and the CER receiving peer.
-
DIAMETER_UNSUPPORTED_VERSION 5011
This error is returned when a request was received, whose version
number is unsupported.
-
DIAMETER_UNABLE_TO_COMPLY 5012
This error is returned when a request is rejected for unspecified
reasons.
+ DIAMETER_INVALID_BIT_IN_HEADER 5013
+
+ This error is returned when a reserved bit in the Diameter header
+ is set to one (1) or the bits in the Diameter header are set
+ incorrectly.
DIAMETER_INVALID_AVP_LENGTH 5014
@@ -5407,56 +5255,41 @@ Internet-Draft Diameter Base Protocol January 2011
value exceeds the message length or is less than the minimum AVP
header length, it is sufficient to include the offending AVP
header and a zero filled payload of the minimum required length
- for the payloads data type. If the AVP is a grouped AVP, the
- grouped AVP header with an empty payload would be sufficient to
+ for the payloads data type. If the AVP is a Grouped AVP, the
+ Grouped AVP header with an empty payload would be sufficient to
indicate the offending AVP. In the case where the offending AVP
header cannot be fully decoded when the AVP length is less than
- 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.
-
-
- DIAMETER_NO_COMMON_SECURITY 5017
-
- This error is returned when a CER message is received, and there
- are no common security mechanisms supported between the peers. A
- Capabilities-Exchange-Answer (CEA) MUST be returned with the
- Result-Code AVP set to DIAMETER_NO_COMMON_SECURITY.
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 97]
+Fajardo, et al. Standards Track [Page 94]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
- DIAMETER_UNKNOWN_PEER 5018
-
- A CER was received from an unknown peer.
-
-
- DIAMETER_COMMAND_UNSUPPORTED 5019
-
- This error code is used when a Diameter entity receives a message
- with a Command Code that it does not support.
-
+ 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.
- DIAMETER_INVALID_HDR_BITS 5020
+ DIAMETER_INVALID_MESSAGE_LENGTH 5015
- A request was received whose bits in the Diameter header were
- either set to an invalid combination, or to a value that is
- inconsistent with the command code's definition.
+ This error is returned when a request is received with an invalid
+ message length.
+ DIAMETER_INVALID_AVP_BIT_COMBO 5016
- DIAMETER_INVALID_AVP_BITS 5021
+ The request contained an AVP with which is not allowed to have the
+ given value in the AVP Flags field. A Diameter message indicating
+ this error MUST include the offending AVPs within a Failed-AVP
+ AVP.
- A request was received that included an AVP whose flag bits are
- set to an unrecognized value, or that is inconsistent with the
- AVP's definition.
+ DIAMETER_NO_COMMON_SECURITY 5017
+ This error is returned when a CER message is received, and there
+ are no common security mechanisms supported between the peers. A
+ Capabilities-Exchange-Answer (CEA) message MUST be returned with
+ the Result-Code AVP set to DIAMETER_NO_COMMON_SECURITY.
7.2. Error Bit
@@ -5465,12 +5298,12 @@ Internet-Draft Diameter Base Protocol January 2011
the 'E' bit MUST NOT be sent as a response to an answer message.
Note that a message with the 'E' bit set is still subjected to the
processing rules defined in Section 6.2. When set, the answer
- message will not conform to the ABNF specification for the command,
- and will instead conform to the following ABNF:
+ message will not conform to the CCF specification for the command;
+ instead, it and will conform to the following CCF:
Message Format
- <answer-message> ::= < Diameter Header: code, ERR [PXY] >
+ <answer-message> ::= < Diameter Header: code, ERR [, PXY] >
0*1< Session-Id >
{ Origin-Host }
{ Origin-Realm }
@@ -5481,16 +5314,16 @@ Internet-Draft Diameter Base Protocol January 2011
[ Failed-AVP ]
[ Experimental-Result ]
* [ Proxy-Info ]
+ * [ AVP ]
-Fajardo, et al. Expires July 24, 2011 [Page 98]
+
+Fajardo, et al. Standards Track [Page 95]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
- * [ AVP ]
-
Note that the code used in the header is the same than the one found
in the request message, but with the 'R' bit cleared and the 'E' bit
set. The 'P' bit in the header is set to the same value as the one
@@ -5499,10 +5332,10 @@ Internet-Draft Diameter Base Protocol January 2011
7.3. Error-Message AVP
The Error-Message AVP (AVP Code 281) is of type UTF8String. It MAY
- accompany a Result-Code AVP as a human readable error message. The
+ accompany a Result-Code AVP as a human-readable error message. The
Error-Message AVP is not intended to be useful in an environment
where error messages are processed automatically. It SHOULD NOT be
- expected that the content of this AVP is parsed by network entities.
+ expected that the content of this AVP be parsed by network entities.
7.4. Error-Reporting-Host AVP
@@ -5511,8 +5344,8 @@ Internet-Draft Diameter Base Protocol January 2011
host that sent the Result-Code AVP to a value other than 2001
(Success), only if the host setting the Result-Code is different from
the one encoded in the Origin-Host AVP. This AVP is intended to be
- used for troubleshooting purposes, and MUST be set when the Result-
- Code AVP indicates a failure.
+ used for troubleshooting purposes, and it MUST be set when the
+ Result-Code AVP indicates a failure.
7.5. Failed-AVP AVP
@@ -5520,43 +5353,44 @@ Internet-Draft Diameter Base Protocol January 2011
debugging information in cases where a request is rejected or not
fully processed due to erroneous information in a specific AVP. The
value of the Result-Code AVP will provide information on the reason
- for the Failed-AVP AVP. A Diameter message SHOULD contain only one
- Failed-AVP that corresponds to the error indicated by the Result-Code
- AVP. For practical purposes, this Failed-AVP would typically refer
- to the first AVP processing error that a Diameter node encounters.
+ for the Failed-AVP AVP. A Diameter answer message SHOULD contain an
+ instance of the Failed-AVP AVP that corresponds to the error
+ indicated by the Result-Code AVP. For practical purposes, this
+ Failed-AVP would typically refer to the first AVP processing error
+ that a Diameter node encounters.
The possible reasons for this AVP are the presence of an improperly
constructed AVP, an unsupported or unrecognized AVP, an invalid AVP
value, the omission of a required AVP, the presence of an explicitly
- excluded AVP (see tables in Section 10), or the presence of two or
- more occurrences of an AVP which is restricted to 0, 1, or 0-1
+ excluded AVP (see tables in Section 10) or the presence of two or
+ more occurrences of an AVP that is restricted to 0, 1, or 0-1
occurrences.
A Diameter message SHOULD contain one Failed-AVP AVP, containing the
entire AVP that could not be processed successfully. If the failure
reason is omission of a required AVP, an AVP with the missing AVP
- code, the missing vendor id, and a zero filled payload of the minimum
+ code, the missing Vendor-Id, and a zero-filled payload of the minimum
required length for the omitted AVP will be added. If the failure
+ reason is an invalid AVP length where the reported length is less
-Fajardo, et al. Expires July 24, 2011 [Page 99]
+Fajardo, et al. Standards Track [Page 96]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
- reason is an invalid AVP length where the reported length is less
than the minimum AVP header length or greater than the reported
- message length, a copy of the offending AVP header and a zero filled
+ message length, a copy of the offending AVP header and a zero-filled
payload of the minimum required length SHOULD be added.
- 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 the grouped
- AVP itself is embedded in yet another grouped AVP and so on. In this
- case, the Failed-AVP MAY contain 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.
+ 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 the
+ grouped AVP itself is embedded in yet another grouped AVP and so on.
+ In this case, the Failed-AVP MAY contain 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.
AVP Format
@@ -5577,7 +5411,7 @@ Internet-Draft Diameter Base Protocol January 2011
{ Experimental-Result-Code }
The Vendor-Id AVP (see Section 5.3.3) in this grouped AVP identifies
- the vendor responsible for the assignment of the result code which
+ the vendor responsible for the assignment of the result code that
follows. All Diameter answer messages defined in vendor-specific
applications MUST include either one Result-Code AVP or one
Experimental-Result AVP.
@@ -5590,23 +5424,24 @@ Internet-Draft Diameter Base Protocol January 2011
It is recommended that vendor-specific result codes follow the same
conventions given for the Result-Code AVP regarding the different
- types of result codes and the handling of errors (for non 2xxx
+ types of result codes and the handling of errors (for non-2xxx
values).
-Fajardo, et al. Expires July 24, 2011 [Page 100]
+
+Fajardo, et al. Standards Track [Page 97]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
8. Diameter User Sessions
In general, Diameter can provide two different types of services to
applications. The first involves authentication and authorization,
- and can optionally make use of accounting. The second only makes use
- of accounting.
+ and it can optionally make use of accounting. The second only makes
+ use of accounting.
When a service makes use of the authentication and/or authorization
portion of an application, and a user requests access to the network,
@@ -5614,27 +5449,28 @@ Internet-Draft Diameter Base Protocol January 2011
auth request is defined in a service-specific Diameter application
(e.g., NASREQ). The request contains a Session-Id AVP, which is used
in subsequent messages (e.g., subsequent authorization, accounting,
- etc) relating to the user's session. The Session-Id AVP is a means
+ etc.) relating to the user's session. The Session-Id AVP is a means
for the client and servers to correlate a Diameter message with a
user session.
- When a Diameter server authorizes a user to use network resources for
- a finite amount of time, and it is willing to extend the
- authorization via a future request, it MUST add the Authorization-
- Lifetime AVP to the answer message. The Authorization-Lifetime AVP
- defines the maximum number of seconds a user MAY make use of the
- resources before another authorization request is expected by the
- server. The Auth-Grace-Period AVP contains the number of seconds
- following the expiration of the Authorization-Lifetime, after which
- the server will release all state information related to the user's
- session. Note that if payment for services is expected by the
- serving realm from the user's home realm, the Authorization-Lifetime
- AVP, combined with the Auth-Grace-Period AVP, implies the maximum
- length of the session the home realm is willing to be fiscally
- responsible for. Services provided past the expiration of the
- Authorization-Lifetime and Auth-Grace-Period AVPs are the
- responsibility of the access device. Of course, the actual cost of
- services rendered is clearly outside the scope of the protocol.
+ When a Diameter server authorizes a user to implement network
+ resources for a finite amount of time, and it is willing to extend
+ the authorization via a future request, it MUST add the
+ Authorization- Lifetime AVP to the answer message. The
+ Authorization-Lifetime AVP defines the maximum number of seconds a
+ user MAY make use of the resources before another authorization
+ request is expected by the server. The Auth-Grace-Period AVP
+ contains the number of seconds following the expiration of the
+ Authorization-Lifetime, after which the server will release all state
+ information related to the user's session. Note that if payment for
+ services is expected by the serving realm from the user's home realm,
+ the Authorization-Lifetime AVP, combined with the Auth-Grace-Period
+ AVP, implies the maximum length of the session for which the home
+ realm is willing to be fiscally responsible. Services provided past
+ the expiration of the Authorization-Lifetime and Auth-Grace-Period
+ AVPs are the responsibility of the access device. Of course, the
+ actual cost of services rendered is clearly outside the scope of the
+ protocol.
An access device that does not expect to send a re-authorization or a
session termination request to the server MAY include the Auth-
@@ -5648,32 +5484,33 @@ Internet-Draft Diameter Base Protocol January 2011
value NO_STATE_MAINTAINED MUST NOT be set in subsequent re-
authorization requests and answers.
- The base protocol does not include any authorization request
-Fajardo, et al. Expires July 24, 2011 [Page 101]
+Fajardo, et al. Standards Track [Page 98]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
+ The base protocol does not include any authorization request
messages, since these are largely application-specific and are
defined in a Diameter application document. However, the base
protocol does define a set of messages that are used to terminate
user sessions. These are used to allow servers that maintain state
information to free resources.
- When a service only makes use of the Accounting portion of the
+ When a service only makes use of the accounting portion of the
Diameter protocol, even in combination with an application, the
Session-Id is still used to identify user sessions. However, the
session termination messages are not used, since a session is
signaled as being terminated by issuing an accounting stop message.
Diameter may also be used for services that cannot be easily
- categorized as authentication, authorization or accounting (e.g.,
- certain 3GPP IMS interfaces). In such cases, the finite state
+ categorized as authentication, authorization, or accounting (e.g.,
+ certain Third Generation Partnership Project Internet Multimedia
+ System (3GPP IMS) interfaces). In such cases, the finite state
machine defined in subsequent sections may not be applicable.
- Therefore, the applications itself MAY need to define its own finite
+ Therefore, the application itself MAY need to define its own finite
state machine. However, such application-specific state machines
SHOULD follow the general state machine framework outlined in this
document such as the use of Session-Id AVPs and the use of STR/STA,
@@ -5681,12 +5518,12 @@ Internet-Draft Diameter Base Protocol January 2011
8.1. Authorization Session State Machine
- This section contains a set of finite state machines, representing
- the life cycle of Diameter sessions, and which MUST be observed by
- all Diameter implementations that make use of the authentication
- and/or authorization portion of a Diameter application. The term
- Service-Specific below refers to a message defined in a Diameter
- application (e.g., Mobile IPv4, NASREQ).
+ This section contains a set of finite state machines, which represent
+ the life cycle of Diameter sessions and which MUST be observed by all
+ Diameter implementations that make use of the authentication and/or
+ authorization portion of a Diameter application. The term "Service-
+ Specific" below refers to a message defined in a Diameter application
+ (e.g., Mobile IPv4, NASREQ).
There are four different authorization session state machines
supported in the Diameter base protocol. The first two describe a
@@ -5700,26 +5537,25 @@ Internet-Draft Diameter Base Protocol January 2011
When a session is moved to the Idle state, any resources that were
allocated for the particular session must be released. Any event not
- listed in the state machines MUST be considered as an error
- condition, and an answer, if applicable, MUST be returned to the
- originator of the message.
+ listed in the state machines MUST be considered an error condition,
+ and an answer, if applicable, MUST be returned to the originator of
+ the message.
- In the case that an application does not support re-auth, the state
-
-Fajardo, et al. Expires July 24, 2011 [Page 102]
+Fajardo, et al. Standards Track [Page 99]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
- transitions related to server-initiated re-auth when both client and
- server session maintains state (e.g., Send RAR, Pending, Receive RAA)
- MAY be ignored.
+ In the case that an application does not support re-auth, the state
+ transitions related to server-initiated re-auth, when both client and
+ server sessions maintain state (e.g., Send RAR, Pending, Receive
+ RAA), MAY be ignored.
- In the state table, the event 'Failure to send X' means that the
+ In the state table, the event "Failure to send X" means that the
Diameter agent is unable to send command X to the desired
- destination. This could be due to the peer being down, or due to the
+ destination. This could be due to the peer being down or due to the
peer sending back a transient failure or temporary protocol error
notification DIAMETER_TOO_BUSY or DIAMETER_LOOP_DETECTED in the
Result-Code AVP of the corresponding Answer command. The event 'X
@@ -5731,8 +5567,8 @@ Internet-Draft Diameter Base Protocol January 2011
CLIENT, STATEFUL
State Event Action New State
---------------------------------------------------------------
- Idle Client or Device Requests Send Pending
- access service
+ Idle Client or device requests Send Pending
+ access service-
specific
auth req
@@ -5748,39 +5584,38 @@ Internet-Draft Diameter Base Protocol January 2011
UNKNOWN_
SESSION_ID
- Pending Successful Service-specific Grant Open
+ Pending Successful service-specific Grant Open
authorization answer Access
received with default
Auth-Session-State value
- Pending Successful Service-specific Sent STR Discon
- authorization answer received
+ Pending Successful service-specific Sent STR Discon
+ authorization answer received,
but service not provided
Pending Error processing successful Sent STR Discon
- Service-specific authorization
+ service-specific authorization
answer
-
-Fajardo, et al. Expires July 24, 2011 [Page 103]
+Fajardo, et al. Standards Track [Page 100]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
- Pending Failed Service-specific Cleanup Idle
+ Pending Failed service-specific Clean up Idle
authorization answer received
Open User or client device Send Open
- requests access to service service
+ requests access to service service-
specific
auth req
- Open Successful Service-specific Provide Open
- authorization answer received Service
+ Open Successful service-specific Provide Open
+ authorization answer received service
- Open Failed Service-specific Discon. Idle
+ Open Failed service-specific Discon. Idle
authorization answer user/device
received.
@@ -5796,10 +5631,10 @@ Internet-Draft Diameter Base Protocol January 2011
Discon.
user/device
- Open Session-Timeout Expires on Send STR Discon
- Access Device
+ Open Session-Timeout expires on Send STR Discon
+ access device
- Open ASR Received, Send ASA Discon
+ Open ASR received, Send ASA Discon
client will comply with
with request to end the Result-Code =
session = SUCCESS,
@@ -5814,17 +5649,18 @@ Internet-Draft Diameter Base Protocol January 2011
Auth-Grace-Period expires on
access device
- Discon ASR Received Send ASA Discon
+ Discon ASR received Send ASA Discon
+
- Discon STA Received Discon. Idle
-Fajardo, et al. Expires July 24, 2011 [Page 104]
+Fajardo, et al. Standards Track [Page 101]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
+ Discon STA received Discon. Idle
user/device
The following state machine is observed by a server when it is
@@ -5835,31 +5671,34 @@ Internet-Draft Diameter Base Protocol January 2011
---------------------------------------------------------------
Idle Service-specific authorization Send Open
request received, and successful
- user is authorized serv.
+ user is authorized service-
specific
answer
Idle Service-specific authorization Send Idle
- request received, and failed serv.
- user is not authorized specific
+ request received, and failed
+ user is not authorized service-
+ specific
answer
Open Service-specific authorization Send Open
request received, and user successful
- is authorized serv. specific
+ is authorized service-
+ specific
answer
Open Service-specific authorization Send Idle
- request received, and user failed serv.
- is not authorized specific
+ request received, and user failed
+ is not authorized service-
+ specific
answer,
- Cleanup
+ Clean up
Open Home server wants to confirm Send RAR Pending
authentication and/or
authorization of the user
- Pending Received RAA with a failed Cleanup Idle
+ Pending Received RAA with a failed Clean up Idle
Result-Code
Pending Received RAA with Result-Code Update Open
@@ -5868,32 +5707,33 @@ Internet-Draft Diameter Base Protocol January 2011
Open Home server wants to Send ASR Discon
terminate the service
- Open Authorization-Lifetime (and Cleanup Idle
- Auth-Grace-Period) expires
- on home server.
- Open Session-Timeout expires on Cleanup Idle
-Fajardo, et al. Expires July 24, 2011 [Page 105]
+Fajardo, et al. Standards Track [Page 102]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
+ Open Authorization-Lifetime (and Clean up Idle
+ Auth-Grace-Period) expires
+ on home server
+
+ Open Session-Timeout expires on Clean up Idle
home server
Discon Failure to send ASR Wait, Discon
resend ASR
- Discon ASR successfully sent and Cleanup Idle
+ Discon ASR successfully sent and Clean up Idle
ASA Received with Result-Code
- Not ASA Received None No Change.
+ Not ASA Received None No Change
Discon
Any STR Received Send STA, Idle
- Cleanup.
+ Clean up
The following state machine is observed by a client when state is not
maintained on the server:
@@ -5901,48 +5741,47 @@ Internet-Draft Diameter Base Protocol January 2011
CLIENT, STATELESS
State Event Action New State
---------------------------------------------------------------
- Idle Client or Device Requests Send Pending
- access service
+ Idle Client or device requests Send Pending
+ access service-
specific
auth req
- Pending Successful Service-specific Grant Open
- authorization answer Access
+ Pending Successful service-specific Grant Open
+ authorization answer access
received with Auth-Session-
State set to
NO_STATE_MAINTAINED
- Pending Failed Service-specific Cleanup Idle
+ Pending Failed service-specific Clean up Idle
authorization answer
received
- Open Session-Timeout Expires on Discon. Idle
- Access Device user/device
+ Open Session-Timeout expires on Discon. Idle
+ access device user/device
Open Service to user is terminated Discon. Idle
user/device
- The following state machine is observed by a server when it is not
- maintaining state for the session:
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 106]
+Fajardo, et al. Standards Track [Page 103]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
+
+ The following state machine is observed by a server when it is not
+ maintaining state for the session:
SERVER, STATELESS
State Event Action New State
---------------------------------------------------------------
- Idle Service-specific authorization Send serv. Idle
- request received, and specific
- successfully processed answer
+ Idle Service-specific authorization Send Idle
+ request received, and service-
+ successfully processed specific
+ answer
8.2. Accounting Session State Machine
@@ -5960,8 +5799,8 @@ Internet-Draft Diameter Base Protocol January 2011
machine in this section described below.
The default server side state machine requires the reception of
- accounting records in any order and at any time, and does not place
- any standards requirement on the processing of these records.
+ accounting records in any order and at any time, and it does not
+ place any standards requirement on the processing of these records.
Implementations of Diameter may perform checking, ordering,
correlation, fraud detection, and other tasks based on these records.
AVPs may need to be inspected as a part of these tasks. The tasks
@@ -5970,7 +5809,7 @@ Internet-Draft Diameter Base Protocol January 2011
or even policy dependent, they are not standardized by the Diameter
specifications. Applications MAY define requirements on when to
accept accounting records based on the used value of Accounting-
- Realtime-Required AVP, credit limits checks, and so on.
+ Realtime-Required AVP, credit-limit checks, and so on.
However, the Diameter base protocol defines one optional server side
state machine that MAY be followed by applications that require
@@ -5978,31 +5817,31 @@ Internet-Draft Diameter Base Protocol January 2011
that such tracking is incompatible with the ability to sustain long
duration connectivity problems. Therefore, the use of this state
machine is recommended only in applications where the value of the
- Accounting-Realtime-Required AVP is DELIVER_AND_GRANT, and hence
+ Accounting-Realtime-Required AVP is DELIVER_AND_GRANT; hence,
accounting connectivity problems are required to cause the serviced
user to be disconnected. Otherwise, records produced by the client
- may be lost by the server which no longer accepts them after the
- connectivity is re-established. This state machine is the third
- state machine in this section. The state machine is supervised by a
- supervision session timer Ts, which the value should be reasonably
-Fajardo, et al. Expires July 24, 2011 [Page 107]
+Fajardo, et al. Standards Track [Page 104]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
- higher than the Acct_Interim_Interval value. Ts MAY be set to two
- times the value of the Acct_Interim_Interval so as to avoid the
- accounting session in the Diameter server to change to Idle state in
- case of short transient network failure.
+ may be lost by the server, which no longer accepts them after the
+ connectivity is re-established. This state machine is the third
+ state machine in this section. The state machine is supervised by a
+ supervision session timer Ts, whose value should be reasonably higher
+ than the Acct_Interim_Interval value. Ts MAY be set to two times the
+ value of the Acct_Interim_Interval so as to avoid the accounting
+ session in the Diameter server to change to Idle state in case of
+ short transient network failure.
Any event not listed in the state machines MUST be considered as an
error condition, and a corresponding answer, if applicable, MUST be
returned to the originator of the message.
- In the state table, the event 'Failure to send' means that the
+ In the state table, the event "Failure to send" means that the
Diameter client is unable to communicate with the desired
destination. This could be due to the peer being down, or due to the
peer sending back a transient failure or temporary protocol error
@@ -6010,17 +5849,17 @@ Internet-Draft Diameter Base Protocol January 2011
DIAMETER_LOOP_DETECTED in the Result-Code AVP of the Accounting
Answer command.
- The event 'Failed answer' means that the Diameter client received a
+ The event "Failed answer" means that the Diameter client received a
non-transient failure notification in the Accounting Answer command.
- Note that the action 'Disconnect user/dev' MUST have an effect also
- to the authorization session state table, e.g., cause the STR message
+ Note that the action "Disconnect user/dev" MUST also have an effect
+ on the authorization session state table, e.g., cause the STR message
to be sent, if the given application has both authentication/
authorization and accounting portions.
- The states PendingS, PendingI, PendingL, PendingE and PendingB stand
+ The states PendingS, PendingI, PendingL, PendingE, and PendingB stand
for pending states to wait for an answer to an accounting request
- related to a Start, Interim, Stop, Event or buffered record,
+ related to a Start, Interim, Stop, Event, or buffered record,
respectively.
CLIENT, ACCOUNTING
@@ -6037,36 +5876,36 @@ Internet-Draft Diameter Base Protocol January 2011
Idle Records in storage Send PendingB
record
- PendingS Successful accounting Open
- start answer received
-
- PendingS Failure to send and buffer Store Open
-Fajardo, et al. Expires July 24, 2011 [Page 108]
+Fajardo, et al. Standards Track [Page 105]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
- space available and realtime Start
+ PendingS Successful accounting Open
+ start answer received
+
+ PendingS Failure to send and buffer Store Open
+ space available and real time Start
not equal to DELIVER_AND_GRANT Record
PendingS Failure to send and no buffer Open
- space available and realtime
+ space available and real time
equal to GRANT_AND_LOSE
PendingS Failure to send and no Disconnect Idle
buffer space available and user/dev
- realtime not equal to
+ real time not equal to
GRANT_AND_LOSE
PendingS Failed accounting start answer Open
- received and realtime equal
+ received and real time equal
to GRANT_AND_LOSE
PendingS Failed accounting start answer Disconnect Idle
- received and realtime not user/dev
+ received and real time not user/dev
equal to GRANT_AND_LOSE
PendingS User service terminated Store PendingS
@@ -6077,6 +5916,7 @@ Internet-Draft Diameter Base Protocol January 2011
accounting
interim
record
+
Open User service terminated Send PendingL
accounting
stop req.
@@ -6087,34 +5927,35 @@ Internet-Draft Diameter Base Protocol January 2011
PendingI Failure to send and (buffer Store Open
space available or old interim
record can be overwritten) record
- and realtime not equal to
+ and real time not equal to
DELIVER_AND_GRANT
- PendingI Failure to send and no buffer Open
- space available and realtime
- equal to GRANT_AND_LOSE
- PendingI Failure to send and no Disconnect Idle
- buffer space available and user/dev
-Fajardo, et al. Expires July 24, 2011 [Page 109]
+Fajardo, et al. Standards Track [Page 106]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
+
+ PendingI Failure to send and no buffer Open
+ space available and real time
+ equal to GRANT_AND_LOSE
- realtime not equal to
+ PendingI Failure to send and no Disconnect Idle
+ buffer space available and user/dev
+ real time not equal to
GRANT_AND_LOSE
PendingI Failed accounting interim Open
- answer received and realtime
+ answer received and real time
equal to GRANT_AND_LOSE
PendingI Failed accounting interim Disconnect Idle
answer received and user/dev
- realtime not equal to
+ real time not equal to
GRANT_AND_LOSE
PendingI User service terminated Store PendingI
@@ -6148,6 +5989,13 @@ Internet-Draft Diameter Base Protocol January 2011
space available stop
record
+
+
+Fajardo, et al. Standards Track [Page 107]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
PendingL Failure to send and no buffer Idle
space available
@@ -6155,124 +6003,133 @@ Internet-Draft Diameter Base Protocol January 2011
received
-
-Fajardo, et al. Expires July 24, 2011 [Page 110]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
SERVER, STATELESS ACCOUNTING
State Event Action New State
---------------------------------------------------------------
Idle Accounting start request Send Idle
- received, and successfully accounting
+ received and successfully accounting
processed. start
answer
Idle Accounting event request Send Idle
- received, and successfully accounting
+ received and successfully accounting
processed. event
answer
- Idle Interim record received, Send Idle
+ Idle Interim record received Send Idle
and successfully processed. accounting
interim
answer
Idle Accounting stop request Send Idle
- received, and successfully accounting
+ received and successfully accounting
processed stop answer
- Idle Accounting request received, Send Idle
+ Idle Accounting request received; Send Idle
no space left to store accounting
- records answer,
+ records answer;
Result-Code =
OUT_OF_
SPACE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Fajardo, et al. Standards Track [Page 108]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
SERVER, STATEFUL ACCOUNTING
State Event Action New State
---------------------------------------------------------------
Idle Accounting start request Send Open
- received, and successfully accounting
+ received and successfully accounting
processed. start
- answer,
+ answer;
Start Ts
Idle Accounting event request Send Idle
- received, and successfully accounting
+ received and successfully accounting
processed. event
answer
-
- Idle Accounting request received, Send Idle
+ Idle Accounting request received; Send Idle
no space left to store accounting
- records answer,
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 111]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
+ records answer;
Result-Code =
OUT_OF_
SPACE
- Open Interim record received, Send Open
+ Open Interim record received Send Open
and successfully processed. accounting
interim
- answer,
+ answer;
Restart Ts
Open Accounting stop request Send Idle
- received, and successfully accounting
- processed stop answer,
+ received and successfully accounting
+ processed stop answer;
Stop Ts
- Open Accounting request received, Send Idle
+ Open Accounting request received; Send Idle
no space left to store accounting
- records answer,
+ records answer;
Result-Code =
OUT_OF_
- SPACE,
+ SPACE;
Stop Ts
Open Session supervision timer Ts Stop Ts Idle
expired
+
+
+
+
+
+
+
+
+Fajardo, et al. Standards Track [Page 109]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
8.3. Server-Initiated Re-Auth
A Diameter server may initiate a re-authentication and/or re-
authorization service for a particular session by issuing a Re-Auth-
Request (RAR).
- For example, for pre-paid services, the Diameter server that
+ For example, for prepaid services, the Diameter server that
originally authorized a session may need some confirmation that the
user is still using the services.
- An access device that receives a RAR message with Session-Id equal to
- a currently active session MUST initiate a re-auth towards the user,
- if the service supports this particular feature. Each Diameter
- application MUST state whether server-initiated re-auth is supported,
- since some applications do not allow access devices to prompt the
- user for re-auth.
+ An access device that receives an RAR message with the Session-Id
+ equal to a currently active session MUST initiate a re-auth towards
+ the user, if the service supports this particular feature. Each
+ Diameter application MUST state whether server-initiated re-auth is
+ supported, since some applications do not allow access devices to
+ prompt the user for re-auth.
8.3.1. Re-Auth-Request
- The Re-Auth-Request (RAR), indicated by the Command-Code set to 258
+ The Re-Auth-Request (RAR), indicated by the Command Code set to 258
and the message flags' 'R' bit set, may be sent by any server to the
access device that is providing session service, to request that the
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 112]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
user be re-authenticated and/or re-authorized.
@@ -6294,15 +6151,22 @@ Internet-Draft Diameter Base Protocol January 2011
8.3.2. Re-Auth-Answer
- The Re-Auth-Answer (RAA), indicated by the Command-Code set to 258
+ The Re-Auth-Answer (RAA), indicated by the Command Code set to 258
and the message flags' 'R' bit clear, is sent in response to the RAR.
- The Result-Code AVP MUST be present, and indicates the disposition of
- the request.
+ The Result-Code AVP MUST be present, and it indicates the disposition
+ of the request.
+
+
+
+
+Fajardo, et al. Standards Track [Page 110]
+
+RFC 6733 Diameter Base Protocol October 2012
+
A successful RAA message MUST be followed by an application-specific
authentication and/or authorization message.
-
Message Format
<RAA> ::= < Diameter Header: 258, PXY >
@@ -6321,14 +6185,6 @@ Internet-Draft Diameter Base Protocol January 2011
* [ Proxy-Info ]
* [ AVP ]
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 113]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
8.4. Session Termination
It is necessary for a Diameter server that authorized a session, for
@@ -6356,6 +6212,14 @@ Internet-Draft Diameter Base Protocol January 2011
It is also possible that a session that was authorized is never
actually started due to action of a proxy. For example, a proxy may
+
+
+
+Fajardo, et al. Standards Track [Page 111]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
modify an authorization answer, converting the result from success to
failure, prior to forwarding the message to the access device. If
the answer did not contain an Auth-Session-State AVP with the value
@@ -6366,36 +6230,27 @@ Internet-Draft Diameter Base Protocol January 2011
A Diameter server that receives an STR message MUST clean up
resources (e.g., session state) associated with the Session-Id
- specified in the STR, and return a Session-Termination-Answer.
+ specified in the STR and return a Session-Termination-Answer.
A Diameter server also MUST clean up resources when the Session-
Timeout expires, or when the Authorization-Lifetime and the Auth-
- Grace-Period AVPs expires without receipt of a re-authorization
+ Grace-Period AVPs expire without receipt of a re-authorization
request, regardless of whether an STR for that session is received.
The access device is not expected to provide service beyond the
expiration of these timers; thus, expiration of either of these
timers implies that the access device may have unexpectedly shut
down.
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 114]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
8.4.1. Session-Termination-Request
- The Session-Termination-Request (STR), indicated by the Command-Code
+ The Session-Termination-Request (STR), indicated by the Command Code
set to 275 and the Command Flags' 'R' bit set, is sent by a Diameter
- client or by a Diameter proxy to inform the Diameter Server that an
+ client or by a Diameter proxy to inform the Diameter server that an
authenticated and/or authorized session is being terminated.
+ Message Format
- Message Format
-
- <STR> ::= < Diameter Header: 275, REQ, PXY >
+ <STR> ::= < Diameter Header: 275, REQ, PXY >
< Session-Id >
{ Origin-Host }
{ Origin-Realm }
@@ -6410,40 +6265,33 @@ Internet-Draft Diameter Base Protocol January 2011
* [ Route-Record ]
* [ AVP ]
-8.4.2. Session-Termination-Answer
-
- The Session-Termination-Answer (STA), indicated by the Command-Code
- set to 275 and the message flags' 'R' bit clear, is sent by the
- Diameter Server to acknowledge the notification that the session has
- been terminated. The Result-Code AVP MUST be present, and MAY
- contain an indication that an error occurred while servicing the STR.
-
- Upon sending or receipt of the STA, the Diameter Server MUST release
- all resources for the session indicated by the Session-Id AVP. Any
- intermediate server in the Proxy-Chain MAY also release any
- resources, if necessary.
-
-
-
-
-
+Fajardo, et al. Standards Track [Page 112]
+
+RFC 6733 Diameter Base Protocol October 2012
+8.4.2. Session-Termination-Answer
-Fajardo, et al. Expires July 24, 2011 [Page 115]
-
-Internet-Draft Diameter Base Protocol January 2011
+ The Session-Termination-Answer (STA), indicated by the Command Code
+ set to 275 and the message flags' 'R' bit clear, is sent by the
+ Diameter server to acknowledge the notification that the session has
+ been terminated. The Result-Code AVP MUST be present, and it MAY
+ contain an indication that an error occurred while servicing the STR.
+ Upon sending or receipt of the STA, the Diameter server MUST release
+ all resources for the session indicated by the Session-Id AVP. Any
+ intermediate server in the Proxy-Chain MAY also release any
+ resources, if necessary.
- Message Format
+ Message Format
- <STA> ::= < Diameter Header: 275, PXY >
+ <STA> ::= < Diameter Header: 275, PXY >
< Session-Id >
{ Result-Code }
{ Origin-Host }
@@ -6473,31 +6321,29 @@ Internet-Draft Diameter Base Protocol January 2011
An access device that receives an ASR with Session-ID equal to a
currently active session MAY stop the session. Whether the access
- device stops the session or not is implementation- and/or
- configuration-dependent. For example, an access device may honor
+ device stops the session or not is implementation and/or
+ configuration dependent. For example, an access device may honor
ASRs from certain agents only. In any case, the access device MUST
+
+
+
+Fajardo, et al. Standards Track [Page 113]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
respond with an Abort-Session-Answer, including a Result-Code AVP to
indicate what action it took.
8.5.1. Abort-Session-Request
- The Abort-Session-Request (ASR), indicated by the Command-Code set to
+ The Abort-Session-Request (ASR), indicated by the Command Code set to
274 and the message flags' 'R' bit set, may be sent by any Diameter
server or any Diameter proxy to the access device that is providing
session service, to request that the session identified by the
Session-Id be stopped.
-
-
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 116]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
- Message Format
+ Message Format
<ASR> ::= < Diameter Header: 274, REQ, PXY >
< Session-Id >
@@ -6514,20 +6360,35 @@ Internet-Draft Diameter Base Protocol January 2011
8.5.2. Abort-Session-Answer
- The Abort-Session-Answer (ASA), indicated by the Command-Code set to
+ The Abort-Session-Answer (ASA), indicated by the Command Code set to
274 and the message flags' 'R' bit clear, is sent in response to the
- ASR. The Result-Code AVP MUST be present, and indicates the
+ ASR. The Result-Code AVP MUST be present and indicates the
disposition of the request.
If the session identified by Session-Id in the ASR was successfully
- terminated, Result-Code is set to DIAMETER_SUCCESS. If the session
- is not currently active, Result-Code is set to
+ terminated, the Result-Code is set to DIAMETER_SUCCESS. If the
+ session is not currently active, the Result-Code is set to
DIAMETER_UNKNOWN_SESSION_ID. If the access device does not stop the
- session for any other reason, Result-Code is set to
+ session for any other reason, the Result-Code is set to
DIAMETER_UNABLE_TO_COMPLY.
- Message Format
+
+
+
+
+
+
+
+
+
+
+Fajardo, et al. Standards Track [Page 114]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
+ Message Format
<ASA> ::= < Diameter Header: 274, PXY >
< Session-Id >
@@ -6545,14 +6406,6 @@ Internet-Draft Diameter Base Protocol January 2011
* [ Proxy-Info ]
* [ AVP ]
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 117]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
8.6. Inferring Session Termination from Origin-State-Id
The Origin-State-Id is used to allow detection of terminated sessions
@@ -6560,94 +6413,96 @@ Internet-Draft Diameter Base Protocol January 2011
shutdown of an access device.
A Diameter client or access device increments the value of the
- Origin-State-Id every time it is started or powered-up. The new
+ Origin-State-Id every time it is started or powered up. The new
Origin-State-Id is then sent in the CER/CEA message immediately upon
connection to the server. The Diameter server receiving the new
Origin-State-Id can determine whether the sending Diameter client had
- abruptly shutdown by comparing the old value of the Origin-State-Id
+ abruptly shut down by comparing the old value of the Origin-State-Id
it has kept for that specific client is less than the new value and
whether it has un-terminated sessions originating from that client.
An access device can also include the Origin-State-Id in request
- messages other than CER if there are relays or proxies in between the
- access device and the server. In this case, however, the server
+ messages other than the CER if there are relays or proxies in between
+ the access device and the server. In this case, however, the server
cannot discover that the access device has been restarted unless and
- until it receives a new request from it. Therefore this mechanism is
- more opportunistic across proxies and relays.
+ until it receives a new request from it. Therefore, this mechanism
+ is more opportunistic across proxies and relays.
The Diameter server may assume that all sessions that were active
prior to detection of a client restart have been terminated. The
Diameter server MAY clean up all session state associated with such
- lost sessions, and MAY also issues STRs for all such lost sessions
+ lost sessions, and it MAY also issue STRs for all such lost sessions
that were authorized on upstream servers, to allow session state to
be cleaned up globally.
+
+
+
+
+Fajardo, et al. Standards Track [Page 115]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
8.7. Auth-Request-Type AVP
The Auth-Request-Type AVP (AVP Code 274) is of type Enumerated and is
included in application-specific auth requests to inform the peers
- whether a user is to be authenticated only, authorized only or both.
+ whether a user is to be authenticated only, authorized only, or both.
Note any value other than both MAY cause RADIUS interoperability
issues. The following values are defined:
-
AUTHENTICATE_ONLY 1
- The request being sent is for authentication only, and MUST
- contain the relevant application specific authentication AVPs that
+ The request being sent is for authentication only, and it MUST
+ contain the relevant application-specific authentication AVPs that
are needed by the Diameter server to authenticate the user.
-
-
-
-
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 118]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
AUTHORIZE_ONLY 2
- The request being sent is for authorization only, and MUST contain
- the application-specific authorization AVPs that are necessary to
- identify the service being requested/offered.
-
+ The request being sent is for authorization only, and it MUST
+ contain the application-specific authorization AVPs that are
+ necessary to identify the service being requested/offered.
AUTHORIZE_AUTHENTICATE 3
The request contains a request for both authentication and
authorization. The request MUST include both the relevant
- application-specific authentication information, and authorization
+ application-specific authentication information and authorization
information necessary to identify the service being requested/
offered.
-
8.8. Session-Id AVP
The Session-Id AVP (AVP Code 263) is of type UTF8String and is used
to identify a specific session (see Section 8). All messages
- pertaining to a specific session MUST include only one Session-Id AVP
- and the same value MUST be used throughout the life of a session.
- When present, the Session-Id SHOULD appear immediately following the
- Diameter Header (see Section 3).
+ pertaining to a specific session MUST include only one Session-Id
+ AVP, and the same value MUST be used throughout the life of a
+ session. When present, the Session-Id SHOULD appear immediately
+ following the Diameter header (see Section 3).
The Session-Id MUST be globally and eternally unique, as it is meant
to uniquely identify a user session without reference to any other
- information, and may be needed to correlate historical authentication
- information with accounting information. The Session-Id includes a
- mandatory portion and an implementation-defined portion; a
- recommended format for the implementation-defined portion is outlined
- below.
+ information, and it may be needed to correlate historical
+ authentication information with accounting information. The
+ Session-Id includes a mandatory portion and an implementation-defined
+ portion; a recommended format for the implementation-defined portion
+ is outlined below.
The Session-Id MUST begin with the sender's identity encoded in the
- DiameterIdentity type (see Section 4.4). The remainder of the
- Session-Id is delimited by a ";" character, and MAY be any sequence
- that the client can guarantee to be eternally unique; however, the
- following format is recommended, (square brackets [] indicate an
- optional element):
+ DiameterIdentity type (see Section 4.3.1). The remainder of the
+ Session-Id is delimited by a ";" character, and it MAY be any
+
+
+
+Fajardo, et al. Standards Track [Page 116]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
+ sequence that the client can guarantee to be eternally unique;
+ however, the following format is recommended, (square brackets []
+ indicate an optional element):
<DiameterIdentity>;<high 32 bits>;<low 32 bits>[;<optional value>]
@@ -6657,22 +6512,14 @@ Internet-Draft Diameter Base Protocol January 2011
processors. At startup, the high 32 bits of the 64-bit value MAY be
initialized to the time in NTP format [RFC5905], and the low 32 bits
MAY be initialized to zero. This will for practical purposes
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 119]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
eliminate the possibility of overlapping Session-Ids after a reboot,
assuming the reboot process takes longer than a second.
Alternatively, an implementation MAY keep track of the increasing
value in non-volatile memory.
- <optional value> is implementation specific but may include a modem's
- device Id, a layer 2 address, timestamp, etc.
+ <optional value> is implementation specific, but it may include a
+ modem's device Id, a Layer 2 address, timestamp, etc.
Example, in which there is no optional value:
@@ -6683,45 +6530,44 @@ Internet-Draft Diameter Base Protocol January 2011
accesspoint7.example.com;1876543210;523;[email protected]
The Session-Id is created by the Diameter application initiating the
- session, which in most cases is done by the client. Note that a
- Session-Id MAY be used for both the authentication, authorization and
- accounting commands of a given application.
+ session, which, in most cases, is done by the client. Note that a
+ Session-Id MAY be used for both the authentication, authorization,
+ and accounting commands of a given application.
8.9. Authorization-Lifetime AVP
The Authorization-Lifetime AVP (AVP Code 291) is of type Unsigned32
and contains the maximum number of seconds of service to be provided
to the user before the user is to be re-authenticated and/or re-
- authorized. Care should be taken when the Authorization- Lifetime
- value is determined, since a low, non-zero, value could create
+ authorized. Care should be taken when the Authorization-Lifetime
+ value is determined, since a low, non-zero value could create
significant Diameter traffic, which could congest both the network
and the agents.
A value of zero (0) means that immediate re-auth is necessary by the
access device. The absence of this AVP, or a value of all ones
- (meaning all bits in the 32 bit field are set to one) means no re-
+ (meaning all bits in the 32-bit field are set to one) means no re-
auth is expected.
+
+
+Fajardo, et al. Standards Track [Page 117]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
If both this AVP and the Session-Timeout AVP are present in a
message, the value of the latter MUST NOT be smaller than the
Authorization-Lifetime AVP.
An Authorization-Lifetime AVP MAY be present in re-authorization
- messages, and contains the number of seconds the user is authorized
- to receive service from the time the re-auth answer message is
- received by the access device.
+ messages, and it contains the number of seconds the user is
+ authorized to receive service from the time the re-auth answer
+ message is received by the access device.
This AVP MAY be provided by the client as a hint of the maximum
lifetime that it is willing to accept. The server MUST return a
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 120]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
- value that is equal to, or smaller, than the one provided by the
+ value that is equal to, or smaller than, the one provided by the
client.
8.10. Auth-Grace-Period AVP
@@ -6739,7 +6585,6 @@ Internet-Draft Diameter Base Protocol January 2011
the value in the server's answer message is binding. The following
values are supported:
-
STATE_MAINTAINED 0
This value is used to specify that session state is being
@@ -6747,46 +6592,42 @@ Internet-Draft Diameter Base Protocol January 2011
message when service to the user is terminated. This is the
default value.
-
NO_STATE_MAINTAINED 1
This value is used to specify that no session termination messages
will be sent by the access device upon expiration of the
Authorization-Lifetime.
-
8.12. Re-Auth-Request-Type AVP
The Re-Auth-Request-Type AVP (AVP Code 285) is of type Enumerated and
is included in application-specific auth answers to inform the client
of the action expected upon expiration of the Authorization-Lifetime.
- If the answer message contains an Authorization-Lifetime AVP with a
- positive value, the Re-Auth-Request-Type AVP MUST be present in an
- answer message. The following values are defined:
- AUTHORIZE_ONLY 0
- An authorization only re-auth is expected upon expiration of the
- Authorization-Lifetime. This is the default value if the AVP is
+Fajardo, et al. Standards Track [Page 118]
+
+RFC 6733 Diameter Base Protocol October 2012
-Fajardo, et al. Expires July 24, 2011 [Page 121]
-
-Internet-Draft Diameter Base Protocol January 2011
+ If the answer message contains an Authorization-Lifetime AVP with a
+ positive value, the Re-Auth-Request-Type AVP MUST be present in an
+ answer message. The following values are defined:
+ AUTHORIZE_ONLY 0
+ An authorization only re-auth is expected upon expiration of the
+ Authorization-Lifetime. This is the default value if the AVP is
not present in answer messages that include the Authorization-
Lifetime.
-
AUTHORIZE_AUTHENTICATE 1
An authentication and authorization re-auth is expected upon
expiration of the Authorization-Lifetime.
-
8.13. Session-Timeout AVP
The Session-Timeout AVP (AVP Code 27) [RFC2865] is of type Unsigned32
@@ -6799,10 +6640,10 @@ Internet-Draft Diameter Base Protocol January 2011
A session that terminates on an access device due to the expiration
of the Session-Timeout MUST cause an STR to be issued, unless both
the access device and the home server had previously agreed that no
- session termination messages would be sent (see Section 8.11).
+ session termination messages would be sent (see Section 8).
A Session-Timeout AVP MAY be present in a re-authorization answer
- message, and contains the remaining number of seconds from the
+ message, and it contains the remaining number of seconds from the
beginning of the re-auth.
A value of zero, or the absence of this AVP, means that this session
@@ -6810,7 +6651,7 @@ Internet-Draft Diameter Base Protocol January 2011
This AVP MAY be provided by the client as a hint of the maximum
timeout that it is willing to accept. However, the server MAY return
- a value that is equal to, or smaller, than the one provided by the
+ a value that is equal to, or smaller than, the one provided by the
client.
8.14. User-Name AVP
@@ -6819,83 +6660,29 @@ Internet-Draft Diameter Base Protocol January 2011
contains the User-Name, in a format consistent with the NAI
specification [RFC4282].
-8.15. Termination-Cause AVP
-
- The Termination-Cause AVP (AVP Code 295) is of type Enumerated, and
- is used to indicate the reason why a session was terminated on the
- access device. The following values are defined:
-
-Fajardo, et al. Expires July 24, 2011 [Page 122]
+Fajardo, et al. Standards Track [Page 119]
-Internet-Draft Diameter Base Protocol January 2011
-
-
- DIAMETER_LOGOUT 1
-
- The user initiated a disconnect
-
-
- DIAMETER_SERVICE_NOT_PROVIDED 2
-
- This value is used when the user disconnected prior to the receipt
- of the authorization answer message.
-
-
- DIAMETER_BAD_ANSWER 3
-
- This value indicates that the authorization answer received by the
- access device was not processed successfully.
-
-
- DIAMETER_ADMINISTRATIVE 4
-
- The user was not granted access, or was disconnected, due to
- administrative reasons, such as the receipt of a Abort-Session-
- Request message.
-
-
- DIAMETER_LINK_BROKEN 5
-
- The communication to the user was abruptly disconnected.
-
-
- DIAMETER_AUTH_EXPIRED 6
-
- The user's access was terminated since its authorized session time
- has expired.
-
-
- DIAMETER_USER_MOVED 7
-
- The user is receiving services from another access device.
-
-
- DIAMETER_SESSION_TIMEOUT 8
+RFC 6733 Diameter Base Protocol October 2012
- The user's session has timed out, and service has been terminated.
+8.15. Termination-Cause AVP
-
-
-
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 123]
-
-Internet-Draft Diameter Base Protocol January 2011
-
+ The Termination-Cause AVP (AVP Code 295) is of type Enumerated, and
+ is used to indicate the reason why a session was terminated on the
+ access device. The currently assigned values for this AVP can be
+ found in the IANA registry for Termination-Cause AVP Values
+ [IANATCV].
8.16. Origin-State-Id AVP
The Origin-State-Id AVP (AVP Code 278), of type Unsigned32, is a
monotonically increasing value that is advanced whenever a Diameter
- entity restarts with loss of previous state, for example upon reboot.
- Origin-State-Id MAY be included in any Diameter message, including
- CER.
+ entity restarts with loss of previous state, for example, upon
+ reboot. Origin-State-Id MAY be included in any Diameter message,
+ including CER.
A Diameter entity issuing this AVP MUST create a higher value for
this AVP each time its state is reset. A Diameter entity MAY set
@@ -6911,20 +6698,34 @@ Internet-Draft Diameter Base Protocol January 2011
message, it allows other Diameter entities to infer that sessions
associated with a lower Origin-State-Id are no longer active. If an
access device does not intend for such inferences to be made, it MUST
- either not include Origin-State-Id in any message, or set its value
- to 0.
+ either not include Origin-State-Id in any message or set its value to
+ 0.
8.17. Session-Binding AVP
- The Session-Binding AVP (AVP Code 270) is of type Unsigned32, and MAY
- be present in application-specific authorization answer messages. If
- present, this AVP MAY inform the Diameter client that all future
+ The Session-Binding AVP (AVP Code 270) is of type Unsigned32, and it
+ MAY be present in application-specific authorization answer messages.
+ If present, this AVP MAY inform the Diameter client that all future
application-specific re-auth and Session-Termination-Request messages
for this session MUST be sent to the same authorization server.
- This field is a bit mask, and the following bits have been defined:
+
+
+
+
+
+
+
+
+Fajardo, et al. Standards Track [Page 120]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
+ This field is a bit mask, and the following bits have been defined:
+
RE_AUTH 1
When set, future re-auth messages for this session MUST NOT
@@ -6932,23 +6733,13 @@ Internet-Draft Diameter Base Protocol January 2011
value, the Destination-Host AVP MUST be present in all re-auth
messages for this session.
-
STR 2
When set, the STR message for this session MUST NOT include the
Destination-Host AVP. When cleared, the default value, the
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 124]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
Destination-Host AVP MUST be present in the STR message for this
session.
-
ACCOUNTING 4
When set, all accounting messages for this session MUST NOT
@@ -6956,10 +6747,9 @@ Internet-Draft Diameter Base Protocol January 2011
value, the Destination-Host AVP, if known, MUST be present in all
accounting messages for this session.
-
8.18. Session-Server-Failover AVP
- The Session-Server-Failover AVP (AVP Code 271) is of type Enumerated,
+ The Session-Server-Failover AVP (AVP Code 271) is of type Enumerated
and MAY be present in application-specific authorization answer
messages that either do not include the Session-Binding AVP or
include the Session-Binding AVP with any of the bits set to a zero
@@ -6970,11 +6760,24 @@ Internet-Draft Diameter Base Protocol January 2011
The following values are supported:
-
REFUSE_SERVICE 0
If either the re-auth or the STR message delivery fails, terminate
- service with the user, and do not attempt any subsequent attempts.
+ service with the user and do not attempt any subsequent attempts.
+
+
+
+
+
+
+
+
+
+
+
+Fajardo, et al. Standards Track [Page 121]
+
+RFC 6733 Diameter Base Protocol October 2012
TRY_AGAIN 1
@@ -6982,34 +6785,23 @@ Internet-Draft Diameter Base Protocol January 2011
If either the re-auth or the STR message delivery fails, resend
the failed message without the Destination-Host AVP present.
-
ALLOW_SERVICE 2
If re-auth message delivery fails, assume that re-authorization
succeeded. If STR message delivery fails, terminate the session.
-
TRY_AGAIN_ALLOW_SERVICE 3
If either the re-auth or the STR message delivery fails, resend
the failed message without the Destination-Host AVP present. If
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 125]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
the second delivery fails for re-auth, assume re-authorization
succeeded. If the second delivery fails for STR, terminate the
session.
-
8.19. Multi-Round-Time-Out AVP
- The Multi-Round-Time-Out AVP (AVP Code 272) is of type Unsigned32,
- and SHOULD be present in application-specific authorization answer
+ The Multi-Round-Time-Out AVP (AVP Code 272) is of type Unsigned32 and
+ SHOULD be present in application-specific authorization answer
messages whose Result-Code AVP is set to DIAMETER_MULTI_ROUND_AUTH.
This AVP contains the maximum number of seconds that the access
device MUST provide the user in responding to an authentication
@@ -7031,37 +6823,24 @@ Internet-Draft Diameter Base Protocol January 2011
8.21. Event-Timestamp AVP
- The Event-Timestamp (AVP Code 55) is of type Time, and MAY be
- included in an Accounting-Request and Accounting-Answer messages to
- record the time that the reported event occurred, in seconds since
- January 1, 1900 00:00 UTC.
-
-
+ The Event-Timestamp (AVP Code 55) is of type Time and MAY be included
+ in an Accounting-Request and Accounting-Answer messages to record the
+ time that the reported event occurred, in seconds since January 1,
+ 1900 00:00 UTC.
-
-
-
-
-
-
-
-
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 126]
+Fajardo, et al. Standards Track [Page 122]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
9. Accounting
This accounting protocol is based on a server directed model with
capabilities for real-time delivery of accounting information.
- Several fault resilience methods [RFC2975] have been built in to the
+ Several fault resilience methods [RFC2975] have been built into the
protocol in order minimize loss of accounting data in various fault
situations and under different assumptions about the capabilities of
the used devices.
@@ -7075,15 +6854,16 @@ Internet-Draft Diameter Base Protocol January 2011
timeliness requirements.
As discussed in [RFC2975], real-time transfer of accounting records
- is a requirement, such as the need to perform credit limit checks and
+ is a requirement, such as the need to perform credit-limit checks and
fraud detection. Note that batch accounting is not a requirement,
and is therefore not supported by Diameter. Should batched
accounting be required in the future, a new Diameter application will
need to be created, or it could be handled using another protocol.
- Note, however, that even if at the Diameter layer accounting requests
- are processed one by one, transport protocols used under Diameter
- typically batch several requests in the same packet under heavy
- traffic conditions. This may be sufficient for many applications.
+ Note, however, that even if at the Diameter layer, accounting
+ requests are processed one by one; transport protocols used under
+ Diameter typically batch several requests in the same packet under
+ heavy traffic conditions. This may be sufficient for many
+ applications.
The authorization server (chain) directs the selection of proper
transfer strategy, based on its knowledge of the user and
@@ -7097,7 +6877,7 @@ Internet-Draft Diameter Base Protocol January 2011
records from the Diameter client is delayed or unsuccessful.
The Diameter accounting server MAY override the interim interval or
- the realtime requirements by including the Acct-Interim-Interval or
+ the real-time requirements by including the Acct-Interim-Interval or
Accounting-Realtime-Required AVP in the Accounting-Answer message.
When one of these AVPs is present, the latest value received SHOULD
be used in further accounting activities for the same session.
@@ -7107,16 +6887,15 @@ Internet-Draft Diameter Base Protocol January 2011
-
-Fajardo, et al. Expires July 24, 2011 [Page 127]
+Fajardo, et al. Standards Track [Page 123]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
9.2. Protocol Messages
A Diameter node that receives a successful authentication and/or
- authorization messages from the Diameter server SHOULD collect
+ authorization message from the Diameter server SHOULD collect
accounting information for the session. The Accounting-Request
message is used to transmit the accounting information to the
Diameter server, which MUST reply with the Accounting-Answer message
@@ -7129,12 +6908,12 @@ Internet-Draft Diameter Base Protocol January 2011
9.3. Accounting Application Extension and Requirements
- Each Diameter application (e.g., NASREQ, MobileIP), SHOULD define
- their Service-Specific AVPs that MUST be present in the Accounting-
- Request message in a section entitled "Accounting AVPs". The
- application MUST assume that the AVPs described in this document will
- be present in all Accounting messages, so only their respective
- service-specific AVPs need to be defined in that section.
+ Each Diameter application (e.g., NASREQ, Mobile IP) SHOULD define its
+ service-specific AVPs that MUST be present in the Accounting-Request
+ message in a section titled "Accounting AVPs". The application MUST
+ assume that the AVPs described in this document will be present in
+ all Accounting messages, so only their respective service-specific
+ AVPs need to be defined in that section.
Applications have the option of using one or both of the following
accounting application extension models:
@@ -7150,40 +6929,37 @@ Internet-Draft Diameter Base Protocol January 2011
advertise the Diameter base accounting Application Id during
capabilities exchange.
-
Coupled Accounting Service
- The accounting messages will carry the Application Id of the
+ The accounting message will carry the Application Id of the
application that is using it. The application itself will process
the received accounting records or forward them to an accounting
server. There is no accounting application advertisement required
- during capabilities exchange and the accounting messages will be
- routed the same as any of the other application messages.
-
+ during capabilities exchange, and the accounting messages will be
+ routed the same way as any of the other application messages.
+ In cases where an application does not define its own accounting
+ service, it is preferred that the split accounting model be used.
-Fajardo, et al. Expires July 24, 2011 [Page 128]
+Fajardo, et al. Standards Track [Page 124]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
- In cases where an application does not define its own accounting
- service, it is preferred that the split accounting model be used.
-
9.4. Fault Resilience
- Diameter Base protocol mechanisms are used to overcome small message
- loss and network faults of temporary nature.
+ Diameter base protocol mechanisms are used to overcome small message
+ loss and network faults of a temporary nature.
Diameter peers acting as clients MUST implement the use of failover
to guard against server failures and certain network failures.
Diameter peers acting as agents or related off-line processing
systems MUST detect duplicate accounting records caused by the
- sending of same record to several servers and duplication of messages
- in transit. This detection MUST be based on the inspection of the
- Session-Id and Accounting-Record-Number AVP pairs. Appendix C
+ sending of the same record to several servers and duplication of
+ messages in transit. This detection MUST be based on the inspection
+ of the Session-Id and Accounting-Record-Number AVP pairs. Appendix C
discusses duplicate detection needs and implementation issues.
Diameter clients MAY have non-volatile memory for the safe storage of
@@ -7191,23 +6967,23 @@ Internet-Draft Diameter Base Protocol January 2011
partitions, and server failures. If such memory is available, the
client SHOULD store new accounting records there as soon as the
records are created and until a positive acknowledgement of their
- reception from the Diameter Server has been received. Upon a reboot,
- the client MUST starting sending the records in the non-volatile
- memory to the accounting server with appropriate modifications in
+ reception from the Diameter server has been received. Upon a reboot,
+ the client MUST start sending the records in the non-volatile memory
+ to the accounting server with the appropriate modifications in
termination cause, session length, and other relevant information in
the records.
A further application of this protocol may include AVPs to control
- how many accounting records may at most be stored in the Diameter
- client without committing them to the non-volatile memory or
+ the maximum number of accounting records that may be stored in the
+ Diameter client without committing them to the non-volatile memory or
transferring them to the Diameter server.
The client SHOULD NOT remove the accounting data from any of its
memory areas before the correct Accounting-Answer has been received.
- The client MAY remove oldest, undelivered or yet unacknowledged
- accounting data if it runs out of resources such as memory. It is an
- implementation dependent matter for the client to accept new sessions
- under this condition.
+ The client MAY remove the oldest, undelivered, or as yet
+ unacknowledged accounting data if it runs out of resources such as
+ memory. It is an implementation-dependent matter for the client to
+ accept new sessions under this condition.
9.5. Accounting Records
@@ -7217,15 +6993,17 @@ Internet-Draft Diameter Base Protocol January 2011
Different types of accounting records are sent depending on the
actual type of accounted service and the authorization server's
+ directions for interim accounting. If the accounted service is a
+
+
-Fajardo, et al. Expires July 24, 2011 [Page 129]
+Fajardo, et al. Standards Track [Page 125]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
- directions for interim accounting. If the accounted service is a
one-time event, meaning that the start and stop of the event are
simultaneous, then the Accounting-Record-Type AVP MUST be present and
set to the value EVENT_RECORD.
@@ -7251,11 +7029,11 @@ Internet-Draft Diameter Base Protocol January 2011
session.
A particular value of Accounting-Sub-Session-Id MUST appear only in
- one sequence of accounting records from a DIAMETER client, except for
+ one sequence of accounting records from a Diameter client, except for
the purposes of retransmission. The one sequence that is sent MUST
be either one record with Accounting-Record-Type AVP set to the value
- EVENT_RECORD, or several records starting with one having the value
- START_RECORD, followed by zero or more INTERIM_RECORD and a single
+ EVENT_RECORD or several records starting with one having the value
+ START_RECORD, followed by zero or more INTERIM_RECORDs and a single
STOP_RECORD. A particular Diameter application specification MUST
define the type of sequences that MUST be used.
@@ -7265,20 +7043,21 @@ Internet-Draft Diameter Base Protocol January 2011
accounting records with a specific application session by using the
Session-Id of the particular application session in the accounting
messages. Accounting messages MAY also use a different Session-Id
- from that of the application sessions in which case other session
+ from that of the application sessions, in which case, other session-
related information is needed to perform correlation.
In cases where an application requires multiple accounting sub-
- session, an Accounting-Sub-Session-Id AVP is used to differentiate
+ sessions, an Accounting-Sub-Session-Id AVP is used to differentiate
each sub-session. The Session-Id would remain constant for all sub-
- sessions and is be used to correlate all the sub-sessions to a
+ sessions and is used to correlate all the sub-sessions to a
particular application session. Note that receiving a STOP_RECORD
-Fajardo, et al. Expires July 24, 2011 [Page 130]
+
+Fajardo, et al. Standards Track [Page 126]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
with no Accounting-Sub-Session-Id AVP when sub-sessions were
@@ -7290,36 +7069,36 @@ Internet-Draft Diameter Base Protocol January 2011
record may span multiple different Diameter applications and sessions
used by the same user at a given time. In such cases, the Acct-
Multi-Session-Id AVP is used. The Acct-Multi-Session-Id AVP SHOULD
- be signaled by the server to the access device (typically during
+ be signaled by the server to the access device (typically, during
authorization) when it determines that a request belongs to an
existing session. The access device MUST then include the Acct-
Multi-Session-Id AVP in all subsequent accounting messages.
The Acct-Multi-Session-Id AVP MAY include the value of the original
- Session-Id. It's contents are implementation specific, but MUST be
- globally unique across other Acct-Multi-Session-Id, and MUST NOT
+ Session-Id. Its contents are implementation specific, but the MUST
+ be globally unique across other Acct-Multi-Session-Ids and MUST NOT
change during the life of a session.
A Diameter application document MUST define the exact concept of a
- session that is being accounted, and MAY define the concept of a
+ session that is being accounted, and it MAY define the concept of a
multi-session. For instance, the NASREQ DIAMETER application treats
- a single PPP connection to a Network Access Server as one session,
- and a set of Multilink PPP sessions as one multi-session.
+ a single PPP connection to a Network Access Server as one session and
+ a set of Multilink PPP sessions as one multi-session.
-9.7. Accounting Command-Codes
+9.7. Accounting Command Codes
- This section defines Command-Code values that MUST be supported by
- all Diameter implementations that provide Accounting services.
+ This section defines Command Code values that MUST be supported by
+ all Diameter implementations that provide accounting services.
9.7.1. Accounting-Request
- The Accounting-Request (ACR) command, indicated by the Command-Code
+ The Accounting-Request (ACR) command, indicated by the Command Code
field set to 271 and the Command Flags' 'R' bit set, is sent by a
Diameter node, acting as a client, in order to exchange accounting
information with a peer.
- The AVP listed below SHOULD include service-specific accounting AVPs,
- as described in Section 9.3.
+ In addition to the AVPs listed below, Accounting-Request messages
+ SHOULD include service-specific accounting AVPs.
@@ -7332,9 +7111,9 @@ Internet-Draft Diameter Base Protocol January 2011
-Fajardo, et al. Expires July 24, 2011 [Page 131]
+Fajardo, et al. Standards Track [Page 127]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
Message Format
@@ -7363,16 +7142,16 @@ Internet-Draft Diameter Base Protocol January 2011
9.7.2. Accounting-Answer
- The Accounting-Answer (ACA) command, indicated by the Command-Code
+ The Accounting-Answer (ACA) command, indicated by the Command Code
field set to 271 and the Command Flags' 'R' bit cleared, is used to
acknowledge an Accounting-Request command. The Accounting-Answer
command contains the same Session-Id as the corresponding request.
- Only the target Diameter Server, known as the home Diameter Server,
+ Only the target Diameter server, known as the home Diameter server,
SHOULD respond with the Accounting-Answer command.
- The AVP listed below SHOULD include service-specific accounting AVPs,
- as described in Section 9.3.
+ In addition to the AVPs listed below, Accounting-Answer messages
+ SHOULD include service-specific accounting AVPs.
@@ -7388,9 +7167,9 @@ Internet-Draft Diameter Base Protocol January 2011
-Fajardo, et al. Expires July 24, 2011 [Page 132]
+Fajardo, et al. Standards Track [Page 128]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
Message Format
@@ -7429,13 +7208,12 @@ Internet-Draft Diameter Base Protocol January 2011
and contains the type of accounting record being sent. The following
values are currently defined for the Accounting-Record-Type AVP:
-
EVENT_RECORD 1
An Accounting Event Record is used to indicate that a one-time
event has occurred (meaning that the start and end of the event
are simultaneous). This record contains all information relevant
- to the service, and is the only record of the service.
+ to the service, and it is the only record of the service.
@@ -7444,20 +7222,20 @@ Internet-Draft Diameter Base Protocol January 2011
-Fajardo, et al. Expires July 24, 2011 [Page 133]
+
+Fajardo, et al. Standards Track [Page 129]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
START_RECORD 2
- An Accounting Start, Interim, and Stop Records are used to
- indicate that a service of a measurable length has been given. An
- Accounting Start Record is used to initiate an accounting session,
+ Accounting Start, Interim, and Stop Records are used to indicate
+ that a service of a measurable length has been given. An
+ Accounting Start Record is used to initiate an accounting session
and contains accounting information that is relevant to the
initiation of the session.
-
INTERIM_RECORD 3
An Interim Accounting Record contains cumulative accounting
@@ -7468,14 +7246,12 @@ Internet-Draft Diameter Base Protocol January 2011
applications. The selection of whether to use INTERIM_RECORD
records is done by the Acct-Interim-Interval AVP.
-
STOP_RECORD 4
An Accounting Stop Record is sent to terminate an accounting
session and contains cumulative accounting information relevant to
the existing session.
-
9.8.2. Acct-Interim-Interval AVP
The Acct-Interim-Interval AVP (AVP Code 85) is of type Unsigned32 and
@@ -7483,31 +7259,31 @@ Internet-Draft Diameter Base Protocol January 2011
client. The client uses information in this AVP to decide how and
when to produce accounting records. With different values in this
AVP, service sessions can result in one, two, or two+N accounting
- records, based on the needs of the home-organization. The following
+ records, based on the needs of the home organization. The following
accounting record production behavior is directed by the inclusion of
this AVP:
-
1. The omission of the Acct-Interim-Interval AVP or its inclusion
with Value field set to 0 means that EVENT_RECORD, START_RECORD,
and STOP_RECORD are produced, as appropriate for the service.
-
2. The inclusion of the AVP with Value field set to a non-zero value
means that INTERIM_RECORD records MUST be produced between the
START_RECORD and STOP_RECORD records. The Value field of this
AVP is the nominal interval between these records in seconds.
+ The Diameter node that originates the accounting information,
+ known as the client, MUST produce the first INTERIM_RECORD record
+ roughly at the time when this nominal interval has elapsed from
+
+
-Fajardo, et al. Expires July 24, 2011 [Page 134]
+Fajardo, et al. Standards Track [Page 130]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
- The Diameter node that originates the accounting information,
- known as the client, MUST produce the first INTERIM_RECORD record
- roughly at the time when this nominal interval has elapsed from
the START_RECORD, the next one again as the interval has elapsed
once more, and so on until the session ends and a STOP_RECORD
record is produced.
@@ -7522,10 +7298,10 @@ Internet-Draft Diameter Base Protocol January 2011
The Accounting-Record-Number AVP (AVP Code 485) is of type Unsigned32
and identifies this record within one session. As Session-Id AVPs
are globally unique, the combination of Session-Id and Accounting-
- Record-Number AVPs is also globally unique, and can be used in
+ Record-Number AVPs is also globally unique and can be used in
matching accounting records with confirmations. An easy way to
produce unique numbers is to set the value to 0 for records of type
- EVENT_RECORD and START_RECORD, and set the value to 1 for the first
+ EVENT_RECORD and START_RECORD and set the value to 1 for the first
INTERIM_RECORD, 2 for the second, and so on until the value for
STOP_RECORD is one more than for the last INTERIM_RECORD.
@@ -7539,10 +7315,10 @@ Internet-Draft Diameter Base Protocol January 2011
The Acct-Multi-Session-Id AVP (AVP Code 50) is of type UTF8String,
following the format specified in Section 8.8. The Acct-Multi-
- Session-Id AVP is used to link together multiple related accounting
- sessions, where each session would have a unique Session-Id, but the
- same Acct-Multi-Session-Id AVP. This AVP MAY be returned by the
- Diameter server in an authorization answer, and MUST be used in all
+ Session-Id AVP is used to link multiple related accounting sessions,
+ where each session would have a unique Session-Id but the same Acct-
+ Multi-Session-Id AVP. This AVP MAY be returned by the Diameter
+ server in an authorization answer, and it MUST be used in all
accounting messages for the given session.
9.8.6. Accounting-Sub-Session-Id AVP
@@ -7553,18 +7329,17 @@ Internet-Draft Diameter Base Protocol January 2011
session, and the value of this AVP MUST be monotonically increased by
one for all new sub-sessions. The absence of this AVP implies no
sub-sessions are in use, with the exception of an Accounting-Request
+ whose Accounting-Record-Type is set to STOP_RECORD. A STOP_RECORD
+ message with no Accounting-Sub-Session-Id AVP present will signal the
+ termination of all sub-sessions for a given Session-Id.
-Fajardo, et al. Expires July 24, 2011 [Page 135]
+Fajardo, et al. Standards Track [Page 131]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
- whose Accounting-Record-Type is set to STOP_RECORD. A STOP_RECORD
- message with no Accounting-Sub-Session-Id AVP present will signal the
- termination of all sub-sessions for a given Session-Id.
-
9.8.7. Accounting-Realtime-Required AVP
The Accounting-Realtime-Required AVP (AVP Code 483) is of type
@@ -7574,7 +7349,6 @@ Internet-Draft Diameter Base Protocol January 2011
if the sending of accounting records to the accounting server has
been temporarily prevented due to, for instance, a network problem.
-
DELIVER_AND_GRANT 1
The AVP with Value field set to DELIVER_AND_GRANT means that the
@@ -7584,7 +7358,6 @@ Internet-Draft Diameter Base Protocol January 2011
the accounting record stream to a backup server is not a reason to
discontinue the service to the user.
-
GRANT_AND_STORE 2
The AVP with Value field set to GRANT_AND_STORE means that service
@@ -7594,60 +7367,51 @@ Internet-Draft Diameter Base Protocol January 2011
This is the default behavior if the AVP isn't included in the
reply from the authorization server.
-
GRANT_AND_LOSE 3
The AVP with Value field set to GRANT_AND_LOSE means that service
SHOULD be granted even if the records cannot be delivered or
stored.
+10. AVP Occurrence Tables
+ The following tables present the AVPs defined in this document and
+ specify in which Diameter messages they MAY or MAY NOT be present.
+ AVPs that occur only inside a Grouped AVP are not shown in these
+ tables.
+ The tables use the following symbols:
+ 0 The AVP MUST NOT be present in the message.
+ 0+ Zero or more instances of the AVP MAY be present in the
+ message.
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 136]
+Fajardo, et al. Standards Track [Page 132]
-Internet-Draft Diameter Base Protocol January 2011
-
-
-10. AVP Occurrence Table
-
- The following tables presents the AVPs defined in this document, and
- specifies in which Diameter messages they MAY be present or not.
- AVPs that occur only inside a Grouped AVP are not shown in this
- table.
+RFC 6733 Diameter Base Protocol October 2012
- The table uses the following symbols:
+ 0-1 Zero or one instance of the AVP MAY be present in the message.
+ It is considered an error if there are more than one instance
+ of the AVP.
- 0 The AVP MUST NOT be present in the message.
+ 1 One instance of the AVP MUST be present in the message.
- 0+ Zero or more instances of the AVP MAY be present in the
- message.
-
- 0-1 Zero or one instance of the AVP MAY be present in the message.
- It is considered an error if there are more than one instance of
- the AVP.
-
- 1 One instance of the AVP MUST be present in the message.
-
- 1+ At least one instance of the AVP MUST be present in the
- message.
+ 1+ At least one instance of the AVP MUST be present in the
+ message.
10.1. Base Protocol Command AVP Table
- The table in this section is limited to the non-accounting Command
+ The table in this section is limited to the non-Accounting Command
Codes defined in this specification.
+-----------------------------------------------+
- | Command-Code |
+ | Command Code |
+---+---+---+---+---+---+---+---+---+---+---+---+
Attribute Name |CER|CEA|DPR|DPA|DWR|DWA|RAR|RAA|ASR|ASA|STR|STA|
--------------------+---+---+---+---+---+---+---+---+---+---+---+---+
@@ -7665,22 +7429,29 @@ Internet-Draft Diameter Base Protocol January 2011
Class |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0+ |0+ |
Destination-Host |0 |0 |0 |0 |0 |0 |1 |0 |1 |0 |0-1|0 |
Destination-Realm |0 |0 |0 |0 |0 |0 |1 |0 |1 |0 |1 |0 |
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 137]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
Disconnect-Cause |0 |0 |1 |0 |0 |0 |0 |0 |0 |0 |0 |0 |
Error-Message |0 |0-1|0 |0-1|0 |0-1|0 |0-1|0 |0-1|0 |0-1|
Error-Reporting-Host|0 |0 |0 |0 |0 |0 |0 |0-1|0 |0-1|0 |0-1|
- Failed-AVP |0 |0+ |0 |0+ |0 |0+ |0 |0+ |0 |0+ |0 |0+ |
+ Failed-AVP |0 |0-1|0 |0-1|0 |0-1|0 |0-1|0 |0-1|0 |0-1|
Firmware-Revision |0-1|0-1|0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |
Host-IP-Address |1+ |1+ |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |
Inband-Security-Id |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |
Multi-Round-Time-Out|0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |
+
+
+
+
+
+
+
+
+
+
+Fajardo, et al. Standards Track [Page 133]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
Origin-Host |1 |1 |1 |1 |1 |1 |1 |1 |1 |1 |1 |1 |
Origin-Realm |1 |1 |1 |1 |1 |1 |1 |1 |1 |1 |1 |1 |
Origin-State-Id |0-1|0-1|0 |0 |0-1|0-1|0-1|0-1|0-1|0-1|0-1|0-1|
@@ -7724,9 +7495,17 @@ Internet-Draft Diameter Base Protocol January 2011
-Fajardo, et al. Expires July 24, 2011 [Page 138]
+
+
+
+
+
+
+
+
+Fajardo, et al. Standards Track [Page 134]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
+-----------+
@@ -7749,6 +7528,7 @@ Internet-Draft Diameter Base Protocol January 2011
Destination-Realm | 1 | 0 |
Error-Reporting-Host | 0 | 0+ |
Event-Timestamp | 0-1 | 0-1 |
+ Failed-AVP | 0 | 0-1 |
Origin-Host | 1 | 1 |
Origin-Realm | 1 | 1 |
Proxy-Info | 0+ | 0+ |
@@ -7760,144 +7540,220 @@ Internet-Draft Diameter Base Protocol January 2011
Vendor-Specific-Application-Id| 0-1 | 0-1 |
------------------------------+-----+-----+
+11. IANA Considerations
+ This section provides guidance to the Internet Assigned Numbers
+ Authority (IANA) regarding registration of values related to the
+ Diameter protocol, in accordance with [RFC5226]. Existing IANA
+ registries and assignments put in place by RFC 3588 remain the same
+ unless explicitly updated or deprecated in this section.
+11.1. AVP Header
+ As defined in Section 4, the AVP header contains three fields that
+ require IANA namespace management: the AVP Code, Vendor-ID, and Flags
+ fields.
-
-
-
-
-
-
-
-
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 139]
+Fajardo, et al. Standards Track [Page 135]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
-11. IANA Considerations
+11.1.1. AVP Codes
- This section provides guidance to the Internet Assigned Numbers
- Authority (IANA) regarding registration of values related to the
- Diameter protocol, in accordance with BCP 26 [RFC5226]. The policies
- and procedures for the IANA put in place by [RFC3588] applies here.
- The criteria used by the IANA for assignment of numbers within this
- namespace remains the same unless otherwise stated in this section.
- Existing assignments remains the same unless explicitly updated or
- deprecated in this secion.
+ There are multiple namespaces. Vendors can have their own AVP Codes
+ namespace that will be identified by their Vendor-ID (also known as
+ Enterprise-Number), and they control the assignments of their vendor-
+ specific AVP Codes within their own namespace. The absence of a
+ Vendor-ID or a Vendor-ID value of zero (0) identifies the IETF AVP
+ Codes namespace, which is under IANA control. The AVP Codes and
+ sometimes possible values in an AVP are controlled and maintained by
+ IANA. AVP Code 0 is not used. AVP Codes 1-255 are managed
+ separately as RADIUS Attribute Types. Where a Vendor-Specific AVP is
+ implemented by more than one vendor, allocation of global AVPs should
+ be encouraged instead.
+
+ AVPs may be allocated following Expert Review (by a Designated
+ Expert) with Specification Required [RFC5226]. A block allocation
+ (release of more than three AVPs at a time for a given purpose)
+ requires IETF Review [RFC5226].
-11.1. Changes to AVP Header Allocation
+11.1.2. AVP Flags
- For AVP Headers, the only change is the AVP code block allocations.
- Block allocation (release of more than 3 at a time for a given
- purpose) now only require IETF Review as opposed to an IETF
- Consensus.
+ Section 4.1 describes the existing AVP Flags. The remaining bits can
+ only be assigned via a Standards Action [RFC5226].
11.2. Diameter Header
- For the Diameter Header, the command code namespace allocation has
+11.2.1. Command Codes
+
+ For the Diameter header, the Command Code namespace allocation has
changed. The new allocation rules are as follows:
- The command code values 256 - 8,388,607 (0x100 to 0x7fffff) are
+ The Command Code values 256 - 8,388,607 (0x100 to 0x7fffff) are
for permanent, standard commands, allocated by IETF Review
[RFC5226].
The values 8,388,608 - 16,777,213 (0x800000 - 0xfffffd) are
- reserved for vendor-specific command codes, to be allocated on a
+ reserved for vendor-specific Command Codes, to be allocated on a
First Come, First Served basis by IANA [RFC5226]. The request to
IANA for a Vendor-Specific Command Code SHOULD include a reference
- to a publicly available specification which documents the command
+ to a publicly available specification that documents the command
in sufficient detail to aid in interoperability between
independent implementations. If the specification cannot be made
- publicly available, the request for a vendor-specific command code
+ publicly available, the request for a vendor-specific Command Code
MUST include the contact information of persons and/or entities
responsible for authoring and maintaining the command.
+
+
+
+
+
+Fajardo, et al. Standards Track [Page 136]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
+ The values 16,777,214 and 16,777,215 (hexadecimal values 0xfffffe
+ - 0xffffff) are reserved for experimental commands. As these
+ codes are only for experimental and testing purposes, no guarantee
+ is made for interoperability between Diameter peers using
+ experimental commands.
+
+11.2.2. Command Flags
+
+ Section 3 describes the existing Command Flags field. The remaining
+ bits can only be assigned via a Standards Action [RFC5226].
+
11.3. AVP Values
For AVP values, the Experimental-Result-Code AVP value allocation has
- been added. The new rule is as follows:
+ been added; see Section 11.3.1. The old AVP value allocation rule,
+ IETF Consensus, has been updated to IETF Review as per [RFC5226], and
+ affected AVPs are listed as reminders.
11.3.1. Experimental-Result-Code AVP
Values for this AVP are purely local to the indicated vendor, and no
IANA registry is maintained for them.
+11.3.2. Result-Code AVP Values
+ New values are available for assignment via IETF Review [RFC5226].
+11.3.3. Accounting-Record-Type AVP Values
-Fajardo, et al. Expires July 24, 2011 [Page 140]
-
-Internet-Draft Diameter Base Protocol January 2011
+ New values are available for assignment via IETF Review [RFC5226].
+
+11.3.4. Termination-Cause AVP Values
+ New values are available for assignment via IETF Review [RFC5226].
-11.4. Diameter TCP, SCTP, TLS/TCP and DTLS/SCTP Port Numbers
+11.3.5. Redirect-Host-Usage AVP Values
- Updated port number assignments are described in this section. The
- IANA has assigned port number 3868 for TCP and SCTP. The port number
- [TBD] has been assigned for TLS/TCP and DTLS/SCTP.
+ New values are available for assignment via IETF Review [RFC5226].
-11.5. S-NAPTR Parameters
+11.3.6. Session-Server-Failover AVP Values
- This document registers a new S-NAPTR Application Service Tag value
- of "aaa".
+ New values are available for assignment via IETF Review [RFC5226].
- This document also registers the following S-NAPTR Application
- Protocol Tags:
+11.3.7. Session-Binding AVP Values
- Tag | Protocol
- -------------------|---------
- diameter.tcp | TCP
- diameter.sctp | SCTP
- diameter.tls.tcp | TLS/TCP
- diameter.dtls.sctp | DTLS/SCTP
+ New values are available for assignment via IETF Review [RFC5226].
+Fajardo, et al. Standards Track [Page 137]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
+11.3.8. Disconnect-Cause AVP Values
+ New values are available for assignment via IETF Review [RFC5226].
+11.3.9. Auth-Request-Type AVP Values
+ New values are available for assignment via IETF Review [RFC5226].
+11.3.10. Auth-Session-State AVP Values
+ New values are available for assignment via IETF Review [RFC5226].
+11.3.11. Re-Auth-Request-Type AVP Values
+ New values are available for assignment via IETF Review [RFC5226].
+11.3.12. Accounting-Realtime-Required AVP Values
+ New values are available for assignment via IETF Review [RFC5226].
+11.3.13. Inband-Security-Id AVP (code 299)
+ The use of this AVP has been deprecated.
+11.4. _diameters Service Name and Port Number Registration
+ IANA has registered the "_diameters" service name and assigned port
+ numbers for TLS/TCP and DTLS/SCTP according to the guidelines given
+ in [RFC6335].
+ Service Name: _diameters
+ Transport Protocols: TCP, SCTP
+ Assignee: IESG <[email protected]>
+ Contact: IETF Chair <[email protected]>
+ Description: Diameter over TLS/TCP and DTLS/SCTP
+ Reference: RFC 6733
+ Port Number: 5868, from the User Range
-Fajardo, et al. Expires July 24, 2011 [Page 141]
+
+
+Fajardo, et al. Standards Track [Page 138]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
+
+
+11.5. SCTP Payload Protocol Identifiers
+
+ Two SCTP payload protocol identifiers have been registered in the
+ SCTP Payload Protocol Identifiers registry:
+
+
+ Value | SCTP Payload Protocol Identifier
+ -------|-----------------------------------
+ 46 | Diameter in a SCTP DATA chunk
+ 47 | Diameter in a DTLS/SCTP DATA chunk
+
+11.6. S-NAPTR Parameters
-12. Diameter protocol related configurable parameters
+ The following tag has been registered in the S-NAPTR Application
+ Protocol Tags registry:
+
+ Tag | Protocol
+ -------------------|---------
+ diameter.dtls.sctp | DTLS/SCTP
+
+12. Diameter Protocol-Related Configurable Parameters
This section contains the configurable parameters that are found
throughout this document:
@@ -7915,8 +7771,8 @@ Internet-Draft Diameter Base Protocol January 2011
A Diameter proxy server routes messages based on the realm portion
of a Network Access Identifier (NAI). The server MUST have a
table of Realm Names, and the address of the peer to which the
- message must be forwarded to. The routing table MAY also include
- a "default route", which is typically used for all messages that
+ message must be forwarded. The routing table MAY also include a
+ "default route", which is typically used for all messages that
cannot be locally processed.
Tc timer
@@ -7927,30 +7783,9 @@ Internet-Draft Diameter Base Protocol January 2011
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 142]
+Fajardo, et al. Standards Track [Page 139]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
13. Security Considerations
@@ -7959,34 +7794,34 @@ Internet-Draft Diameter Base Protocol January 2011
[RFC5246] or DTLS/SCTP [RFC6083]. Additional security mechanisms
such as IPsec [RFC4301] MAY also be deployed to secure connections
between peers. However, all Diameter base protocol implementations
- MUST support the use of TLS/TCP and DTLS/SCTP and the Diameter
- protocol MUST NOT be used without any security mechanism.
+ MUST support the use of TLS/TCP and DTLS/SCTP, and the Diameter
+ protocol MUST NOT be used without one of TLS, DTLS, or IPsec.
If a Diameter connection is to be protected via TLS/TCP and DTLS/SCTP
or IPsec, then TLS/TCP and DTLS/SCTP or IPsec/IKE SHOULD begin prior
to any Diameter message exchange. All security parameters for TLS/
TCP and DTLS/SCTP or IPsec are configured independent of the Diameter
- protocol. All Diameter message will be sent through the TLS/TCP and
+ protocol. All Diameter messages will be sent through the TLS/TCP and
DTLS/SCTP or IPsec connection after a successful setup.
For TLS/TCP and DTLS/SCTP connections to be established in the open
state, the CER/CEA exchange MUST include an Inband-Security-ID AVP
with a value of TLS/TCP and DTLS/SCTP. The TLS/TCP and DTLS/SCTP
- handshake will begin when both ends successfully reached the open
+ handshake will begin when both ends successfully reach the open
state, after completion of the CER/CEA exchange. If the TLS/TCP and
DTLS/SCTP handshake is successful, all further messages will be sent
- via TLS/TCP and DTLS/SCTP. If the handshake fails, both ends move to
- the closed state. See Sections 13.1 for more details.
+ via TLS/TCP and DTLS/SCTP. If the handshake fails, both ends MUST
+ move to the closed state. See Section 13.1 for more details.
13.1. TLS/TCP and DTLS/SCTP Usage
Diameter nodes using TLS/TCP and DTLS/SCTP for security MUST mutually
authenticate as part of TLS/TCP and DTLS/SCTP session establishment.
In order to ensure mutual authentication, the Diameter node acting as
- TLS/TCP and DTLS/SCTP server MUST request a certificate from the
+ the TLS/TCP and DTLS/SCTP server MUST request a certificate from the
Diameter node acting as TLS/TCP and DTLS/SCTP client, and the
- Diameter node acting as TLS/TCP and DTLS/SCTP client MUST be prepared
- to supply a certificate on request.
+ Diameter node acting as the TLS/TCP and DTLS/SCTP client MUST be
+ prepared to supply a certificate on request.
Diameter nodes MUST be able to negotiate the following TLS/TCP and
DTLS/SCTP cipher suites:
@@ -8000,16 +7835,24 @@ Internet-Draft Diameter Base Protocol January 2011
TLS_RSA_WITH_AES_128_CBC_SHA
- Diameter nodes MAY negotiate other TLS/TCP and DTLS/SCTP cipher
-Fajardo, et al. Expires July 24, 2011 [Page 143]
+
+Fajardo, et al. Standards Track [Page 140]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
+
+ Note that it is quite possible that support for the
+ TLS_RSA_WITH_AES_128_CBC_SHA cipher suite will be REQUIRED at some
+ future date. Diameter nodes MAY negotiate other TLS/TCP and DTLS/
+ SCTP cipher suites.
- suites.
+ If public key certificates are used for Diameter security (for
+ example, with TLS), the value of the expiration times in the routing
+ and peer tables MUST NOT be greater than the expiry time in the
+ relevant certificates.
13.2. Peer-to-Peer Considerations
@@ -8027,67 +7870,105 @@ Internet-Draft Diameter Base Protocol January 2011
peers may not be known beforehand and therefore peer discovery may be
required.
+13.3. AVP Considerations
+ Diameter AVPs often contain security-sensitive data; for example,
+ user passwords and location data, network addresses and cryptographic
+ keys. The following AVPs defined in this document are considered to
+ be security-sensitive:
+ o Acct-Interim-Interval
+ o Accounting-Realtime-Required
+ o Acct-Multi-Session-Id
+ o Accounting-Record-Number
+ o Accounting-Record-Type
+ o Accounting-Session-Id
+ o Accounting-Sub-Session-Id
+ o Class
+Fajardo, et al. Standards Track [Page 141]
+
+RFC 6733 Diameter Base Protocol October 2012
+ o Session-Id
+ o Session-Binding
+ o Session-Server-Failover
+ o User-Name
+ Diameter messages containing these or any other AVPs considered to be
+ security-sensitive MUST only be sent protected via mutually
+ authenticated TLS or IPsec. In addition, those messages MUST NOT be
+ sent via intermediate nodes unless there is end-to-end security
+ between the originator and recipient or the originator has locally
+ trusted configuration that indicates that end-to-end security is not
+ needed. For example, end-to-end security may not be required in the
+ case where an intermediary node is known to be operated as part of
+ the same administrative domain as the endpoints so that an ability to
+ successfully compromise the intermediary would imply a high
+ probability of being able to compromise the endpoints as well. Note
+ that no end-to-end security mechanism is specified in this document.
+14. References
+14.1. Normative References
+ [FLOATPOINT]
+ Institute of Electrical and Electronics Engineers, "IEEE
+ Standard for Binary Floating-Point Arithmetic, ANSI/IEEE
+ Standard 754-1985", August 1985.
+ [IANAADFAM]
+ IANA, "Address Family Numbers",
+ <http://www.iana.org/assignments/address-family-numbers>.
+ [RFC0791] Postel, J., "Internet Protocol", STD 5, RFC 791,
+ September 1981.
+ [RFC0793] Postel, J., "Transmission Control Protocol", STD 7,
+ RFC 793, September 1981.
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+ [RFC3492] Costello, A., "Punycode: A Bootstring encoding of Unicode
+ for Internationalized Domain Names in Applications
+ (IDNA)", RFC 3492, March 2003.
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 144]
+Fajardo, et al. Standards Track [Page 142]
-Internet-Draft Diameter Base Protocol January 2011
-
-
-14. References
-
-14.1. Normative References
-
- [FLOATPOINT]
- Institute of Electrical and Electronics Engineers, "IEEE
- Standard for Binary Floating-Point Arithmetic, ANSI/IEEE
- Standard 754-1985", August 1985.
+RFC 6733 Diameter Base Protocol October 2012
- [IANAADFAM]
- IANA,, "Address Family Numbers",
- http://www.iana.org/assignments/address-family-numbers.
- [RADTYPE] IANA,, "RADIUS Types",
- http://www.iana.org/assignments/radius-types.
+ [RFC3539] Aboba, B. and J. Wood, "Authentication, Authorization and
+ Accounting (AAA) Transport Profile", RFC 3539, June 2003.
- [RFC791] Postel, J., "Internet Protocol", RFC 791, September 1981.
+ [RFC3629] Yergeau, F., "UTF-8, a transformation format of ISO
+ 10646", STD 63, RFC 3629, November 2003.
- [RFC793] Postel, J., "Transmission Control Protocol", RFC 793,
- January 1981.
+ [RFC3958] Daigle, L. and A. Newton, "Domain-Based Application
+ Service Location Using SRV RRs and the Dynamic Delegation
+ Discovery Service (DDDS)", RFC 3958, January 2005.
- [RFC3539] Aboba, B. and J. Wood, "Authentication, Authorization and
- Accounting (AAA) Transport Profile", RFC 3539, June 2003.
+ [RFC3986] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
+ Resource Identifier (URI): Generic Syntax", STD 66,
+ RFC 3986, January 2005.
[RFC4004] Calhoun, P., Johansson, T., Perkins, C., Hiller, T., and
P. McCann, "Diameter Mobile IPv4 Application", RFC 4004,
@@ -8101,51 +7982,44 @@ Internet-Draft Diameter Base Protocol January 2011
Loughney, "Diameter Credit-Control Application", RFC 4006,
August 2005.
- [RFC5234] Crocker, D. and P. Overell, "Augmented BNF for Syntax
- Specifications: ABNF", STD 68, RFC 5234, January 2008.
-
- [RFC3588] Calhoun, P., Loughney, J., Guttman, E., Zorn, G., and J.
- Arkko, "Diameter Base Protocol", RFC 3588, September 2003.
+ [RFC4086] Eastlake, D., Schiller, J., and S. Crocker, "Randomness
+ Requirements for Security", BCP 106, RFC 4086, June 2005.
- [RFC5226] Narten, T. and H. Alvestrand, "Guidelines for Writing an
- IANA Considerations Section in RFCs", BCP 26, RFC 5226,
- May 2008.
+ [RFC4282] Aboba, B., Beadles, M., Arkko, J., and P. Eronen, "The
+ Network Access Identifier", RFC 4282, December 2005.
[RFC4291] Hinden, R. and S. Deering, "IP Version 6 Addressing
Architecture", RFC 4291, February 2006.
+ [RFC4960] Stewart, R., "Stream Control Transmission Protocol",
+ RFC 4960, September 2007.
+ [RFC5226] Narten, T. and H. Alvestrand, "Guidelines for Writing an
+ IANA Considerations Section in RFCs", BCP 26, RFC 5226,
+ May 2008.
-Fajardo, et al. Expires July 24, 2011 [Page 145]
-
-Internet-Draft Diameter Base Protocol January 2011
-
+ [RFC5234] Crocker, D. and P. Overell, "Augmented BNF for Syntax
+ Specifications: ABNF", STD 68, RFC 5234, January 2008.
- [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
- Requirement Levels", BCP 14, RFC 2119, March 1997.
+ [RFC5246] Dierks, T. and E. Rescorla, "The Transport Layer Security
+ (TLS) Protocol Version 1.2", RFC 5246, August 2008.
- [RFC4282] Aboba, B., Beadles, M., Arkko, J., and P. Eronen, "The
- Network Access Identifier", RFC 4282, December 2005.
- [RFC4086] Eastlake, D., Schiller, J., and S. Crocker, "Randomness
- Requirements for Security", BCP 106, RFC 4086, June 2005.
- [RFC4960] Stewart, R., "Stream Control Transmission Protocol",
- RFC 4960, September 2007.
- [RFC3958] Daigle, L. and A. Newton, "Domain-Based Application
- Service Location Using SRV RRs and the Dynamic Delegation
- Discovery Service (DDDS)", RFC 3958, January 2005.
+Fajardo, et al. Standards Track [Page 143]
+
+RFC 6733 Diameter Base Protocol October 2012
- [RFC5246] Dierks, T. and E. Rescorla, "The Transport Layer Security
- (TLS) Protocol Version 1.2", RFC 5246, August 2008.
- [RFC3986] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
- Resource Identifier (URI): Generic Syntax", STD 66,
- RFC 3986, January 2005.
+ [RFC5280] Cooper, D., Santesson, S., Farrell, S., Boeyen, S.,
+ Housley, R., and W. Polk, "Internet X.509 Public Key
+ Infrastructure Certificate and Certificate Revocation List
+ (CRL) Profile", RFC 5280, May 2008.
- [RFC3629] Yergeau, F., "UTF-8, a transformation format of ISO
- 10646", STD 63, RFC 3629, November 2003.
+ [RFC5729] Korhonen, J., Jones, M., Morand, L., and T. Tsou,
+ "Clarifications on the Routing of Diameter Requests Based
+ on the Username and the Realm", RFC 5729, December 2009.
[RFC5890] Klensin, J., "Internationalized Domain Names for
Applications (IDNA): Definitions and Document Framework",
@@ -8154,103 +8028,120 @@ Internet-Draft Diameter Base Protocol January 2011
[RFC5891] Klensin, J., "Internationalized Domain Names in
Applications (IDNA): Protocol", RFC 5891, August 2010.
- [RFC3492] Costello, A., "Punycode: A Bootstring encoding of Unicode
- for Internationalized Domain Names in Applications
- (IDNA)", RFC 3492, March 2003.
-
- [RFC5729] Korhonen, J., Jones, M., Morand, L., and T. Tsou,
- "Clarifications on the Routing of Diameter Requests Based
- on the Username and the Realm", RFC 5729, December 2009.
-
- [RFC4347] Rescorla, E. and N. Modadugu, "Datagram Transport Layer
- Security", RFC 4347, April 2006.
-
[RFC6083] Tuexen, M., Seggelmann, R., and E. Rescorla, "Datagram
Transport Layer Security (DTLS) for Stream Control
Transmission Protocol (SCTP)", RFC 6083, January 2011.
+ [RFC6347] Rescorla, E. and N. Modadugu, "Datagram Transport Layer
+ Security Version 1.2", RFC 6347, January 2012.
+ [RFC6408] Jones, M., Korhonen, J., and L. Morand, "Diameter
+ Straightforward-Naming Authority Pointer (S-NAPTR) Usage",
+ RFC 6408, November 2011.
+14.2. Informative References
-Fajardo, et al. Expires July 24, 2011 [Page 146]
-
-Internet-Draft Diameter Base Protocol January 2011
+ [ENTERPRISE] IANA, "SMI Network Management Private Enterprise
+ Codes",
+ <http://www.iana.org/assignments/enterprise-numbers>.
+ [IANATCV] IANA, "Termination-Cause AVP Values (code 295)",
+ <http://www.iana.org/assignments/aaa-parameters/
+ aaa-parameters.xml#aaa-parameters-16>.
-14.2. Informational References
+ [RFC1492] Finseth, C., "An Access Control Protocol, Sometimes
+ Called TACACS", RFC 1492, July 1993.
- [RFC2989] Aboba, B., Calhoun, P., Glass, S., Hiller, T., McCann, P.,
- Shiino, H., Walsh, P., Zorn, G., Dommety, G., Perkins, C.,
- Patil, B., Mitton, D., Manning, S., Beadles, M., Chen, X.,
- Sivalingham, S., Hameed, A., Munson, M., Jacobs, S., Lim,
- B., Hirschman, B., Hsu, R., Koo, H., Lipford, M.,
- Campbell, E., Xu, Y., Baba, S., and E. Jaques, "Criteria
- for Evaluating AAA Protocols for Network Access",
- RFC 2989, November 2000.
+ [RFC1661] Simpson, W., "The Point-to-Point Protocol (PPP)",
+ STD 51, RFC 1661, July 1994.
- [RFC2975] Aboba, B., Arkko, J., and D. Harrington, "Introduction to
- Accounting Management", RFC 2975, October 2000.
+ [RFC2104] Krawczyk, H., Bellare, M., and R. Canetti, "HMAC:
+ Keyed-Hashing for Message Authentication", RFC 2104,
+ February 1997.
- [RFC3232] Reynolds, J., "Assigned Numbers: RFC 1700 is Replaced by
- an On-line Database", RFC 3232, January 2002.
- [RFC5176] Chiba, M., Dommety, G., Eklund, M., Mitton, D., and B.
- Aboba, "Dynamic Authorization Extensions to Remote
- Authentication Dial In User Service (RADIUS)", RFC 5176,
- January 2008.
- [RFC1661] Simpson, W., "The Point-to-Point Protocol (PPP)", STD 51,
- RFC 1661, July 1994.
- [RFC2866] Rigney, C., "RADIUS Accounting", RFC 2866, June 2000.
- [RFC2869] Rigney, C., Willats, W., and P. Calhoun, "RADIUS
- Extensions", RFC 2869, June 2000.
+Fajardo, et al. Standards Track [Page 144]
+
+RFC 6733 Diameter Base Protocol October 2012
- [RFC2865] Rigney, C., Willens, S., Rubens, A., and W. Simpson,
- "Remote Authentication Dial In User Service (RADIUS)",
- RFC 2865, June 2000.
- [RFC3162] Aboba, B., Zorn, G., and D. Mitton, "RADIUS and IPv6",
- RFC 3162, August 2001.
+ [RFC2782] Gulbrandsen, A., Vixie, P., and L. Esibov, "A DNS RR
+ for specifying the location of services (DNS SRV)",
+ RFC 2782, February 2000.
- [RFC4301] Kent, S. and K. Seo, "Security Architecture for the
- Internet Protocol", RFC 4301, December 2005.
+ [RFC2865] Rigney, C., Willens, S., Rubens, A., and W. Simpson,
+ "Remote Authentication Dial In User Service (RADIUS)",
+ RFC 2865, June 2000.
- [RFC5905] Mills, D., Martin, J., Burbank, J., and W. Kasch, "Network
- Time Protocol Version 4: Protocol and Algorithms
- Specification", RFC 5905, June 2010.
+ [RFC2866] Rigney, C., "RADIUS Accounting", RFC 2866, June 2000.
- [RFC1492] Finseth, C., "An Access Control Protocol, Sometimes Called
- TACACS", RFC 1492, July 1993.
+ [RFC2869] Rigney, C., Willats, W., and P. Calhoun, "RADIUS
+ Extensions", RFC 2869, June 2000.
- [RFC4690] Klensin, J., Faltstrom, P., Karp, C., and IAB, "Review and
+ [RFC2881] Mitton, D. and M. Beadles, "Network Access Server
+ Requirements Next Generation (NASREQNG) NAS Model",
+ RFC 2881, July 2000.
+ [RFC2975] Aboba, B., Arkko, J., and D. Harrington, "Introduction
+ to Accounting Management", RFC 2975, October 2000.
+ [RFC2989] Aboba, B., Calhoun, P., Glass, S., Hiller, T., McCann,
+ P., Shiino, H., Walsh, P., Zorn, G., Dommety, G.,
+ Perkins, C., Patil, B., Mitton, D., Manning, S.,
+ Beadles, M., Chen, X., Sivalingham, S., Hameed, A.,
+ Munson, M., Jacobs, S., Lim, B., Hirschman, B., Hsu,
+ R., Koo, H., Lipford, M., Campbell, E., Xu, Y., Baba,
+ S., and E. Jaques, "Criteria for Evaluating AAA
+ Protocols for Network Access", RFC 2989, November 2000.
-Fajardo, et al. Expires July 24, 2011 [Page 147]
-
-Internet-Draft Diameter Base Protocol January 2011
+ [RFC3162] Aboba, B., Zorn, G., and D. Mitton, "RADIUS and IPv6",
+ RFC 3162, August 2001.
+ [RFC3748] Aboba, B., Blunk, L., Vollbrecht, J., Carlson, J., and
+ H. Levkowetz, "Extensible Authentication Protocol
+ (EAP)", RFC 3748, June 2004.
- Recommendations for Internationalized Domain Names
- (IDNs)", RFC 4690, September 2006.
+ [RFC4301] Kent, S. and K. Seo, "Security Architecture for the
+ Internet Protocol", RFC 4301, December 2005.
- [RFC5461] Gont, F., "TCP's Reaction to Soft Errors", RFC 5461,
- February 2009.
+ [RFC4690] Klensin, J., Faltstrom, P., Karp, C., and IAB, "Review
+ and Recommendations for Internationalized Domain Names
+ (IDNs)", RFC 4690, September 2006.
- [RFC5927] Gont, F., "ICMP Attacks against TCP", RFC 5927, July 2010.
+ [RFC5176] Chiba, M., Dommety, G., Eklund, M., Mitton, D., and B.
+ Aboba, "Dynamic Authorization Extensions to Remote
+ Authentication Dial In User Service (RADIUS)",
+ RFC 5176, January 2008.
- [RFC3692] Narten, T., "Assigning Experimental and Testing Numbers
- Considered Useful", BCP 82, RFC 3692, January 2004.
+Fajardo, et al. Standards Track [Page 145]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+ [RFC5461] Gont, F., "TCP's Reaction to Soft Errors", RFC 5461,
+ February 2009.
+ [RFC5905] Mills, D., Martin, J., Burbank, J., and W. Kasch,
+ "Network Time Protocol Version 4: Protocol and
+ Algorithms Specification", RFC 5905, June 2010.
+ [RFC5927] Gont, F., "ICMP Attacks against TCP", RFC 5927,
+ July 2010.
+ [RFC6335] Cotton, M., Eggert, L., Touch, J., Westerlund, M., and
+ S. Cheshire, "Internet Assigned Numbers Authority
+ (IANA) Procedures for the Management of the Service
+ Name and Transport Protocol Port Number Registry",
+ BCP 165, RFC 6335, August 2011.
+ [RFC6737] Kang, J. and G. Zorn, "The Diameter Capabilities Update
+ Application", RFC 6737, October 2012.
@@ -8284,80 +8175,83 @@ Internet-Draft Diameter Base Protocol January 2011
-Fajardo, et al. Expires July 24, 2011 [Page 148]
+Fajardo, et al. Standards Track [Page 146]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
Appendix A. Acknowledgements
-A.1. RFC3588bis
+A.1. This Document
The authors would like to thank the following people that have
provided proposals and contributions to this document:
To Vishnu Ram and Satendra Gera for their contributions on
- Capabilities Updates, Predictive Loop Avoidance as well as many other
- technical proposals. To Tolga Asveren for his insights and
+ capabilities updates, predictive loop avoidance, as well as many
+ other technical proposals. To Tolga Asveren for his insights and
contributions on almost all of the proposed solutions incorporated
- into this document. To Timothy Smith for helping on the Capabilities
- Updates and other topics. To Tony Zhang for providing fixes to loop
- holes on composing Failed-AVPs as well as many other issues and
+ into this document. To Timothy Smith for helping on the capabilities
+ Update and other topics. To Tony Zhang for providing fixes to
+ loopholes on composing Failed-AVPs as well as many other issues and
topics. To Jan Nordqvist for clearly stating the usage of
- Application Ids. To Anders Kristensen for providing needed technical
+ Application Ids. To Anders Kristensen for providing needed technical
opinions. To David Frascone for providing invaluable review of the
document. To Mark Jones for providing clarifying text on vendor
- command codes and other vendor specific indicators.
+ command codes and other vendor-specific indicators. To Victor
+ Pascual and Sebastien Decugis for new text and recommendations on
+ SCTP/DTLS. To Jouni Korhonen for taking over the editing task and
+ resolving last bits from versions 27 through 29.
- Special thanks to the Diameter extensibility design team which helped
- resolve the tricky question of mandatory AVPs and ABNF semantics.
- The members of this team are as follows:
+ Special thanks to the Diameter extensibility design team, which
+ helped resolve the tricky question of mandatory AVPs and ABNF
+ semantics. The members of this team are as follows:
Avi Lior, Jari Arkko, Glen Zorn, Lionel Morand, Mark Jones, Tolga
- Asveren Jouni Korhonen, Glenn McGregor.
+ Asveren, Jouni Korhonen, and Glenn McGregor.
Special thanks also to people who have provided invaluable comments
and inputs especially in resolving controversial issues:
- Glen Zorn, Yoshihiro Ohba, Marco Stura, and Pasi Eronen.
+ Glen Zorn, Yoshihiro Ohba, Marco Stura, Stephen Farrel, Pete Resnick,
+ Peter Saint-Andre, Robert Sparks, Krishna Prasad, Sean Turner, Barry
+ Leiba, and Pasi Eronen.
Finally, we would like to thank the original authors of this
document:
- Pat Calhoun, John Loughney, Jari Arkko, Erik Guttman and Glen Zorn.
+ Pat Calhoun, John Loughney, Jari Arkko, Erik Guttman, and Glen Zorn.
Their invaluable knowledge and experience has given us a robust and
flexible AAA protocol that many people have seen great value in
adopting. We greatly appreciate their support and stewardship for
the continued improvements of Diameter as a protocol. We would also
like to extend our gratitude to folks aside from the authors who have
- assisted and contributed to the original version of this document.
- Their efforts significantly contributed to the success of Diameter.
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 149]
+Fajardo, et al. Standards Track [Page 147]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
-A.2. RFC3588
+ assisted and contributed to the original version of this document.
+ Their efforts significantly contributed to the success of Diameter.
+
+A.2. RFC 3588
The authors would like to thank Nenad Trifunovic, Tony Johansson and
Pankaj Patel for their participation in the pre-IETF Document Reading
- Party. Allison Mankin, Jonathan Wood and Bernard Aboba provided
- invaluable assistance in working out transport issues, and similarly
- with Steven Bellovin in the security area.
+ Party. Allison Mankin, Jonathan Wood, and Bernard Aboba provided
+ invaluable assistance in working out transport issues and this was
+ also the case with Steven Bellovin in the security area.
Paul Funk and David Mitton were instrumental in getting the Peer
State Machine correct, and our deep thanks go to them for their time.
Text in this document was also provided by Paul Funk, Mark Eklund,
- Mark Jones and Dave Spence. Jacques Caron provided many great
+ Mark Jones, and Dave Spence. Jacques Caron provided many great
comments as a result of a thorough review of the spec.
The authors would also like to acknowledge the following people for
@@ -8367,96 +8261,57 @@ A.2. RFC3588
David Frascone, Daniel C. Fox, Lol Grant, Ignacio Goyret, Nancy
Greene, Peter Heitman, Fredrik Johansson, Mark Jones, Martin Julien,
Bob Kopacz, Paul Krumviede, Fergal Ladley, Ryan Moats, Victor Muslin,
- Kenneth Peirce, John Schnizlein, Sumit Vakil, John R. Vollbrecht and
+ Kenneth Peirce, John Schnizlein, Sumit Vakil, John R. Vollbrecht, and
Jeff Weisberg.
Finally, Pat Calhoun would like to thank Sun Microsystems since most
of the effort put into this document was done while he was in their
employ.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 150]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
Appendix B. S-NAPTR Example
As an example, consider a client that wishes to resolve aaa:
- example1.com. The client performs a NAPTR query for that domain, and
- the following NAPTR records are returned:
+ ex1.example.com. The client performs a NAPTR query for that domain,
+ and the following NAPTR records are returned:
;; order pref flags service regexp replacement
IN NAPTR 50 50 "s" "aaa:diameter.tls.tcp" ""
- _diameter._tls.example1.com
+ _diameter._tls.ex1.example.com
IN NAPTR 100 50 "s" "aaa:diameter.tcp" ""
- _aaa._tcp.example1.com
+ _aaa._tcp.ex1.example.com
IN NAPTR 150 50 "s" "aaa:diameter.sctp" ""
- _diameter._sctp.example1.com
+ _diameter._sctp.ex1.example.com
- This indicates that the server supports TLS, TCP and SCTP in that
+ This indicates that the server supports TLS, TCP, and SCTP in that
order. If the client supports TLS, TLS will be used, targeted to a
- host determined by an SRV lookup of _diameter._tls.example1.com.
+
+
+
+Fajardo, et al. Standards Track [Page 148]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
+ host determined by an SRV lookup of _diameter._tls.ex1.example.com.
That lookup would return:
;; Priority Weight Port Target
- IN SRV 0 1 5060 server1.example1.com
- IN SRV 0 2 5060 server2.example1.com
+ IN SRV 0 1 5060 server1.ex1.example.com
+ IN SRV 0 2 5060 server2.ex1.example.com
As an alternative example, a client that wishes to resolve aaa:
- example2.com. The client performs a NAPTR query for that domain, and
- the following NAPTR records are returned:
+ ex2.example.com. The client performs a NAPTR query for that domain,
+ and the following NAPTR records are returned:
;; order pref flags service regexp replacement
IN NAPTR 150 50 "a" "aaa:diameter.tls.tcp" ""
- server1.example2.com
+ server1.ex2.example.com
IN NAPTR 150 50 "a" "aaa:diameter.tls.tcp" ""
- server2.example2.com
+ server2.ex2.example.com
This indicates that the server supports TCP available at the returned
host names.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 151]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
Appendix C. Duplicate Detection
As described in Section 9.4, accounting record duplicate detection is
@@ -8464,14 +8319,14 @@ Appendix C. Duplicate Detection
reasons:
o Failover to an alternate server. Where close to real-time
- performance is required, failover thresholds need to be kept low
- and this may lead to an increased likelihood of duplicates.
- Failover can occur at the client or within Diameter agents.
-
- o Failure of a client or agent after sending of a record from non-
- volatile memory, but prior to receipt of an application layer ACK
- and deletion of the record. record to be sent. This will result
- in retransmission of the record soon after the client or agent has
+ performance is required, failover thresholds need to be kept low.
+ This may lead to an increased likelihood of duplicates. Failover
+ can occur at the client or within Diameter agents.
+
+ o Failure of a client or agent after sending a record from non-
+ volatile memory, but prior to receipt of an application-layer ACK
+ and deletion of the record to be sent. This will result in
+ retransmission of the record soon after the client or agent has
rebooted.
o Duplicates received from RADIUS gateways. Since the
@@ -8481,48 +8336,48 @@ Appendix C. Duplicate Detection
o Implementation problems and misconfiguration.
- The T flag is used as an indication of an application layer
+ The T flag is used as an indication of an application-layer
retransmission event, e.g., due to failover to an alternate server.
It is defined only for request messages sent by Diameter clients or
agents. For instance, after a reboot, a client may not know whether
+
+
+
+Fajardo, et al. Standards Track [Page 149]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
it has already tried to send the accounting records in its non-
volatile memory before the reboot occurred. Diameter servers MAY use
the T flag as an aid when processing requests and detecting duplicate
messages. However, servers that do this MUST ensure that duplicates
are found even when the first transmitted request arrives at the
server after the retransmitted request. It can be used only in cases
- where no answer has been received from the Server for a request and
+ where no answer has been received from the server for a request and
the request is sent again, (e.g., due to a failover to an alternate
peer, due to a recovered primary peer or due to a client re-sending a
stored record from non-volatile memory such as after reboot of a
client or agent).
- In some cases the Diameter accounting server can delay the duplicate
+ In some cases, the Diameter accounting server can delay the duplicate
detection and accounting record processing until a post-processing
phase takes place. At that time records are likely to be sorted
according to the included User-Name and duplicate elimination is easy
- in this case. In other situations it may be necessary to perform
+ in this case. In other situations, it may be necessary to perform
real-time duplicate detection, such as when credit limits are imposed
or real-time fraud detection is desired.
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 152]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
In general, only generation of duplicates due to failover or re-
sending of records in non-volatile storage can be reliably detected
- by Diameter clients or agents. In such cases the Diameter client or
- agents can mark the message as possible duplicate by setting the T
+ by Diameter clients or agents. In such cases, the Diameter client or
+ agents can mark the message as a possible duplicate by setting the T
flag. Since the Diameter server is responsible for duplicate
- detection, it can choose to make use of the T flag or not, in order
- to optimize duplicate detection. Since the T flag does not affect
- interoperability, and may not be needed by some servers, generation
- of the T flag is REQUIRED for Diameter clients and agents, but MAY be
- implemented by Diameter servers.
+ detection, it can choose whether or not to make use of the T flag, in
+ order to optimize duplicate detection. Since the T flag does not
+ affect interoperability, and it may not be needed by some servers,
+ generation of the T flag is REQUIRED for Diameter clients and agents,
+ but it MAY be implemented by Diameter servers.
As an example, it can be usually be assumed that duplicates appear
within a time window of longest recorded network partition or device
@@ -8535,40 +8390,39 @@ Internet-Draft Diameter Base Protocol January 2011
The following is an example of how the T flag may be used by the
server to detect duplicate requests.
-
A Diameter server MAY check the T flag of the received message to
determine if the record is a possible duplicate. If the T flag is
set in the request message, the server searches for a duplicate
within a configurable duplication time window backward and
forward. This limits database searching to those records where
- the T flag is set. In a well run network, network partitions and
+ the T flag is set. In a well-run network, network partitions and
+
+
+
+Fajardo, et al. Standards Track [Page 150]
+
+RFC 6733 Diameter Base Protocol October 2012
+
+
device faults will presumably be rare events, so this approach
represents a substantial optimization of the duplicate detection
process. During failover, it is possible for the original record
- to be received after the T flag marked record, due to differences
+ to be received after the T-flag-marked record, due to differences
in network delays experienced along the path by the original and
duplicate transmissions. The likelihood of this occurring
increases as the failover interval is decreased. In order to be
- able to detect out of order duplicates, the Diameter server should
- use backward and forward time windows when performing duplicate
- checking for the T flag marked request. For example, in order to
- allow time for the original record to exit the network and be
- recorded by the accounting server, the Diameter server can delay
- processing records with the T flag set until a time period
- TIME_WAIT + RECORD_PROCESSING_TIME has elapsed after the closing
- of the original transport connection. After this time period has
- expired, then it may check the T flag marked records against the
+ able to detect duplicates that are out of order, the Diameter
+ server should use backward and forward time windows when
+ performing duplicate checking for the T-flag-marked request. For
+ example, in order to allow time for the original record to exit
+ the network and be recorded by the accounting server, the Diameter
+ server can delay processing records with the T flag set until a
+ time period TIME_WAIT + RECORD_PROCESSING_TIME has elapsed after
+ the closing of the original transport connection. After this time
+ period, it may check the T-flag-marked records against the
database with relative assurance that the original records, if
sent, have been received and recorded.
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 153]
-
-Internet-Draft Diameter Base Protocol January 2011
-
-
Appendix D. Internationalized Domain Names
To be compatible with the existing DNS infrastructure and simplify
@@ -8579,14 +8433,7 @@ Appendix D. Internationalized Domain Names
recommendations in [RFC4690] and [RFC5890]. Applications that
provide support for IDNs outside of the Diameter protocol but
interacting with it SHOULD use the representation and conversion
- framework described in [RFC5890], [RFC5891] and [RFC3492].
-
-
-
-
-
-
-
+ framework described in [RFC5890], [RFC5891], and [RFC3492].
@@ -8608,21 +8455,9 @@ Appendix D. Internationalized Domain Names
-
-
-
-
-
-
-
-
-
-
-
-
-Fajardo, et al. Expires July 24, 2011 [Page 154]
+Fajardo, et al. Standards Track [Page 151]
-Internet-Draft Diameter Base Protocol January 2011
+RFC 6733 Diameter Base Protocol October 2012
Authors' Addresses
@@ -8634,7 +8469,7 @@ Authors' Addresses
USA
Phone: +1-908-421-1845
Jari Arkko
@@ -8643,7 +8478,7 @@ Authors' Addresses
Finland
Phone: +358 40 5079256
John Loughney
@@ -8653,17 +8488,17 @@ Authors' Addresses
US
Phone: +1-650-283-8068
- Glenn Zorn
+ Glen Zorn (editor)
Network Zen
- 1310 East Thomas Street
- Seattle, WA 98102
- US
+ 227/358 Thanon Sanphawut
+ Bang Na, Bangkok 10260
+ Thailand
- Phone:
+ Phone: +66 (0) 87-0404617
@@ -8676,6 +8511,5 @@ Authors' Addresses
-Fajardo, et al. Expires July 24, 2011 [Page 155]
+Fajardo, et al. Standards Track [Page 152]
-
diff --git a/lib/diameter/doc/standard/rfc6737.txt b/lib/diameter/doc/standard/rfc6737.txt
new file mode 100644
index 0000000000..50aa33e98f
--- /dev/null
+++ b/lib/diameter/doc/standard/rfc6737.txt
@@ -0,0 +1,339 @@
+
+
+
+
+
+
+Internet Engineering Task Force (IETF) K. Jiao
+Request for Comments: 6737 Huawei
+Category: Standards Track G. Zorn
+ISSN: 2070-1721 Network Zen
+ October 2012
+
+
+ The Diameter Capabilities Update Application
+
+Abstract
+
+ This document defines a new Diameter application and associated
+ Command Codes. The Capabilities Update application is intended to
+ allow the dynamic update of certain Diameter peer capabilities while
+ the peer-to-peer connection is in the open state.
+
+Status of This Memo
+
+ This is an Internet Standards Track document.
+
+ This document is a product of the Internet Engineering Task Force
+ (IETF). It represents the consensus of the IETF community. It has
+ received public review and has been approved for publication by the
+ Internet Engineering Steering Group (IESG). Further information on
+ Internet Standards is available in Section 2 of RFC 5741.
+
+ Information about the current status of this document, any errata,
+ and how to provide feedback on it may be obtained at
+ http://www.rfc-editor.org/info/rfc6737.
+
+Copyright Notice
+
+ Copyright (c) 2012 IETF Trust and the persons identified as the
+ document authors. All rights reserved.
+
+ This document is subject to BCP 78 and the IETF Trust's Legal
+ Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info) in effect on the date of
+ publication of this document. Please review these documents
+ carefully, as they describe your rights and restrictions with respect
+ to this document. Code Components extracted from this document must
+ include Simplified BSD License text as described in Section 4.e of
+ the Trust Legal Provisions and are provided without warranty as
+ described in the Simplified BSD License.
+
+
+
+
+
+
+
+Jiao & Zorn Standards Track [Page 1]
+
+RFC 6737 Diameter Capabilities Update October 2012
+
+
+Table of Contents
+
+ 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 2
+ 2. Specification of Requirements . . . . . . . . . . . . . . . . . 2
+ 3. Diameter Protocol Considerations . . . . . . . . . . . . . . . 3
+ 4. Capabilities Update . . . . . . . . . . . . . . . . . . . . . . 3
+ 4.1. Command Code Values . . . . . . . . . . . . . . . . . . . . 4
+ 4.1.1. Capabilities-Update-Request . . . . . . . . . . . . . . 4
+ 4.1.2. Capabilities-Update-Answer . . . . . . . . . . . . . . 5
+ 5. Security Considerations . . . . . . . . . . . . . . . . . . . . 5
+ 6. IANA Considerations . . . . . . . . . . . . . . . . . . . . . . 5
+ 6.1. Application Identifier . . . . . . . . . . . . . . . . . . 5
+ 6.2. Command Codes . . . . . . . . . . . . . . . . . . . . . . . 5
+ 7. Contributors . . . . . . . . . . . . . . . . . . . . . . . . . 5
+ 8. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 5
+ 9. References . . . . . . . . . . . . . . . . . . . . . . . . . . 6
+ 9.1. Normative References . . . . . . . . . . . . . . . . . . . 6
+ 9.2. Informative References . . . . . . . . . . . . . . . . . . 6
+
+1. Introduction
+
+ Capabilities exchange is an important component of the Diameter base
+ protocol [RFC6733], allowing peers to exchange identities and
+ Diameter capabilities (protocol version number, supported Diameter
+ applications, security mechanisms, etc.). As defined in RFC 3588,
+ however, the capabilities exchange process takes place only once, at
+ the inception of a transport connection between a given pair of
+ peers. Therefore, if a peer's capabilities change (due to a software
+ update, for example), the existing connection(s) must be torn down
+ (along with all of the associated user sessions) and restarted before
+ the modified capabilities can be advertised.
+
+ This document defines a new Diameter application intended to allow
+ the dynamic update of a subset of Diameter peer capabilities over an
+ existing connection. Because the Capabilities Update application
+ specified herein operates over an existing transport connection,
+ modification of certain capabilities is prohibited. Specifically,
+ modifying the security mechanism in use is not allowed; if the
+ security method used between a pair of peers is changed, the affected
+ connection MUST be restarted.
+
+2. Specification of Requirements
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in RFC 2119 [RFC2119].
+
+
+
+
+
+Jiao & Zorn Standards Track [Page 2]
+
+RFC 6737 Diameter Capabilities Update October 2012
+
+
+3. Diameter Protocol Considerations
+
+ This section details the relationship of the Diameter Capabilities
+ Update application to the Diameter base protocol.
+
+ This document specifies Diameter Application-Id 10. Diameter nodes
+ conforming to this specification MUST advertise support by including
+ the value 10 in the Auth-Application-Id of the Capabilities-Exchange-
+ Request (CER) and Capabilities-Exchange-Answer (CEA) commands
+ [RFC6733].
+
+4. Capabilities Update
+
+ When the capabilities of a Diameter node conforming to this
+ specification change, the node MUST notify all of the nodes with
+ which it has an open transport connection and which have also
+ advertised support for the Capabilities Update application using the
+ Capabilities-Update-Request (CUR) message (Section 4.1.1). This
+ message allows the update of a peer's capabilities (supported
+ Diameter applications, etc.).
+
+ A Diameter node only issues a given command to those peers that have
+ advertised support for the Diameter application that defines the
+ command; a Diameter node must cache the supported applications in
+ order to ensure that unrecognized commands and/or Attribute-Value
+ Pairs (AVPs) are not unnecessarily sent to a peer.
+
+ The receiver of the CUR MUST determine common applications by
+ computing the intersection of its own set of supported Application
+ Ids against all of the Application-Id AVPs (Auth-Application-Id,
+ Acct-Application-Id, and Vendor-Specific-Application-Id) present in
+ the CUR. The value of the Vendor-Id AVP in the Vendor-Specific-
+ Application-Id MUST NOT be used during computation.
+
+ If the receiver of a CUR does not have any applications in common
+ with the sender, then it MUST return a Capabilities-Update-Answer
+ (CUA) (Section 4.1.2) with the Result-Code AVP set to
+ DIAMETER_NO_COMMON_APPLICATION [RFC6733], and it SHOULD disconnect
+ the transport-layer connection. However, if active sessions are
+ using the connection, peers MAY delay disconnection until the
+ sessions can be redirected or gracefully terminated. Note that
+ receiving a CUA from a peer advertising itself as a relay (see
+ [RFC6733], Section 2.4) MUST be interpreted as having common
+ applications with the peer.
+
+ As for CER/CEA messages, the CUR and CUA messages MUST NOT be
+ proxied, redirected, or relayed.
+
+
+
+
+Jiao & Zorn Standards Track [Page 3]
+
+RFC 6737 Diameter Capabilities Update October 2012
+
+
+ Even though the CUR/CUA messages cannot be proxied, it is still
+ possible for an upstream agent to receive a message for which there
+ are no peers available to handle the application that corresponds to
+ the Command Code. This could happen if, for example, the peers are
+ too busy or down. In such instances, the 'E' bit MUST be set in the
+ answer message with the Result-Code AVP set to
+ DIAMETER_UNABLE_TO_DELIVER to inform the downstream peer to take
+ action (e.g., re-routing requests to an alternate peer).
+
+4.1. Command Code Values
+
+ This section defines Command Code [RFC6733] values that MUST be
+ supported by all Diameter implementations conforming to this
+ specification. The following Command Codes are defined in this
+ document: Capabilities-Update-Request (CUR, Section 4.1.1), and
+ Capabilities-Update-Answer (CUA, Section 4.1.2). The Diameter
+ Command Code Format (CCF) ([RFC6733], Section 3.2) is used in the
+ definitions.
+
+4.1.1. Capabilities-Update-Request
+
+ The Capabilities-Update-Request (CUR), indicated by the Command Code
+ set to 328 and the Command Flags' 'R' bit set, is sent to update
+ local capabilities. Upon detection of a transport failure, this
+ message MUST NOT be sent to an alternate peer.
+
+ When Diameter is run over the Stream Control Transmission Protocol
+ (SCTP) [RFC4960], which allows connections to span multiple
+ interfaces and multiple IP addresses, the Capabilities-Update-Request
+ message MUST contain one Host-IP-Address AVP for each potential IP
+ address that may be locally used when transmitting Diameter messages.
+
+ Message Format
+
+ <CUR> ::= < Diameter Header: 328, REQ >
+ { Origin-Host }
+ { Origin-Realm }
+ 1* { Host-IP-Address }
+ { Vendor-Id }
+ { Product-Name }
+ [ Origin-State-Id ]
+ * [ Supported-Vendor-Id ]
+ * [ Auth-Application-Id ]
+ * [ Acct-Application-Id ]
+ * [ Vendor-Specific-Application-Id ]
+ [ Firmware-Revision ]
+ * [ AVP ]
+
+
+
+
+Jiao & Zorn Standards Track [Page 4]
+
+RFC 6737 Diameter Capabilities Update October 2012
+
+
+4.1.2. Capabilities-Update-Answer
+
+ The Capabilities-Update-Answer, indicated by the Command Code set to
+ 328 and the Command Flags' 'R' bit cleared, is sent in response to a
+ CUR message.
+
+ Message Format
+
+ <CUA> ::= < Diameter Header: 328 >
+ { Origin-Host }
+ { Origin-Realm }
+ { Result-Code }
+ [ Error-Message ]
+ * [ AVP ]
+
+5. Security Considerations
+
+ The security considerations applicable to the Diameter base protocol
+ [RFC6733] are also applicable to this document.
+
+6. IANA Considerations
+
+ This section explains the criteria to be used by the IANA for
+ assignment of numbers within namespaces used within this document.
+
+6.1. Application Identifier
+
+ This specification assigns the value 10 (Diameter Capabilities
+ Update) from the Application Identifiers namespace [RFC6733]. See
+ Section 3 for the assignment of the namespace in this specification.
+
+6.2. Command Codes
+
+ This specification assigns the value 328 (Capabilities-Update-
+ Request/Capabilities-Update-Answer (CUR/CUA)) from the Command Codes
+ namespace [RFC6733]. See Section 4.1 for the assignment of the
+ namespace in this specification.
+
+7. Contributors
+
+ This document is based upon work done by Tina Tsou.
+
+8. Acknowledgements
+
+ Thanks to Sebastien Decugis, Niklas Neumann, Subash Comerica, Lionel
+ Morand, Dan Romascanu, Dan Harkins, and Ravi for helpful review and
+ discussion.
+
+
+
+
+Jiao & Zorn Standards Track [Page 5]
+
+RFC 6737 Diameter Capabilities Update October 2012
+
+
+9. References
+
+9.1. Normative References
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC6733] Fajardo, V., Arkko, J., Loughney, J., and G. Zorn,
+ "Diameter Base Protocol", RFC 6733, October 2012.
+
+9.2. Informative References
+
+ [RFC4960] Stewart, R., "Stream Control Transmission Protocol",
+ RFC 4960, September 2007.
+
+Authors' Addresses
+
+ Jiao Kang
+ Huawei Technologies
+ Section F1, Huawei Industrial Base
+ Bantian, Longgang District
+ Shenzhen 518129
+ P.R. China
+
+
+
+ Glen Zorn
+ Network Zen
+ 227/358 Thanon Sanphawut
+ Bang Na, Bangkok 10260
+ Thailand
+
+ Phone: +66 (0) 909-201060
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Jiao & Zorn Standards Track [Page 6]
+
diff --git a/lib/diameter/make/release_targets.mk b/lib/diameter/make/release_targets.mk
deleted file mode 100644
index 5a3b585cbc..0000000000
--- a/lib/diameter/make/release_targets.mk
+++ /dev/null
@@ -1,92 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1997-2011. All Rights Reserved.
-#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# 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%
-#
-
-ifeq ($(TOPDOC),)
-$(HTMLDIR)/index.html: $(XML_FILES)
- date=`date +"%B %e %Y"`; \
- $(XSLTPROC) --noout --stringparam outdir $(HTMLDIR) --stringparam docgen "$(DOCGEN)" --stringparam topdocdir "$(TOPDOCDIR)" \
- --stringparam pdfdir "$(PDFDIR)" \
- --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude \
- -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_html_entities $(DOCGEN)/priv/xsl/db_html.xsl book.xml
-endif
-
-$(HTMLDIR)/users_guide.html: $(XML_FILES)
- date=`date +"%B %e %Y"`; \
- $(XSLTPROC) --noout --stringparam outdir $(HTMLDIR) --stringparam docgen "$(DOCGEN)" --stringparam topdocdir "$(TOPDOCDIR)" \
- --stringparam pdfdir "$(PDFDIR)" \
- --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude \
- -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_html_entities $(DOCGEN)/priv/xsl/db_html.xsl book.xml
-
-
-%.fo: $(XML_FILES)
- date=`date +"%B %e %Y"`; \
- $(XSLTPROC) --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" \
- --stringparam appver "$(VSN)" --xinclude \
- -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_html_entities $(DOCGEN)/priv/xsl/db_pdf.xsl book.xml > $@
-
-
-
-# ------------------------------------------------------------------------
-# The following targets just exist in the documentation directory
-# ------------------------------------------------------------------------
-ifneq ($(XML_FILES),)
-
-# ----------------------------------------------------
-# Generation of application index data
-# ----------------------------------------------------
-$(HTMLDIR)/$(APPLICATION).eix: $(XML_FILES)
- date=`date +"%B %e %Y"`; \
- $(XSLTPROC) --stringparam docgen "$(DOCGEN)" \
- --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude \
- -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_html_entities $(DOCGEN)/priv/xsl/db_eix.xsl book.xml > $@
-
-docs:
-#docs: $(HTMLDIR)/$(APPLICATION).eix
-
-# ----------------------------------------------------
-# Local documentation target for testing
-# ----------------------------------------------------
-local_docs: TOPDOCDIR=.
-local_docs: local_copy_of_topdefs docs
-
-local_html: TOPDOCDIR=.
-local_html: local_copy_of_topdefs html
-
-local_copy_of_topdefs:
- $(INSTALL) $(DOCGEN)/priv/css/otp_doc.css $(HTMLDIR)
- $(INSTALL) $(DOCGEN)/priv/images/erlang-logo.png $(HTMLDIR)
- $(INSTALL) $(DOCGEN)/priv/images/erlang-logo.gif $(HTMLDIR)
- $(INSTALL_DIR) $(HTMLDIR)/js/flipmenu
- $(INSTALL) $(DOCGEN)/priv/js/flipmenu/flip_closed.gif \
- $(DOCGEN)/priv/js/flipmenu/flip_open.gif \
- $(DOCGEN)/priv/js/flipmenu/flip_static.gif \
- $(DOCGEN)/priv/js/flipmenu/flipmenu.js $(HTMLDIR)/js/flipmenu
-
-endif
-
-# ----------------------------------------------------
-# Standard release target
-# ----------------------------------------------------
-
-ifneq ($(PREFIX),)
-
-release release_docs release_tests release_html:
- $(MAKE) $(MFLAGS) RELEASE_PATH=$(PREFIX) $(TARGET_MAKEFILE) $@_spec
-
-endif
diff --git a/lib/diameter/make/rules.mk.in b/lib/diameter/make/rules.mk.in
deleted file mode 100644
index cd3c297d75..0000000000
--- a/lib/diameter/make/rules.mk.in
+++ /dev/null
@@ -1,193 +0,0 @@
-#-*-makefile-*- ; force emacs to enter makefile-mode
-# ----------------------------------------------------
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2009-2011. All Rights Reserved.
-#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# 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%
-
-.SUFFIXES: .erl .beam .yrl .hrl .xml .xmlsrc .html \
- .3 .1 .pdf .fo .el .elc
-
-# ----------------------------------------------------
-# Common macros
-# ----------------------------------------------------
-DEFAULT_TARGETS = opt debug release release_docs clean docs
-
-
-# Slash separated list of return values from $(origin VAR)
-# that are untrusted - set default in this file instead.
-# The list is not space separated since some return values
-# contain space, and we want to use $(findstring ...) to
-# search the list.
-DUBIOUS_ORIGINS = /undefined/environment/
-
-
-# # ----------------------------------------------------
-# # TARGET definition
-# # ----------------------------------------------------
-# # TARGET = @TARGET@
-# ifneq ($(OVERRIDE_TARGET),)
-# ifneq ($(TARGET), $(OVERRIDE_TARGET))
-# $(warning overriding $$(TARGET) = \
-# "$(TARGET)" \
-# with \
-# $$(OVERRIDE_TARGET) = \
-# "$(OVERRIDE_TARGET)")
-# override TARGET := $(OVERRIDE_TARGET)
-# endif
-# endif
-#
-
-# ----------------------------------------------------
-# Command macros
-# ----------------------------------------------------
-PREFIX = @prefix@
-INSTALL = @INSTALL@
-INSTALL_DIR = @INSTALL_DIR@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@
-INSTALL_SCRIPT = @INSTALL_SCRIPT@
-INSTALL_DATA = @INSTALL_DATA@
-
-
-# ----------------------------------------------------
-# Erlang language section
-# ----------------------------------------------------
-ERL_ROOT_DIR = @ERLANG_ROOT_DIR@
-ERL_LIB_DIR = @ERLANG_LIB_DIR@
-DOCGEN_DIR = @ERLANG_LIB_DIR_erl_docgen@
-TEST_SERVER_DIR = @ERLANG_LIB_VER_test_server@
-EMULATOR = beam
-ERL_COMPILE_FLAGS += +debug_info
-ERLC_WFLAGS = -W
-ERLC = $(ERL_ROOT_DIR)/bin/erlc $(ERLC_WFLAGS) $(ERLC_FLAGS)
-ERL = $(ERL_ROOT_DIR)/bin/erl -boot start_clean
-#ERLC = @ERLC@ $(ERLC_WFLAGS) $(ERLC_FLAGS)
-#ERL = @ERL@ -boot start_clean
-
-ifneq (,$(findstring $(origin EBIN),$(DUBIOUS_ORIGINS)))
-EBIN = ../../ebin
-endif
-
-# Generated (non ebin) files...
-ifneq (,$(findstring $(origin EGEN),$(DUBIOUS_ORIGINS)))
-EGEN = .
-endif
-
-ifneq (,$(findstring $(origin ESRC),$(DUBIOUS_ORIGINS)))
-ESRC = .
-endif
-
-$(EBIN)/%.beam: $(EGEN)/%.erl
- $(ERLC) $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
-
-$(EBIN)/%.beam: $(ESRC)/%.erl
- $(ERLC) $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
-
-.erl.beam:
- $(ERLC) $(ERL_COMPILE_FLAGS) -o$(dir $@) $<
-
-
-#
-# When .erl files are automatically created GNU make removes them if
-# they were the result of a chain of implicit rules. To prevent this
-# we say that all .erl files are "precious".
-#
-.PRECIOUS: %.erl %.fo
-
-
-# ----------------------------------------------------
-# Documentation section
-# ----------------------------------------------------
-# export VSN
-
-# TOPDOCDIR=../../../../doc
-
-DOCDIR = ..
-
-PDFDIR=$(DOCDIR)/pdf
-
-HTMLDIR = $(DOCDIR)/html
-
-MAN1DIR = $(DOCDIR)/man1
-MAN2DIR = $(DOCDIR)/man2
-MAN3DIR = $(DOCDIR)/man3
-MAN4DIR = $(DOCDIR)/man4
-MAN6DIR = $(DOCDIR)/man6
-MAN9DIR = $(DOCDIR)/man9
-
-# HTML & GIF files that always are generated and must be delivered
-XML_COLL_FILES = $(XML_APPLICATION_FILES) $(XML_PART_FILES)
-DEFAULT_HTML_FILES = \
- $(XML_COLL_FILES:%.xml=$(HTMLDIR)/%_frame.html) \
- $(XML_COLL_FILES:%.xml=$(HTMLDIR)/%_first.html) \
- $(XML_COLL_FILES:%.xml=$(HTMLDIR)/%_term.html) \
- $(XML_COLL_FILES:%.xml=$(HTMLDIR)/%_cite.html) \
- $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%_index.html) \
- $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.kwc) \
- $(HTMLDIR)/index.html
-
-DEFAULT_GIF_FILES = $(HTMLDIR)/min_head.gif
-
-#
-# Flags & Commands
-#
-XSLTPROC = @XSLTPROC@
-FOP = @FOP@
-
-DOCGEN=$(DOCGEN_DIR)
-
-$(MAN1DIR)/%.1:: %.xml
- date=`date +"%B %e %Y"`; \
- xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $<
-
-
-$(MAN2DIR)/%.2:: %.xml
- date=`date +"%B %e %Y"`; \
- xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $<
-
-
-$(MAN3DIR)/%.3:: %.xml
- date=`date +"%B %e %Y"`; \
- xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $<
-
-# left for compatibility
-$(MAN4DIR)/%.4:: %.xml
- date=`date +"%B %e %Y"`; \
- xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $<
-
-$(MAN4DIR)/%.5:: %.xml
- date=`date +"%B %e %Y"`; \
- xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $<
-
-# left for compatibility
-$(MAN6DIR)/%.6:: %_app.xml
- date=`date +"%B %e %Y"`; \
- xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $<
-
-$(MAN6DIR)/%.7:: %_app.xml
- date=`date +"%B %e %Y"`; \
- xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $<
-
-$(MAN9DIR)/%.9:: %.xml
- date=`date +"%B %e %Y"`; \
- xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $<
-
-
-.xmlsrc.xml:
- escript $(DOCGEN)/priv/bin/codeline_preprocessing.escript $< $@
-
-.fo.pdf:
- $(FOP) -fo $< -pdf $@
-
diff --git a/lib/diameter/make/subdir.mk b/lib/diameter/make/subdir.mk
deleted file mode 100644
index 24b08080ae..0000000000
--- a/lib/diameter/make/subdir.mk
+++ /dev/null
@@ -1,53 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1997-2011. All Rights Reserved.
-#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# 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%
-#
-# Make include file for otp
-
-.PHONY: debug opt release docs release_docs tests release_tests \
- clean depend valgrind
-
-#
-# Targets that don't affect documentation directories
-#
-opt debug release docs release_docs tests release_tests clean depend valgrind:
- @set -e ; \
- app_pwd=`pwd` ; \
- if test -f vsn.mk; then \
- echo "=== Entering application" `basename $$app_pwd` ; \
- fi ; \
- case "$(MAKE)" in *clearmake*) tflag="-T";; *) tflag="";; esac; \
- for d in $(SUB_DIRS); do \
- if test -f $$d/SKIP ; then \
- echo "=== Skipping subdir $$d, reason:" ; \
- cat $$d/SKIP ; \
- echo "===" ; \
- else \
- if test ! -d $$d ; then \
- echo "=== Skipping subdir $$d, it is missing" ; \
- else \
- xflag="" ; \
- if test -f $$d/ignore_config_record.inf; then \
- xflag=$$tflag ; \
- fi ; \
- (cd $$d && $(MAKE) $$xflag $@) || exit $$? ; \
- fi ; \
- fi ; \
- done ; \
- if test -f vsn.mk; then \
- echo "=== Leaving application" `basename $$app_pwd` ; \
- fi
diff --git a/lib/diameter/make/target.mk b/lib/diameter/make/target.mk
deleted file mode 100644
index 4ae470b9e2..0000000000
--- a/lib/diameter/make/target.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-ifeq ($(OVERRIDE_TARGET),)
-
-ifeq ($(TARGET),)
-
-TARGET := $(shell $(DIAMETER_TOP)/autoconf/config.guess)
-
-else
-
-endif
-
-else
-
-ifneq ($(TARGET),)
-
-ifneq ($(TARGET), $(OVERRIDE_TARGET))
-$(warning overriding $$(TARGET) = \
- "$(TARGET)" \
- with \
- $$(OVERRIDE_TARGET) = \
- "$(OVERRIDE_TARGET)")
-else
-endif
-
-override TARGET := $(OVERRIDE_TARGET)
-
-else
-
-TARGET := $(OVERRIDE_TARGET)
-
-endif
-
-endif
-
diff --git a/lib/diameter/src/Makefile b/lib/diameter/src/Makefile
index 99c343275b..60bb7e6a10 100644
--- a/lib/diameter/src/Makefile
+++ b/lib/diameter/src/Makefile
@@ -16,13 +16,8 @@
#
# %CopyrightEnd%
-ifeq ($(ERL_TOP),)
-include $(DIAMETER_TOP)/make/target.mk
-include $(DIAMETER_TOP)/make/$(TARGET)/rules.mk
-else
include $(ERL_TOP)/make/target.mk
include $(ERL_TOP)/make/$(TARGET)/otp.mk
-endif
# ----------------------------------------------------
# Application version
@@ -124,7 +119,7 @@ ERL_COMPILE_FLAGS += \
# erl/hrl from dictionary file.
gen/diameter_gen_%.erl gen/diameter_gen_%.hrl: dict/%.dia
- ../bin/diameterc -o gen -i $(EBIN) $<
+ $(dia_verbose)../bin/diameterc -o gen -i $(EBIN) $<
opt: $(TARGET_FILES)
@@ -133,17 +128,17 @@ debug:
# The dictionary parser.
gen/$(DICT_YRL).erl: compiler/$(DICT_YRL).yrl
- $(ERLC) -Werror -o $(@D) $<
+ $(yecc_verbose)$(ERLC) -Werror -o $(@D) $<
# Generate the app file.
$(APP_TARGET): $(APP_SRC) ../vsn.mk modules.mk
- M=`echo $(notdir $(APP_MODULES)) | tr ' ' ,`; \
+ $(gen_verbose)M=`echo $(notdir $(APP_MODULES)) | tr ' ' ,`; \
sed -e 's;%VSN%;$(VSN);' \
-e "s;%MODULES%;$$M;" \
$< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
app: $(APP_TARGET) $(APPUP_TARGET)
dict: $(DICT_ERLS)
@@ -210,11 +205,7 @@ dialyze: opt $(PLT)
# Release targets
# ----------------------------------------------------
-ifeq ($(ERL_TOP),)
-include $(DIAMETER_TOP)/make/release_targets.mk
-else
include $(ERL_TOP)/make/otp_release_targets.mk
-endif
# Can't $(INSTALL_DIR) more than one directory at a time on Solaris.
@@ -263,7 +254,7 @@ depend: depend.mk
# Generate dependencies makefile.
depend.mk: depend.sed $(MODULES:%=%.erl) Makefile
- (for f in $(MODULES); do \
+ $(gen_verbose)(for f in $(MODULES); do \
(echo $$f; cat $$f.erl) | sed -f $<; \
done) \
> $@
diff --git a/lib/diameter/src/base/diameter.appup.src b/lib/diameter/src/base/diameter.appup.src
index 9b2a7d18ab..a04a387918 100644
--- a/lib/diameter/src/base/diameter.appup.src
+++ b/lib/diameter/src/base/diameter.appup.src
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -20,30 +20,21 @@
{"%VSN%",
[
- {"0.9", [{restart_application, diameter}]},
- {"0.10", [{restart_application, diameter}]},
- {"1.0", [{restart_application, diameter}]},
- {"1.1", [%% new code
- {add_module, diameter_transport},
- %% modified code
- {load, diameter_sctp},
- {load, diameter_stats},
- {load, diameter_service},
- {load, diameter_config},
- {load, diameter_codec},
- {load, diameter_watchdog},
- {load, diameter_peer},
- {load, diameter_peer_fsm},
- {load, diameter},
- %% unmodified but including modified diameter.hrl
- {load, diameter_callback},
- {load, diameter_capx},
- {load, diameter_types}]}
+ {"0.9", [{restart_application, diameter}]},
+ {"0.10", [{restart_application, diameter}]},
+ {"1.0", [{restart_application, diameter}]},
+ {"1.1", [{restart_application, diameter}]},
+ {"1.2", [{restart_application, diameter}]},
+ {"1.2.1", [{restart_application, diameter}]},
+ {"1.3", [{load_module, diameter_service}]}
],
[
- {"0.9", [{restart_application, diameter}]},
- {"0.10", [{restart_application, diameter}]},
- {"1.0", [{restart_application, diameter}]},
- {"1.1", [{restart_application, diameter}]}
+ {"0.9", [{restart_application, diameter}]},
+ {"0.10", [{restart_application, diameter}]},
+ {"1.0", [{restart_application, diameter}]},
+ {"1.1", [{restart_application, diameter}]},
+ {"1.2", [{restart_application, diameter}]},
+ {"1.2.1", [{restart_application, diameter}]},
+ {"1.3", [{load_module, diameter_service}]}
]
}.
diff --git a/lib/diameter/src/base/diameter.erl b/lib/diameter/src/base/diameter.erl
index 4f90b741ae..8f9901907a 100644
--- a/lib/diameter/src/base/diameter.erl
+++ b/lib/diameter/src/base/diameter.erl
@@ -44,6 +44,8 @@
stop/0]).
-export_type([evaluable/0,
+ restriction/0,
+ sequence/0,
app_alias/0,
service_name/0,
capability/0,
@@ -280,11 +282,23 @@ call(SvcName, App, Message) ->
| fun()
| maybe_improper_list(evaluable(), list()).
+-type sequence()
+ :: {'Unsigned32'(), 0..32}.
+
+-type restriction()
+ :: false
+ | node
+ | nodes
+ | [node()]
+ | evaluable().
+
%% Options passed to start_service/2
-type service_opt()
:: capability()
- | {application, [application_opt()]}.
+ | {application, [application_opt()]}
+ | {restrict_connections, restriction()}
+ | {sequence, sequence() | evaluable()}.
-type application_opt()
:: {alias, app_alias()}
@@ -316,6 +330,8 @@ call(SvcName, App, Message) ->
| {applications, [app_alias()]}
| {capabilities, [capability()]}
| {capabilities_cb, evaluable()}
+ | {capx_timeout, 'Unsigned32'()}
+ | {disconnect_cb, evaluable()}
| {watchdog_timer, 'Unsigned32'() | {module(), atom(), list()}}
| {reconnect_timer, 'Unsigned32'()}
| {private, any()}.
diff --git a/lib/diameter/src/base/diameter_capx.erl b/lib/diameter/src/base/diameter_capx.erl
index 6c4d60ee9b..c6c3d2934d 100644
--- a/lib/diameter/src/base/diameter_capx.erl
+++ b/lib/diameter/src/base/diameter_capx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -141,7 +141,9 @@ cap('Host-IP-Address', Vs)
when is_list(Vs) ->
lists:map(fun ipaddr/1, Vs);
-cap('Firmware-Revision', V) ->
+cap(K, V)
+ when K == 'Firmware-Revision';
+ K == 'Origin-State-Id' ->
[V];
cap(_, Vs)
@@ -149,7 +151,7 @@ cap(_, Vs)
Vs;
cap(K, V) ->
- ?THROW({invalid, K, V}).
+ ?THROW({invalid, {K,V}}).
ipaddr(A) ->
try
diff --git a/lib/diameter/src/base/diameter_codec.erl b/lib/diameter/src/base/diameter_codec.erl
index 421e280422..0b0bfe3f0a 100644
--- a/lib/diameter/src/base/diameter_codec.erl
+++ b/lib/diameter/src/base/diameter_codec.erl
@@ -193,9 +193,11 @@ encode_avps(Avps) ->
msg_header(Mod, 'answer-message' = MsgName, Header) ->
?BASE = Mod,
- #diameter_header{cmd_code = Code} = Header,
- {_, Flags, ApplId} = ?BASE:msg_header(MsgName),
- {Code, Flags, ApplId};
+ #diameter_header{application_id = Aid,
+ cmd_code = Code}
+ = Header,
+ {-1, Flags, ?DIAMETER_APP_ID_COMMON} = ?BASE:msg_header(MsgName),
+ {Code, Flags, Aid};
msg_header(Mod, MsgName, _) ->
Mod:msg_header(MsgName).
@@ -333,6 +335,9 @@ decode_header(_) ->
%% wraparound counter. The 8-bit counter is incremented each time the
%% system is restarted.
+sequence_numbers({_,_} = T) ->
+ T;
+
sequence_numbers(#diameter_packet{bin = Bin})
when is_binary(Bin) ->
sequence_numbers(Bin);
diff --git a/lib/diameter/src/base/diameter_config.erl b/lib/diameter/src/base/diameter_config.erl
index e47f63f814..63d28f25a2 100644
--- a/lib/diameter/src/base/diameter_config.erl
+++ b/lib/diameter/src/base/diameter_config.erl
@@ -97,6 +97,9 @@
-record(monitor, {mref = make_ref() :: reference(),
service}). %% name
+%% The default sequence mask.
+-define(NOMASK, {0,32}).
+
%% Time to lay low before restarting a dead service.
-define(RESTART_SLEEP, 2000).
@@ -549,9 +552,11 @@ make_config(SvcName, Opts) ->
ok = encode_CER(COpts),
- Os = split(Opts, [{[fun erlang:is_boolean/1], false, share_peers},
- {[fun erlang:is_boolean/1], false, use_shared_peers},
- {[fun erlang:is_pid/1, false], false, monitor}]),
+ Os = split(Opts, fun opt/2, [{false, share_peers},
+ {false, use_shared_peers},
+ {false, monitor},
+ {?NOMASK, sequence},
+ {nodes, restrict_connections}]),
%% share_peers and use_shared_peers are currently undocumented.
#service{name = SvcName,
@@ -559,11 +564,66 @@ make_config(SvcName, Opts) ->
capabilities = Caps},
options = Os}.
+split(Opts, F, Defs) ->
+ [{K, F(K, get_opt(K, Opts, D))} || {D,K} <- Defs].
+
+opt(K, false = B)
+ when K /= sequence ->
+ B;
+
+opt(K, true = B)
+ when K == share_peer;
+ K == use_shared_peers ->
+ B;
+
+opt(monitor, P)
+ when is_pid(P) ->
+ P;
+
+opt(restrict_connections, T)
+ when T == node;
+ T == nodes;
+ T == [];
+ is_atom(hd(T)) ->
+ T;
+
+opt(restrict_connections = K, F) ->
+ try diameter_lib:eval(F) of %% no guarantee that it won't fail later
+ Nodes when is_list(Nodes) ->
+ F;
+ V ->
+ ?THROW({value, {K,V}})
+ catch
+ E:R ->
+ ?THROW({value, {K, E, R, ?STACK}})
+ end;
+
+opt(sequence, {_,_} = T) ->
+ sequence(T);
+
+opt(sequence = K, F) ->
+ try diameter_lib:eval(F) of
+ T -> sequence(T)
+ catch
+ E:R ->
+ ?THROW({value, {K, E, R, ?STACK}})
+ end;
+
+opt(K, _) ->
+ ?THROW({value, K}).
+
+sequence({H,N} = T)
+ when 0 =< N, N =< 32, 0 =< H, 0 == H bsr N ->
+ T;
+
+sequence(_) ->
+ ?THROW({value, sequence}).
+
make_caps(Caps, Opts) ->
case diameter_capx:make_caps(Caps, Opts) of
{ok, T} ->
T;
- {error, {Reason, _}} ->
+ {error, Reason} ->
?THROW(Reason)
end.
@@ -663,21 +723,6 @@ get_opt(Key, List, Def) ->
_ -> ?THROW({arity, Key})
end.
-split(Opts, Defs) ->
- [{K, value(D, Opts)} || {_,_,K} = D <- Defs].
-
-value({Preds, Def, Key}, Opts) ->
- V = get_opt(Key, Opts, Def),
- lists:any(fun(P) -> pred(P,V) end, Preds)
- orelse ?THROW({value, Key}),
- V.
-
-pred(F, V)
- when is_function(F) ->
- F(V);
-pred(T, V) ->
- T == V.
-
cb(M,F) ->
try M:F() of
V -> V
diff --git a/lib/diameter/src/base/diameter_peer.erl b/lib/diameter/src/base/diameter_peer.erl
index 46b2ba9465..1b2f32ddff 100644
--- a/lib/diameter/src/base/diameter_peer.erl
+++ b/lib/diameter/src/base/diameter_peer.erl
@@ -76,7 +76,7 @@ notify(SvcName, T) ->
%%% # start/3
%%% ---------------------------------------------------------------------------
-%% From old code: make is restart.
+%% From old code: make it restart.
start(_T, _Opts, #diameter_service{}) ->
{error, restart}.
diff --git a/lib/diameter/src/base/diameter_peer_fsm.erl b/lib/diameter/src/base/diameter_peer_fsm.erl
index 302540e76b..858870566f 100644
--- a/lib/diameter/src/base/diameter_peer_fsm.erl
+++ b/lib/diameter/src/base/diameter_peer_fsm.erl
@@ -48,43 +48,64 @@
-include("diameter_internal.hrl").
-include("diameter_gen_base_rfc3588.hrl").
+%% Values of Disconnect-Cause in DPR.
-define(GOAWAY, ?'DIAMETER_BASE_DISCONNECT-CAUSE_DO_NOT_WANT_TO_TALK_TO_YOU').
-define(REBOOT, ?'DIAMETER_BASE_DISCONNECT-CAUSE_REBOOTING').
+-define(BUSY, ?'DIAMETER_BASE_DISCONNECT-CAUSE_BUSY').
-define(NO_INBAND_SECURITY, 0).
-define(TLS, 1).
%% Keys in process dictionary.
--define(CB_KEY, cb). %% capabilities callback
--define(DWA_KEY, dwa). %% outgoing DWA
--define(Q_KEY, q). %% transport start queue
--define(START_KEY, start). %% start of connected transport
+-define(CB_KEY, cb). %% capabilities callback
+-define(DPR_KEY, dpr). %% disconnect callback
+-define(DWA_KEY, dwa). %% outgoing DWA
+-define(REF_KEY, ref). %% transport_ref()
+-define(Q_KEY, q). %% transport start queue
+-define(START_KEY, start). %% start of connected transport
+-define(SEQUENCE_KEY, mask). %% mask for sequence numbers
+-define(RESTRICT_KEY, restrict). %% nodes for connection check
+
+%% The default sequence mask.
+-define(NOMASK, {0,32}).
%% A 2xxx series Result-Code. Not necessarily 2001.
-define(IS_SUCCESS(N), 2 == (N) div 1000).
+%% Guards.
+-define(IS_UINT32(N), (is_integer(N) andalso 0 =< N andalso 0 == N bsr 32)).
+-define(IS_TIMEOUT(N), ?IS_UINT32(N)).
+-define(IS_CAUSE(N), N == ?REBOOT; N == rebooting;
+ N == ?GOAWAY; N == goaway;
+ N == ?BUSY; N == busy).
+
%% RFC 3588:
%%
%% Timeout An application-defined timer has expired while waiting
%% for some event.
%%
-define(EVENT_TIMEOUT, 10000).
+%% Default timeout for reception of CER/CEA.
-%% How long to wait for a DPA in response to DPR before simply
-%% aborting. Used to distinguish between shutdown and not but there's
-%% not really any need. Stopping a service will require a timeout if
-%% the peer doesn't answer DPR so the value should be short-ish.
+%% Default timeout for DPA in response to DPR. A bit short but the
+%% timeout used to be hardcoded. (So it could be worse.)
-define(DPA_TIMEOUT, 1000).
+-type uint32() :: diameter:'Unsigned32'().
+
-record(state,
- {state = 'Wait-Conn-Ack' %% state of RFC 3588 Peer State Machine
- :: 'Wait-Conn-Ack' | recv_CER | 'Wait-CEA' | 'Open',
+ {state %% of RFC 3588 Peer State Machine
+ :: 'Wait-Conn-Ack' %% old code
+ | {'Wait-Conn-Ack', uint32()}
+ | recv_CER
+ | 'Wait-CEA' %% old code
+ | {'Wait-CEA', uint32(), uint32()}
+ | 'Open',
mode :: accept | connect | {connect, reference()},
- parent :: pid(),
- transport :: pid(),
+ parent :: pid(), %% watchdog process
+ transport :: pid(), %% transport process
service :: #diameter_service{},
- dpr = false :: false | {diameter:'Unsigned32'(),
- diameter:'Unsigned32'()}}).
+ dpr = false :: false | {uint32(), uint32()}}).
%% | hop by hop and end to end identifiers
%% There are non-3588 states possible as a consequence of 5.6.1 of the
@@ -121,7 +142,10 @@
%%% Output: Pid
%%% ---------------------------------------------------------------------------
--spec start(T, [Opt], #diameter_service{})
+-spec start(T, [Opt], #diameter_service{} %% from old code
+ | {diameter:sequence(),
+ diameter:restriction(),
+ #diameter_service{}})
-> pid()
when T :: {connect|accept, diameter:transport_ref()},
Opt :: diameter:transport_opt().
@@ -131,10 +155,8 @@
%% specified on the transport in question. Check here that the list is
%% still non-empty.
-start({_,_} = Type, Opts, #diameter_service{applications = Apps} = Svc) ->
- [] /= Apps orelse ?ERROR({no_apps, Type, Opts}),
- T = {self(), Type, Opts, Svc},
- {ok, Pid} = diameter_peer_fsm_sup:start_child(T),
+start({_,_} = Type, Opts, MS) ->
+ {ok, Pid} = diameter_peer_fsm_sup:start_child({self(), Type, Opts, MS}),
Pid.
start_link(T) ->
@@ -153,15 +175,28 @@ init(T) ->
proc_lib:init_ack({ok, self()}),
gen_server:enter_loop(?MODULE, [], i(T)).
-i({WPid, T, Opts, #diameter_service{capabilities = Caps} = Svc}) ->
- putr(?DWA_KEY, dwa(Caps)),
+i({WPid, Type, Opts, #diameter_service{} = Svc}) -> %% from old code
+ i({WPid, Type, Opts, {?NOMASK, [node() | nodes()], Svc}});
+
+i({WPid, T, Opts, {Mask, Nodes, #diameter_service{applications = Apps,
+ capabilities = LCaps}
+ = Svc}}) ->
+ [] /= Apps orelse ?ERROR({no_apps, T, Opts}),
+ putr(?DWA_KEY, dwa(LCaps)),
{M, Ref} = T,
diameter_stats:reg(Ref),
- {[Ts], Rest} = proplists:split(Opts, [capabilities_cb]),
- putr(?CB_KEY, {Ref, [F || {_,F} <- Ts]}),
+ {[Cs,Ds], Rest} = proplists:split(Opts, [capabilities_cb, disconnect_cb]),
+ putr(?CB_KEY, {Ref, [F || {_,F} <- Cs]}),
+ putr(?DPR_KEY, [F || {_, F} <- Ds]),
+ putr(?REF_KEY, Ref),
+ putr(?SEQUENCE_KEY, Mask),
+ putr(?RESTRICT_KEY, Nodes),
erlang:monitor(process, WPid),
{TPid, Addrs} = start_transport(T, Rest, Svc),
- #state{parent = WPid,
+ Tmo = proplists:get_value(capx_timeout, Opts, ?EVENT_TIMEOUT),
+ ?IS_TIMEOUT(Tmo) orelse ?ERROR({invalid, {capx_timeout, Tmo}}),
+ #state{state = {'Wait-Conn-Ack', Tmo},
+ parent = WPid,
transport = TPid,
mode = M,
service = svc(Svc, Addrs)}.
@@ -174,8 +209,8 @@ i({WPid, T, Opts, #diameter_service{capabilities = Caps} = Svc}) ->
%% watchdog start (start/2) succeeds regardless so as not to crash the
%% service.
-start_transport(T, Opts, #diameter_service{capabilities = Caps} = Svc) ->
- Addrs0 = Caps#diameter_caps.host_ip_address,
+start_transport(T, Opts, #diameter_service{capabilities = LCaps} = Svc) ->
+ Addrs0 = LCaps#diameter_caps.host_ip_address,
start_transport(Addrs0, {T, Opts, Svc}).
start_transport(Addrs0, T) ->
@@ -198,9 +233,9 @@ svc(Svc, []) ->
svc(Svc, Addrs) ->
readdr(Svc, Addrs).
-readdr(#diameter_service{capabilities = Caps0} = Svc, Addrs) ->
- Caps = Caps0#diameter_caps{host_ip_address = Addrs},
- Svc#diameter_service{capabilities = Caps}.
+readdr(#diameter_service{capabilities = LCaps0} = Svc, Addrs) ->
+ LCaps = LCaps0#diameter_caps{host_ip_address = Addrs},
+ Svc#diameter_service{capabilities = LCaps}.
%% The 4-tuple Data returned from diameter_peer:start/1 identifies the
%% transport module/config use to start the transport process in
@@ -299,13 +334,17 @@ eraser(Key) ->
%% transition/2
+%% Started in old code.
+transition(T, #state{state = 'Wait-Conn-Ack' = PS} = S) ->
+ transition(T, S#state{state = {PS, ?EVENT_TIMEOUT}});
+
%% Connection to peer.
transition({diameter, {TPid, connected, Remote}},
#state{transport = TPid,
state = PS,
mode = M}
= S) ->
- 'Wait-Conn-Ack' = PS, %% assert
+ {'Wait-Conn-Ack', _} = PS, %% assert
connect = M, %%
keep_transport(TPid),
send_CER(S#state{mode = {M, Remote}});
@@ -317,11 +356,11 @@ transition({diameter, {TPid, connected}},
mode = M,
parent = Pid}
= S) ->
- 'Wait-Conn-Ack' = PS, %% assert
+ {'Wait-Conn-Ack', Tmo} = PS, %% assert
accept = M, %%
keep_transport(TPid),
Pid ! {accepted, self()},
- start_timer(S#state{state = recv_CER});
+ start_timer(Tmo, S#state{state = recv_CER});
%% Connection established after receiving a connection_timeout
%% message. This may be followed by an incoming message which arrived
@@ -335,7 +374,7 @@ transition({diameter, {_, connected, _}}, _) ->
%% Connection has timed out: start an alternate.
transition({connection_timeout = T, TPid},
#state{transport = TPid,
- state = 'Wait-Conn-Ack'}
+ state = {'Wait-Conn-Ack', _}}
= S) ->
exit(TPid, {shutdown, T}),
start_next(S);
@@ -349,7 +388,8 @@ transition({diameter, {recv, Pkt}}, S) ->
recv(Pkt, S);
%% Timeout when still in the same state ...
-transition({timeout, PS}, #state{state = PS}) ->
+transition({timeout = T, PS}, #state{state = PS} = S) ->
+ close({capx(PS), T}, S),
stop;
%% ... or not.
@@ -361,25 +401,19 @@ transition({send, Msg}, #state{transport = TPid}) ->
send(TPid, Msg),
ok;
-%% Request for graceful shutdown.
-transition({shutdown, Pid}, #state{parent = Pid, dpr = false} = S) ->
- dpr(?GOAWAY, S);
-transition({shutdown, Pid}, #state{parent = Pid}) ->
+%% Messages from old (diameter_service) code.
+transition(shutdown = T, #state{parent = Pid} = S) ->
+ transition({T, Pid, service}, S); %% Reason irrelevant: old code has no cb
+
+%% Request for graceful shutdown at remove_transport, stop_service of
+%% application shutdown.
+transition({shutdown = T, Pid}, S) ->
+ transition({T, Pid, transport}, S);
+transition({shutdown, Pid, Reason}, #state{parent = Pid, dpr = false} = S) ->
+ dpr(Reason, S);
+transition({shutdown, Pid, _}, #state{parent = Pid}) ->
ok;
-%% Application shutdown.
-transition(shutdown, #state{dpr = false} = S) ->
- dpr(?REBOOT, S);
-transition(shutdown, _) -> %% DPR already send: ensure expected timeout
- dpa_timer(),
- ok;
-
-%% Request to close the transport connection.
-transition({close = T, Pid}, #state{parent = Pid,
- transport = TPid}) ->
- diameter_peer:close(TPid),
- {stop, T};
-
%% DPA reception has timed out.
transition(dpa_timeout, _) ->
stop;
@@ -411,6 +445,11 @@ transition({state, Pid}, #state{state = S, transport = TPid}) ->
%% Crash on anything unexpected.
+capx(recv_CER) ->
+ 'CER';
+capx({'Wait-CEA', _, _}) ->
+ 'CEA'.
+
%% start_next/1
start_next(#state{service = Svc0} = S) ->
@@ -426,18 +465,23 @@ start_next(#state{service = Svc0} = S) ->
%% send_CER/1
-send_CER(#state{mode = {connect, Remote},
- service = #diameter_service{capabilities = Caps},
+send_CER(#state{state = {'Wait-Conn-Ack', Tmo},
+ mode = {connect, Remote},
+ service = #diameter_service{capabilities = LCaps},
transport = TPid}
= S) ->
- OH = Caps#diameter_caps.origin_host,
+ OH = LCaps#diameter_caps.origin_host,
req_send_CER(OH, Remote)
orelse
- close({already_connected, Remote, Caps}, S),
+ close({already_connected, Remote, LCaps}, S),
CER = build_CER(S),
?LOG(send, 'CER'),
- send(TPid, encode(CER)),
- start_timer(S#state{state = 'Wait-CEA'}).
+ #diameter_packet{header = #diameter_header{end_to_end_id = Eid,
+ hop_by_hop_id = Hid}}
+ = Pkt
+ = encode(CER),
+ send(TPid, Pkt),
+ start_timer(Tmo, S#state{state = {'Wait-CEA', Hid, Eid}}).
%% Register ourselves as connecting to the remote endpoint in
%% question. This isn't strictly necessary since a peer implementing
@@ -449,23 +493,36 @@ send_CER(#state{mode = {connect, Remote},
req_send_CER(OriginHost, Remote) ->
register_everywhere({?MODULE, connection, OriginHost, {remote, Remote}}).
-%% start_timer/1
+%% start_timer/2
-start_timer(#state{state = PS} = S) ->
- erlang:send_after(?EVENT_TIMEOUT, self(), {timeout, PS}),
+start_timer(Tmo, #state{state = PS} = S) ->
+ erlang:send_after(Tmo, self(), {timeout, PS}),
S.
%% build_CER/1
-build_CER(#state{service = #diameter_service{capabilities = Caps}}) ->
- {ok, CER} = diameter_capx:build_CER(Caps),
+build_CER(#state{service = #diameter_service{capabilities = LCaps}}) ->
+ {ok, CER} = diameter_capx:build_CER(LCaps),
CER.
%% encode/1
encode(Rec) ->
- #diameter_packet{bin = Bin} = diameter_codec:encode(?BASE, Rec),
- Bin.
+ Seq = diameter_session:sequence(sequence()),
+ Hdr = #diameter_header{version = ?DIAMETER_VERSION,
+ end_to_end_id = Seq,
+ hop_by_hop_id = Seq},
+ diameter_codec:encode(?BASE, #diameter_packet{header = Hdr,
+ msg = Rec}).
+
+sequence() ->
+ case getr(?SEQUENCE_KEY) of
+ {_,_} = Mask ->
+ Mask;
+ undefined -> %% started in old code
+ putr(?SEQUENCE_KEY, ?NOMASK),
+ ?NOMASK
+ end.
%% recv/2
@@ -524,7 +581,14 @@ discard(Reason, F, A) ->
%% rcv/3
%% Incoming CEA.
-rcv('CEA', Pkt, #state{state = 'Wait-CEA'} = S) ->
+rcv('CEA',
+ #diameter_packet{header = #diameter_header{end_to_end_id = Eid,
+ hop_by_hop_id = Hid}}
+ = Pkt,
+ #state{state = {'Wait-CEA' = T, Hid, Eid}}
+ = S) ->
+ handle_CEA(Pkt, S#state{state = T});
+rcv('CEA', Pkt, #state{state = 'Wait-CEA'} = S) -> %% old code
handle_CEA(Pkt, S);
%% Incoming CER
@@ -544,16 +608,16 @@ rcv(N, Pkt, S)
N == 'DPR' ->
handle_request(N, Pkt, S);
-%% DPA even though we haven't sent DPR: ignore.
-rcv('DPA', _Pkt, #state{dpr = false}) ->
- ok;
-
-%% DPA in response to DPR. We could check the sequence numbers but
-%% don't bother, just close.
-rcv('DPA' = N, _Pkt, #state{transport = TPid}) ->
+%% DPA in response to DPR and with the expected identifiers.
+rcv('DPA' = N,
+ #diameter_packet{header = #diameter_header{end_to_end_id = Eid,
+ hop_by_hop_id = Hid}},
+ #state{transport = TPid,
+ dpr = {Hid, Eid}}) ->
diameter_peer:close(TPid),
{stop, N};
+%% Ignore anything else, an unsolicited DPA in particular.
rcv(_, _, _) ->
ok.
@@ -771,8 +835,8 @@ a('CER', #diameter_caps{vendor_id = Vid,
{'Product-Name', Name},
{'Origin-State-Id', OSI}];
-a('DPR', #diameter_caps{origin_host = Host,
- origin_realm = Realm}) ->
+a('DPR', #diameter_caps{origin_host = {Host, _},
+ origin_realm = {Realm, _}}) ->
['DPA', {'Origin-Host', Host},
{'Origin-Realm', Realm}].
@@ -880,7 +944,9 @@ rejected(N)
%% open/5
-open(Pkt, SupportedApps, Caps, {Type, IS}, #state{parent = Pid} = S) ->
+open(Pkt, SupportedApps, Caps, {Type, IS}, #state{parent = Pid,
+ service = Svc}
+ = S) ->
#diameter_caps{origin_host = {_,_} = H,
inband_security_id = {LS,_}}
= Caps,
@@ -888,7 +954,9 @@ open(Pkt, SupportedApps, Caps, {Type, IS}, #state{parent = Pid} = S) ->
tls_ack(lists:member(?TLS, LS), Caps, Type, IS, S),
Pid ! {open, self(), H, {Caps, SupportedApps, Pkt}},
- S#state{state = 'Open'}.
+ %% Replace capabilities record with local/remote pairs.
+ S#state{state = 'Open',
+ service = Svc#diameter_service{capabilities = Caps}}.
%% We've advertised TLS support: tell the transport the result
%% and expect a reply when the handshake is complete.
@@ -941,38 +1009,148 @@ dwa(#diameter_caps{origin_host = OH,
{'Origin-State-Id', OSI}].
%% dpr/2
+%%
+%% The RFC isn't clear on whether DPR should be send in a non-Open
+%% state. The Peer State Machine transitions it documents aren't
+%% exhaustive (no Stop in Wait-I-CEA for example) so assume it's up to
+%% the implementation and transition to Closed (ie. die) if we haven't
+%% yet reached Open.
+
+%% Connection is open, DPR has not been sent.
+dpr(Reason, #state{state = 'Open',
+ dpr = false,
+ service = #diameter_service{capabilities = Caps}}
+ = S) ->
+ case getr(?DPR_KEY) of
+ CBs when is_list(CBs) ->
+ Ref = getr(?REF_KEY),
+ Peer = {self(), Caps},
+ dpr(CBs, [Reason, Ref, Peer], S);
+ undefined -> %% started in old code
+ send_dpr(Reason, [], S)
+ end;
-dpr(Cause, #state{transport = TPid,
- service = #diameter_service{capabilities = Caps}}
- = S) ->
- #diameter_caps{origin_host = OH,
- origin_realm = OR}
+%% Connection is open, DPR already sent.
+dpr(_, #state{state = 'Open'}) ->
+ ok;
+
+%% Connection not open.
+dpr(_Reason, _S) ->
+ stop.
+
+%% dpr/3
+%%
+%% Note that an implementation that wants to do something
+%% transport_module-specific can lookup the pid of the transport
+%% process and contact it. (eg. diameter:service_info/2)
+
+dpr([CB|Rest], [Reason | _] = Args, S) ->
+ try diameter_lib:eval([CB | Args]) of
+ {dpr, Opts} when is_list(Opts) ->
+ send_dpr(Reason, Opts, S);
+ dpr ->
+ send_dpr(Reason, [], S);
+ close = T ->
+ {stop, {disconnect_cb, T}};
+ ignore ->
+ dpr(Rest, Args, S);
+ T ->
+ No = {disconnect_cb, T},
+ diameter_lib:error_report(invalid, No),
+ {stop, No}
+ catch
+ E:R ->
+ No = {disconnect_cb, E, R, ?STACK},
+ diameter_lib:error_report(failure, No),
+ {stop, No}
+ end;
+
+dpr([], [Reason | _], S) ->
+ send_dpr(Reason, [], S).
+
+-record(opts, {cause, timeout = ?DPA_TIMEOUT}).
+
+send_dpr(Reason, Opts, #state{transport = TPid,
+ service = #diameter_service{capabilities = Caps}}
+ = S) ->
+ #opts{cause = Cause, timeout = Tmo}
+ = lists:foldl(fun opt/2,
+ #opts{cause = case Reason of
+ transport -> ?GOAWAY;
+ _ -> ?REBOOT
+ end,
+ timeout = ?DPA_TIMEOUT},
+ Opts),
+ #diameter_caps{origin_host = {OH, _},
+ origin_realm = {OR, _}}
= Caps,
- Bin = encode(['DPR', {'Origin-Host', OH},
+ #diameter_packet{header = #diameter_header{end_to_end_id = Eid,
+ hop_by_hop_id = Hid}}
+ = Pkt
+ = encode(['DPR', {'Origin-Host', OH},
{'Origin-Realm', OR},
{'Disconnect-Cause', Cause}]),
- send(TPid, Bin),
- dpa_timer(),
+ send(TPid, Pkt),
+ dpa_timer(Tmo),
?LOG(send, 'DPR'),
- S#state{dpr = diameter_codec:sequence_numbers(Bin)}.
-
-dpa_timer() ->
- erlang:send_after(?DPA_TIMEOUT, self(), dpa_timeout).
+ S#state{dpr = {Hid, Eid}}.
+
+opt({timeout, Tmo}, Rec)
+ when ?IS_TIMEOUT(Tmo) ->
+ Rec#opts{timeout = Tmo};
+opt({cause, Cause}, Rec)
+ when ?IS_CAUSE(Cause) ->
+ Rec#opts{cause = cause(Cause)};
+opt(T, _) ->
+ ?ERROR({invalid_option, T}).
+
+cause(rebooting) -> ?REBOOT;
+cause(goaway) -> ?GOAWAY;
+cause(busy) -> ?BUSY;
+cause(N)
+ when ?IS_CAUSE(N) ->
+ N;
+cause(N) ->
+ ?ERROR({invalid_cause, N}).
+
+dpa_timer(Tmo) ->
+ erlang:send_after(Tmo, self(), dpa_timeout).
%% register_everywhere/1
%%
%% Register a term and ensure it's not registered elsewhere. Note that
%% two process that simultaneously register the same term may well
%% both fail to do so this isn't foolproof.
+%%
+%% Everywhere is no longer everywhere, it's where a
+%% restrict_connections service_opt() specifies.
register_everywhere(T) ->
- diameter_reg:add_new(T)
- andalso unregistered(T).
+ reg(getr(?RESTRICT_KEY), T).
+
+reg(Nodes, T) ->
+ add(lists:member(node(), Nodes), T) andalso unregistered(Nodes, T).
+
+add(true, T) ->
+ diameter_reg:add_new(T);
+add(false, T) ->
+ diameter_reg:add(T).
+
+%% unregistered
+%%
+%% Ensure that the term in question isn't registered on other nodes.
+
+unregistered(Nodes, T) ->
+ {ResL, _} = rpc:multicall(Nodes, ?MODULE, match, [{node(), T}]),
+ lists:all(fun nomatch/1, ResL).
+
+nomatch({badrpc, {'EXIT', {undef, _}}}) -> %% no diameter on remote node
+ true;
+nomatch(L) ->
+ [] == L.
-unregistered(T) ->
- {ResL, _} = rpc:multicall(?MODULE, match, [{node(), T}]),
- lists:all(fun(L) -> [] == L end, ResL).
+%% match/1
match({Node, _})
when Node == node() ->
diff --git a/lib/diameter/src/base/diameter_reg.erl b/lib/diameter/src/base/diameter_reg.erl
index 882b9da238..619b12ecad 100644
--- a/lib/diameter/src/base/diameter_reg.erl
+++ b/lib/diameter/src/base/diameter_reg.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -30,7 +30,8 @@
add_new/1,
del/1,
repl/2,
- match/1]).
+ match/1,
+ wait/1]).
-export([start_link/0]).
@@ -65,27 +66,22 @@
%% Table entry containing the Term -> Pid mapping.
-define(MAPPING(Term, Pid), {Term, Pid}).
--record(state, {id = now()}).
-
-%%% ----------------------------------------------------------
-%%% # add(T)
-%%%
-%%% Input: Term = term()
-%%%
-%%% Output: true
-%%%
-%%% Description: Associate the specified term with self(). The list of pids
-%%% having this or other assocations can be retrieved using
-%%% match/1.
-%%%
-%%% An association is removed when the calling process dies
-%%% or as a result of calling del/1. Adding the same term
-%%% more than once is equivalent to adding it exactly once.
-%%%
-%%% Note that since match/1 takes a pattern as argument,
-%%% specifying a term that contains match variables is
-%%% probably not a good idea
-%%% ----------------------------------------------------------
+-record(state, {id = now(),
+ q = []}). %% [{From, Pat}]
+
+%% ===========================================================================
+%% # add(T)
+%%
+%% Associate the specified term with self(). The list of pids having
+%% this or other assocations can be retrieved using match/1.
+%%
+%% An association is removed when the calling process dies or as a
+%% result of calling del/1. Adding the same term more than once is
+%% equivalent to adding it exactly once.
+%%
+%% Note that since match/1 takes a pattern as argument, specifying a
+%% term that contains match variables is probably not a good idea
+%% ===========================================================================
-spec add(any())
-> true.
@@ -93,17 +89,12 @@
add(T) ->
call({add, fun ets:insert/2, T, self()}).
-%%% ----------------------------------------------------------
-%%% # add_new(T)
-%%%
-%%% Input: T = term()
-%%%
-%%% Output: true | false
-%%%
-%%% Description: Like add/1 but only one process is allowed to have the
-%%% the association, false being returned if an association
-%%% already exists.
-%%% ----------------------------------------------------------
+%% ===========================================================================
+%% # add_new(T)
+%%
+%% Like add/1 but only one process is allowed to have the the
+%% association, false being returned if an association already exists.
+%% ===========================================================================
-spec add_new(any())
-> boolean().
@@ -111,16 +102,12 @@ add(T) ->
add_new(T) ->
call({add, fun insert_new/2, T, self()}).
-%%% ----------------------------------------------------------
-%%% # repl(T, NewT)
-%%%
-%%% Input: T, NewT = term()
-%%%
-%%% Output: true | false
-%%%
-%%% Description: Like add/1 but only replace an existing association on T,
-%%% false being returned if it doesn't exist.
-%%% ----------------------------------------------------------
+%% ===========================================================================
+%% # repl(T, NewT)
+%%
+%% Like add/1 but only replace an existing association on T, false
+%% being returned if it doesn't exist.
+%% ===========================================================================
-spec repl(any(), any())
-> boolean().
@@ -128,15 +115,11 @@ add_new(T) ->
repl(T, U) ->
call({repl, T, U, self()}).
-%%% ----------------------------------------------------------
-%%% # del(Term)
-%%%
-%%% Input: Term = term()
-%%%
-%%% Output: true
-%%%
-%%% Description: Remove any existing association of Term with self().
-%%% ----------------------------------------------------------
+%% ===========================================================================
+%% # del(Term)
+%%
+%% Remove any existing association of Term with self().
+%% ===========================================================================
-spec del(any())
-> true.
@@ -144,20 +127,16 @@ repl(T, U) ->
del(T) ->
call({del, T, self()}).
-%%% ----------------------------------------------------------
-%%% # match(Pat)
-%%%
-%%% Input: Pat = pattern in the sense of ets:match_object/2.
-%%%
-%%% Output: list of {Term, Pid}
-%%%
-%%% Description: Return the list of associations whose Term, as specified
-%%% to add/1 or add_new/1, matches the specified pattern.
-%%%
-%%% Note that there's no guarantee that the returned processes
-%%% are still alive. (Although one that isn't will soon have
-%%% its associations removed.)
-%%% ----------------------------------------------------------
+%% ===========================================================================
+%% # match(Pat)
+%%
+%% Return the list of associations whose Term, as specified to add/1
+%% or add_new/1, matches the specified pattern.
+%%
+%% Note that there's no guarantee that the returned processes are
+%% still alive. (Although one that isn't will soon have its
+%% associations removed.)
+%% ===========================================================================
-spec match(tuple())
-> [{term(), pid()}].
@@ -165,9 +144,17 @@ del(T) ->
match(Pat) ->
ets:match_object(?TABLE, ?MAPPING(Pat, '_')).
-%% ---------------------------------------------------------
-%% EXPORTED INTERNAL FUNCTIONS
-%% ---------------------------------------------------------
+%% ===========================================================================
+%% # wait(Pat)
+%%
+%% Like match/1 but return only when the result is non-empty or fails.
+%% It's up to the caller to ensure that the wait won't be forever.
+%% ===========================================================================
+
+wait(Pat) ->
+ call({wait, Pat}).
+
+%% ===========================================================================
start_link() ->
ServerName = {local, ?SERVER},
@@ -182,7 +169,7 @@ uptime() ->
%% pids/0
%%
-%% Output: list of {Pid, [Term, ...]}
+%% Return: list of {Pid, [Term, ...]}
pids() ->
to_list(fun swap/1).
@@ -202,89 +189,100 @@ id(T) -> T.
%% terms/0
%%
-%% Output: list of {Term, [Pid, ...]}
+%% Return: list of {Term, [Pid, ...]}
terms() ->
to_list(fun id/1).
swap({X,Y}) -> {Y,X}.
-%%% ----------------------------------------------------------
-%%% # init(Role)
-%%%
-%%% Output: {ok, State}
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # init/1
+%% ----------------------------------------------------------
init(_) ->
ets:new(?TABLE, [bag, named_table]),
{ok, #state{}}.
-%%% ----------------------------------------------------------
-%%% # handle_call(Request, From, State)
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # handle_call/3
+%% ----------------------------------------------------------
-handle_call({add, Fun, Key, Pid}, _, State) ->
+handle_call(Req, From, S)
+ when not is_record(S, state) ->
+ handle_call(Req, From, upgrade(S));
+
+handle_call({add, Fun, Key, Pid}, _, S) ->
B = Fun(?TABLE, {Key, Pid}),
monitor(B andalso no_monitor(Pid), Pid),
- {reply, B, State};
+ {reply, B, pending(B, S)};
-handle_call({del, Key, Pid}, _, State) ->
- {reply, ets:delete_object(?TABLE, ?MAPPING(Key, Pid)), State};
+handle_call({del, Key, Pid}, _, S) ->
+ {reply, ets:delete_object(?TABLE, ?MAPPING(Key, Pid)), S};
-handle_call({repl, T, U, Pid}, _, State) ->
+handle_call({repl, T, U, Pid}, _, S) ->
MatchSpec = [{?MAPPING('$1', Pid),
[{'=:=', '$1', {const, T}}],
['$_']}],
- {reply, repl(ets:select(?TABLE, MatchSpec), U, Pid), State};
+ {reply, repl(ets:select(?TABLE, MatchSpec), U, Pid), S};
+
+handle_call({wait, Pat}, From, #state{q = Q} = S) ->
+ case find(Pat) of
+ {ok, L} ->
+ {reply, L, S};
+ false ->
+ {noreply, S#state{q = [{From, Pat} | Q]}}
+ end;
-handle_call(state, _, State) ->
- {reply, State, State};
+handle_call(state, _, S) ->
+ {reply, S, S};
-handle_call(uptime, _, #state{id = Time} = State) ->
- {reply, diameter_lib:now_diff(Time), State};
+handle_call(uptime, _, #state{id = Time} = S) ->
+ {reply, diameter_lib:now_diff(Time), S};
-handle_call(Req, From, State) ->
+handle_call(Req, From, S) ->
?UNEXPECTED([Req, From]),
- {reply, nok, State}.
+ {reply, nok, S}.
-%%% ----------------------------------------------------------
-%%% # handle_cast(Request, State)
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # handle_cast/2
+%% ----------------------------------------------------------
-handle_cast(Msg, State)->
+handle_cast(Msg, S)->
?UNEXPECTED([Msg]),
- {noreply, State}.
+ {noreply, S}.
-%%% ----------------------------------------------------------
-%%% # handle_info(Request, State)
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # handle_info/2
+%% ----------------------------------------------------------
-handle_info({'DOWN', MRef, process, Pid, _}, State) ->
+handle_info({'DOWN', MRef, process, Pid, _}, S) ->
ets:delete_object(?TABLE, ?MONITOR(Pid, MRef)),
ets:match_delete(?TABLE, ?MAPPING('_', Pid)),
- {noreply, State};
+ {noreply, S};
-handle_info(Info, State) ->
+handle_info(Info, S) ->
?UNEXPECTED([Info]),
- {noreply, State}.
+ {noreply, S}.
-%%% ----------------------------------------------------------
-%%% # terminate(Reason, State)
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # terminate/2
+%% ----------------------------------------------------------
terminate(_Reason, _State)->
ok.
-%%% ----------------------------------------------------------
-%%% # code_change(OldVsn, State, Extra)
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # code_change/3
+%% ----------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
-%% ---------------------------------------------------------
-%% INTERNAL FUNCTIONS
-%% ---------------------------------------------------------
+%% ===========================================================================
+
+upgrade(S) ->
+ #state{} = list_to_tuple(tuple_to_list(S) ++ [[]]).
monitor(true, Pid) ->
ets:insert(?TABLE, ?MONITOR(Pid, erlang:monitor(process, Pid)));
@@ -321,6 +319,37 @@ repl([?MAPPING(_, Pid) = M], Key, Pid) ->
repl([], _, _) ->
false.
+%% pending/1
+
+pending(true, #state{q = [_|_] = Q} = S) ->
+ S#state{q = q(lists:reverse(Q), [])}; %% retain reply order
+pending(_, S) ->
+ S.
+
+q([], Q) ->
+ Q;
+q([{From, Pat} = T | Rest], Q) ->
+ case find(Pat) of
+ {ok, L} ->
+ gen_server:reply(From, L),
+ q(Rest, Q);
+ false ->
+ q(Rest, [T|Q])
+ end.
+
+%% find/1
+
+find(Pat) ->
+ try match(Pat) of
+ [] ->
+ false;
+ L ->
+ {ok, L}
+ catch
+ _:_ ->
+ {ok, []}
+ end.
+
%% call/1
call(Request) ->
diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl
index 725cccda1e..b5584ca0d0 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-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -64,7 +64,7 @@
-include_lib("diameter/include/diameter.hrl").
-include("diameter_internal.hrl").
-%% The "old" states maintained in this module historically.
+%% The states mirrored by peer_up/peer_down callbacks.
-define(STATE_UP, up).
-define(STATE_DOWN, down).
@@ -107,6 +107,12 @@
%% process.
-define(STATE_TABLE, ?MODULE).
+%% The default sequence mask.
+-define(NOMASK, {0,32}).
+
+%% The default restrict_connections.
+-define(RESTRICT, nodes).
+
%% Workaround for dialyzer's lack of understanding of match specs.
-type match(T)
:: T | '_' | '$1' | '$2' | '$3' | '$4'.
@@ -114,15 +120,18 @@
%% State of service gen_server.
-record(state,
{id = now(),
- service_name, %% as passed to start_service/2, key in ?STATE_TABLE
+ service_name, %% as passed to start_service/2, key in ?STATE_TABLE
service :: #diameter_service{},
- peerT = ets_new(peers) :: ets:tid(), %% #peer{} at start_fsm
- connT = ets_new(conns) :: ets:tid(), %% #conn{} at connection_up
- share_peers = false :: boolean(), %% broadcast peers to remote nodes?
- use_shared_peers = false :: boolean(), %% use broadcasted peers?
+ peerT = ets_new(peers) :: ets:tid(),%% #peer{} at start_fsm
+ connT = ets_new(conns) :: ets:tid(),%% #conn{} at connection_up/reopen
shared_peers = ?Dict:new(), %% Alias -> [{TPid, Caps}, ...]
local_peers = ?Dict:new(), %% Alias -> [{TPid, Caps}, ...]
- monitor = false :: false | pid()}). %% process to die with
+ monitor = false :: false | pid(), %% process to die with
+ options
+ :: [{sequence, diameter:sequence()} %% sequence mask
+ | {restrict_connections, diameter:restriction()}
+ | {share_peers, boolean()} %% broadcast peers to remote nodes?
+ | {use_shared_peers, boolean()}]}).%% use broadcasted peers?
%% shared_peers reflects the peers broadcast from remote nodes. Note
%% that the state term itself doesn't change, which is relevant for
%% the stateless application callbacks since the state is retrieved
@@ -130,7 +139,12 @@
%% service record is used to determine whether or not we need to call
%% the process for a pick_peer callback.
-%% Record representing a watchdog process.
+%% Record representing a watchdog process as implemented by
+%% diameter_watchdog. The term "peer" here is historical, made
+%% especially confusing by the fact that a peer_ref() in the
+%% documentation is the key of a #conn{} record, not a #peer{} record.
+%% The name is also unfortunate given the meaning of peer in the
+%% Diameter sense.
-record(peer,
{pid :: match(pid()),
type :: match(connect | accept),
@@ -140,9 +154,15 @@
:: match(op_state() | {op_state(), wd_state()}),
started = now(), %% at process start
conn = false :: match(boolean() | pid())}).
- %% true at accept, pid() at connection_up (connT key)
-
-%% Record representing a peer_fsm process.
+ %% true at accepted, pid() at connection_up or reopen
+
+%% Record representing a peer process as implemented by
+%% diameter_peer_fsm. The term "conn" is historical. Despite the name
+%% here, comments refer to watchdog and peer processes, that are keys
+%% in #peer{} and #conn{} records respectively. To add to the
+%% confusion, a #request.transport is a peer process = key in a
+%% #conn{} record. The actual transport process (that the peer process
+%% knows about and that has a transport connection) isn't seen here.
-record(conn,
{pid :: pid(),
apps :: [{0..16#FFFFFFFF, diameter:app_alias()}], %% {Id, Alias}
@@ -156,10 +176,9 @@
handler :: match(pid()), %% request process
transport :: match(pid()), %% peer process
caps :: match(#diameter_caps{}),
- app :: match(diameter:app_alias()), %% #diameter_app.alias
- dictionary :: match(module()), %% #diameter_app.dictionary
- module :: match([module() | list()]),
- %% #diameter_app.module
+ app :: match(diameter:app_alias()),%% #diameter_app.alias
+ dictionary :: match(module()), %% #diameter_app.dictionary
+ module :: match([module() | list()]), %% #diameter_app.module
filter :: match(diameter:peer_filter()),
packet :: match(#diameter_packet{})}).
@@ -170,20 +189,6 @@
timeout = ?DEFAULT_TIMEOUT :: 0..16#FFFFFFFF,
detach = false :: boolean()}).
-%% Since RFC 3588 requires that a Diameter agent not modify End-to-End
-%% Identifiers, the possibility of explicitly setting an End-to-End
-%% Identifier would be needed to be able to implement an agent in
-%% which one side of the communication is not implemented on top of
-%% diameter. For example, Diameter being sent or received encapsulated
-%% in some other protocol, or even another Diameter stack in a
-%% non-Erlang environment. (Not that this is likely to be a normal
-%% case.)
-%%
-%% The implemented solution is not an option but to respect any header
-%% values set in a diameter_header record returned from a
-%% prepare_request callback. A call to diameter:call/4 can communicate
-%% values to the callback using the 'extra' option if so desired.
-
%%% ---------------------------------------------------------------------------
%%% # start(SvcName)
%%% ---------------------------------------------------------------------------
@@ -236,20 +241,20 @@ stop_transport(SvcName, [_|_] = Refs) ->
%%% ---------------------------------------------------------------------------
info(SvcName, Item) ->
- info_rc(call_service_by_name(SvcName, {info, Item})).
-
-info_rc({error, _}) ->
- undefined;
-info_rc(Info) ->
- Info.
+ case find_state(SvcName) of
+ #state{} = S ->
+ service_info(Item, S);
+ false ->
+ undefined
+ end.
%%% ---------------------------------------------------------------------------
%%% # receive_message(TPid, Pkt, MessageData)
%%% ---------------------------------------------------------------------------
-%% Handle an incoming 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. This
+%% used to come through the service process but this avoids that
+%% becoming a bottleneck.
receive_message(TPid, Pkt, T)
when is_pid(TPid) ->
@@ -329,21 +334,39 @@ call_rc(_, _, Sent) ->
%% In the process spawned for the outgoing request.
call(SvcName, App, Msg, Opts, Caller) ->
- c(ets:lookup(?STATE_TABLE, SvcName), App, Msg, Opts, Caller).
+ c(find_state(SvcName), App, Msg, Opts, Caller).
-c([#state{service_name = SvcName} = S], App, Msg, Opts, Caller) ->
+c(#state{service_name = Svc, options = [{_, Mask} | _]} = S,
+ App,
+ Msg,
+ Opts,
+ Caller) ->
case find_transport(App, Msg, Opts, S) of
{_,_,_} = T ->
- send_request(T, Msg, Opts, Caller, SvcName);
+ send_request(T, Mask, Msg, Opts, Caller, Svc);
false ->
{error, no_connection};
{error, _} = No ->
No
end;
-c([], _, _, _, _) ->
+c(false, _, _, _, _) ->
{error, no_service}.
+%% find_state/1
+
+find_state(SvcName) ->
+ fs(ets:lookup(?STATE_TABLE, SvcName)).
+
+fs([#state{} = S]) ->
+ S;
+
+fs([S]) -> %% inserted from old code
+ upgrade(S);
+
+fs([]) ->
+ false.
+
%% make_options/1
make_options(Options) ->
@@ -439,6 +462,10 @@ i(_, false) ->
%%% # handle_call(Req, From, State)
%%% ---------------------------------------------------------------------------
+handle_call(T, From, S)
+ when not is_record(S, state) ->
+ handle_call(T, From, upgrade(S));
+
handle_call(state, _, S) ->
{reply, S, S};
@@ -462,16 +489,25 @@ handle_call({pick_peer, Local, Remote, App}, _From, S) ->
handle_call({call_module, AppMod, Req}, From, S) ->
call_module(AppMod, Req, From, S);
+%% Call from old code.
handle_call({info, Item}, _From, S) ->
{reply, service_info(Item, S), S};
handle_call(stop, _From, S) ->
- shutdown(S),
+ shutdown(service, S),
{stop, normal, ok, S};
%% The server currently isn't guaranteed to be dead when the caller
%% gets the reply. We deal with this in the call to the server,
%% stating a monitor that waits for DOWN before returning.
+%% Watchdog is asking for the sequence mask.
+handle_call(sequence, _From, #state{options = [{_, Mask} | _]} = S) ->
+ {reply, Mask, S};
+
+%% Watchdog is asking for the nodes restriction.
+handle_call(restriction, _From, #state{options = [_,_,_,{_,R} | _]} = S) ->
+ {reply, R, S};
+
handle_call(Req, From, S) ->
unexpected(handle_call, [Req, From], S),
{reply, nok, S}.
@@ -488,15 +524,16 @@ handle_cast(Req, S) ->
%%% # handle_info(Req, State)
%%% ---------------------------------------------------------------------------
-handle_info(T,S) ->
+handle_info(T, #state{} = S) ->
case transition(T,S) of
ok ->
{noreply, S};
- #state{} = NS ->
- {noreply, NS};
{stop, Reason} ->
{stop, {shutdown, Reason}, S}
- end.
+ end;
+
+handle_info(T, S) ->
+ handle_info(T, upgrade(S)).
%% transition/2
@@ -507,15 +544,26 @@ transition({accepted, Pid, TPid}, S) ->
%% Peer process has a new open connection.
transition({connection_up, Pid, T}, S) ->
- connection_up(Pid, T, S);
+ connection_up(Pid, T, S),
+ ok;
+
+%% Watchdog has a new connection that will be opened after DW[RA]
+%% exchange. This message was added long after connection_up, to
+%% communicate the information as soon as it's available. Leave
+%% connection_up as is it for now, duplicated information and all.
+transition({reopen, Pid, T}, S) ->
+ reopen(Pid, T, S),
+ ok;
-%% Peer process has left state open.
+%% Watchdog has left state OKAY.
transition({connection_down, Pid}, S) ->
- connection_down(Pid, S);
+ connection_down(Pid, S),
+ ok;
-%% Peer process has returned to state open.
+%% Watchdog has returned to state OKAY.
transition({connection_up, Pid}, S) ->
- connection_up(Pid, S);
+ connection_up(Pid, S),
+ ok;
%% Accepting transport has lost connectivity.
transition({close, Pid}, S) ->
@@ -529,7 +577,7 @@ transition({reconnect, Pid}, S) ->
%% Watchdog is sending notification of a state transition. Note that
%% the connection_up/down messages are pre-date this message and are
-%% still used. A 'watchdog' message will follow these and communicate
+%% still used. A watchdog message will follow these and communicate
%% the same state as was set in handling connection_up/down.
transition({watchdog, Pid, {TPid, From, To}}, #state{service_name = SvcName,
peerT = PeerT}) ->
@@ -539,21 +587,22 @@ transition({watchdog, Pid, {TPid, From, To}}, #state{service_name = SvcName,
insert(PeerT, P#peer{op_state = {OS, To}}),
send_event(SvcName, {watchdog, Ref, TPid, {From, To}, {T, Opts}}),
ok;
-%% Death of a peer process results in the removal of it's peer and any
-%% associated conn record when 'DOWN' is received (after this) but the
-%% states will be {?STATE_UP, ?WD_DOWN} for a short time. (No real
-%% problem since ?WD_* is only used in service_info.) We set ?WD_OKAY
-%% as a consequence of connection_up since we know a watchdog is
-%% coming. We can't set anything at connection_down since we don't
-%% know if the subsequent watchdog message will be ?WD_DOWN or
-%% ?WD_SUSPECT. We don't (yet) set ?STATE_* as a consequence of a
-%% watchdog message since this requires changing some of the matching
-%% on ?STATE_*.
-%%
-%% Death of a conn process results in connection_down followed by
-%% watchdog ?WD_DOWN. The latter doesn't result in the conn record
-%% being deleted since 'DOWN' from death of its peer doesn't (yet)
-%% deal with the record having been removed.
+%% Death of a watchdog process (#peer.pid) results in the removal of
+%% it's peer and any associated conn record when 'DOWN' is received
+%% (after this) but the states will be {?STATE_UP, ?WD_DOWN} for a
+%% short time. (No real problem since ?WD_* is only used in
+%% service_info.) We set ?WD_OKAY as a consequence of connection_up
+%% since we know a watchdog is coming. We can't set anything at
+%% connection_down since we don't know if the subsequent watchdog
+%% message will be ?WD_DOWN or ?WD_SUSPECT. We don't (yet) set
+%% ?STATE_* as a consequence of a watchdog message since this requires
+%% changing some of the matching on ?STATE_*.
+%%
+%% Death of a peer process process (#conn.pid, #peer.conn) results in
+%% connection_down followed by watchdog ?WD_DOWN. The latter doesn't
+%% result in the conn record being deleted since 'DOWN' from death of
+%% its watchdog doesn't (yet) deal with the record having been
+%% removed.
%% Monitor process has died. Just die with a reason that tells
%% diameter_config about the happening. If a cleaner shutdown is
@@ -561,23 +610,26 @@ transition({watchdog, Pid, {TPid, From, To}}, #state{service_name = SvcName,
transition({'DOWN', MRef, process, _, Reason}, #state{monitor = MRef}) ->
{stop, {monitor, Reason}};
-%% Local peer process has died.
+%% Local watchdog process has died.
transition({'DOWN', _, process, Pid, Reason}, S)
when node(Pid) == node() ->
- peer_down(Pid, Reason, S);
+ peer_down(Pid, Reason, S),
+ ok;
-%% Remote service wants to know about shared transports.
+%% Remote service wants to know about shared peers.
transition({service, Pid}, S) ->
share_peers(Pid, S),
ok;
%% Remote service is communicating a shared peer.
transition({peer, TPid, Aliases, Caps}, S) ->
- remote_peer_up(TPid, Aliases, Caps, S);
+ remote_peer_up(TPid, Aliases, Caps, S),
+ ok;
%% Remote peer process has died.
transition({'DOWN', _, process, TPid, _}, S) ->
- remote_peer_down(TPid, S);
+ remote_peer_down(TPid, S),
+ ok;
%% Restart after tc expiry.
transition({tc_timeout, T}, S) ->
@@ -591,18 +643,48 @@ transition({failover, TRef, Seqs}, S) ->
failover(TRef, Seqs, S),
ok;
+%% Ensure upgraded state is stored in state table.
+transition(upgrade, _) ->
+ ok;
+
transition(Req, S) ->
unexpected(handle_info, [Req], S),
ok.
+%% upgrade/1
+
+upgrade({state, Id, Svc, Name, Svc, PT, CT, SB, UB, SD, LD, MPid}) ->
+ S = #state{id = Id,
+ service_name = Name,
+ service = Svc,
+ peerT = PT,
+ connT = CT,
+ shared_peers = SD,
+ local_peers = LD,
+ monitor = MPid,
+ options = [{sequence, ?NOMASK},
+ {share_peers, SB},
+ {use_shared_peers, UB},
+ {restrict_connections, ?RESTRICT}]},
+ upgrade_insert(S),
+ S.
+
+upgrade_insert(#state{service = #diameter_service{pid = Pid}} = S) ->
+ if Pid == self() ->
+ ets:insert(?STATE_TABLE, S);
+ true ->
+ Pid ! upgrade
+ end.
+
%%% ---------------------------------------------------------------------------
%%% # terminate(Reason, State)
%%% ---------------------------------------------------------------------------
terminate(Reason, #state{service_name = Name} = S) ->
+ send_event(Name, stop),
ets:delete(?STATE_TABLE, Name),
shutdown == Reason %% application shutdown
- andalso shutdown(S).
+ andalso shutdown(application, S).
%%% ---------------------------------------------------------------------------
%%% # code_change(FromVsn, State, Extra)
@@ -685,41 +767,49 @@ mod_state(Alias, ModS) ->
%%% # shutdown/2
%%% ---------------------------------------------------------------------------
-shutdown(Refs, #state{peerT = PeerT}) ->
- ets:foldl(fun(P,ok) -> s(P, Refs), ok end, ok, PeerT).
-
-s(#peer{ref = Ref, pid = Pid}, Refs) ->
- s(lists:member(Ref, Refs), Pid);
-
-s(true, Pid) ->
- Pid ! {shutdown, self()}; %% 'DOWN' will cleanup as usual
-s(false, _) ->
- ok.
+%% remove_transport: ask watchdogs to terminate their transport.
+shutdown(Refs, #state{peerT = PeerT})
+ when is_list(Refs) ->
+ ets:foldl(fun(P,ok) -> sp(P, Refs), ok end, ok, PeerT);
-%%% ---------------------------------------------------------------------------
-%%% # shutdown/1
-%%% ---------------------------------------------------------------------------
-
-shutdown(#state{peerT = PeerT}) ->
+%% application/service shutdown: ask transports to terminate themselves.
+shutdown(Reason, #state{peerT = PeerT}) ->
%% A transport might not be alive to receive the shutdown request
%% but give those that are a chance to shutdown gracefully.
- wait(fun st/2, PeerT),
+ shutdown(conn, Reason, PeerT),
%% Kill the watchdogs explicitly in case there was no transport.
- wait(fun sw/2, PeerT).
+ shutdown(peer, Reason, PeerT).
-wait(Fun, T) ->
- diameter_lib:wait(ets:foldl(Fun, [], T)).
+%% sp/2
-st(#peer{conn = B}, Acc)
- when is_boolean(B) ->
- Acc;
-st(#peer{conn = Pid}, Acc) ->
- Pid ! shutdown,
- [Pid | Acc].
+sp(#peer{ref = Ref, pid = Pid}, Refs) ->
+ lists:member(Ref, Refs)
+ andalso (Pid ! {shutdown, self()}). %% 'DOWN' cleans up
-sw(#peer{pid = Pid}, Acc) ->
+%% shutdown/3
+
+shutdown(Who, Reason, T) ->
+ diameter_lib:wait(ets:foldl(fun(X,A) -> shutdown(Who, X, Reason, A) end,
+ [],
+ T)).
+
+shutdown(conn = Who, #peer{op_state = {OS,_}} = P, Reason, Acc) ->
+ shutdown(Who, P#peer{op_state = OS}, Reason, Acc);
+
+shutdown(conn,
+ #peer{pid = Pid, op_state = ?STATE_UP, conn = TPid},
+ Reason,
+ Acc) ->
+ TPid ! {shutdown, Pid, Reason},
+ [TPid | Acc];
+
+shutdown(peer, #peer{pid = Pid}, _Reason, Acc)
+ when is_pid(Pid) ->
exit(Pid, shutdown),
- [Pid | Acc].
+ [Pid | Acc];
+
+shutdown(_, #peer{}, _, Acc) ->
+ Acc.
%%% ---------------------------------------------------------------------------
%%% # call_service/2
@@ -769,6 +859,7 @@ i(SvcName) ->
true = ets:insert_new(?STATE_TABLE, S),
%% Start fsms for each transport.
+ send_event(SvcName, start),
lists:foreach(fun(T) -> start_fsm(T,S) end, CL),
init_shared(S),
@@ -779,9 +870,8 @@ cfg_acc({SvcName, #diameter_service{applications = Apps} = Rec, Opts},
lists:foreach(fun init_mod/1, Apps),
S = #state{service_name = SvcName,
service = Rec#diameter_service{pid = self()},
- share_peers = get_value(share_peers, Opts),
- use_shared_peers = get_value(use_shared_peers, Opts),
- monitor = mref(get_value(monitor, Opts))},
+ monitor = mref(get_value(monitor, Opts)),
+ options = service_options(Opts)},
{S, Acc};
cfg_acc({_Ref, Type, _Opts} = T, {S, Acc})
@@ -789,15 +879,24 @@ cfg_acc({_Ref, Type, _Opts} = T, {S, Acc})
Type == listen ->
{S, [T | Acc]}.
+service_options(Opts) ->
+ [{sequence, proplists:get_value(sequence, Opts, ?NOMASK)},
+ {share_peers, get_value(share_peers, Opts)},
+ {use_shared_peers, get_value(use_shared_peers, Opts)},
+ {restrict_connections, proplists:get_value(restrict_connections,
+ Opts,
+ ?RESTRICT)}].
+%% The order of options is significant since we match against the list.
+
mref(false = No) ->
No;
mref(P) ->
erlang:monitor(process, P).
-init_shared(#state{use_shared_peers = true,
+init_shared(#state{options = [_, _, {_, true} | _],
service_name = Svc}) ->
diameter_peer:notify(Svc, {service, self()});
-init_shared(#state{use_shared_peers = false}) ->
+init_shared(#state{options = [_, _, {_, false} | _]}) ->
ok.
init_mod(#diameter_app{alias = Alias,
@@ -860,9 +959,8 @@ start(Ref, Type, Opts, #state{peerT = PeerT,
Pid.
%% Note that the service record passed into the watchdog is the merged
-%% record so that each watchdog (and peer_fsm) may get a different
-%% record. This record is what is passed back into application
-%% callbacks.
+%% record so that each watchdog may get a different record. This
+%% record is what is passed back into application callbacks.
s(Type, Ref, T) ->
case diameter_watchdog:start({Type, Ref}, T) of
@@ -913,8 +1011,8 @@ accepted(Pid, _TPid, #state{peerT = PeerT} = S) ->
#peer{ref = Ref, type = accept = T, conn = false, options = Opts}
= P
= fetch(PeerT, Pid),
- insert(PeerT, P#peer{conn = true}), %% mark replacement transport started
- start(Ref, T, Opts, S). %% start new peer
+ insert(PeerT, P#peer{conn = true}), %% mark replacement as started
+ start(Ref, T, Opts, S). %% start new watchdog
fetch(Tid, Key) ->
[T] = ets:lookup(Tid, Key),
@@ -929,11 +1027,9 @@ fetch(Tid, Key) ->
%%% ---------------------------------------------------------------------------
%%% # connection_up/3
-%%%
-%%% Output: #state{}
%%% ---------------------------------------------------------------------------
-%% Peer process has reached the open state.
+%% Watchdog process has reached state OKAY.
connection_up(Pid, {TPid, {Caps, SApps, Pkt}}, #state{peerT = PeerT,
connT = ConnT}
@@ -948,9 +1044,29 @@ connection_up(Pid, {TPid, {Caps, SApps, Pkt}}, #state{peerT = PeerT,
connection_up([Pkt], P#peer{conn = TPid}, C, S).
%%% ---------------------------------------------------------------------------
+%%% # reopen/3
+%%% ---------------------------------------------------------------------------
+
+%% Note that this connection_up/3 rewrites the same #conn{} now
+%% written here. Both do so in case reopen has not happened in old
+%% code.
+
+reopen(Pid, {TPid, {Caps, SApps, _Pkt}}, #state{peerT = PeerT,
+ connT = ConnT}) ->
+ P = fetch(PeerT, Pid),
+ C = #conn{pid = TPid,
+ apps = SApps,
+ caps = Caps,
+ peer = Pid},
+
+ insert(ConnT, C),
+ #peer{op_state = {?STATE_DOWN, _}}
+ = P,
+ insert(PeerT, P#peer{op_state = {?STATE_DOWN, ?WD_REOPEN},
+ conn = TPid}).
+
+%%% ---------------------------------------------------------------------------
%%% # connection_up/2
-%%%
-%%% Output: #state{}
%%% ---------------------------------------------------------------------------
%% Peer process has transitioned back into the open state. Note that there
@@ -979,10 +1095,8 @@ connection_up(T, P, C, #state{peerT = PeerT,
insert(PeerT, P#peer{op_state = {?STATE_UP, ?WD_OKAY}}),
request_peer_up(TPid),
- report_status(up, P, C, S, T),
- S#state{local_peers = insert_local_peer(SApps,
- {{TPid, Caps}, {SvcName, Apps}},
- LDict)}.
+ insert_local_peer(SApps, {{TPid, Caps}, {SvcName, Apps}}, LDict),
+ report_status(up, P, C, S, T).
insert_local_peer(SApps, T, LDict) ->
lists:foldl(fun(A,D) -> ilp(A, T, D) end, LDict, SApps).
@@ -1024,11 +1138,9 @@ peer_cb(MFA, Alias) ->
%%% ---------------------------------------------------------------------------
%%% # connection_down/2
-%%%
-%%% Output: #state{}
%%% ---------------------------------------------------------------------------
-%% Peer process has transitioned out of the open state.
+%% Watchdog has transitioned out of state OKAY.
connection_down(Pid, #state{peerT = PeerT,
connT = ConnT}
@@ -1044,8 +1156,8 @@ connection_down(Pid, #state{peerT = PeerT,
%% connection_down/3
-connection_down(#peer{op_state = {?STATE_DOWN, _}}, _, S) ->
- S;
+connection_down(#peer{op_state = {?STATE_DOWN, _}}, _, _) ->
+ ok;
connection_down(#peer{conn = TPid,
op_state = {?STATE_UP, _}}
@@ -1058,12 +1170,8 @@ connection_down(#peer{conn = TPid,
local_peers = LDict}
= S) ->
report_status(down, P, C, S, []),
- NewS = S#state{local_peers
- = remove_local_peer(SApps,
- {{TPid, Caps}, {SvcName, Apps}},
- LDict)},
- request_peer_down(TPid, NewS),
- NewS.
+ remove_local_peer(SApps, {{TPid, Caps}, {SvcName, Apps}}, LDict),
+ request_peer_down(TPid, S).
remove_local_peer(SApps, T, LDict) ->
lists:foldl(fun(A,D) -> rlp(A, T, D) end, LDict, SApps).
@@ -1082,11 +1190,9 @@ down_conn(Id, Alias, TC, {SvcName, Apps}) ->
%%% ---------------------------------------------------------------------------
%%% # peer_down/3
-%%%
-%%% Output: #state{}
%%% ---------------------------------------------------------------------------
-%% Peer process has died.
+%% Watchdog process has died.
peer_down(Pid, Reason, #state{peerT = PeerT} = S) ->
P = fetch(PeerT, Pid),
@@ -1106,12 +1212,12 @@ closed({shutdown, {close, _TPid, Reason}},
closed(_, _, _) ->
ok.
-%% The peer has never come up ...
-peer_down(#peer{conn = B}, S)
+%% The watchdog has never reached OKAY ...
+peer_down(#peer{conn = B}, _)
when is_boolean(B) ->
- S;
+ ok;
-%% ... or it has.
+%% ... or maybe it has.
peer_down(#peer{conn = TPid} = P, #state{connT = ConnT} = S) ->
#conn{} = C = fetch(ConnT, TPid),
ets:delete_object(ConnT, C),
@@ -1139,7 +1245,7 @@ restart(#peer{ref = Ref,
started = Time}) ->
{Time, {Ref, T, Opts}};
-%% ... or it has: a replacement transport has already been spawned.
+%% ... or it has: a replacement has already been spawned.
restart(#peer{type = accept}) ->
false.
@@ -1165,8 +1271,8 @@ default_tc(connect, Opts) ->
default_tc(accept, _) ->
0.
-%% Bound tc below if the peer was restarted recently to avoid
-%% continuous in case of faulty config or other problems.
+%% Bound tc below if the watchdog was restarted recently to avoid
+%% continuous restarted in case of faulty config or other problems.
tc(Time, Tc) ->
choose(Tc > ?RESTART_TC
orelse timer:now_diff(now(), Time) > 1000*?RESTART_TC,
@@ -1288,7 +1394,7 @@ cm([_,_|_], _, _, _) ->
multiple.
%%% ---------------------------------------------------------------------------
-%%% # send_request/5
+%%% # send_request/6
%%% ---------------------------------------------------------------------------
%% Send an outgoing request in its dedicated process.
@@ -1301,71 +1407,90 @@ cm([_,_|_], _, _, _) ->
%% The mod field of the #diameter_app{} here includes any extra
%% arguments passed to diameter:call/2.
-send_request({TPid, Caps, App}, Msg, Opts, Caller, SvcName) ->
+send_request({TPid, Caps, App} = T, Mask, Msg, Opts, Caller, SvcName) ->
#diameter_app{module = ModX}
= App,
- Pkt = make_request_packet(Msg),
-
- case cb(ModX, prepare_request, [Pkt, SvcName, {TPid, Caps}]) of
- {send, P} ->
- send_request(make_request_packet(P, Pkt),
- TPid,
- Caps,
- App,
- Opts,
- Caller,
- SvcName);
- {discard, Reason} ->
- {error, Reason};
- discard ->
- {error, discarded};
- T ->
- ?ERROR({invalid_return, prepare_request, App, T})
- end.
+ Pkt = make_prepare_packet(Mask, Msg),
+
+ send_req(cb(ModX, prepare_request, [Pkt, SvcName, {TPid, Caps}]),
+ Pkt,
+ T,
+ Opts,
+ Caller,
+ SvcName,
+ []).
+
+send_req({send, P}, Pkt, T, Opts, Caller, SvcName, Fs) ->
+ send_req(make_request_packet(P, Pkt), T, Opts, Caller, SvcName, Fs);
+
+send_req({discard, Reason} , _, _, _, _, _, _) ->
+ {error, Reason};
+
+send_req(discard, _, _, _, _, _, _) ->
+ {error, discarded};
-%% make_request_packet/1
+send_req({eval_packet, RC, F}, Pkt, T, Opts, Caller, SvcName, Fs) ->
+ send_req(RC, Pkt, T, Opts, Caller, SvcName, [F|Fs]);
+
+send_req(E, _, {_, _, App}, _, _, _, _) ->
+ ?ERROR({invalid_return, prepare_request, App, E}).
+
+%% make_prepare_packet/2
%%
%% Turn an outgoing request as passed to call/4 into a diameter_packet
%% record in preparation for a prepare_request callback.
-make_request_packet(Bin)
+make_prepare_packet(_, Bin)
when is_binary(Bin) ->
#diameter_packet{header = diameter_codec:decode_header(Bin),
bin = Bin};
-make_request_packet(#diameter_packet{msg = [#diameter_header{} = Hdr | Avps]}
- = Pkt) ->
- Pkt#diameter_packet{msg = [make_request_header(Hdr) | Avps]};
+make_prepare_packet(Mask, #diameter_packet{msg = [#diameter_header{} = Hdr
+ | Avps]}
+ = Pkt) ->
+ Pkt#diameter_packet{msg = [make_prepare_header(Mask, Hdr) | Avps]};
-make_request_packet(#diameter_packet{header = Hdr} = Pkt) ->
- Pkt#diameter_packet{header = make_request_header(Hdr)};
+make_prepare_packet(Mask, #diameter_packet{header = Hdr} = Pkt) ->
+ Pkt#diameter_packet{header = make_prepare_header(Mask, Hdr)};
-make_request_packet(Msg) ->
- make_request_packet(#diameter_packet{msg = Msg}).
+make_prepare_packet(Mask, Msg) ->
+ make_prepare_packet(Mask, #diameter_packet{msg = Msg}).
-%% make_request_header/1
+%% make_prepare_header/2
-make_request_header(undefined) ->
- Seq = diameter_session:sequence(),
- make_request_header(#diameter_header{end_to_end_id = Seq,
+make_prepare_header(Mask, undefined) ->
+ Seq = diameter_session:sequence(Mask),
+ make_prepare_header(#diameter_header{end_to_end_id = Seq,
hop_by_hop_id = Seq});
-make_request_header(#diameter_header{version = undefined} = Hdr) ->
- make_request_header(Hdr#diameter_header{version = ?DIAMETER_VERSION});
+make_prepare_header(Mask, #diameter_header{end_to_end_id = undefined,
+ hop_by_hop_id = undefined}
+ = H) ->
+ Seq = diameter_session:sequence(Mask),
+ make_prepare_header(H#diameter_header{end_to_end_id = Seq,
+ hop_by_hop_id = Seq});
+
+make_prepare_header(Mask, #diameter_header{end_to_end_id = undefined} = H) ->
+ Seq = diameter_session:sequence(Mask),
+ make_prepare_header(H#diameter_header{end_to_end_id = Seq});
+
+make_prepare_header(Mask, #diameter_header{hop_by_hop_id = undefined} = H) ->
+ Seq = diameter_session:sequence(Mask),
+ make_prepare_header(H#diameter_header{hop_by_hop_id = Seq});
-make_request_header(#diameter_header{end_to_end_id = undefined} = H) ->
- Seq = diameter_session:sequence(),
- make_request_header(H#diameter_header{end_to_end_id = Seq});
+make_prepare_header(_, Hdr) ->
+ make_prepare_header(Hdr).
-make_request_header(#diameter_header{hop_by_hop_id = undefined} = H) ->
- Seq = diameter_session:sequence(),
- make_request_header(H#diameter_header{hop_by_hop_id = Seq});
+%% make_prepare_header/1
-make_request_header(#diameter_header{} = Hdr) ->
+make_prepare_header(#diameter_header{version = undefined} = Hdr) ->
+ make_prepare_header(Hdr#diameter_header{version = ?DIAMETER_VERSION});
+
+make_prepare_header(#diameter_header{} = Hdr) ->
Hdr;
-make_request_header(T) ->
+make_prepare_header(T) ->
?ERROR({invalid_header, T}).
%% make_request_packet/2
@@ -1375,7 +1500,7 @@ make_request_header(T) ->
make_request_packet(Bin, _)
when is_binary(Bin) ->
- make_request_packet(Bin);
+ make_prepare_packet(false, Bin);
make_request_packet(#diameter_packet{msg = [#diameter_header{} | _]}
= Pkt,
@@ -1387,7 +1512,7 @@ make_request_packet(#diameter_packet{msg = [#diameter_header{} | _]}
%% This is primarily so that the end to end and hop by hop identifiers
%% are retained.
make_request_packet(#diameter_packet{header = Hdr} = Pkt,
- #diameter_packet{header = Hdr0}) ->
+ #diameter_packet{header = Hdr0}) ->
Pkt#diameter_packet{header = fold_record(Hdr0, Hdr)};
make_request_packet(Msg, Pkt) ->
@@ -1400,16 +1525,16 @@ fold_record(undefined, R) ->
fold_record(Rec, R) ->
diameter_lib:fold_tuple(2, Rec, R).
-%% send_request/7
+%% send_req/6
-send_request(Pkt, TPid, Caps, App, Opts, Caller, SvcName) ->
+send_req(Pkt, {TPid, Caps, App}, Opts, Caller, SvcName, Fs) ->
#diameter_app{alias = Alias,
dictionary = Dict,
module = ModX,
options = [{answer_errors, AE} | _]}
= App,
- EPkt = encode(Dict, Pkt),
+ EPkt = encode(Dict, Pkt, Fs),
#options{filter = Filter,
timeout = Timeout}
@@ -1490,6 +1615,13 @@ msg(#diameter_packet{msg = undefined, bin = Bin}) ->
msg(#diameter_packet{msg = Msg}) ->
Msg.
+%% encode/3
+
+encode(Dict, Pkt, Fs) ->
+ P = encode(Dict, Pkt),
+ eval_packet(P, Fs),
+ P.
+
%% encode/2
%% Note that prepare_request can return a diameter_packet containing
@@ -1571,38 +1703,51 @@ send(Pid, Pkt) ->
%% retransmit/4
-retransmit({TPid, Caps, #diameter_app{alias = Alias} = App},
- #request{app = Alias,
- packet = Pkt}
+retransmit({TPid, Caps, #diameter_app{alias = Alias} = App} = T,
+ #request{app = Alias, packet = Pkt0}
= Req,
SvcName,
Timeout) ->
- have_request(Pkt, TPid) %% Don't failover to a peer we've
+ have_request(Pkt0, TPid) %% Don't failover to a peer we've
andalso ?THROW(timeout), %% already sent to.
- case cb(App, prepare_retransmit, [Pkt, SvcName, {TPid, Caps}]) of
- {send, P} ->
- retransmit(make_request_packet(P, Pkt), TPid, Caps, Req, Timeout);
- {discard, Reason} ->
- ?THROW(Reason);
- discard ->
- ?THROW(discarded);
- T ->
- ?ERROR({invalid_return, prepare_retransmit, App, T})
- end.
+ #diameter_packet{header = Hdr0} = Pkt0,
+ Hdr = Hdr0#diameter_header{is_retransmitted = true},
+ Pkt = Pkt0#diameter_packet{header = Hdr},
-%% retransmit/5
+ resend_req(cb(App, prepare_retransmit, [Pkt, SvcName, {TPid, Caps}]),
+ T,
+ Req#request{packet = Pkt},
+ Timeout,
+ []).
-retransmit(Pkt, TPid, Caps, #request{dictionary = Dict} = Req, Timeout) ->
- EPkt = encode(Dict, Pkt),
+resend_req({send, P}, T, #request{packet = Pkt} = Req, Timeout, Fs) ->
+ retransmit(make_request_packet(P, Pkt), T, Req, Timeout, Fs);
+
+resend_req({discard, Reason}, _, _, _, _) ->
+ ?THROW(Reason);
+
+resend_req(discard, _, _, _, _) ->
+ ?THROW(discarded);
+
+resend_req({eval_packet, RC, F}, T, Req, Timeout, Fs) ->
+ resend_req(RC, T, Req, Timeout, [F|Fs]);
+
+resend_req(T, {_, _, App}, _, _, _) ->
+ ?ERROR({invalid_return, prepare_retransmit, App, T}).
- NewReq = Req#request{transport = TPid,
- packet = Pkt,
- caps = Caps},
+%% retransmit/6
- ?LOG(retransmission, NewReq),
- TRef = send_request(TPid, EPkt, NewReq, Timeout),
- {TRef, NewReq}.
+retransmit(Pkt, {TPid, Caps, _}, #request{dictionary = D} = Req0, Tmo, Fs) ->
+ EPkt = encode(D, Pkt, Fs),
+
+ Req = Req0#request{transport = TPid,
+ packet = Pkt,
+ caps = Caps},
+
+ ?LOG(retransmission, Req),
+ TRef = send_request(TPid, EPkt, Req, Tmo),
+ {TRef, Req}.
%% store_request/4
@@ -1674,10 +1819,13 @@ request_peer_down(TPid, S) ->
%%% recv_request/3
%%% ---------------------------------------------------------------------------
-recv_request(TPid, Pkt, {ConnT, SvcName, Apps}) ->
+recv_request(TPid, Pkt, {ConnT, SvcName, Apps}) -> %% upgrade
+ recv_request(TPid, Pkt, {ConnT, SvcName, Apps, ?NOMASK});
+
+recv_request(TPid, Pkt, {ConnT, SvcName, Apps, Mask}) ->
try ets:lookup(ConnT, TPid) of
[C] ->
- recv_request(C, TPid, Pkt, SvcName, Apps);
+ recv_request(C, TPid, Pkt, SvcName, Apps, Mask);
[] -> %% transport has gone down
ok
catch
@@ -1687,7 +1835,12 @@ recv_request(TPid, Pkt, {ConnT, SvcName, Apps}) ->
%% recv_request/5
-recv_request(#conn{apps = SApps, caps = Caps}, TPid, Pkt, SvcName, Apps) ->
+recv_request(#conn{apps = SApps, caps = Caps},
+ TPid,
+ Pkt,
+ SvcName,
+ Apps,
+ Mask) ->
#diameter_caps{origin_host = {OH,_},
origin_realm = {OR,_}}
= Caps,
@@ -1699,6 +1852,7 @@ recv_request(#conn{apps = SApps, caps = Caps}, TPid, Pkt, SvcName, Apps) ->
{SvcName, OH, OR},
TPid,
Apps,
+ Mask,
Caps,
Pkt).
@@ -1724,20 +1878,24 @@ keyfind([Key | Rest], Pos, L) ->
T
end.
-%% recv_request/6
+%% recv_request/7
-recv_request({Id, Alias}, T, TPid, Apps, Caps, Pkt) ->
+recv_request({Id, Alias}, T, TPid, Apps, Mask, Caps, Pkt) ->
#diameter_app{dictionary = Dict}
= A
= find_app(Alias, Apps),
- recv_request(T, {TPid, Caps}, A, diameter_codec:decode(Id, Dict, Pkt));
+ recv_request(T,
+ {TPid, Caps},
+ A,
+ Mask,
+ diameter_codec:decode(Id, Dict, Pkt));
%% Note that the decode is different depending on whether or not Id is
%% ?APP_ID_RELAY.
%% DIAMETER_APPLICATION_UNSUPPORTED 3007
%% A request was sent for an application that is not supported.
-recv_request(false, T, TPid, _, _, Pkt) ->
+recv_request(false, T, TPid, _, _, _, Pkt) ->
As = collect_avps(Pkt),
protocol_error(3007, T, TPid, Pkt#diameter_packet{avps = As}).
@@ -1749,7 +1907,7 @@ collect_avps(Pkt) ->
As
end.
-%% recv_request/4
+%% recv_request/5
%% Wrong number of bits somewhere in the message: reply.
%%
@@ -1758,7 +1916,7 @@ collect_avps(Pkt) ->
%% set to an unrecognized value, or that is inconsistent with the
%% AVP's definition.
%%
-recv_request(T, {TPid, _}, _, #diameter_packet{errors = [Bs | _]} = Pkt)
+recv_request(T, {TPid, _}, _, _, #diameter_packet{errors = [Bs | _]} = Pkt)
when is_bitstring(Bs) ->
protocol_error(3009, T, TPid, Pkt);
@@ -1773,6 +1931,7 @@ recv_request(T, {TPid, _}, _, #diameter_packet{errors = [Bs | _]} = Pkt)
recv_request(T,
{TPid, _},
#diameter_app{id = Id},
+ _,
#diameter_packet{header = #diameter_header{is_proxiable = P},
msg = M}
= Pkt)
@@ -1790,6 +1949,7 @@ recv_request(T,
recv_request(T,
{TPid, _},
_,
+ _,
#diameter_packet{header = #diameter_header{is_error = true}}
= Pkt) ->
protocol_error(3008, T, TPid, Pkt);
@@ -1798,14 +1958,20 @@ recv_request(T,
%% in the relay application. Don't distinguish between the two since
%% each application has its own callback config. That is, the user can
%% easily distinguish between the two cases.
-recv_request(T, TC, App, Pkt) ->
- request_cb(T, TC, App, examine(Pkt)).
+recv_request(T, TC, App, Mask, Pkt) ->
+ request_cb(T, TC, App, Mask, examine(Pkt)).
%% Note that there may still be errors but these aren't protocol
%% (3xxx) errors that lead to an answer-message.
-request_cb({SvcName, _OH, _OR} = T, TC, App, Pkt) ->
- request_cb(cb(App, handle_request, [Pkt, SvcName, TC]), App, T, TC, Pkt).
+request_cb({SvcName, _OH, _OR} = T, TC, App, Mask, Pkt) ->
+ request_cb(cb(App, handle_request, [Pkt, SvcName, TC]),
+ App,
+ Mask,
+ T,
+ TC,
+ [],
+ Pkt).
%% examine/1
%%
@@ -1825,7 +1991,7 @@ examine(#diameter_packet{errors = Es} = Pkt) ->
Pkt#diameter_packet{errors = [5011 | Es]}.
%% It's odd/unfortunate that this isn't a protocol error.
-%% request_cb/5
+%% request_cb/7
%% A reply may be an answer-message, constructed either here or by
%% the handle_request callback. The header from the incoming request
@@ -1835,21 +2001,23 @@ examine(#diameter_packet{errors = Es} = Pkt) ->
request_cb({reply, Ans},
#diameter_app{dictionary = Dict},
_,
+ _,
{TPid, _},
+ Fs,
Pkt) ->
- reply(Ans, Dict, TPid, Pkt);
+ reply(Ans, Dict, TPid, Fs, Pkt);
%% An 3xxx result code, for which the E-bit is set in the header.
-request_cb({protocol_error, RC}, _, T, {TPid, _}, Pkt)
+request_cb({protocol_error, RC}, _, _, T, {TPid, _}, Fs, Pkt)
when 3000 =< RC, RC < 4000 ->
- protocol_error(RC, T, TPid, Pkt);
+ protocol_error(RC, T, TPid, Fs, Pkt);
%% RFC 3588 says we must reply 3001 to anything unrecognized or
%% unsupported. 'noreply' is undocumented (and inappropriately named)
%% backwards compatibility for this, protocol_error the documented
%% alternative.
-request_cb(noreply, _, T, {TPid, _}, Pkt) ->
- protocol_error(3001, T, TPid, Pkt);
+request_cb(noreply, _, _, T, {TPid, _}, Fs, Pkt) ->
+ protocol_error(3001, T, TPid, Fs, Pkt);
%% Relay a request to another peer. This is equivalent to doing an
%% explicit call/4 with the message in question except that (1) a loop
@@ -1869,38 +2037,57 @@ request_cb(noreply, _, T, {TPid, _}, Pkt) ->
request_cb({A, Opts},
#diameter_app{id = Id}
= App,
+ Mask,
T,
TC,
+ Fs,
Pkt)
when A == relay, Id == ?APP_ID_RELAY;
A == proxy, Id /= ?APP_ID_RELAY;
A == resend ->
- resend(Opts, App, T, TC, Pkt);
+ resend(Opts, App, Mask, T, TC, Fs, Pkt);
-request_cb(discard, _, _, _, _) ->
+request_cb(discard, _, _, _, _, _, _) ->
ok;
-request_cb({eval, RC, F}, App, T, TC, Pkt) ->
- request_cb(RC, App, T, TC, Pkt),
+request_cb({eval_packet, RC, F}, App, Mask, T, TC, Fs, Pkt) ->
+ request_cb(RC, App, Mask, T, TC, [F|Fs], Pkt);
+
+request_cb({eval, RC, F}, App, Mask, T, TC, Fs, Pkt) ->
+ request_cb(RC, App, Mask, T, TC, Fs, Pkt),
diameter_lib:eval(F).
-%% protocol_error/4
+%% protocol_error/5
-protocol_error(RC, {_, OH, OR}, TPid, #diameter_packet{avps = Avps} = Pkt) ->
+protocol_error(RC, {_, OH, OR}, TPid, Fs, Pkt) ->
+ #diameter_packet{avps = Avps, errors = Es} = Pkt,
?LOG({error, RC}, Pkt),
- reply(answer_message({OH, OR, RC}, Avps), ?BASE, TPid, Pkt).
+ reply(answer_message({OH, OR, RC}, Avps),
+ ?BASE,
+ TPid,
+ Fs,
+ Pkt#diameter_packet{errors = [RC | Es]}).
+%% Note that reply/5 may set the result code once more. It's set in
+%% answer_message/2 in case reply/5 doesn't.
+
+%% protocol_error/4
-%% resend/5
+protocol_error(RC, T, TPid, Pkt) ->
+ protocol_error(RC, T, TPid, [], Pkt).
+
+%% resend/7
%%
%% Resend a message as a relay or proxy agent.
resend(Opts,
#diameter_app{} = App,
+ Mask,
{_SvcName, OH, _OR} = T,
{_TPid, _Caps} = TC,
+ Fs,
#diameter_packet{avps = Avps} = Pkt) ->
{Code, _Flags, Vid} = ?BASE:avp_header('Route-Record'),
- resend(is_loop(Code, Vid, OH, Avps), Opts, App, T, TC, Pkt).
+ resend(is_loop(Code, Vid, OH, Avps), Opts, App, Mask, T, TC, Fs, Pkt).
%% DIAMETER_LOOP_DETECTED 3005
%% An agent detected a loop while trying to get the message to the
@@ -1908,8 +2095,8 @@ resend(Opts,
%% if one is available, but the peer reporting the error has
%% identified a configuration problem.
-resend(true, _, _, T, {TPid, _}, Pkt) -> %% Route-Record loop
- protocol_error(3005, T, TPid, Pkt);
+resend(true, _, _, _, T, {TPid, _}, Fs, Pkt) -> %% Route-Record loop
+ protocol_error(3005, T, TPid, Fs, Pkt);
%% 6.1.8. Relaying and Proxying Requests
%%
@@ -1920,16 +2107,18 @@ resend(true, _, _, T, {TPid, _}, Pkt) -> %% Route-Record loop
resend(false,
Opts,
App,
+ Mask,
{SvcName, _, _} = T,
{TPid, #diameter_caps{origin_host = {_, OH}}},
+ Fs,
#diameter_packet{header = Hdr0,
avps = Avps}
= Pkt) ->
Route = #diameter_avp{data = {?BASE, 'Route-Record', OH}},
- Seq = diameter_session:sequence(),
+ Seq = diameter_session:sequence(Mask),
Hdr = Hdr0#diameter_header{hop_by_hop_id = Seq},
Msg = [Hdr, Route | Avps],
- resend(call(SvcName, App, Msg, Opts), T, TPid, Pkt).
+ resend(call(SvcName, App, Msg, Opts), T, TPid, Fs, Pkt).
%% The incoming request is relayed with the addition of a
%% Route-Record. Note the requirement on the return from call/4 below,
%% which places a requirement on the value returned by the
@@ -1955,15 +2144,18 @@ resend(#diameter_packet{bin = B}
= Pkt,
_,
TPid,
+ Fs,
#diameter_packet{header = #diameter_header{hop_by_hop_id = Id},
transport_data = TD}) ->
- send(TPid, Pkt#diameter_packet{bin = diameter_codec:hop_by_hop_id(Id, B),
- transport_data = TD});
+ P = Pkt#diameter_packet{bin = diameter_codec:hop_by_hop_id(Id, B),
+ transport_data = TD},
+ eval_packet(P, Fs),
+ send(TPid, P);
%% TODO: counters
%% Or not: DIAMETER_UNABLE_TO_DELIVER.
-resend(_, T, TPid, Pkt) ->
- protocol_error(3002, T, TPid, Pkt).
+resend(_, T, TPid, Fs, Pkt) ->
+ protocol_error(3002, T, TPid, Fs, Pkt).
%% is_loop/4
%%
@@ -1985,52 +2177,69 @@ is_loop(Code, Vid, OH, [_ | Avps])
is_loop(Code, Vid, OH, Avps) ->
is_loop(Code, Vid, ?BASE:avp(encode, OH, 'Route-Record'), Avps).
-%% reply/4
+%% reply/5
%%
%% Send a locally originating reply.
-%% Skip the setting of Result-Code and Failed-AVP's below.
-reply([Msg], Dict, TPid, Pkt)
+%% Skip the setting of Result-Code and Failed-AVP's below. This is
+%% currently undocumented.
+reply([Msg], Dict, TPid, Fs, Pkt)
when is_list(Msg);
is_tuple(Msg) ->
- reply(Msg, Dict, TPid, Pkt#diameter_packet{errors = []});
+ reply(Msg, Dict, TPid, Fs, Pkt#diameter_packet{errors = []});
%% No errors or a diameter_header/avp list.
-reply(Msg, Dict, TPid, #diameter_packet{errors = Es,
- transport_data = TD}
- = ReqPkt)
+reply(Msg, Dict, TPid, Fs, #diameter_packet{errors = Es} = ReqPkt)
when [] == Es;
is_record(hd(Msg), diameter_header) ->
Pkt = diameter_codec:encode(Dict, make_answer_packet(Msg, ReqPkt)),
+ eval_packet(Pkt, Fs),
incr(send, Pkt, Dict, TPid), %% count result codes in sent answers
- send(TPid, Pkt#diameter_packet{transport_data = TD});
+ send(TPid, Pkt);
%% Or not: set Result-Code and Failed-AVP AVP's.
-reply(Msg, Dict, TPid, #diameter_packet{errors = [H|_] = Es} = Pkt) ->
+reply(Msg, Dict, TPid, Fs, #diameter_packet{errors = [H|_] = Es} = Pkt) ->
reply(rc(Msg, rc(H), [A || {_,A} <- Es], Dict),
Dict,
TPid,
+ Fs,
Pkt#diameter_packet{errors = []}).
+eval_packet(Pkt, Fs) ->
+ lists:foreach(fun(F) -> diameter_lib:eval([F,Pkt]) end, Fs).
+
%% make_answer_packet/2
+%% A reply message clears the R and T flags and retains the P flag.
+%% The E flag will be set at encode. 6.2 of 3588 requires the same P
+%% flag on an answer as on the request. A #diameter_packet{} returned
+%% from a handle_request callback can circumvent this by setting its
+%% own header values.
+make_answer_packet(#diameter_packet{header = Hdr,
+ msg = Msg,
+ transport_data = TD},
+ #diameter_packet{header = ReqHdr}) ->
+ Hdr0 = ReqHdr#diameter_header{version = ?DIAMETER_VERSION,
+ is_request = false,
+ is_error = undefined,
+ is_retransmitted = false},
+ #diameter_packet{header = fold_record(Hdr0, Hdr),
+ msg = Msg,
+ transport_data = TD};
+
%% Binaries and header/avp lists are sent as-is.
-make_answer_packet(Bin, _)
+make_answer_packet(Bin, #diameter_packet{transport_data = TD})
when is_binary(Bin) ->
- #diameter_packet{bin = Bin};
-make_answer_packet([#diameter_header{} | _] = Msg, _) ->
- #diameter_packet{msg = Msg};
-
-%% Otherwise a reply message clears the R and T flags and retains the
-%% P flag. The E flag will be set at encode. 6.2 of 3588 requires the
-%% same P flag on an answer as on the request.
-make_answer_packet(Msg, #diameter_packet{header = ReqHdr}) ->
- Hdr = ReqHdr#diameter_header{version = ?DIAMETER_VERSION,
- is_request = false,
- is_error = undefined,
- is_retransmitted = false},
- #diameter_packet{header = Hdr,
- msg = Msg}.
+ #diameter_packet{bin = Bin,
+ transport_data = TD};
+make_answer_packet([#diameter_header{} | _] = Msg,
+ #diameter_packet{transport_data = TD}) ->
+ #diameter_packet{msg = Msg,
+ transport_data = TD};
+
+%% Otherwise, preserve transport_data.
+make_answer_packet(Msg, #diameter_packet{transport_data = TD} = Pkt) ->
+ make_answer_packet(#diameter_packet{msg = Msg, transport_data = TD}, Pkt).
%% rc/1
@@ -2041,6 +2250,9 @@ rc(RC) ->
%% rc/4
+rc(#diameter_packet{msg = Rec} = Pkt, RC, Failed, Dict) ->
+ Pkt#diameter_packet{msg = rc(Rec, RC, Failed, Dict)};
+
rc(Rec, RC, Failed, Dict)
when is_integer(RC) ->
set(Rec,
@@ -2071,7 +2283,7 @@ rc([MsgName | _], {'Result-Code' = K, RC} = T, Dict) ->
rc(Rec, T, Dict) ->
rc([Dict:rec2msg(element(1, Rec))], T, Dict).
-
+
%% failed_avp/3
failed_avp(_, [] = No, _) ->
@@ -2307,7 +2519,7 @@ a(#diameter_packet{errors = Es} = Pkt, SvcName, AE, #request{transport = TPid,
when [] == Es;
callback == AE ->
cb(Req, handle_answer, [Pkt, msg(P), SvcName, {TPid, Caps}]);
-
+
a(Pkt, SvcName, report, Req) ->
x(errors, handle_answer, [SvcName, Req, Pkt]);
@@ -2469,7 +2681,7 @@ send_event(#diameter_event{service = SvcName} = E) ->
%%% # share_peer/5
%%% ---------------------------------------------------------------------------
-share_peer(up, Caps, Aliases, TPid, #state{share_peers = true,
+share_peer(up, Caps, Aliases, TPid, #state{options = [_, {_, true} | _],
service_name = Svc}) ->
diameter_peer:notify(Svc, {peer, TPid, Aliases, Caps});
@@ -2480,11 +2692,11 @@ share_peer(_, _, _, _, _) ->
%%% # share_peers/2
%%% ---------------------------------------------------------------------------
-share_peers(Pid, #state{share_peers = true,
+share_peers(Pid, #state{options = [_, {_, true} | _],
local_peers = PDict}) ->
?Dict:fold(fun(A,Ps,ok) -> sp(Pid, A, Ps), ok end, ok, PDict);
-share_peers(_, #state{share_peers = false}) ->
+share_peers(_, _) ->
ok.
sp(Pid, Alias, Peers) ->
@@ -2494,39 +2706,31 @@ sp(Pid, Alias, Peers) ->
%%% # remote_peer_up/4
%%% ---------------------------------------------------------------------------
-remote_peer_up(Pid, Aliases, Caps, #state{use_shared_peers = true,
+remote_peer_up(Pid, Aliases, Caps, #state{options = [_, _, {_, true} | _],
service = Svc,
- shared_peers = PDict}
- = S) ->
+ shared_peers = PDict}) ->
#diameter_service{applications = Apps} = Svc,
- Update = lists:filter(fun(A) ->
- lists:keymember(A, #diameter_app.alias, Apps)
- end,
- Aliases),
- S#state{shared_peers = rpu(Pid, Caps, PDict, Update)};
+ Key = #diameter_app.alias,
+ As = lists:filter(fun(A) -> lists:keymember(A, Key, Apps) end, Aliases),
+ rpu(Pid, Caps, PDict, As);
-remote_peer_up(_, _, _, #state{use_shared_peers = false} = S) ->
- S.
+remote_peer_up(_, _, _, #state{options = [_, _, {_, false} | _]}) ->
+ ok.
rpu(_, _, PDict, []) ->
PDict;
rpu(Pid, Caps, PDict, Aliases) ->
erlang:monitor(process, Pid),
T = {Pid, Caps},
- lists:foldl(fun(A,D) -> ?Dict:append(A, T, D) end,
- PDict,
- Aliases).
+ lists:foreach(fun(A) -> ?Dict:append(A, T, PDict) end, Aliases).
%%% ---------------------------------------------------------------------------
%%% # remote_peer_down/2
%%% ---------------------------------------------------------------------------
-remote_peer_down(Pid, #state{use_shared_peers = true,
- shared_peers = PDict}
- = S) ->
- S#state{shared_peers = lists:foldl(fun(A,D) -> rpd(Pid, A, D) end,
- PDict,
- ?Dict:fetch_keys(PDict))}.
+remote_peer_down(Pid, #state{options = [_, _, {_, true} | _],
+ shared_peers = PDict}) ->
+ lists:foreach(fun(A) -> rpd(Pid, A, PDict) end, ?Dict:fetch_keys(PDict)).
rpd(Pid, Alias, PDict) ->
?Dict:update(Alias, fun(Ps) -> lists:keydelete(Pid, 1, Ps) end, PDict).
@@ -2851,7 +3055,8 @@ transports(#state{peerT = PeerT}) ->
-define(ALL_INFO, [capabilities,
applications,
transport,
- pending]).
+ pending,
+ options]).
%% The rest.
-define(OTHER_INFO, [connections,
@@ -2878,6 +3083,19 @@ tagged_info(Item, S)
undefined
end;
+tagged_info(TPid, #state{peerT = PT, connT = CT})
+ when is_pid(TPid) ->
+ try
+ [#conn{peer = Pid}] = ets:lookup(CT, TPid),
+ [#peer{ref = Ref, type = Type, options = Opts}] = ets:lookup(PT, Pid),
+ [{ref, Ref},
+ {type, Type},
+ {options, Opts}]
+ catch
+ error:_ ->
+ []
+ end;
+
tagged_info(Items, S)
when is_list(Items) ->
[T || I <- Items, T <- [tagged_info(I,S)], T /= undefined, T /= []];
@@ -2928,6 +3146,7 @@ complete_info(Item, #state{service = Svc} = S) ->
capabilities -> service_info(?CAP_INFO, 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);
@@ -2955,7 +3174,12 @@ info_stats(#state{peerT = PeerT}) ->
MatchSpec = [{#peer{ref = '$1', conn = '$2', _ = '_'},
[{'is_pid', '$2'}],
[['$1', '$2']]}],
- diameter_stats:read(lists:append(ets:select(PeerT, MatchSpec))).
+ try ets:select(PeerT, MatchSpec) of
+ L ->
+ diameter_stats:read(lists:append(L))
+ catch
+ error: badarg -> [] %% service has gone down
+ end.
%% info_transport/1
%%
@@ -3000,7 +3224,12 @@ transport([[{type, accept}, {options, Opts} | _] | _] = Ls) ->
{accept, [lists:nthtail(2,L) || L <- Ls]}].
peer_dict(#state{peerT = PeerT, connT = ConnT}, Dict0) ->
- ets:foldl(fun(T,A) -> peer_acc(ConnT, A, T) end, Dict0, PeerT).
+ try ets:tab2list(PeerT) of
+ L ->
+ lists:foldl(fun(T,A) -> peer_acc(ConnT, A, T) end, Dict0, L)
+ catch
+ error: badarg -> Dict0 %% service has gone down
+ end.
peer_acc(ConnT, Acc, #peer{pid = Pid,
type = Type,
@@ -3019,7 +3248,11 @@ peer_acc(ConnT, Acc, #peer{pid = Pid,
info_conn(ConnT, TPid, true)
when is_pid(TPid) ->
- info_conn(ets:lookup(ConnT, TPid));
+ try ets:lookup(ConnT, TPid) of
+ T -> info_conn(T)
+ catch
+ error: badarg -> [] %% service has gone down
+ end;
info_conn(_, _, _) ->
[].
@@ -3096,7 +3329,11 @@ info_pending(#state{} = S) ->
{{transport, '$2'}},
{{from, '$3'}}]}}]}],
- ets:select(?REQUEST_TABLE, MatchSpec).
+ try
+ ets:select(?REQUEST_TABLE, MatchSpec)
+ catch
+ error: badarg -> [] %% service has gone down
+ end.
%% info_connections/1
%%
@@ -3151,3 +3388,8 @@ peer_acc(Peer, {PeerD, RefD}) ->
[{TPid, _}, [{origin_host, {_, OH}} | _]]
= [proplists:get_value(K, Peer) || K <- [peer, caps]],
{dict:append(OH, Peer, PeerD), dict:append(OH, TPid, RefD)}.
+
+%% info_options/1
+
+info_options(S) ->
+ S#state.options.
diff --git a/lib/diameter/src/base/diameter_session.erl b/lib/diameter/src/base/diameter_session.erl
index 4c468f207c..3b236f109a 100644
--- a/lib/diameter/src/base/diameter_session.erl
+++ b/lib/diameter/src/base/diameter_session.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -20,6 +20,7 @@
-module(diameter_session).
-export([sequence/0,
+ sequence/1,
session_id/1,
origin_state_id/0]).
@@ -30,7 +31,7 @@
-define(INT32, 16#FFFFFFFF).
%% ---------------------------------------------------------------------------
-%% # sequence/0
+%% # sequence/0-1
%%
%% Output: 32-bit
%% ---------------------------------------------------------------------------
@@ -77,6 +78,15 @@ sequence() ->
Instr = {_Pos = 2, _Incr = 1, _Threshold = ?INT32, _SetVal = 0},
ets:update_counter(diameter_sequence, sequence, Instr).
+-spec sequence(diameter:sequence())
+ -> diameter:'Unsigned32'().
+
+sequence({_,32}) ->
+ sequence();
+
+sequence({H,N}) ->
+ (H bsl N) bor (sequence() band (1 bsl N - 1)).
+
%% ---------------------------------------------------------------------------
%% # origin_state_id/0
%% ---------------------------------------------------------------------------
diff --git a/lib/diameter/src/base/diameter_watchdog.erl b/lib/diameter/src/base/diameter_watchdog.erl
index d7474e5c56..243ad0a986 100644
--- a/lib/diameter/src/base/diameter_watchdog.erl
+++ b/lib/diameter/src/base/diameter_watchdog.erl
@@ -43,20 +43,24 @@
-include("diameter_internal.hrl").
-define(DEFAULT_TW_INIT, 30000). %% RFC 3539 ch 3.4.1
+-define(NOMASK, {0,32}). %% default sequence mask
-record(watchdog,
{%% PCB - Peer Control Block; see RFC 3539, Appendix A
status = initial :: initial | okay | suspect | down | reopen,
- pending = false :: boolean(),
+ pending = false :: boolean(), %% DWA
tw :: 6000..16#FFFFFFFF | {module(), atom(), list()},
%% {M,F,A} -> integer() >= 0
num_dwa = 0 :: -1 | non_neg_integer(),
%% number of DWAs received during reopen
%% end PCB
- parent = self() :: pid(),
- transport :: pid() | undefined,
+ parent = self() :: pid(), %% service process
+ transport :: pid() | undefined, %% peer_fsm process
tref :: reference(), %% reference for current watchdog timer
- message_data}). %% term passed into diameter_service with message
+ message_data, %% term passed into diameter_service with message
+ sequence :: diameter:sequence(), %% mask
+ restrict :: {diameter:restriction(), boolean()},
+ shutdown = false :: boolean()}).
%% start/2
%%
@@ -118,12 +122,23 @@ make_state({T, Pid, {RecvData,
random:seed(now()),
putr(restart, {T, Opts, Svc}), %% save seeing it in trace
putr(dwr, dwr(Caps)), %%
+ {_,_} = Mask = call(Pid, sequence),
+ Restrict = call(Pid, restriction),
+ Nodes = restrict_nodes(Restrict),
#watchdog{parent = Pid,
- transport = monitor(diameter_peer_fsm:start(T, Opts, Svc)),
+ transport = monitor(diameter_peer_fsm:start(T,
+ Opts,
+ {Mask, Nodes, Svc})),
tw = proplists:get_value(watchdog_timer,
Opts,
?DEFAULT_TW_INIT),
- message_data = {RecvData, SvcName, Apps}}.
+ message_data = {RecvData, SvcName, Apps, Mask},
+ sequence = Mask,
+ restrict = {Restrict, lists:member(node(), Nodes)}}.
+
+%% Retrieve the sequence mask from the parent from the parent, rather
+%% than having it passed into init/1, for upgrade reasons: the call to
+%% diameter_service:receive_message/3 passes back the mask.
%% handle_call/3
@@ -137,7 +152,7 @@ handle_cast(_, State) ->
%% handle_info/2
-handle_info(T, State) ->
+handle_info(T, #watchdog{} = State) ->
case transition(T, State) of
ok ->
{noreply, State};
@@ -148,7 +163,14 @@ handle_info(T, State) ->
?LOG(stop, T),
event(State, State#watchdog{status = down}),
{stop, {shutdown, T}, State}
- end.
+ end;
+
+handle_info(T, S) ->
+ handle_info(T, upgrade(S)).
+
+upgrade(S) ->
+ #watchdog{} = list_to_tuple(tuple_to_list(S)
+ ++ [?NOMASK, {nodes, true}, false]).
event(#watchdog{status = T}, #watchdog{status = T}) ->
ok;
@@ -205,9 +227,10 @@ transition({shutdown, Pid}, #watchdog{parent = Pid,
down = S, %% sanity check
stop;
transition({shutdown = T, Pid}, #watchdog{parent = Pid,
- transport = TPid}) ->
+ transport = TPid}
+ = S) ->
TPid ! {T, self()},
- ok;
+ S#watchdog{shutdown = true};
%% Parent process has died,
transition({'DOWN', _, process, Pid, _Reason},
@@ -241,9 +264,10 @@ transition({close, TPid, _Reason}, #watchdog{transport = TPid}) ->
transition({open, TPid, Hosts, T} = Open,
#watchdog{transport = TPid,
status = initial,
- parent = Pid}
+ parent = Pid,
+ restrict = {_, R}}
= S) ->
- case okay(getr(restart), Hosts) of
+ case okay(getr(restart), Hosts, R) of
okay ->
open(Pid, {TPid, T}),
set_watchdog(S#watchdog{status = okay});
@@ -258,12 +282,15 @@ transition({open, TPid, Hosts, T} = Open,
transition({open = P, TPid, _Hosts, T},
#watchdog{transport = TPid,
+ parent = Pid,
status = down}
= S) ->
%% Store the info we need to notify the parent to reopen the
%% connection after the requisite DWA's are received, at which
- %% time we eraser(open).
+ %% time we eraser(open). The reopen message is a later addition,
+ %% to communicate the new capabilities as soon as they're known.
putr(P, {TPid, T}),
+ Pid ! {reopen, self(), {TPid, T}},
set_watchdog(send_watchdog(S#watchdog{status = reopen,
num_dwa = 0}));
@@ -277,7 +304,10 @@ transition({open = P, TPid, _Hosts, T},
transition({'DOWN', _, process, TPid, _},
#watchdog{transport = TPid,
- status = initial}) ->
+ status = S,
+ shutdown = D})
+ when S == initial;
+ D ->
stop;
transition({'DOWN', _, process, TPid, _},
@@ -312,6 +342,15 @@ transition({state, Pid}, #watchdog{status = S}) ->
%% ===========================================================================
+%% Only call "upwards", to the parent service.
+call(Pid, Req) ->
+ try
+ gen_server:call(Pid, Req, infinity)
+ catch
+ exit: Reason ->
+ exit({shutdown, {Req, Reason}})
+ end.
+
monitor(Pid) ->
erlang:monitor(process, Pid),
Pid.
@@ -325,26 +364,36 @@ getr(Key) ->
eraser(Key) ->
erase({?MODULE, Key}).
-%% encode/1
+%% encode/2
-encode(Msg) ->
- #diameter_packet{bin = Bin} = diameter_codec:encode(?BASE, Msg),
+encode(Msg, Mask) ->
+ Seq = diameter_session:sequence(Mask),
+ Hdr = #diameter_header{version = ?DIAMETER_VERSION,
+ end_to_end_id = Seq,
+ hop_by_hop_id = Seq},
+ Pkt = #diameter_packet{header = Hdr,
+ msg = Msg},
+ #diameter_packet{bin = Bin} = diameter_codec:encode(?BASE, Pkt),
Bin.
-%% okay/2
+%% okay/3
-okay({{accept, Ref}, _, _}, Hosts) ->
+okay({{accept, Ref}, _, _}, Hosts, Restrict) ->
T = {?MODULE, connection, Ref, Hosts},
diameter_reg:add(T),
- okay(diameter_reg:match(T));
+ if Restrict ->
+ okay(diameter_reg:match(T));
+ true ->
+ okay
+ end;
%% Register before matching so that at least one of two registering
-%% processes will match the other. (Which can't happen as long as
-%% diameter_peer_fsm guarantees at most one open connection to the same
-%% peer.)
+%% processes will match the other.
-okay({{connect, _}, _, _}, _) ->
+okay({{connect, _}, _, _}, _, _) ->
okay.
+%% okay/2
+
%% The peer hasn't been connected recently ...
okay([{_,P}]) ->
P = self(), %% assert
@@ -400,9 +449,10 @@ close(#watchdog{parent = Pid}) ->
%% send_watchdog/1
send_watchdog(#watchdog{pending = false,
- transport = TPid}
+ transport = TPid,
+ sequence = Mask}
= S) ->
- TPid ! {send, encode(getr(dwr))},
+ TPid ! {send, encode(getr(dwr), Mask)},
?LOG(send, 'DWR'),
S#watchdog{pending = true}.
@@ -437,6 +487,14 @@ throwaway(S) ->
throw({?MODULE, throwaway, S}).
%% rcv/2
+%%
+%% The lack of Hop-by-Hop and End-to-End Identifiers checks in a
+%% received DWA is intentional. The purpose of the message is to
+%% demonstrate life but a peer that consistently bungles it by sending
+%% the wrong identifiers causes the connection to toggle between OPEN
+%% and SUSPECT, with failover and failback as result, despite there
+%% being no real problem with connectivity. Thus, relax and accept any
+%% incoming DWA as being in response to an outgoing DWR.
%% INITIAL Receive DWA Pending = FALSE
%% Throwaway() INITIAL
@@ -555,7 +613,7 @@ timeout(#watchdog{status = T,
= S)
when T == suspect;
T == reopen, P, N < 0 ->
- exit(TPid, shutdown),
+ exit(TPid, {shutdown, watchdog_timeout}),
close(S),
S#watchdog{status = down};
@@ -600,19 +658,40 @@ restart(#watchdog{transport = undefined} = S) ->
restart(S) ->
S.
+%% restart/2
+%%
%% Only restart the transport in the connecting case. For an accepting
-%% transport, we've registered the peer connection when leaving state
-%% initial and this is used by a new accepting process to realize that
-%% it's actually in state down rather then initial when receiving
-%% notification of an open connection.
-
-restart({{connect, _} = T, Opts, Svc}, #watchdog{parent = Pid} = S) ->
+%% transport, there's no guarantee that an accepted connection in a
+%% restarted transport if from the peer we've lost contact with so
+%% have to be prepared for another watchdog to handle it. This is what
+%% the diameter_reg registration in this module is for: the peer
+%% connection is registered when leaving state initial and this is
+%% used by a new accepting watchdog to realize that it's actually in
+%% state down rather then initial when receiving notification of an
+%% open connection.
+
+restart({{connect, _} = T, Opts, Svc}, #watchdog{parent = Pid,
+ sequence = Mask,
+ restrict = {R,_}}
+ = S) ->
Pid ! {reconnect, self()},
- S#watchdog{transport = monitor(diameter_peer_fsm:start(T, Opts, Svc))};
+ Nodes = restrict_nodes(R),
+ S#watchdog{transport = monitor(diameter_peer_fsm:start(T,
+ Opts,
+ {Mask, Nodes, Svc})),
+ restrict = {R, lists:member(node(), Nodes)}};
+
+%% No restriction on the number of connections to the same peer: just
+%% die. Note that a state machine never enters state REOPEN in this
+%% case.
+restart({{accept, _}, _, _}, #watchdog{restrict = {_, false}}) ->
+ stop;
+
+%% Otherwise hang around until told to die.
restart({{accept, _}, _, _}, S) ->
S.
-%% Don't currently use Opts/Svc in the accept case but having them in
-%% the process dictionary is helpful if the process dies unexpectedly.
+
+%% Don't currently use Opts/Svc in the accept case.
%% dwr/1
@@ -622,3 +701,22 @@ dwr(#diameter_caps{origin_host = OH,
['DWR', {'Origin-Host', OH},
{'Origin-Realm', OR},
{'Origin-State-Id', OSI}].
+
+%% restrict_nodes/1
+
+restrict_nodes(false) ->
+ [];
+
+restrict_nodes(nodes) ->
+ [node() | nodes()];
+
+restrict_nodes(node) ->
+ [node()];
+
+restrict_nodes(Nodes)
+ when [] == Nodes;
+ is_atom(hd(Nodes)) ->
+ Nodes;
+
+restrict_nodes(F) ->
+ diameter_lib:eval(F).
diff --git a/lib/diameter/test/Makefile b/lib/diameter/test/Makefile
index e3a57553c1..866d135bd9 100644
--- a/lib/diameter/test/Makefile
+++ b/lib/diameter/test/Makefile
@@ -16,13 +16,8 @@
#
# %CopyrightEnd%
-ifeq ($(ERL_TOP),)
-include $(DIAMETER_TOP)/make/target.mk
-include $(DIAMETER_TOP)/make/$(TARGET)/rules.mk
-else
include $(ERL_TOP)/make/target.mk
include $(ERL_TOP)/make/$(TARGET)/otp.mk
-endif
# ----------------------------------------------------
# Application version
@@ -148,11 +143,7 @@ log:
/%: % force
sed -f release.sed $< > "$(RELSYSDIR)$@"
-ifeq ($(ERL_TOP),)
-include $(DIAMETER_TOP)/make/release_targets.mk
-else
include $(ERL_TOP)/make/otp_release_targets.mk
-endif
release_spec release_docs_spec:
diff --git a/lib/diameter/test/diameter_compiler_SUITE.erl b/lib/diameter/test/diameter_compiler_SUITE.erl
index 4b792b5426..79bf9d32db 100644
--- a/lib/diameter/test/diameter_compiler_SUITE.erl
+++ b/lib/diameter/test/diameter_compiler_SUITE.erl
@@ -31,8 +31,8 @@
%% testcases
-export([format/1, format/2,
replace/1, replace/2,
- generate/1, generate/4, generate/0,
- examples/1, examples/0]).
+ generate/1, generate/4,
+ examples/1]).
-export([dict/0]). %% fake dictionary module
@@ -339,7 +339,7 @@
%% ===========================================================================
suite() ->
- [{timetrap, {minutes, 2}}].
+ [{timetrap, {minutes, 10}}].
all() ->
[format,
@@ -407,9 +407,6 @@ re({RE, Repl}, Bin) ->
%%
%% Ensure success when generating code and compiling.
-generate() ->
- [{timetrap, {seconds, 2*length(?REPLACE)}}].
-
generate(Config) ->
Bin = proplists:get_value(base, Config),
Rs = lists:zip(?REPLACE, lists:seq(1, length(?REPLACE))),
@@ -436,9 +433,6 @@ generate(Mods, Bin, N, Mode) ->
%%
%% Compile dictionaries extracted from various standards.
-examples() ->
- [{timetrap, {seconds, 3*length(?EXAMPLES)}}].
-
examples(_Config) ->
Dir = filename:join([code:lib_dir(diameter, examples), "dict"]),
[D || D <- ?EXAMPLES, _ <- [examples(?S(D), Dir)]].
diff --git a/lib/diameter/test/diameter_dpr_SUITE.erl b/lib/diameter/test/diameter_dpr_SUITE.erl
new file mode 100644
index 0000000000..9252650bf7
--- /dev/null
+++ b/lib/diameter/test/diameter_dpr_SUITE.erl
@@ -0,0 +1,196 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%% Tests of the disconnect_cb configuration.
+%%
+
+-module(diameter_dpr_SUITE).
+
+-export([suite/0,
+ all/0,
+ groups/0,
+ init_per_group/2,
+ end_per_group/2]).
+
+%% testcases
+-export([start/1,
+ connect/1,
+ remove_transport/1,
+ stop_service/1,
+ check/1,
+ stop/1]).
+
+%% disconnect_cb
+-export([disconnect/5]).
+
+-include("diameter.hrl").
+
+%% ===========================================================================
+
+-define(util, diameter_util).
+
+-define(ADDR, {127,0,0,1}).
+
+-define(CLIENT, "CLIENT").
+-define(SERVER, "SERVER").
+
+-define(DICT_COMMON, ?DIAMETER_DICT_COMMON).
+-define(APP_ID, ?DICT_COMMON:id()).
+
+%% Config for diameter:start_service/2.
+-define(SERVICE(Host),
+ [{'Origin-Host', Host},
+ {'Origin-Realm', "erlang.org"},
+ {'Host-IP-Address', [?ADDR]},
+ {'Vendor-Id', hd(Host)}, %% match this in disconnect/5
+ {'Product-Name', "OTP/diameter"},
+ {'Acct-Application-Id', [?APP_ID]},
+ {restrict_connections, false},
+ {application, [{dictionary, ?DICT_COMMON},
+ {module, #diameter_callback{_ = false}}]}]).
+
+%% Disconnect reasons that diameter passes as the first argument of a
+%% function configured as disconnect_cb.
+-define(REASONS, [transport, service, application]).
+
+%% Valid values for Disconnect-Cause.
+-define(CAUSES, [0, rebooting, 1, busy, 2, goaway]).
+
+%% Establish one client connection for element of this list,
+%% configured with disconnect/5 as disconnect_cb and returning the
+%% specified value.
+-define(RETURNS,
+ [[close, {dpr, [{cause, invalid}]}], [ignore, close], []]
+ ++ [[{dpr, [{timeout, 5000}, {cause, T}]}] || T <- ?CAUSES]).
+
+%% ===========================================================================
+
+suite() ->
+ [{timetrap, {seconds, 60}}].
+
+all() ->
+ [{group, R} || R <- ?REASONS].
+
+%% The group determines how transports are terminated: by remove_transport,
+%% stop_service or application stop.
+groups() ->
+ Ts = tc(),
+ [{R, [], Ts} || R <- ?REASONS].
+
+init_per_group(Name, Config) ->
+ [{group, Name} | Config].
+
+end_per_group(_, _) ->
+ ok.
+
+tc() ->
+ [start, connect, remove_transport, stop_service, check, stop].
+
+%% ===========================================================================
+%% start/stop testcases
+
+start(_Config) ->
+ ok = diameter:start(),
+ ok = diameter:start_service(?SERVER, ?SERVICE(?SERVER)),
+ ok = diameter:start_service(?CLIENT, ?SERVICE(?CLIENT)).
+
+connect(Config) ->
+ Pid = spawn(fun init/0), %% process for disconnect_cb to bang
+ Grp = group(Config),
+ LRef = ?util:listen(?SERVER, tcp),
+ Refs = [?util:connect(?CLIENT, tcp, LRef, opts(RCs, {Grp, Pid}))
+ || RCs <- ?RETURNS],
+ ?util:write_priv(Config, config, [Pid | Refs]).
+
+%% Remove all the client transports only in the transport group.
+remove_transport(Config) ->
+ transport == group(Config)
+ andalso (ok = diameter:remove_transport(?CLIENT, true)).
+
+%% Stop the service only in the service group.
+stop_service(Config) ->
+ service == group(Config)
+ andalso (ok = diameter:stop_service(?CLIENT)).
+
+%% Check for callbacks and stop the service. (Not the other way around
+%% for the timing reason explained below.)
+check(Config) ->
+ Grp = group(Config),
+ [Pid | Refs] = ?util:read_priv(Config, config),
+ Pid ! self(), %% ask for dictionary
+ Dict = receive {Pid, D} -> D end, %% get it
+ check(Refs, ?RETURNS, Grp, Dict). %% check for callbacks
+
+stop(_Config) ->
+ ok = diameter:stop().
+
+%% Whether or not there are callbacks after diameter:stop() depends on
+%% timing as long as the server runs on the same node: a server
+%% transport could close the connection before the client has chance
+%% to apply its callback. Therefore, just check that there haven't
+%% been any callbacks yet.
+check(_, _, application, Dict) ->
+ [] = dict:to_list(Dict);
+
+check([], [], _, _) ->
+ ok;
+
+check([Ref | Refs], CBs, Grp, Dict) ->
+ check1(Ref, hd(CBs), Grp, Dict),
+ check(Refs, tl(CBs), Grp, Dict).
+
+check1(Ref, [ignore | RCs], Reason, Dict) ->
+ check1(Ref, RCs, Reason, Dict);
+
+check1(Ref, [_|_], Reason, Dict) ->
+ {ok, Reason} = dict:find(Ref, Dict); %% callback with expected reason
+
+check1(Ref, [], _, Dict) ->
+ error = dict:find(Ref, Dict). %% no callback
+
+%% ----------------------------------------
+
+group(Config) ->
+ {group, Grp} = lists:keyfind(group, 1, Config),
+ Grp.
+
+%% Configure the callback with the group name (= disconnect reason) as
+%% extra argument.
+opts(RCs, T) ->
+ [{disconnect_cb, {?MODULE, disconnect, [T, RC]}} || RC <- RCs].
+
+%% Match the group name with the disconnect reason to ensure the
+%% callback is being called as expected.
+disconnect(Reason, Ref, Peer, {Reason, Pid}, RC) ->
+ io:format("disconnect: ~p ~p~n", [Ref, Reason]),
+ {_, #diameter_caps{vendor_id = {$C,$S}}} = Peer,
+ Pid ! {Reason, Ref},
+ RC.
+
+init() ->
+ exit(recv(dict:new())).
+
+recv(Dict) ->
+ receive
+ Pid when is_pid(Pid) ->
+ Pid ! {self(), Dict};
+ {Reason, Ref} ->
+ recv(dict:store(Ref, Reason, Dict))
+ end.
diff --git a/lib/diameter/test/diameter_event_SUITE.erl b/lib/diameter/test/diameter_event_SUITE.erl
new file mode 100644
index 0000000000..7c1c76f22a
--- /dev/null
+++ b/lib/diameter/test/diameter_event_SUITE.erl
@@ -0,0 +1,182 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%% Tests of events sent as a consequence of diameter:subscribe/1.
+%% Watchdog events are dealt with more extensively in the watchdog
+%% suite.
+%%
+
+-module(diameter_event_SUITE).
+
+-export([suite/0,
+ all/0,
+ init_per_testcase/2,
+ end_per_testcase/2]).
+
+%% testcases
+-export([start/1,
+ start_server/1,
+ up/1,
+ down/1,
+ cea_timeout/1,
+ stop/1]).
+
+-include("diameter.hrl").
+
+%% ===========================================================================
+
+-define(util, diameter_util).
+
+-define(ADDR, {127,0,0,1}).
+-define(REALM, "REALM").
+
+-define(SERVER, "SERVER.SERVER-REALM").
+-define(CLIENT, "CLIENT.CLIENT-REALM").
+
+-define(DICT_COMMON, ?DIAMETER_DICT_COMMON).
+-define(DICT_ACCT, ?DIAMETER_DICT_ACCOUNTING).
+
+-define(SERVER_CAPX_TMO, 6000).
+
+%% Config for diameter:start_service/2.
+-define(SERVICE(Host, Dicts),
+ [{'Origin-Host', Host},
+ {'Origin-Realm', realm(Host)},
+ {'Host-IP-Address', [?ADDR]},
+ {'Vendor-Id', 12345},
+ {'Product-Name', "OTP/diameter"},
+ {'Acct-Application-Id', [D:id() || D <- Dicts]}
+ | [{application, [{dictionary, D},
+ {module, #diameter_callback{}}]}
+ || D <- Dicts]]).
+
+%% Diameter Result-Code's:
+-define(NO_COMMON_APP, 5010).
+
+%% ===========================================================================
+
+suite() ->
+ [{timetrap, {seconds, 60}}].
+
+all() ->
+ [start,
+ start_server,
+ up,
+ down,
+ cea_timeout,
+ stop].
+
+init_per_testcase(Name, Config) ->
+ [{name, Name} | Config].
+
+end_per_testcase(_, _) ->
+ ok.
+
+%% ===========================================================================
+%% start/stop testcases
+
+start(_Config) ->
+ ok = diameter:start().
+
+start_server(Config) ->
+ diameter:subscribe(?SERVER),
+ ok = diameter:start_service(?SERVER, ?SERVICE(?SERVER, [?DICT_COMMON])),
+ LRef = ?util:listen(?SERVER, tcp, [{capabilities_cb, fun capx_cb/2},
+ {capx_timeout, ?SERVER_CAPX_TMO}]),
+ [PortNr] = ?util:lport(tcp, LRef, 20),
+ ?util:write_priv(Config, portnr, PortNr),
+ start = event(?SERVER).
+
+%% Connect with matching capabilities and expect the connection to
+%% come up.
+up(Config) ->
+ {Svc, Ref} = connect(Config, []),
+ start = event(Svc),
+ {up, Ref, {_,_Caps}, _Config, #diameter_packet{}} = event(Svc),
+ {watchdog, Ref, _, {initial, okay}, _} = event(Svc).
+
+%% Connect with non-matching capabilities and expect CEA from the peer
+%% to indicate as much and then for the transport to be restarted
+%% (after reconnect_timer).
+down(Config) ->
+ {Svc, Ref} = connect(Config, [{capabilities, [{'Acct-Application-Id',
+ [?DICT_ACCT:id()]}]},
+ {applications, [?DICT_ACCT]},
+ {reconnect_timer, 5000}]),
+ start = event(Svc),
+ {watchdog, Ref, _, {initial, down}, _} = event(Svc),
+ {closed, Ref, {'CEA', ?NO_COMMON_APP, _, #diameter_packet{}}, _}
+ = event(Svc),
+ {reconnect, Ref, _} = event(Svc).
+
+%% Connect with matching capabilities but have the server delay its
+%% CEA and cause the client to timeout.
+cea_timeout(Config) ->
+ {Svc, Ref} = connect(Config, [{capx_timeout, ?SERVER_CAPX_TMO div 2},
+ {reconnect_timer, 2*?SERVER_CAPX_TMO}]),
+ start = event(Svc),
+ {watchdog, Ref, _, {initial, down}, _} = event(Svc),
+ {closed, Ref, {'CEA', timeout}, _} = event(Svc).
+
+stop(_Config) ->
+ ok = diameter:stop().
+
+%% ----------------------------------------
+
+%% Keep the server from sending CEA until the client has timed out.
+capx_cb(_, #diameter_caps{origin_host = {_, "cea_timeout-" ++ _}}) ->
+ receive after ?SERVER_CAPX_TMO -> ok end;
+
+%% Or not.
+capx_cb(_, _Caps) ->
+ ok.
+
+%% ----------------------------------------
+
+%% Use the testcase name to construct Origin-Host of the client so
+%% that the server can match on it in capx_cb/2.
+connect(Config, Opts) ->
+ Pre = atom_to_list(proplists:get_value(name, Config)),
+ Name = Pre ++ uniq() ++ ?CLIENT,
+ diameter:subscribe(Name),
+ ok = start_service(Name, ?SERVICE(Name, [?DICT_COMMON, ?DICT_ACCT])),
+ {ok, Ref} = diameter:add_transport(Name, opts(Config, Opts)),
+ {Name, Ref}.
+
+uniq() ->
+ {MS,S,US} = now(),
+ lists:flatten(io_lib:format("-~p-~p-~p-", [MS,S,US])).
+
+event(Name) ->
+ receive #diameter_event{service = Name, info = T} -> T end.
+
+start_service(Name, Opts) ->
+ diameter:start_service(Name, [{monitor, self()} | Opts]).
+
+opts(Config, Opts) ->
+ PortNr = ?util:read_priv(Config, portnr),
+
+ {connect, [{transport_module, diameter_tcp},
+ {transport_config, [{ip, ?ADDR}, {port, 0},
+ {raddr, ?ADDR}, {rport, PortNr}]}
+ | Opts]}.
+
+realm(Host) ->
+ tl(lists:dropwhile(fun(C) -> C /= $. end, Host)).
diff --git a/lib/diameter/test/diameter_failover_SUITE.erl b/lib/diameter/test/diameter_failover_SUITE.erl
index ed31670031..bb820a8bf2 100644
--- a/lib/diameter/test/diameter_failover_SUITE.erl
+++ b/lib/diameter/test/diameter_failover_SUITE.erl
@@ -18,19 +18,19 @@
%%
%%
-%% Tests of traffic between six Diameter nodes in three realms,
+%% Tests of traffic between seven Diameter nodes in four realms,
%% connected as follows.
%%
-%% ----- SERVER1.REALM2
-%% /
-%% / ----- SERVER2.REALM2
-%% | /
-%% CLIENT.REALM1 ------ SERVER3.REALM2
-%% | \
-%% | \
-%% \ ---- SERVER1.REALM3
-%% \
-%% ----- SERVER2.REALM3
+%% ----- SERVER1.REALM2 -----
+%% / \
+%% / ----- SERVER2.REALM2 ----- \
+%% | / \ |
+%% CLIENT.REALM1 ------ SERVER3.REALM2 ------ CLIENT.REALM4
+%% | \ / |
+%% | \ / |
+%% \ ---- SERVER1.REALM3 ----- /
+%% \ /
+%% ----- SERVER2.REALM3 -----
%%
-module(diameter_failover_SUITE).
@@ -44,12 +44,16 @@
connect/1,
send_ok/1,
send_nok/1,
+ send_discard_1/1,
+ send_discard_2/1,
stop_services/1,
stop/1]).
%% diameter callbacks
-export([pick_peer/4,
prepare_request/3,
+ prepare_retransmit/3,
+ handle_error/4,
handle_answer/4,
handle_request/3]).
@@ -62,14 +66,18 @@
-define(ADDR, {127,0,0,1}).
--define(CLIENT, "CLIENT.REALM1").
+-define(CLIENT1, "CLIENT.REALM1").
+-define(CLIENT2, "CLIENT.REALM4").
-define(SERVER1, "SERVER1.REALM2").
-define(SERVER2, "SERVER2.REALM2").
-define(SERVER3, "SERVER3.REALM2").
-define(SERVER4, "SERVER1.REALM3").
-define(SERVER5, "SERVER2.REALM3").
--define(SERVICES, [?CLIENT, ?SERVER1, ?SERVER2, ?SERVER3, ?SERVER4, ?SERVER5]).
+-define(IS_CLIENT(Svc), Svc == ?CLIENT1; Svc == ?CLIENT2).
+
+-define(CLIENTS, [?CLIENT1, ?CLIENT2]).
+-define(SERVERS, [?SERVER1, ?SERVER2, ?SERVER3, ?SERVER4, ?SERVER5]).
-define(DICT_COMMON, ?DIAMETER_DICT_COMMON).
@@ -77,26 +85,27 @@
-define(APP_ID, ?DICT_COMMON:id()).
%% Config for diameter:start_service/2.
--define(SERVICE(Host, Dict),
+-define(SERVICE(Host),
[{'Origin-Host', Host},
{'Origin-Realm', realm(Host)},
{'Host-IP-Address', [?ADDR]},
{'Vendor-Id', 12345},
{'Product-Name', "OTP/diameter"},
- {'Acct-Application-Id', [Dict:id()]},
+ {'Acct-Application-Id', [?APP_ID]},
{application, [{alias, ?APP_ALIAS},
- {dictionary, Dict},
+ {dictionary, ?DICT_COMMON},
{module, #diameter_callback
{peer_up = false,
peer_down = false,
- handle_error = false,
- prepare_retransmit = false,
default = ?MODULE}},
{answer_errors, callback}]}]).
-define(SUCCESS, 2001).
--define(LOGOUT, ?'DIAMETER_BASE_TERMINATION-CAUSE_DIAMETER_LOGOUT').
+%% Value of Termination-Cause determines client/server behaviour.
+-define(LOGOUT, ?'DIAMETER_BASE_TERMINATION-CAUSE_DIAMETER_LOGOUT').
+-define(MOVED, ?'DIAMETER_BASE_TERMINATION-CAUSE_DIAMETER_USER_MOVED').
+-define(TIMEOUT, ?'DIAMETER_BASE_TERMINATION-CAUSE_DIAMETER_SESSION_TIMEOUT').
%% ===========================================================================
@@ -109,6 +118,8 @@ all() ->
connect,
send_ok,
send_nok,
+ send_discard_1,
+ send_discard_2,
stop_services,
stop].
@@ -119,19 +130,20 @@ start(_Config) ->
ok = diameter:start().
start_services(_Config) ->
- S = [server(N, ?DICT_COMMON) || N <- tl(?SERVICES)],
-
- ok = diameter:start_service(?CLIENT, ?SERVICE(?CLIENT, ?DICT_COMMON)),
+ Servers = [server(N) || N <- ?SERVERS],
+ [] = [T || C <- ?CLIENTS,
+ T <- [diameter:start_service(C, ?SERVICE(C))],
+ T /= ok],
- {save_config, [{?CLIENT, S}]}.
+ {save_config, Servers}.
connect(Config) ->
- {_, Conns} = proplists:get_value(saved_config, Config),
+ {start_services, Servers} = proplists:get_value(saved_config, Config),
- lists:foreach(fun({CN,Ss}) -> connect(CN, Ss) end, Conns).
+ lists:foreach(fun(C) -> connect(C, Servers) end, ?CLIENTS).
stop_services(_Config) ->
- [] = [{H,T} || H <- ?SERVICES,
+ [] = [{H,T} || H <- ?CLIENTS ++ ?SERVERS,
T <- [diameter:stop_service(H)],
T /= ok].
@@ -140,8 +152,8 @@ stop(_Config) ->
%% ----------------------------------------
-server(Name, Dict) ->
- ok = diameter:start_service(Name, ?SERVICE(Name, Dict)),
+server(Name) ->
+ ok = diameter:start_service(Name, ?SERVICE(Name)),
{Name, ?util:listen(Name, tcp)}.
connect(Name, Refs) ->
@@ -153,30 +165,39 @@ connect(Name, Refs) ->
%% Send an STR and expect success after SERVER3 answers after a couple
%% of failovers.
send_ok(_Config) ->
- Req = ['STR', {'Destination-Realm', realm(?SERVER1)},
- {'Termination-Cause', ?LOGOUT},
- {'Auth-Application-Id', ?APP_ID}],
+ Req = #diameter_base_STR{'Destination-Realm' = realm(?SERVER1),
+ 'Termination-Cause' = ?LOGOUT,
+ 'Auth-Application-Id' = ?APP_ID},
#diameter_base_STA{'Result-Code' = ?SUCCESS,
'Origin-Host' = ?SERVER3}
- = call(Req, [{filter, realm}]).
+ = call(?CLIENT1, Req).
%% Send an STR and expect failure when both servers fail.
send_nok(_Config) ->
- Req = ['STR', {'Destination-Realm', realm(?SERVER4)},
- {'Termination-Cause', ?LOGOUT},
- {'Auth-Application-Id', ?APP_ID}],
- {error, failover} = call(Req, [{filter, realm}]).
+ Req = #diameter_base_STR{'Destination-Realm' = realm(?SERVER4),
+ 'Termination-Cause' = ?LOGOUT,
+ 'Auth-Application-Id' = ?APP_ID},
+ {failover, ?LOGOUT} = call(?CLIENT1, Req).
+
+%% Send an STR and have prepare_retransmit discard it.
+send_discard_1(_Config) ->
+ Req = #diameter_base_STR{'Destination-Realm' = realm(?SERVER1),
+ 'Termination-Cause' = ?TIMEOUT,
+ 'Auth-Application-Id' = ?APP_ID},
+ {rejected, ?TIMEOUT} = call(?CLIENT2, Req).
+send_discard_2(_Config) ->
+ Req = #diameter_base_STR{'Destination-Realm' = realm(?SERVER4),
+ 'Termination-Cause' = ?MOVED,
+ 'Auth-Application-Id' = ?APP_ID},
+ {discarded, ?MOVED} = call(?CLIENT2, Req).
%% ===========================================================================
realm(Host) ->
tl(lists:dropwhile(fun(C) -> C /= $. end, Host)).
-call(Req, Opts) ->
- diameter:call(?CLIENT, ?APP_ALIAS, Req, Opts).
-
-set([H|T], Vs) ->
- [H | Vs ++ T].
+call(Svc, Req) ->
+ diameter:call(Svc, ?APP_ALIAS, Req, [{filter, realm}]).
%% ===========================================================================
%% diameter callbacks
@@ -184,7 +205,8 @@ set([H|T], Vs) ->
%% pick_peer/4
%% Choose a server other than SERVER3 or SERVER5 if possible.
-pick_peer(Peers, _, ?CLIENT, _State) ->
+pick_peer(Peers, _, Svc, _State)
+ when ?IS_CLIENT(Svc) ->
case lists:partition(fun({_, #diameter_caps{origin_host = {_, OH}}}) ->
OH /= ?SERVER3 andalso OH /= ?SERVER5
end,
@@ -198,20 +220,41 @@ pick_peer(Peers, _, ?CLIENT, _State) ->
%% prepare_request/3
-prepare_request(Pkt, ?CLIENT, {_Ref, Caps}) ->
+prepare_request(Pkt, Svc, {_Ref, Caps})
+ when ?IS_CLIENT(Svc) ->
{send, prepare(Pkt, Caps)}.
prepare(#diameter_packet{msg = Req}, Caps) ->
#diameter_caps{origin_host = {OH, _},
origin_realm = {OR, _}}
= Caps,
- set(Req, [{'Session-Id', diameter:session_id(OH)},
- {'Origin-Host', OH},
- {'Origin-Realm', OR}]).
+ Req#diameter_base_STR{'Origin-Host' = OH,
+ 'Origin-Realm' = OR,
+ 'Session-Id' = diameter:session_id(OH)}.
+
+%% prepare_retransmit/3
+
+prepare_retransmit(#diameter_packet{header = H} = P, Svc, {_,_})
+ when ?IS_CLIENT(Svc) ->
+ #diameter_header{is_retransmitted = true} = H, %% assert
+ prepare(P).
+
+prepare(#diameter_packet{msg = M} = P) ->
+ case M#diameter_base_STR.'Termination-Cause' of
+ ?LOGOUT -> {send, P};
+ ?MOVED -> discard;
+ ?TIMEOUT -> {discard, rejected}
+ end.
+
+%% handle_error/4
+
+handle_error(Reason, Req, _, _) ->
+ {Reason, Req#diameter_base_STR.'Termination-Cause'}.
%% handle_answer/4
-handle_answer(Pkt, _Req, ?CLIENT, _Peer) ->
+handle_answer(Pkt, _Req, Svc, _Peer)
+ when ?IS_CLIENT(Svc) ->
#diameter_packet{msg = Rec, errors = []} = Pkt,
Rec.
@@ -219,8 +262,8 @@ handle_answer(Pkt, _Req, ?CLIENT, _Peer) ->
%% Only SERVER3 actually answers.
handle_request(Pkt, ?SERVER3, {_, Caps}) ->
- #diameter_packet{msg = #diameter_base_STR{'Session-Id' = SId,
- 'Origin-Host' = ?CLIENT}}
+ #diameter_packet{header = #diameter_header{is_retransmitted = true},
+ msg = #diameter_base_STR{'Session-Id' = SId}}
= Pkt,
#diameter_caps{origin_host = {OH, _},
origin_realm = {OR, _}}
diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl
index 669918f757..b03a9ce4d1 100644
--- a/lib/diameter/test/diameter_traffic_SUITE.erl
+++ b/lib/diameter/test/diameter_traffic_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -38,6 +38,9 @@
result_codes/1,
send_ok/1,
send_nok/1,
+ send_eval/1,
+ send_bad_answer/1,
+ send_protocol_error/1,
send_arbitrary/1,
send_unknown/1,
send_unknown_mandatory/1,
@@ -46,6 +49,9 @@
send_unsupported_app/1,
send_error_bit/1,
send_unsupported_version/1,
+ send_invalid_avp_bits/1,
+ send_invalid_avp_length/1,
+ send_invalid_reject/1,
send_long/1,
send_nopeer/1,
send_noapp/1,
@@ -81,11 +87,11 @@
%% diameter callbacks
-export([peer_up/3,
peer_down/3,
- pick_peer/5, pick_peer/6,
- prepare_request/4, prepare_request/5,
- prepare_retransmit/4,
- handle_answer/5, handle_answer/6,
- handle_error/5,
+ pick_peer/6, pick_peer/7,
+ prepare_request/5, prepare_request/6,
+ prepare_retransmit/5,
+ handle_answer/6, handle_answer/7,
+ handle_error/6,
handle_request/3]).
-include("diameter.hrl").
@@ -108,14 +114,26 @@
-define(BASE, ?DIAMETER_DICT_COMMON).
-define(ACCT, ?DIAMETER_DICT_ACCOUNTING).
-%% Run tests cases in different encoding variants. Send outgoing
-%% messages as lists or records.
+%% Sequence mask for End-to-End and Hop-by-Hop identifiers.
+-define(CLIENT_MASK, {1,26}). %% 1 in top 6 bits
+
+%% How to construct messages, as record or list.
-define(ENCODINGS, [list, record]).
+%% How to send answers, in a diameter_packet or not.
+-define(CONTAINERS, [pkt, msg]).
+
+%% Send over multiple connections that are mapped onto
+%% [{E,P} || E <- ?ENCODINGS, P <- ?CONTAINERS].
+-define(CONNECTIONS, [c0,c1,c2,c3]).
+
%% Not really what we should be setting unless the message is sent in
%% the common application but diameter doesn't care.
-define(APP_ID, ?DIAMETER_APP_ID_COMMON).
+%% An Application-ID the server doesn't support.
+-define(BAD_APP, 42).
+
%% Config for diameter:start_service/2.
-define(SERVICE(Name),
[{'Origin-Host', Name ++ "." ++ ?REALM},
@@ -124,7 +142,8 @@
{'Vendor-Id', 12345},
{'Product-Name', "OTP/diameter"},
{'Auth-Application-Id', [?DIAMETER_APP_ID_COMMON]},
- {'Acct-Application-Id', [?DIAMETER_APP_ID_ACCOUNTING]}
+ {'Acct-Application-Id', [?DIAMETER_APP_ID_ACCOUNTING]},
+ {restrict_connections, false}
| [{application, [{dictionary, D},
{module, ?MODULE},
{answer_errors, callback}]}
@@ -150,6 +169,8 @@
?'DIAMETER_BASE_RESULT-CODE_DIAMETER_REALM_NOT_SERVED').
-define(UNABLE_TO_DELIVER,
?'DIAMETER_BASE_RESULT-CODE_DIAMETER_UNABLE_TO_DELIVER').
+-define(INVALID_AVP_LENGTH,
+ ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_INVALID_AVP_LENGTH').
-define(EVENT_RECORD,
?'DIAMETER_BASE_ACCOUNTING-RECORD-TYPE_EVENT_RECORD').
@@ -162,6 +183,8 @@
?'DIAMETER_BASE_TERMINATION-CAUSE_DIAMETER_LOGOUT').
-define(BAD_ANSWER,
?'DIAMETER_BASE_TERMINATION-CAUSE_DIAMETER_BAD_ANSWER').
+-define(USER_MOVED,
+ ?'DIAMETER_BASE_TERMINATION-CAUSE_DIAMETER_USER_MOVED').
-define(A, list_to_atom).
-define(L, atom_to_list).
@@ -175,12 +198,17 @@ suite() ->
all() ->
[start, start_services, add_transports, result_codes]
- ++ [{group, name([E]), P} || E <- ?ENCODINGS, P <- [[], [parallel]]]
+ ++ [{group, ?util:name([R,C,A]), P} || R <- ?ENCODINGS,
+ C <- ?CONTAINERS,
+ A <- ?ENCODINGS,
+ P <- [[], [parallel]]]
++ [remove_transports, stop_services, stop].
groups() ->
Ts = tc(),
- [{name([E]), [], Ts} || E <- ?ENCODINGS].
+ [{?util:name([R,C,A]), [], Ts} || R <- ?ENCODINGS,
+ C <- ?CONTAINERS,
+ A <- ?ENCODINGS].
init_per_group(Name, Config) ->
[{group, Name} | Config].
@@ -199,6 +227,9 @@ end_per_testcase(_, _) ->
tc() ->
[send_ok,
send_nok,
+ send_eval,
+ send_bad_answer,
+ send_protocol_error,
send_arbitrary,
send_unknown,
send_unknown_mandatory,
@@ -207,6 +238,9 @@ tc() ->
send_unsupported_app,
send_error_bit,
send_unsupported_version,
+ send_invalid_avp_bits,
+ send_invalid_avp_length,
+ send_invalid_reject,
send_long,
send_nopeer,
send_noapp,
@@ -244,16 +278,19 @@ start(_Config) ->
start_services(_Config) ->
ok = diameter:start_service(?SERVER, ?SERVICE(?SERVER)),
- ok = diameter:start_service(?CLIENT, ?SERVICE(?CLIENT)).
+ ok = diameter:start_service(?CLIENT, [{sequence, ?CLIENT_MASK}
+ | ?SERVICE(?CLIENT)]).
add_transports(Config) ->
LRef = ?util:listen(?SERVER, tcp, [{capabilities_cb, fun capx/2}]),
- CRef = ?util:connect(?CLIENT, tcp, LRef),
- ?util:write_priv(Config, "transport", {LRef, CRef}).
+ Cs = [?util:connect(?CLIENT, tcp, LRef, [{id, C},
+ {capabilities, [osi(C)]}])
+ || C <- ?CONNECTIONS],
+ ?util:write_priv(Config, "transport", [LRef | Cs]).
remove_transports(Config) ->
- {LRef, CRef} = ?util:read_priv(Config, "transport"),
- ?util:disconnect(?CLIENT, CRef, ?SERVER, LRef).
+ [LRef | Cs] = ?util:read_priv(Config, "transport"),
+ [?util:disconnect(?CLIENT, C, ?SERVER, LRef) || C <- Cs].
stop_services(_Config) ->
ok = diameter:stop_service(?CLIENT),
@@ -266,11 +303,15 @@ capx(_, #diameter_caps{origin_host = {OH,DH}}) ->
io:format("connection: ~p -> ~p~n", [DH,OH]),
ok.
+osi(Id) ->
+ [$c,N] = atom_to_list(Id),
+ {'Origin-State-Id', N - $0}.
+
%% ===========================================================================
%% Ensure that result codes have the expected values.
result_codes(_Config) ->
- {2001, 3001, 3002, 3003, 3004, 3007, 3008, 3009, 5001, 5011}
+ {2001, 3001, 3002, 3003, 3004, 3007, 3008, 3009, 5001, 5011, 5014}
= {?SUCCESS,
?COMMAND_UNSUPPORTED,
?UNABLE_TO_DELIVER,
@@ -280,13 +321,14 @@ result_codes(_Config) ->
?INVALID_HDR_BITS,
?INVALID_AVP_BITS,
?AVP_UNSUPPORTED,
- ?UNSUPPORTED_VERSION}.
+ ?UNSUPPORTED_VERSION,
+ ?INVALID_AVP_LENGTH}.
%% Send an ACR and expect success.
send_ok(Config) ->
Req = ['ACR', {'Accounting-Record-Type', ?EVENT_RECORD},
{'Accounting-Record-Number', 1}],
-
+
#diameter_base_accounting_ACA{'Result-Code' = ?SUCCESS}
= call(Config, Req).
@@ -294,10 +336,35 @@ send_ok(Config) ->
send_nok(Config) ->
Req = ['ACR', {'Accounting-Record-Type', ?EVENT_RECORD},
{'Accounting-Record-Number', 0}],
-
+
#'diameter_base_answer-message'{'Result-Code' = ?INVALID_AVP_BITS}
= call(Config, Req).
+%% Send an ACR and expect success.
+send_eval(Config) ->
+ Req = ['ACR', {'Accounting-Record-Type', ?EVENT_RECORD},
+ {'Accounting-Record-Number', 3}],
+
+ #diameter_base_accounting_ACA{'Result-Code' = ?SUCCESS}
+ = call(Config, Req).
+
+%% Send an accounting ACR that the server tries to answer with an
+%% inappropriate header, resulting in no answer being sent and the
+%% request timing out.
+send_bad_answer(Config) ->
+ Req = ['ACR', {'Accounting-Record-Type', ?EVENT_RECORD},
+ {'Accounting-Record-Number', 2}],
+ {error, timeout} = call(Config, Req).
+
+%% Send an ACR that the server callback answers explicitly with a
+%% protocol error.
+send_protocol_error(Config) ->
+ Req = ['ACR', {'Accounting-Record-Type', ?EVENT_RECORD},
+ {'Accounting-Record-Number', 4}],
+
+ #'diameter_base_answer-message'{'Result-Code' = ?TOO_BUSY}
+ = call(Config, Req).
+
%% Send an ASR with an arbitrary AVP and expect success and the same
%% AVP in the reply.
send_arbitrary(Config) ->
@@ -365,6 +432,29 @@ send_unsupported_version(Config) ->
#diameter_base_STA{'Result-Code' = ?UNSUPPORTED_VERSION}
= call(Config, Req).
+%% Send a request containing an incorrect AVP length.
+send_invalid_avp_bits(Config) ->
+ Req = ['STR', {'Termination-Cause', ?LOGOUT}],
+
+ #'diameter_base_answer-message'{'Result-Code' = ?INVALID_AVP_BITS}
+ = call(Config, Req).
+
+%% Send a request containing an AVP length that doesn't match the
+%% AVP's type.
+send_invalid_avp_length(Config) ->
+ Req = ['STR', {'Termination-Cause', ?LOGOUT}],
+
+ #'diameter_base_STA'{'Result-Code' = ?INVALID_AVP_LENGTH}
+ = call(Config, Req).
+
+%% Send a request containing 5xxx errors that the server rejects with
+%% 3xxx.
+send_invalid_reject(Config) ->
+ Req = ['STR', {'Termination-Cause', ?USER_MOVED}],
+
+ #'diameter_base_answer-message'{'Result-Code' = ?TOO_BUSY}
+ = call(Config, Req).
+
%% Send something long that will be fragmented by TCP.
send_long(Config) ->
Req = ['STR', {'Termination-Cause', ?LOGOUT},
@@ -539,21 +629,44 @@ call(Config, Req) ->
call(Config, Req, Opts) ->
Name = proplists:get_value(testcase, Config),
- [Enc] = name(proplists:get_value(group, Config)),
+ [Encoding, C, E] = ?util:name(proplists:get_value(group, Config)),
diameter:call(?CLIENT,
dict(Req),
- req(Req, Enc),
- [{extra, [Name]} | Opts]).
+ msg(Req, Encoding),
+ [{extra, [Name, client(E,C)]} | Opts]).
+
+client(E, C) ->
+ list_to_atom([$c, $0 + 2*codec(E) + container(C)]).
+
+client(N) ->
+ {codec(N bsr 1), container(N rem 2)}.
-req(['ACR' = H | T], record) ->
+codec(record) -> 0;
+codec(list) -> 1;
+codec(0) -> record;
+codec(1) -> list.
+
+%% Here we're just mapping booleans but the readable atoms are part of
+%% (constructed) group names, so it's good that they're readable.
+
+container(pkt) -> 0;
+container(msg) -> 1;
+container(0) -> pkt;
+container(1) -> msg.
+
+msg([H|T], record)
+ when H == 'ACR';
+ H == 'ACA' ->
?ACCT:'#new-'(?ACCT:msg2rec(H), T);
-req([H|T], record) ->
+msg([H|T], record) ->
?BASE:'#new-'(?BASE:msg2rec(H), T);
-req(T, _) ->
+msg(T, _) ->
T.
dict(['ACR' | _]) ->
?ACCT;
+dict(#diameter_base_accounting_ACR{}) ->
+ ?ACCT;
dict(_) ->
?BASE.
@@ -579,17 +692,6 @@ set(Dict, E, FV, Rec)
set(_, _, _, Rec) ->
Rec.
-%% Contruct and deconstruct names to work around group names being
-%% restricted to atoms. (Not really used yet.)
-
-name(Names)
- when is_list(Names) ->
- ?A(string:join([?L(A) || A <- Names], ","));
-
-name(A)
- when is_atom(A) ->
- [?A(S) || S <- string:tokens(?L(A), ",")].
-
%% ===========================================================================
%% diameter callbacks
@@ -603,28 +705,74 @@ peer_up(_SvcName, _Peer, State) ->
peer_down(_SvcName, _Peer, State) ->
State.
-%% pick_peer/5/6
+%% pick_peer/6-7
-pick_peer([Peer], _, ?CLIENT, _State, Name)
+pick_peer(Peers, _, ?CLIENT, _State, Name, Id)
when Name /= send_detach ->
- {ok, Peer}.
+ find(Id, Peers).
-pick_peer([_Peer], _, ?CLIENT, _State, send_nopeer, ?EXTRA) ->
+pick_peer(_Peers, _, ?CLIENT, _State, send_nopeer, _, ?EXTRA) ->
false;
-pick_peer([Peer], _, ?CLIENT, _State, send_detach, {_,_}) ->
- {ok, Peer}.
+pick_peer(Peers, _, ?CLIENT, _State, send_detach, Id, {_,_}) ->
+ find(Id, Peers).
+
+find(Id, Peers) ->
+ [P] = [P || P <- Peers, id(Id, P)],
+ {ok, P}.
+
+id(Id, {Pid, _Caps}) ->
+ [{ref, _}, {type, _}, {options, Opts} | _]
+ = diameter:service_info(?CLIENT, Pid),
+ lists:member({id, Id}, Opts).
-%% prepare_request/4/5
+%% prepare_request/5-6
-prepare_request(_Pkt, ?CLIENT, {_Ref, _Caps}, send_discard) ->
+prepare_request(_Pkt, ?CLIENT, {_Ref, _Caps}, send_discard, _) ->
{discard, unprepared};
-prepare_request(Pkt, ?CLIENT, {_Ref, Caps}, Name) ->
+prepare_request(Pkt, ?CLIENT, {_Ref, Caps}, Name, _) ->
{send, prepare(Pkt, Caps, Name)}.
-prepare_request(Pkt, ?CLIENT, {_Ref, Caps}, send_detach, _) ->
- {send, prepare(Pkt, Caps)}.
+prepare_request(Pkt, ?CLIENT, {_Ref, Caps}, send_detach, _, _) ->
+ {eval_packet, {send, prepare(Pkt, Caps)}, [fun log/2, detach]}.
+
+log(#diameter_packet{} = P, T) ->
+ io:format("~p: ~p~n", [T,P]).
+
+%% prepare/3
+
+prepare(Pkt, Caps, send_invalid_avp_bits) ->
+ Req = prepare(Pkt, Caps),
+ %% Last AVP in our STR is Termination-Cause of type Unsigned32:
+ %% set its length improperly.
+ #diameter_packet{header = #diameter_header{length = L},
+ bin = B}
+ = E
+ = diameter_codec:encode(?BASE, Pkt#diameter_packet{msg = Req}),
+ Offset = L - 7, %% to AVP Length
+ <<H:Offset/binary, 12:24/integer, T:4/binary>> = B,
+ E#diameter_packet{bin = <<H/binary, 13:24/integer, T/binary>>};
+
+prepare(Pkt, Caps, N)
+ when N == send_invalid_avp_length;
+ N == send_invalid_reject ->
+ Req = prepare(Pkt, Caps),
+ %% Second last AVP in our STR is Auth-Application-Id of type
+ %% Unsigned32: Send a value of length 8.
+ #diameter_packet{header = #diameter_header{length = L},
+ bin = B0}
+ = E
+ = diameter_codec:encode(?BASE, Pkt#diameter_packet{msg = Req}),
+ Offset = L - 7 - 12, %% to AVP Length
+ <<H0:Offset/binary, 12:24/integer, T:16/binary>> = B0,
+ <<V, L:24/integer, H/binary>> = H0, %% assert
+ E#diameter_packet{bin = <<V,
+ (L+4):24/integer,
+ H/binary,
+ 16:24/integer,
+ 0:32/integer,
+ T/binary>>};
prepare(Pkt, Caps, send_unsupported) ->
Req = prepare(Pkt, Caps),
@@ -638,7 +786,7 @@ prepare(Pkt, Caps, send_unsupported_app) ->
#diameter_packet{bin = <<H:8/binary, _ApplId:4/binary, T/binary>>}
= E
= diameter_codec:encode(?BASE, Pkt#diameter_packet{msg = Req}),
- E#diameter_packet{bin = <<H/binary, 42:32/integer, T/binary>>};
+ E#diameter_packet{bin = <<H/binary, ?BAD_APP:32/integer, T/binary>>};
prepare(Pkt, Caps, send_error_bit) ->
#diameter_packet{header = Hdr} = Pkt,
@@ -657,6 +805,8 @@ prepare(Pkt, Caps, send_anything) ->
prepare(Pkt, Caps, _Name) ->
prepare(Pkt, Caps).
+%% prepare/2
+
prepare(#diameter_packet{msg = Req}, Caps)
when is_record(Req, diameter_base_accounting_ACR);
'ACR' == hd(Req) ->
@@ -707,25 +857,42 @@ prepare(#diameter_packet{msg = Req}, Caps)
{'Destination-Realm', DR},
{'Auth-Application-Id', ?APP_ID}]).
-%% prepare_retransmit/4
+%% prepare_retransmit/5
-prepare_retransmit(_Pkt, false, _Peer, _Name) ->
+prepare_retransmit(_Pkt, false, _Peer, _Name, _Id) ->
discard.
-%% handle_answer/5/6
+%% handle_answer/6-7
-handle_answer(Pkt, Req, ?CLIENT, Peer, Name) ->
+handle_answer(Pkt, Req, ?CLIENT, Peer, Name, _Id) ->
answer(Pkt, Req, Peer, Name).
-handle_answer(Pkt, _Req, ?CLIENT, _Peer, send_detach, {Pid, Ref}) ->
+handle_answer(Pkt, _Req, ?CLIENT, _Peer, send_detach, _Id, {Pid, Ref}) ->
Pid ! {Ref, Pkt}.
-answer(#diameter_packet{msg = Rec, errors = []}, _Req, _Peer, _) ->
+answer(Pkt, Req, _Peer, Name) ->
+ #diameter_packet{header = H, msg = Rec, errors = Es} = Pkt,
+ ApplId = app(Req, Name),
+ #diameter_header{application_id = ApplId} = H, %% assert
+ answer(Rec, Es, Name).
+
+answer(Rec, [_|_], N)
+ when N == send_invalid_avp_bits;
+ N == send_invalid_avp_length;
+ N == send_invalid_reject ->
+ Rec;
+answer(Rec, [], _) ->
Rec.
-%% handle_error/5
+app(_, send_unsupported_app) ->
+ ?BAD_APP;
+app(Req, _) ->
+ Dict = dict(Req),
+ Dict:id().
+
+%% handle_error/6
-handle_error(Reason, _Req, ?CLIENT, _Peer, _Name) ->
+handle_error(Reason, _Req, ?CLIENT, _Peer, _Name, _Id) ->
{error, Reason}.
%% handle_request/3
@@ -733,16 +900,64 @@ handle_error(Reason, _Req, ?CLIENT, _Peer, _Name) ->
%% Note that diameter will set Result-Code and Failed-AVPs if
%% #diameter_packet.errors is non-null.
-handle_request(#diameter_packet{msg = M}, ?SERVER, {_Ref, Caps}) ->
- request(M, Caps).
+handle_request(#diameter_packet{header = H, msg = M}, ?SERVER, {_Ref, Caps}) ->
+ #diameter_header{end_to_end_id = EI,
+ hop_by_hop_id = HI}
+ = H,
+ {V,B} = ?CLIENT_MASK,
+ V = EI bsr B, %% assert
+ V = HI bsr B, %%
+ #diameter_caps{origin_state_id = {_,[N]}} = Caps,
+ answer(client(N), request(M, Caps)).
+
+answer(T, {Tag, Action, Post}) ->
+ {Tag, answer(T, Action), Post};
+answer({E,C}, {reply, Ans}) ->
+ answer(C, {reply, msg(Ans, E)});
+answer(pkt, {reply, Ans}) ->
+ {reply, #diameter_packet{msg = Ans}};
+answer(_, T) ->
+ T.
+%% send_nok
request(#diameter_base_accounting_ACR{'Accounting-Record-Number' = 0},
_) ->
- {protocol_error, ?INVALID_AVP_BITS};
+ {eval_packet, {protocol_error, ?INVALID_AVP_BITS}, [fun log/2, invalid]};
+%% send_bad_answer
request(#diameter_base_accounting_ACR{'Session-Id' = SId,
'Accounting-Record-Type' = RT,
- 'Accounting-Record-Number' = RN},
+ 'Accounting-Record-Number' = 2 = RN},
+ #diameter_caps{origin_host = {OH, _},
+ origin_realm = {OR, _}}) ->
+ Ans = ['ACA', {'Result-Code', ?SUCCESS},
+ {'Session-Id', SId},
+ {'Origin-Host', OH},
+ {'Origin-Realm', OR},
+ {'Accounting-Record-Type', RT},
+ {'Accounting-Record-Number', RN}],
+
+ {reply, #diameter_packet{header = #diameter_header{is_error = true},%% NOT
+ msg = Ans}};
+
+%% send_eval
+request(#diameter_base_accounting_ACR{'Session-Id' = SId,
+ 'Accounting-Record-Type' = RT,
+ 'Accounting-Record-Number' = 3 = RN},
+ #diameter_caps{origin_host = {OH, _},
+ origin_realm = {OR, _}}) ->
+ Ans = ['ACA', {'Result-Code', ?SUCCESS},
+ {'Session-Id', SId},
+ {'Origin-Host', OH},
+ {'Origin-Realm', OR},
+ {'Accounting-Record-Type', RT},
+ {'Accounting-Record-Number', RN}],
+ {eval, {reply, Ans}, {erlang, now, []}};
+
+%% send_ok
+request(#diameter_base_accounting_ACR{'Session-Id' = SId,
+ 'Accounting-Record-Type' = RT,
+ 'Accounting-Record-Number' = 1 = RN},
#diameter_caps{origin_host = {OH, _},
origin_realm = {OR, _}}) ->
{reply, ['ACA', {'Result-Code', ?SUCCESS},
@@ -752,26 +967,42 @@ request(#diameter_base_accounting_ACR{'Session-Id' = SId,
{'Accounting-Record-Type', RT},
{'Accounting-Record-Number', RN}]};
+%% send_protocol_error
+request(#diameter_base_accounting_ACR{'Accounting-Record-Number' = 4},
+ #diameter_caps{origin_host = {OH, _},
+ origin_realm = {OR, _}}) ->
+ Ans = ['answer-message', {'Result-Code', ?TOO_BUSY},
+ {'Origin-Host', OH},
+ {'Origin-Realm', OR}],
+ {reply, Ans};
+
request(#diameter_base_ASR{'Session-Id' = SId,
'AVP' = Avps},
#diameter_caps{origin_host = {OH, _},
origin_realm = {OR, _}}) ->
- {reply, #diameter_base_ASA{'Result-Code' = ?SUCCESS,
- 'Session-Id' = SId,
- 'Origin-Host' = OH,
- 'Origin-Realm' = OR,
- 'AVP' = Avps}};
+ {reply, ['ASA', {'Result-Code', ?SUCCESS},
+ {'Session-Id', SId},
+ {'Origin-Host', OH},
+ {'Origin-Realm', OR},
+ {'AVP', Avps}]};
+
+%% send_invalid_reject
+request(#diameter_base_STR{'Termination-Cause' = ?USER_MOVED}, _Caps) ->
+ {protocol_error, ?TOO_BUSY};
+%% send_noreply
request(#diameter_base_STR{'Termination-Cause' = T},
_Caps)
when T /= ?LOGOUT ->
discard;
+%% send_destination_5
request(#diameter_base_STR{'Destination-Realm'= R},
#diameter_caps{origin_realm = {OR, _}})
when R /= undefined, R /= OR ->
{protocol_error, ?REALM_NOT_SERVED};
+%% send_destination_6
request(#diameter_base_STR{'Destination-Host'= [H]},
#diameter_caps{origin_host = {OH, _}})
when H /= OH ->
@@ -780,11 +1011,12 @@ request(#diameter_base_STR{'Destination-Host'= [H]},
request(#diameter_base_STR{'Session-Id' = SId},
#diameter_caps{origin_host = {OH, _},
origin_realm = {OR, _}}) ->
- {reply, #diameter_base_STA{'Result-Code' = ?SUCCESS,
- 'Session-Id' = SId,
- 'Origin-Host' = OH,
- 'Origin-Realm' = OR}};
+ {reply, ['STA', {'Result-Code', ?SUCCESS},
+ {'Session-Id', SId},
+ {'Origin-Host', OH},
+ {'Origin-Realm', OR}]};
+%% send_error
request(#diameter_base_RAR{}, _Caps) ->
receive after 2000 -> ok end,
{protocol_error, ?TOO_BUSY}.
diff --git a/lib/diameter/test/diameter_util.erl b/lib/diameter/test/diameter_util.erl
index 890d24f6f8..5af4ad9ba5 100644
--- a/lib/diameter/test/diameter_util.erl
+++ b/lib/diameter/test/diameter_util.erl
@@ -24,7 +24,8 @@
%%
%% generic
--export([consult/2,
+-export([name/1,
+ consult/2,
run/1,
fold/3,
foldl/3,
@@ -45,6 +46,21 @@
-define(L, atom_to_list).
+
+%% ---------------------------------------------------------------------------
+%% name/2
+%%
+%% Contruct and deconstruct lists of atoms as atoms to work around
+%% group names in common_test being restricted to atoms.
+
+name(Names)
+ when is_list(Names) ->
+ list_to_atom(string:join([atom_to_list(A) || A <- Names], ","));
+
+name(A)
+ when is_atom(A) ->
+ [list_to_atom(S) || S <- string:tokens(atom_to_list(A), ",")].
+
%% ---------------------------------------------------------------------------
%% consult/2
%%
diff --git a/lib/diameter/test/diameter_watchdog_SUITE.erl b/lib/diameter/test/diameter_watchdog_SUITE.erl
index ff40326947..7ce09e93ca 100644
--- a/lib/diameter/test/diameter_watchdog_SUITE.erl
+++ b/lib/diameter/test/diameter_watchdog_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -30,11 +30,21 @@
end_per_suite/1]).
%% testcases
--export([reopen/1, reopen/4]).
+-export([reopen/1, reopen/4, reopen/7]).
--export([start/3, %% diameter_transport callback
- id/1, %% jitter callback
- run/1]).
+-export([id/1, %% jitter callback
+ run1/1]).
+
+%% diameter_app callbacks
+-export([peer_up/3,
+ peer_down/3]).
+
+%% gen_tcp-ish interface
+-export([listen/2,
+ accept/1,
+ connect/3,
+ send/2,
+ setopts/2]).
-include("diameter.hrl").
-include("diameter_ct.hrl").
@@ -43,33 +53,21 @@
-define(util, diameter_util).
--define(BASE, diameter_gen_base_rfc3588).
--define(APPL_ID, diameter_gen_base_rfc3588:id()).
--define(SUCCESS, 2001). %% DIAMETER_SUCCESS
-
-%% Addresses for the local and remote diameter nodes. The values don't
-%% matter since we're faking transport.
--define(LOCALHOST, {127,0,0,1}).
--define(REMOTEHOST, {10,0,0,1}).
-
--define(CAPS, #diameter_caps{origin_host = "node.innan.com",
- origin_realm = "innan.com",
- host_ip_address = [?LOCALHOST],
- vendor_id = 1022,
- product_name = "remote",
- auth_application_id = [?APPL_ID]}).
-
--define(APPL, #diameter_app{alias = ?MODULE,
- dictionary = ?BASE,
- module = [?MODULE],
- init_state = now(),
- id = ?APPL_ID,
- mutable = false}).
-
-%% Service record maintained by our faked service process.
--define(SERVICE, #diameter_service{pid = self(),
- capabilities = ?CAPS,
- applications = [?APPL]}).
+-define(BASE, ?DIAMETER_DICT_COMMON).
+-define(REALM, "erlang.org").
+-define(ADDR, {127,0,0,1}).
+
+%% Config for diameter:start_service/2.
+-define(SERVICE(Name),
+ [{'Origin-Host', Name ++ "." ++ ?REALM},
+ {'Origin-Realm', ?REALM},
+ {'Host-IP-Address', [?ADDR]},
+ {'Vendor-Id', 42},
+ {'Product-Name', "OTP/diameter"},
+ {'Auth-Application-Id', [?DIAMETER_APP_ID_COMMON]},
+ {application, [{alias, Name},
+ {dictionary, ?BASE},
+ {module, ?MODULE}]}]).
%% Watchdog timer as a callback.
-define(WD(T), {?MODULE, id, [T]}).
@@ -82,28 +80,28 @@
F_ <- [fun(T__) -> T__ end,
fun(T__) -> ?WD(T__) end]]]).
-%% Transport types.
--define(TRANSPORTS, [connect, accept]).
+%% Watchdog timer of the misbehaving peer.
+-define(PEER_WD, 10000).
-%% Message over the transport interface.
--define(TMSG(T), {diameter, T}).
-
-%% Receive a message within a specified time.
--define(RECV(T, Timeout),
- receive T -> now()
- after Timeout -> ?ERROR({timeout, Timeout})
+%% Receive a watchdog event within a specified time.
+-define(EVENT(T, Tmo),
+ receive #diameter_event{info = T} -> now()
+ after Tmo -> ?ERROR({timeout, Tmo})
end).
-%% Receive a message in a given number of watchdogs, plus or minus
+%% Receive an event in a given number of watchdogs, plus or minus
%% half. Note that the call to now_diff assumes left to right
%% evaluation order.
--define(RECV(T, N, WdL, WdH),
+-define(EVENT(T, N, WdL, WdH),
[?ERROR({received, _Elapsed_, _LowerBound_, N, WdL})
|| _UpperBound_ <- [(N)*(WdH) + (WdH) div 2],
- _Elapsed_ <- [now_diff(now(), ?RECV(T, _UpperBound_))],
+ _Elapsed_ <- [now_diff(now(), ?EVENT(T, _UpperBound_))],
_LowerBound_ <- [(N)*(WdL) - (WdL) div 2],
_Elapsed_ =< _LowerBound_*1000]).
+-define(EVENT(T, N, Wd),
+ ?EVENT(T, N, Wd, Wd)).
+
%% A timeout that ensures one watchdog. The ensure only one watchdog
%% requires (Wd + 2000) + 1000 < 2*(Wd - 2000) ==> 7000 < Wd for the
%% case with random jitter.
@@ -112,7 +110,7 @@
%% ===========================================================================
suite() ->
- [{timetrap, {minutes, 6}}].%% enough for 11 watchdogs @ 30 sec plus jitter
+ [{timetrap, {minutes, 10}}].%% enough for 17 watchdogs @ 30 sec plus jitter
all() ->
[reopen].
@@ -134,52 +132,97 @@ end_per_suite(_Config) ->
%% implement a transport process that plays the role of the peer
%% Diameter node.
+%reopen(_) ->
+% reopen(connect, ?WD(10000), 1, 'DWR');
+
reopen(_) ->
- [] = ?util:run([{?MODULE, [run, [reopen, Wd, T, N, M]]}
- || Wd <- ?WD_TIMERS,
- T <- ?TRANSPORTS,
- N <- [0,1,2],
- M <- ['DWR', 'DWA', other]]).
+ [] = run([[reopen, T, Wd, N, M]
+ || Wd <- ?WD_TIMERS, %% watchdog_timer value
+ T <- [listen, connect], %% watchdog to test
+ N <- [0,1,2], %% DWR's to answer before ignoring
+ M <- ['DWR', 'DWA', 'RAA']]). %% how to induce failback
-reopen(Wd, Type, N, What) ->
- Ref = make_ref(),
+reopen(Type, Wd, N, M) ->
+ Server = start_service(),
+ Client = start_service(),
- %% The maker of transport processes.
- TPid = start({N, Wd, What, Ref}),
+ %% The peer to the transport whose watchdog is tested is given a
+ %% long watchdog timeout so that it doesn't send DWR of its own.
+ {Node, Peer} = {{[], Wd}, {[{module, ?MODULE}], ?WD(?PEER_WD)}},
- %% Act like diameter_service and start the watchdog process, which
- %% in turn starts a peer_fsm process, which in turn starts a
- %% transport process by way of start/3. Messages received by the
- %% testcase are those sent by diameter_watchdog to the service
- %% process (= process starting the watchdog).
- WPid1 = watchdog(Type, Ref, TPid, Wd),
+ {{LH,LW},{CH,CW}} = case Type of
+ listen -> {Node, Peer};
+ connect -> {Peer, Node}
+ end,
- %% Low/high watchdog timeouts.
- WdL = jitter(Wd, -2000),
- WdH = jitter(Wd, 2000),
+ LO = [{transport_module, diameter_tcp},
+ {transport_config, LH ++ [{ip, ?ADDR}, {port, 0}]},
+ {watchdog_timer, LW}],
+
+ {ok, LRef} = diameter:add_transport(Server, {listen, LO}),
+
+ [LP] = ?util:lport(tcp, LRef, 20),
+
+ CO = [{transport_module, diameter_tcp},
+ {transport_config, CH ++ [{ip, ?ADDR}, {port, 0},
+ {raddr, ?ADDR}, {rport, LP}]},
+ {watchdog_timer, CW}],
+
+ %% Use a temporary process to ensure the connecting transport is
+ %% added only once events from the listening transport are
+ %% subscribed to.
+ Pid = spawn(fun() -> receive _ -> ok end end),
+
+ [] = run([[reopen, Type, T, LRef, Pid, Wd, N, M]
+ || T <- [{listen, Server}, {connect, Client, CO}]]).
+
+%% start_service/1
+
+start_service() ->
+ Name = hostname(),
+ ok = diameter:start_service(Name, [{monitor, self()} | ?SERVICE(Name)]),
+ Name.
+
+%% reopen/7
+reopen(Type, {listen = T, SvcName}, Ref, Pid, Wd, N, M) ->
+ diameter:subscribe(SvcName),
+ Pid ! ok,
+ recv(Type, T, SvcName, Ref, Wd, N, M);
+
+reopen(Type, {connect = T, SvcName, Opts}, _, Pid, Wd, N, M) ->
+ diameter:subscribe(SvcName),
+ MRef = erlang:monitor(process, Pid),
+ receive {'DOWN', MRef, process, _, _} -> ok end,
+ {ok, Ref} = diameter:add_transport(SvcName, {T, Opts}),
+ recv(Type, T, SvcName, Ref, Wd, N, M).
+
+%% recv/7
+
+%% The watchdog to be tested.
+recv(Type, Type, _SvcName, Ref, Wd, N, M) ->
%% Connection should come up immediately as a consequence of
%% starting the watchdog process. In the accepting case this
%% results in a new watchdog on a transport waiting for a new
%% connection.
- ?RECV({connection_up, WPid1, _}, 1000),
- WPid2 = case Type of
- connect ->
- WPid1;
- accept ->
- watchdog(Type, Ref, TPid, Wd)
- end,
+ ?EVENT({watchdog, Ref, _, {initial, okay}, _}, 2000),
+ ?EVENT({up, Ref, _, _, #diameter_packet{}}, 0),
+
+ %% Low/high watchdog timeouts.
+ WdL = jitter(Wd, -2000),
+ WdH = jitter(Wd, 2000),
%% OKAY Timer expires & Failover()
%% Pending SetWatchdog() SUSPECT
%%
- %% Since our transport is replying to N DWR's before becoming
- %% silent, we should go down after N+2 watchdog_timer expirations:
- %% that is, after the first unanswered DWR. Knowing the min/max
- %% watchdog timeout values gives the time interval in which the
- %% down message is expected.
- ?RECV({connection_down, WPid1}, N+2, WdL, WdH),
+ %% The peer replies to N DWR's before becoming silent, we should
+ %% go down after N+2 watchdog_timer expirations: that is, after
+ %% the first unanswered DWR. Knowing the min/max watchdog timeout
+ %% values gives the time interval in which the event is expected.
+
+ ?EVENT({watchdog, Ref, _, {okay, suspect}, _}, N+2, WdL, WdH),
+ ?EVENT({down, Ref, _, _}, 0),
%% SUSPECT Receive DWA Pending = FALSE
%% Failback()
@@ -188,9 +231,11 @@ reopen(Wd, Type, N, What) ->
%% SUSPECT Receive non-DWA Failback()
%% SetWatchdog() OKAY
%%
- %% The transport receives a message before the expiry of another
- %% watchdog to induce failback.
- ?RECV({connection_up, WPid1}, WdH),
+ %% The peer sends a message before the expiry of another watchdog
+ %% to induce failback.
+
+ ?EVENT({watchdog, Ref, _, {suspect, okay}, _}, WdH + 2000),
+ ?EVENT({up, Ref, _, _}, 0),
%% OKAY Timer expires & SendWatchdog()
%% !Pending SetWatchdog()
@@ -199,30 +244,35 @@ reopen(Wd, Type, N, What) ->
%% OKAY Timer expires & Failover()
%% Pending SetWatchdog() SUSPECT
%%
- %% The transport is still not responding to watchdogs so the
- %% connection should go back down after either one or two watchdog
- %% expiries, depending on whether or not DWA restored the connection.
- F = choose(What == 'DWA', 2, 1),
- ?RECV({connection_down, WPid1}, F, WdL, WdH),
+ %% The peer is now ignoring all watchdogs so the connection goes
+ %% back down after either one or two watchdog expiries, depending
+ %% on whether or not DWA restored the connection.
+
+ F = choose(M == 'DWA', 2, 1),
+ ?EVENT({watchdog, Ref, _, {okay, suspect}, _}, F, WdL, WdH),
+ ?EVENT({down, Ref, _, _}, 0),
%% SUSPECT Timer expires CloseConnection()
%% SetWatchdog() DOWN
%%
+ %% Non-response brings the connection down after another timeout.
+
+ ?EVENT({watchdog, Ref, _, {suspect, down}, _}, 1, WdL, WdH),
+
%% DOWN Timer expires AttemptOpen()
%% SetWatchdog() DOWN
%%
- %% Our transport tells us when the fake connection is
- %% reestablished, which should happen after another couple of
- %% watchdog expiries, the first bringing the watchdog to state
- %% DOWN, the second triggering an attempt to reopen the
- %% connection.
- ?RECV({reopen, Ref}, 2, WdL, WdH),
-
%% DOWN Connection up NumDWA = 0
%% SendWatchdog()
%% SetWatchdog()
%% Pending = TRUE REOPEN
%%
+ %% The connection is reestablished after another timeout.
+
+ recv_reopen(Type, Ref, WdL, WdH),
+
+ %% REOPEN Receive non-DWA Throwaway() REOPEN
+ %%
%% REOPEN Receive DWA & Pending = FALSE
%% NumDWA < 2 NumDWA++ REOPEN
%%
@@ -230,312 +280,259 @@ reopen(Wd, Type, N, What) ->
%% NumDWA == 2 NumDWA++
%% Failback() OKAY
%%
- %% Now the watchdog should require three received DWA's before
- %% taking the connection back up. The first DWR is sent directly
- %% after capabilities exchange so it should take no more than two
- %% watchdog expiries.
- ?RECV({connection_up, WPid2, _}, 2, WdL, WdH).
+ %% REOPEN Timer expires & SendWatchdog()
+ %% !Pending SetWatchdog()
+ %% Pending = TRUE REOPEN
+ %%
+ %% An exchange of 3 watchdogs (the first directly after
+ %% capabilities exchange) brings the connection back up.
-%% ===========================================================================
+ ?EVENT({watchdog, Ref, _, {reopen, okay}, _}, 2, WdL, WdH),
+ ?EVENT({up, Ref, _, _, #diameter_packet{}}, 0),
-%% Start the fake transport process. From diameter's point of view
-%% it's started when diameter calls start/3. We start it before this
-%% happens since we use the same fake transport each time diameter
-%% calls start/3. The process lives and dies with the test case.
-start(Config) ->
- Pid = self(),
- spawn(fun() -> loop(init(Pid, Config)) end).
-
-%% Transport start from diameter. This may be called multiple times
-%% depending on the testcase.
-start({Type, _Ref}, #diameter_service{}, Pid) ->
- Ref = make_ref(),
- MRef = erlang:monitor(process, Pid),
- Pid ! {start, self(), Type, Ref},
- {Ref, TPid} = receive
- {Ref, _} = T ->
- T;
- {'DOWN', MRef, process, _, _} = T ->
- T
- end,
- erlang:demonitor(MRef, [flush]),
- {ok, TPid}.
+ %% Non-response brings it down again.
-%% id/1
+ ?EVENT({watchdog, Ref, _, {okay, suspect}, _}, 2, WdL, WdH),
+ ?EVENT({down, Ref, _, _}, 0),
+ ?EVENT({watchdog, Ref, _, {suspect, down}, _}, 1, WdL, WdH),
-id(T) ->
- T.
+ %% Reestablish after another watchdog.
-%% ===========================================================================
+ recv_reopen(Type, Ref, WdL, WdH),
-choose(true, X, _) -> X;
-choose(false, _, X) -> X.
+ %% REOPEN Timer expires & NumDWA = -1
+ %% Pending & SetWatchdog()
+ %% NumDWA >= 0 REOPEN
+ %%
+ %% REOPEN Timer expires & CloseConnection()
+ %% Pending & SetWatchdog()
+ %% NumDWA < 0 DOWN
+ %%
+ %% Peer is now ignoring all watchdogs go down again after 2
+ %% timeouts.
-%% run/1
-%%
-%% A more useful badmatch in case of failure.
+ ?EVENT({watchdog, Ref, _, {reopen, down}, _}, 2, WdL, WdH);
-run([F|A]) ->
- ok = try
- apply(?MODULE, F, A),
- ok
- catch
- E:R ->
- {A, E, R, erlang:get_stacktrace()}
- end.
+%% The misbehaving peer.
+recv(_, Type, SvcName, Ref, Wd, N, M) ->
+ %% First transport process.
+ ?EVENT({watchdog, Ref, _, {initial, okay}, _}, 1000),
+ ?EVENT({up, Ref, _, _, #diameter_packet{}}, 0),
+ reg(Type, Ref, SvcName, {SvcName, {Wd,N,M}}),
+ ?EVENT({watchdog, Ref, _, {okay, down}, _}, infinity),
-%% now_diff/2
+ %% Second transport process.
+ ?EVENT({watchdog, Ref, _, {_, reopen}, _}, infinity),
+ reg(Type, Ref, SvcName, 3),
+ ?EVENT({watchdog, Ref, _, {_, down}, _}, infinity),
-now_diff(T1, T2) ->
- timer:now_diff(T2, T1).
+ %% Third transport process.
+ ?EVENT({watchdog, Ref, _, {_, reopen}, _}, infinity),
+ reg(Type, Ref, SvcName, 0),
+ ?EVENT({watchdog, Ref, _, {_, down}, _}, infinity),
-%% jitter/2
+ ok.
-jitter(?WD(T), _) ->
- T;
-jitter(T,D) ->
- T+D.
+%% recv_reopen/4
-%% watchdog/4
-%%
-%% Fake the call from diameter_service. The watchdog process will send
-%% messages to the calling "service" process so our tests are that the
-%% watchdog responds as expected.
-
-watchdog(Type, Ref, TPid, Wd) ->
- Opts = [{transport_module, ?MODULE},
- {transport_config, TPid},
- {watchdog_timer, Wd}],
- {_MRef, Pid} = diameter_watchdog:start({Type, Ref},
- {false, Opts, false, ?SERVICE}),
- Pid.
+recv_reopen(connect, Ref, WdL, WdH) ->
+ ?EVENT({watchdog, Ref, _, {_, reopen}, _}, 1, WdL, WdH),
+ ?EVENT({reconnect, Ref, _}, 0);
-%% ===========================================================================
+recv_reopen(listen, Ref, _, _) ->
+ ?EVENT({watchdog, Ref, _, {_, reopen}, _}, 1, ?PEER_WD).
-%% Transport process implmentation. Fakes reception of messages by
-%% sending fakes to the parent (peer fsm) process that called start/3.
-
--record(transport,
- {type, %% connect | accept | manager
- parent, %% pid() of peer_fsm/ervice process
- open = false, %% done with capabilities exchange?
- config}).%% testcase-specific config
-
-%% init/2
-
-%% Testcase starting the manager.
-init(SvcPid, {_,_,_,_} = Config) ->
- putr(peer, [{'Origin-Host', hostname() ++ ".utan.com"},
- {'Origin-Realm', "utan.com"}]),
- #transport{type = manager,
- parent = monitor(SvcPid),
- config = Config};
-
-%% Manager starting a transport.
-init(_, {Type, ParentPid, SvcPid, TwinPid, Peer, {N,_,_,_} = Config}) ->
- putr(peer, Peer),
- putr(service, SvcPid),
- putr(count, init(Type, ParentPid, TwinPid, N)),%% number of DWR's to answer
- #transport{type = Type,
- parent = monitor(ParentPid),
- config = Config}.
-
-init(Type, ParentPid, undefined, N) ->
- connected(ParentPid, Type),
- N;
-init(_, _, TPid, _) ->
- monitor(TPid),
- 3.
-
-monitor(Pid) ->
- erlang:monitor(process, Pid),
- Pid.
+%% reg/4
+%%
+%% Lookup the pid of the transport process and publish a term for
+%% send/2 to lookup.
+reg(Type, Ref, SvcName, T) ->
+ TPid = tpid(Type, Ref, diameter:service_info(SvcName, transport)),
+ true = diameter_reg:add_new({?MODULE, TPid, T}).
+
+%% tpid/3
+
+tpid(connect, Ref, [[{ref, Ref},
+ {type, connect},
+ {options, _},
+ {watchdog, _},
+ {peer, _},
+ {apps, _},
+ {caps, _},
+ {port, [{owner, TPid} | _]}
+ | _]]) ->
+ TPid;
+
+tpid(listen, Ref, [[{ref, Ref},
+ {type, listen},
+ {options, _},
+ {accept, As}
+ | _]]) ->
+ [[{watchdog, _},
+ {peer, _},
+ {apps, _},
+ {caps, _},
+ {port, [{owner, TPid} | _]}
+ | _]]
+ = lists:filter(fun([{watchdog, {_,_,S}} | _]) ->
+ S == okay orelse S == reopen
+ end,
+ As),
+ TPid.
-%% Generate a unique hostname for the faked peer.
-hostname() ->
- lists:flatten(io_lib:format("~p-~p-~p", tuple_to_list(now()))).
+%% ===========================================================================
-%% loop/1
-
-loop(S) ->
- loop(msg(receive T -> T end, S)).
-
-msg(T,S) ->
- case transition(T,S) of
- ok ->
- S;
- #transport{} = NS ->
- NS;
- {stop, Reason} ->
- x(Reason)
- end.
-
-x(Reason) ->
- exit(Reason).
-
-%% transition/2
-
-%% Manager is being asked for a new transport process.
-transition({start, Pid, Type, Ref}, #transport{type = manager,
- parent = SvcPid,
- config = Config}) ->
- TPid = start({Type, Pid, SvcPid, getr(transport), getr(peer), Config}),
- Pid ! {Ref, TPid},
- putr(transport, TPid),
+listen(PortNr, Opts) ->
+ gen_tcp:listen(PortNr, Opts).
+
+accept(LSock) ->
+ gen_tcp:accept(LSock).
+
+connect(Addr, Port, Opts) ->
+ gen_tcp:connect(Addr, Port, Opts).
+
+setopts(Sock, Opts) ->
+ inet:setopts(Sock, Opts).
+
+send(Sock, Bin) ->
+ send(getr(config), Sock, Bin).
+
+%% send/3
+
+%% First outgoing message from a new transport process is CER/CEA.
+%% Remaining outgoing messages are either DWR or DWA.
+send(undefined, Sock, Bin) ->
+ putr(config, init),
+ gen_tcp:send(Sock, Bin);
+
+%% Outgoing DWR: fake reception of DWA. Use the fact that AVP values
+%% are ignored. This is to ensure that the peer's watchdog state
+%% transitions are only induced by responses to messages it sends.
+send(_, Sock, <<_:32, 1:1, _:7, 280:24, _:32, EId:32, HId:32, _/binary>>) ->
+ Pkt = #diameter_packet{header = #diameter_header{version = 1,
+ end_to_end_id = EId,
+ hop_by_hop_id = HId},
+ msg = ['DWA', {'Result-Code', 2001},
+ {'Origin-Host', "XXX"},
+ {'Origin-Realm', ?REALM}]},
+ #diameter_packet{bin = Bin} = diameter_codec:encode(?BASE, Pkt),
+ self() ! {tcp, Sock, Bin},
ok;
-%% Peer fsm or testcase process has died.
-transition({'DOWN', _, process, Pid, _} = T, #transport{parent = Pid}) ->
- {stop, T};
-
-%% Twin transport process has gone down. In the connect case, the
-%% transport isn't started until this happens in the first place so
-%% connect immediately. In the accept case, fake the peer reconnecting
-%% only after another watchdog expiry.
-transition({'DOWN', _, process, _, _}, #transport{type = Type,
- config = {_, Wd, _, _}}) ->
- Tmo = case Type of
- connect ->
- 0;
- accept ->
- ?ONE_WD(Wd)
- end,
- erlang:send_after(Tmo, self(), reconnect),
+%% First outgoing DWA.
+send(init, Sock, Bin) ->
+ [{{?MODULE, _, T}, _}] = diameter_reg:wait({?MODULE, self(), '_'}),
+ putr(config, T),
+ send(Sock, Bin);
+
+%% First transport process.
+send({SvcName, {_,_,_} = T}, Sock, Bin) ->
+ [{'Origin-Host', _} = OH, {'Origin-Realm', _} = OR | _]
+ = ?SERVICE(SvcName),
+ putr(origin, [OH, OR]),
+ putr(config, T),
+ send(Sock, Bin);
+
+%% Discard DWA, failback after another timeout in the peer.
+send({Wd, 0 = No, Msg}, Sock, Bin) ->
+ Origin = getr(origin),
+ spawn(fun() -> failback(?ONE_WD(Wd), Msg, Sock, Bin, Origin) end),
+ putr(config, No),
ok;
-transition(reconnect, #transport{type = Type,
- parent = Pid,
- config = {_,_,_,Ref}}) ->
- getr(service) ! {reopen, Ref},
- connected(Pid, Type),
- ok;
+%% Send DWA while we're in the mood (aka 0 < N).
+send({Wd, N, Msg}, Sock, Bin) ->
+ putr(config, {Wd, N-1, Msg}),
+ gen_tcp:send(Sock, Bin);
-%% Peer fsm process is sending CER: fake the peer's CEA.
-transition(?TMSG({send, Bin}), #transport{type = connect,
- open = false,
- parent = Pid}
- = S) ->
- {Code, Flags, _} = ?BASE:msg_header('CER'),
- <<_:32, Flags:8, Code:24, _:96, _/binary>> = Bin,
- Hdr = make_header(Bin),
- recv(Pid, {Hdr, make_cea()}),
- S#transport{open = true};
-
-%% Peer fsm process is sending CEA.
-transition(?TMSG({send, Bin}), #transport{type = accept,
- open = false}
- = S) ->
- {Code, Flags, _} = ?BASE:msg_header('CEA'),
- <<_:32, Flags:8, Code:24, _:96, _/binary>> = Bin,
- S#transport{open = true};
-
-%% Watchdog is sending DWR or DWA.
-transition(?TMSG({send, Bin}), #transport{open = true} = S) ->
- {Code, _, _} = ?BASE:msg_header('DWR'),
- {Code, _, _} = ?BASE:msg_header('DWA'),
- <<_:32, R:1, 0:7, Code:24, _:96, _/binary>> = Bin,
- Hdr = make_header(Bin),
- dwa(1 == R, S, Hdr),
+%% Discard DWA.
+send(0, _Sock, _Bin) ->
ok;
-%% We're telling ourselves to fake a received message.
-transition({recv, Msg}, #transport{parent = Pid}) ->
- recv(Pid, Msg),
- ok;
+%% Send DWA.
+send(N, Sock, <<_:32, 0:1, _:7, 280:24, _/binary>> = Bin) ->
+ putr(config, N-1),
+ gen_tcp:send(Sock, Bin).
-%% We're telling ourselves to receive a message to induce failback.
-transition(failback = T, #transport{parent = Pid}) ->
- recv(Pid, eraser(T)),
- ok.
+failback(Tmo, Msg, Sock, Bin, Origin) ->
+ timer:sleep(Tmo),
+ ok = gen_tcp:send(Sock, msg(Msg, Bin, Origin)).
-make_header(Bin) ->
- #diameter_header{end_to_end_id = E,
- hop_by_hop_id = H}
- = diameter_codec:decode_header(Bin),
- #diameter_header{end_to_end_id = E,
- hop_by_hop_id = H}.
-
-recv(Pid, Msg) ->
- Pid ! ?TMSG({recv, encode(Msg)}).
-
-%% Replace the end-to-end/hop-by-hop identifiers with those from an
-%% incoming request to which we're constructing a reply.
-encode({Hdr, [_|_] = Msg}) ->
- #diameter_header{hop_by_hop_id = HBH,
- end_to_end_id = E2E}
- = Hdr,
- #diameter_packet{bin = Bin} = diameter_codec:encode(?BASE, Msg),
- <<H:12/binary, _:64, T/binary>> = Bin,
- <<H/binary, HBH:32, E2E:32, T/binary>>;
-
-encode([_|_] = Msg) ->
- #diameter_packet{bin = Bin} = diameter_codec:encode(?BASE, Msg),
+%% msg/2
+
+msg('DWA', Bin, _Origin) ->
+ Bin;
+msg(Msg, _Bin, Origin) ->
+ #diameter_packet{bin = Bin}
+ = diameter_codec:encode(?BASE, msg(Msg, Origin)),
Bin.
-connected(Pid, connect) ->
- Pid ! ?TMSG({self(), connected, make_ref()});
-connected(Pid, accept) ->
- Pid ! ?TMSG({self(), connected}),
- recv(Pid, make_cer()).
+msg('DWR' = M, T) ->
+ [M | T];
-make_cer() ->
- ['CER' | getr(peer)] ++ [{'Host-IP-Address', [?REMOTEHOST]},
- {'Vendor-Id', 1028},
- {'Product-Name', "Utan"},
- {'Auth-Application-Id', [?APPL_ID]}].
+msg('RAA', T) ->
+ ['RAA', {'Session-Id', diameter:session_id("abc")},
+ {'Result-Code', 2001}
+ | T].
+%% An unexpected answer is discarded after passing through the
+%% watchdog state machine.
-make_cea() ->
- ['CER' | Rest] = make_cer(),
- ['CEA', {'Result-Code', ?SUCCESS} | Rest].
+%% ===========================================================================
-make_dwr() ->
- ['DWR' | getr(peer)].
+peer_up(_SvcName, _Peer, S) ->
+ S.
-make_dwa() ->
- ['DWR' | Rest] = make_dwr(),
- ['DWA', {'Result-Code', ?SUCCESS} | Rest].
+peer_down(_SvcName, _Peer, S) ->
+ S.
-dwa(false, _, _) -> %% outgoing was DWA ...
- ok;
-dwa(true, S, Hdr) -> %% ... or DWR
- dwa(getr(count), Hdr, S);
-
-%% React to the DWR only after another watchdog expiry. We shouldn't
-%% get another DWR while the answer is pending.
-dwa(0, Hdr, #transport{config = {_, Wd, What, _}}) ->
- erlang:send_after(?ONE_WD(Wd), self(), failback),
- putr(failback, make_msg(What, Hdr)),
- eraser(count);
-
-dwa(undefined, _, _) ->
- undefined = getr(failback), %% ensure this is after failback
- ok;
+%% ===========================================================================
-%% Reply with DWA.
-dwa(N, Hdr, #transport{parent = Pid}) ->
- putr(count, N-1),
- recv(Pid, {Hdr, make_dwa()}).
+choose(true, X, _) -> X;
+choose(false, _, X) -> X.
-%% Answer to received DWR.
-make_msg('DWA', Hdr) ->
- {Hdr, make_dwa()};
+%% id/1
+%%
+%% Jitter callback.
-%% DWR from peer.
-make_msg('DWR', _) ->
- make_dwr();
+id(T) ->
+ T.
-%% An unexpected answer is discarded after passing through the
-%% watchdog state machine.
-make_msg(other, _) ->
- ['RAA', {'Session-Id', diameter:session_id("abc")},
- {'Result-Code', 2001}
- | getr(peer)].
+%% run/1
+%%
+%% A more useful badmatch in case of failure.
+
+run(Fs) ->
+ ?util:run([{?MODULE, [run1, F]} || F <- Fs]).
+
+run1([F|A]) ->
+ ok = try
+ apply(?MODULE, F, A),
+ ok
+ catch
+ E:R ->
+ S = erlang:get_stacktrace(),
+ io:format("~p~n", [{A, E, R, S}]),
+ S
+ end.
+
+%% now_diff/2
+
+now_diff(T1, T2) ->
+ timer:now_diff(T2, T1).
+
+%% jitter/2
+
+jitter(?WD(T), _) ->
+ T;
+jitter(T,D) ->
+ T+D.
+
+%% Generate a unique hostname for the faked peer.
+hostname() ->
+ lists:flatten(io_lib:format("~p-~p-~p", tuple_to_list(now()))).
putr(Key, Val) ->
put({?MODULE, Key}, Val).
getr(Key) ->
get({?MODULE, Key}).
-
-eraser(Key) ->
- erase({?MODULE, Key}).
diff --git a/lib/diameter/test/modules.mk b/lib/diameter/test/modules.mk
index 7f163536fb..80b1769d04 100644
--- a/lib/diameter/test/modules.mk
+++ b/lib/diameter/test/modules.mk
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2010-2011. All Rights Reserved.
+# Copyright Ericsson AB 2010-2012. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -39,7 +39,9 @@ MODULES = \
diameter_traffic_SUITE \
diameter_relay_SUITE \
diameter_tls_SUITE \
- diameter_failover_SUITE
+ diameter_failover_SUITE \
+ diameter_dpr_SUITE \
+ diameter_event_SUITE
HRL_FILES = \
diameter_ct.hrl
diff --git a/lib/diameter/vsn.mk b/lib/diameter/vsn.mk
index 48e6596e72..7b2208137b 100644
--- a/lib/diameter/vsn.mk
+++ b/lib/diameter/vsn.mk
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2010-2012. All Rights Reserved.
+# Copyright Ericsson AB 2010-2013. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -18,7 +18,7 @@
# %CopyrightEnd%
APPLICATION = diameter
-DIAMETER_VSN = 1.2
+DIAMETER_VSN = 1.3.1
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(DIAMETER_VSN)$(PRE_VSN)"
diff --git a/lib/edoc/doc/src/notes.xml b/lib/edoc/doc/src/notes.xml
index e01a6d6675..472b3bfc34 100644
--- a/lib/edoc/doc/src/notes.xml
+++ b/lib/edoc/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2007</year><year>2011</year>
+ <year>2007</year><year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/edoc/priv/Makefile b/lib/edoc/priv/Makefile
index 73c42c05eb..9873136201 100644
--- a/lib/edoc/priv/Makefile
+++ b/lib/edoc/priv/Makefile
@@ -27,8 +27,11 @@ GEN_SCRIPT_SRC = edoc_generate.src
GEN_SCRIPT = edoc_generate
PRIV_FILES = stylesheet.css erlang.png edoc.dtd
-debug opt:
- sed -e "s/%EDOC_VSN%/$(EDOC_VSN)/g" \
+debug opt: $(GEN_SCRIPT)
+
+$(GEN_SCRIPT): ../vsn.mk ../../xmerl/vsn.mk ../../syntax_tools/vsn.mk \
+ $(GEN_SCRIPT_SRC)
+ $(vsn_verbose)sed -e "s/%EDOC_VSN%/$(EDOC_VSN)/g" \
-e "s/%XMERL_VSN%/$(XMERL_VSN)/g" \
-e "s/%SYNTAX_TOOLS_VSN%/$(SYNTAX_TOOLS_VSN)/g" \
$(GEN_SCRIPT_SRC) > $(GEN_SCRIPT)
diff --git a/lib/edoc/priv/edoc.dtd b/lib/edoc/priv/edoc.dtd
index 6a332cf22f..ba4ac0db28 100644
--- a/lib/edoc/priv/edoc.dtd
+++ b/lib/edoc/priv/edoc.dtd
@@ -4,7 +4,8 @@
<!ELEMENT overview (title, description?, author*, copyright?, version?,
since?, see*, reference*, todo?, packages, modules)>
<!ATTLIST overview
- root CDATA #IMPLIED>
+ root CDATA #IMPLIED
+ encoding CDATA #IMPLIED>
<!ELEMENT title (#PCDATA)>
@@ -25,6 +26,7 @@
name CDATA #REQUIRED
private (yes | no) #IMPLIED
hidden (yes | no) #IMPLIED
+ encoding CDATA #IMPLIED
root CDATA #IMPLIED>
<!ELEMENT description (briefDescription, fullDescription?)>
diff --git a/lib/edoc/src/Makefile b/lib/edoc/src/Makefile
index 72354ac711..4e5a4182da 100644
--- a/lib/edoc/src/Makefile
+++ b/lib/edoc/src/Makefile
@@ -67,17 +67,17 @@ distclean: clean
realclean: clean
$(EBIN)/%.$(EMULATOR):%.erl
- erlc -W $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
+ $(erlc_verbose)erlc -W $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
# ----------------------------------------------------
# Special Build Targets
# ----------------------------------------------------
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
# ----------------------------------------------------
# Release Target
diff --git a/lib/edoc/src/edoc.erl b/lib/edoc/src/edoc.erl
index 544465b14a..599036f380 100644
--- a/lib/edoc/src/edoc.erl
+++ b/lib/edoc/src/edoc.erl
@@ -120,7 +120,8 @@ file(Name, Options) ->
Suffix = proplists:get_value(file_suffix, Options,
?DEFAULT_FILE_SUFFIX),
Dir = proplists:get_value(dir, Options, filename:dirname(Name)),
- edoc_lib:write_file(Text, Dir, BaseName ++ Suffix).
+ Encoding = [{encoding, edoc_lib:read_encoding(Name, [])}],
+ edoc_lib:write_file(Text, Dir, BaseName ++ Suffix, '', Encoding).
%% TODO: better documentation of files/1/2, packages/1/2, application/1/2/3
@@ -455,14 +456,14 @@ expand_sources(Ss, Opts) ->
end,
expand_sources(Ss1, Suffix, sets:new(), [], []).
-expand_sources([{P, F, D} | Fs], Suffix, S, As, Ms) ->
- M = list_to_atom(packages:concat(P, filename:rootname(F, Suffix))),
+expand_sources([{'', F, D} | Fs], Suffix, S, As, Ms) ->
+ M = list_to_atom(filename:rootname(F, Suffix)),
case sets:is_element(M, S) of
true ->
expand_sources(Fs, Suffix, S, As, Ms);
false ->
S1 = sets:add_element(M, S),
- expand_sources(Fs, Suffix, S1, [{M, P, F, D} | As],
+ expand_sources(Fs, Suffix, S1, [{M, '', F, D} | As],
[M | Ms])
end;
expand_sources([], _Suffix, _S, As, Ms) ->
diff --git a/lib/edoc/src/edoc.hrl b/lib/edoc/src/edoc.hrl
index 98debba4ab..44c5d6fef4 100644
--- a/lib/edoc/src/edoc.hrl
+++ b/lib/edoc/src/edoc.hrl
@@ -48,7 +48,8 @@
%% functions = ordset(function_name()),
%% exports = ordset(function_name()),
%% attributes = ordset({atom(), term()}),
-%% records = [{atom(), [{atom(), term()}]}]}
+%% records = [{atom(), [{atom(), term()}]}],
+%% encoding = epp:source_encoding()}
%% ordset(T) = sets:ordset(T)
%% function_name(T) = {atom(), integer()}
@@ -57,7 +58,8 @@
functions = [],
exports = [],
attributes = [],
- records = []
+ records = [],
+ encoding = latin1
}).
%% Environment for generating documentation data
diff --git a/lib/edoc/src/edoc_data.erl b/lib/edoc/src/edoc_data.erl
index 624f9177a2..f88ba05f4b 100644
--- a/lib/edoc/src/edoc_data.erl
+++ b/lib/edoc/src/edoc_data.erl
@@ -83,7 +83,8 @@ module(Module, Entries, Env, Opts) ->
AllTags = get_all_tags(Entries),
Functions = function_filter(Entries, Opts),
Out = {module, ([{name, Name},
- {root, Env#env.root}]
+ {root, Env#env.root},
+ {encoding, Module#module.encoding}]
++ case is_private(HeaderTags) of
true -> [{private, "yes"}];
false -> []
diff --git a/lib/edoc/src/edoc_doclet.erl b/lib/edoc/src/edoc_doclet.erl
index 385d20e9ae..a0c1ae1c0f 100644
--- a/lib/edoc/src/edoc_doclet.erl
+++ b/lib/edoc/src/edoc_doclet.erl
@@ -192,8 +192,9 @@ source({M, P, Name, Path}, Dir, Suffix, Env, Set, Private, Hidden,
andalso ((not is_hidden(Doc)) orelse Hidden) of
true ->
Text = edoc:layout(Doc, Options),
- Name1 = packages:last(M) ++ Suffix,
- edoc_lib:write_file(Text, Dir, Name1, P),
+ Name1 = atom_to_list(M) ++ Suffix,
+ Encoding = [{encoding,encoding(Doc)}],
+ edoc_lib:write_file(Text, Dir, Name1, P, Encoding),
{sets:add_element(Module, Set), Error};
false ->
{Set, Error}
@@ -204,9 +205,9 @@ source({M, P, Name, Path}, Dir, Suffix, Env, Set, Private, Hidden,
end.
check_name(M, M0, P0, File) ->
- P = list_to_atom(packages:strip_last(M)),
- N = packages:last(M),
- N0 = packages:last(M0),
+ P = '',
+ N = M,
+ N0 = M0,
case N of
[$? | _] ->
%% A module name of the form '?...' is assumed to be caused
@@ -359,14 +360,19 @@ xhtml_1(Title, CSS, Body) ->
overview(Dir, Title, Env, Opts) ->
File = proplists:get_value(overview, Opts,
filename:join(Dir, ?OVERVIEW_FILE)),
+ Encoding = edoc_lib:read_encoding(File, [{in_comment_only, false}]),
Tags = read_file(File, overview, Env, Opts),
- Data = edoc_data:overview(Title, Tags, Env, Opts),
+ Data0 = edoc_data:overview(Title, Tags, Env, Opts),
+ EncodingAttribute = #xmlAttribute{name = encoding,
+ value = atom_to_list(Encoding)},
+ #xmlElement{attributes = As} = Data0,
+ Data = Data0#xmlElement{attributes = [EncodingAttribute | As]},
F = fun (M) ->
M:overview(Data, Opts)
end,
Text = edoc_lib:run_layout(F, Opts),
- edoc_lib:write_file(Text, Dir, ?OVERVIEW_SUMMARY).
-
+ EncOpts = [{encoding,Encoding}],
+ edoc_lib:write_file(Text, Dir, ?OVERVIEW_SUMMARY, '', EncOpts).
copy_image(Dir) ->
case code:priv_dir(?EDOC_APP) of
@@ -441,6 +447,12 @@ is_hidden(E) ->
_ -> false
end.
+encoding(E) ->
+ case get_attrval(encoding, E) of
+ "latin1" -> latin1;
+ _ -> utf8
+ end.
+
get_attrval(Name, #xmlElement{attributes = As}) ->
case get_attr(Name, As) of
[#xmlAttribute{value = V}] ->
diff --git a/lib/edoc/src/edoc_extract.erl b/lib/edoc/src/edoc_extract.erl
index 5a79e127f6..67a95e80aa 100644
--- a/lib/edoc/src/edoc_extract.erl
+++ b/lib/edoc/src/edoc_extract.erl
@@ -121,7 +121,7 @@ source1(Tree, File0, Env, Opts, TypeDocs) ->
Module = get_module_info(Tree, File),
{Header, Footer, Entries} = collect(Forms, Module),
Name = Module#module.name,
- Package = list_to_atom(packages:strip_last(Name)),
+ Package = '',
Env1 = Env#env{module = Name,
package = Package,
root = edoc_refs:relative_package_path('', Package)},
@@ -226,7 +226,7 @@ add_macro_defs(Defs0, Opts, Env) ->
%% lines of text before the first tag are ignored. `Env' is an
%% environment created by {@link edoc_lib:get_doc_env/4}. Upon error,
%% `Reason' is an atom returned from the call to {@link
-%% //kernel/file:read_file/1}.
+%% //kernel/file:read_file/1} or the atom 'invalid_unicode'.
%%
%% See {@link text/4} for options.
@@ -235,7 +235,13 @@ add_macro_defs(Defs0, Opts, Env) ->
file(File, Context, Env, Opts) ->
case file:read_file(File) of
{ok, Bin} ->
- {ok, text(binary_to_list(Bin), Context, Env, Opts, File)};
+ Enc = edoc_lib:read_encoding(File,[{in_comment_only, false}]),
+ case catch unicode:characters_to_list(Bin, Enc) of
+ String when is_list(String) ->
+ {ok, text(String, Context, Env, Opts, File)};
+ _ ->
+ {error, invalid_unicode}
+ end;
{error, _} = Error ->
Error
end.
@@ -306,12 +312,14 @@ get_module_info(Forms, File) ->
Exports = ordsets:from_list(get_list_keyval(exports, L)),
Attributes = ordsets:from_list(get_list_keyval(attributes, L)),
Records = get_list_keyval(records, L),
+ Encoding = edoc_lib:read_encoding(File, []),
#module{name = Name,
parameters = Vars,
functions = Functions,
exports = ordsets:intersection(Exports, Functions),
attributes = Attributes,
- records = Records}.
+ records = Records,
+ encoding = Encoding}.
get_list_keyval(Key, L) ->
case lists:keyfind(Key, 1, L) of
diff --git a/lib/edoc/src/edoc_layout.erl b/lib/edoc/src/edoc_layout.erl
index 951cec121c..7bd0615f5c 100644
--- a/lib/edoc/src/edoc_layout.erl
+++ b/lib/edoc/src/edoc_layout.erl
@@ -210,7 +210,8 @@ layout_module(#xmlElement{name = module, content = Es}=E, Opts) ->
++ [hr, ?NL]
++ navigation("bottom")
++ timestamp()),
- xhtml(Title, stylesheet(Opts), Body).
+ Encoding = get_attrval(encoding, E),
+ xhtml(Title, stylesheet(Opts), Body, Encoding).
module_params(Es) ->
As = [{get_text(argName, Es1),
@@ -956,10 +957,17 @@ local_label(R) ->
"#" ++ R.
xhtml(Title, CSS, Body) ->
+ xhtml(Title, CSS, Body, "latin1").
+
+xhtml(Title, CSS, Body, Encoding) ->
+ EncString = case Encoding of
+ "latin1" -> "ISO-8859-1";
+ _ -> "UTF-8"
+ end,
[{html, [?NL,
{head, [?NL,
{meta, [{'http-equiv',"Content-Type"},
- {content, "text/html; charset=ISO-8859-1"}],
+ {content, "text/html; charset="++EncString}],
[]},
?NL,
{title, Title},
@@ -1021,7 +1029,8 @@ overview(E=#xmlElement{name = overview, content = Es}, Options) ->
++ [?NL, hr]
++ navigation("bottom")
++ timestamp()),
- XML = xhtml(Title, stylesheet(Opts), Body),
+ Encoding = get_attrval(encoding, E),
+ XML = xhtml(Title, stylesheet(Opts), Body, Encoding),
xmerl:export_simple(XML, ?HTML_EXPORT, []).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% NYTT
diff --git a/lib/edoc/src/edoc_lib.erl b/lib/edoc/src/edoc_lib.erl
index 90fb8a679c..3d193c4bfa 100644
--- a/lib/edoc/src/edoc_lib.erl
+++ b/lib/edoc/src/edoc_lib.erl
@@ -1,3 +1,4 @@
+%% -*- coding: utf-8 -*-
%% =====================================================================
%% This library is free software; you can redistribute it and/or modify
%% it under the terms of the GNU Lesser General Public License as
@@ -30,10 +31,10 @@
parse_contact/2, escape_uri/1, join_uri/2, is_relative_uri/1,
is_name/1, to_label/1, find_doc_dirs/0, find_sources/2,
find_sources/3, find_file/3, try_subdir/2, unique/1,
- write_file/3, write_file/4, write_info_file/4,
+ write_file/3, write_file/4, write_file/5, write_info_file/4,
read_info_file/1, get_doc_env/1, get_doc_env/4, copy_file/2,
uri_get/1, run_doclet/2, run_layout/2,
- simplify_path/1, timestr/1, datestr/1]).
+ simplify_path/1, timestr/1, datestr/1, read_encoding/2]).
-import(edoc_report, [report/2, warning/2]).
@@ -57,6 +58,13 @@ datestr({Y,M,D}) ->
lists:flatten(io_lib:fwrite("~s ~w ~w",[lists:nth(M, Ms),D,Y])).
%% @private
+read_encoding(File, Options) ->
+ case epp:read_encoding(File, Options) of
+ none -> epp:default_encoding();
+ Encoding -> Encoding
+ end.
+
+%% @private
count(X, Xs) ->
count(X, Xs, 0).
@@ -228,13 +236,13 @@ end_of_sentence_1(_, false, _) ->
%% 173 - 176 { - ~ punctuation
%% 177 DEL control
%% 200 - 237 control
-%% 240 - 277 NBSP - � punctuation
-%% 300 - 326 � - � uppercase
-%% 327 � punctuation
-%% 330 - 336 � - � uppercase
-%% 337 - 366 � - � lowercase
-%% 367 � punctuation
-%% 370 - 377 � - � lowercase
+%% 240 - 277 NBSP - ¿ punctuation
+%% 300 - 326 À - Ö uppercase
+%% 327 × punctuation
+%% 330 - 336 Ø - Þ uppercase
+%% 337 - 366 ß - ö lowercase
+%% 367 ÷ punctuation
+%% 370 - 377 ø - ÿ lowercase
%% Names must begin with a lowercase letter and contain only
%% alphanumerics and underscores.
@@ -261,6 +269,10 @@ is_name_1(_) -> false.
to_atom(A) when is_atom(A) -> A;
to_atom(S) when is_list(S) -> list_to_atom(S).
+
+to_list(A) when is_atom(A) -> atom_to_list(A);
+to_list(S) when is_list(S) -> S.
+
%% @private
unique([X | Xs]) -> [X | unique(Xs, X)];
@@ -677,7 +689,6 @@ try_subdir(Dir, Subdir) ->
write_file(Text, Dir, Name) ->
write_file(Text, Dir, Name, '').
-
%% @spec (Text::deep_string(), Dir::edoc:filename(),
%% Name::edoc:filename(), Package::atom()|string()) -> ok
%% @doc Like {@link write_file/3}, but adds path components to the target
@@ -685,10 +696,12 @@ write_file(Text, Dir, Name) ->
%% @private
write_file(Text, Dir, Name, Package) ->
- Dir1 = filename:join([Dir | packages:split(Package)]),
- File = filename:join(Dir1, Name),
+ write_file(Text, Dir, Name, Package, [{encoding,latin1}]).
+
+write_file(Text, Dir, Name, Package, Options) ->
+ File = filename:join([Dir, to_list(Package), Name]),
ok = filelib:ensure_dir(File),
- case file:open(File, [write]) of
+ case file:open(File, [write] ++ Options) of
{ok, FD} ->
io:put_chars(FD, Text),
ok = file:close(FD);
@@ -705,8 +718,9 @@ write_info_file(App, Packages, Modules, Dir) ->
Ts1 = if App =:= ?NO_APP -> Ts;
true -> [{application, App} | Ts]
end,
- S = [io_lib:fwrite("~p.\n", [T]) || T <- Ts1],
- write_file(S, Dir, ?INFO_FILE).
+ S0 = [io_lib:fwrite("~p.\n", [T]) || T <- Ts1],
+ S = ["%% encoding: UTF-8\n" | S0],
+ write_file(S, Dir, ?INFO_FILE, '', [{encoding,unicode}]).
%% @spec (Name::edoc:filename()) -> {ok, string()} | {error, Reason}
%%
@@ -714,7 +728,14 @@ write_info_file(App, Packages, Modules, Dir) ->
read_file(File) ->
case file:read_file(File) of
- {ok, Bin} -> {ok, binary_to_list(Bin)};
+ {ok, Bin} ->
+ Enc = edoc_lib:read_encoding(File, []),
+ case catch unicode:characters_to_list(Bin, Enc) of
+ String when is_list(String) ->
+ {ok, String};
+ _ ->
+ {error, invalid_unicode}
+ end;
{error, Reason} -> {error, Reason}
end.
@@ -818,7 +839,7 @@ find_sources(Path, Pkg, Rec, Ext, Opts) ->
lists:flatten(find_sources_1(Path, to_atom(Pkg), Rec, Ext, Skip)).
find_sources_1([P | Ps], Pkg, Rec, Ext, Skip) ->
- Dir = filename:join(P, filename:join(packages:split(Pkg))),
+ Dir = filename:join(P, atom_to_list(Pkg)),
Fs1 = find_sources_1(Ps, Pkg, Rec, Ext, Skip),
case filelib:is_dir(Dir) of
true ->
@@ -844,9 +865,9 @@ find_sources_2(Dir, Pkg, Rec, Ext, Skip) ->
[]
end.
-find_sources_3(Es, Dir, Pkg, Rec, Ext, Skip) ->
+find_sources_3(Es, Dir, '', Rec, Ext, Skip) ->
[find_sources_2(filename:join(Dir, E),
- to_atom(packages:concat(Pkg, E)), Rec, Ext, Skip)
+ to_atom(E), Rec, Ext, Skip)
|| E <- Es, is_package_dir(E, Dir)].
is_source_file(Name, Ext) ->
@@ -858,16 +879,16 @@ is_package_dir(Name, Dir) ->
andalso filelib:is_dir(filename:join(Dir, Name)).
%% @private
-find_file([P | Ps], Pkg, Name) ->
- Dir = filename:join(P, filename:join(packages:split(Pkg))),
- File = filename:join(Dir, Name),
+find_file([P | Ps], []=Pkg, Name) ->
+ Pkg = [],
+ File = filename:join(P, Name),
case filelib:is_file(File) of
true ->
File;
false ->
find_file(Ps, Pkg, Name)
end;
-find_file([], _Pkg, _Name) ->
+find_file([], [], _Name) ->
"".
%% @private
diff --git a/lib/edoc/src/edoc_macros.erl b/lib/edoc/src/edoc_macros.erl
index 70fb38bf0a..08686c4fb5 100644
--- a/lib/edoc/src/edoc_macros.erl
+++ b/lib/edoc/src/edoc_macros.erl
@@ -88,13 +88,13 @@ link_macro(S, Line, Env) ->
true -> " target=\"_top\""; % note the initial space
false -> ""
end,
- lists:flatten(io_lib:fwrite("<a href=\"~s\"~s>~s</a>",
+ lists:flatten(io_lib:fwrite("<a href=\"~s\"~s>~ts</a>",
[URI, Target, Txt])).
section_macro(S, _Line, _Env) ->
S1 = lists:reverse(edoc_lib:strip_space(
lists:reverse(edoc_lib:strip_space(S)))),
- lists:flatten(io_lib:format("<a href=\"#~s\">~s</a>",
+ lists:flatten(io_lib:format("<a href=\"#~ts\">~ts</a>",
[edoc_lib:to_label(S1), S1])).
type_macro(S, Line, Env) ->
diff --git a/lib/edoc/src/edoc_parser.yrl b/lib/edoc/src/edoc_parser.yrl
index d7c1b1c045..cf1a2d6b11 100644
--- a/lib/edoc/src/edoc_parser.yrl
+++ b/lib/edoc/src/edoc_parser.yrl
@@ -1,6 +1,7 @@
+%% -*- coding: utf-8 -*-
%% ========================== -*-Erlang-*- =============================
%% EDoc type specification grammar for the Yecc parser generator,
-%% adapted from Sven-Olof Nystr�m's type specification parser.
+%% adapted from Sven-Olof Nyström's type specification parser.
%%
%% Also contains entry points for parsing things like typedefs,
%% references, and throws-declarations.
@@ -317,10 +318,7 @@ tok_val(T) -> element(3, T).
tok_line(T) -> element(2, T).
-qname([A]) ->
- A; % avoid unnecessary call to packages:concat/1.
-qname(List) ->
- list_to_atom(packages:concat(lists:reverse(List))).
+qname([A]) -> A.
union(Ts) ->
case Ts of
diff --git a/lib/edoc/src/edoc_refs.erl b/lib/edoc/src/edoc_refs.erl
index 1f578a3b83..ea439490ed 100644
--- a/lib/edoc/src/edoc_refs.erl
+++ b/lib/edoc/src/edoc_refs.erl
@@ -126,7 +126,7 @@ abs_uri({package, P}, Env) ->
module_ref(M, Env) ->
case (Env#env.modules)(M) of
"" ->
- File = packages:last(M) ++ Env#env.file_suffix,
+ File = atom_to_list(M) ++ Env#env.file_suffix,
Path = relative_module_path(M, Env#env.package),
join_uri(Path, escape_uri(File));
Base ->
@@ -134,8 +134,7 @@ module_ref(M, Env) ->
end.
module_absref(M, Env) ->
- join_segments(packages:split(M))
- ++ escape_uri(Env#env.file_suffix).
+ escape_uri(atom_to_list(M)) ++ escape_uri(Env#env.file_suffix).
package_ref(P, Env) ->
case (Env#env.packages)(P) of
@@ -147,7 +146,7 @@ package_ref(P, Env) ->
end.
package_absref(P, Env) ->
- join_uri(join_segments(packages:split(P)),
+ join_uri(escape_uri(atom_to_list(P)),
escape_uri(Env#env.package_summary)).
app_ref(A, Env) ->
@@ -179,14 +178,11 @@ join_segments([S | Ss]) ->
%% The empty string is returned if the To module has only one segment,
%% implying a local reference.
-relative_module_path(To, From) ->
- case first(packages:split(To)) of
- [] -> "";
- P -> relative_path(P, packages:split(From))
- end.
+relative_module_path(_To, _From) ->
+ "".
relative_package_path(To, From) ->
- relative_path(packages:split(To), packages:split(From)).
+ relative_path([atom_to_list(To)], [atom_to_list(From)]).
%% This takes two lists of path segments (From, To). Note that an empty
%% string will be returned if the paths are the same. Empty leading
@@ -210,6 +206,3 @@ relative_path_2([], []) ->
"";
relative_path_2([], Ts) ->
join_segments(Ts).
-
-first([H | T]) when T /= [] -> [H | first(T)];
-first(_) -> [].
diff --git a/lib/edoc/src/edoc_wiki.erl b/lib/edoc/src/edoc_wiki.erl
index 5c71658af5..cc0529d2a9 100644
--- a/lib/edoc/src/edoc_wiki.erl
+++ b/lib/edoc/src/edoc_wiki.erl
@@ -80,6 +80,7 @@ parse_xml(Data, Line) ->
parse_xml_1(Text, Line) ->
Text1 = "<doc>" ++ Text ++ "</doc>",
+ %% Any coding except "utf-8".
Opts = [{line, Line}, {encoding, 'iso-8859-1'}],
case catch {ok, xmerl_scan:string(Text1, Opts)} of
{ok, {E, _}} ->
@@ -174,7 +175,7 @@ expand_heading_1(Cs, N, L, As) ->
expand_heading_2(Ts, Cs, N, L, As) ->
H = ?BASE_HEADING + N,
- Ts1 = io_lib:format("<h~w><a name=\"~s\">~s</a></h~w>\n",
+ Ts1 = io_lib:format("<h~w><a name=\"~ts\">~ts</a></h~w>\n",
[H, make_label(Ts), Ts, H]),
expand_new_line(Cs, L + 1, lists:reverse(lists:flatten(Ts1), As)).
diff --git a/lib/eldap/src/Makefile b/lib/eldap/src/Makefile
index 39a41d08e2..ad93e1087a 100644
--- a/lib/eldap/src/Makefile
+++ b/lib/eldap/src/Makefile
@@ -75,10 +75,10 @@ clean:
rm -f errs core *~
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(ELDAP_VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(ELDAP_VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(ELDAP_VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(ELDAP_VSN);' $< > $@
docs:
@@ -88,7 +88,7 @@ $(TARGET_FILES): $(HRL_FILES)
# Special Build Targets
# ----------------------------------------------------
$(ASN1_HRL): ../asn1/$(ASN1_FILES)
- $(ERLC) -o $(EBIN) -bber_bin +optimize +nif $(ERL_COMPILE_FLAGS) ../asn1/ELDAPv3.asn1
+ $(asn_verbose)$(ERLC) -o $(EBIN) -bber $(ERL_COMPILE_FLAGS) ../asn1/ELDAPv3.asn1
# ----------------------------------------------------
# Release Target
diff --git a/lib/eldap/src/eldap.erl b/lib/eldap/src/eldap.erl
index 699dfc8791..5753cc4749 100644
--- a/lib/eldap/src/eldap.erl
+++ b/lib/eldap/src/eldap.erl
@@ -320,7 +320,7 @@ present(Attribute) when is_list(Attribute) ->
%%% will match entries containing: 'sn: Tornkvist'
%%%
substrings(Type, SubStr) when is_list(Type), is_list(SubStr) ->
- Ss = {'SubstringFilter_substrings',v_substr(SubStr)},
+ Ss = v_substr(SubStr),
{substrings,#'SubstringFilter'{type = Type,
substrings = Ss}}.
@@ -700,20 +700,22 @@ recv_response(S, Data) ->
Error -> throw(Error)
end;
{error,Reason} ->
- throw({gen_tcp_error, Reason});
- Error ->
- throw(Error)
+ throw({gen_tcp_error, Reason})
end.
%%% Sanity check of received packet
check_tag(Data) ->
- case asn1rt_ber_bin:decode_tag(l2b(Data)) of
- {_Tag, Data1, _Rb} ->
- case asn1rt_ber_bin:decode_length(l2b(Data1)) of
- {{_Len, _Data2}, _Rb2} -> ok;
- _ -> throw({error,decoded_tag_length})
- end;
- _ -> throw({error,decoded_tag})
+ try
+ {_Tag, Data1, _Rb} = asn1rt_ber_bin:decode_tag(l2b(Data)),
+ try
+ {{_Len, _Data2}, _Rb2} = asn1rt_ber_bin:decode_length(l2b(Data1)),
+ ok
+ catch
+ _ -> throw({error,decoded_tag_length})
+ end
+ catch
+ _ ->
+ throw({error, decoded_tag})
end.
%%% Check for expected kind of reply
diff --git a/lib/eldap/vsn.mk b/lib/eldap/vsn.mk
index c9d6e4e324..4d05d3d1e3 100644
--- a/lib/eldap/vsn.mk
+++ b/lib/eldap/vsn.mk
@@ -1 +1 @@
-ELDAP_VSN = 1.0
+ELDAP_VSN = 1.0.1
diff --git a/lib/erl_docgen/doc/src/doc-build.xml b/lib/erl_docgen/doc/src/doc-build.xml
index 08410a1539..ae1b17dff5 100644
--- a/lib/erl_docgen/doc/src/doc-build.xml
+++ b/lib/erl_docgen/doc/src/doc-build.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2011</year>
+ <year>1997</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -56,7 +56,8 @@
</p>
<code>
- 1> escript $(ERL_TOP)/lib/erl_docgen/priv/bin/codeline_preprocessing.escript ex1.xmlsrc ex1.xml
+ 1> escript $(ERL_TOP)/lib/erl_docgen/priv/bin/codeline_preprocessing.escript \
+ ex1.xmlsrc ex1.xml
</code>
</section>
</section>
diff --git a/lib/erl_docgen/doc/src/notes.xml b/lib/erl_docgen/doc/src/notes.xml
index ee62de86b1..9775909d76 100644
--- a/lib/erl_docgen/doc/src/notes.xml
+++ b/lib/erl_docgen/doc/src/notes.xml
@@ -30,7 +30,23 @@
</header>
<p>This document describes the changes made to the <em>erl_docgen</em> application.</p>
- <section><title>Erl_Docgen 0.3.2</title>
+ <section><title>Erl_Docgen 0.3.3</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> A possibility to configure erl_docgen so it can
+ generate documentation for other products than
+ Erlang/OTP. </p>
+ <p>
+ Own Id: OTP-9040</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Docgen 0.3.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/erl_docgen/priv/bin/xml_from_edoc.escript b/lib/erl_docgen/priv/bin/xml_from_edoc.escript
index 2cb81be1be..65a580dca2 100755
--- a/lib/erl_docgen/priv/bin/xml_from_edoc.escript
+++ b/lib/erl_docgen/priv/bin/xml_from_edoc.escript
@@ -2,7 +2,7 @@
%% -*- erlang -*-
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -100,10 +100,12 @@ module(File, Args) ->
users_guide(File, Args) ->
case filelib:is_regular(File) of
true ->
+ Enc = epp:read_encoding(File, [{in_comment_only, false}]),
+ Encoding = [{encoding, Enc} || Enc =/= none],
Opts = [{def, Args#args.def},
{app_default, "OTPROOT"},
{file_suffix, Args#args.suffix},
- {layout, Args#args.layout}],
+ {layout, Args#args.layout}] ++ Encoding,
Env = edoc_lib:get_doc_env(Opts),
@@ -115,7 +117,7 @@ users_guide(File, Args) ->
Text = edoc_lib:run_layout(F, Opts),
OutFile = "chapter" ++ Args#args.suffix,
- edoc_lib:write_file(Text, ".", OutFile);
+ edoc_lib:write_file(Text, ".", OutFile, '', Encoding);
false ->
io:format("~s: not a regular file\n", [File]),
usage()
diff --git a/lib/erl_docgen/priv/dtd/common.refs.dtd b/lib/erl_docgen/priv/dtd/common.refs.dtd
index c1237766e1..93592607df 100644
--- a/lib/erl_docgen/priv/dtd/common.refs.dtd
+++ b/lib/erl_docgen/priv/dtd/common.refs.dtd
@@ -26,10 +26,12 @@
<!ELEMENT description (%block;|quote|br|marker|warning|note)* >
<!ELEMENT funcs (func)+ >
-<!ELEMENT func (name+,type_desc+,fsummary,type?,desc?) >
+<!ELEMENT func (name+,type_desc*,fsummary,type?,desc?) >
<!-- ELEMENT name is defined in each ref dtd -->
<!ELEMENT fsummary (#PCDATA|c|em)* >
-<!ELEMENT type (v,d?)+ >
+<!ELEMENT type (v,d?)* >
+<!ATTLIST type variable CDATA #IMPLIED
+ name_i CDATA #IMPLIED>
<!ELEMENT v (#PCDATA) >
<!ELEMENT d (#PCDATA|c|em)* >
<!ELEMENT desc (%block;|quote|br|marker|warning|note|anno)* >
@@ -41,3 +43,4 @@
<!ELEMENT datatypes (datatype)+ >
<!ELEMENT datatype (name+,desc?) >
<!ELEMENT type_desc (#PCDATA) >
+<!ATTLIST type_desc variable CDATA #REQUIRED>
diff --git a/lib/erl_docgen/priv/dtd/erlref.dtd b/lib/erl_docgen/priv/dtd/erlref.dtd
index 9905086ff4..0cc5cfa06d 100644
--- a/lib/erl_docgen/priv/dtd/erlref.dtd
+++ b/lib/erl_docgen/priv/dtd/erlref.dtd
@@ -29,3 +29,6 @@
<!-- `name' is used in common.refs.dtd and must therefore
be defined in each *ref. dtd -->
<!ELEMENT name (#PCDATA) >
+<!ATTLIST name name CDATA #IMPLIED
+ arity CDATA #IMPLIED
+ clause_i CDATA #IMPLIED>
diff --git a/lib/erl_docgen/priv/fop.xconf b/lib/erl_docgen/priv/fop.xconf
new file mode 100644
index 0000000000..70ecd608c3
--- /dev/null
+++ b/lib/erl_docgen/priv/fop.xconf
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<!--
+ #
+ # %CopyrightBegin%
+ #
+ # Copyright Ericsson AB 2009-2012. All Rights Reserved.
+ #
+ # The 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%
+
+ -->
+<!-- NOTE: This is the version of the configuration -->
+<fop version="1.0">
+ <!-- The substitutions of DejaVu 700 are there because FOP outputs
+ warnings about doing the substitutions otherwise -->
+ <fonts>
+ <substitutions>
+ <substitution>
+ <from font-family="DejaVuSans" font-weight="700"/>
+ <to font-family="DejaVuSans" font-weight="400"/>
+ </substitution>
+ <substitution>
+ <from font-family="DejaVuSansMono" font-weight="700"/>
+ <to font-family="DejaVuSansMono" font-weight="400"/>
+ </substitution>
+ </substitutions>
+ </fonts>
+ <renderers>
+ <renderer mime="application/pdf">
+ <fonts>
+ <auto-detect/>
+ </fonts>
+ </renderer>
+ </renderers>
+</fop>
diff --git a/lib/erl_docgen/priv/xsl/Makefile b/lib/erl_docgen/priv/xsl/Makefile
index 1510387d72..58589672b8 100644
--- a/lib/erl_docgen/priv/xsl/Makefile
+++ b/lib/erl_docgen/priv/xsl/Makefile
@@ -42,7 +42,8 @@ XSL_FILES = \
db_pdf_params.xsl \
db_html.xsl \
db_html_params.xsl \
- db_man.xsl
+ db_man.xsl \
+ db_eix.xsl
# ----------------------------------------------------
diff --git a/lib/erl_docgen/priv/xsl/db_html.xsl b/lib/erl_docgen/priv/xsl/db_html.xsl
index 4bc5abb364..ab5f24c406 100644
--- a/lib/erl_docgen/priv/xsl/db_html.xsl
+++ b/lib/erl_docgen/priv/xsl/db_html.xsl
@@ -578,8 +578,22 @@
<xsl:param name="curModule"/>
<html>
<head>
- <link rel="stylesheet" href="{$topdocdir}/otp_doc.css" type="text/css"/>
- <title>Erlang -- <xsl:value-of select="header/title"/></title>
+ <xsl:choose>
+ <xsl:when test="string-length($stylesheet) > 0">
+ <link rel="stylesheet" href="{$topdocdir}/{$stylesheet}" type="text/css"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <link rel="stylesheet" href="{$topdocdir}/otp_doc.css" type="text/css"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:choose>
+ <xsl:when test="string-length($winprefix) > 0">
+ <title><xsl:value-of select="$winprefix"/> -- <xsl:value-of select="header/title"/></title>
+ </xsl:when>
+ <xsl:otherwise>
+ <title>Erlang -- <xsl:value-of select="header/title"/></title>
+ </xsl:otherwise>
+ </xsl:choose>
</head>
<body bgcolor="white" text="#000000" link="#0000ff" vlink="#ff00ff" alink="#ff0000">
@@ -719,7 +733,14 @@
<xsl:template name="menu_top">
- <img alt="Erlang logo" src="{$topdocdir}/erlang-logo.png"/>
+ <xsl:choose>
+ <xsl:when test="string-length($logo) > 0">
+ <img alt="Erlang logo" src="{$topdocdir}/{$logo}"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <img alt="Erlang logo" src="{$topdocdir}/erlang-logo.png"/>
+ </xsl:otherwise>
+ </xsl:choose>
<br/>
<small>
<xsl:if test="boolean(/book/parts/part)">
@@ -731,7 +752,14 @@
<xsl:if test="boolean(/book/releasenotes)">
<a href="release_notes.html">Release Notes</a><br/>
</xsl:if>
- <a href="{$pdfdir}/{$appname}-{$appver}.pdf">PDF</a><br/>
+ <xsl:choose>
+ <xsl:when test="string-length($pdfname) > 0">
+ <a href="{$pdfdir}/{$pdfname}.pdf">PDF</a><br/>
+ </xsl:when>
+ <xsl:otherwise>
+ <a href="{$pdfdir}/{$appname}-{$appver}.pdf">PDF</a><br/>
+ </xsl:otherwise>
+ </xsl:choose>
<a href="{$topdocdir}/index.html">Top</a>
</small>
</xsl:template>
diff --git a/lib/erl_docgen/priv/xsl/db_pdf.xsl b/lib/erl_docgen/priv/xsl/db_pdf.xsl
index da96052462..c846bdbf34 100644
--- a/lib/erl_docgen/priv/xsl/db_pdf.xsl
+++ b/lib/erl_docgen/priv/xsl/db_pdf.xsl
@@ -650,7 +650,7 @@
<fo:flow flow-name="xsl-region-body">
<fo:block xsl:use-attribute-sets="cover.logo">
- <fo:external-graphic src="{$docgen}/priv/images/erlang-logo.gif"/>
+ <fo:external-graphic src="{$logo}"/>
</fo:block>
<fo:block xsl:use-attribute-sets="cover.title" id="cover-page">
<xsl:apply-templates/>
@@ -1102,11 +1102,13 @@
<xsl:template match="taglist/item">
<xsl:param name="partnum"/>
- <fo:block xsl:use-attribute-sets="tagitem">
- <xsl:apply-templates>
- <xsl:with-param name="partnum" select="$partnum"/>
- </xsl:apply-templates>
- </fo:block>
+ <fo:block-container>
+ <fo:block xsl:use-attribute-sets="tagitem">
+ <xsl:apply-templates>
+ <xsl:with-param name="partnum" select="$partnum"/>
+ </xsl:apply-templates>
+ </fo:block>
+ </fo:block-container>
</xsl:template>
diff --git a/lib/erl_docgen/priv/xsl/db_pdf_params.xsl b/lib/erl_docgen/priv/xsl/db_pdf_params.xsl
index 4d9c08d0c3..2e3b22acf4 100644
--- a/lib/erl_docgen/priv/xsl/db_pdf_params.xsl
+++ b/lib/erl_docgen/priv/xsl/db_pdf_params.xsl
@@ -3,7 +3,7 @@
#
# %CopyrightBegin%
#
- # Copyright Ericsson AB 2009-2011. All Rights Reserved.
+ # Copyright Ericsson AB 2009-2012. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -52,7 +52,7 @@
<!-- XSL-FO properties -->
<xsl:attribute-set name="caption">
- <xsl:attribute name="font-family">sans-serif</xsl:attribute>
+ <xsl:attribute name="font-family">DejaVuSans, sans-serif</xsl:attribute>
<xsl:attribute name="font-size">0.8em</xsl:attribute>
<xsl:attribute name="font-weight">bold</xsl:attribute>
<xsl:attribute name="keep-with-previous.within-page">always</xsl:attribute>
@@ -61,7 +61,7 @@
</xsl:attribute-set>
<xsl:attribute-set name="pre">
- <xsl:attribute name="font-family">monospace</xsl:attribute>
+ <xsl:attribute name="font-family">DejaVuSansMono, monospace</xsl:attribute>
<xsl:attribute name="font-size">0.8em</xsl:attribute>
<xsl:attribute name="keep-together.within-page">auto</xsl:attribute>
<xsl:attribute name="linefeed-treatment">preserve</xsl:attribute>
@@ -87,7 +87,7 @@
<xsl:attribute-set name="cover.title">
<xsl:attribute name="border-before-style">solid</xsl:attribute>
<xsl:attribute name="border-before-width">10pt</xsl:attribute>
- <xsl:attribute name="border-color">#960003</xsl:attribute>
+ <xsl:attribute name="border-color"><xsl:value-of select="$pdfcolor"/></xsl:attribute>
<xsl:attribute name="font-size">2.3em</xsl:attribute>
<xsl:attribute name="padding-before">0.5em</xsl:attribute>
<xsl:attribute name="text-align">end</xsl:attribute>
@@ -101,7 +101,7 @@
<xsl:attribute-set name="cover.inner.copyright">
<xsl:attribute name="border-before-style">solid</xsl:attribute>
<xsl:attribute name="border-before-width">1pt</xsl:attribute>
- <xsl:attribute name="border-color">#960003</xsl:attribute>
+ <xsl:attribute name="border-color"><xsl:value-of select="$pdfcolor"/></xsl:attribute>
<xsl:attribute name="font-weight">bold</xsl:attribute>
<xsl:attribute name="padding-before">0.5em</xsl:attribute>
<xsl:attribute name="space-before">200mm</xsl:attribute>
@@ -160,9 +160,9 @@
<xsl:attribute-set name="h1">
<xsl:attribute name="border-after-style">solid</xsl:attribute>
<xsl:attribute name="border-after-width">1pt</xsl:attribute>
- <xsl:attribute name="border-color">#960003</xsl:attribute>
+ <xsl:attribute name="border-color"><xsl:value-of select="$pdfcolor"/></xsl:attribute>
<xsl:attribute name="break-before">page</xsl:attribute>
- <xsl:attribute name="font-family">sans-serif</xsl:attribute>
+ <xsl:attribute name="font-family">DejaVuSans, sans-serif</xsl:attribute>
<xsl:attribute name="font-size">1.83em</xsl:attribute>
<xsl:attribute name="font-weight">normal</xsl:attribute>
<xsl:attribute name="space-after">1em</xsl:attribute>
@@ -171,7 +171,7 @@
</xsl:attribute-set>
<xsl:attribute-set name="h2">
- <xsl:attribute name="font-family">sans-serif</xsl:attribute>
+ <xsl:attribute name="font-family">DejaVuSans, sans-serif</xsl:attribute>
<xsl:attribute name="font-size">1.5em</xsl:attribute>
<xsl:attribute name="font-weight">normal</xsl:attribute>
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
@@ -180,7 +180,7 @@
</xsl:attribute-set>
<xsl:attribute-set name="h3">
- <xsl:attribute name="font-family">sans-serif</xsl:attribute>
+ <xsl:attribute name="font-family">DejaVuSans, sans-serif</xsl:attribute>
<xsl:attribute name="font-size">1.33em</xsl:attribute>
<xsl:attribute name="font-weight">normal</xsl:attribute>
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
@@ -189,7 +189,7 @@
</xsl:attribute-set>
<xsl:attribute-set name="h4">
- <xsl:attribute name="font-family">sans-serif</xsl:attribute>
+ <xsl:attribute name="font-family">DejaVuSans, sans-serif</xsl:attribute>
<xsl:attribute name="font-size">1.17em</xsl:attribute>
<xsl:attribute name="font-weight">normal</xsl:attribute>
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
@@ -198,7 +198,7 @@
</xsl:attribute-set>
<xsl:attribute-set name="h5">
- <xsl:attribute name="font-family">sans-serif</xsl:attribute>
+ <xsl:attribute name="font-family">DejaVuSans, sans-serif</xsl:attribute>
<xsl:attribute name="font-size">1em</xsl:attribute>
<xsl:attribute name="font-weight">bold</xsl:attribute>
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
@@ -207,7 +207,7 @@
</xsl:attribute-set>
<xsl:attribute-set name="h6">
- <xsl:attribute name="font-family">sans-serif</xsl:attribute>
+ <xsl:attribute name="font-family">DejaVuSans, sans-serif</xsl:attribute>
<xsl:attribute name="font-size">0.83em</xsl:attribute>
<xsl:attribute name="font-weight">bold</xsl:attribute>
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
@@ -226,21 +226,21 @@
<xsl:attribute-set name="page-header">
<xsl:attribute name="border-after-style">solid</xsl:attribute>
<xsl:attribute name="border-after-width">2pt</xsl:attribute>
- <xsl:attribute name="border-color">#960003</xsl:attribute>
- <xsl:attribute name="font-family">sans-serif</xsl:attribute>
+ <xsl:attribute name="border-color"><xsl:value-of select="$pdfcolor"/></xsl:attribute>
+ <xsl:attribute name="font-family">DejaVuSans, sans-serif</xsl:attribute>
<xsl:attribute name="font-size">0.9em</xsl:attribute>
<xsl:attribute name="font-weight">bold</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="page-footer">
- <xsl:attribute name="font-family">sans-serif</xsl:attribute>
+ <xsl:attribute name="font-family">DejaVuSans, sans-serif</xsl:attribute>
<xsl:attribute name="font-size">0.9em</xsl:attribute>
<xsl:attribute name="font-weight">bold</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="code">
<xsl:attribute name="background-color">#e0e0ff</xsl:attribute>
- <xsl:attribute name="font-family">monospace</xsl:attribute>
+ <xsl:attribute name="font-family">DejaVuSansMono, monospace</xsl:attribute>
<xsl:attribute name="font-size">0.8em</xsl:attribute>
<xsl:attribute name="keep-together.within-page">auto</xsl:attribute>
<xsl:attribute name="linefeed-treatment">preserve</xsl:attribute>
@@ -303,7 +303,7 @@
<xsl:attribute-set name="module-name">
<xsl:attribute name="border-after-style">solid</xsl:attribute>
<xsl:attribute name="border-after-width">1pt</xsl:attribute>
- <xsl:attribute name="font-family">sans-serif</xsl:attribute>
+ <xsl:attribute name="font-family">DejaVuSans, sans-serif</xsl:attribute>
<xsl:attribute name="font-size">1.5em</xsl:attribute>
<xsl:attribute name="font-weight">normal</xsl:attribute>
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
@@ -313,7 +313,7 @@
<xsl:attribute-set name="function-name">
<xsl:attribute name="font-weight">bold</xsl:attribute>
- <xsl:attribute name="font-family">monospace</xsl:attribute>
+ <xsl:attribute name="font-family">DejaVuSansMono, monospace</xsl:attribute>
<!-- xsl:attribute name="font-size">0.8em</xsl:attribute -->
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
<xsl:attribute name="space-after">0.25em</xsl:attribute>
@@ -401,7 +401,7 @@
</xsl:attribute-set>
<xsl:attribute-set name="caption">
- <xsl:attribute name="font-family">sans-serif</xsl:attribute>
+ <xsl:attribute name="font-family">DejaVuSans, sans-serif</xsl:attribute>
<xsl:attribute name="font-size">0.8em</xsl:attribute>
<xsl:attribute name="font-weight">bold</xsl:attribute>
<xsl:attribute name="keep-with-previous.within-page">always</xsl:attribute>
diff --git a/lib/erl_docgen/src/Makefile b/lib/erl_docgen/src/Makefile
index 6c8b438b25..ef96f5dbf2 100644
--- a/lib/erl_docgen/src/Makefile
+++ b/lib/erl_docgen/src/Makefile
@@ -78,10 +78,10 @@ docs:
# ----------------------------------------------------
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
# ----------------------------------------------------
# Release Target
diff --git a/lib/erl_docgen/src/docgen_edoc_xml_cb.erl b/lib/erl_docgen/src/docgen_edoc_xml_cb.erl
index cbaa93a15d..e3cc354206 100644
--- a/lib/erl_docgen/src/docgen_edoc_xml_cb.erl
+++ b/lib/erl_docgen/src/docgen_edoc_xml_cb.erl
@@ -1,19 +1,20 @@
-%% ``The contents of this file are subject to the Erlang Public License,
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2012. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
+%% 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 expressed or implied. See
-%% the Licence for the specific language governing rights and limitations
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
%% under the License.
%%
-%% The Initial Developer of the Original Code is Ericsson AB.
-%% Portions created by Ericsson are Copyright 1999-2006, Ericsson AB.
-%% All Rights Reserved.��
-%%
-%% $Id$
+%% %CopyrightEnd%
%%
-module(docgen_edoc_xml_cb).
@@ -39,12 +40,14 @@
module(Element, Opts) ->
SortP = proplists:get_value(sort_functions, Opts, true),
XML = layout_module(Element, SortP),
- xmerl:export_simple([XML], docgen_xmerl_xml_cb, []).
+ RootAttributes = root_attributes(Element, Opts),
+ xmerl:export_simple([XML], docgen_xmerl_xml_cb, RootAttributes).
%% CHAPTER
-overview(Element, _Opts) ->
+overview(Element, Opts) ->
XML = layout_chapter(Element),
- xmerl:export_simple([XML], docgen_xmerl_xml_cb, []).
+ RootAttributes = root_attributes(Element, Opts),
+ xmerl:export_simple([XML], docgen_xmerl_xml_cb, RootAttributes).
%%--Internal functions--------------------------------------------------
@@ -99,6 +102,16 @@ layout_module(#xmlElement{name = module, content = Es}=E, SortP) ->
?NL,Authors]
}.
+root_attributes(Element, Opts) ->
+ Encoding = case get_attrval(encoding, Element) of
+ "" ->
+ DefaultEncoding = epp:default_encoding(),
+ proplists:get_value(encoding, Opts, DefaultEncoding);
+ Enc ->
+ Enc
+ end,
+ [#xmlAttribute{name=encoding, value=Encoding}].
+
layout_chapter(#xmlElement{name=overview, content=Es}) ->
Title = get_text(title, Es),
Header = {header, [
diff --git a/lib/erl_docgen/src/docgen_xmerl_xml_cb.erl b/lib/erl_docgen/src/docgen_xmerl_xml_cb.erl
index 884932ed12..d713b61c0a 100644
--- a/lib/erl_docgen/src/docgen_xmerl_xml_cb.erl
+++ b/lib/erl_docgen/src/docgen_xmerl_xml_cb.erl
@@ -1,19 +1,20 @@
-%% ``The contents of this file are subject to the Erlang Public License,
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2012. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
+%% 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 expressed or implied. See
-%% the Licence for the specific language governing rights and limitations
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
%% under the License.
%%
-%% The Initial Developer of the Original Code is Ericsson AB.
-%% Portions created by Ericsson are Copyright 1999-2006, Ericsson AB.
-%% All Rights Reserved.��
-%%
-%% $Id$
+%% %CopyrightEnd%
%%
-module(docgen_xmerl_xml_cb).
@@ -35,9 +36,14 @@
'#xml-inheritance#'() ->
[xmerl_xml].
-'#root#'(Data, _Attrs, [], _E) ->
+'#root#'(Data, Attrs, [], _E) ->
+ Encoding =
+ case [E || #xmlAttribute{name = encoding, value = E} <- Attrs] of
+ [E] -> E;
+ _ -> atom_to_list(epp:default_encoding())
+ end,
["<",DTD,">"] = hd(hd(Data)),
- ["<?xml version=\"1.0\" encoding=\"latin1\" ?>\n",
+ ["<?xml version=\"1.0\" encoding=\"",Encoding,"\" ?>\n",
"<!DOCTYPE "++DTD++" SYSTEM \""++DTD++".dtd\">\n",
Data].
diff --git a/lib/erl_docgen/vsn.mk b/lib/erl_docgen/vsn.mk
index b05df254a6..a2262198dc 100644
--- a/lib/erl_docgen/vsn.mk
+++ b/lib/erl_docgen/vsn.mk
@@ -1,2 +1 @@
-ERL_DOCGEN_VSN = 0.3.2
-
+ERL_DOCGEN_VSN = 0.3.4
diff --git a/lib/erl_interface/aclocal.m4 b/lib/erl_interface/aclocal.m4
index b1cf1fe404..918e30a886 100644
--- a/lib/erl_interface/aclocal.m4
+++ b/lib/erl_interface/aclocal.m4
@@ -740,11 +740,16 @@ dnl Try to find POSIX threads
dnl The usual pthread lib...
AC_CHECK_LIB(pthread, pthread_create, THR_LIBS="-lpthread")
-dnl FreeBSD has pthreads in special c library, c_r...
+dnl Very old versions of FreeBSD have pthreads in special c library, c_r...
if test "x$THR_LIBS" = "x"; then
AC_CHECK_LIB(c_r, pthread_create, THR_LIBS="-lc_r")
fi
+dnl QNX has pthreads in standard C library
+ if test "x$THR_LIBS" = "x"; then
+ AC_CHECK_FUNC(pthread_create, THR_LIBS="none_needed")
+ fi
+
dnl On ofs1 the '-pthread' switch should be used
if test "x$THR_LIBS" = "x"; then
AC_MSG_CHECKING([if the '-pthread' switch can be used])
@@ -765,6 +770,9 @@ dnl On ofs1 the '-pthread' switch should be used
if test "x$THR_LIBS" != "x"; then
THR_DEFS="$THR_DEFS -D_THREAD_SAFE -D_REENTRANT -DPOSIX_THREADS"
THR_LIB_NAME=pthread
+ if test "x$THR_LIBS" = "xnone_needed"; then
+ THR_LIBS=
+ fi
case $host_os in
solaris*)
THR_DEFS="$THR_DEFS -D_POSIX_PTHREAD_SEMANTICS" ;;
@@ -1841,6 +1849,31 @@ case $erl_gethrvtime in
esac
])dnl
+dnl ----------------------------------------------------------------------
+dnl
+dnl LM_TRY_ENABLE_CFLAG
+dnl
+dnl
+dnl Tries a CFLAG and sees if it can be enabled without compiler errors
+dnl $1: textual cflag to add
+dnl $2: variable to store the modified CFLAG in
+dnl Usage example LM_TRY_ENABLE_CFLAG([-Werror=return-type], [CFLAGS])
+dnl
+dnl
+AC_DEFUN([LM_TRY_ENABLE_CFLAG], [
+ AC_MSG_CHECKING([if we can add $1 to $2 (via CFLAGS)])
+ saved_CFLAGS=$CFLAGS;
+ CFLAGS="$1 $$2";
+ AC_TRY_COMPILE([],[return 0;],can_enable_flag=true,can_enable_flag=false)
+ CFLAGS=$saved_CFLAGS;
+ if test "X$can_enable_flag" = "Xtrue"; then
+ AC_MSG_RESULT([yes])
+ AS_VAR_SET($2, "$1 $$2")
+ else
+ AC_MSG_RESULT([no])
+ fi
+])
+
dnl ERL_TRY_LINK_JAVA(CLASSES, FUNCTION-BODY
dnl [ACTION_IF_FOUND [, ACTION-IF-NOT-FOUND]])
dnl Freely inspired by AC_TRY_LINK. (Maybe better to create a
diff --git a/lib/erl_interface/configure.in b/lib/erl_interface/configure.in
index c958f80065..d511f2e240 100644
--- a/lib/erl_interface/configure.in
+++ b/lib/erl_interface/configure.in
@@ -1,7 +1,7 @@
# -*- Autoconf -*-
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2000-2011. All Rights Reserved.
+# Copyright Ericsson AB 2000-2012. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -79,7 +79,7 @@ AC_ARG_ENABLE(threads,
no) threads_disabled=yes ;;
*) threads_disabled=no ;;
esac ],
-[ threads_disabled=no ])
+[ threads_disabled=maybe ])
dnl ----------------------------------------------------------------------
dnl Checks for programs
@@ -237,12 +237,16 @@ AC_SUBST(THR_DEFS)
AC_SUBST(EI_THREADS)
case "$threads_disabled" in
- no)
+ no|maybe)
LM_CHECK_THR_LIB
case "$THR_LIB_NAME" in
"")
EI_THREADS="false"
+ # Fail if --enable-threads given and no threads found
+ if test "x$threads_disabled" = "xno"; then
+ AC_MSG_ERROR(No threads support found)
+ fi
;;
win32_threads)
EI_THREADS="true"
@@ -269,6 +273,8 @@ esac
AC_SUBST(WFLAGS)
if test "x$GCC" = xyes; then
+ # Treat certain GCC warnings as errors
+ LM_TRY_ENABLE_CFLAG([-Werror=return-type], [WERRORFLAGS])
WFLAGS="-Wall -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Winline"
# check which GCC version
GCC_VERSION=`$CC -v 2>&1 | sed -n 's/gcc version //p'`
@@ -283,8 +289,10 @@ if test "x$GCC" = xyes; then
*)
WFLAGS="$WFLAGS -fno-strict-aliasing";;
esac
+ CFLAGS="$WERRORFLAGS $CFLAGS"
else
WFLAGS=""
+ WERRORFLAGS=""
fi
# ---------------------------------------------------------------------------
diff --git a/lib/erl_interface/doc/src/notes.xml b/lib/erl_interface/doc/src/notes.xml
index 6791c39c7d..f0a9b336ff 100644
--- a/lib/erl_interface/doc/src/notes.xml
+++ b/lib/erl_interface/doc/src/notes.xml
@@ -30,6 +30,24 @@
</header>
<p>This document describes the changes made to the Erl_interface application.</p>
+<section><title>Erl_Interface 3.7.9</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>Teach lib/erl_interface/configure.in to look for
+ pthreads support in libc (where it can be found on
+ QNX)</p> <p>A minor tweak such that this configure
+ *fails* if you pass --enable-threads and no pthreads
+ support can be found.</p> (Thanks to Per Hedeland)
+ <p>
+ Own Id: OTP-10581</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erl_Interface 3.7.8</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/erl_interface/src/Makefile b/lib/erl_interface/src/Makefile
index 5f0367bec1..03e2ce14f0 100644
--- a/lib/erl_interface/src/Makefile
+++ b/lib/erl_interface/src/Makefile
@@ -22,10 +22,11 @@
# FIXME let configure put in this last part TARGET
+include $(ERL_TOP)/make/output.mk
include $(ERL_TOP)/make/target.mk
debug opt shared purify quantify purecov gcov:
- $(MAKE) -f $(TARGET)/Makefile TYPE=$@
+ $(make_verbose)$(MAKE) -f $(TARGET)/Makefile TYPE=$@
clean depend docs release release_docs tests release_tests check:
- $(MAKE) -f $(TARGET)/Makefile $@
+ $(make_verbose)$(MAKE) -f $(TARGET)/Makefile $@
diff --git a/lib/erl_interface/src/Makefile.in b/lib/erl_interface/src/Makefile.in
index cb41391fe9..ebacc1cee0 100644
--- a/lib/erl_interface/src/Makefile.in
+++ b/lib/erl_interface/src/Makefile.in
@@ -38,6 +38,8 @@ TARGET = @TARGET@
include ../vsn.mk
include $(TARGET)/eidefs.mk
+include $(ERL_TOP)/make/output.mk
+
USING_MINGW=@MIXED_CYGWIN_MINGW@
USING_MSYS_VC==@MIXED_MSYS_VC@
USING_CYGWIN_VC==@MIXED_MSYS_VC@
@@ -98,6 +100,12 @@ LD = @LD@
AR = @AR@
RANLIB = @RANLIB@
+ifeq ($(V),0)
+AR_FLAGS=rc
+else
+AR_FLAGS=rcv
+endif
+
INCFLAGS = -I. -I../include -Iconnect -Iencode -Idecode -Imisc -Iepmd \
-Iregistry -I$(TARGET)
@@ -552,16 +560,18 @@ distclean: clean
ifeq ($(findstring vxworks,$(TARGET)),vxworks)
$(TARGET)/config.h:
- echo "/* Generated by Makefile */" > $@
- echo "#define HAVE_STRERROR 1" >> $@
- echo "#define HAVE_SOCKLEN_T 1" >> $@
+ $(gen_verbose)
+ $(V_at)echo "/* Generated by Makefile */" > $@
+ $(V_at)echo "#define HAVE_STRERROR 1" >> $@
+ $(V_at)echo "#define HAVE_SOCKLEN_T 1" >> $@
endif
ifeq ($(findstring ose,$(TARGET)),ose)
$(TARGET)/config.h:
- echo "/* Generated by Makefile */" > $@
- echo "#define HAVE_STRERROR 1" >> $@
- echo "#define HAVE_SOCKLEN_T 1" >> $@
+ $(gen_verbose)
+ $(V_at)echo "/* Generated by Makefile */" > $@
+ $(V_at)echo "#define HAVE_STRERROR 1" >> $@
+ $(V_at)echo "#define HAVE_SOCKLEN_T 1" >> $@
endif
###########################################################################
@@ -569,19 +579,19 @@ endif
###########################################################################
$(ST_OBJDIR)/%.o: %.c
- $(CC) $(CFLAGS) -c $< -o $@
+ $(V_CC) $(CFLAGS) -c $< -o $@
$(MT_OBJDIR)/%.o: %.c
- $(CC) $(MTFLAG) $(CFLAGS) $(THR_DEFS) -c $< -o $@
+ $(V_CC) $(MTFLAG) $(CFLAGS) $(THR_DEFS) -c $< -o $@
$(MD_OBJDIR)/%.o: %.c
- $(CC) -MD $(CFLAGS) $(THR_DEFS) -c $< -o $@
+ $(V_CC) -MD $(CFLAGS) $(THR_DEFS) -c $< -o $@
$(MD_OBJDIR)/%.o: %.c
- $(CC) -MD $(CFLAGS) $(THR_DEFS) -c $< -o $@
+ $(V_CC) -MD $(CFLAGS) $(THR_DEFS) -c $< -o $@
$(MDD_OBJDIR)/%.o: %.c
- $(CC) -MDd $(CFLAGS) $(THR_DEFS) -c $< -o $@
+ $(V_CC) -MDd $(CFLAGS) $(THR_DEFS) -c $< -o $@
###########################################################################
# Create directories
@@ -598,67 +608,67 @@ ifeq ($(TARGET),win32)
# Windows archive creation
$(ST_EILIB) : $(ST_EIOBJECTS)
- $(AR) -out:$@ $(ST_EIOBJECTS)
- $(RANLIB) $@
+ $(V_AR) -out:$@ $(ST_EIOBJECTS)
+ $(V_RANLIB) $@
$(ST_ERLLIB) : $(ST_ERLOBJECTS)
- $(AR) -out:$@ $(ST_ERLOBJECTS)
- $(RANLIB) $@
+ $(V_AR) -out:$@ $(ST_ERLOBJECTS)
+ $(V_RANLIB) $@
$(MT_EILIB) : $(MT_EIOBJECTS)
- $(AR) -out:$@ $(MT_EIOBJECTS)
- $(RANLIB) $@
+ $(V_AR) -out:$@ $(MT_EIOBJECTS)
+ $(V_RANLIB) $@
$(MT_ERLLIB) : $(MT_ERLOBJECTS)
- $(AR) -out:$@ $(MT_ERLOBJECTS)
- $(RANLIB) $@
+ $(V_AR) -out:$@ $(MT_ERLOBJECTS)
+ $(V_RANLIB) $@
$(MD_EILIB) : $(MD_EIOBJECTS)
- $(AR) -out:$@ $(MD_EIOBJECTS)
- $(RANLIB) $@
+ $(V_AR) -out:$@ $(MD_EIOBJECTS)
+ $(V_RANLIB) $@
$(MD_ERLLIB) : $(MD_ERLOBJECTS)
- $(AR) -out:$@ $(MD_ERLOBJECTS)
- $(RANLIB) $@
+ $(V_AR) -out:$@ $(MD_ERLOBJECTS)
+ $(V_RANLIB) $@
$(MDD_EILIB) : $(MDD_EIOBJECTS)
- $(AR) -out:$@ $(MDD_EIOBJECTS)
- $(RANLIB) $@
+ $(V_AR) -out:$@ $(MDD_EIOBJECTS)
+ $(V_RANLIB) $@
$(MDD_ERLLIB) : $(MDD_ERLOBJECTS)
- $(AR) -out:$@ $(MDD_ERLOBJECTS)
- $(RANLIB) $@
+ $(V_AR) -out:$@ $(MDD_ERLOBJECTS)
+ $(V_RANLIB) $@
else
# Unix archive creation
$(ST_EILIB) : $(ST_EIOBJECTS)
- rm -f $@
- $(AR) rcv $@ $(ST_EIOBJECTS)
+ $(V_at)rm -f $@
+ $(V_AR) $(AR_FLAGS) $@ $(ST_EIOBJECTS)
ifdef RANLIB
- $(RANLIB) $@
+ $(V_RANLIB) $@
endif
$(ST_ERLLIB) : $(ST_ERLOBJECTS)
- rm -f $@
- $(AR) rcv $@ $(ST_ERLOBJECTS)
+ $(V_at)rm -f $@
+ $(V_AR) $(AR_FLAGS) $@ $(ST_ERLOBJECTS)
ifdef RANLIB
- $(RANLIB) $@
+ $(V_RANLIB) $@
endif
$(MT_EILIB) : $(MT_EIOBJECTS)
- rm -f $@
- $(AR) rcv $@ $(MT_EIOBJECTS)
+ $(V_at)rm -f $@
+ $(V_AR) $(AR_FLAGS) $@ $(MT_EIOBJECTS)
ifdef RANLIB
- $(RANLIB) $@
+ $(V_RANLIB) $@
endif
$(MT_ERLLIB) : $(MT_ERLOBJECTS)
- rm -f $@
- $(AR) rcv $@ $(MT_ERLOBJECTS)
+ $(V_at)rm -f $@
+ $(V_AR) $(AR_FLAGS) $@ $(MT_ERLOBJECTS)
ifdef RANLIB
- $(RANLIB) $@
+ $(V_RANLIB) $@
endif
endif
@@ -669,18 +679,18 @@ endif
ifeq ($(TARGET),win32)
$(ERL_CALL): $(ERLCALL) ../include/ei.h $(MD_EILIB)
- $(PURIFY) $(CC) -MD $(PROG_CFLAGS) $(THR_DEFS) -o $@ $(ERLCALL) \
+ $(ld_verbose)$(PURIFY) $(CC) -MD $(PROG_CFLAGS) $(THR_DEFS) -o $@ $(ERLCALL) \
-L$(OBJDIR) -lei_md $(THR_LIBS) $(LIBS) -lsocket
else
ifeq ($(findstring vxworks,$(TARGET)),vxworks)
$(ERL_CALL): $(ST_OBJDIR)/erl_call.o $(ST_OBJDIR)/erl_start.o ../include/ei.h $(ST_EILIB)
- $(LD) -r -d -o $@ $(ST_OBJDIR)/erl_call.o $(ST_OBJDIR)/erl_start.o -L$(OBJDIR) -lei $(LIBS)
+ $(V_LD) -r -d -o $@ $(ST_OBJDIR)/erl_call.o $(ST_OBJDIR)/erl_start.o -L$(OBJDIR) -lei $(LIBS)
$(ST_OBJDIR)/erl_call.o: prog/erl_call.c
- $(CC) $(CFLAGS) -c $< -o $@
+ $(V_CC) $(CFLAGS) -c $< -o $@
$(ST_OBJDIR)/erl_start.o: prog/erl_start.c
- $(CC) $(CFLAGS) -c $< -o $@
+ $(V_CC) $(CFLAGS) -c $< -o $@
else
ifeq ($(findstring ose,$(TARGET)),ose)
@@ -688,11 +698,11 @@ $(ERL_CALL):
else
ifdef THR_DEFS
$(ERL_CALL): $(ERLCALL) ../include/ei.h $(MT_EILIB)
- $(PURIFY) $(CC) $(PROG_CFLAGS) $(THR_DEFS) $(LDFLAGS) -o $@ $(ERLCALL) \
+ $(ld_verbose)$(PURIFY) $(CC) $(PROG_CFLAGS) $(THR_DEFS) $(LDFLAGS) -o $@ $(ERLCALL) \
-L$(OBJDIR) -lei $(THR_LIBS) $(LIBS)
else
$(ERL_CALL): $(ERLCALL) ../include/ei.h $(ST_EILIB)
- $(PURIFY) $(CC) $(PROG_CFLAGS) $(LDFLAGS) -o $@ $(ERLCALL) \
+ $(ld_verbose)$(PURIFY) $(CC) $(PROG_CFLAGS) $(LDFLAGS) -o $@ $(ERLCALL) \
-L$(OBJDIR) -lei $(LIBS)
endif
endif
@@ -707,36 +717,36 @@ check: $(FAKE_TARGETS)
ifndef THR_DEFS
$(ST_OBJDIR)/erl_fake_prog_st$(EXE): prog/erl_fake_prog.c $(ST_ERLLIB) $(ST_EILIB)
- $(CC) $(PROG_CFLAGS) -o $@ $< -L$(OBJDIR) -lerl_interface -lei \
+ $(V_CC) $(PROG_CFLAGS) -o $@ $< -L$(OBJDIR) -lerl_interface -lei \
$(LIBS)
$(ST_OBJDIR)/ei_fake_prog_st$(EXE): prog/ei_fake_prog.c $(ST_EILIB)
- $(CC) $(PROG_CFLAGS) -o $@ $< -L$(OBJDIR) -lei $(LIBS)
+ $(V_CC) $(PROG_CFLAGS) -o $@ $< -L$(OBJDIR) -lei $(LIBS)
$(ST_OBJDIR)/erl_fake_prog_cxx_st$(EXE): prog/erl_fake_prog.c \
$(ST_ERLLIB) $(ST_EILIB)
- $(CC) $(PROG_CFLAGS) -o $@ -xc++ $< -L$(OBJDIR) \
+ $(V_CC) $(PROG_CFLAGS) -o $@ -xc++ $< -L$(OBJDIR) \
-lerl_interface -lei $(LIBS)
$(ST_OBJDIR)/ei_fake_prog_cxx_st$(EXE): prog/ei_fake_prog.c $(ST_EILIB)
- $(CC) $(PROG_CFLAGS) -o $@ -xc++ $< -L$(OBJDIR) -lei $(LIBS)
+ $(V_CC) $(PROG_CFLAGS) -o $@ -xc++ $< -L$(OBJDIR) -lei $(LIBS)
else
$(ST_OBJDIR)/erl_fake_prog_st$(EXE): prog/erl_fake_prog.c $(ST_ERLLIB) $(ST_EILIB)
- $(CC) $(PROG_CFLAGS) -o $@ $< -L$(OBJDIR) -lerl_interface_st -lei_st \
+ $(V_CC) $(PROG_CFLAGS) -o $@ $< -L$(OBJDIR) -lerl_interface_st -lei_st \
$(LIBS)
$(ST_OBJDIR)/ei_fake_prog_st$(EXE): prog/ei_fake_prog.c $(ST_EILIB)
- $(CC) $(PROG_CFLAGS) -o $@ $< -L$(OBJDIR) -lei_st $(LIBS)
+ $(V_CC) $(PROG_CFLAGS) -o $@ $< -L$(OBJDIR) -lei_st $(LIBS)
$(ST_OBJDIR)/erl_fake_prog_cxx_st$(EXE): prog/erl_fake_prog.c \
$(ST_ERLLIB) $(ST_EILIB)
- $(CC) $(PROG_CFLAGS) -o $@ -xc++ $< -L$(OBJDIR) \
+ $(V_CC) $(PROG_CFLAGS) -o $@ -xc++ $< -L$(OBJDIR) \
-lerl_interface_st -lei_st $(LIBS)
$(ST_OBJDIR)/ei_fake_prog_cxx_st$(EXE): prog/ei_fake_prog.c $(ST_EILIB)
- $(CC) $(PROG_CFLAGS) -o $@ -xc++ $< -L$(OBJDIR) -lei_st $(LIBS)
+ $(V_CC) $(PROG_CFLAGS) -o $@ -xc++ $< -L$(OBJDIR) -lei_st $(LIBS)
endif
@@ -744,63 +754,63 @@ endif
$(MT_OBJDIR)/erl_fake_prog_mt$(EXE): prog/erl_fake_prog.c \
$(MT_ERLLIB) $(MT_EILIB)
- $(CC) $(MTFLAG) $(PROG_CFLAGS) $(THR_DEFS) -o $@ $< -L$(OBJDIR) \
+ $(V_CC) $(MTFLAG) $(PROG_CFLAGS) $(THR_DEFS) -o $@ $< -L$(OBJDIR) \
-lerl_interface -lei $(THR_LIBS) $(LIBS)
$(MT_OBJDIR)/ei_fake_prog_mt$(EXE): prog/ei_fake_prog.c $(MT_EILIB)
- $(CC) $(MTFLAG) $(PROG_CFLAGS) $(THR_DEFS) -o $@ $< \
+ $(V_CC) $(MTFLAG) $(PROG_CFLAGS) $(THR_DEFS) -o $@ $< \
-L$(OBJDIR) -lei $(THR_LIBS) $(LIBS)
$(MT_OBJDIR)/erl_fake_prog_mt_cxx$(EXE): prog/erl_fake_prog.c \
$(MT_ERLLIB) $(MT_EILIB)
- $(CC) $(MTFLAG) $(PROG_CFLAGS) $(THR_DEFS) -o $@ -xc++ $< \
+ $(V_CC) $(MTFLAG) $(PROG_CFLAGS) $(THR_DEFS) -o $@ -xc++ $< \
-L$(OBJDIR) -lerl_interface -lei \
$(THR_LIBS) $(LIBS)
$(MT_OBJDIR)/ei_fake_prog_mt_cxx$(EXE): prog/ei_fake_prog.c $(MT_EILIB)
- $(CC) $(MTFLAG) $(PROG_CFLAGS) $(THR_DEFS) -o $@ -xc++ $< \
+ $(V_CC) $(MTFLAG) $(PROG_CFLAGS) $(THR_DEFS) -o $@ -xc++ $< \
-L$(OBJDIR) -lei $(THR_LIBS) $(LIBS)
####
$(MD_OBJDIR)/erl_fake_prog_md$(EXE): prog/erl_fake_prog.c \
$(MD_ERLLIB) $(MD_EILIB)
- $(CC) -MD $(PROG_CFLAGS) $(THR_DEFS) -o $@ $< -L$(OBJDIR) \
+ $(V_CC) -MD $(PROG_CFLAGS) $(THR_DEFS) -o $@ $< -L$(OBJDIR) \
-lerl_interface_r -lei_r $(THR_LIBS) $(LIBS)
$(MD_OBJDIR)/ei_fake_prog_md$(EXE): prog/ei_fake_prog.c $(MD_EILIB)
- $(CC) -MD $(PROG_CFLAGS) $(THR_DEFS) -o $@ $< \
+ $(V_CC) -MD $(PROG_CFLAGS) $(THR_DEFS) -o $@ $< \
-L$(OBJDIR) -lei_r $(THR_LIBS) $(LIBS)
$(MD_OBJDIR)/erl_fake_prog_md_cxx$(EXE): prog/erl_fake_prog.c \
$(MD_ERLLIB) $(MD_EILIB)
- $(CC) -MD $(PROG_CFLAGS) $(THR_DEFS) -o $@ -xc++ $< \
+ $(V_CC) -MD $(PROG_CFLAGS) $(THR_DEFS) -o $@ -xc++ $< \
-L$(OBJDIR) -lerl_interface_r -lei_r \
$(THR_LIBS) $(LIBS)
$(MD_OBJDIR)/ei_fake_prog_md_cxx$(EXE): prog/ei_fake_prog.c $(MD_EILIB)
- $(CC) -MD $(PROG_CFLAGS) $(THR_DEFS) -o $@ -xc++ $< \
+ $(V_CC) -MD $(PROG_CFLAGS) $(THR_DEFS) -o $@ -xc++ $< \
-L$(OBJDIR) -lei_r $(THR_LIBS) $(LIBS)
####
$(MDD_OBJDIR)/erl_fake_prog_mdd$(EXE): prog/erl_fake_prog.c \
$(MDD_ERLLIB) $(MDD_EILIB)
- $(CC) -MDD $(PROG_CFLAGS) $(THR_DEFS) -o $@ $< -L$(OBJDIR) \
+ $(V_CC) -MDD $(PROG_CFLAGS) $(THR_DEFS) -o $@ $< -L$(OBJDIR) \
-lerl_interface_r -lei_r $(THR_LIBS) $(LIBS)
$(MDD_OBJDIR)/ei_fake_prog_mdd$(EXE): prog/ei_fake_prog.c $(MDD_EILIB)
- $(CC) -MDD $(PROG_CFLAGS) $(THR_DEFS) -o $@ $< \
+ $(V_CC) -MDD $(PROG_CFLAGS) $(THR_DEFS) -o $@ $< \
-L$(OBJDIR) -lei_r $(THR_LIBS) $(LIBS)
$(MDD_OBJDIR)/erl_fake_prog_mdd_cxx$(EXE): prog/erl_fake_prog.c \
$(MDD_ERLLIB) $(MDD_EILIB)
- $(CC) -MDD $(PROG_CFLAGS) $(THR_DEFS) -o $@ -xc++ $< \
+ $(V_CC) -MDD $(PROG_CFLAGS) $(THR_DEFS) -o $@ -xc++ $< \
-L$(OBJDIR) -lerl_interface_r -lei_r \
$(THR_LIBS) $(LIBS)
$(MDD_OBJDIR)/ei_fake_prog_mdd_cxx$(EXE): prog/ei_fake_prog.c $(MDD_EILIB)
- $(CC) -MDD $(PROG_CFLAGS) $(THR_DEFS) -o $@ -xc++ $< \
+ $(V_CC) -MDD $(PROG_CFLAGS) $(THR_DEFS) -o $@ -xc++ $< \
-L$(OBJDIR) -lei_r $(THR_LIBS) $(LIBS)
###########################################################################
@@ -808,9 +818,10 @@ $(MDD_OBJDIR)/ei_fake_prog_mdd_cxx$(EXE): prog/ei_fake_prog.c $(MDD_EILIB)
###########################################################################
depend:
- @echo "Generating dependency file depend.mk..."
+ $(gen_verbose)
+ $(V_colon)@echo "Generating dependency file depend.mk..."
@echo "# Generated dependency rules" > depend.mk; \
- $(CC) $(CFLAGS) -MM $(SOURCES) | \
+ $(V_CC) $(CFLAGS) -MM $(SOURCES) | \
sed 's&$(TARGET)&\$$\(TARGET\)&g' | \
sed 's/^.*:/\$$\(ST_OBJDIR\)\/&/' >> depend.mk; \
echo >> depend.mk; \
diff --git a/lib/erl_interface/src/connect/ei_resolve.c b/lib/erl_interface/src/connect/ei_resolve.c
index ba8f8fbce3..79d259b92d 100644
--- a/lib/erl_interface/src/connect/ei_resolve.c
+++ b/lib/erl_interface/src/connect/ei_resolve.c
@@ -186,11 +186,11 @@ static int verify_dns_configuration(void)
* advance: increment buf by n bytes, reduce len by same amount .
*/
#if defined SIZEOF_VOID_P
-#define ALIGNBYTES (SIZEOF_VOID_P - 1)
+#define EI_ALIGNBYTES (SIZEOF_VOID_P - 1)
#else
-#define ALIGNBYTES (sizeof(void*) - 1)
+#define EI_ALIGNBYTES (sizeof(void*) - 1)
#endif
-#define align_buf(buf,len) for (;(((unsigned)buf) & ALIGNBYTES); (buf)++, len--)
+#define align_buf(buf,len) for (;(((unsigned)buf) & EI_ALIGNBYTES); (buf)++, len--)
#define advance_buf(buf,len,n) ((buf)+=(n),(len)-=(n))
/* "and now the tricky part..." */
@@ -282,6 +282,8 @@ static int copy_hostent(struct hostent *dest, const struct hostent *src, char *b
return 0;
}
+#undef EI_ALIGNBYTES
+
/* This function is a pseudo-reentrant version of gethostbyname(). It
* uses locks to serialize the call to the regular (non-reentrant)
* gethostbyname() and then copies the data into the user-provided
diff --git a/lib/erl_interface/test/ei_decode_SUITE.erl b/lib/erl_interface/test/ei_decode_SUITE.erl
index bb44b78854..2c4b6e5541 100644
--- a/lib/erl_interface/test/ei_decode_SUITE.erl
+++ b/lib/erl_interface/test/ei_decode_SUITE.erl
@@ -1,7 +1,8 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -204,15 +205,15 @@ test_ei_decode_misc(Config) when is_list(Config) ->
?line send_term_as_binary(P,foo),
?line send_term_as_binary(P,''),
- ?line send_term_as_binary(P,'������'),
+ ?line send_term_as_binary(P,'ÅÄÖåäö'),
?line send_term_as_binary(P,"foo"),
?line send_term_as_binary(P,""),
- ?line send_term_as_binary(P,"������"),
+ ?line send_term_as_binary(P,"ÅÄÖåäö"),
?line send_term_as_binary(P,<<"foo">>),
?line send_term_as_binary(P,<<>>),
- ?line send_term_as_binary(P,<<"������">>),
+ ?line send_term_as_binary(P,<<"ÅÄÖåäö">>),
% ?line send_term_as_binary(P,{}),
% ?line send_term_as_binary(P,[]),
diff --git a/lib/erl_interface/test/ei_encode_SUITE.erl b/lib/erl_interface/test/ei_encode_SUITE.erl
index cefd33e5f6..537e9cb01c 100644
--- a/lib/erl_interface/test/ei_encode_SUITE.erl
+++ b/lib/erl_interface/test/ei_encode_SUITE.erl
@@ -1,7 +1,8 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -213,19 +214,19 @@ test_ei_encode_misc(Config) when is_list(Config) ->
?line {<<100,0,3,"foo">>,foo} = get_buf_and_term(P),
?line {<<100,0,0,"">>,''} = get_buf_and_term(P),
?line {<<100,0,0,"">>,''} = get_buf_and_term(P),
- ?line {<<100,0,6,"������">>,'������'} = get_buf_and_term(P),
- ?line {<<100,0,6,"������">>,'������'} = get_buf_and_term(P),
+ ?line {<<100,0,6,"ÅÄÖåäö">>,'ÅÄÖåäö'} = get_buf_and_term(P),
+ ?line {<<100,0,6,"ÅÄÖåäö">>,'ÅÄÖåäö'} = get_buf_and_term(P),
?line {<<107,0,3,"foo">>,"foo"} = get_buf_and_term(P),
?line {<<107,0,3,"foo">>,"foo"} = get_buf_and_term(P),
?line {<<106>>,""} = get_buf_and_term(P),
?line {<<106>>,""} = get_buf_and_term(P),
- ?line {<<107,0,6,"������">>,"������"} = get_buf_and_term(P),
- ?line {<<107,0,6,"������">>,"������"} = get_buf_and_term(P),
+ ?line {<<107,0,6,"ÅÄÖåäö">>,"ÅÄÖåäö"} = get_buf_and_term(P),
+ ?line {<<107,0,6,"ÅÄÖåäö">>,"ÅÄÖåäö"} = get_buf_and_term(P),
?line {<<109,0,0,0,3,"foo">>,<<"foo">>} = get_buf_and_term(P),
?line {<<109,0,0,0,0,"">>,<<>>} = get_buf_and_term(P),
- ?line {<<109,0,0,0,6,"������">>,<<"������">>} = get_buf_and_term(P),
+ ?line {<<109,0,0,0,6,"ÅÄÖåäö">>,<<"ÅÄÖåäö">>} = get_buf_and_term(P),
?line {<<104,0>>,{}} = get_buf_and_term(P), % Tuple header for {}
?line {<<106>>,[]} = get_buf_and_term(P), % Empty list []
diff --git a/lib/erl_interface/test/ei_print_SUITE.erl b/lib/erl_interface/test/ei_print_SUITE.erl
index 2a3ed81f53..6305302e28 100644
--- a/lib/erl_interface/test/ei_print_SUITE.erl
+++ b/lib/erl_interface/test/ei_print_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -136,7 +136,7 @@ lists(Config) when is_list(Config) ->
%% ?line {term, "[{name, 'Madonna'}, {age, 21}, {data, [{addr, "E-street", 42}]}]"} =
%% get_term(P),
- %% kanske regexp i st�llet?
+ %% maybe regexp instead?
?line {term, "[{pi, 3.141500}, {'cos(70)', 0.342020}]"} = get_term(P),
?line {term, "[[pi, 3.141500], ['cos(70)', 0.342020]]"} = get_term(P),
diff --git a/lib/erl_interface/vsn.mk b/lib/erl_interface/vsn.mk
index 4e401c874e..1718f38069 100644
--- a/lib/erl_interface/vsn.mk
+++ b/lib/erl_interface/vsn.mk
@@ -1 +1 @@
-EI_VSN = 3.7.8
+EI_VSN = 3.7.9
diff --git a/lib/et/src/Makefile b/lib/et/src/Makefile
index c68a3f4efd..386169fe95 100644
--- a/lib/et/src/Makefile
+++ b/lib/et/src/Makefile
@@ -92,10 +92,10 @@ docs:
# ----------------------------------------------------
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
# ----------------------------------------------------
# Release Target
diff --git a/lib/et/src/et.erl b/lib/et/src/et.erl
index e2cd8564c3..c9ba4f6816 100644
--- a/lib/et/src/et.erl
+++ b/lib/et/src/et.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -102,7 +102,7 @@
%% From = actor()
%% To = actor()
%% FromTo = actor()
-%% Label = atom() | string() |�term()
+%% Label = atom() | string() | term()
%% Contents = [{Key, Value}] | term()
%%
%% actor() = term()
diff --git a/lib/eunit/doc/src/notes.xml b/lib/eunit/doc/src/notes.xml
index 814580e228..b797be0ccb 100644
--- a/lib/eunit/doc/src/notes.xml
+++ b/lib/eunit/doc/src/notes.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2008</year>
- <year>2011</year>
+ <year>2012</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
diff --git a/lib/eunit/include/eunit.hrl b/lib/eunit/include/eunit.hrl
index fba840c3bd..8ebdb6ba16 100644
--- a/lib/eunit/include/eunit.hrl
+++ b/lib/eunit/include/eunit.hrl
@@ -1,3 +1,4 @@
+%% -*- coding: utf-8 -*-
%% This library is free software; you can redistribute it and/or modify
%% it under the terms of the GNU Lesser General Public License as
%% published by the Free Software Foundation; either version 2 of the
@@ -13,7 +14,7 @@
%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
%% USA
%%
-%% Copyright (C) 2004-2006 Micka�l R�mond, Richard Carlsson
+%% Copyright (C) 2004-2006 Mickaël Rémond, Richard Carlsson
%% Including this file turns on testing and defines TEST, unless NOTEST
%% is defined before the file is included. If both NOTEST and TEST are
@@ -124,8 +125,8 @@
-ifndef(UNDER_EUNIT).
-define(UNDER_EUNIT,
(?MATCHES({current_function,{eunit_proc,_,_}},
- .erlang:process_info(.erlang:group_leader(),
- current_function)))).
+ erlang:process_info(erlang:group_leader(),
+ current_function)))).
-endif.
%% The plain assert macro should be defined to do nothing if this file
@@ -142,14 +143,14 @@
((fun () ->
case (BoolExpr) of
true -> ok;
- __V -> .erlang:error({assertion_failed,
- [{module, ?MODULE},
- {line, ?LINE},
- {expression, (??BoolExpr)},
- {expected, true},
- {value, case __V of false -> __V;
- _ -> {not_a_boolean,__V}
- end}]})
+ __V -> erlang:error({assertion_failed,
+ [{module, ?MODULE},
+ {line, ?LINE},
+ {expression, (??BoolExpr)},
+ {expected, true},
+ {value, case __V of false -> __V;
+ _ -> {not_a_boolean,__V}
+ end}]})
end
end)())).
-endif.
@@ -170,12 +171,12 @@
((fun () ->
case (Expr) of
Guard -> ok;
- __V -> .erlang:error({assertMatch_failed,
- [{module, ?MODULE},
- {line, ?LINE},
- {expression, (??Expr)},
- {pattern, (??Guard)},
- {value, __V}]})
+ __V -> erlang:error({assertMatch_failed,
+ [{module, ?MODULE},
+ {line, ?LINE},
+ {expression, (??Expr)},
+ {pattern, (??Guard)},
+ {value, __V}]})
end
end)())).
-endif.
@@ -189,12 +190,12 @@
((fun () ->
__V = (Expr),
case __V of
- Guard -> .erlang:error({assertNotMatch_failed,
- [{module, ?MODULE},
- {line, ?LINE},
- {expression, (??Expr)},
- {pattern, (??Guard)},
- {value, __V}]});
+ Guard -> erlang:error({assertNotMatch_failed,
+ [{module, ?MODULE},
+ {line, ?LINE},
+ {expression, (??Expr)},
+ {pattern, (??Guard)},
+ {value, __V}]});
_ -> ok
end
end)())).
@@ -210,12 +211,12 @@
((fun (__X) ->
case (Expr) of
__X -> ok;
- __V -> .erlang:error({assertEqual_failed,
- [{module, ?MODULE},
- {line, ?LINE},
- {expression, (??Expr)},
- {expected, __X},
- {value, __V}]})
+ __V -> erlang:error({assertEqual_failed,
+ [{module, ?MODULE},
+ {line, ?LINE},
+ {expression, (??Expr)},
+ {expected, __X},
+ {value, __V}]})
end
end)(Expect))).
-endif.
@@ -228,11 +229,11 @@
-define(assertNotEqual(Unexpected, Expr),
((fun (__X) ->
case (Expr) of
- __X -> .erlang:error({assertNotEqual_failed,
- [{module, ?MODULE},
- {line, ?LINE},
- {expression, (??Expr)},
- {value, __X}]});
+ __X -> erlang:error({assertNotEqual_failed,
+ [{module, ?MODULE},
+ {line, ?LINE},
+ {expression, (??Expr)},
+ {value, __X}]});
_ -> ok
end
end)(Unexpected))).
@@ -248,7 +249,7 @@
-define(assertException(Class, Term, Expr),
((fun () ->
try (Expr) of
- __V -> .erlang:error({assertException_failed,
+ __V -> erlang:error({assertException_failed,
[{module, ?MODULE},
{line, ?LINE},
{expression, (??Expr)},
@@ -259,16 +260,16 @@
catch
Class:Term -> ok;
__C:__T ->
- .erlang:error({assertException_failed,
- [{module, ?MODULE},
- {line, ?LINE},
- {expression, (??Expr)},
- {pattern,
- "{ "++(??Class)++" , "++(??Term)
- ++" , [...] }"},
- {unexpected_exception,
- {__C, __T,
- .erlang:get_stacktrace()}}]})
+ erlang:error({assertException_failed,
+ [{module, ?MODULE},
+ {line, ?LINE},
+ {expression, (??Expr)},
+ {pattern,
+ "{ "++(??Class)++" , "++(??Term)
+ ++" , [...] }"},
+ {unexpected_exception,
+ {__C, __T,
+ erlang:get_stacktrace()}}]})
end
end)())).
-endif.
@@ -299,17 +300,17 @@
Class ->
case __T of
Term ->
- .erlang:error({assertNotException_failed,
- [{module, ?MODULE},
- {line, ?LINE},
- {expression, (??Expr)},
- {pattern,
- "{ "++(??Class)++" , "
- ++(??Term)++" , [...] }"},
- {unexpected_exception,
- {__C, __T,
- .erlang:get_stacktrace()
- }}]});
+ erlang:error({assertNotException_failed,
+ [{module, ?MODULE},
+ {line, ?LINE},
+ {expression, (??Expr)},
+ {pattern,
+ "{ "++(??Class)++" , "
+ ++(??Term)++" , [...] }"},
+ {unexpected_exception,
+ {__C, __T,
+ erlang:get_stacktrace()
+ }}]});
_ -> ok
end;
_ -> ok
@@ -324,17 +325,17 @@
%% require EUnit to be present at runtime, or at least eunit_lib.)
%% these can be used for simply running commands in a controlled way
--define(_cmd_(Cmd), (.eunit_lib:command(Cmd))).
+-define(_cmd_(Cmd), (eunit_lib:command(Cmd))).
-define(cmdStatus(N, Cmd),
((fun () ->
case ?_cmd_(Cmd) of
{(N), __Out} -> __Out;
- {__N, _} -> .erlang:error({command_failed,
- [{module, ?MODULE},
- {line, ?LINE},
- {command, (Cmd)},
- {expected_status,(N)},
- {status,__N}]})
+ {__N, _} -> erlang:error({command_failed,
+ [{module, ?MODULE},
+ {line, ?LINE},
+ {command, (Cmd)},
+ {expected_status,(N)},
+ {status,__N}]})
end
end)())).
-define(_cmdStatus(N, Cmd), ?_test(?cmdStatus(N, Cmd))).
@@ -350,12 +351,12 @@
((fun () ->
case ?_cmd_(Cmd) of
{(N), _} -> ok;
- {__N, _} -> .erlang:error({assertCmd_failed,
- [{module, ?MODULE},
- {line, ?LINE},
- {command, (Cmd)},
- {expected_status,(N)},
- {status,__N}]})
+ {__N, _} -> erlang:error({assertCmd_failed,
+ [{module, ?MODULE},
+ {line, ?LINE},
+ {command, (Cmd)},
+ {expected_status,(N)},
+ {status,__N}]})
end
end)())).
-endif.
@@ -368,12 +369,12 @@
((fun () ->
case ?_cmd_(Cmd) of
{_, (T)} -> ok;
- {_, __T} -> .erlang:error({assertCmdOutput_failed,
- [{module, ?MODULE},
- {line, ?LINE},
- {command,(Cmd)},
- {expected_output,(T)},
- {output,__T}]})
+ {_, __T} -> erlang:error({assertCmdOutput_failed,
+ [{module, ?MODULE},
+ {line, ?LINE},
+ {command,(Cmd)},
+ {expected_output,(T)},
+ {output,__T}]})
end
end)())).
-endif.
@@ -394,12 +395,12 @@
-else.
-define(debugMsg(S),
(begin
- .io:fwrite(user, <<"~s:~w:~w: ~s\n">>,
- [?FILE, ?LINE, self(), S]),
+ io:fwrite(user, <<"~s:~w:~w: ~s\n">>,
+ [?FILE, ?LINE, self(), S]),
ok
end)).
-define(debugHere, (?debugMsg("<-"))).
--define(debugFmt(S, As), (?debugMsg(.io_lib:format((S), (As))))).
+-define(debugFmt(S, As), (?debugMsg(io_lib:format((S), (As))))).
-define(debugVal(E),
((fun (__V) ->
?debugFmt(<<"~s = ~P">>, [(??E), __V, 15]),
diff --git a/lib/eunit/src/Makefile b/lib/eunit/src/Makefile
index 0a2e71cf7b..e88e28df83 100644
--- a/lib/eunit/src/Makefile
+++ b/lib/eunit/src/Makefile
@@ -104,10 +104,10 @@ $(OBJECTS): $(PARSE_TRANSFORM_BIN)
# ----------------------------------------------------
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
# ----------------------------------------------------
# Release Target
diff --git a/lib/eunit/src/eunit.erl b/lib/eunit/src/eunit.erl
index 51846d73b3..5763949519 100644
--- a/lib/eunit/src/eunit.erl
+++ b/lib/eunit/src/eunit.erl
@@ -1,3 +1,4 @@
+%% -*- coding: utf-8 -*-
%% This library is free software; you can redistribute it and/or modify
%% it under the terms of the GNU Lesser General Public License as
%% published by the Free Software Foundation; either version 2 of the
@@ -13,8 +14,8 @@
%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
%% USA
%%
-%% @copyright 2004-2009 Micka�l R�mond, Richard Carlsson
-%% @author Micka�l R�mond <[email protected]>
+%% @copyright 2004-2009 Mickaël Rémond, Richard Carlsson
+%% @author Mickaël Rémond <[email protected]>
%% [http://www.process-one.net/]
%% @author Richard Carlsson <[email protected]>
%% @version {@version}, {@date} {@time}
diff --git a/lib/eunit/src/eunit_autoexport.erl b/lib/eunit/src/eunit_autoexport.erl
index 099bcb222e..36ae3b71d7 100644
--- a/lib/eunit/src/eunit_autoexport.erl
+++ b/lib/eunit/src/eunit_autoexport.erl
@@ -80,10 +80,9 @@ rewrite([F | Fs], As, Module, Test) ->
rewrite(Fs, [F | As], Module, Test);
rewrite([], As, Module, Test) ->
{if Test ->
- EUnit = {record_field,0,{atom,0,''},{atom,0,eunit}},
[{function,0,test,0,
[{clause,0,[],[],
- [{call,0,{remote,0,EUnit,{atom,0,test}},
+ [{call,0,{remote,0,{atom,0,eunit},{atom,0,test}},
[{atom,0,Module}]}]}]}
| As];
true ->
@@ -92,9 +91,7 @@ rewrite([], As, Module, Test) ->
Test}.
module_decl(Name, M, Fs, Exports) ->
- Module = if is_atom(Name) -> Name;
- true -> list_to_atom(packages:concat(Name))
- end,
+ Module = Name,
{Fs1, Test} = rewrite(Fs, [], Module, true),
Es = if Test -> [{test,0} | Exports];
true -> Exports
diff --git a/lib/eunit/src/eunit_lib.erl b/lib/eunit/src/eunit_lib.erl
index ea9e944d7e..809cb7ab7b 100644
--- a/lib/eunit/src/eunit_lib.erl
+++ b/lib/eunit/src/eunit_lib.erl
@@ -1,3 +1,4 @@
+%% -*- coding: utf-8 -*-
%% This library is free software; you can redistribute it and/or modify
%% it under the terms of the GNU Lesser General Public License as
%% published by the Free Software Foundation; either version 2 of the
@@ -13,8 +14,8 @@
%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
%% USA
%%
-%% @copyright 2004-2007 Micka�l R�mond, Richard Carlsson
-%% @author Micka�l R�mond <[email protected]>
+%% @copyright 2004-2007 Mickaël Rémond, Richard Carlsson
+%% @author Mickaël Rémond <[email protected]>
%% [http://www.process-one.net/]
%% @author Richard Carlsson <[email protected]>
%% @private
diff --git a/lib/eunit/src/eunit_surefire.erl b/lib/eunit/src/eunit_surefire.erl
index 46b8c8b503..cc021625d5 100644
--- a/lib/eunit/src/eunit_surefire.erl
+++ b/lib/eunit/src/eunit_surefire.erl
@@ -1,3 +1,4 @@
+%% -*- coding: utf-8 -*-
%% This library is free software; you can redistribute it and/or modify
%% it under the terms of the GNU Lesser General Public License as
%% published by the Free Software Foundation; either version 2 of the
@@ -13,8 +14,8 @@
%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
%% USA
%%
-%% @author Micka�l R�mond <[email protected]>
-%% @copyright 2009 Micka�l R�mond, Paul Guyot
+%% @author Mickaël Rémond <[email protected]>
+%% @copyright 2009 Mickaël Rémond, Paul Guyot
%% @see eunit
%% @doc Surefire reports for EUnit (Format used by Maven and Atlassian
%% Bamboo for example to integrate test results). Based on initial code
diff --git a/lib/gs/contribs/bonk/Makefile b/lib/gs/contribs/bonk/Makefile
index a630deaf24..d160ca8b73 100644
--- a/lib/gs/contribs/bonk/Makefile
+++ b/lib/gs/contribs/bonk/Makefile
@@ -81,12 +81,12 @@ clean:
# ----------------------------------------------------
$(EBIN)/$(TOOLNAME).gif: $(TOOLNAME).gif
- rm -f $@
- cp $(TOOLNAME).gif $@
+ $(gen_verbose)rm -f $@
+ $(V_at)cp $(TOOLNAME).gif $@
$(EBIN)/$(TOOLNAME).tool: $(TOOLNAME).tool
- rm -f $@
- cp $(TOOLNAME).tool $@
+ $(gen_verbose)rm -f $@
+ $(V_at)cp $(TOOLNAME).tool $@
# ----------------------------------------------------
# Release Target
diff --git a/lib/gs/contribs/cols/Makefile b/lib/gs/contribs/cols/Makefile
index 3af91e1dae..3036e9565e 100644
--- a/lib/gs/contribs/cols/Makefile
+++ b/lib/gs/contribs/cols/Makefile
@@ -74,16 +74,16 @@ clean:
# ----------------------------------------------------
$(EBIN)/$(TOOLNAME).gif: $(TOOLNAME).gif
- rm -f $@
- cp $(TOOLNAME).gif $@
+ $(gen_verbose)rm -f $@
+ $(V_at)cp $(TOOLNAME).gif $@
$(EBIN)/$(TOOLNAME).tool: $(TOOLNAME).tool
- rm -f $@
- cp $(TOOLNAME).tool $@
+ $(gen_verbose)rm -f $@
+ $(V_at)cp $(TOOLNAME).tool $@
$(EBIN)/help.gif: help.gif
- rm -f $@
- cp help.gif $@
+ $(gen_verbose)rm -f $@
+ $(V_at)cp help.gif $@
# ----------------------------------------------------
# Release Target
diff --git a/lib/gs/contribs/mandel/Makefile b/lib/gs/contribs/mandel/Makefile
index 5f0b047955..308ba0cbb0 100644
--- a/lib/gs/contribs/mandel/Makefile
+++ b/lib/gs/contribs/mandel/Makefile
@@ -73,16 +73,16 @@ clean:
# ----------------------------------------------------
$(EBIN)/$(TOOLNAME).gif: $(TOOLNAME).gif
- rm -f $@
- cp $(TOOLNAME).gif $@
+ $(gen_verbose)rm -f $@
+ $(V_at)cp $(TOOLNAME).gif $@
$(EBIN)/$(TOOLNAME).tool: $(TOOLNAME).tool
- rm -f $@
- cp $(TOOLNAME).tool $@
+ $(gen_verbose)rm -f $@
+ $(V_at)cp $(TOOLNAME).tool $@
$(EBIN)/help.gif: help.gif
- rm -f $@
- cp help.gif $@
+ $(gen_verbose)rm -f $@
+ $(V_at)cp help.gif $@
# ----------------------------------------------------
# Release Target
diff --git a/lib/gs/contribs/mandel/mandel.erl b/lib/gs/contribs/mandel/mandel.erl
index 8ecd649532..a7a786ce98 100644
--- a/lib/gs/contribs/mandel/mandel.erl
+++ b/lib/gs/contribs/mandel/mandel.erl
@@ -1,3 +1,4 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
@@ -34,7 +35,7 @@
%%%-----------------------------------------------------------------
%%% Distributed Mandelbrot program.
%%% Originally written i C++/rpc/lwp/interviews by Klas Eriksson.(1200 lines)
-%%% Rewritten in Erlang by Klas Eriksson and Martin Bj�rklund.
+%%% Rewritten in Erlang by Klas Eriksson and Martin Björklund.
%%%-----------------------------------------------------------------
%% unix>erl -sname foo (all nodes will get the same name)
diff --git a/lib/gs/contribs/othello/Makefile b/lib/gs/contribs/othello/Makefile
index 5f37d164f5..f9d131c315 100644
--- a/lib/gs/contribs/othello/Makefile
+++ b/lib/gs/contribs/othello/Makefile
@@ -76,12 +76,12 @@ clean:
# ----------------------------------------------------
$(EBIN)/$(TOOLNAME).gif: $(TOOLNAME).gif
- rm -f $@
- cp $(TOOLNAME).gif $@
+ $(gen_verbose)rm -f $@
+ $(V_at)cp $(TOOLNAME).gif $@
$(EBIN)/$(TOOLNAME).tool: $(TOOLNAME).tool
- rm -f $@
- cp $(TOOLNAME).tool $@
+ $(gen_verbose)rm -f $@
+ $(V_at)cp $(TOOLNAME).tool $@
# ----------------------------------------------------
# Release Target
diff --git a/lib/gs/src/Makefile b/lib/gs/src/Makefile
index 4b7a4523b9..0a63d5466e 100644
--- a/lib/gs/src/Makefile
+++ b/lib/gs/src/Makefile
@@ -91,13 +91,13 @@ clean:
# ----------------------------------------------------
gstk_generic.hrl: gs_make.erl ../ebin/gs_make.$(EMULATOR) ../ebin/gs.$(EMULATOR)
- $(ERL) -pa $(EBIN) -s gs_make -s erlang halt -noshell
+ $(gen_verbose)$(ERL) -pa $(EBIN) -s gs_make -s erlang halt -noshell
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(GSTK_GENERIC_TARGET): gstk_generic.hrl
diff --git a/lib/gs/src/gstk_editor.erl b/lib/gs/src/gstk_editor.erl
index e918d93147..cb422aef95 100644
--- a/lib/gs/src/gstk_editor.erl
+++ b/lib/gs/src/gstk_editor.erl
@@ -90,9 +90,9 @@
%% type
%%
-%.t tag names 2.7 -> red blue (blue �r f�rgen)
-%.t tag add blue 2.1 2.10 tagga text
-%.t tag configure blue -foregr blue skapa tag
+%.t tag names 2.7 -> red blue (blue is the colour)
+%.t tag add blue 2.1 2.10 tag the text
+%.t tag configure blue -foregr blue create tag
% .t index end -> MaxRows.cols
% .t yview moveto (Row-1)/MaxRows
diff --git a/lib/hipe/Makefile b/lib/hipe/Makefile
index 2294f98158..a9e24f4d17 100644
--- a/lib/hipe/Makefile
+++ b/lib/hipe/Makefile
@@ -57,20 +57,20 @@ edocs:
fi
all-subdirs:
- for dir in $(SUB_DIRECTORIES); do \
+ $(V_at)for dir in $(SUB_DIRECTORIES); do \
(cd $$dir; $(MAKE) $(MAKETARGET) EBIN=$(EBIN); cd ..); \
done
# distclean and realclean should clean the bootstrap files
all-subdirs-x:
- for dir in $(SUB_DIRECTORIES); do \
+ $(V_at)for dir in $(SUB_DIRECTORIES); do \
(cd $$dir; $(MAKE) $(MAKETARGET) EBIN=../boot_ebin; cd ..); \
done
clean:
- $(MAKE) MAKETARGET="clean" all-subdirs all-subdirs-x
+ $(V_at)$(MAKE) MAKETARGET="clean" all-subdirs all-subdirs-x
distclean:
- $(MAKE) MAKETARGET="distclean" all-subdirs all-subdirs-x
+ $(V_at)$(MAKE) MAKETARGET="distclean" all-subdirs all-subdirs-x
realclean:
- $(MAKE) MAKETARGET="realclean" all-subdirs all-subdirs-x
+ $(V_at)$(MAKE) MAKETARGET="realclean" all-subdirs all-subdirs-x
diff --git a/lib/hipe/amd64/hipe_amd64_encode.erl b/lib/hipe/amd64/hipe_amd64_encode.erl
index ee68dfb3b8..cbdab25b25 100644
--- a/lib/hipe/amd64/hipe_amd64_encode.erl
+++ b/lib/hipe/amd64/hipe_amd64_encode.erl
@@ -1,7 +1,7 @@
%%%
%%% %CopyrightBegin%
%%%
-%%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%%% Copyright Ericsson AB 2004-2012. All Rights Reserved.
%%%
%%% The contents of this file are subject to the Erlang Public License,
%%% Version 1.1, (the "License"); you may not use this file except in
@@ -373,16 +373,16 @@ sse2_arith_binop_encode(Prefix, Opcode, {{xmm, XMM64}, {rm64fp, RM64}}) ->
[Prefix, 16#0F, Opcode | encode_rm(RM64, XMM64, [])].
sse2_cvtsi2sd_encode({{xmm,XMM64}, {rm64,RM64}}) ->
- [rex([{w, 1}]), 16#F2, 16#0F, 16#2A�| encode_rm(RM64, XMM64, [])].
+ [rex([{w, 1}]), 16#F2, 16#0F, 16#2A | encode_rm(RM64, XMM64, [])].
sse2_mov_encode(Opnds) ->
case Opnds of
{{xmm, XMM64}, {rm64fp, RM64}} -> % movsd
- [16#F2, 16#0F, 16#10�| encode_rm(RM64, XMM64, [])];
+ [16#F2, 16#0F, 16#10 | encode_rm(RM64, XMM64, [])];
{{rm64fp, RM64}, {xmm, XMM64}} -> % movsd
- [16#F2, 16#0F, 16#11�| encode_rm(RM64, XMM64, [])]
+ [16#F2, 16#0F, 16#11 | encode_rm(RM64, XMM64, [])]
% {{xmm, XMM64}, {rm64, RM64}} -> % cvtsi2sd
-% [rex([{w, 1}]), 16#F2, 16#0F, 16#2A�| encode_rm(RM64, XMM64, [])]
+% [rex([{w, 1}]), 16#F2, 16#0F, 16#2A | encode_rm(RM64, XMM64, [])]
end.
%% arith_binop_sizeof(Opnds) ->
diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl
index 776e336aea..98d65abba1 100644
--- a/lib/hipe/cerl/erl_bif_types.erl
+++ b/lib/hipe/cerl/erl_bif_types.erl
@@ -766,37 +766,6 @@ type(erlang, node, 0, _) -> t_node();
type(erlang, node, 1, Xs) ->
strict(arg_types(erlang, node, 1), Xs, fun (_) -> t_node() end);
type(erlang, nodes, 0, _) -> t_list(t_node());
-type(erlang, port_call, Arity, Xs) when Arity =:= 2; Arity =:= 3 ->
- strict(arg_types(erlang, port_call, Arity), Xs, fun (_) -> t_any() end);
-type(erlang, port_info, 1, Xs) ->
- strict(arg_types(erlang, port_info, 1), Xs,
- fun (_) -> t_sup(t_atom('undefined'), t_list()) end);
-type(erlang, port_info, 2, Xs) ->
- strict(arg_types(erlang, port_info, 2), Xs,
- fun ([_Port, Item]) ->
- t_sup(t_atom('undefined'),
- case t_atom_vals(Item) of
- ['connected'] -> t_tuple([Item, t_pid()]);
- ['id'] -> t_tuple([Item, t_integer()]);
- ['input'] -> t_tuple([Item, t_integer()]);
- ['links'] -> t_tuple([Item, t_list(t_pid())]);
- ['name'] -> t_tuple([Item, t_string()]);
- ['output'] -> t_tuple([Item, t_integer()]);
- ['os_pid'] -> t_tuple([Item, t_sup(t_non_neg_integer(),t_atom('undefined'))]);
- ['registered_name'] -> t_tuple([Item, t_atom()]);
- List when is_list(List) ->
- t_tuple([t_sup([t_atom(A) || A <- List]),
- t_sup([t_atom(), t_integer(),
- t_pid(), t_list(t_pid()),
- t_string()])]);
- unknown ->
- [_, PosItem] = arg_types(erlang, port_info, 2),
- t_tuple([PosItem,
- t_sup([t_atom(), t_integer(),
- t_pid(), t_list(t_pid()),
- t_string()])])
- end)
- end);
%% Guard bif, needs to be here.
type(erlang, round, 1, Xs) ->
strict(arg_types(erlang, round, 1), Xs, fun (_) -> t_integer() end);
@@ -922,6 +891,14 @@ type(erlang, system_info, 1, Xs) ->
t_non_neg_fixnum(),
t_non_neg_fixnum()]),
t_string());
+ ['otp_release'] ->
+ t_string();
+ ['port_parallelism'] ->
+ t_boolean();
+ ['port_count'] ->
+ t_non_neg_fixnum();
+ ['port_limit'] ->
+ t_non_neg_fixnum();
['process_count'] ->
t_non_neg_fixnum();
['process_limit'] ->
@@ -2275,16 +2252,6 @@ arg_types(erlang, node, 1) ->
[t_identifier()];
arg_types(erlang, nodes, 0) ->
[];
-arg_types(erlang, port_call, 2) ->
- [t_sup(t_port(), t_atom()), t_any()];
-arg_types(erlang, port_call, 3) ->
- [t_sup(t_port(), t_atom()), t_integer(), t_any()];
-arg_types(erlang, port_info, 1) ->
- [t_sup(t_port(), t_atom())];
-arg_types(erlang, port_info, 2) ->
- [t_sup(t_port(), t_atom()),
- t_atoms(['registered_name', 'id', 'connected',
- 'links', 'name', 'input', 'output', 'os_pid'])];
%% Guard bif, needs to be here.
arg_types(erlang, round, 1) ->
[t_number()];
diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl
index 1579735773..f5be8fb08f 100644
--- a/lib/hipe/cerl/erl_types.erl
+++ b/lib/hipe/cerl/erl_types.erl
@@ -687,8 +687,8 @@ t_solve_remote(?tuple(Types, _Arity, _Tag), ET, R, C) ->
{RL, RR} = list_solve_remote(Types, ET, R, C),
{t_tuple(RL), RR};
t_solve_remote(?tuple_set(Set), ET, R, C) ->
- {NewSet, RR} = tuples_solve_remote(Set, ET, R, C),
- {?tuple_set(NewSet), RR};
+ {NewTuples, RR} = tuples_solve_remote(Set, ET, R, C),
+ {t_sup(NewTuples), RR};
t_solve_remote(?remote(Set), ET, R, C) ->
RemoteList = ordsets:to_list(Set),
{RL, RR} = list_solve_remote_type(RemoteList, ET, R, C),
@@ -788,10 +788,10 @@ opaques_solve_remote([#opaque{struct = Struct} = Remote|Tail], ET, R, C) ->
tuples_solve_remote([], _ET, _R, _C) ->
{[], []};
-tuples_solve_remote([{Sz, Tuples}|Tail], ET, R, C) ->
+tuples_solve_remote([{_Sz, Tuples}|Tail], ET, R, C) ->
{RL, RR1} = list_solve_remote(Tuples, ET, R, C),
{LSzTpls, RR2} = tuples_solve_remote(Tail, ET, R, C),
- {[{Sz, RL}|LSzTpls], RR1 ++ RR2}.
+ {RL ++ LSzTpls, RR1 ++ RR2}.
%%-----------------------------------------------------------------------------
%% Unit type. Signals non termination.
@@ -3432,7 +3432,7 @@ record_field_diffs_to_string(?tuple([_|Fs], Arity, Tag), RecDict) ->
field_diffs([F|Fs], [{FName, DefType}|FDefs], RecDict, Acc) ->
NewAcc =
- case t_is_subtype(F, DefType) of
+ case not t_is_none(t_inf(F, DefType)) of
true -> Acc;
false ->
Str = atom_to_string(FName) ++ "::" ++ t_to_string(DefType, RecDict),
diff --git a/lib/hipe/doc/src/notes.xml b/lib/hipe/doc/src/notes.xml
index 1841c7d9de..cfd22a9d8d 100644
--- a/lib/hipe/doc/src/notes.xml
+++ b/lib/hipe/doc/src/notes.xml
@@ -30,6 +30,22 @@
</header>
<p>This document describes the changes made to HiPE.</p>
+<section><title>Hipe 3.9.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A faulty spec for process_info/2 could cause false
+ dialyzer warnings. The spec is corrected.</p>
+ <p>
+ Own Id: OTP-10584</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Hipe 3.9.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/hipe/flow/hipe_dominators.erl b/lib/hipe/flow/hipe_dominators.erl
index 17357461a5..1f2c830eaf 100644
--- a/lib/hipe/flow/hipe_dominators.erl
+++ b/lib/hipe/flow/hipe_dominators.erl
@@ -1,8 +1,8 @@
-%% -*- erlang-indent-level: 2 -*-
+%% -*- coding: utf-8; erlang-indent-level: 2 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -19,7 +19,7 @@
%%
%%------------------------------------------------------------------------
%% File : hipe_dominators.erl
-%% Author : Christoffer Vikstr�m <[email protected]>
+%% Author : Christoffer Vikström <[email protected]>
%% Daniel Deogun <[email protected]>
%% Jesper Bengtsson <[email protected]>
%% Created : 18 Mar 2002
diff --git a/lib/hipe/icode/hipe_icode_mulret.erl b/lib/hipe/icode/hipe_icode_mulret.erl
index a3cae621ab..0bf9f89994 100644
--- a/lib/hipe/icode/hipe_icode_mulret.erl
+++ b/lib/hipe/icode/hipe_icode_mulret.erl
@@ -1,8 +1,8 @@
-%% -*- erlang-indent-level: 2 -*-
+%% -*- coding: utf-8; erlang-indent-level: 2 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -19,9 +19,9 @@
%%
%%----------------------------------------------------------------------
%% File : hipe_icode_mulret.erl
-%% Author : Christoffer Vikstr�m <[email protected]>
+%% Author : Christoffer Vikström <[email protected]>
%% Purpose :
-%% Created : 23 Jun 2004 by Christoffer Vikstr�m <[email protected]>
+%% Created : 23 Jun 2004 by Christoffer Vikström <[email protected]>
%%----------------------------------------------------------------------
-module(hipe_icode_mulret).
@@ -890,7 +890,7 @@ removeUnElems([I|Code], [OldVar] = OldVars, DstLst, Res, Def, Lab) ->
%% [I|Res], Def, Lab)
%% end;
false ->
- io:format("Borde aldrig kunna hamna h�r!", []),
+ io:format("Borde aldrig kunna hamna här!", []),
removeUnElems(Code, OldVars, DstLst, [I|Res], Def, Lab)
end
end;
@@ -1159,8 +1159,8 @@ printCallList([]) -> io:format("~n").
%% % Purpose :
%% % Arguments :
%% % Return :
-%% % Notes : Fixa s� att funktionen anv�nder defines(I) ist�llet och
-%% % selektorer ist�llet f�r att matcha p� #call{}. L�tt gjort.
+%% % Notes : Fixa så att funktionen använder defines(I) istället och
+%% % selektorer istället för att matcha på #call{}. Lätt gjort.
%% %%>----------------------------------------------------------------------<
%% removeUnElems(List, Var) -> removeUnElems(List, Var, []).
%% removeUnElems([#icode_call{'fun'={unsafe_element,_}, args=Var}|List], Var, Res) ->
diff --git a/lib/hipe/main/Makefile b/lib/hipe/main/Makefile
index 673431a175..66e4c3e39a 100644
--- a/lib/hipe/main/Makefile
+++ b/lib/hipe/main/Makefile
@@ -76,7 +76,7 @@ ERL_COMPILE_FLAGS += +nowarn_shadow_vars +warn_missing_spec +warn_untyped_record
# ----------------------------------------------------
hipe.hrl: ../vsn.mk hipe.hrl.src
- sed -e "s;%VSN%;$(HIPE_VSN);" ../../hipe/main/hipe.hrl.src > ../../hipe/main/hipe.hrl
+ $(vsn_verbose)sed -e "s;%VSN%;$(HIPE_VSN);" ../../hipe/main/hipe.hrl.src > ../../hipe/main/hipe.hrl
$(EBIN)/hipe.beam: hipe.hrl ../../compiler/src/beam_disasm.hrl
$(EBIN)/hipe_main.beam: hipe.hrl ../icode/hipe_icode.hrl #../rtl/hipe_rtl.hrl
@@ -97,17 +97,17 @@ distclean: clean
realclean: clean
$(DOCS)/%.html:%.erl
- erl -noshell -run edoc_run file '"$<"' '[{dir, "$(DOCS)"}]' -s init stop
+ $(gen_verbose)erl -noshell -run edoc_run file '"$<"' '[{dir, "$(DOCS)"}]' -s init stop
# ----------------------------------------------------
# Special Build Targets
# ----------------------------------------------------
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
# ----------------------------------------------------
# Release Target
diff --git a/lib/hipe/regalloc/hipe_coalescing_regalloc.erl b/lib/hipe/regalloc/hipe_coalescing_regalloc.erl
index 5a4b017c71..7169dd18f3 100644
--- a/lib/hipe/regalloc/hipe_coalescing_regalloc.erl
+++ b/lib/hipe/regalloc/hipe_coalescing_regalloc.erl
@@ -1,8 +1,8 @@
-%% -*- erlang-indent-level: 2 -*-
+%% -*- coding: utf-8; erlang-indent-level: 2 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -20,8 +20,8 @@
%%-----------------------------------------------------------------------
%% File : hipe_coalescing_regalloc.erl
%% Authors : Andreas Wallin <[email protected]>
-%% Thorild Sel�n <[email protected]>
-%% Ingemar �berg <[email protected]>
+%% Thorild Selén <[email protected]>
+%% Ingemar Åberg <[email protected]>
%% Purpose : Play paintball with registers on a target machine. We win
%% if they are all colored. This is an iterated coalescing
%% register allocator.
diff --git a/lib/hipe/regalloc/hipe_optimistic_regalloc.erl b/lib/hipe/regalloc/hipe_optimistic_regalloc.erl
index 183ec1994c..fc3718cbc0 100644
--- a/lib/hipe/regalloc/hipe_optimistic_regalloc.erl
+++ b/lib/hipe/regalloc/hipe_optimistic_regalloc.erl
@@ -1,8 +1,8 @@
-%% -*- erlang-indent-level: 2 -*-
+%% -*- coding: utf-8; erlang-indent-level: 2 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -1657,9 +1657,9 @@ findPrimitiveNodes(Node, N, Alias, PrimitiveNodes) ->
% %?debug_msg("Node ~p~n", [Node]),
% NextNode = Node - 1,
% Coalesced_to = hipe_reg_worklists:member_coalesced_to(NextNode, Worklists),
-% ?debug_msg("��-- member coalesced: ~p~n", [Coalesced_to]),
+% ?debug_msg("³³-- member coalesced: ~p~n", [Coalesced_to]),
% {Primitives, Alias1} = undoCoalescing(NextNode, No_temporaries, Alias),
-% ?debug_msg("��-- primitivenodes ~w\n", [Primitives]),
+% ?debug_msg("½½-- primitivenodes ~w\n", [Primitives]),
% case (Coalesced_to) of
% true -> printAlias(Alias1);
% _ -> true
@@ -1683,9 +1683,9 @@ findPrimitiveNodes(Node, N, Alias, PrimitiveNodes) ->
fixAdj(N, SavedAdj, IG, Target) ->
%Saved = hipe_vectors:get(SavedAdj, N),
Saved = hipe_adj_list:edges(N, SavedAdj),
- ?debug_msg("��--adj to ~p: ~p~n", [N, Saved]),
+ ?debug_msg("§§--adj to ~p: ~p~n", [N, Saved]),
Adj = hipe_ig:node_adj_list(N, IG),
- ?debug_msg("��--adj to ~p: ~p~n", [N, Adj]),
+ ?debug_msg("««--adj to ~p: ~p~n", [N, Adj]),
New = findNew(Adj, Saved),
?debug_msg("++--new adj to ~p: ~p~n", [N, New]),
removeAdj(New, N, IG, Target),
diff --git a/lib/hipe/regalloc/hipe_reg_worklists.erl b/lib/hipe/regalloc/hipe_reg_worklists.erl
index 67a5788c7c..e22cc8dc07 100644
--- a/lib/hipe/regalloc/hipe_reg_worklists.erl
+++ b/lib/hipe/regalloc/hipe_reg_worklists.erl
@@ -1,8 +1,8 @@
-%%% -*- erlang-indent-level: 2 -*-
+%%% -*- coding: utf-8; erlang-indent-level: 2 -*-
%%%
%%% %CopyrightBegin%
%%%
-%%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%%% Copyright Ericsson AB 2001-2012. All Rights Reserved.
%%%
%%% The contents of this file are subject to the Erlang Public License,
%%% Version 1.1, (the "License"); you may not use this file except in
@@ -28,7 +28,7 @@
%%%----------------------------------------------------------------------
-module(hipe_reg_worklists).
--author(['Andreas Wallin', 'Thorild Sel�n']).
+-author(['Andreas Wallin', 'Thorild Selén']).
-export([new/5, % only used by optimistic allocator
new/6,
simplify/1,
diff --git a/lib/hipe/rtl/Makefile b/lib/hipe/rtl/Makefile
index 426d1bd3ee..7852a2172b 100644
--- a/lib/hipe/rtl/Makefile
+++ b/lib/hipe/rtl/Makefile
@@ -134,13 +134,13 @@ HIPE_MKLITERALS=$(ERL_TOP)/bin/$(TARGET)/hipe_mkliterals$(TYPE_STR)$(FLAVOR_STR)
hipe_literals.hrl: $(HIPE_MKLITERALS)
- $(HIPE_MKLITERALS) $(MKLIT_FLAGS) -e > hipe_literals.hrl
+ $(gen_verbose)$(HIPE_MKLITERALS) $(MKLIT_FLAGS) -e > hipe_literals.hrl
# Need to generate hipe.hrl from one and only one target in one and only
# one makefile; otherwise, clearmake will force rebuilds of hipe over and
# over again.
../main/hipe.hrl: ../vsn.mk ../main/hipe.hrl.src
- (cd ../main && $(MAKE) hipe.hrl)
+ $(V_at)(cd ../main && $(MAKE) hipe.hrl)
# 2012-02-24. Please keep these dependencies up to date. They tend to rot.
# grep ^-include *.erl says a lot, but you need to dig further, e.g:
diff --git a/lib/hipe/rtl/hipe_rtl_arith.inc b/lib/hipe/rtl/hipe_rtl_arith.inc
index e608506234..7b587e882d 100644
--- a/lib/hipe/rtl/hipe_rtl_arith.inc
+++ b/lib/hipe/rtl/hipe_rtl_arith.inc
@@ -1,9 +1,9 @@
%% -*- Erlang -*-
-%% -*- erlang-indent-level: 2 -*-
+%% -*- coding: utf-8; erlang-indent-level: 2 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -114,7 +114,7 @@ eval_alu(Op, Arg1, Arg2)
eval_alu(Op, Arg1, Arg2) ->
?EXIT({argument_overflow,Op,Arg1,Arg2}).
-%% Bj�rn & Bjarni:
+%% Björn & Bjarni:
%% We need to be able to do evaluations based only on the bits, since
%% there are cases where we can evaluate a subset of the bits, but can
%% not do a full eval-alub call (eg. a + 0 gives no carry)
diff --git a/lib/hipe/rtl/hipe_rtl_mk_switch.erl b/lib/hipe/rtl/hipe_rtl_mk_switch.erl
index e5175217d6..d859c50b7d 100644
--- a/lib/hipe/rtl/hipe_rtl_mk_switch.erl
+++ b/lib/hipe/rtl/hipe_rtl_mk_switch.erl
@@ -1,8 +1,8 @@
-%% -*- erlang-indent-level: 2 -*-
+%% -*- coding: utf-8; erlang-indent-level: 2 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -31,7 +31,7 @@
%% History : * 2001-02-28 Erik Johansson ([email protected]):
%% Created.
%% * 2001-04-01 Erik Trulsson ([email protected]):
-%% Stefan Lindstr�m ([email protected]):
+%% Stefan Lindström ([email protected]):
%% Added clustering and inlined binary search trees.
%% * 2001-07-30 EJ ([email protected]):
%% Fixed some bugs and started cleanup.
diff --git a/lib/hipe/rtl/hipe_rtl_primops.erl b/lib/hipe/rtl/hipe_rtl_primops.erl
index 53aaa72aa6..d9d08356ce 100644
--- a/lib/hipe/rtl/hipe_rtl_primops.erl
+++ b/lib/hipe/rtl/hipe_rtl_primops.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -738,7 +738,7 @@ gen_mkfun([Dst], {_Mod, _FunId, _Arity} = MFidA, MagicNr, Index, FreeVars) ->
%% Tag the thing and increase the heap_pointer.
%% make_fun(funp);
- WordSize�= hipe_rtl_arch:word_size(),
+ WordSize = hipe_rtl_arch:word_size(),
HeapNeed = (?ERL_FUN_SIZE + NumFree) * WordSize,
TagCode = [hipe_tagscheme:tag_fun(Dst, HP),
%% AdjustHPCode
@@ -829,7 +829,7 @@ load_struct_field(Dest, StructP, Offset, int32) ->
gen_free_vars(Vars, HPReg) ->
HPVar = hipe_rtl:mk_new_var(),
- WordSize�= hipe_rtl_arch:word_size(),
+ WordSize = hipe_rtl_arch:word_size(),
[hipe_rtl:mk_alu(HPVar, HPReg, add, hipe_rtl:mk_imm(?EFT_ENV)) |
gen_free_vars(Vars, HPVar, 0, WordSize, [])].
diff --git a/lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl b/lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl
index 194cf29b64..1c900d767e 100644
--- a/lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl
+++ b/lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl
@@ -1,8 +1,8 @@
-%% -*- erlang-indent-level: 2 -*-
+%% -*- coding: utf-8; erlang-indent-level: 2 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -190,7 +190,7 @@ set_to(Dst, Val, Env) ->
%% Returns : { FlowWorkList, SSAWorkList, NewEnvironment}
%%-----------------------------------------------------------------------------
-visit_branch(Inst, Env) -> %% Titta ocks� p� exekverbarflagga
+visit_branch(Inst, Env) -> %% Titta också på exekverbarflagga
Val1 = lookup_lattice_value(hipe_rtl:branch_src1(Inst), Env),
Val2 = lookup_lattice_value(hipe_rtl:branch_src2(Inst), Env),
CFGWL = case evaluate_relop(Val1, hipe_rtl:branch_cond(Inst), Val2) of
diff --git a/lib/hipe/rtl/hipe_rtl_ssapre.erl b/lib/hipe/rtl/hipe_rtl_ssapre.erl
index a9e92e5688..34897ba4b7 100644
--- a/lib/hipe/rtl/hipe_rtl_ssapre.erl
+++ b/lib/hipe/rtl/hipe_rtl_ssapre.erl
@@ -1,8 +1,8 @@
-%% -*- erlang-indent-level: 2 -*-
+%% -*- coding: utf-8; erlang-indent-level: 2 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -19,7 +19,7 @@
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% File : hipe_rtl_ssapre.erl
-%% Author : He Bingwen and Fr�d�ric Haziza
+%% Author : He Bingwen and Frédéric Haziza
%% Description : Performs Partial Redundancy Elimination on SSA form.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% @doc
@@ -552,7 +552,7 @@ emend_with_processed_xsis(E, [I|Rest], Pred, XsiGraph) ->
true -> %% It's a computation of E!
case xsi_arg(Xsi,Pred) of
undetermined_operand ->
- exit({?MODULE,check_operand_sharing,"######## �h Dear, we trusted Kostis !!!!!!!!! #############"});
+ exit({?MODULE,check_operand_sharing,"######## Ôh Dear, we trusted Kostis !!!!!!!!! #############"});
XsiOp ->
{sharing_operand,XsiOp} %% They share operands
end;
@@ -571,7 +571,7 @@ emend_with_processed_xsis(E, [I|Rest], Pred, XsiGraph) ->
NewE = emend(E,Def,A#eop.var),
emend_with_processed_xsis(NewE,Rest,Pred,XsiGraph);
undetermined_operand ->
- exit({?MODULE,emend_with_processed_xsis,"######## �h Dear, we trusted Kostis, again !!!!!!!!! #############"});
+ exit({?MODULE,emend_with_processed_xsis,"######## Ôh Dear, we trusted Kostis, again !!!!!!!!! #############"});
XsiOp ->
NewE = emend(E,Def,XsiOp),
emend_with_processed_xsis(NewE,Rest,Pred,XsiGraph)
diff --git a/lib/hipe/ssa/hipe_ssa.inc b/lib/hipe/ssa/hipe_ssa.inc
index d15b5ddd56..e766a83c41 100644
--- a/lib/hipe/ssa/hipe_ssa.inc
+++ b/lib/hipe/ssa/hipe_ssa.inc
@@ -1,8 +1,8 @@
-%% -*- erlang-indent-level: 2 -*-
+%% -*- coding: utf-8; erlang-indent-level: 2 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -19,7 +19,7 @@
%%
%%----------------------------------------------------------------------
%% File : hipe_ssa.inc
-%% Authors : Christoffer Vikstr�m, Daniel Deogun, and Jesper Bengtsson
+%% Authors : Christoffer Vikström, Daniel Deogun, and Jesper Bengtsson
%% Created : March 2002
%% Purpose : Provides code which converts the code of a CFG into SSA
%% (Static Single Assignment) form and back.
diff --git a/lib/hipe/vsn.mk b/lib/hipe/vsn.mk
index 144167f5d1..f3e2e695b5 100644
--- a/lib/hipe/vsn.mk
+++ b/lib/hipe/vsn.mk
@@ -1 +1 @@
-HIPE_VSN = 3.9.2
+HIPE_VSN = 3.9.3
diff --git a/lib/hipe/x86/hipe_x86_assemble.erl b/lib/hipe/x86/hipe_x86_assemble.erl
index 4e65736db3..7878c7219d 100644
--- a/lib/hipe/x86/hipe_x86_assemble.erl
+++ b/lib/hipe/x86/hipe_x86_assemble.erl
@@ -2,7 +2,7 @@
%%%
%%% %CopyrightBegin%
%%%
-%%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%%% Copyright Ericsson AB 2001-2012. All Rights Reserved.
%%%
%%% The contents of this file are subject to the Erlang Public License,
%%% Version 1.1, (the "License"); you may not use this file except in
@@ -698,7 +698,7 @@ mem_to_ea_common(#x86_mem{base=#x86_temp{reg=Base}, off=#x86_imm{value=Off}}) ->
%% jmp_switch
-ifdef(HIPE_AMD64).
-resolve_jmp_switch_arg(I,�_Context) ->
+resolve_jmp_switch_arg(I, _Context) ->
Base = hipe_x86:temp_reg(hipe_x86:jmp_switch_jtab(I)),
Index = hipe_x86:temp_reg(hipe_x86:jmp_switch_temp(I)),
SINDEX = hipe_amd64_encode:sindex(3, Index),
diff --git a/lib/hipe/x86/hipe_x86_postpass.erl b/lib/hipe/x86/hipe_x86_postpass.erl
index 34e3d7a11b..c0918c4f89 100644
--- a/lib/hipe/x86/hipe_x86_postpass.erl
+++ b/lib/hipe/x86/hipe_x86_postpass.erl
@@ -1,8 +1,8 @@
-%%% -*- erlang-indent-level: 2 -*-
+%%% -*- coding: utf-8; erlang-indent-level: 2 -*-
%%%
%%% %CopyrightBegin%
%%%
-%%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%% Copyright Ericsson AB 2003-2012. All Rights Reserved.
%%%
%%% The contents of this file are subject to the Erlang Public License,
%%% Version 1.1, (the "License"); you may not use this file except in
@@ -19,9 +19,9 @@
%%%
%%%----------------------------------------------------------------------
%%% File : hipe_x86_postpass.erl
-%%% Author : Christoffer Vikstr�m <[email protected]>
+%%% Author : Christoffer Vikström <[email protected]>
%%% Purpose : Contain postpass optimisations for x86-assembler code.
-%%% Created : 5 Aug 2003 by Christoffer Vikstr�m <[email protected]>
+%%% Created : 5 Aug 2003 by Christoffer Vikström <[email protected]>
%%%----------------------------------------------------------------------
-ifndef(HIPE_X86_POSTPASS).
diff --git a/lib/hipe/x86/hipe_x86_ra_postconditions.erl b/lib/hipe/x86/hipe_x86_ra_postconditions.erl
index 0b70764daf..6d7e90df43 100644
--- a/lib/hipe/x86/hipe_x86_ra_postconditions.erl
+++ b/lib/hipe/x86/hipe_x86_ra_postconditions.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -224,7 +224,7 @@ do_byte_move(Src0, Dst0, TempMap, Strategy) ->
do_move64(I, TempMap, Strategy) ->
#move64{dst=Dst} = I,
- case�is_spilled(Dst, TempMap) of
+ case is_spilled(Dst, TempMap) of
false ->
{[I], false};
true ->
diff --git a/lib/ic/c_src/Makefile.in b/lib/ic/c_src/Makefile.in
index de46eadb3b..856823b1b3 100644
--- a/lib/ic/c_src/Makefile.in
+++ b/lib/ic/c_src/Makefile.in
@@ -67,7 +67,11 @@ ifeq ($(findstring solaris,$(HOST_OS)),solaris)
SKIP_BUILDING_BINARIES := true
endif
else
+ifeq ($(V),0)
+AR_OUT = rc
+else
AR_OUT = rcv
+endif
CC_FLAGS = @DED_CFLAGS@
LIBRARY = $(LIBDIR)/libic.a
SKIP_BUILDING_BINARIES := false
@@ -128,11 +132,13 @@ docs:
_create_dirs := $(shell mkdir -p $(OBJDIR) $(LIBDIR))
$(LIBRARY): $(OBJ_FILES)
- -$(AR) $(AR_OUT) $@ $(OBJ_FILES)
+ $(ar_verbose)
+ -$(AR) $(AR_OUT) $@ $(OBJ_FILES)
+ $(ranlib_verbose)
-$(RANLIB) $@
$(OBJDIR)/%.o: %.c
- $(CC) $(CC_FLAGS) -c -o $@ $(ALL_CFLAGS) $<
+ $(V_CC) $(CC_FLAGS) -c -o $@ $(ALL_CFLAGS) $<
# ----------------------------------------------------
# Release Target
diff --git a/lib/ic/examples/pre_post_condition/Makefile b/lib/ic/examples/pre_post_condition/Makefile
index d18f81fec9..53e647e793 100644
--- a/lib/ic/examples/pre_post_condition/Makefile
+++ b/lib/ic/examples/pre_post_condition/Makefile
@@ -109,9 +109,9 @@ test: $(TEST_TARGET_FILES)
IDL-GENERATED: ex.idl
- erlc $(ERL_LOCAL_FLAGS) +'{precond,{tracer,pre}}' \
+ $(gen_verbose)erlc $(ERL_LOCAL_FLAGS) +'{precond,{tracer,pre}}' \
+'{{postcond,"m::i::f"},{tracer,post}}' ex.idl
- >IDL-GENERATED
+ $(V_at)>IDL-GENERATED
$(GEN_ERL_MODULES:%=%.erl) $(GEN_HRL_FILES): IDL-GENERATED
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/Makefile b/lib/ic/java_src/com/ericsson/otp/ic/Makefile
index cf4c353f3f..273614e8d9 100644
--- a/lib/ic/java_src/com/ericsson/otp/ic/Makefile
+++ b/lib/ic/java_src/com/ericsson/otp/ic/Makefile
@@ -85,7 +85,10 @@ JAR= jar
JAVADOCFLAGS=-d $(DOCDIR)
JAVAFLAGS=-d $(JAVA_DEST_ROOT)
-JARFLAGS= -cvf
+JARFLAGS= -cf
+ifneq ($(V),0)
+JARFLAGS= -cfv
+endif
JAVA_OPTIONS =
diff --git a/lib/ic/src/Makefile b/lib/ic/src/Makefile
index 280d86a8a4..e8769d2335 100644
--- a/lib/ic/src/Makefile
+++ b/lib/ic/src/Makefile
@@ -175,7 +175,7 @@ clean:
rm -f errs core *~
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
docs:
@@ -183,7 +183,7 @@ docs:
# Special Build Targets
# ----------------------------------------------------
../ebin/icparse.beam: icparse.erl
- $(ERLC) $(ERL_COMPILE_FLAGS) +nowarn_unused_vars +nowarn_unused_function -o$(EBIN) +pj $<
+ $(V_ERLC) $(ERL_COMPILE_FLAGS) +nowarn_unused_vars +nowarn_unused_function -o$(EBIN) +pj $<
icparse.erl: icparse.yrl icyeccpre.hrl
diff --git a/lib/ic/test/java_client_erl_server_SUITE.erl b/lib/ic/test/java_client_erl_server_SUITE.erl
index c2bec94697..9e49305c3c 100644
--- a/lib/ic/test/java_client_erl_server_SUITE.erl
+++ b/lib/ic/test/java_client_erl_server_SUITE.erl
@@ -62,9 +62,14 @@ init_per_suite(Config) when is_list(Config) ->
case case code:priv_dir(jinterface) of
{error,bad_name} ->
false;
- P ->
- filelib:is_dir(P)
- end
+ P ->
+ case filelib:wildcard(filename:join(P, "*.jar")) of
+ [_|_] ->
+ true;
+ [] ->
+ false
+ end
+ end
of
true ->
case find_executable(["java"]) of
diff --git a/lib/ic/test/java_client_erl_server_SUITE_data/Makefile.src b/lib/ic/test/java_client_erl_server_SUITE_data/Makefile.src
index ac8f2e619f..a2440adc92 100644
--- a/lib/ic/test/java_client_erl_server_SUITE_data/Makefile.src
+++ b/lib/ic/test/java_client_erl_server_SUITE_data/Makefile.src
@@ -68,7 +68,7 @@ EBINS = $(ERL_FILES:.erl=.@EMULATOR@)
@IFEQ@ (@jinterface_classpath@,)
all:
-@ELSE
+@ELSE@
all: $(CLASS_FILES) $(EBINS)
@ENDIF@
@@ -86,15 +86,15 @@ clean:
java_erl_test.built_erl java_erl_test.built_java
java_erl_test.built_java: java_erl_test.idl
- $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,java}" java_erl_test.idl
- echo done > java_erl_test.built_java
+ $(gen_verbose)$(ERLC) -I $(IC_INCLUDE_PATH) "+{be,java}" java_erl_test.idl
+ $(V_at)echo done > java_erl_test.built_java
$(CLASS_FILES) : $(JAVA_FILES)
- $(JAVAC) -classpath $(CLASSPATH) $(JAVA_FILES)
+ $(V_JAVAC) -classpath $(CLASSPATH) $(JAVA_FILES)
java_erl_test.built_erl: java_erl_test.idl
- $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,erl_genserv}" java_erl_test.idl
- echo done > java_erl_test.built_erl
+ $(gen_verbose)$(ERLC) -I $(IC_INCLUDE_PATH) "+{be,erl_genserv}" java_erl_test.idl
+ $(V_at)echo done > java_erl_test.built_erl
.erl.@EMULATOR@:
- $(ERLC) -I $(IC_INCLUDE_PATH) $<
+ $(V_ERLC) -I $(IC_INCLUDE_PATH) $<
diff --git a/lib/inets/doc/src/http_uri.xml b/lib/inets/doc/src/http_uri.xml
index bd31ae42d2..d9e8587bbf 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>2012</year>
+ <year>2012</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -55,7 +55,8 @@ string() = list of ASCII characters
<p>For more information about URI, see RFC 3986. </p>
<code type="none"><![CDATA[
-uri() = string() - Syntax according to the URI definition in rfc 3986, ex: "http://www.erlang.org/"
+uri() = string() - Syntax according to the URI definition in rfc 3986,
+ e.g.: "http://www.erlang.org/"
user_info() = string()
scheme() = atom() - Example: http, https
host() = string()
diff --git a/lib/inets/doc/src/httpd.xml b/lib/inets/doc/src/httpd.xml
index 7e21229fcf..3fced5dfcd 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>2011</year>
+ <year>1997</year><year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -178,7 +178,13 @@
<p>Note that this option is only used when the option
<c>socket_type</c> has the value <c>ip_comm</c>. </p>
</item>
-
+ <marker id="prop_minimum_bytes_per_second"></marker>
+ <tag>{minimum_bytes_per_second, integer()}</tag>
+ <item>
+ <p>If given, sets a minimum bytes per second value for connections.</p>
+ <p>If the value is not reached, the socket will close for that connection.</p>
+ <p>The option is good for reducing the risk of "slow dos" attacks.</p>
+ </item>
</taglist>
<marker id="props_api_modules"></marker>
diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml
index 3aae1ff70a..e0d6ae3454 100644
--- a/lib/inets/doc/src/notes.xml
+++ b/lib/inets/doc/src/notes.xml
@@ -33,7 +33,27 @@
</header>
- <section>
+ <section><title>Inets 5.9.2</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Minimum bytes per second</p>
+ <p>
+ New option to http server, {minimum_bytes_per_second,
+ integer()}, for a connection, if it is not reached the
+ socket will close for that specific connection. Can be
+ used to prevent hanging requests from faulty clients.</p>
+ <p>
+ Own Id: OTP-10392</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section>
<title>Inets 5.9.1</title>
<section>
diff --git a/lib/inets/src/http_server/httpd_conf.erl b/lib/inets/src/http_server/httpd_conf.erl
index 747118431e..a97bbd9b25 100644
--- a/lib/inets/src/http_server/httpd_conf.erl
+++ b/lib/inets/src/http_server/httpd_conf.erl
@@ -483,7 +483,7 @@ validate_properties(Properties) ->
case mandatory_properties(Properties) of
ok ->
%% Second, check that property dependency are ok
- {ok, validate_properties2(Properties)};
+ {ok, check_minimum_bytes_per_second(validate_properties2(Properties))};
Error ->
throw(Error)
end.
@@ -522,7 +522,18 @@ validate_properties2(Properties) ->
throw(Error)
end
end.
-
+check_minimum_bytes_per_second(Properties) ->
+ case proplists:get_value(minimum_bytes_per_second, Properties, false) of
+ false ->
+ Properties;
+ Nr ->
+ case is_integer(Nr) of
+ false ->
+ throw({error, {minimum_bytes_per_second, is_not_integer}});
+ _ ->
+ Properties
+ end
+ end.
mandatory_properties(ConfigList) ->
a_must(ConfigList, [server_name, port, server_root, document_root]).
diff --git a/lib/inets/src/http_server/httpd_request_handler.erl b/lib/inets/src/http_server/httpd_request_handler.erl
index b62c10bbc7..0f47d785ef 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-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -44,7 +44,9 @@
timeout, %% infinity | integer() > 0
timer, %% ref() - Request timer
headers, %% #http_request_h{}
- body %% binary()
+ body, %% binary()
+ data, %% The total data received in bits, checked after 10s
+ byte_limit %% Bit limit per second before kick out
}).
%%====================================================================
@@ -98,7 +100,6 @@ init([Manager, ConfigDB, AcceptTimeout]) ->
[{socket_type, SocketType}, {socket, Socket}]),
TimeOut = httpd_util:lookup(ConfigDB, keep_alive_timeout, 150000),
-
Then = erlang:now(),
?hdrd("negotiate", []),
@@ -139,12 +140,11 @@ continue_init(Manager, ConfigDB, SocketType, Socket, TimeOut) ->
mfa = MFA},
?hdrt("activate request timeout", []),
- NewState = activate_request_timeout(State),
?hdrt("set socket options (binary, packet & active)", []),
http_transport:setopts(SocketType, Socket,
[binary, {packet, 0}, {active, once}]),
-
+ NewState = data_receive_counter(activate_request_timeout(State), httpd_util:lookup(ConfigDB, minimum_bytes_per_second, false)),
?hdrt("init done", []),
gen_server:enter_loop(?MODULE, [], NewState).
@@ -205,16 +205,25 @@ handle_info({Proto, Socket, Data},
?hdrd("received data",
[{data, Data}, {proto, Proto},
{socket, Socket}, {socket_type, SockType}, {mfa, MFA}]),
-
+
%% case (catch Module:Function([Data | Args])) of
PROCESSED = (catch Module:Function([Data | Args])),
-
+ NewDataSize = case State#state.byte_limit of
+ undefined ->
+ undefined;
+ _ ->
+ State#state.data + byte_size(Data)
+ end,
?hdrt("data processed", [{processing_result, PROCESSED}]),
-
case PROCESSED of
{ok, Result} ->
?hdrd("data processed", [{result, Result}]),
- NewState = cancel_request_timeout(State),
+ NewState = case NewDataSize of
+ undefined ->
+ cancel_request_timeout(State);
+ _ ->
+ set_new_data_size(cancel_request_timeout(State), NewDataSize)
+ end,
handle_http_msg(Result, NewState);
{error, {uri_too_long, MaxSize}, Version} ->
@@ -239,7 +248,12 @@ handle_info({Proto, Socket, Data},
NewMFA ->
?hdrd("data processed - reactivate socket", [{new_mfa, NewMFA}]),
http_transport:setopts(SockType, Socket, [{active, once}]),
- {noreply, State#state{mfa = NewMFA}}
+ case NewDataSize of
+ undefined ->
+ {noreply, State#state{mfa = NewMFA}};
+ _ ->
+ {noreply, State#state{mfa = NewMFA, data = NewDataSize}}
+ end
end;
%% Error cases
@@ -263,7 +277,22 @@ handle_info(timeout, #state{mod = ModData} = State) ->
error_log("The client did not send the whole request before the "
"server side timeout", ModData),
{stop, normal, State#state{response_sent = true}};
-
+handle_info(check_data_first, #state{data = Data, byte_limit = Byte_Limit} = State) ->
+ case Data >= (Byte_Limit*3) of
+ true ->
+ erlang:send_after(1000, self(), check_data),
+ {noreply, State#state{data = 0}};
+ _ ->
+ {stop, normal, State#state{response_sent = true}}
+ end;
+handle_info(check_data, #state{data = Data, byte_limit = Byte_Limit} = State) ->
+ case Data >= Byte_Limit of
+ true ->
+ erlang:send_after(1000, self(), check_data),
+ {noreply, State#state{data = 0}};
+ _ ->
+ {stop, normal, State#state{response_sent = true}}
+ end;
%% Default case
handle_info(Info, #state{mod = ModData} = State) ->
Error = lists:flatten(
@@ -311,6 +340,8 @@ code_change(_OldVsn, State, _Extra) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
+set_new_data_size(State, NewData) ->
+ State#state{data = NewData}.
await_socket_ownership_transfer(AcceptTimeout) ->
receive
{socket_ownership_transfered, SocketType, Socket} ->
@@ -603,7 +634,14 @@ activate_request_timeout(#state{timeout = Time} = State) ->
?hdrt("activate request timeout", [{time, Time}]),
Ref = erlang:send_after(Time, self(), timeout),
State#state{timer = Ref}.
-
+data_receive_counter(State, Byte_limit) ->
+ case Byte_limit of
+ false ->
+ State#state{data = 0};
+ Nr ->
+ erlang:send_after(3000, self(), check_data_first),
+ State#state{data = 0, byte_limit = Nr}
+ end.
cancel_request_timeout(#state{timer = undefined} = State) ->
State;
cancel_request_timeout(#state{timer = Timer} = State) ->
diff --git a/lib/inets/src/inets_app/Makefile b/lib/inets/src/inets_app/Makefile
index 7d68145287..22426eee79 100644
--- a/lib/inets/src/inets_app/Makefile
+++ b/lib/inets/src/inets_app/Makefile
@@ -99,10 +99,10 @@ docs:
# ----------------------------------------------------
$(APP_TARGET): $(APP_SRC) ../../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
# ----------------------------------------------------
diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src
index 2adb2a0fc8..ffd0ed622f 100644
--- a/lib/inets/src/inets_app/inets.appup.src
+++ b/lib/inets/src/inets_app/inets.appup.src
@@ -18,8 +18,14 @@
{"%VSN%",
[
+ {"5.9.1",
+ [
+ {load_module, httpd_request_handler, soft_purge, soft_purge, []}
+ ]
+ },
{"5.9",
[
+ {load_module, httpd_request_handler, soft_purge, soft_purge, []},
{load_module, tftp, soft_purge, soft_purge, [inets_service]},
{load_module, inets_service, soft_purge, soft_purge, []},
{load_module, httpc, soft_purge, soft_purge, [httpc_manager]},
@@ -29,6 +35,7 @@
},
{"5.8.1",
[
+ {load_module, httpd_request_handler, soft_purge, soft_purge, []},
{load_module, tftp, soft_purge, soft_purge, [inets_service]},
{load_module, inets_service, soft_purge, soft_purge, []},
@@ -64,8 +71,14 @@
}
],
[
+ {"5.9.1",
+ [
+ {load_module, httpd_request_handler, soft_purge, soft_purge, []}
+ ]
+ },
{"5.9",
[
+ {load_module, httpd_request_handler, soft_purge, soft_purge, []},
{load_module, tftp, soft_purge, soft_purge, [inets_service]},
{load_module, inets_service, soft_purge, soft_purge, []},
{load_module, httpc, soft_purge, soft_purge, [httpc_manager]},
@@ -75,6 +88,7 @@
},
{"5.8.1",
[
+ {load_module, httpd_request_handler, soft_purge, soft_purge, []},
{load_module, tftp, soft_purge, soft_purge, [inets_service]},
{load_module, inets_service, soft_purge, soft_purge, []},
diff --git a/lib/inets/test/erl_make_certs.erl b/lib/inets/test/erl_make_certs.erl
index 254aa6d2f9..d6bdd05d01 100644
--- a/lib/inets/test/erl_make_certs.erl
+++ b/lib/inets/test/erl_make_certs.erl
@@ -137,10 +137,10 @@ decode_key(PemBin, Pw) ->
encode_key(Key = #'RSAPrivateKey'{}) ->
{ok, Der} = 'OTP-PUB-KEY':encode('RSAPrivateKey', Key),
- {'RSAPrivateKey', list_to_binary(Der), not_encrypted};
+ {'RSAPrivateKey', Der, not_encrypted};
encode_key(Key = #'DSAPrivateKey'{}) ->
{ok, Der} = 'OTP-PUB-KEY':encode('DSAPrivateKey', Key),
- {'DSAPrivateKey', list_to_binary(Der), not_encrypted}.
+ {'DSAPrivateKey', Der, not_encrypted}.
make_tbs(SubjectKey, Opts) ->
Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))),
diff --git a/lib/inets/test/ftp_suite_lib.erl b/lib/inets/test/ftp_suite_lib.erl
index ffb58c91b6..211c9b5bee 100644
--- a/lib/inets/test/ftp_suite_lib.erl
+++ b/lib/inets/test/ftp_suite_lib.erl
@@ -206,7 +206,6 @@ init_per_testcase(Case, Config)
init_per_testcase(Case, Config) ->
put(ftp_testcase, Case),
- inets:enable_trace(max, io, ftpc),
do_init_per_testcase(Case, Config).
do_init_per_testcase(Case, Config)
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index cb81d2cc5e..644b01120c 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -337,7 +337,6 @@ init_per_testcase(Case, Timeout, Config) ->
%% so this value will be overwritten (see "ipv6_" below).
%% </IPv6>
- inets:enable_trace(max, io, httpc),
%% inets:enable_trace(max, io, all),
%% snmp:set_trace([gen_tcp]),
tsp("init_per_testcase(~w) -> done when"
@@ -381,7 +380,6 @@ end_per_testcase(http_save_to_file = Case, Config) ->
end_per_testcase(Case, Config) ->
io:format(user, "~n~n*** END ~w:~w ***~n~n",
[?MODULE, Case]),
- dbg:stop(), % ?
case atom_to_list(Case) of
"ipv6_" ++ _Rest ->
tsp("end_per_testcase(~w) -> stop ssl", [Case]),
diff --git a/lib/inets/test/httpc_cookie_SUITE.erl b/lib/inets/test/httpc_cookie_SUITE.erl
index 93dbc270c5..3862bf7a20 100644
--- a/lib/inets/test/httpc_cookie_SUITE.erl
+++ b/lib/inets/test/httpc_cookie_SUITE.erl
@@ -276,8 +276,6 @@ secure_cookie(Config) when is_list(Config) ->
tsp("secure_cookie -> entry with"
"~n Config: ~p", [Config]),
- inets:enable_trace(max, io, httpc),
-
%% httpc:reset_cookies(),
tsp("secure_cookie -> Cookies 1: ~p", [httpc:which_cookies()]),
@@ -309,7 +307,6 @@ secure_cookie(Config) when is_list(Config) ->
tsp("secure_cookie -> Cookies 4: ~p", [httpc:which_cookies()]),
- inets:disable_trace(),
tsp("secure_cookie -> done"),
ok.
diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl
index 58f7d4fa25..592469a12f 100644
--- a/lib/inets/test/httpd_SUITE.erl
+++ b/lib/inets/test/httpd_SUITE.erl
@@ -530,24 +530,10 @@ init_per_testcase3(Case, Config) ->
application:stop(inets),
application:stop(ssl),
cleanup_mnesia(),
-
- %% Set trace level
- case lists:reverse(atom_to_list(Case)) of
- "tset_emit" ++ _Rest -> % test-cases ending with time_test
- tsp("init_per_testcase3(~w) -> disabling trace", [Case]),
- inets:disable_trace();
- _ ->
- tsp("init_per_testcase3(~w) -> enabling trace", [Case]),
- %% TraceLevel = 70,
- TraceLevel = max,
- TraceDest = io,
- inets:enable_trace(TraceLevel, TraceDest, httpd)
- end,
-
+
%% Start initialization
tsp("init_per_testcase3(~w) -> start init", [Case]),
-
-
+
Dog = test_server:timetrap(inets_test_lib:minutes(10)),
NewConfig = lists:keydelete(watchdog, 1, Config),
TcTopDir = ?config(tc_top_dir, Config),
diff --git a/lib/inets/test/httpd_basic_SUITE.erl b/lib/inets/test/httpd_basic_SUITE.erl
index 7a476ea14a..523cf9d38c 100644
--- a/lib/inets/test/httpd_basic_SUITE.erl
+++ b/lib/inets/test/httpd_basic_SUITE.erl
@@ -34,7 +34,8 @@ all() ->
[
uri_too_long_414,
header_too_long_413,
- escaped_url_in_error_body
+ escaped_url_in_error_body,
+ slowdose
].
groups() ->
@@ -278,7 +279,18 @@ escaped_url_in_error_body(Config) when is_list(Config) ->
inets:stop(httpd, Pid),
tsp("escaped_url_in_error_body -> done"),
ok.
-
+slowdose(doc) ->
+ ["Testing minimum bytes per second option"];
+slowdose(Config) when is_list(Config) ->
+ HttpdConf = ?config(httpd_conf, Config),
+ {ok, Pid} = inets:start(httpd, [{port, 0}, {minimum_bytes_per_second, 200}|HttpdConf]),
+ Info = httpd:info(Pid),
+ Port = proplists:get_value(port, Info),
+ {ok, Socket} = gen_tcp:connect("localhost", Port, []),
+ receive
+ after 6000 ->
+ {error, closed} = gen_tcp:send(Socket, "Hey")
+ end.
find_URL_path([]) ->
"";
find_URL_path(["URL", URL | _]) ->
diff --git a/lib/inets/test/inets_SUITE.erl b/lib/inets/test/inets_SUITE.erl
index 6fa0f44d77..069c68fa1e 100644
--- a/lib/inets/test/inets_SUITE.erl
+++ b/lib/inets/test/inets_SUITE.erl
@@ -363,8 +363,6 @@ start_ftpc(suite) ->
[];
start_ftpc(Config) when is_list(Config) ->
process_flag(trap_exit, true),
- inets:disable_trace(),
- inets:enable_trace(max, io, ftpc),
ok = inets:start(),
try
begin
@@ -393,16 +391,13 @@ start_ftpc(Config) when is_list(Config) ->
tsf(stand_alone_not_shutdown)
end,
ok = inets:stop(),
- inets:disable_trace(),
ok;
_ ->
- inets:disable_trace(),
{skip, "Unable to reach selected FTP server " ++ FtpdHost}
end
end
catch
throw:{error, not_found} ->
- inets:disable_trace(),
{skip, "No available FTP servers"}
end.
@@ -462,8 +457,6 @@ httpd_reload(Config) when is_list(Config) ->
{document_root, PrivDir},
{bind_address, "localhost"}],
- inets:enable_trace(max, io),
-
i("httpd_reload -> start inets"),
ok = inets:start(),
diff --git a/lib/inets/test/inets_app_test.erl b/lib/inets/test/inets_app_test.erl
index db2218f3b6..eabfa69f7c 100644
--- a/lib/inets/test/inets_app_test.erl
+++ b/lib/inets/test/inets_app_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -35,6 +35,15 @@
init_per_testcase(undef_funcs, Config) ->
NewConfig = lists:keydelete(watchdog, 1, Config),
Dog = test_server:timetrap(inets_test_lib:minutes(10)),
+
+ %% We need to check if there is a point to run this test.
+ %% On some platforms, crypto will not build, which in turn
+ %% causes ssl to not build (at this time, this will
+ %% change in the future).
+ %% So, we first check if we can start crypto, and if not,
+ %% we skip this test case!
+ ?ENSURE_STARTED(crypto),
+
[{watchdog, Dog}| NewConfig];
init_per_testcase(_, Config) ->
Config.
@@ -240,13 +249,6 @@ undef_funcs(suite) ->
undef_funcs(doc) ->
[];
undef_funcs(Config) when is_list(Config) ->
- %% We need to check if there is a point to run this test.
- %% On some platforms, crypto will not build, which in turn
- %% causes ssl to not build (at this time, this will
- %% change in the future).
- %% So, we first check if we can start crypto, and if not,
- %% we skip this test case!
- ?ENSURE_STARTED(crypto),
App = inets,
AppFile = key1search(app_file, Config),
Mods = key1search(modules, AppFile),
diff --git a/lib/inets/test/inets_sup_SUITE.erl b/lib/inets/test/inets_sup_SUITE.erl
index 1d262a2739..65f0f0e09a 100644
--- a/lib/inets/test/inets_sup_SUITE.erl
+++ b/lib/inets/test/inets_sup_SUITE.erl
@@ -226,8 +226,6 @@ ftpc_worker(doc) ->
ftpc_worker(suite) ->
[];
ftpc_worker(Config) when is_list(Config) ->
- inets:disable_trace(),
- inets:enable_trace(max, io, ftpc),
[] = supervisor:which_children(ftp_sup),
try
begin
@@ -239,20 +237,16 @@ ftpc_worker(Config) when is_list(Config) ->
inets:stop(ftpc, Pid),
test_server:sleep(5000),
[] = supervisor:which_children(ftp_sup),
- inets:disable_trace(),
ok;
Children ->
- inets:disable_trace(),
exit({unexpected_children, Children})
end;
_ ->
- inets:disable_trace(),
{skip, "Unable to reach test FTP server"}
end
end
catch
throw:{error, not_found} ->
- inets:disable_trace(),
{skip, "No available FTP servers"}
end.
diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk
index 949eceea7f..0c7cb5e7c2 100644
--- a/lib/inets/vsn.mk
+++ b/lib/inets/vsn.mk
@@ -18,7 +18,7 @@
# %CopyrightEnd%
APPLICATION = inets
-INETS_VSN = 5.9.1
+INETS_VSN = 5.9.2
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)"
diff --git a/lib/jinterface/java_src/Makefile b/lib/jinterface/java_src/Makefile
index 19f99831eb..0aa9c09548 100644
--- a/lib/jinterface/java_src/Makefile
+++ b/lib/jinterface/java_src/Makefile
@@ -47,7 +47,7 @@ POM_SRC= $(POM_FILE).src
# ----------------------------------------------------
$(POM_TARGET): $(POM_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
include $(ERL_TOP)/make/otp_subdir.mk
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile b/lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile
index 8ae63a1561..f476d4594d 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile
@@ -61,7 +61,10 @@ CLASSPATH = $(JAVA_SRC_ROOT)
JAVADOCFLAGS=-d $(DOCDIR)
JAVAFLAGS=-d $(JAVA_DEST_ROOT)
-JARFLAGS=-cvf
+JARFLAGS=-cf
+ifneq ($(V),0)
+JARFLAGS=-cfv
+endif
JAVA_OPTIONS =
@@ -79,13 +82,13 @@ endif
debug opt: make_dirs $(JAVA_DEST_ROOT)$(JARFILE)
make_dirs:
- if [ ! -d "$(JAVA_DEST_ROOT)" ];then mkdir "$(JAVA_DEST_ROOT)"; fi
+ $(V_at)if [ ! -d "$(JAVA_DEST_ROOT)" ];then mkdir "$(JAVA_DEST_ROOT)"; fi
$(JAVA_DEST_ROOT)$(JARFILE): $(TARGET_FILES)
@(cd $(JAVA_DEST_ROOT) ; $(JAR) $(JARFLAGS) $(JARFILE) $(JAVA_CLASS_SUBDIR))
clean:
- rm -f $(TARGET_FILES) *~
+ $(V_at)rm -f $(TARGET_FILES) *~
docs:
@@ -96,13 +99,13 @@ docs:
# include $(ERL_TOP)/make/otp_release_targets.mk
release release_docs release_tests release_html:
- $(MAKE) $(MFLAGS) RELEASE_PATH="$(RELEASE_PATH)" $(TARGET_MAKEFILE) $@_spec
+ $(V_at)$(MAKE) $(MFLAGS) RELEASE_PATH="$(RELEASE_PATH)" $(TARGET_MAKEFILE) $@_spec
release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/java_src/com/ericsson/otp/erlang"
- $(INSTALL_DATA) $(JAVA_SRC) "$(RELSYSDIR)/java_src/com/ericsson/otp/erlang"
- $(INSTALL_DIR) "$(RELSYSDIR)/priv"
- $(INSTALL_DATA) $(JAVA_DEST_ROOT)$(JARFILE) "$(RELSYSDIR)/priv"
+ $(V_at)$(INSTALL_DIR) "$(RELSYSDIR)/java_src/com/ericsson/otp/erlang"
+ $(V_at)$(INSTALL_DATA) $(JAVA_SRC) "$(RELSYSDIR)/java_src/com/ericsson/otp/erlang"
+ $(V_at)$(INSTALL_DIR) "$(RELSYSDIR)/priv"
+ $(V_at)$(INSTALL_DATA) $(JAVA_DEST_ROOT)$(JARFILE) "$(RELSYSDIR)/priv"
release_docs_spec:
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpEpmd.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpEpmd.java
index deac528133..b985f8aa50 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpEpmd.java
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpEpmd.java
@@ -358,7 +358,7 @@ public class OtpEpmd {
}
public static String[] lookupNames() throws IOException {
- return lookupNames(InetAddress.getLocalHost());
+ return lookupNames(InetAddress.getByName(null));
}
public static String[] lookupNames(final InetAddress address)
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpInputStream.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpInputStream.java
index b9b43481ee..ae5f4ee072 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpInputStream.java
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpInputStream.java
@@ -1112,12 +1112,16 @@ public class OtpInputStream extends ByteArrayInputStream {
final int size = read4BE();
final byte[] buf = new byte[size];
final java.util.zip.InflaterInputStream is =
- new java.util.zip.InflaterInputStream(this);
+ new java.util.zip.InflaterInputStream(this, new java.util.zip.Inflater(), size);
+ int curPos = 0;
try {
- final int dsize = is.read(buf, 0, size);
- if (dsize != size) {
+ int curRead;
+ while(curPos < size && (curRead = is.read(buf, curPos, size - curPos)) != -1) {
+ curPos += curRead;
+ }
+ if (curPos != size) {
throw new OtpErlangDecodeException("Decompression gave "
- + dsize + " bytes, not " + size);
+ + curPos + " bytes, not " + size);
}
} catch (final IOException e) {
throw new OtpErlangDecodeException("Cannot read from input stream");
diff --git a/lib/jinterface/test/jitu.erl b/lib/jinterface/test/jitu.erl
index fb262cf9d7..571a2dc9c7 100644
--- a/lib/jinterface/test/jitu.erl
+++ b/lib/jinterface/test/jitu.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2012. All Rights Reserved.
%%
%% The 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/jinterface/test/nc_SUITE.erl b/lib/jinterface/test/nc_SUITE.erl
index 9c88400c2a..c91c743498 100644
--- a/lib/jinterface/test/nc_SUITE.erl
+++ b/lib/jinterface/test/nc_SUITE.erl
@@ -1,7 +1,8 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -89,7 +90,7 @@ end_per_suite(Config) ->
init_per_testcase(Case, Config) ->
T = case atom_to_list(Case) of
"unicode"++_ -> 240;
- _ -> 20
+ _ -> 30
end,
WatchDog = test_server:timetrap(test_server:seconds(T)),
[{watchdog, WatchDog}| Config].
@@ -187,10 +188,18 @@ binary_roundtrip(Config) when is_list(Config) ->
decompress_roundtrip(doc) -> [];
decompress_roundtrip(suite) -> [];
decompress_roundtrip(Config) when is_list(Config) ->
+ RandomBin = erlang:term_to_binary(lists:seq(1, 5 * 1024 * 1024)), % roughly 26MB
+ <<RandomBin1k:1024/binary,_/binary>> = RandomBin,
+ <<RandomBin1M:1048576/binary,_/binary>> = RandomBin,
+ <<RandomBin10M:10485760/binary,_/binary>> = RandomBin,
Terms =
[0.0,
math:sqrt(2),
<<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,31:5>>,
+ RandomBin1k,
+ RandomBin1M,
+ RandomBin10M,
+ RandomBin,
make_ref()],
OutTrans =
fun (D) ->
@@ -205,10 +214,18 @@ decompress_roundtrip(Config) when is_list(Config) ->
compress_roundtrip(doc) -> [];
compress_roundtrip(suite) -> [];
compress_roundtrip(Config) when is_list(Config) ->
+ RandomBin = erlang:term_to_binary(lists:seq(1, 5 * 1024 * 1024)), % roughly 26MB
+ <<RandomBin1k:1024/binary,_/binary>> = RandomBin,
+ <<RandomBin1M:1048576/binary,_/binary>> = RandomBin,
+ <<RandomBin10M:10485760/binary,_/binary>> = RandomBin,
Terms =
[0.0,
math:sqrt(2),
<<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,31:5>>,
+ RandomBin1k,
+ RandomBin1M,
+ RandomBin10M,
+ RandomBin,
make_ref()],
OutTrans =
fun (D) ->
@@ -345,8 +362,8 @@ unicode(doc) -> [];
unicode(suite) -> [];
unicode(Config) when is_list(Config) ->
S1 = "plain ascii",
- S2 = "iso-latin ��� �",
- S3 = "Codepoints... ��� \x{1000}",
+ S2 = "iso-latin åäö ñ",
+ S3 = "Codepoints... åäö \x{1000}",
S4 = [0,1,31,32,63,64,127,128,255],
S5 = [0,1,127,128,255,256,16#d7ff,
16#e000,16#fffd,16#10000,16#10ffff],
diff --git a/lib/kernel/doc/src/Makefile b/lib/kernel/doc/src/Makefile
index 5e04bff0c1..de3ca1e176 100644
--- a/lib/kernel/doc/src/Makefile
+++ b/lib/kernel/doc/src/Makefile
@@ -58,7 +58,6 @@ XML_REF3_FILES = application.xml \
net_adm.xml \
net_kernel.xml \
os.xml \
- packages.xml \
pg2.xml \
rpc.xml \
seq_trace.xml \
diff --git a/lib/kernel/doc/src/application.xml b/lib/kernel/doc/src/application.xml
index 51a3311ec2..9f19efc793 100644
--- a/lib/kernel/doc/src/application.xml
+++ b/lib/kernel/doc/src/application.xml
@@ -121,6 +121,15 @@
</desc>
</func>
<func>
+ <name name="get_env" arity="3"/>
+ <fsummary>Get the value of a configuration parameter using a default</fsummary>
+ <desc>
+ <p>Works like <seealso marker="#get_env/2">get_env/2</seealso> but returns
+ <c><anno>Def</anno></c> value when configuration parameter
+ <c><anno>Par</anno></c> does not exist.</p>
+ </desc>
+ </func>
+ <func>
<name name="get_key" arity="1"/>
<name name="get_key" arity="2"/>
<fsummary>Get the value of an application specification key</fsummary>
diff --git a/lib/kernel/doc/src/error_handler.xml b/lib/kernel/doc/src/error_handler.xml
index acbf9a2c6e..610b65f0a2 100644
--- a/lib/kernel/doc/src/error_handler.xml
+++ b/lib/kernel/doc/src/error_handler.xml
@@ -43,19 +43,39 @@
A (possibly empty) list of arguments <c>Arg1,..,ArgN</c>
</type_desc>
<desc>
- <p>This function is evaluated if a call is made to
+ <p>This function is called by the run-time system if a call is made to
<c><anno>Module</anno>:<anno>Function</anno>(Arg1,.., ArgN)</c> and
<c><anno>Module</anno>:<anno>Function</anno>/N</c> is undefined. Note that
<c>undefined_function/3</c> is evaluated inside the process
making the original call.</p>
- <p>If <c><anno>Module</anno></c> is interpreted, the interpreter is invoked
- and the return value of the interpreted
- <c><anno>Function</anno>(Arg1,.., ArgN)</c> call is returned.</p>
- <p>Otherwise, it returns, if possible, the value of
- <c>apply(<anno>Module</anno>, <anno>Function</anno>, <anno>Args</anno>)</c> after an attempt has been
- made to autoload <c><anno>Module</anno></c>. If this is not possible, the
- call to <c><anno>Module</anno>:<anno>Function</anno>(Arg1,.., ArgN)</c> fails with
- exit reason <c>undef</c>.</p>
+
+ <p>This function will first attempt to autoload
+ <c><anno>Module</anno></c>. If that is not possible,
+ an <c>undef</c> exception will be raised.</p>
+
+ <p>If it was possible to load <c><anno>Module</anno></c>
+ and the function <c><anno>Function</anno>/N</c> is exported,
+ it will be called.</p>
+
+ <p>Otherwise, if the function <c>'$handle_undefined_function'/2</c>
+ is exported, it will be called as
+ <c>'$handle_undefined_function'(</c><anno>Function</anno>,
+ <anno>Args</anno>).
+ </p>
+ <p>Otherwise an <c>undef</c> exception will be raised.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="raise_undef_exception" arity="3"/>
+ <fsummary>Raise an undef exception</fsummary>
+ <type_desc variable="Args">
+ A (possibly empty) list of arguments <c>Arg1,..,ArgN</c>
+ </type_desc>
+ <desc>
+ <p>Raise an <c>undef</c> exception with a stacktrace indicating
+ that <c><anno>Module</anno>:<anno>Function</anno>/N</c> is
+ undefined.
+ </p>
</desc>
</func>
<func>
diff --git a/lib/kernel/doc/src/file.xml b/lib/kernel/doc/src/file.xml
index b2a259080d..e30ade1bd2 100644
--- a/lib/kernel/doc/src/file.xml
+++ b/lib/kernel/doc/src/file.xml
@@ -110,7 +110,7 @@
<desc>
<p>As returned by
<seealso marker="#open/2">file:open/2</seealso>,
- a process handling IO protocols.</p>
+ a process handling I/O-protocols.</p>
</desc>
</datatype>
<datatype>
@@ -170,6 +170,18 @@
</desc>
</func>
<func>
+ <name name="allocate" arity="3"/>
+ <fsummary>Allocate file space</fsummary>
+ <desc>
+ <p><c>allocate/3</c> can be used to preallocate space for a file.</p>
+ <p>This function only succeeds in platforms that implement this
+ feature. When it succeeds, space is preallocated for the file but
+ the file size might not be updated. This behaviour depends on the
+ preallocation implementation. To guarantee the file size is updated
+ one must truncate the file to the new size.</p>
+ </desc>
+ </func>
+ <func>
<name name="change_group" arity="2"/>
<fsummary>Change group of a file</fsummary>
<desc>
@@ -261,6 +273,9 @@
{person, "pelle", 30}.</code>
<pre>1> <input>file:consult("f.txt").</input>
{ok,[{person,"kalle",25},{person,"pelle",30}]}</pre>
+ <p>The encoding of of <c><anno>Filename</anno></c> can be set
+ by a comment as described in <seealso
+ marker="stdlib:epp#encoding">epp(3)</seealso>.</p>
</desc>
</func>
<func>
@@ -399,6 +414,9 @@
of the error.</p>
</item>
</taglist>
+ <p>The encoding of of <c><anno>Filename</anno></c> can be set
+ by a comment as described in <seealso
+ marker="stdlib:epp#encoding">epp(3)</seealso>.</p>
</desc>
</func>
<func>
@@ -610,7 +628,7 @@
<name name="open" arity="2"/>
<fsummary>Open a file</fsummary>
<desc>
- <p>Opens the file <c><anno>Filename</anno></c> in the mode determined
+ <p>Opens the file <c><anno>File</anno></c> in the mode determined
by <c><anno>Modes</anno></c>, which may contain one or more of the
following items:</p>
<taglist>
@@ -767,6 +785,10 @@
<p>The Encoding can be changed for a file "on the fly" by using the <seealso marker="stdlib:io#setopts/2">io:setopts/2</seealso> function, why a file can be analyzed in latin1 encoding for i.e. a BOM, positioned beyond the BOM and then be set for the right encoding before further reading.See the <seealso marker="stdlib:unicode">unicode(3)</seealso> module for functions identifying BOM's.</p>
<p>This option is not allowed on <c>raw</c> files.</p>
</item>
+ <tag><c>ram</c></tag>
+ <item>
+ <p><c>File</c> must be <c>iodata()</c>. Returns an <c>fd()</c> which lets the <c>file</c> module operate on the data in-memory as if it is a file.</p>
+ </item>
</taglist>
<p>Returns:</p>
<taglist>
@@ -861,6 +883,9 @@
the error.</p>
</item>
</taglist>
+ <p>The encoding of of <c><anno>Filename</anno></c> can be set
+ by a comment as described in <seealso
+ marker="stdlib:epp#encoding">epp(3)</seealso>.</p>
</desc>
</func>
<func>
@@ -902,6 +927,9 @@
of the error.</p>
</item>
</taglist>
+ <p>The encoding of of <c><anno>Filename</anno></c> can be set
+ by a comment as described in <seealso
+ marker="stdlib:epp#encoding">epp(3)</seealso>.</p>
</desc>
</func>
<func>
@@ -971,7 +999,10 @@
of the error.</p>
</item>
</taglist>
- </desc>
+ <p>The encoding of of <c><anno>Filename</anno></c> can be set
+ by a comment as described in <seealso
+ marker="stdlib:epp#encoding">epp(3)</seealso>.</p>
+ </desc>
</func>
<func>
<name name="path_script" arity="3"/>
@@ -1502,6 +1533,9 @@
of the error.</p>
</item>
</taglist>
+ <p>The encoding of of <c><anno>Filename</anno></c> can be set
+ by a comment as described in <seealso
+ marker="stdlib:epp#encoding">epp(3)</seealso>.</p>
</desc>
</func>
<func>
diff --git a/lib/kernel/doc/src/heart.xml b/lib/kernel/doc/src/heart.xml
index 26d1e27822..2856d84dcf 100644
--- a/lib/kernel/doc/src/heart.xml
+++ b/lib/kernel/doc/src/heart.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2011</year>
+ <year>1996</year><year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -71,6 +71,39 @@
timeout and try to reboot the system. This can happen, for
example, if the system clock is adjusted automatically by use of
NTP (Network Time Protocol).</p>
+
+ <p> If a crash occurs, an <c><![CDATA[erl_crash.dump]]></c> will <em>not</em> be written
+ unless the environment variable <c><![CDATA[ERL_CRASH_DUMP_SECONDS]]></c> is set.
+ </p>
+
+ <pre>
+% <input>erl -heart -env ERL_CRASH_DUMP_SECONDS 10 ...</input></pre>
+ <p>
+ Furthermore, <c><![CDATA[ERL_CRASH_DUMP_SECONDS]]></c> has the following behaviour on
+ <c>heart</c>:
+ </p>
+ <taglist>
+ <tag><c><![CDATA[ERL_CRASH_DUMP_SECONDS=0]]></c></tag>
+ <item><p>
+ Suppresses the writing a crash dump file entirely,
+ thus rebooting the runtime system immediately.
+ This is the same as not setting the environment variable.
+ </p>
+ </item>
+ <tag><c><![CDATA[ERL_CRASH_DUMP_SECONDS=-1]]></c></tag>
+ <item><p> Setting the environment variable to a negative value will not reboot
+ the runtime system until the crash dump file has been completly written.
+ </p>
+ </item>
+ <tag><c><![CDATA[ERL_CRASH_DUMP_SECONDS=S]]></c></tag>
+ <item><p>
+ Heart will wait for <c>S</c> seconds to let the crash dump file be written.
+ After <c>S</c> seconds <c>heart</c> will reboot the runtime system regardless of
+ the crash dump file has been written or not.
+ </p>
+ </item>
+ </taglist>
+
<p>In the following descriptions, all function fails with reason
<c>badarg</c> if <c>heart</c> is not started.</p>
</description>
diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml
index 32b4a429dd..3d929a772e 100644
--- a/lib/kernel/doc/src/inet.xml
+++ b/lib/kernel/doc/src/inet.xml
@@ -323,8 +323,11 @@ fe80::204:acff:fe17:bf38
<type name="stat_option"/>
<desc>
<p>Gets one or more statistic options for a socket.</p>
+
<p><c>getstat(<anno>Socket</anno>)</c> is equivalent to
- <c>getstat(<anno>Socket</anno>,&nbsp;[recv_avg,&nbsp;recv_cnt,&nbsp;recv_dvi,&nbsp;recv_max,&nbsp;recv_oct,&nbsp;send_avg,&nbsp;send_cnt,&nbsp;send_dvi,&nbsp;send_max,&nbsp;send_oct])</c></p>
+ <c>getstat(<anno>Socket</anno>, [recv_avg, recv_cnt, recv_dvi,
+ recv_max, recv_oct, send_avg, send_cnt, send_dvi, send_max,
+ send_oct])</c>.</p>
<p>The following options are available:</p>
<taglist>
<tag><c>recv_avg</c></tag>
@@ -371,7 +374,51 @@ fe80::204:acff:fe17:bf38
</taglist>
</desc>
</func>
-
+ <func>
+ <name name="parse_ipv4_address" arity="1" />
+ <fsummary>Parse an IPv4 address</fsummary>
+ <desc>
+ <p>Parses an IPv4 address string and returns an <a href="#type-ip4_address">ip4_address()</a>.
+ Accepts a shortened IPv4 shortened address string.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="parse_ipv4strict_address" arity="1" />
+ <fsummary>Parse an IPv4 address strict.</fsummary>
+ <desc>
+ <p>Parses an IPv4 address string containing four fields, i.e <b>not</b> shortened, and returns an <a href="#type-ip4_adress">ip4_address()</a>.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="parse_ipv6_address" arity="1" />
+ <fsummary>Parse an IPv6 address</fsummary>
+ <desc>
+ <p>Parses an IPv6 address string and returns an <a href="#type-ip6_address">ip6_address()</a>.
+ If an IPv4 address string is passed, an IPv4-mapped IPv6 address is returned.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="parse_ipv6strict_address" arity="1" />
+ <fsummary>Parse an IPv6 address strict.</fsummary>
+ <desc>
+ <p>Parses an IPv6 address string and returns an <a href="#type-ip6_address">ip6_address()</a>.
+ Does <b>not</b> accept IPv4 adresses.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="parse_address" arity="1" />
+ <fsummary>Parse an IPv4 or IPv6 address.</fsummary>
+ <desc>
+ <p>Parses an IPv4 or IPv6 address string and returns an <a href="#type-ip4_address">ip4_address()</a> or <a href="#type-ip6_address">ip6_address()</a>. Accepts a shortened IPv4 address string.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="parse_strict_address" arity="1" />
+ <fsummary>Parse an IPv4 or IPv6 address strict.</fsummary>
+ <desc>
+ <p>Parses an IPv4 or IPv6 address string and returns an <a href="#type-ip4_address">ip4_address()</a> or <a href="#type-ip6_adress">ip6_address()</a>. Does <b>not</b> accept a shortened IPv4 address string.</p>
+ </desc>
+ </func>
<func>
<name name="peername" arity="1"/>
<fsummary>Return the address and port for the other end of a connection</fsummary>
@@ -512,13 +559,100 @@ fe80::204:acff:fe17:bf38
<c>[Byte1,Byte2|Binary]</c>.</p>
</item>
- <tag><c>{high_watermark, Size}</c></tag>
- <item> <p>
- Sender is forced busy if sent and enqueued data
- reaches the highwater mark.
- <br /> Default: 8192 kB.
- </p>
- </item>
+ <tag><c>{high_msgq_watermark, Size}</c> (TCP/IP sockets)</tag>
+ <item>
+ <p>The socket message queue will be set into a busy
+ state when the amount of data queued on the message
+ queue reaches this limit. Note that this limit only
+ concerns data that have not yet reached the ERTS internal
+ socket implementation. Default value used is 8 kB.</p>
+ <p>Senders of data to the socket will be suspended if
+ either the socket message queue is busy, or the socket
+ itself is busy.</p>
+ <p>For more information see the <c>low_msgq_watermark</c>,
+ <c>high_watermark</c>, and <c>low_watermark</c> options.</p>
+ <p>Note that distribution sockets will disable the use of
+ <c>high_msgq_watermark</c> and <c>low_msgq_watermark</c>,
+ and will instead use the
+ <seealso marker="erts:erlang#system_info_dist_buf_busy_limit">distribution
+ buffer busy limit</seealso> which is a similar feature.</p>
+ </item>
+
+ <tag><c>{high_watermark, Size}</c> (TCP/IP sockets)</tag>
+ <item>
+ <p>The socket will be set into a busy state when the amount
+ of data queued internally by the ERTS socket implementation
+ reaches this limit. Default value used is 8 kB.</p>
+ <p>Senders of data to the socket will be suspended if
+ either the socket message queue is busy, or the socket
+ itself is busy.</p>
+ <p>For more information see the <c>low_watermark</c>,
+ <c>high_msgq_watermark</c>, and <c>low_msqg_watermark</c>
+ options.</p>
+ </item>
+
+ <tag><c>{ipv6_v6only, Boolean}</c></tag>
+ <item>
+ <p>
+ Restricts the socket to only use IPv6, prohibiting any
+ IPv4 connections. This is only applicable for
+ IPv6 sockets (option <c>inet6</c>).
+ </p>
+ <p>
+ On most platforms this option has to be set on the socket
+ before associating it to an address. Therefore it is only
+ reasonable to give it when creating the socket and not
+ to use it when calling the function
+ (<seealso marker="#setopts/2">setopts/2</seealso>)
+ containing this description.
+ </p>
+ <p>
+ The behaviour of a socket with this socket option set to
+ <c>true</c> is becoming the only portable one. The original
+ idea when IPv6 was new of using IPv6 for all traffic
+ is now not recommended by FreeBSD (you can use
+ <c>{ipv6_v6only,false}</c> to override the recommended
+ system default value),
+ forbidden by OpenBSD (the supported GENERIC kernel)
+ and impossible on Windows (that has separate
+ IPv4 and IPv6 protocol stacks). Most Linux distros
+ still have a system default value of <c>false</c>.
+ This policy shift among operating systems towards
+ separating IPv6 from IPv4 traffic has evolved since
+ it gradually proved hard and complicated to get
+ a dual stack implementation correct and secure.
+ </p>
+ <p>
+ On some platforms the only allowed value for this option
+ is <c>true</c>, e.g. OpenBSD and Windows. Trying to set
+ this option to <c>false</c> when creating the socket
+ will in this case fail.
+ </p>
+ <p>
+ Setting this option on platforms where it does not exist
+ is ignored and getting this option with
+ <seealso marker="#getopts/2">getopts/2</seealso>
+ returns no value i.e the returned list will not contain an
+ <c>{ipv6_v6only,_}</c> tuple. On Windows the option acually
+ does not exist, but it is emulated as being a
+ read-only option with the value <c>true</c>.
+ </p>
+ <p>
+ So it boils down to that setting this option to <c>true</c>
+ when creating a socket will never fail except possibly
+ (at the time of this writing) on a platform where you
+ have customized the kernel to only allow <c>false</c>,
+ which might be doable (but weird) on e.g. OpenBSD.
+ </p>
+ <p>
+ If you read back the option value using
+ <seealso marker="#getopts/2">getopts/2</seealso>
+ and get no value the option does not exist in the host OS
+ and all bets are off regarding the behaviour of both
+ an IPv6 and an IPv4 socket listening on the same port
+ as well as for an IPv6 socket getting IPv4 traffic.
+ </p>
+ </item>
<tag><c>{keepalive, Boolean}</c>(TCP/IP sockets)</tag>
<item>
@@ -540,14 +674,41 @@ fe80::204:acff:fe17:bf38
the flushing time-out in seconds.</p>
</item>
- <tag><c>{low_watermark, Size}</c></tag>
- <item> <p>
- If the port has reached its <c>high_watermark</c> it will
- force busy onto senders. When the port data queue reaches the
- <c>low_watermark</c> callers are no longer forced busy.
- <br /> Default: 4096 kB.
- </p>
- </item>
+ <tag><c>{low_msgq_watermark, Size}</c> (TCP/IP sockets)</tag>
+ <item>
+ <p>If the socket message queue is in a busy state, the
+ socket message queue will be set in a not busy state when
+ the amount of data queued in the message queue falls
+ below this limit. Note that this limit only concerns data
+ that have not yet reached the ERTS internal socket
+ implementation. Default value used is 4 kB.</p>
+ <p>Senders that have been suspended due to either a
+ busy message queue or a busy socket, will be resumed
+ when neither the socket message queue, nor the socket
+ are busy.</p>
+ <p>For more information see the <c>high_msgq_watermark</c>,
+ <c>high_watermark</c>, and <c>low_watermark</c> options.</p>
+ <p>Note that distribution sockets will disable the use of
+ <c>high_msgq_watermark</c> and <c>low_msgq_watermark</c>,
+ and will instead use the
+ <seealso marker="erts:erlang#system_info_dist_buf_busy_limit">distribution
+ buffer busy limit</seealso> which is a similar feature.</p>
+ </item>
+
+ <tag><c>{low_watermark, Size}</c> (TCP/IP sockets)</tag>
+ <item>
+ <p>If the socket is in a busy state, the socket will
+ be set in a not busy state when the amount of data
+ queued internally by the ERTS socket implementation
+ falls below this limit. Default value used is 4 kB.</p>
+ <p>Senders that have been suspended due to either a
+ busy message queue or a busy socket, will be resumed
+ when neither the socket message queue, nor the socket
+ are busy.</p>
+ <p>For more information see the <c>high_watermark</c>,
+ <c>high_msgq_watermark</c>, and <c>low_msgq_watermark</c>
+ options.</p>
+ </item>
<tag><c>{mode, Mode :: binary | list}</c></tag>
<item>
diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml
index 8e911a406b..78bc533464 100644
--- a/lib/kernel/doc/src/notes.xml
+++ b/lib/kernel/doc/src/notes.xml
@@ -30,6 +30,44 @@
</header>
<p>This document describes the changes made to the Kernel application.</p>
+<section><title>Kernel 2.15.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Ensure 'erl_crash.dump' when asked for it. This will
+ change erl_crash.dump behaviour.</p>
+ <p>
+ * Not setting ERL_CRASH_DUMP_SECONDS will now terminate
+ beam immediately on a crash without writing a crash dump
+ file.</p>
+ <p>
+ * Setting ERL_CRASH_DUMP_SECONDS to 0 will also terminate
+ beam immediately on a crash without writing a crash dump
+ file, i.e. same as not setting ERL_CRASH_DUMP_SECONDS
+ environment variable.</p>
+ <p>
+ * Setting ERL_CRASH_DUMP_SECONDS to a negative value will
+ let the beam wait indefinitely on the crash dump file
+ being written.</p>
+ <p>
+ * Setting ERL_CRASH_DUMP_SECONDS to a positive value will
+ let the beam wait that many seconds on the crash dump
+ file being written.</p>
+ <p>
+ A positive value will set an alarm/timeout for restart
+ both in beam and in heart if heart is running.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-10422 Aux Id: kunagi-250 [161] </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Kernel 2.15.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/kernel/doc/src/packages.xml b/lib/kernel/doc/src/packages.xml
deleted file mode 100644
index 8a82b91a90..0000000000
--- a/lib/kernel/doc/src/packages.xml
+++ /dev/null
@@ -1,208 +0,0 @@
-<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2004</year><year>2012</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved online at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- </legalnotice>
-
- <title>packages</title>
- <prepared>Kenneth Lundin</prepared>
- <responsible>Kenneth Lundin</responsible>
- <docno>1</docno>
- <approved>Kenneth Lundin</approved>
- <checked></checked>
- <date>2004-09-07</date>
- <rev>A</rev>
- <file>packages.sgml</file>
- </header>
- <module>packages</module>
- <modulesummary>Packages in Erlang</modulesummary>
- <description>
- <warning><p>
- Packages has since it was introduced more than 5 years ago been an
- experimental feature. Use it at your own risk, we do not
- actively maintain and develop this feature. It might however be
- supported some
- day.
- </p>
- <p>
- In spite of this packages work quite well, but there are some
- known issues in tools and other parts where packages don't work well.
- </p>
- </warning>
- <p><em>Introduction</em></p>
- <p>Packages are simply namespaces for modules.
- All old Erlang modules automatically belong to the top level
- ("empty-string") namespace, and do not need any changes.</p>
- <p>The full name of a packaged module is written as e.g.
- "<c>fee.fie.foe.foo</c>",
- i.e., as atoms separated by periods,
- where the package name is the part up to
- but not including the last period;
- in this case "<c>fee.fie.foe</c>".
- A more concrete example is the module <c>erl.lang.term</c>,
- which is in the
- package <c>erl.lang</c>.
- Package names can have any number of segments, as in
- <c>erl.lang.list.sort</c>.
- The atoms in the name can be quoted, as in <c>foo.'Bar'.baz</c>,
- or even the
- whole name, as in <c>'foo.bar.baz'</c> but the concatenation of
- atoms and
- periods must not contain two consecutive period characters or
- end with a period,
- as in <c>'foo..bar'</c>, <c>foo.'.bar'</c>, or <c>foo.'bar.'</c>.
- The periods must not be followed by whitespace.</p>
- <p>The code loader maps module names onto the file system directory
- structure.
- E.g., the module <c>erl.lang.term</c> corresponds to a file
- <c>.../erl/lang/term.beam</c>
- in the search path.
- Note that the name of the actual object file corresponds to
- the last part only of the full module name.
- (Thus, old existing modules such as <c>lists</c>
- simply map to <c>.../lists.beam</c>, exactly as before.)</p>
- <p>A packaged module in a file "<c>foo/bar/fred.erl</c>" is declared
- as:</p>
- <code type="none">
--module(foo.bar.fred).</code>
- <p>This can be compiled and loaded from the Erlang shell using
- <c>c(fred)</c>, if
- your current directory is the same as that of the file.
- The object file will be named <c>fred.beam</c>.</p>
- <p>The Erlang search path works exactly as before,
- except that the package segments will be appended to each
- directory in the path in order to find the
- file. E.g., assume the path is <c>["/usr/lib/erl", "/usr/local/lib/otp/legacy/ebin", "/home/barney/erl"]</c>.
- Then, the code for a module named <c>foo.bar.fred</c> will be
- searched for
- first as <c>"/usr/lib/erl/foo/bar/fred.beam"</c>, then
- <c>"/usr/local/lib/otp/legacy/ebin/foo/bar/fred.beam"</c>
- and lastly <c>"/home/barney/erl/foo/bar/fred.beam"</c>.
- A module
- like <c>lists</c>, which is in the top-level package,
- will be looked for as <c>"/usr/lib/erl/lists.beam"</c>,
- <c>"/usr/local/lib/otp/legacy/ebin/lists.beam"</c> and
- <c>"/home/barney/erl/lists.beam"</c>.</p>
- <p><em>Programming</em></p>
- <p>Normally, if a call is made from one module to another,
- it is assumed that the
- called module belongs to the same package as the source module.
- The compiler
- automatically expands such calls. E.g., in:</p>
- <code type="none">
--module(foo.bar.m1).
--export([f/1]).
-
-f(X) -> m2:g(X).</code>
- <p><c>m2:g(X)</c> becomes a call to <c>foo.bar.m2</c>
- If this is not what was intended, the call can be written
- explicitly, as in</p>
- <code type="none">
--module(foo.bar.m1).
--export([f/1]).
-
-f(X) -> fee.fie.foe.m2:g(X).</code>
- <p>Because the called module is given with an explicit package name,
- no expansion is done in this case.</p>
- <p>If a module from another package is used repeatedly in a module,
- an import declaration can make life easier:</p>
- <code type="none">
--module(foo.bar.m1).
--export([f/1, g/1]).
--import(fee.fie.foe.m2).
-
-f(X) -> m2:g(X).
-g(X) -> m2:h(X).</code>
- <p>will make the calls to <c>m2</c> refer to <c>fee.fie.foe.m2</c>.
- More generally, a declaration <c>-import(Package.Module).</c>
- will cause calls to <c>Module</c>
- to be expanded to <c>Package.Module</c>.</p>
- <p>Old-style function imports work as normal (but full module
- names must be
- used); e.g.:</p>
- <code type="none">
--import(fee.fie.foe.m2, [g/1, h/1]).</code>
- <p>however, it is probably better to avoid this form of import
- altogether in new
- code, since it makes it hard to see what calls are really "remote".</p>
- <p>If it is necessary to call a module in the top-level package
- from within a
- named package, the module name can be written either with an
- initial period as
- in e.g. "<c>.lists</c>", or with an empty initial atom, as in
- "<c>''.lists</c>".
- However, the best way is to use an import declaration -
- this is most obvious to
- the eye, and makes sure we don't forget adding a period somewhere:</p>
- <code type="none">
--module(foo.bar.fred).
--export([f/1]).
--import(lists).
-
-f(X) -> lists:reverse(X).</code>
- <p>The dot-syntax for module names can be used in any expression.
- All segments must
- be constant atoms, and the result must be a well-formed
- package/module name.
- E.g.:</p>
- <code type="none">
-spawn(foo.bar.fred, f, [X])</code>
- <p>is equivalent to <c>spawn('foo.bar.fred', f, [X])</c>.</p>
- <p><em>The Erlang Shell</em></p>
- <p>The shell also automatically expands remote calls,
- however currently no
- expansions are made by default.
- The user can change the behaviour by using the <c>import/1</c>
- shell command (or its abbreviation <c>use/1</c>). E.g.:</p>
- <pre>
-1> <input>import(foo.bar.m).</input>
-ok
-2> <input>m:f().</input></pre>
- <p>will evaluate <c>foo.bar.m:f()</c>.
- If a new import is made of the same name,
- this overrides any previous import.
- (It is likely that in the future, some
- system packages will be pre-imported.)</p>
- <p>In addition, the shell command <c>import_all/1</c>
- (and its alias <c>use_all/1</c>)
- imports all modules currently found in the path for a given
- package name. E.g.,
- assuming the files "<c>.../foo/bar/fred.beam</c>",
- "<c>.../foo/bar/barney.beam</c>"
- and "<c>.../foo/bar/bambam.beam</c>" can be found from our current
- path,</p>
- <pre>
-1> <input>import_all(foo.bar).</input></pre>
- <p>will make <c>fred</c>, <c>barney</c> and <c>bambam</c>
- expand to <c>foo.bar.fred</c>,
- <c>foo.bar.barney</c> and <c>foo.bar.bambam</c>, respectively.</p>
- <p>Note: The compiler does not have an "import all" directive, for the
- reason that Erlang has no compile time type checking.
- E.g. if the wrong search
- path is used at compile time, a call <c>m:f(...)</c>
- could be expanded to <c>foo.bar.m:f(...)</c>
- without any warning, instead of the intended
- <c>frob.ozz.m:f(...)</c>, if
- package <c>foo.bar</c> happens to be found first in the path.
- Explicitly
- declaring each use of a module makes for safe code.</p>
- </description>
-</erlref>
-
diff --git a/lib/kernel/doc/src/ref_man.xml b/lib/kernel/doc/src/ref_man.xml
index 9ef0959271..67d91ba585 100644
--- a/lib/kernel/doc/src/ref_man.xml
+++ b/lib/kernel/doc/src/ref_man.xml
@@ -64,6 +64,5 @@
<xi:include href="zlib_stub.xml"/>
<xi:include href="app.xml"/>
<xi:include href="config.xml"/>
- <xi:include href="packages.xml"/>
</application>
diff --git a/lib/kernel/src/Makefile b/lib/kernel/src/Makefile
index c76ff9e2f0..eaced4861a 100644
--- a/lib/kernel/src/Makefile
+++ b/lib/kernel/src/Makefile
@@ -107,7 +107,6 @@ MODULES = \
net_adm \
net_kernel \
os \
- packages \
pg2 \
ram_file \
rpc \
@@ -171,13 +170,13 @@ docs:
# ----------------------------------------------------
../../hipe/main/hipe.hrl: ../../hipe/vsn.mk ../../hipe/main/hipe.hrl.src
- sed -e "s;%VSN%;$(HIPE_VSN);" ../../hipe/main/hipe.hrl.src > ../../hipe/main/hipe.hrl
+ $(vsn_verbose)sed -e "s;%VSN%;$(HIPE_VSN);" ../../hipe/main/hipe.hrl.src > ../../hipe/main/hipe.hrl
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(KERNEL_VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(KERNEL_VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(KERNEL_VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(KERNEL_VSN);' $< > $@
EPMD_FLAGS = -Depmd_port_no=$(EPMD_PORT_NO) \
@@ -187,10 +186,10 @@ EPMD_FLAGS = -Depmd_port_no=$(EPMD_PORT_NO) \
-Derlang_daemon_port=$(EPMD_PORT_NO)
$(ESRC)/inet_dns_record_adts.hrl: $(ESRC)/inet_dns_record_adts.pl
- LANG=C $(PERL) $< > $@
+ $(gen_verbose)LANG=C $(PERL) $< > $@
$(EBIN)/erl_epmd.beam: $(ESRC)/erl_epmd.erl
- $(ERLC) $(ERL_COMPILE_FLAGS) $(EPMD_FLAGS) -o$(EBIN) $<
+ $(V_ERLC) $(ERL_COMPILE_FLAGS) $(EPMD_FLAGS) -o$(EBIN) $<
# ----------------------------------------------------
# Release Target
diff --git a/lib/kernel/src/application.erl b/lib/kernel/src/application.erl
index 9b7c4aa7b8..4e65883be7 100644
--- a/lib/kernel/src/application.erl
+++ b/lib/kernel/src/application.erl
@@ -23,7 +23,7 @@
which_applications/0, which_applications/1,
loaded_applications/0, permit/2]).
-export([set_env/3, set_env/4, unset_env/2, unset_env/3]).
--export([get_env/1, get_env/2, get_all_env/0, get_all_env/1]).
+-export([get_env/1, get_env/2, get_env/3, get_all_env/0, get_all_env/1]).
-export([get_key/1, get_key/2, get_all_key/0, get_all_key/1]).
-export([get_application/0, get_application/1, info/0]).
-export([start_type/0]).
@@ -264,6 +264,20 @@ get_env(Key) ->
get_env(Application, Key) ->
application_controller:get_env(Application, Key).
+-spec get_env(Application, Par, Def) -> Val when
+ Application :: atom(),
+ Par :: atom(),
+ Def :: term(),
+ Val :: term().
+
+get_env(Application, Key, Def) ->
+ case get_env(Application, Key) of
+ {ok, Val} ->
+ Val;
+ undefined ->
+ Def
+ end.
+
-spec get_all_env() -> Env when
Env :: [{Par :: atom(), Val :: term()}].
diff --git a/lib/kernel/src/application_controller.erl b/lib/kernel/src/application_controller.erl
index 68cd26ec10..75ce852001 100644
--- a/lib/kernel/src/application_controller.erl
+++ b/lib/kernel/src/application_controller.erl
@@ -1960,5 +1960,5 @@ to_string(Term) ->
true ->
Term;
false ->
- lists:flatten(io_lib:write(Term))
+ lists:flatten(io_lib:format("~134217728p", [Term]))
end.
diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl
index c808ac7cb7..361f2bdf8a 100644
--- a/lib/kernel/src/code.erl
+++ b/lib/kernel/src/code.erl
@@ -359,7 +359,6 @@ load_code_server_prerequisites() ->
hipe_unified_loader,
lists,
os,
- packages,
unicode],
[M = M:module_info(module) || M <- Needed],
ok.
@@ -413,7 +412,7 @@ which(Module) when is_atom(Module) ->
end.
which2(Module) ->
- Base = to_path(Module),
+ Base = atom_to_list(Module),
File = filename:basename(Base) ++ objfile_extension(),
Path = get_path(),
which(File, filename:dirname(Base), Path).
@@ -547,9 +546,6 @@ has_ext(Ext, Extlen, File) ->
_ -> false
end.
-to_path(X) ->
- filename:join(packages:split(X)).
-
-spec load_native_code_for_all_loaded() -> ok.
load_native_code_for_all_loaded() ->
Architecture = erlang:system_info(hipe_architecture),
diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl
index 00ad923466..b2d2c19f78 100644
--- a/lib/kernel/src/code_server.erl
+++ b/lib/kernel/src/code_server.erl
@@ -1229,7 +1229,7 @@ load_abs(File, Mod0, Caller, St) ->
end.
try_load_module(Mod, Dir, Caller, St) ->
- File = filename:append(Dir, to_path(Mod) ++
+ File = filename:append(Dir, to_list(Mod) ++
objfile_extension()),
case erl_prim_loader:get_file(File) of
error ->
@@ -1347,7 +1347,7 @@ load_file_1(Mod, Caller, #state{cache=Cache}=St0) ->
end.
mod_to_bin([Dir|Tail], Mod) ->
- File = filename:append(Dir, to_path(Mod) ++ objfile_extension()),
+ File = filename:append(Dir, to_list(Mod) ++ objfile_extension()),
case erl_prim_loader:get_file(File) of
error ->
mod_to_bin(Tail, Mod);
@@ -1356,7 +1356,7 @@ mod_to_bin([Dir|Tail], Mod) ->
end;
mod_to_bin([], Mod) ->
%% At last, try also erl_prim_loader's own method
- File = to_path(Mod) ++ objfile_extension(),
+ File = to_list(Mod) ++ objfile_extension(),
case erl_prim_loader:get_file(File) of
error ->
error; % No more alternatives !
@@ -1570,6 +1570,3 @@ to_list(X) when is_atom(X) -> atom_to_list(X).
to_atom(X) when is_atom(X) -> X;
to_atom(X) when is_list(X) -> list_to_atom(X).
-
-to_path(X) ->
- filename:join(packages:split(X)).
diff --git a/lib/kernel/src/disk_log.erl b/lib/kernel/src/disk_log.erl
index 5b1efcd395..1513fdaec0 100644
--- a/lib/kernel/src/disk_log.erl
+++ b/lib/kernel/src/disk_log.erl
@@ -44,6 +44,8 @@
%% To be used for debugging only:
-export([pid2name/1]).
+-export_type([continuation/0]).
+
-type dlog_state_error() :: 'ok' | {'error', term()}.
-record(state, {queue = [],
diff --git a/lib/kernel/src/dist_util.erl b/lib/kernel/src/dist_util.erl
index f0d54a2f3e..e3511988a6 100644
--- a/lib/kernel/src/dist_util.erl
+++ b/lib/kernel/src/dist_util.erl
@@ -757,7 +757,8 @@ setup_timer(Pid, Timeout) ->
end.
reset_timer(Timer) ->
- Timer ! {self(), reset}.
+ Timer ! {self(), reset},
+ ok.
cancel_timer(Timer) ->
unlink(Timer),
diff --git a/lib/kernel/src/erl_ddll.erl b/lib/kernel/src/erl_ddll.erl
index f967fcc2ef..e03d280cd8 100644
--- a/lib/kernel/src/erl_ddll.erl
+++ b/lib/kernel/src/erl_ddll.erl
@@ -54,9 +54,7 @@ info(_, _) ->
erlang:nif_error(undef).
-spec format_error_int(ErrSpec) -> string() when
- ErrSpec :: inconsisten | linked_in_driver | permanent
- | not_loaded | not_loaded_by_this_process | not_pending
- | already_loaded | unloading.
+ ErrSpec :: term().
format_error_int(_) ->
erlang:nif_error(undef).
diff --git a/lib/kernel/src/error_handler.erl b/lib/kernel/src/error_handler.erl
index f8bc5f499c..a3aa1f1dcf 100644
--- a/lib/kernel/src/error_handler.erl
+++ b/lib/kernel/src/error_handler.erl
@@ -23,10 +23,12 @@
%% "error_handler: add no_native compiler directive"
-compile(no_native).
-%% A simple error handler.
+%% Callbacks called from the run-time system.
+-export([undefined_function/3,undefined_lambda/3,breakpoint/3]).
--export([undefined_function/3, undefined_lambda/3, stub_function/3,
- breakpoint/3]).
+%% Exported utility functions.
+-export([raise_undef_exception/3]).
+-export([stub_function/3]).
-spec undefined_function(Module, Function, Args) ->
any() when
@@ -41,12 +43,7 @@ undefined_function(Module, Func, Args) ->
true ->
apply(Module, Func, Args);
false ->
- case check_inheritance(Module, Args) of
- {value, Base, Args1} ->
- apply(Base, Func, Args1);
- none ->
- crash(Module, Func, Args)
- end
+ call_undefined_function_handler(Module, Func, Args)
end;
{module, _} ->
crash(Module, Func, Args);
@@ -77,6 +74,14 @@ undefined_lambda(Module, Fun, Args) ->
breakpoint(Module, Func, Args) ->
(int()):eval(Module, Func, Args).
+-spec raise_undef_exception(Module, Function, Args) -> no_return() when
+ Module :: atom(),
+ Function :: atom(),
+ Args :: list().
+
+raise_undef_exception(Module, Func, Args) ->
+ crash({Module,Func,Args,[]}).
+
%% Used to make the call to the 'int' module a "weak" one, to avoid
%% building strong components in xref or dialyzer.
@@ -130,27 +135,11 @@ ensure_loaded(Module) ->
stub_function(Mod, Func, Args) ->
exit({undef,[{Mod,Func,Args,[]}]}).
-check_inheritance(Module, Args) ->
- Attrs = erlang:get_module_info(Module, attributes),
- case lists:keyfind(extends, 1, Attrs) of
- {extends, [Base]} when is_atom(Base), Base =/= Module ->
- %% This is just a heuristic for detecting abstract modules
- %% with inheritance so they can be handled; it would be
- %% much better to do it in the emulator runtime
- case lists:keyfind(abstract, 1, Attrs) of
- {abstract, [true]} ->
- case lists:reverse(Args) of
- [M|Rs] when tuple_size(M) > 1,
- element(1,M) =:= Module,
- tuple_size(element(2,M)) > 0,
- is_atom(element(1,element(2,M))) ->
- {value, Base, lists:reverse(Rs, [element(2,M)])};
- _ ->
- {value, Base, Args}
- end;
- _ ->
- {value, Base, Args}
- end;
- _ ->
- none
+call_undefined_function_handler(Module, Func, Args) ->
+ Handler = '$handle_undefined_function',
+ case erlang:function_exported(Module, Handler, 2) of
+ false ->
+ crash(Module, Func, Args);
+ true ->
+ Module:Handler(Func, Args)
end.
diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl
index 22af38c598..16f2dde464 100644
--- a/lib/kernel/src/file.erl
+++ b/lib/kernel/src/file.erl
@@ -38,7 +38,7 @@
%% Specialized
-export([ipread_s32bu_p32bu/3]).
%% Generic file contents.
--export([open/2, close/1, advise/4,
+-export([open/2, close/1, advise/4, allocate/3,
read/2, write/2,
pread/2, pread/3, pwrite/2, pwrite/3,
read_line/1,
@@ -397,9 +397,10 @@ raw_write_file_info(Name, #file_info{} = Info) ->
%% Contemporary mode specification - list of options
--spec open(Filename, Modes) -> {ok, IoDevice} | {error, Reason} when
+-spec open(File, Modes) -> {ok, IoDevice} | {error, Reason} when
+ File :: Filename | iodata(),
Filename :: name(),
- Modes :: [mode()],
+ Modes :: [mode() | ram],
IoDevice :: io_device(),
Reason :: posix() | badarg | system_limit.
@@ -489,6 +490,18 @@ advise(#file_descriptor{module = Module} = Handle, Offset, Length, Advise) ->
advise(_, _, _, _) ->
{error, badarg}.
+-spec allocate(File, Offset, Length) ->
+ 'ok' | {'error', posix()} when
+ File :: io_device(),
+ Offset :: non_neg_integer(),
+ Length :: non_neg_integer().
+
+allocate(File, Offset, Length) when is_pid(File) ->
+ R = file_request(File, {allocate, Offset, Length}),
+ wait_file_reply(File, R);
+allocate(#file_descriptor{module = Module} = Handle, Offset, Length) ->
+ Module:allocate(Handle, Offset, Length).
+
-spec read(IoDevice, Number) -> {ok, Data} | eof | {error, Reason} when
IoDevice :: io_device() | atom(),
Number :: non_neg_integer(),
@@ -1314,6 +1327,7 @@ sendfile_send(Sock, Data, Old) ->
%%% Helpers
consult_stream(Fd) ->
+ _ = epp:set_encoding(Fd),
consult_stream(Fd, 1, []).
consult_stream(Fd, Line, Acc) ->
@@ -1327,6 +1341,7 @@ consult_stream(Fd, Line, Acc) ->
end.
eval_stream(Fd, Handling, Bs) ->
+ _ = epp:set_encoding(Fd),
eval_stream(Fd, Handling, 1, undefined, [], Bs).
eval_stream(Fd, H, Line, Last, E, Bs) ->
diff --git a/lib/kernel/src/file_io_server.erl b/lib/kernel/src/file_io_server.erl
index 0bff56cf46..fad2ed7fb3 100644
--- a/lib/kernel/src/file_io_server.erl
+++ b/lib/kernel/src/file_io_server.erl
@@ -40,6 +40,8 @@ format_error({_Line, ?MODULE, Reason}) ->
io_lib:format("~w", [Reason]);
format_error({_Line, Mod, Reason}) ->
Mod:format_error(Reason);
+format_error(invalid_unicode) ->
+ io_lib:format("cannot translate from UTF-8", []);
format_error(ErrorId) ->
erl_posix_msg:message(ErrorId).
@@ -209,6 +211,10 @@ file_request({advise,Offset,Length,Advise},
Reply ->
{reply,Reply,State}
end;
+file_request({allocate, Offset, Length},
+ #state{handle = Handle} = State) ->
+ Reply = ?PRIM_FILE:allocate(Handle, Offset, Length),
+ {reply, Reply, State};
file_request({pread,At,Sz},
#state{handle=Handle,buf=Buf,read_mode=ReadMode}=State) ->
case position(Handle, At, Buf) of
@@ -549,7 +555,7 @@ get_chars_notempty(Mod, Func, XtraArg, S, OutEnc,
<<>> ->
get_chars_apply(Mod, Func, XtraArg, S, OutEnc, State, eof);
_ ->
- {stop,invalid_unicode,{error,invalid_unicode},State}
+ {stop,invalid_unicode,invalid_unicode_error(Mod, Func, XtraArg, S),State}
end;
{error,Reason}=Error ->
{stop,Reason,Error,State}
@@ -616,12 +622,22 @@ get_chars_apply(Mod, Func, XtraArg, S0, OutEnc,
end
catch
exit:ExReason ->
- {stop,ExReason,{error,err_func(Mod, Func, XtraArg)},State};
+ {stop,ExReason,invalid_unicode_error(Mod, Func, XtraArg, S0),State};
error:ErrReason ->
{stop,ErrReason,{error,err_func(Mod, Func, XtraArg)},State}
end.
-
+%% A hack that tries to inform the caller about the position where the
+%% error occured.
+invalid_unicode_error(Mod, Func, XtraArg, S) ->
+ try
+ {erl_scan,tokens,_Args} = XtraArg,
+ Location = erl_scan:continuation_location(S),
+ {error,{Location, ?MODULE, invalid_unicode},Location}
+ catch
+ _:_ ->
+ {error,err_func(Mod, Func, XtraArg)}
+ end.
%% Convert error code to make it look as before
err_func(io_lib, get_until, {_,F,_}) ->
diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl
index 8fa963ec78..74ad192802 100644
--- a/lib/kernel/src/gen_sctp.erl
+++ b/lib/kernel/src/gen_sctp.erl
@@ -44,6 +44,7 @@
{priority, non_neg_integer()} |
{recbuf, non_neg_integer()} |
{reuseaddr, boolean()} |
+ {ipv6_v6only, boolean()} |
{sctp_adaptation_layer, #sctp_setadaptation{}} |
{sctp_associnfo, #sctp_assocparams{}} |
{sctp_autoclose, non_neg_integer()} |
@@ -72,6 +73,7 @@
priority |
recbuf |
reuseaddr |
+ ipv6_v6only |
sctp_adaptation_layer |
sctp_associnfo |
sctp_autoclose |
diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl
index e6dfdadb03..ec13ab6d2e 100644
--- a/lib/kernel/src/gen_tcp.erl
+++ b/lib/kernel/src/gen_tcp.erl
@@ -37,9 +37,11 @@
{dontroute, boolean()} |
{exit_on_close, boolean()} |
{header, non_neg_integer()} |
+ {high_msgq_watermark, pos_integer()} |
{high_watermark, non_neg_integer()} |
{keepalive, boolean()} |
{linger, {boolean(), non_neg_integer()}} |
+ {low_msgq_watermark, pos_integer()} |
{low_watermark, non_neg_integer()} |
{mode, list | binary} | list | binary |
{nodelay, boolean()} |
@@ -57,7 +59,8 @@
{send_timeout, non_neg_integer() | infinity} |
{send_timeout_close, boolean()} |
{sndbuf, non_neg_integer()} |
- {tos, non_neg_integer()}.
+ {tos, non_neg_integer()} |
+ {ipv6_v6only, boolean()}.
-type option_name() ::
active |
buffer |
@@ -66,9 +69,11 @@
dontroute |
exit_on_close |
header |
+ high_msgq_watermark |
high_watermark |
keepalive |
linger |
+ low_msgq_watermark |
low_watermark |
mode |
nodelay |
@@ -85,7 +90,8 @@
send_timeout |
send_timeout_close |
sndbuf |
- tos.
+ tos |
+ ipv6_v6only.
-type connect_option() ::
{ip, inet:ip_address()} |
{fd, Fd :: non_neg_integer()} |
diff --git a/lib/kernel/src/gen_udp.erl b/lib/kernel/src/gen_udp.erl
index 830ca61b3c..c5a1173575 100644
--- a/lib/kernel/src/gen_udp.erl
+++ b/lib/kernel/src/gen_udp.erl
@@ -47,7 +47,8 @@
{recbuf, non_neg_integer()} |
{reuseaddr, boolean()} |
{sndbuf, non_neg_integer()} |
- {tos, non_neg_integer()}.
+ {tos, non_neg_integer()} |
+ {ipv6_v6only, boolean()}.
-type option_name() ::
active |
broadcast |
@@ -69,7 +70,8 @@
recbuf |
reuseaddr |
sndbuf |
- tos.
+ tos |
+ ipv6_v6only.
-type socket() :: port().
-export_type([option/0, option_name/0]).
diff --git a/lib/kernel/src/group.erl b/lib/kernel/src/group.erl
index f92c6f7208..4d2e31a429 100644
--- a/lib/kernel/src/group.erl
+++ b/lib/kernel/src/group.erl
@@ -424,7 +424,7 @@ get_password_chars(Drv,Buf) ->
end.
get_chars(Prompt, M, F, Xa, Drv, Buf, Encoding) ->
- Pbs = prompt_bytes(Prompt),
+ Pbs = prompt_bytes(Prompt, Encoding),
get_chars_loop(Pbs, M, F, Xa, Drv, Buf, start, Encoding).
get_chars_loop(Pbs, M, F, Xa, Drv, Buf0, State, Encoding) ->
@@ -688,9 +688,9 @@ edit_password([Char|Cs],Chars) ->
edit_password(Cs,[Char|Chars]).
%% prompt_bytes(Prompt)
-%% Return a flat list of bytes for the Prompt.
-prompt_bytes(Prompt) ->
- lists:flatten(io_lib:format_prompt(Prompt)).
+%% Return a flat list of characters for the Prompt.
+prompt_bytes(Prompt, Encoding) ->
+ lists:flatten(io_lib:format_prompt(Prompt, Encoding)).
cast(L, binary,latin1) when is_list(L) ->
list_to_binary(L);
diff --git a/lib/kernel/src/heart.erl b/lib/kernel/src/heart.erl
index 28452a377e..87cb9d7f51 100644
--- a/lib/kernel/src/heart.erl
+++ b/lib/kernel/src/heart.erl
@@ -42,9 +42,11 @@
-define(CLEAR_CMD, 5).
-define(GET_CMD, 6).
-define(HEART_CMD, 7).
+-define(PREPARING_CRASH, 8). % Used in beam vm
-define(TIMEOUT, 5000).
-define(CYCLE_TIMEOUT, 10000).
+-define(HEART_PORT_NAME, heart_port).
%%---------------------------------------------------------------------
@@ -130,6 +132,8 @@ start_portprogram() ->
Port when is_port(Port) ->
case wait_ack(Port) of
ok ->
+ %% register port so the vm can find it if need be
+ register(?HEART_PORT_NAME, Port),
{ok, Port};
{error, Reason} ->
report_problem({{port_problem, Reason},
@@ -225,6 +229,7 @@ no_reboot_shutdown(Port) ->
end.
do_cycle_port_program(Caller, Parent, Port, Cmd) ->
+ unregister(?HEART_PORT_NAME),
case catch start_portprogram() of
{ok, NewPort} ->
send_shutdown(Port),
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index b4ebb1500c..9670271b2e 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -30,7 +30,9 @@
ifget/3, ifget/2, ifset/3, ifset/2,
getstat/1, getstat/2,
ip/1, stats/0, options/0,
- pushf/3, popf/1, close/1, gethostname/0, gethostname/1]).
+ pushf/3, popf/1, close/1, gethostname/0, gethostname/1,
+ parse_ipv4_address/1, parse_ipv6_address/1, parse_ipv4strict_address/1,
+ parse_ipv6strict_address/1, parse_address/1, parse_strict_address/1]).
-export([connect_options/2, listen_options/2, udp_options/2, sctp_options/2]).
@@ -527,14 +529,57 @@ getservbyname(Name, Protocol) when is_atom(Name) ->
Error -> Error
end.
+-spec parse_ipv4_address(Address) ->
+ {ok, IPv4Address} | {error, einval} when
+ Address :: string(),
+ IPv4Address :: ip_address().
+parse_ipv4_address(Addr) ->
+ inet_parse:ipv4_address(Addr).
+
+-spec parse_ipv6_address(Address) ->
+ {ok, IPv6Address} | {error, einval} when
+ Address :: string(),
+ IPv6Address :: ip_address().
+parse_ipv6_address(Addr) ->
+ inet_parse:ipv6_address(Addr).
+
+-spec parse_ipv4strict_address(Address) ->
+ {ok, IPv4Address} | {error, einval} when
+ Address :: string(),
+ IPv4Address :: ip_address().
+parse_ipv4strict_address(Addr) ->
+ inet_parse:ipv4strict_address(Addr).
+
+-spec parse_ipv6strict_address(Address) ->
+ {ok, IPv6Address} | {error, einval} when
+ Address :: string(),
+ IPv6Address :: ip_address().
+parse_ipv6strict_address(Addr) ->
+ inet_parse:ipv6strict_address(Addr).
+
+-spec parse_address(Address) ->
+ {ok, IPAddress} | {error, einval} when
+ Address :: string(),
+ IPAddress :: ip_address().
+parse_address(Addr) ->
+ inet_parse:address(Addr).
+
+-spec parse_strict_address(Address) ->
+ {ok, IPAddress} | {error, einval} when
+ Address :: string(),
+ IPAddress :: ip_address().
+parse_strict_address(Addr) ->
+ inet_parse:strict_address(Addr).
+
%% Return a list of available options
options() ->
[
tos, priority, reuseaddr, keepalive, dontroute, linger,
- broadcast, sndbuf, recbuf, nodelay,
+ broadcast, sndbuf, recbuf, nodelay, ipv6_v6only,
buffer, header, active, packet, deliver, mode,
multicast_if, multicast_ttl, multicast_loop,
exit_on_close, high_watermark, low_watermark,
+ high_msgq_watermark, low_msgq_watermark,
send_timeout, send_timeout_close
].
@@ -552,8 +597,8 @@ stats() ->
connect_options() ->
[tos, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay,
header, active, packet, packet_size, buffer, mode, deliver,
- exit_on_close, high_watermark, low_watermark, send_timeout,
- send_timeout_close, delay_send,raw].
+ exit_on_close, high_watermark, low_watermark, high_msgq_watermark,
+ low_msgq_watermark, send_timeout, send_timeout_close, delay_send, raw].
connect_options(Opts, Family) ->
BaseOpts =
@@ -607,9 +652,10 @@ con_add(Name, Val, R, Opts, AllOpts) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
listen_options() ->
[tos, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay,
- header, active, packet, buffer, mode, deliver, backlog,
- exit_on_close, high_watermark, low_watermark, send_timeout,
- send_timeout_close, delay_send, packet_size,raw].
+ 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,
+ packet_size, raw].
listen_options(Opts, Family) ->
BaseOpts =
@@ -664,7 +710,7 @@ list_add(Name, Val, R, Opts, As) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
udp_options() ->
[tos, priority, reuseaddr, sndbuf, recbuf, header, active, buffer, mode,
- deliver,
+ deliver, ipv6_v6only,
broadcast, dontroute, multicast_if, multicast_ttl, multicast_loop,
add_membership, drop_membership, read_packets,raw].
@@ -720,7 +766,7 @@ udp_add(Name, Val, R, Opts, As) ->
sctp_options() ->
[ % The following are generic inet options supported for SCTP sockets:
mode, active, buffer, tos, priority, dontroute, reuseaddr, linger, sndbuf,
- recbuf,
+ recbuf, ipv6_v6only,
% Other options are SCTP-specific (though they may be similar to their
% TCP and UDP counter-parts):
diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl
index 467c4d5065..000119bc74 100644
--- a/lib/kernel/src/inet_int.hrl
+++ b/lib/kernel/src/inet_int.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -124,6 +124,7 @@
-define(UDP_OPT_MULTICAST_LOOP, 13).
-define(UDP_OPT_ADD_MEMBERSHIP, 14).
-define(UDP_OPT_DROP_MEMBERSHIP, 15).
+-define(INET_OPT_IPV6_V6ONLY, 16).
% "Local" options: codes start from 20:
-define(INET_LOPT_BUFFER, 20).
-define(INET_LOPT_HEADER, 21).
@@ -140,6 +141,8 @@
-define(INET_LOPT_READ_PACKETS, 33).
-define(INET_OPT_RAW, 34).
-define(INET_LOPT_TCP_SEND_TIMEOUT_CLOSE, 35).
+-define(INET_LOPT_TCP_MSGQ_HIWTRMRK, 36).
+-define(INET_LOPT_TCP_MSGQ_LOWTRMRK, 37).
% Specific SCTP options: separate range:
-define(SCTP_OPT_RTOINFO, 100).
-define(SCTP_OPT_ASSOCINFO, 101).
diff --git a/lib/kernel/src/inet_parse.erl b/lib/kernel/src/inet_parse.erl
index ba62a59068..3551e701b6 100644
--- a/lib/kernel/src/inet_parse.erl
+++ b/lib/kernel/src/inet_parse.erl
@@ -36,7 +36,7 @@
-export([ipv4_address/1, ipv6_address/1]).
-export([ipv4strict_address/1, ipv6strict_address/1]).
--export([address/1]).
+-export([address/1, strict_address/1]).
-export([visible_string/1, domain/1]).
-export([ntoa/1, dots/1]).
-export([split_line/1]).
@@ -456,6 +456,17 @@ address(Cs) when is_list(Cs) ->
address(_) ->
{error, einval}.
+%%Parse ipv4 strict address or ipv6 strict address
+strict_address(Cs) when is_list(Cs) ->
+ case ipv4strict_address(Cs) of
+ {ok,IP} ->
+ {ok,IP};
+ _ ->
+ ipv6strict_address(Cs)
+ end;
+strict_address(Cs) ->
+ {error, einval}.
+
%%
%% Parse IPv4 address:
%% d1.d2.d3.d4
diff --git a/lib/kernel/src/kernel.app.src b/lib/kernel/src/kernel.app.src
index 17ab84c177..9a20baf8d0 100644
--- a/lib/kernel/src/kernel.app.src
+++ b/lib/kernel/src/kernel.app.src
@@ -28,7 +28,6 @@
application_starter,
auth,
code,
- packages,
code_server,
dist_util,
erl_boot_server,
diff --git a/lib/kernel/src/packages.erl b/lib/kernel/src/packages.erl
deleted file mode 100644
index e0b1f36b85..0000000000
--- a/lib/kernel/src/packages.erl
+++ /dev/null
@@ -1,158 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2002-2009. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
--module(packages).
-
--export([to_string/1, concat/1, concat/2, is_valid/1, is_segmented/1,
- split/1, last/1, first/1, strip_last/1, find_modules/1,
- find_modules/2]).
-
-%% A package name (or a package-qualified module name) may be an atom or
-%% a string (list of nonnegative integers) - not a deep list, and not a
-%% list containing atoms. A name may be empty, but may not contain two
-%% consecutive period (`.') characters or end with a period character.
-
--type package_name() :: atom() | string().
-
--spec to_string(package_name()) -> string().
-to_string(Name) when is_atom(Name) ->
- atom_to_list(Name);
-to_string(Name) ->
- Name.
-
-%% `concat' does not insert a leading period if the first segment is
-%% empty. However, the result may contain leading, consecutive or
-%% dangling period characters, if any of the segments after the first
-%% are empty. Use 'is_valid' to check the result if necessary.
-
--spec concat(package_name(), package_name()) -> string().
-concat(A, B) ->
- concat([A, B]).
-
--spec concat([package_name()]) -> string().
-concat([H | T]) when is_atom(H) ->
- concat([atom_to_list(H) | T]);
-concat(["" | T]) ->
- concat_1(T);
-concat(L) ->
- concat_1(L).
-
-concat_1([H | T]) when is_atom(H) ->
- concat_1([atom_to_list(H) | T]);
-concat_1([H]) ->
- H;
-concat_1([H | T]) ->
- H ++ "." ++ concat_1(T);
-concat_1([]) ->
- "";
-concat_1(Name) ->
- erlang:error({badarg, Name}).
-
--spec is_valid(package_name()) -> boolean().
-is_valid(Name) when is_atom(Name) ->
- is_valid_1(atom_to_list(Name));
-is_valid([$. | _]) ->
- false;
-is_valid(Name) ->
- is_valid_1(Name).
-
-is_valid_1([$.]) -> false;
-is_valid_1([$., $. | _]) -> false;
-is_valid_1([H | T]) when is_integer(H), H >= 0 ->
- is_valid_1(T);
-is_valid_1([]) -> true;
-is_valid_1(_) -> false.
-
--spec split(package_name()) -> [string()].
-split(Name) when is_atom(Name) ->
- split_1(atom_to_list(Name), []);
-split(Name) ->
- split_1(Name, []).
-
-split_1([$. | T], Cs) ->
- [lists:reverse(Cs) | split_1(T, [])];
-split_1([H | T], Cs) when is_integer(H), H >= 0 ->
- split_1(T, [H | Cs]);
-split_1([], Cs) ->
- [lists:reverse(Cs)];
-split_1(_, _) ->
- erlang:error(badarg).
-
-%% This is equivalent to testing if `split(Name)' yields a list of
-%% length larger than one (i.e., if the name can be split into two or
-%% more segments), but is cheaper.
-
--spec is_segmented(package_name()) -> boolean().
-is_segmented(Name) when is_atom(Name) ->
- is_segmented_1(atom_to_list(Name));
-is_segmented(Name) ->
- is_segmented_1(Name).
-
-is_segmented_1([$. | _]) -> true;
-is_segmented_1([H | T]) when is_integer(H), H >= 0 ->
- is_segmented_1(T);
-is_segmented_1([]) -> false;
-is_segmented_1(_) ->
- erlang:error(badarg).
-
--spec last(package_name()) -> string().
-last(Name) ->
- last_1(split(Name)).
-
-last_1([H]) -> H;
-last_1([_ | T]) -> last_1(T).
-
--spec first(package_name()) -> [string()].
-first(Name) ->
- first_1(split(Name)).
-
-first_1([H | T]) when T =/= [] -> [H | first_1(T)];
-first_1(_) -> [].
-
--spec strip_last(package_name()) -> string().
-strip_last(Name) ->
- concat(first(Name)).
-
-%% This finds all modules available for a given package, using the
-%% current code server search path. (There is no guarantee that the
-%% modules are loadable; only that the object files exist.)
-
--spec find_modules(package_name()) -> [string()].
-find_modules(P) ->
- find_modules(P, code:get_path()).
-
--spec find_modules(package_name(), [string()]) -> [string()].
-find_modules(P, Paths) ->
- P1 = filename:join(packages:split(P)),
- find_modules(P1, Paths, code:objfile_extension(), sets:new()).
-
-find_modules(P, [Path | Paths], Ext, S0) ->
- case file:list_dir(filename:join(Path, P)) of
- {ok, Fs} ->
- Fs1 = [F || F <- Fs, filename:extension(F) =:= Ext],
- S1 = lists:foldl(fun (F, S) ->
- F1 = filename:rootname(F, Ext),
- sets:add_element(F1, S)
- end,
- S0, Fs1),
- find_modules(P, Paths, Ext, S1);
- _ ->
- find_modules(P, Paths, Ext, S0)
- end;
-find_modules(_P, [], _Ext, S) ->
- sets:to_list(S).
diff --git a/lib/kernel/src/pg2.erl b/lib/kernel/src/pg2.erl
index 0d5838716e..1ff10eb303 100644
--- a/lib/kernel/src/pg2.erl
+++ b/lib/kernel/src/pg2.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -159,7 +159,7 @@ get_closest_pid(Name) ->
-record(state, {}).
--opaque state() :: #state{}.
+-type state() :: #state{}.
-spec init(Arg :: []) -> {'ok', state()}.
diff --git a/lib/kernel/src/ram_file.erl b/lib/kernel/src/ram_file.erl
index 48ea871433..ca881ff8a4 100644
--- a/lib/kernel/src/ram_file.erl
+++ b/lib/kernel/src/ram_file.erl
@@ -29,6 +29,7 @@
%% Specialized file operations
-export([get_size/1, get_file/1, set_file/2, get_file_close/1]).
-export([compress/1, uncompress/1, uuencode/1, uudecode/1, advise/4]).
+-export([allocate/3]).
-export([open_mode/1]). %% used by ftp-file
@@ -72,6 +73,7 @@
-define(RAM_FILE_UUDECODE, 36).
-define(RAM_FILE_SIZE, 37).
-define(RAM_FILE_ADVISE, 38).
+-define(RAM_FILE_ALLOCATE, 39).
%% Open modes for RAM_FILE_OPEN
-define(RAM_FILE_MODE_READ, 1).
@@ -383,6 +385,11 @@ advise(#file_descriptor{module = ?MODULE, data = Port}, Offset,
advise(#file_descriptor{}, _Offset, _Length, _Advise) ->
{error, enotsup}.
+allocate(#file_descriptor{module = ?MODULE, data = Port}, Offset, Length) ->
+ call_port(Port, <<?RAM_FILE_ALLOCATE, Offset:64/signed, Length:64/signed>>);
+allocate(#file_descriptor{}, _Offset, _Length) ->
+ {error, enotsup}.
+
%%%-----------------------------------------------------------------
diff --git a/lib/kernel/src/rpc.erl b/lib/kernel/src/rpc.erl
index 0b1fc6e939..7c965ca384 100644
--- a/lib/kernel/src/rpc.erl
+++ b/lib/kernel/src/rpc.erl
@@ -62,6 +62,8 @@
%% Internals
-export([proxy_user_flush/0]).
+-export_type([key/0]).
+
%%------------------------------------------------------------------------
-type state() :: gb_tree().
diff --git a/lib/kernel/src/user.erl b/lib/kernel/src/user.erl
index 88f32df20b..d6449d9e5e 100644
--- a/lib/kernel/src/user.erl
+++ b/lib/kernel/src/user.erl
@@ -81,7 +81,7 @@ server(PortName,PortSettings) ->
run(P) ->
put(read_mode,list),
- put(unicode,false),
+ put(encoding,latin1),
case init:get_argument(noshell) of
%% non-empty list -> noshell
{ok, [_|_]} ->
@@ -191,39 +191,27 @@ do_io_request(Req, From, ReplyAs, Port, Q0) ->
%% New in R13B
%% Encoding option (unicode/latin1)
io_request({put_chars,unicode,Chars}, Port, Q) -> % Binary new in R9C
- put_chars(wrap_characters_to_binary(Chars,unicode,
- case get(unicode) of
- true -> unicode;
- _ -> latin1
- end), Port, Q);
+ put_chars(wrap_characters_to_binary(Chars,unicode, get(encoding)), Port, Q);
io_request({put_chars,unicode,Mod,Func,Args}, Port, Q) ->
Result = case catch apply(Mod,Func,Args) of
Data when is_list(Data); is_binary(Data) ->
- wrap_characters_to_binary(Data,unicode,
- case get(unicode) of
- true -> unicode;
- _ -> latin1
- end);
+ wrap_characters_to_binary(Data,unicode,get(encoding));
Undef ->
Undef
end,
put_chars(Result, Port, Q);
io_request({put_chars,latin1,Chars}, Port, Q) -> % Binary new in R9C
- Data = case get(unicode) of
- true ->
+ Data = case get(encoding) of
+ unicode ->
unicode:characters_to_binary(Chars,latin1,unicode);
- false ->
+ latin1 ->
erlang:iolist_to_binary(Chars)
end,
put_chars(Data, Port, Q);
io_request({put_chars,latin1,Mod,Func,Args}, Port, Q) ->
Result = case catch apply(Mod,Func,Args) of
Data when is_list(Data); is_binary(Data) ->
- unicode:characters_to_binary(Data,latin1,
- case get(unicode) of
- true -> unicode;
- _ -> latin1
- end);
+ unicode:characters_to_binary(Data,latin1,get(encoding));
Undef ->
Undef
end,
@@ -351,9 +339,9 @@ check_valid_opts(_) ->
do_setopts(Opts, _Port, Q) ->
case proplists:get_value(encoding,Opts) of
Valid when Valid =:= unicode; Valid =:= utf8 ->
- put(unicode,true);
+ put(encoding,unicode);
latin1 ->
- put(unicode,false);
+ put(encoding,latin1);
undefined ->
ok
end,
@@ -370,12 +358,7 @@ do_setopts(Opts, _Port, Q) ->
getopts(_Port,Q) ->
Bin = {binary, get(read_mode) =:= binary},
- Uni = {encoding, case get(unicode) of
- true ->
- unicode;
- _ ->
- latin1
- end},
+ Uni = {encoding, get(encoding)},
{ok,[Bin,Uni],Q}.
@@ -575,31 +558,32 @@ binrev(L, T) ->
%% end
%% end
%% end.
-%% get_chars(Prompt, Module, Function, XtraArg, Port, Queue)
+%% get_chars(Prompt, Module, Function, XtraArg, Port, Queue, Encoding)
%% Gets characters from the input port until the applied function
%% returns {stop,Result,RestBuf}. Does not block output until input
-%% has been received.
+%% has been received. Encoding is the encoding of the data sent to
+%% the client and to Function.
%% Returns:
%% {Status,Result,NewQueue}
%% {exit,Reason}
%% Entry function.
-get_chars(Prompt, M, F, Xa, Port, Q, Fmt) ->
+get_chars(Prompt, M, F, Xa, Port, Q, Enc) ->
prompt(Port, Prompt),
case {get(eof),queue:is_empty(Q)} of
{true,true} ->
{ok,eof,Q};
_ ->
- get_chars(Prompt, M, F, Xa, Port, Q, start, Fmt)
+ get_chars(Prompt, M, F, Xa, Port, Q, start, Enc)
end.
%% First loop. Wait for port data. Respond to output requests.
-get_chars(Prompt, M, F, Xa, Port, Q, State, Fmt) ->
+get_chars(Prompt, M, F, Xa, Port, Q, State, Enc) ->
case queue:is_empty(Q) of
true ->
receive
{Port,{data,Bytes}} ->
- get_chars_bytes(State, M, F, Xa, Port, Q, Bytes, Fmt);
+ get_chars_bytes(State, M, F, Xa, Port, Q, Bytes, Enc);
{Port, eof} ->
put(eof, true),
{ok, eof, []};
@@ -610,41 +594,41 @@ get_chars(Prompt, M, F, Xa, Port, Q, State, Fmt) ->
do_io_request(Req, From, ReplyAs, Port,
queue:new()), %Keep Q over this call
%% No prompt.
- get_chars(Prompt, M, F, Xa, Port, Q, State, Fmt);
+ get_chars(Prompt, M, F, Xa, Port, Q, State, Enc);
{io_request,From,ReplyAs,Request} when is_pid(From) ->
get_chars_req(Prompt, M, F, Xa, Port, Q, State,
- Request, From, ReplyAs, Fmt);
+ Request, From, ReplyAs, Enc);
{'EXIT',From,What} when node(From) =:= node() ->
{exit,What}
end;
false ->
- get_chars_apply(State, M, F, Xa, Port, Q, Fmt)
+ get_chars_apply(State, M, F, Xa, Port, Q, Enc)
end.
get_chars_req(Prompt, M, F, XtraArg, Port, Q, State,
- Req, From, ReplyAs, Fmt) ->
+ Req, From, ReplyAs, Enc) ->
do_io_request(Req, From, ReplyAs, Port, queue:new()), %Keep Q over this call
prompt(Port, Prompt),
- get_chars(Prompt, M, F, XtraArg, Port, Q, State, Fmt).
+ get_chars(Prompt, M, F, XtraArg, Port, Q, State, Enc).
%% Second loop. Pass data to client as long as it wants more.
%% A ^G in data interrupts loop if 'noshell' is not undefined.
-get_chars_bytes(State, M, F, Xa, Port, Q, Bytes, Fmt) ->
+get_chars_bytes(State, M, F, Xa, Port, Q, Bytes, Enc) ->
case get(shell) of
noshell ->
- get_chars_apply(State, M, F, Xa, Port, queue:snoc(Q, Bytes),Fmt);
+ get_chars_apply(State, M, F, Xa, Port, queue:snoc(Q, Bytes),Enc);
_ ->
case contains_ctrl_g_or_ctrl_c(Bytes) of
false ->
get_chars_apply(State, M, F, Xa, Port,
- queue:snoc(Q, Bytes),Fmt);
+ queue:snoc(Q, Bytes),Enc);
_ ->
throw(new_shell)
end
end.
-get_chars_apply(State0, M, F, Xa, Port, Q, Fmt) ->
- case catch M:F(State0, cast(queue:head(Q),Fmt), Fmt, Xa) of
+get_chars_apply(State0, M, F, Xa, Port, Q, Enc) ->
+ case catch M:F(State0, cast(queue:head(Q),Enc), Enc, Xa) of
{stop,Result,<<>>} ->
{ok,Result,queue:tail(Q)};
{stop,Result,[]} ->
@@ -653,32 +637,32 @@ get_chars_apply(State0, M, F, Xa, Port, Q, Fmt) ->
{ok,Result,queue:tail(Q)};
{stop,Result,Buf} ->
{ok,Result,queue:cons(Buf, queue:tail(Q))};
- {'EXIT',_} ->
+ {'EXIT',_Why} ->
{error,{error,err_func(M, F, Xa)},queue:new()};
State1 ->
- get_chars_more(State1, M, F, Xa, Port, queue:tail(Q), Fmt)
+ get_chars_more(State1, M, F, Xa, Port, queue:tail(Q), Enc)
end.
-get_chars_more(State, M, F, Xa, Port, Q, Fmt) ->
+get_chars_more(State, M, F, Xa, Port, Q, Enc) ->
case queue:is_empty(Q) of
true ->
case get(eof) of
undefined ->
receive
{Port,{data,Bytes}} ->
- get_chars_bytes(State, M, F, Xa, Port, Q, Bytes, Fmt);
+ get_chars_bytes(State, M, F, Xa, Port, Q, Bytes, Enc);
{Port,eof} ->
put(eof, true),
get_chars_apply(State, M, F, Xa, Port,
- queue:snoc(Q, eof), Fmt);
+ queue:snoc(Q, eof), Enc);
{'EXIT',From,What} when node(From) =:= node() ->
{exit,What}
end;
_ ->
- get_chars_apply(State, M, F, Xa, Port, queue:snoc(Q, eof), Fmt)
+ get_chars_apply(State, M, F, Xa, Port, queue:snoc(Q, eof), Enc)
end;
false ->
- get_chars_apply(State, M, F, Xa, Port, Q, Fmt)
+ get_chars_apply(State, M, F, Xa, Port, Q, Enc)
end.
@@ -689,11 +673,10 @@ get_chars_more(State, M, F, Xa, Port, Q, Fmt) ->
prompt(_Port, '') -> ok;
prompt(Port, Prompt) ->
- put_port(wrap_characters_to_binary(io_lib:format_prompt(Prompt),unicode,
- case get(unicode) of
- true -> unicode;
- _ -> latin1
- end), Port).
+ Encoding = get(encoding),
+ put_port(wrap_characters_to_binary(io_lib:format_prompt(Prompt, Encoding),
+ unicode, Encoding),
+ Port).
%% Convert error code to make it look as before
err_func(io_lib, get_until, {_,F,_}) ->
@@ -710,56 +693,65 @@ contains_ctrl_g_or_ctrl_c(BinOrList)->
end.
%% Convert a buffer between list and binary
-cast(Data, _Format) when is_atom(Data) ->
+cast(Data, _Encoding) when is_atom(Data) ->
Data;
-cast(Data, Format) ->
- cast(Data, get(read_mode), Format, get(unicode)).
+cast(Data, Encoding) ->
+ IoEncoding = get(encoding),
+ cast(Data, get(read_mode), IoEncoding, Encoding).
-cast(B, binary, latin1, false) when is_binary(B) ->
+cast(B, binary, latin1, latin1) when is_binary(B) ->
B;
-cast(B, binary, latin1, true) when is_binary(B) ->
- unicode:characters_to_binary(B, unicode, latin1);
-cast(L, binary, latin1, false) ->
- erlang:iolist_to_binary(L);
-cast(L, binary, latin1, true) ->
- case unicode:characters_to_binary(
- erlang:iolist_to_binary(L),unicode,latin1) of % may fail
- {error,_,_} -> exit({no_translation, unicode, latin1});
- Else -> Else
+cast(L, binary, latin1, latin1) ->
+ case catch erlang:iolist_to_binary(L) of
+ Bin when is_binary(Bin) -> Bin;
+ _ -> exit({no_translation, latin1, latin1})
+ end;
+cast(Data, binary, unicode, latin1) when is_binary(Data); is_list(Data) ->
+ case catch unicode:characters_to_binary(Data, unicode, latin1) of
+ Bin when is_binary(Bin) -> Bin;
+ _ -> exit({no_translation, unicode, latin1})
+ end;
+cast(Data, binary, latin1, unicode) when is_binary(Data); is_list(Data) ->
+ case catch unicode:characters_to_binary(Data, latin1, unicode) of
+ Bin when is_binary(Bin) -> Bin;
+ _ -> exit({no_translation, latin1, unicode})
end;
-cast(B, binary, unicode, true) when is_binary(B) ->
+cast(B, binary, unicode, unicode) when is_binary(B) ->
B;
-cast(B, binary, unicode, false) when is_binary(B) ->
- unicode:characters_to_binary(B,latin1,unicode);
-cast(L, binary, unicode, true) ->
- % possibly a list containing UTF-8 encoded characters
- unicode:characters_to_binary(erlang:iolist_to_binary(L));
-cast(L, binary, unicode, false) ->
- unicode:characters_to_binary(L, latin1, unicode);
-cast(L, list, latin1, UniTerm) ->
- case UniTerm of
- true -> % Convert input characters to protocol format (i.e latin1)
- case unicode:characters_to_list(
- erlang:iolist_to_binary(L),unicode) of % may fail
- {error,_,_} -> exit({no_translation, unicode, latin1});
- Else -> [ case X of
- High when High > 255 ->
- exit({no_translation, unicode, latin1});
- Low ->
- Low
- end || X <- Else ]
- end;
- _ ->
- binary_to_list(erlang:iolist_to_binary(L))
+cast(L, binary, unicode, unicode) ->
+ case catch unicode:characters_to_binary(L, unicode) of
+ Bin when is_binary(Bin) -> Bin;
+ _ -> exit({no_translation, unicode, unicode})
end;
-cast(L, list, unicode, UniTerm) ->
- unicode:characters_to_list(erlang:iolist_to_binary(L),
- case UniTerm of
- true -> unicode;
- _ -> latin1
- end);
-cast(Other, _, _,_) ->
- Other.
+cast(B, list, latin1, latin1) when is_binary(B) ->
+ binary_to_list(B);
+cast(L, list, latin1, latin1) ->
+ case catch erlang:iolist_to_binary(L) of
+ Bin when is_binary(Bin) -> binary_to_list(Bin);
+ _ -> exit({no_translation, latin1, latin1})
+ end;
+cast(Data, list, unicode, latin1) when is_binary(Data); is_list(Data) ->
+ case catch unicode:characters_to_list(Data, unicode) of
+ Chars when is_list(Chars) ->
+ [ case X of
+ High when High > 255 ->
+ exit({no_translation, unicode, latin1});
+ Low ->
+ Low
+ end || X <- Chars ];
+ _ ->
+ exit({no_translation, unicode, latin1})
+ end;
+cast(Data, list, latin1, unicode) when is_binary(Data); is_list(Data) ->
+ case catch unicode:characters_to_list(Data, latin1) of
+ Chars when is_list(Chars) -> Chars;
+ _ -> exit({no_translation, latin1, unicode})
+ end;
+cast(Data, list, unicode, unicode) when is_binary(Data); is_list(Data) ->
+ case catch unicode:characters_to_list(Data, unicode) of
+ Chars when is_list(Chars) -> Chars;
+ _ -> exit({no_translation, unicode, unicode})
+ end.
wrap_characters_to_binary(Chars,unicode,latin1) ->
case unicode:characters_to_binary(Chars,unicode,latin1) of
diff --git a/lib/kernel/src/wrap_log_reader.erl b/lib/kernel/src/wrap_log_reader.erl
index c41e0091e4..689269fc28 100644
--- a/lib/kernel/src/wrap_log_reader.erl
+++ b/lib/kernel/src/wrap_log_reader.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -30,6 +30,8 @@
-export([open/1, open/2, chunk/1, chunk/2, close/1]).
+-export_type([continuation/0]).
+
-include("disk_log.hrl").
-record(wrap_reader,
diff --git a/lib/kernel/test/Makefile b/lib/kernel/test/Makefile
index 8eca37029d..8d2d55777b 100644
--- a/lib/kernel/test/Makefile
+++ b/lib/kernel/test/Makefile
@@ -48,6 +48,7 @@ MODULES= \
erl_distribution_SUITE \
erl_distribution_wb_SUITE \
erl_prim_loader_SUITE \
+ error_handler_SUITE \
error_logger_SUITE \
error_logger_warn_SUITE \
file_SUITE \
@@ -73,6 +74,7 @@ MODULES= \
seq_trace_SUITE \
wrap_log_reader_SUITE \
cleanup \
+ ignore_cores \
zlib_SUITE \
loose_node \
sendfile_SUITE
diff --git a/lib/kernel/test/application_SUITE.erl b/lib/kernel/test/application_SUITE.erl
index f469a0af98..2ca8840e1f 100644
--- a/lib/kernel/test/application_SUITE.erl
+++ b/lib/kernel/test/application_SUITE.erl
@@ -27,7 +27,7 @@
otp_1586/1, otp_2078/1, otp_2012/1, otp_2718/1, otp_2973/1,
otp_3002/1, otp_3184/1, otp_4066/1, otp_4227/1, otp_5363/1,
otp_5606/1,
- start_phases/1, get_key/1,
+ start_phases/1, get_key/1, get_env/1,
permit_false_start_local/1, permit_false_start_dist/1, script_start/1,
nodedown_start/1, init2973/0, loop2973/0, loop5606/1]).
@@ -49,7 +49,7 @@ all() ->
[failover, failover_comp, permissions, load,
load_use_cache, {group, reported_bugs}, start_phases,
script_start, nodedown_start, permit_false_start_local,
- permit_false_start_dist, get_key,
+ permit_false_start_dist, get_key, get_env,
{group, distr_changed}, config_change, shutdown_func, shutdown_timeout].
groups() ->
@@ -1503,6 +1503,15 @@ loop5606(Pid) ->
Pid ! {self(), Res}
end.
+get_env(suite) -> [];
+get_env(doc) ->
+ ["Tests get_env/* functions"];
+get_env(Conf) when is_list(Conf) ->
+ {ok, _} = application:get_env(kernel, error_logger),
+ undefined = application:get_env(undefined_app, a),
+ undefined = application:get_env(kernel, error_logger_xyz),
+ default = application:get_env(kernel, error_logger_xyz, default),
+ ok.
%%-----------------------------------------------------------------
%% Should be started in a CC view with:
diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl
index 5e0300639e..d7424c0c9a 100644
--- a/lib/kernel/test/code_SUITE.erl
+++ b/lib/kernel/test/code_SUITE.erl
@@ -684,8 +684,8 @@ ext_mod_dep(Config) when is_list(Config) ->
xref:set_default(s, [{verbose,false},{warnings,false},
{builtins,true},{recurse,true}]),
xref:set_library_path(s, code:get_path()),
- xref:add_directory(s, filename:dirname(code:which(kernel))),
- xref:add_directory(s, filename:dirname(code:which(lists))),
+ xref:add_directory(s, filename:join(code:lib_dir(kernel),"ebin")),
+ xref:add_directory(s, filename:join(code:lib_dir(stdlib),"ebin")),
case catch ext_mod_dep2() of
{'EXIT', Reason} ->
xref:stop(s),
diff --git a/lib/kernel/test/error_handler_SUITE.erl b/lib/kernel/test/error_handler_SUITE.erl
new file mode 100644
index 0000000000..2a86d39b74
--- /dev/null
+++ b/lib/kernel/test/error_handler_SUITE.erl
@@ -0,0 +1,68 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(error_handler_SUITE).
+
+-export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1,
+ init_per_group/2,end_per_group/2,
+ undefined_function_handler/1]).
+
+%% Callback from error_handler.
+-export(['$handle_undefined_function'/2]).
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [undefined_function_handler].
+
+groups() ->
+ [].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+
+%%-----------------------------------------------------------------
+
+undefined_function_handler(_) ->
+ 42 = ?MODULE:forty_two(),
+ 42 = (id(?MODULE)):forty_two(),
+ {ok,{a,b,c}} = ?MODULE:one_arg({a,b,c}),
+ {ok,{a,b,c}} = (id(?MODULE)):one_arg({a,b,c}),
+ {'EXIT',{undef,[{?MODULE,undef_and_not_handled,[[1,2,3]],[]}|_]}} =
+ (catch ?MODULE:undef_and_not_handled([1,2,3])),
+ ok.
+
+'$handle_undefined_function'(forty_two, []) ->
+ 42;
+'$handle_undefined_function'(one_arg, [Arg]) ->
+ {ok,Arg};
+'$handle_undefined_function'(Func, Args) ->
+ error_handler:raise_undef_exception(?MODULE, Func, Args).
+
+id(I) ->
+ I.
diff --git a/lib/kernel/test/error_logger_warn_SUITE.erl b/lib/kernel/test/error_logger_warn_SUITE.erl
index 265e1ae4c8..2bf467610e 100644
--- a/lib/kernel/test/error_logger_warn_SUITE.erl
+++ b/lib/kernel/test/error_logger_warn_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -310,7 +310,7 @@ nice_stop_node(Name) ->
{nodedown,Name} -> ok
end.
-%rensa rd() f�re varje rapport-test s� man bara f�r en fil...
+%clean out rd() before each report test in order to get only one file...
clean_rd() ->
{ok,L} = file:list_dir(rd()),
lists:foreach(fun(F) ->
diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl
index 9c507fd437..914f0d6127 100644
--- a/lib/kernel/test/file_SUITE.erl
+++ b/lib/kernel/test/file_SUITE.erl
@@ -84,6 +84,8 @@
-export([advise/1]).
+-export([allocate/1]).
+
-export([standard_io/1,mini_server/1]).
%% Debug exports
@@ -116,7 +118,7 @@ groups() ->
{files, [],
[{group, open}, {group, pos}, {group, file_info},
{group, consult}, {group, eval}, {group, script},
- truncate, sync, datasync, advise]},
+ truncate, sync, datasync, advise, allocate]},
{open, [],
[open1, old_modes, new_modes, path_open, close, access,
read_write, pread_write, append, open_errors,
@@ -1617,6 +1619,74 @@ advise(Config) when is_list(Config) ->
?line test_server:timetrap_cancel(Dog),
ok.
+allocate(suite) -> [];
+allocate(doc) -> "Tests that ?FILE_MODULE:allocate/3 at least doesn't crash.";
+allocate(Config) when is_list(Config) ->
+ ?line Dog = test_server:timetrap(test_server:seconds(5)),
+ ?line PrivDir = ?config(priv_dir, Config),
+ ?line Allocate = filename:join(PrivDir,
+ atom_to_list(?MODULE)
+ ++"_allocate.fil"),
+
+ Line1 = "Hello\n",
+ Line2 = "World!\n",
+
+ ?line {ok, Fd} = ?FILE_MODULE:open(Allocate, [write, binary]),
+ allocate_and_assert(Fd, 1, iolist_size([Line1, Line2])),
+ ?line ok = io:format(Fd, "~s", [Line1]),
+ ?line ok = io:format(Fd, "~s", [Line2]),
+ ?line ok = ?FILE_MODULE:close(Fd),
+
+ ?line {ok, Fd2} = ?FILE_MODULE:open(Allocate, [write, binary]),
+ allocate_and_assert(Fd2, 1, iolist_size(Line1)),
+ ?line ok = io:format(Fd2, "~s", [Line1]),
+ ?line ok = io:format(Fd2, "~s", [Line2]),
+ ?line ok = ?FILE_MODULE:close(Fd2),
+
+ ?line {ok, Fd3} = ?FILE_MODULE:open(Allocate, [write, binary]),
+ allocate_and_assert(Fd3, 1, iolist_size(Line1) + 1),
+ ?line ok = io:format(Fd3, "~s", [Line1]),
+ ?line ok = io:format(Fd3, "~s", [Line2]),
+ ?line ok = ?FILE_MODULE:close(Fd3),
+
+ ?line {ok, Fd4} = ?FILE_MODULE:open(Allocate, [write, binary]),
+ allocate_and_assert(Fd4, 1, 4 * iolist_size([Line1, Line2])),
+ ?line ok = io:format(Fd4, "~s", [Line1]),
+ ?line ok = io:format(Fd4, "~s", [Line2]),
+ ?line ok = ?FILE_MODULE:close(Fd4),
+
+ ?line [] = flush(),
+ ?line test_server:timetrap_cancel(Dog),
+ ok.
+
+allocate_and_assert(Fd, Offset, Length) ->
+ % Just verify that calls to ?PRIM_FILE:allocate/3 don't crash or have
+ % any other negative side effect. We can't really asssert against a
+ % specific return value, because support for file space pre-allocation
+ % depends on the OS, OS version and underlying filesystem.
+ %
+ % The Linux kernel added support for fallocate() in version 2.6.23,
+ % which currently works only for the ext4, ocfs2, xfs and btrfs file
+ % systems. posix_fallocate() is available in glibc as of version
+ % 2.1.94, but it was buggy until glibc version 2.7.
+ %
+ % Mac OS X, as of version 10.3, supports the fcntl operation F_PREALLOCATE.
+ %
+ % Solaris supports posix_fallocate() but only for the UFS file system
+ % apparently (not supported for ZFS).
+ %
+ % FreeBSD 9.0 is the first FreeBSD release supporting posix_fallocate().
+ %
+ % For Windows there's apparently no way to pre-allocate file space, at
+ % least with same semantics as posix_fallocate(), fallocate() and
+ % fcntl F_PREALLOCATE.
+ Result = ?FILE_MODULE:allocate(Fd, Offset, Length),
+ case os:type() of
+ {win32, _} ->
+ ?line {error, enotsup} = Result;
+ _ ->
+ ?line _ = Result
+ end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/kernel/test/file_name_SUITE.erl b/lib/kernel/test/file_name_SUITE.erl
index 3aa010a708..40bde8a736 100644
--- a/lib/kernel/test/file_name_SUITE.erl
+++ b/lib/kernel/test/file_name_SUITE.erl
@@ -1,4 +1,5 @@
-module(file_name_SUITE).
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
@@ -336,7 +337,7 @@ check_normal(Mod) ->
check_icky(Mod) ->
{ok,Dir} = Mod:get_cwd(),
try
- ?line true=(length("���") =:= 3),
+ ?line true=(length("åäö") =:= 3),
?line UniMode = file:native_name_encoding() =/= latin1,
?line make_icky_dir(Mod),
?line {ok, L0} = Mod:list_dir("."),
@@ -357,42 +358,42 @@ check_icky(Mod) ->
|| {T,S,Targ} <- icky_dir(), T =:= symlink ],
?line [ {ok, Cont} = Mod:read_file(SymL) || {SymL,_,Cont} <- Syms ],
?line [ {ok, Targ} = fixlink(Mod:read_link(SymL)) || {SymL,Targ,_} <- Syms ],
- ?line chk_cre_dir(Mod,[{directory,"���_dir",icky_dir()}]),
+ ?line chk_cre_dir(Mod,[{directory,"åäö_dir",icky_dir()}]),
?line {ok,BeginAt} = Mod:get_cwd(),
?line true = is_list(BeginAt),
- ?line {error,enoent} = Mod:set_cwd("��_dir"),
- ?line ok = Mod:set_cwd("���_dir"),
+ ?line {error,enoent} = Mod:set_cwd("åä_dir"),
+ ?line ok = Mod:set_cwd("åäö_dir"),
?line {ok, NowAt} = Mod:get_cwd(),
?line true = is_list(NowAt),
?line true = BeginAt =/= NowAt,
?line ok = Mod:set_cwd(".."),
?line {ok,BeginAt} = Mod:get_cwd(),
- ?line rm_r2(Mod,"���_dir"),
+ ?line rm_r2(Mod,"åäö_dir"),
{OS,TYPE} = os:type(),
% Check that treat_icky really converts to the same as the OS
case UniMode of
true ->
- ?line chk_cre_dir(Mod,[{directory,"���_dir",[]}]),
- ?line ok = Mod:set_cwd("���_dir"),
- ?line ok = Mod:write_file(<<"���">>,<<"hello">>),
- ?line Treated = treat_icky(<<"���">>),
+ ?line chk_cre_dir(Mod,[{directory,"åäö_dir",[]}]),
+ ?line ok = Mod:set_cwd("åäö_dir"),
+ ?line ok = Mod:write_file(<<"ååå">>,<<"hello">>),
+ ?line Treated = treat_icky(<<"ååå">>),
?line {ok,[Treated]} = Mod:list_dir("."),
- ?line ok = Mod:delete(<<"���">>),
+ ?line ok = Mod:delete(<<"ååå">>),
?line {ok,[]} = Mod:list_dir("."),
?line ok = Mod:set_cwd(".."),
- ?line rm_r2(Mod,"���_dir");
+ ?line rm_r2(Mod,"åäö_dir");
false ->
ok
end,
- ?line chk_cre_dir(Mod,[{directory,treat_icky(<<"���_dir">>),icky_dir()}]),
+ ?line chk_cre_dir(Mod,[{directory,treat_icky(<<"åäö_dir">>),icky_dir()}]),
if
UniMode and (OS =/= win32) ->
- ?line {error,enoent} = Mod:set_cwd("���_dir");
+ ?line {error,enoent} = Mod:set_cwd("åäö_dir");
true ->
ok
end,
- ?line ok = Mod:set_cwd(treat_icky(<<"���_dir">>)),
+ ?line ok = Mod:set_cwd(treat_icky(<<"åäö_dir">>)),
?line {ok, NowAt2} = Mod:get_cwd(),
io:format("~p~n",[NowAt2]),
% Cannot create raw unicode-breaking filenames on windows or macos
@@ -400,22 +401,22 @@ check_icky(Mod) ->
?line true = BeginAt =/= NowAt2,
?line ok = Mod:set_cwd(".."),
?line {ok,BeginAt} = Mod:get_cwd(),
- ?line rm_r2(Mod,conv(treat_icky(<<"���_dir">>))),
+ ?line rm_r2(Mod,conv(treat_icky(<<"åäö_dir">>))),
case has_links() of
true ->
- ?line ok = Mod:make_link("fil1","nisse�"),
- ?line {ok, <<"fil1">>} = Mod:read_file("nisse�"),
- ?line {ok, #file_info{type = regular}} = Mod:read_link_info("nisse�"),
- ?line ok = Mod:delete("nisse�"),
- ?line ok = Mod:make_link("fil1",treat_icky(<<"nisse�">>)),
- ?line {ok, <<"fil1">>} = Mod:read_file(treat_icky(<<"nisse�">>)),
- ?line {ok, #file_info{type = regular}} = Mod:read_link_info(treat_icky(<<"nisse�">>)),
- ?line ok = Mod:delete(treat_icky(<<"nisse�">>)),
+ ?line ok = Mod:make_link("fil1","nisseö"),
+ ?line {ok, <<"fil1">>} = Mod:read_file("nisseö"),
+ ?line {ok, #file_info{type = regular}} = Mod:read_link_info("nisseö"),
+ ?line ok = Mod:delete("nisseö"),
+ ?line ok = Mod:make_link("fil1",treat_icky(<<"nisseö">>)),
+ ?line {ok, <<"fil1">>} = Mod:read_file(treat_icky(<<"nisseö">>)),
+ ?line {ok, #file_info{type = regular}} = Mod:read_link_info(treat_icky(<<"nisseö">>)),
+ ?line ok = Mod:delete(treat_icky(<<"nisseö">>)),
?line {ok, <<"fil1">>} = Mod:read_file("fil1"),
- ?line {error,enoent} = Mod:read_file("nisse�"),
- ?line {error,enoent} = Mod:read_link_info("nisse�"),
- ?line {error,enoent} = Mod:read_file(treat_icky(<<"nisse�">>)),
- ?line {error,enoent} = Mod:read_link_info(treat_icky(<<"nisse�">>));
+ ?line {error,enoent} = Mod:read_file("nisseö"),
+ ?line {error,enoent} = Mod:read_link_info("nisseö"),
+ ?line {error,enoent} = Mod:read_file(treat_icky(<<"nisseö">>)),
+ ?line {error,enoent} = Mod:read_link_info(treat_icky(<<"nisseö">>));
false ->
ok
end,
@@ -430,42 +431,42 @@ check_icky(Mod) ->
?line {ok, BC} = Mod:read(FD,1024),
?line ok = file:close(FD)
end || {regular,Name,Content} <- icky_dir() ],
- ?line Mod:rename("���2","���_fil1"),
- ?line {ok, <<"���2">>} = Mod:read_file("���_fil1"),
- ?line {error,enoent} = Mod:read_file("���2"),
- ?line Mod:rename("���_fil1","���2"),
- ?line {ok, <<"���2">>} = Mod:read_file("���2"),
- ?line {error,enoent} = Mod:read_file("���_fil1"),
+ ?line Mod:rename("åäö2","åäö_fil1"),
+ ?line {ok, <<"åäö2">>} = Mod:read_file("åäö_fil1"),
+ ?line {error,enoent} = Mod:read_file("åäö2"),
+ ?line Mod:rename("åäö_fil1","åäö2"),
+ ?line {ok, <<"åäö2">>} = Mod:read_file("åäö2"),
+ ?line {error,enoent} = Mod:read_file("åäö_fil1"),
- ?line Mod:rename("���2",treat_icky(<<"���_fil1">>)),
- ?line {ok, <<"���2">>} = Mod:read_file(treat_icky(<<"���_fil1">>)),
+ ?line Mod:rename("åäö2",treat_icky(<<"åäö_fil1">>)),
+ ?line {ok, <<"åäö2">>} = Mod:read_file(treat_icky(<<"åäö_fil1">>)),
if
UniMode and (OS =/= win32) ->
- {error,enoent} = Mod:read_file("���_fil1");
+ {error,enoent} = Mod:read_file("åäö_fil1");
true ->
ok
end,
- ?line {error,enoent} = Mod:read_file("���2"),
- ?line Mod:rename(treat_icky(<<"���_fil1">>),"���2"),
- ?line {ok, <<"���2">>} = Mod:read_file("���2"),
- ?line {error,enoent} = Mod:read_file("���_fil1"),
- ?line {error,enoent} = Mod:read_file(treat_icky(<<"���_fil1">>)),
+ ?line {error,enoent} = Mod:read_file("åäö2"),
+ ?line Mod:rename(treat_icky(<<"åäö_fil1">>),"åäö2"),
+ ?line {ok, <<"åäö2">>} = Mod:read_file("åäö2"),
+ ?line {error,enoent} = Mod:read_file("åäö_fil1"),
+ ?line {error,enoent} = Mod:read_file(treat_icky(<<"åäö_fil1">>)),
- ?line {ok,FI} = Mod:read_file_info("���2"),
+ ?line {ok,FI} = Mod:read_file_info("åäö2"),
?line NewMode = FI#file_info.mode band (bnot 8#333),
?line NewMode2 = NewMode bor 8#222,
?line true = NewMode2 =/= NewMode,
- ?line ok = Mod:write_file_info("���2",FI#file_info{mode = NewMode}),
- ?line {ok,#file_info{mode = NewMode}} = Mod:read_file_info("���2"),
- ?line ok = Mod:write_file_info("���2",FI#file_info{mode = NewMode2}),
- ?line {ok,#file_info{mode = NewMode2}} = Mod:read_file_info("���2"),
+ ?line ok = Mod:write_file_info("åäö2",FI#file_info{mode = NewMode}),
+ ?line {ok,#file_info{mode = NewMode}} = Mod:read_file_info("åäö2"),
+ ?line ok = Mod:write_file_info("åäö2",FI#file_info{mode = NewMode2}),
+ ?line {ok,#file_info{mode = NewMode2}} = Mod:read_file_info("åäö2"),
- ?line {ok,FII} = Mod:read_file_info(treat_icky(<<"���5">>)),
+ ?line {ok,FII} = Mod:read_file_info(treat_icky(<<"åäö5">>)),
?line true = NewMode2 =/= NewMode,
- ?line ok = Mod:write_file_info(treat_icky(<<"���5">>),FII#file_info{mode = NewMode}),
- ?line {ok,#file_info{mode = NewMode}} = Mod:read_file_info(treat_icky(<<"���5">>)),
- ?line ok = Mod:write_file_info(<<"���5">>,FII#file_info{mode = NewMode2}),
- ?line {ok,#file_info{mode = NewMode2}} = Mod:read_file_info(treat_icky(<<"���5">>)),
+ ?line ok = Mod:write_file_info(treat_icky(<<"åäö5">>),FII#file_info{mode = NewMode}),
+ ?line {ok,#file_info{mode = NewMode}} = Mod:read_file_info(treat_icky(<<"åäö5">>)),
+ ?line ok = Mod:write_file_info(<<"åäö5">>,FII#file_info{mode = NewMode2}),
+ ?line {ok,#file_info{mode = NewMode2}} = Mod:read_file_info(treat_icky(<<"åäö5">>)),
ok
after
Mod:set_cwd(Dir),
@@ -475,7 +476,7 @@ check_icky(Mod) ->
check_very_icky(Mod) ->
{ok,Dir} = Mod:get_cwd(),
try
- ?line true=(length("���") =:= 3),
+ ?line true=(length("åäö") =:= 3),
?line UniMode = file:native_name_encoding() =/= latin1,
if
not UniMode ->
@@ -497,7 +498,7 @@ check_very_icky(Mod) ->
?line chk_cre_dir(Mod,[{directory,[1088,1079,1091]++"_dir",very_icky_dir()}]),
?line {ok,BeginAt} = Mod:get_cwd(),
?line true = is_list(BeginAt),
- ?line {error,enoent} = Mod:set_cwd("��_dir"),
+ ?line {error,enoent} = Mod:set_cwd("åä_dir"),
?line ok = Mod:set_cwd([1088,1079,1091]++"_dir"),
?line {ok, NowAt} = Mod:get_cwd(),
?line true = is_list(NowAt),
@@ -514,16 +515,16 @@ check_very_icky(Mod) ->
?line {ok, #file_info{type = regular}} =
Mod:read_link_info("nisse"++[1088,1079,1091]),
?line ok = Mod:delete("nisse"++[1088,1079,1091]),
- ?line ok = Mod:make_link("fil1",<<"nisse�">>),
- ?line {ok, <<"fil1">>} = Mod:read_file(<<"nisse�">>),
+ ?line ok = Mod:make_link("fil1",<<"nisseö">>),
+ ?line {ok, <<"fil1">>} = Mod:read_file(<<"nisseö">>),
?line {ok, #file_info{type = regular}} =
- Mod:read_link_info(<<"nisse�">>),
- ?line ok = Mod:delete(<<"nisse�">>),
+ Mod:read_link_info(<<"nisseö">>),
+ ?line ok = Mod:delete(<<"nisseö">>),
?line {ok, <<"fil1">>} = Mod:read_file("fil1"),
?line {error,enoent} = Mod:read_file("nisse"++[1088,1079,1091]),
?line {error,enoent} = Mod:read_link_info("nisse"++[1088,1079,1091]),
- ?line {error,enoent} = Mod:read_file(<<"nisse�">>),
- ?line {error,enoent} = Mod:read_link_info(<<"nisse�">>);
+ ?line {error,enoent} = Mod:read_file(<<"nisseö">>),
+ ?line {error,enoent} = Mod:read_link_info(<<"nisseö">>);
false ->
ok
end,
@@ -540,10 +541,10 @@ check_very_icky(Mod) ->
end || {regular,Name,Content} <- very_icky_dir() ],
?line Mod:rename([956,965,963,954,959,49],
[956,965,963,954,959]++"_fil1"),
- ?line {ok, <<"���2">>} = Mod:read_file([956,965,963,954,959]++"_fil1"),
+ ?line {ok, <<"åäö2">>} = Mod:read_file([956,965,963,954,959]++"_fil1"),
?line {error,enoent} = Mod:read_file([956,965,963,954,959,49]),
?line Mod:rename([956,965,963,954,959]++"_fil1",[956,965,963,954,959,49]),
- ?line {ok, <<"���2">>} = Mod:read_file([956,965,963,954,959,49]),
+ ?line {ok, <<"åäö2">>} = Mod:read_file([956,965,963,954,959,49]),
?line {error,enoent} = Mod:read_file([956,965,963,954,959]++"_fil1"),
?line {ok,FI} = Mod:read_file_info([956,965,963,954,959,49]),
@@ -574,9 +575,9 @@ check_very_icky(Mod) ->
end,
?line {NumOK,NumNOK} = filelib:fold_files(".",".*",true,fun(_F,{N,M}) when is_list(_F) -> io:format("~ts~n",[_F]),{N+1,M}; (_F,{N,M}) -> io:format("~p~n",[_F]),{N,M+1} end,{0,0}),
?line ok = filelib:fold_files(".",[1076,1089,1072,124,46,42],true,fun(_F,_) -> ok end,false),
- ?line SF3 = unicode:characters_to_binary("���subfil3",
+ ?line SF3 = unicode:characters_to_binary("åäösubfil3",
file:native_name_encoding()),
- ?line SF2 = case treat_icky(<<"���subfil2">>) of
+ ?line SF2 = case treat_icky(<<"åäösubfil2">>) of
LF2 when is_list(LF2) ->
unicode:characters_to_binary(LF2,
file:native_name_encoding());
@@ -584,7 +585,7 @@ check_very_icky(Mod) ->
BF2
end,
?line Sorted = lists:sort([SF3,SF2]),
- ?line Sorted = lists:sort(filelib:wildcard("*",<<"���subdir2">>)),
+ ?line Sorted = lists:sort(filelib:wildcard("*",<<"åäösubdir2">>)),
ok
catch
throw:need_unicode_mode ->
@@ -744,26 +745,26 @@ hopeless_darwin() ->
icky_dir() ->
[{regular,"fil1","fil1"},
- {regular,"���2","���2"}] ++
+ {regular,"åäö2","åäö2"}] ++
case has_links() of
true ->
- [{regular,"���3","���2"},
- {symlink,"���4","���2"}];
+ [{regular,"åäö3","åäö2"},
+ {symlink,"åäö4","åäö2"}];
false ->
[]
end ++
- [{regular,treat_icky(<<"���5">>),"���5"}] ++
+ [{regular,treat_icky(<<"åäö5">>),"åäö5"}] ++
case has_links() of
true ->
- [{symlink,treat_icky(<<"���6">>),treat_icky(<<"���5">>)}];
+ [{symlink,treat_icky(<<"åäö6">>),treat_icky(<<"åäö5">>)}];
false ->
[]
end ++
- [{directory,treat_icky(<<"���subdir2">>),
- [{regular,treat_icky(<<"���subfil2">>),"���subfil12"},
- {regular,"���subfil3","���subfil13"}]},
- {directory,"���subdir",
- [{regular,"���subfil1","���subfil1"}]}].
+ [{directory,treat_icky(<<"åäösubdir2">>),
+ [{regular,treat_icky(<<"åäösubfil2">>),"åäösubfil12"},
+ {regular,"åäösubfil3","åäösubfil13"}]},
+ {directory,"åäösubdir",
+ [{regular,"åäösubfil1","åäösubfil1"}]}].
make_very_icky_dir(Mod) ->
rm_rf(Mod,"very_icky_dir"),
@@ -774,26 +775,26 @@ make_very_icky_dir(Mod) ->
very_icky_dir() ->
[{regular,"fil1","fil1"},
- {regular,[956,965,963,954,959,49],"���2"}] ++
+ {regular,[956,965,963,954,959,49],"åäö2"}] ++
case has_links() of
true ->
- [{regular,[956,965,963,954,959,50],"���2"},
+ [{regular,[956,965,963,954,959,50],"åäö2"},
{symlink,[956,965,963,954,959,51],[956,965,963,954,959,49]}];
false ->
[]
end ++
- [{regular,treat_icky(<<"���5">>),"���5"}] ++
+ [{regular,treat_icky(<<"åäö5">>),"åäö5"}] ++
case has_links() of
true ->
- [{symlink,treat_icky(<<"���6">>),treat_icky(<<"���5">>)}];
+ [{symlink,treat_icky(<<"åäö6">>),treat_icky(<<"åäö5">>)}];
false ->
[]
end ++
- [{directory,treat_icky(<<"���subdir2">>),
- [{regular,treat_icky(<<"���subfil2">>),"���subfil12"},
- {regular,"���subfil3","���subfil13"}]},
+ [{directory,treat_icky(<<"åäösubdir2">>),
+ [{regular,treat_icky(<<"åäösubfil2">>),"åäösubfil12"},
+ {regular,"åäösubfil3","åäösubfil13"}]},
{directory,[956,965,963,954,959]++"subdir1",
- [{regular,[956,965,963,954,959]++"subfil1","���subfil1"}]}].
+ [{regular,[956,965,963,954,959]++"subfil1","åäösubfil1"}]}].
%% Some OS'es simply do not allow non UTF8 filenames
treat_icky(Bin) ->
diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl
index bcc2f0b840..2a886b2efc 100644
--- a/lib/kernel/test/gen_sctp_SUITE.erl
+++ b/lib/kernel/test/gen_sctp_SUITE.erl
@@ -31,22 +31,24 @@
[basic/1,
api_open_close/1,api_listen/1,api_connect_init/1,api_opts/1,
xfer_min/1,xfer_active/1,def_sndrcvinfo/1,implicit_inet6/1,
- basic_stream/1, xfer_stream_min/1, peeloff/1, buffers/1,
open_multihoming_ipv4_socket/1,
open_unihoming_ipv6_socket/1,
open_multihoming_ipv6_socket/1,
- open_multihoming_ipv4_and_ipv6_socket/1]).
+ open_multihoming_ipv4_and_ipv6_socket/1,
+ basic_stream/1, xfer_stream_min/1, peeloff_active_once/1,
+ peeloff_active_true/1, buffers/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[basic, api_open_close, api_listen, api_connect_init,
api_opts, xfer_min, xfer_active, def_sndrcvinfo, implicit_inet6,
- basic_stream, xfer_stream_min, peeloff, buffers,
open_multihoming_ipv4_socket,
open_unihoming_ipv6_socket,
open_multihoming_ipv6_socket,
- open_multihoming_ipv4_and_ipv6_socket].
+ open_multihoming_ipv4_and_ipv6_socket,
+ basic_stream, xfer_stream_min, peeloff_active_once,
+ peeloff_active_true, buffers].
groups() ->
[].
@@ -923,23 +925,34 @@ do_from_other_process(Fun) ->
end.
+peeloff_active_once(doc) ->
+ "Peel off an SCTP stream socket ({active,once})";
+peeloff_active_once(suite) ->
+ [];
+
+peeloff_active_once(Config) ->
+ peeloff(Config, [{active,once}]).
-peeloff(doc) ->
- "Peel off an SCTP stream socket";
-peeloff(suite) ->
+peeloff_active_true(doc) ->
+ "Peel off an SCTP stream socket ({active,true})";
+peeloff_active_true(suite) ->
[];
-peeloff(Config) when is_list(Config) ->
+
+peeloff_active_true(Config) ->
+ peeloff(Config, [{active,true}]).
+
+peeloff(Config, SockOpts) when is_list(Config) ->
?line Addr = {127,0,0,1},
?line Stream = 0,
?line Timeout = 333,
- ?line S1 = socket_open([{ifaddr,Addr}], Timeout),
+ ?line S1 = socket_open([{ifaddr,Addr}|SockOpts], Timeout),
?line ?LOGVAR(S1),
?line P1 = socket_call(S1, get_port),
?line ?LOGVAR(P1),
?line Socket1 = socket_call(S1, get_socket),
?line ?LOGVAR(Socket1),
?line socket_call(S1, {listen,true}),
- ?line S2 = socket_open([{ifaddr,Addr}], Timeout),
+ ?line S2 = socket_open([{ifaddr,Addr}|SockOpts], Timeout),
?line ?LOGVAR(S2),
?line P2 = socket_call(S2, get_port),
?line ?LOGVAR(P2),
@@ -983,7 +996,7 @@ peeloff(Config) when is_list(Config) ->
socket_bailout([S1,S2])
end,
%%
- ?line S3 = socket_peeloff(Socket1, S1Ai, Timeout),
+ ?line S3 = socket_peeloff(Socket1, S1Ai, SockOpts, Timeout),
?line ?LOGVAR(S3),
?line P3_X = socket_call(S3, get_port),
?line ?LOGVAR(P3_X),
@@ -1302,8 +1315,15 @@ recv_comm_up_eventually(S) ->
%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% socket gen_server ultra light
-socket_open(SocketOpts, Timeout) ->
- Opts = [{type,seqpacket},{active,once},binary|SocketOpts],
+socket_open(SockOpts0, Timeout) ->
+ SockOpts =
+ case lists:keyfind(active,1,SockOpts0) of
+ false ->
+ [{active,once}|SockOpts0];
+ _ ->
+ SockOpts0
+ end,
+ Opts = [{type,seqpacket},binary|SockOpts],
Starter =
fun () ->
{ok,Socket} =
@@ -1312,8 +1332,8 @@ socket_open(SocketOpts, Timeout) ->
end,
s_start(Starter, Timeout).
-socket_peeloff(Socket, AssocId, Timeout) ->
- Opts = [{active,once},binary],
+socket_peeloff(Socket, AssocId, SocketOpts, Timeout) ->
+ Opts = [binary|SocketOpts],
Starter =
fun () ->
{ok,NewSocket} =
diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl
index 2354f8accd..cd768813cf 100644
--- a/lib/kernel/test/gen_udp_SUITE.erl
+++ b/lib/kernel/test/gen_udp_SUITE.erl
@@ -1,7 +1,8 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -442,7 +443,7 @@ open_fd(suite) ->
open_fd(doc) ->
["Test that the 'fd' option works"];
open_fd(Config) when is_list(Config) ->
- Msg = "Det g�r ont n�r knoppar brista. Varf�r skulle annars v�ren tveka?",
+ Msg = "Det gör ont när knoppar brista. Varför skulle annars våren tveka?",
Addr = {127,0,0,1},
{ok,S1} = gen_udp:open(0),
{ok,P2} = inet:port(S1),
diff --git a/lib/kernel/test/global_SUITE.erl b/lib/kernel/test/global_SUITE.erl
index 60035b50a0..9428a38660 100644
--- a/lib/kernel/test/global_SUITE.erl
+++ b/lib/kernel/test/global_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -91,27 +91,9 @@ end_per_group(_GroupName, Config) ->
Config.
init_per_suite(Config) ->
-
- %% Copied from test_server_ctrl ln 647, we have to do this here as
- %% the test_server only does this when run without common_test
- global:sync(),
- case global:whereis_name(test_server) of
- undefined ->
- io:format(user, "Registering test_server globally!~n",[]),
- global:register_name(test_server, whereis(test_server_ctrl));
- Pid ->
- case node() of
- N when N == node(Pid) ->
- io:format(user, "Warning: test_server already running!\n", []),
- global:re_register_name(test_server,self());
- _ ->
- ok
- end
- end,
Config.
end_per_suite(_Config) ->
- global:unregister_name(test_server),
ok.
@@ -135,8 +117,7 @@ end_per_testcase(_Case, Config) ->
?line write_high_level_trace(Config),
?line _ =
gen_server:call(global_name_server, high_level_trace_stop, infinity),
- ?line[global:unregister_name(N) || N <- global:registered_names(),
- N =/= test_server],
+ [global:unregister_name(N) || N <- global:registered_names()],
?line InitRegistered = ?registered,
?line Registered = registered(),
?line [io:format("~s local names: ~p~n", [What, N]) ||
@@ -168,7 +149,7 @@ end_per_testcase(_Case, Config) ->
register_1(suite) -> [];
register_1(Config) when is_list(Config) ->
Timeout = 15,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
P = spawn_link(?MODULE, lock_global, [self(), Config]),
@@ -195,7 +176,6 @@ register_1(Config) when is_list(Config) ->
?line _ = global:unregister_name(foo),
write_high_level_trace(Config),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
lock_global(Parent, Config) ->
@@ -238,7 +218,7 @@ lock_global(Parent, Config) ->
both_known_1(suite) -> [];
both_known_1(Config) when is_list(Config) ->
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
@@ -316,7 +296,6 @@ both_known_1(Config) when is_list(Config) ->
stop_node(Cp3),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
lost_unregister(suite) -> [];
@@ -324,7 +303,7 @@ lost_unregister(doc) ->
["OTP-6428. An unregistered name reappears."];
lost_unregister(Config) when is_list(Config) ->
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
@@ -361,7 +340,6 @@ lost_unregister(Config) when is_list(Config) ->
stop_node(B),
stop_node(C),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
-define(UNTIL_LOOP, 300).
@@ -448,7 +426,7 @@ lock_global2(Id, Parent) ->
names(suite) -> [];
names(Config) when is_list(Config) ->
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -532,7 +510,6 @@ names(Config) when is_list(Config) ->
?line ?UNTIL(undefined =:= global:whereis_name(test)),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
names_hidden(suite) -> [];
@@ -541,7 +518,7 @@ names_hidden(doc) ->
"visible nodes."];
names_hidden(Config) when is_list(Config) ->
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -639,13 +616,12 @@ names_hidden(Config) when is_list(Config) ->
stop_node(Cp3),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
locks(suite) -> [];
locks(Config) when is_list(Config) ->
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line {ok, Cp1} = start_node(cp1, Config),
@@ -750,7 +726,6 @@ locks(Config) when is_list(Config) ->
?line test_server:sleep(10),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
@@ -760,7 +735,7 @@ locks_hidden(doc) ->
"visible nodes."];
locks_hidden(Config) when is_list(Config) ->
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNodes = nodes(),
@@ -833,14 +808,13 @@ locks_hidden(Config) when is_list(Config) ->
stop_node(Cp3),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
bad_input(suite) -> [];
bad_input(Config) when is_list(Config) ->
Timeout = 15,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
Pid = whereis(global_name_server),
@@ -854,13 +828,12 @@ bad_input(Config) when is_list(Config) ->
?line {'EXIT', _} = (catch global:trans({id, self()}, {m,f}, [node()], -1)),
?line Pid = whereis(global_name_server),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
names_and_locks(suite) -> [];
names_and_locks(Config) when is_list(Config) ->
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -922,7 +895,6 @@ names_and_locks(Config) when is_list(Config) ->
stop_node(Cp3),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
lock_die(suite) -> [];
@@ -930,7 +902,7 @@ lock_die(doc) ->
["OTP-6341. Remove locks using monitors."];
lock_die(Config) when is_list(Config) ->
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -964,7 +936,6 @@ lock_die(Config) when is_list(Config) ->
stop_node(Cp1),
stop_node(Cp2),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
name_die(suite) -> [];
@@ -972,7 +943,7 @@ name_die(doc) ->
["OTP-6341. Remove names using monitors."];
name_die(Config) when is_list(Config) ->
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -1027,7 +998,6 @@ name_die(Config) when is_list(Config) ->
write_high_level_trace(Config),
stop_nodes(Cps),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
kill_pid(Pid, File, Config) ->
@@ -1040,7 +1010,7 @@ basic_partition(doc) ->
["Tests that two partitioned networks exchange correct info."];
basic_partition(Config) when is_list(Config) ->
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -1088,7 +1058,6 @@ basic_partition(Config) when is_list(Config) ->
stop_node(Cp2),
stop_node(Cp3),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
basic_name_partition(suite) ->
@@ -1099,7 +1068,7 @@ basic_name_partition(doc) ->
"during connect phase are handled correctly."];
basic_name_partition(Config) when is_list(Config) ->
Timeout = 60,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -1167,7 +1136,6 @@ basic_name_partition(Config) when is_list(Config) ->
stop_node(Cp2),
stop_node(Cp3),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
%Peer nodes cp0 - cp6 are started. Break apart the connections from
@@ -1190,7 +1158,7 @@ advanced_partition(doc) ->
"partitioned networks connect."];
advanced_partition(Config) when is_list(Config) ->
Timeout = 60,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -1278,7 +1246,6 @@ advanced_partition(Config) when is_list(Config) ->
stop_node(Cp5),
stop_node(Cp6),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
%Peer nodes cp0 - cp6 are started, and partitioned just like in
@@ -1297,7 +1264,7 @@ stress_partition(doc) ->
"go up/down a bit."];
stress_partition(Config) when is_list(Config) ->
Timeout = 90,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -1377,7 +1344,6 @@ stress_partition(Config) when is_list(Config) ->
stop_node(Cp7),
stop_node(Cp8),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
@@ -1408,7 +1374,7 @@ ring(doc) ->
"Make sure that there's just one winner."];
ring(Config) when is_list(Config) ->
Timeout = 60,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -1486,7 +1452,6 @@ ring(Config) when is_list(Config) ->
stop_node(Cp7),
stop_node(Cp8),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
simple_ring(suite) ->
@@ -1499,7 +1464,7 @@ simple_ring(doc) ->
"Make sure that there's just one winner."];
simple_ring(Config) when is_list(Config) ->
Timeout = 60,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -1565,7 +1530,6 @@ simple_ring(Config) when is_list(Config) ->
stop_node(Cp4),
stop_node(Cp5),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
line(suite) ->
@@ -1576,7 +1540,7 @@ line(doc) ->
"Make sure that there's just one winner."];
line(Config) when is_list(Config) ->
Timeout = 60,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -1655,7 +1619,6 @@ line(Config) when is_list(Config) ->
stop_node(Cp7),
stop_node(Cp8),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
@@ -1669,7 +1632,7 @@ simple_line(doc) ->
"Make sure that there's just one winner."];
simple_line(Config) when is_list(Config) ->
Timeout = 60,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -1735,7 +1698,6 @@ simple_line(Config) when is_list(Config) ->
stop_node(Cp4),
stop_node(Cp5),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
otp_1849(suite) -> [];
@@ -1743,7 +1705,7 @@ otp_1849(doc) ->
["Test ticket: Global should keep track of all pids that set the same lock."];
otp_1849(Config) when is_list(Config) ->
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line {ok, Cp1} = start_node(cp1, Config),
@@ -1822,7 +1784,6 @@ otp_1849(Config) when is_list(Config) ->
stop_node(Cp2),
stop_node(Cp3),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
@@ -1840,7 +1801,7 @@ otp_3162(Config) when is_list(Config) ->
do_otp_3162(StartFun, Config) ->
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line [Cp1, Cp2, Cp3] = StartFun(),
@@ -1860,16 +1821,16 @@ do_otp_3162(StartFun, Config) ->
?line ?UNTIL
([Cp3] =:= lists:sort(rpc:call(Cp1, erlang, nodes, [])) -- [node()]),
- ?line ?UNTIL([kalle, test_server, vera] =:=
+ ?UNTIL([kalle, vera] =:=
lists:sort(rpc:call(Cp1, global, registered_names, []))),
?line ?UNTIL
([Cp3] =:= lists:sort(rpc:call(Cp2, erlang, nodes, [])) -- [node()]),
- ?line ?UNTIL([stina, test_server, vera] =:=
+ ?UNTIL([stina, vera] =:=
lists:sort(rpc:call(Cp2, global, registered_names, []))),
?line ?UNTIL
([Cp1, Cp2] =:=
lists:sort(rpc:call(Cp3, erlang, nodes, [])) -- [node()]),
- ?line ?UNTIL([kalle, stina, test_server, vera] =:=
+ ?UNTIL([kalle, stina, vera] =:=
lists:sort(rpc:call(Cp3, global, registered_names, []))),
?line pong = rpc:call(Cp2, net_adm, ping, [Cp1]),
@@ -1880,17 +1841,17 @@ do_otp_3162(StartFun, Config) ->
?line
?UNTIL(begin
NN = lists:sort(rpc:call(Cp1, global, registered_names, [])),
- [kalle, stina, test_server, vera] =:= NN
+ [kalle, stina, vera] =:= NN
end),
?line ?UNTIL
([Cp1, Cp3] =:=
lists:sort(rpc:call(Cp2, erlang, nodes, [])) -- [node()]),
- ?line ?UNTIL([kalle, stina, test_server, vera] =:=
+ ?UNTIL([kalle, stina, vera] =:=
lists:sort(rpc:call(Cp2, global, registered_names, []))),
?line ?UNTIL
([Cp1, Cp2] =:=
lists:sort(rpc:call(Cp3, erlang, nodes, [])) -- [node()]),
- ?line ?UNTIL([kalle, stina, test_server, vera] =:=
+ ?UNTIL([kalle, stina, vera] =:=
lists:sort(rpc:call(Cp3, global, registered_names, []))),
write_high_level_trace(Config),
@@ -1898,7 +1859,6 @@ do_otp_3162(StartFun, Config) ->
stop_node(Cp2),
stop_node(Cp3),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
@@ -1907,7 +1867,7 @@ otp_5640(doc) ->
["OTP-5640. 'allow' multiple names for registered processes."];
otp_5640(Config) when is_list(Config) ->
Timeout = 25,
- ?line Dog = test_server:timetrap(test_server:seconds(Timeout)),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
init_condition(Config),
?line {ok, B} = start_node(b, Config),
@@ -1965,7 +1925,6 @@ otp_5640(Config) when is_list(Config) ->
write_high_level_trace(Config),
stop_node(B),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
otp_5640_proc(_Parent) ->
@@ -1979,7 +1938,7 @@ otp_5737(doc) ->
["OTP-5737. set_lock/3 and trans/4 accept Retries = 0."];
otp_5737(Config) when is_list(Config) ->
Timeout = 25,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
@@ -2000,7 +1959,6 @@ otp_5737(Config) when is_list(Config) ->
write_high_level_trace(Config),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
otp_6931(suite) -> [];
@@ -2025,7 +1983,7 @@ simple_disconnect(suite) -> [];
simple_disconnect(doc) -> ["OTP-5563. Disconnected nodes (not partitions)"];
simple_disconnect(Config) when is_list(Config) ->
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -2075,7 +2033,6 @@ simple_disconnect(Config) when is_list(Config) ->
write_high_level_trace(Config),
stop_nodes(Cps),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
%% Not used right now.
@@ -2118,7 +2075,7 @@ simple_resolve(suite) -> [];
simple_resolve(doc) -> ["OTP-5563. Partitions and names."];
simple_resolve(Config) when is_list(Config) ->
Timeout = 360,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -2245,7 +2202,6 @@ simple_resolve(Config) when is_list(Config) ->
write_high_level_trace(Config),
stop_nodes(Cps),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
simple_resolve2(suite) -> [];
@@ -2255,7 +2211,7 @@ simple_resolve2(Config) when is_list(Config) ->
%% always work to re-start z_2. "Cannot be a global bug."
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -2283,7 +2239,6 @@ simple_resolve2(Config) when is_list(Config) ->
write_high_level_trace(Config),
stop_nodes(Cps), % Not all nodes may be present, but it works anyway.
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
simple_resolve3(suite) -> [];
@@ -2292,7 +2247,7 @@ simple_resolve3(Config) when is_list(Config) ->
%% Continuation of simple_resolve.
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -2320,7 +2275,6 @@ simple_resolve3(Config) when is_list(Config) ->
write_high_level_trace(Config),
stop_nodes(Cps), % Not all nodes may be present, but it works anyway.
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
res({Res,Resolver}, [N1, A2, Z2], Cf) ->
@@ -2504,7 +2458,7 @@ leftover_name(suite) -> [];
leftover_name(doc) -> ["OTP-5563. Bug: nodedown while synching."];
leftover_name(Config) when is_list(Config) ->
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -2565,7 +2519,6 @@ leftover_name(Config) when is_list(Config) ->
write_high_level_trace(Config),
stop_nodes(Cps),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
%% Runs on n_1
@@ -2604,7 +2557,7 @@ re_register_name(Config) when is_list(Config) ->
%% occupied by links, that's all.
%% Later: now monitors are checked.
Timeout = 15,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
Me = self(),
@@ -2618,7 +2571,6 @@ re_register_name(Config) when is_list(Config) ->
receive {Pid2, MonitoredBy2} -> [_] = MonitoredBy2 end,
?line _ = global:unregister_name(name),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
proc(Parent) ->
@@ -2652,7 +2604,7 @@ do_name_exit(StartFun, Version, Config) ->
%% The current release uses monitors so this test is not so relevant.
Timeout = 60,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -2692,7 +2644,6 @@ do_name_exit(StartFun, Version, Config) ->
write_high_level_trace(Config),
stop_nodes(Cps),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
long_lock(Parent) ->
@@ -2709,7 +2660,7 @@ external_nodes(suite) -> [];
external_nodes(doc) -> ["OTP-5563. External nodes (cnodes)."];
external_nodes(Config) when is_list(Config) ->
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -2793,7 +2744,6 @@ external_nodes(Config) when is_list(Config) ->
?line ?UNTIL(length(get_ext_names()) =:= 0),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
get_ext_names() ->
@@ -2845,8 +2795,8 @@ many_nodes(suite) ->
many_nodes(doc) ->
["OTP-5770. Start many nodes. Make them connect at the same time."];
many_nodes(Config) when is_list(Config) ->
- Timeout = 180,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ Timeout = 240,
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -2902,7 +2852,6 @@ many_nodes(Config) when is_list(Config) ->
write_high_level_trace(Config),
?line stop_nodes(Cps),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
Diff = Time2 - Time,
Return = lists:flatten(io_lib:format("~w nodes took ~w ms",
[N_cps, Diff])),
@@ -2988,7 +2937,7 @@ sync_0(doc) ->
["OTP-5770. sync/0."];
sync_0(Config) when is_list(Config) ->
Timeout = 180,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
@@ -3013,7 +2962,6 @@ sync_0(Config) when is_list(Config) ->
stop_nodes(Cps),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
start_and_sync([]) ->
@@ -3031,7 +2979,7 @@ global_groups_change(suite) -> [];
global_groups_change(doc) -> ["Test change of global_groups parameter."];
global_groups_change(Config) ->
Timeout = 90,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line M = from($@, atom_to_list(node())),
@@ -3376,7 +3324,6 @@ global_groups_change(Config) ->
stop_node(CpE),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
sync_and_wait(Node) ->
@@ -3855,7 +3802,7 @@ start_node_rel(Name0, Rel, Config) ->
Name = node_name(Name0, Config),
{Release, Compat} = case Rel of
this ->
- {[this], "+R8"};
+ {[this], ""};
Rel when is_atom(Rel) ->
{[{release, atom_to_list(Rel)}], ""};
RelList ->
@@ -3919,7 +3866,7 @@ global_lost_nodes(doc) ->
["Tests that locally loaded nodes do not loose contact with other nodes."];
global_lost_nodes(Config) when is_list(Config) ->
Timeout = 60,
- Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
@@ -3943,7 +3890,6 @@ global_lost_nodes(Config) when is_list(Config) ->
?line stop_node(Node1),
?line stop_node(Node2),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
global_load(MyName, OtherNode, OtherName) ->
@@ -3994,7 +3940,7 @@ mass_death(doc) ->
["Tests the simultaneous death of many processes with registered names"];
mass_death(Config) when is_list(Config) ->
Timeout = 90,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -4023,9 +3969,9 @@ mass_death(Config) when is_list(Config) ->
{H,M,S} = time(),
io:format("Started probing: ~.4.0w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w~n",
[YYYY,MM,DD,H,M,S]),
- wait_mass_death(Dog, Nodes, OrigNames, erlang:now(), Config).
+ wait_mass_death(Nodes, OrigNames, erlang:now(), Config).
-wait_mass_death(Dog, Nodes, OrigNames, Then, Config) ->
+wait_mass_death(Nodes, OrigNames, Then, Config) ->
?line Names = global:registered_names(),
?line
case Names--OrigNames of
@@ -4036,12 +3982,11 @@ wait_mass_death(Dog, Nodes, OrigNames, Then, Config) ->
stop_node(Node)
end, Nodes),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
{comment,lists:flatten(io_lib:format("~.3f s~n", [T/1000.0]))};
Ndiff ->
?line io:format("Ndiff: ~p~n", [Ndiff]),
?line test_server:sleep(1000),
- ?line wait_mass_death(Dog, Nodes, OrigNames, Then, Config)
+ ?line wait_mass_death(Nodes, OrigNames, Then, Config)
end.
mass_spawn([]) ->
@@ -4190,7 +4135,7 @@ init_condition(Config) ->
{"Global Locks (ETS)", global_locks},
{"Global Pid Names (ETS)", global_pid_names},
{"Global Pid Ids (ETS)", global_pid_ids}]],
- ?UNTIL([test_server] =:= global:registered_names()),
+ ?UNTIL([] =:= global:registered_names()),
?UNTIL([] =:= nodes()),
?UNTIL([node()] =:= get_known(node())),
ok.
@@ -4213,7 +4158,7 @@ garbage_messages(suite) ->
[];
garbage_messages(Config) when is_list(Config) ->
Timeout = 25,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line [Slave] = start_nodes([garbage_messages], slave, Config),
@@ -4233,7 +4178,6 @@ garbage_messages(Config) when is_list(Config) ->
write_high_level_trace(Config),
?line stop_node(Slave),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
wait_for_ready_net(Config) ->
diff --git a/lib/kernel/test/heart_SUITE.erl b/lib/kernel/test/heart_SUITE.erl
index 31005a01e2..320b23bea1 100644
--- a/lib/kernel/test/heart_SUITE.erl
+++ b/lib/kernel/test/heart_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -22,7 +22,10 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2, start/1, restart/1,
- reboot/1, set_cmd/1, clear_cmd/1, get_cmd/1,
+ reboot/1,
+ node_start_immediately_after_crash/1,
+ node_start_soon_after_crash/1,
+ set_cmd/1, clear_cmd/1, get_cmd/1,
dont_drop/1, kill_pid/1]).
-export([init_per_testcase/2, end_per_testcase/2]).
@@ -38,15 +41,15 @@ init_per_testcase(_Func, Config) ->
end_per_testcase(_Func, Config) ->
Nodes = nodes(),
lists:foreach(fun(X) ->
- NNam = list_to_atom(hd(string:tokens(atom_to_list(X),"@"))),
- case NNam of
- heart_test ->
- ?t:format(1, "WARNING: Killed ~p~n", [X]),
- rpc:cast(X, erlang, halt, []);
- _ ->
- ok
- end
- end, Nodes),
+ NNam = list_to_atom(hd(string:tokens(atom_to_list(X),"@"))),
+ case NNam of
+ heart_test ->
+ ?t:format(1, "WARNING: Killed ~p~n", [X]),
+ rpc:cast(X, erlang, halt, []);
+ _ ->
+ ok
+ end
+ end, Nodes),
Dog=?config(watchdog, Config),
test_server:timetrap_cancel(Dog).
@@ -57,8 +60,13 @@ end_per_testcase(_Func, Config) ->
%%-----------------------------------------------------------------
suite() -> [{ct_hooks,[ts_install_cth]}].
-all() ->
- [start, restart, reboot, set_cmd, clear_cmd, get_cmd, kill_pid].
+all() -> [
+ start, restart, reboot,
+ node_start_immediately_after_crash,
+ node_start_soon_after_crash,
+ set_cmd, clear_cmd, get_cmd,
+ kill_pid
+ ].
groups() ->
[].
@@ -75,22 +83,27 @@ init_per_suite(Config) when is_list(Config) ->
{win32, windows} ->
{skipped, "No use to run on Windows 95/98"};
_ ->
- Config
+ ignore_cores:init(Config)
end.
end_per_suite(Config) when is_list(Config) ->
- Config.
+ ignore_cores:fini(Config).
+
start_check(Type, Name) ->
+ start_check(Type, Name, []).
+start_check(Type, Name, Envs) ->
Args = case ?t:os_type() of
- {win32,_} -> "-heart -env HEART_COMMAND no_reboot";
- _ -> "-heart"
- end,
+ {win32,_} ->
+ "-heart " ++ env_encode([{"HEART_COMMAND", no_reboot}|Envs]);
+ _ ->
+ "-heart " ++ env_encode(Envs)
+ end,
{ok, Node} = case Type of
- loose ->
- loose_node:start(Name, Args, ?DEFAULT_TIMEOUT_SECS);
- _ ->
- ?t:start_node(Name, Type, [{args, Args}])
- end,
+ loose ->
+ loose_node:start(Name, Args, ?DEFAULT_TIMEOUT_SECS);
+ _ ->
+ ?t:start_node(Name, Type, [{args, Args}])
+ end,
erlang:monitor_node(Node, true),
case rpc:call(Node, erlang, whereis, [heart]) of
Pid when is_pid(Pid) ->
@@ -103,21 +116,19 @@ start_check(Type, Name) ->
start(doc) -> [];
start(suite) -> {req, [{time, 10}]};
start(Config) when is_list(Config) ->
- ?line {ok, Node} = start_check(slave, heart_test),
- ?line rpc:call(Node, init, reboot, []),
+ {ok, Node} = start_check(slave, heart_test),
+ rpc:call(Node, init, reboot, []),
receive
- {nodedown, Node} ->
- ok
- after 2000 ->
- test_server:fail(node_not_closed)
+ {nodedown, Node} -> ok
+ after 2000 -> test_server:fail(node_not_closed)
end,
test_server:sleep(5000),
- ?line case net_adm:ping(Node) of
- pang ->
- ok;
- _ ->
- test_server:fail(node_rebooted)
- end,
+ case net_adm:ping(Node) of
+ pang ->
+ ok;
+ _ ->
+ test_server:fail(node_rebooted)
+ end,
test_server:stop_node(Node).
%% Also test fixed bug in R1B (it was not possible to
@@ -125,6 +136,10 @@ start(Config) when is_list(Config) ->
%% Slave executes erlang:halt() on master nodedown.
%% Therefore the slave process has to be killed
%% before restart.
+
+%% restart
+%% Purpose:
+%% Check that a node is up and running after a init:restart/0
restart(doc) -> [];
restart(suite) ->
case ?t:os_type() of
@@ -134,8 +149,8 @@ restart(suite) ->
{skip, "Only run on unix and win32"}
end;
restart(Config) when is_list(Config) ->
- ?line {ok, Node} = start_check(loose, heart_test),
- ?line rpc:call(Node, init, restart, []),
+ {ok, Node} = start_check(loose, heart_test),
+ rpc:call(Node, init, restart, []),
receive
{nodedown, Node} ->
ok
@@ -143,32 +158,21 @@ restart(Config) when is_list(Config) ->
test_server:fail(node_not_closed)
end,
test_server:sleep(5000),
-
- ?line case net_adm:ping(Node) of
- pong ->
- erlang:monitor_node(Node, true),
- ?line rpc:call(Node, init, stop, []),
- receive
- {nodedown, Node} ->
- ok
- after 2000 ->
- test_server:fail(node_not_closed2)
- end,
- ok;
- _ ->
- test_server:fail(node_not_restarted)
- end,
+ node_check_up_down(Node, 2000),
loose_node:stop(Node).
+%% reboot
+%% Purpose:
+%% Check that a node is up and running after a init:reboot/0
reboot(doc) -> [];
reboot(suite) -> {req, [{time, 10}]};
reboot(Config) when is_list(Config) ->
{ok, Node} = start_check(slave, heart_test),
- ?line ok = rpc:call(Node, heart, set_cmd,
+ ok = rpc:call(Node, heart, set_cmd,
[atom_to_list(lib:progname()) ++
" -noshell -heart " ++ name(Node) ++ "&"]),
- ?line rpc:call(Node, init, reboot, []),
+ rpc:call(Node, init, reboot, []),
receive
{nodedown, Node} ->
ok
@@ -176,44 +180,142 @@ reboot(Config) when is_list(Config) ->
test_server:fail(node_not_closed)
end,
test_server:sleep(5000),
- ?line case net_adm:ping(Node) of
- pong ->
- erlang:monitor_node(Node, true),
- ?line rpc:call(Node, init, reboot, []),
- receive
- {nodedown, Node} ->
- ok
- after 2000 ->
- test_server:fail(node_not_closed2)
- end,
- ok;
- _ ->
- test_server:fail(node_not_rebooted)
- end,
+ node_check_up_down(Node, 2000),
ok.
+%% node_start_immediately_after_crash
+%% Purpose:
+%% Check that a node is up and running after a crash.
+%% This test exhausts the atom table on the remote node.
+%% ERL_CRASH_DUMP_SECONDS=0 will force beam not to dump an erl_crash.dump.
+%% May currently dump core in beam debug build due to lock-order violation
+%% This should be removed when a non-lockad information retriever is implemented
+%% for crash dumps
+node_start_immediately_after_crash(suite) -> {req, [{time, 10}]};
+node_start_immediately_after_crash(Config) when is_list(Config) ->
+ Config2 = ignore_cores:setup(?MODULE, node_start_immediately_after_crash, Config, true),
+ try
+ node_start_immediately_after_crash_test(Config2)
+ after
+ ignore_cores:restore(Config2)
+ end.
+
+
+node_start_immediately_after_crash_test(Config) when is_list(Config) ->
+ {ok, Node} = start_check(loose, heart_test_imm, [{"ERL_CRASH_DUMP_SECONDS", "0"}]),
+
+ ok = rpc:call(Node, heart, set_cmd,
+ [atom_to_list(lib:progname()) ++
+ " -noshell -heart " ++ name(Node) ++ "&"]),
+
+ Mod = exhaust_atoms,
+
+ Code = generate(Mod, [], [
+ "do() -> "
+ " Set = lists:seq($a,$z), "
+ " [ list_to_atom([A,B,C,D,E]) || "
+ " A <- Set, B <- Set, C <- Set, E <- Set, D <- Set ]."
+ ]),
+
+ %% crash it with atom exhaustion
+ rpc:call(Node, erlang, load_module, [Mod, Code]),
+ rpc:cast(Node, Mod, do, []),
+
+ T0 = now(),
+
+ receive {nodedown, Node} ->
+ test_server:format("Took ~.2f s. for node to go down~n", [timer:now_diff(now(), T0)/1000000]),
+ ok
+ %% timeout is very liberal here. nodedown is received in about 1 s. on linux (palantir)
+ %% and in about 10 s. on solaris (carcharoth)
+ after (15000*test_server:timetrap_scale_factor()) -> test_server:fail(node_not_closed)
+ end,
+ test_server:sleep(3000),
+ node_check_up_down(Node, 2000),
+ loose_node:stop(Node).
+
+%% node_start_soon_after_crash
+%% Purpose:
+%% Check that a node is up and running after a crash.
+%% This test exhausts the atom table on the remote node.
+%% ERL_CRASH_DUMP_SECONDS=10 will force beam
+%% to only dump an erl_crash.dump for 10 seconds.
+%% May currently dump core in beam debug build due to lock-order violation
+%% This should be removed when a non-lockad information retriever is implemented
+%% for crash dumps
+node_start_soon_after_crash(suite) -> {req, [{time, 10}]};
+node_start_soon_after_crash(Config) when is_list(Config) ->
+ Config2 = ignore_cores:setup(?MODULE, node_start_soon_after_crash, Config, true),
+ try
+ node_start_soon_after_crash_test(Config2)
+ after
+ ignore_cores:restore(Config2)
+ end.
+
+node_start_soon_after_crash_test(Config) when is_list(Config) ->
+ {ok, Node} = start_check(loose, heart_test_soon, [{"ERL_CRASH_DUMP_SECONDS", "10"}]),
+
+ ok = rpc:call(Node, heart, set_cmd,
+ [atom_to_list(lib:progname()) ++
+ " -noshell -heart " ++ name(Node) ++ "&"]),
+
+ Mod = exhaust_atoms,
+
+ Code = generate(Mod, [], [
+ "do() -> "
+ " Set = lists:seq($a,$z), "
+ " [ list_to_atom([A,B,C,D,E]) || "
+ " A <- Set, B <- Set, C <- Set, E <- Set, D <- Set ]."
+ ]),
+
+ %% crash it with atom exhaustion
+ rpc:call(Node, erlang, load_module, [Mod, Code]),
+ rpc:cast(Node, Mod, do, []),
+
+ receive {nodedown, Node} -> ok
+ after (15000*test_server:timetrap_scale_factor()) -> test_server:fail(node_not_closed)
+ end,
+ test_server:sleep(20000),
+ node_check_up_down(Node, 15000),
+ loose_node:stop(Node).
+
+
+node_check_up_down(Node, Tmo) ->
+ case net_adm:ping(Node) of
+ pong ->
+ erlang:monitor_node(Node, true),
+ rpc:call(Node, init, reboot, []),
+ receive
+ {nodedown, Node} -> ok
+ after Tmo ->
+ test_server:fail(node_not_closed2)
+ end;
+ _ ->
+ test_server:fail(node_not_rebooted)
+ end.
+
%% Only tests bad command, correct behaviour is tested in reboot/1.
set_cmd(suite) -> [];
set_cmd(Config) when is_list(Config) ->
- ?line {ok, Node} = start_check(slave, heart_test),
+ {ok, Node} = start_check(slave, heart_test),
Cmd = wrong_atom,
- ?line {error, {bad_cmd, Cmd}} = rpc:call(Node, heart, set_cmd, [Cmd]),
+ {error, {bad_cmd, Cmd}} = rpc:call(Node, heart, set_cmd, [Cmd]),
Cmd1 = lists:duplicate(2047, $a),
- ?line {error, {bad_cmd, Cmd1}} = rpc:call(Node, heart, set_cmd, [Cmd1]),
+ {error, {bad_cmd, Cmd1}} = rpc:call(Node, heart, set_cmd, [Cmd1]),
Cmd2 = lists:duplicate(28, $a),
- ?line ok = rpc:call(Node, heart, set_cmd, [Cmd2]),
+ ok = rpc:call(Node, heart, set_cmd, [Cmd2]),
Cmd3 = lists:duplicate(2000, $a),
- ?line ok = rpc:call(Node, heart, set_cmd, [Cmd3]),
+ ok = rpc:call(Node, heart, set_cmd, [Cmd3]),
stop_node(Node),
ok.
clear_cmd(suite) -> {req,[{time,15}]};
clear_cmd(Config) when is_list(Config) ->
- ?line {ok, Node} = start_check(slave, heart_test),
- ?line ok = rpc:call(Node, heart, set_cmd,
+ {ok, Node} = start_check(slave, heart_test),
+ ok = rpc:call(Node, heart, set_cmd,
[atom_to_list(lib:progname()) ++
" -noshell -heart " ++ name(Node) ++ "&"]),
- ?line rpc:call(Node, init, reboot, []),
+ rpc:call(Node, init, reboot, []),
receive
{nodedown, Node} ->
ok
@@ -221,16 +323,16 @@ clear_cmd(Config) when is_list(Config) ->
test_server:fail(node_not_closed)
end,
test_server:sleep(5000),
- ?line case net_adm:ping(Node) of
- pong ->
- erlang:monitor_node(Node, true);
- _ ->
- test_server:fail(node_not_rebooted)
- end,
- ?line ok = rpc:call(Node, heart, set_cmd,
+ case net_adm:ping(Node) of
+ pong ->
+ erlang:monitor_node(Node, true);
+ _ ->
+ test_server:fail(node_not_rebooted)
+ end,
+ ok = rpc:call(Node, heart, set_cmd,
["erl -noshell -heart " ++ name(Node) ++ "&"]),
- ?line ok = rpc:call(Node, heart, clear_cmd, []),
- ?line rpc:call(Node, init, reboot, []),
+ ok = rpc:call(Node, heart, clear_cmd, []),
+ rpc:call(Node, init, reboot, []),
receive
{nodedown, Node} ->
ok
@@ -238,20 +340,20 @@ clear_cmd(Config) when is_list(Config) ->
test_server:fail(node_not_closed)
end,
test_server:sleep(5000),
- ?line case net_adm:ping(Node) of
- pang ->
- ok;
- _ ->
- test_server:fail(node_rebooted)
- end,
+ case net_adm:ping(Node) of
+ pang ->
+ ok;
+ _ ->
+ test_server:fail(node_rebooted)
+ end,
ok.
get_cmd(suite) -> [];
get_cmd(Config) when is_list(Config) ->
- ?line {ok, Node} = start_check(slave, heart_test),
+ {ok, Node} = start_check(slave, heart_test),
Cmd = "test",
- ?line ok = rpc:call(Node, heart, set_cmd, [Cmd]),
- ?line {ok, Cmd} = rpc:call(Node, heart, get_cmd, []),
+ ok = rpc:call(Node, heart, set_cmd, [Cmd]),
+ {ok, Cmd} = rpc:call(Node, heart, get_cmd, []),
stop_node(Node),
ok.
@@ -269,57 +371,53 @@ dont_drop(Config) when is_list(Config) ->
[ok,ok,ok,ok,ok,ok,ok,ok,ok,ok] = do_dont_drop(Config,10),
ok.
-do_dont_drop(_,0) ->
- [];
+do_dont_drop(_,0) -> [];
do_dont_drop(Config,N) ->
%% Name of first slave node
- ?line NN1 = atom_to_list(?MODULE) ++ "slave_1",
+ NN1 = atom_to_list(?MODULE) ++ "slave_1",
%% Name of node started by heart on failure
- ?line NN2 = atom_to_list(?MODULE) ++ "slave_2",
+ NN2 = atom_to_list(?MODULE) ++ "slave_2",
%% Name of node started by heart on success
- ?line NN3 = atom_to_list(?MODULE) ++ "slave_3",
- ?line Host = hd(tl(string:tokens(atom_to_list(node()),"@"))),
+ NN3 = atom_to_list(?MODULE) ++ "slave_3",
+ Host = hd(tl(string:tokens(atom_to_list(node()),"@"))),
%% The initial heart command
- ?line FirstCmd = erl() ++ name(NN2 ++ "@" ++ Host),
+ FirstCmd = erl() ++ name(NN2 ++ "@" ++ Host),
%% Separated the parameters to start_node_run for clarity...
- ?line Name = list_to_atom(NN1),
- ?line Env = [{"HEART_COMMAND", FirstCmd}],
- ?line Func = "start_heart_stress",
- ?line Arg = NN3 ++ "@" ++ Host ++ " " ++
+ Name = list_to_atom(NN1),
+ Env = [{"HEART_COMMAND", FirstCmd}],
+ Func = "start_heart_stress",
+ Arg = NN3 ++ "@" ++ Host ++ " " ++
filename:join(?config(data_dir, Config), "simple_echo"),
- ?line start_node_run(Name,Env,Func,Arg),
- ?line case wait_for_any_of(list_to_atom(NN2 ++ "@" ++ Host),
- list_to_atom(NN3 ++ "@" ++ Host)) of
- 2 ->
- ?line [ok | do_dont_drop(Config,N-1)];
- _ ->
- ?line false
- end.
+ start_node_run(Name,Env,Func,Arg),
+ case wait_for_any_of(list_to_atom(NN2 ++ "@" ++ Host),
+ list_to_atom(NN3 ++ "@" ++ Host)) of
+ 2 ->
+ [ok | do_dont_drop(Config,N-1)];
+ _ ->
+ false
+ end.
wait_for_any_of(N1,N2) ->
- ?line wait_for_any_of(N1,N2,45).
+ wait_for_any_of(N1,N2,45).
wait_for_any_of(_N1,_N2,0) ->
- ?line false;
+ false;
wait_for_any_of(N1,N2,Times) ->
- ?line receive
- after 1000 ->
- ?line ok
- end,
- ?line case net_adm:ping(N1) of
- pang ->
- ?line case net_adm:ping(N2) of
- pang ->
- ?line wait_for_any_of(N1,N2,Times - 1);
- pong ->
- ?line rpc:call(N2,init,stop,[]),
- ?line 2
- end;
- pong ->
- ?line rpc:call(N1,init,stop,[]),
- ?line 1
- end.
+ receive after 1000 -> ok end,
+ case net_adm:ping(N1) of
+ pang ->
+ case net_adm:ping(N2) of
+ pang ->
+ wait_for_any_of(N1,N2,Times - 1);
+ pong ->
+ rpc:call(N2,init,stop,[]),
+ 2
+ end;
+ pong ->
+ rpc:call(N1,init,stop,[]),
+ 1
+ end.
kill_pid(suite) ->
@@ -336,9 +434,7 @@ do_kill_pid(_Config) ->
{ok,Node} = start_node_run(Name,Env,suicide_by_heart,[]),
ok = wait_for_node(Node,15),
erlang:monitor_node(Node, true),
- receive
- {nodedown,Node} ->
- ok
+ receive {nodedown,Node} -> ok
after 30000 ->
false
end.
@@ -346,23 +442,16 @@ do_kill_pid(_Config) ->
wait_for_node(_,0) ->
false;
wait_for_node(Node,N) ->
- receive
- after 1000 ->
- ok
- end,
+ receive after 1000 -> ok end,
case net_adm:ping(Node) of
- pong ->
- ok;
- pang ->
- wait_for_node(Node,N-1)
+ pong -> ok;
+ pang -> wait_for_node(Node,N-1)
end.
erl() ->
case os:type() of
- {win32,_} ->
- "werl ";
- _ ->
- "erl "
+ {win32,_} -> "werl ";
+ _ -> "erl "
end.
name(Node) when is_list(Node) -> name(Node,[]);
@@ -379,15 +468,13 @@ name([H|T], Name) ->
name(T, [H|Name]).
-atom_conv(A) when is_atom(A) ->
- atom_to_list(A);
-atom_conv(A) when is_list(A) ->
- A.
+enc(A) when is_atom(A) -> atom_to_list(A);
+enc(A) when is_binary(A) -> binary_to_list(A);
+enc(A) when is_list(A) -> A.
-env_conv([]) ->
- [];
-env_conv([{X,Y}|T]) ->
- atom_conv(X) ++ " \"" ++ atom_conv(Y) ++ "\" " ++ env_conv(T).
+env_encode([]) -> [];
+env_encode([{X,Y}|T]) ->
+ "-env " ++ enc(X) ++ " \"" ++ enc(Y) ++ "\" " ++ env_encode(T).
%%%
%%% Starts a node and runs a function in this
@@ -398,12 +485,12 @@ env_conv([{X,Y}|T]) ->
%%% Argument is the argument(s) to send through erl -s
%%%
start_node_run(Name, Env, Function, Argument) ->
- ?line PA = filename:dirname(code:which(?MODULE)),
- ?line Params = "-heart -env " ++ env_conv(Env) ++ " -pa " ++ PA ++
- " -s " ++
- atom_conv(?MODULE) ++ " " ++ atom_conv(Function) ++ " " ++
- atom_conv(Argument),
- ?line start_node(Name, Params).
+ PA = filename:dirname(code:which(?MODULE)),
+ Params = "-heart " ++ env_encode(Env) ++ " -pa " ++ PA ++
+ " -s " ++
+ enc(?MODULE) ++ " " ++ enc(Function) ++ " " ++
+ enc(Argument),
+ start_node(Name, Params).
start_node(Name, Param) ->
test_server:start_node(Name, slave, [{args, Param}]).
@@ -469,3 +556,24 @@ suicide_by_heart() ->
{makaronipudding} ->
sallad
end.
+
+
+%% generate a module from binary
+generate(Module, Attributes, FunStrings) ->
+ FunForms = function_forms(FunStrings),
+ Forms = [
+ {attribute,1,module,Module},
+ {attribute,2,export,[FA || {FA,_} <- FunForms]}
+ ] ++ [{attribute, 3, A, V}|| {A, V} <- Attributes] ++
+ [ Function || {_, Function} <- FunForms],
+ {ok, Module, Bin} = compile:forms(Forms),
+ Bin.
+
+
+function_forms([]) -> [];
+function_forms([S|Ss]) ->
+ {ok, Ts,_} = erl_scan:string(S),
+ {ok, Form} = erl_parse:parse_form(Ts),
+ Fun = element(3, Form),
+ Arity = element(4, Form),
+ [{{Fun,Arity}, Form}|function_forms(Ss)].
diff --git a/lib/kernel/test/ignore_cores.erl b/lib/kernel/test/ignore_cores.erl
new file mode 100644
index 0000000000..8b1ac0fe6c
--- /dev/null
+++ b/lib/kernel/test/ignore_cores.erl
@@ -0,0 +1,158 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%%-------------------------------------------------------------------
+%%% File : ignore_cores.erl
+%%% Author : Rickard Green <[email protected]>
+%%% Description :
+%%%
+%%% Created : 11 Feb 2008 by Rickard Green <[email protected]>
+%%%-------------------------------------------------------------------
+
+-module(ignore_cores).
+
+-include_lib("test_server/include/test_server.hrl").
+
+-export([init/1, fini/1, setup/3, setup/4, restore/1, dir/1]).
+
+-record(ignore_cores, {org_cwd,
+ org_path,
+ org_pwd_env,
+ ign_dir = false,
+ cores_dir = false}).
+
+%%
+%% Takes a testcase config
+%%
+
+init(Config) ->
+ {ok, OrgCWD} = file:get_cwd(),
+ [{ignore_cores,
+ #ignore_cores{org_cwd = OrgCWD,
+ org_path = code:get_path(),
+ org_pwd_env = os:getenv("PWD")}}
+ | lists:keydelete(ignore_cores, 1, Config)].
+
+fini(Config) ->
+ #ignore_cores{org_cwd = OrgCWD,
+ org_path = OrgPath,
+ org_pwd_env = OrgPWD} = ?config(ignore_cores, Config),
+ ok = file:set_cwd(OrgCWD),
+ true = code:set_path(OrgPath),
+ case OrgPWD of
+ false -> ok;
+ _ -> true = os:putenv("PWD", OrgPWD)
+ end,
+ lists:keydelete(ignore_cores, 1, Config).
+
+setup(Suite, Testcase, Config) ->
+ setup(Suite, Testcase, Config, false).
+
+setup(Suite, Testcase, Config, SetCwd) when is_atom(Suite),
+ is_atom(Testcase),
+ is_list(Config) ->
+ #ignore_cores{org_cwd = OrgCWD,
+ org_path = OrgPath,
+ org_pwd_env = OrgPWD} = ?config(ignore_cores, Config),
+ Path = lists:map(fun (".") -> OrgCWD; (Dir) -> Dir end, OrgPath),
+ true = code:set_path(Path),
+ PrivDir = ?config(priv_dir, Config),
+ IgnDir = filename:join([PrivDir,
+ atom_to_list(Suite)
+ ++ "_"
+ ++ atom_to_list(Testcase)
+ ++ "_wd"]),
+ ok = file:make_dir(IgnDir),
+ case SetCwd of
+ false ->
+ ok;
+ _ ->
+ ok = file:set_cwd(IgnDir),
+ OrgPWD = case os:getenv("PWD") of
+ false -> false;
+ PWD ->
+ os:putenv("PWD", IgnDir),
+ PWD
+ end
+ end,
+ ok = file:write_file(filename:join([IgnDir, "ignore_core_files"]), <<>>),
+ %% cores are dumped in /cores on MacOS X
+ CoresDir = case {?t:os_type(), filelib:is_dir("/cores")} of
+ {{unix,darwin}, true} ->
+ filelib:fold_files("/cores",
+ "^core.*$",
+ false,
+ fun (C,Cs) -> [C|Cs] end,
+ []);
+ _ ->
+ false
+ end,
+ lists:keyreplace(ignore_cores,
+ 1,
+ Config,
+ {ignore_cores,
+ #ignore_cores{org_cwd = OrgCWD,
+ org_path = OrgPath,
+ org_pwd_env = OrgPWD,
+ ign_dir = IgnDir,
+ cores_dir = CoresDir}}).
+
+restore(Config) ->
+ #ignore_cores{org_cwd = OrgCWD,
+ org_path = OrgPath,
+ org_pwd_env = OrgPWD,
+ ign_dir = IgnDir,
+ cores_dir = CoresDir} = ?config(ignore_cores, Config),
+ try
+ case CoresDir of
+ false ->
+ ok;
+ _ ->
+ %% Move cores dumped by these testcases in /cores
+ %% to cwd.
+ lists:foreach(fun (C) ->
+ case lists:member(C, CoresDir) of
+ true -> ok;
+ _ ->
+ Dst = filename:join(
+ [IgnDir,
+ filename:basename(C)]),
+ {ok, _} = file:copy(C, Dst),
+ file:delete(C)
+ end
+ end,
+ filelib:fold_files("/cores",
+ "^core.*$",
+ false,
+ fun (C,Cs) -> [C|Cs] end,
+ []))
+ end
+ after
+ catch file:set_cwd(OrgCWD),
+ catch code:set_path(OrgPath),
+ case OrgPWD of
+ false -> ok;
+ _ -> catch os:putenv("PWD", OrgPWD)
+ end
+ end.
+
+
+dir(Config) ->
+ #ignore_cores{ign_dir = Dir} = ?config(ignore_cores, Config),
+ Dir.
diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl
index ce138b6804..e5e1794514 100644
--- a/lib/kernel/test/inet_SUITE.erl
+++ b/lib/kernel/test/inet_SUITE.erl
@@ -37,7 +37,8 @@
gethostnative_soft_restart/0, gethostnative_soft_restart/1,
gethostnative_debug_level/0, gethostnative_debug_level/1,
getif/1,
- getif_ifr_name_overflow/1,getservbyname_overflow/1, getifaddrs/1]).
+ getif_ifr_name_overflow/1,getservbyname_overflow/1, getifaddrs/1,
+ parse_strict_address/1]).
-export([get_hosts/1, get_ipv6_hosts/1, parse_hosts/1, parse_address/1,
kill_gethost/0, parallell_gethost/0]).
@@ -52,7 +53,7 @@ all() ->
t_gethostnative, gethostnative_parallell, cname_loop,
gethostnative_debug_level, gethostnative_soft_restart,
getif, getif_ifr_name_overflow, getservbyname_overflow,
- getifaddrs].
+ getifaddrs, parse_strict_address].
groups() ->
[{parse, [], [parse_hosts, parse_address]}].
@@ -582,16 +583,16 @@ parse_address(Config) when is_list(Config) ->
"fe80::198.168.0.",
"fec0::fFfF:127.0.0.1."],
t_parse_address
- (ipv6_address,
+ (parse_ipv6_address,
V6Strict++V6Sloppy++V6Err++V4Err),
t_parse_address
- (ipv6strict_address,
+ (parse_ipv6strict_address,
V6Strict++V6Err++V4Err++[S || {_,S} <- V6Sloppy]),
t_parse_address
- (ipv4_address,
+ (parse_ipv4_address,
V4Strict++V4Sloppy++V4Err++V6Err++[S || {_,S} <- V6Strict]),
t_parse_address
- (ipv4strict_address,
+ (parse_ipv4strict_address,
V4Strict++V4Err++V6Err++[S || {_,S} <- V4Sloppy++V6Strict]).
t_parse_address(Func, []) ->
@@ -599,14 +600,16 @@ t_parse_address(Func, []) ->
ok;
t_parse_address(Func, [{Addr,String}|L]) ->
io:format("~p = ~p.~n", [Addr,String]),
- {ok,Addr} = inet_parse:Func(String),
+ {ok,Addr} = inet:Func(String),
t_parse_address(Func, L);
t_parse_address(Func, [String|L]) ->
io:format("~p.~n", [String]),
- {error,einval} = inet_parse:Func(String),
+ {error,einval} = inet:Func(String),
t_parse_address(Func, L).
-
+parse_strict_address(Config) when is_list(Config) ->
+ {ok, Ipv4} = inet:parse_strict_address("127.0.0.1"),
+ {ok, Ipv6} = inet:parse_strict_address("c11:0c22:5c33:c440:55c0:c66c:77:0088").
t_gethostnative(suite) ->[];
t_gethostnative(doc) ->[];
diff --git a/lib/kernel/test/inet_sockopt_SUITE.erl b/lib/kernel/test/inet_sockopt_SUITE.erl
index 087ae6055b..75496ce745 100644
--- a/lib/kernel/test/inet_sockopt_SUITE.erl
+++ b/lib/kernel/test/inet_sockopt_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -53,6 +53,8 @@
simple/1, loop_all/1, simple_raw/1, simple_raw_getbin/1,
doc_examples_raw/1,doc_examples_raw_getbin/1,
large_raw/1,large_raw_getbin/1,combined/1,combined_getbin/1,
+ ipv6_v6only_udp/1, ipv6_v6only_tcp/1, ipv6_v6only_sctp/1,
+ use_ipv6_v6only_udp/1,
type_errors/1]).
-export([init_per_testcase/2, end_per_testcase/2]).
@@ -64,6 +66,8 @@ all() ->
[simple, loop_all, simple_raw, simple_raw_getbin,
doc_examples_raw, doc_examples_raw_getbin, large_raw,
large_raw_getbin, combined, combined_getbin,
+ ipv6_v6only_udp, ipv6_v6only_tcp, ipv6_v6only_sctp,
+ use_ipv6_v6only_udp,
type_errors].
groups() ->
@@ -127,7 +131,7 @@ loop_all(Config) when is_list(Config) ->
io_lib:format("Non mandatory failed:~w",
[Failed]))}
end.
-
+
simple_raw(suite) -> [];
@@ -461,6 +465,153 @@ do_combined(Config,Binary) when is_list(Config) ->
ok
end.
+
+
+ipv6_v6only_udp(suite) -> [];
+ipv6_v6only_udp(doc) -> "Test socket option ipv6_v6only for UDP";
+ipv6_v6only_udp(Config) when is_list(Config) ->
+ ipv6_v6only(Config, gen_udp).
+
+ipv6_v6only_tcp(suite) -> [];
+ipv6_v6only_tcp(doc) -> "Test socket option ipv6_v6only for TCP";
+ipv6_v6only_tcp(Config) when is_list(Config) ->
+ ipv6_v6only(Config, gen_tcp).
+
+ipv6_v6only_sctp(suite) -> [];
+ipv6_v6only_sctp(doc) -> "Test socket option ipv6_v6only for SCTP";
+ipv6_v6only_sctp(Config) when is_list(Config) ->
+ ipv6_v6only(Config, gen_sctp).
+
+ipv6_v6only(Config, Module) when is_list(Config) ->
+ ?line case ipv6_v6only_open(Module, []) of
+ {ok,S1} ->
+ ?line case inet:getopts(S1, [ipv6_v6only]) of
+ {ok,[{ipv6_v6only,Default}]}
+ when is_boolean(Default) ->
+ ?line ok =
+ ipv6_v6only_close(Module, S1),
+ ?line ipv6_v6only(Config, Module, Default);
+ {ok,[]} ->
+ ?line io:format("Not implemented.~n", []),
+ %% This list of OS:es where the option is
+ %% supposed to be not implemented is just
+ %% a guess, and may grow with time.
+ ?line case {os:type(),os:version()} of
+ {{unix,linux},{2,M,_}}
+ when M =< 4 -> ok
+ end,
+ %% At least this should work
+ ?line {ok,S2} =
+ ipv6_v6only_open(
+ Module,
+ [{ipv6_v6only,true}]),
+ ?line ok =
+ ipv6_v6only_close(Module, S2)
+ end;
+ {error,_} ->
+ {skipped,"Socket type not supported"}
+ end.
+
+ipv6_v6only(Config, Module, Default) when is_list(Config) ->
+ ?line io:format("Default ~w.~n", [Default]),
+ ?line {ok,S1} =
+ ipv6_v6only_open(Module, [{ipv6_v6only,Default}]),
+ ?line {ok,[{ipv6_v6only,Default}]} =
+ inet:getopts(S1, [ipv6_v6only]),
+ ?line ok =
+ ipv6_v6only_close(Module, S1),
+ ?line NotDefault = not Default,
+ ?line case ipv6_v6only_open(Module, [{ipv6_v6only,NotDefault}]) of
+ {ok,S2} ->
+ ?line io:format("Read-write.~n", []),
+ ?line {ok,[{ipv6_v6only,NotDefault}]} =
+ inet:getopts(S2, [ipv6_v6only]),
+ ok;
+ {error,einval} ->
+ ?line io:format("Read-only.~n", []),
+ %% This option is known to be read-only and true
+ %% on Windows and OpenBSD
+ ?line case os:type() of
+ {unix,openbsd} when Default =:= true -> ok;
+ {win32,_} when Default =:= true -> ok
+ end
+ end.
+
+ipv6_v6only_open(Module, Opts) ->
+ Module:case Module of
+ gen_tcp -> listen;
+ _ -> open
+ end(0, [inet6|Opts]).
+
+ipv6_v6only_close(Module, Socket) ->
+ Module:close(Socket).
+
+
+use_ipv6_v6only_udp(suite) -> [];
+use_ipv6_v6only_udp(doc) -> "Test using socket option ipv6_v6only for UDP";
+use_ipv6_v6only_udp(Config) when is_list(Config) ->
+ ?line case gen_udp:open(0, [inet6,{ipv6_v6only,true}]) of
+ {ok,S6} ->
+ ?line case inet:getopts(S6, [ipv6_v6only]) of
+ {ok,[{ipv6_v6only,true}]} ->
+ use_ipv6_v6only_udp(Config, S6);
+ {ok,Other} ->
+ {skipped,{getopts,Other}}
+ end;
+ {error,_} ->
+ {skipped,"Socket type not supported"}
+ end.
+
+use_ipv6_v6only_udp(_Config, S6) ->
+ ?line {ok,Port} = inet:port(S6),
+ ?line {ok,S4} = gen_udp:open(Port, [inet]),
+ ?line E6 = " IPv6-echo.",
+ ?line E4 = " IPv4-echo.",
+ ?line Sender =
+ spawn_link(fun () -> use_ipv6_v6only_udp_sender(Port, E6, E4) end),
+ ?line use_ipv6_v6only_udp_listener(
+ S6, S4, E6, E4, monitor(process, Sender)).
+
+use_ipv6_v6only_udp_listener(S6, S4, E6, E4, Mref) ->
+ ?line receive
+ {udp,S6,IP,P,Data} ->
+ ?line ok = gen_udp:send(S6, IP, P, [Data|E6]),
+ ?line use_ipv6_v6only_udp_listener(S6, S4, E6, E4, Mref);
+ {udp,S4,IP,P,Data} ->
+ ?line ok = gen_udp:send(S4, IP, P, [Data|E4]),
+ ?line use_ipv6_v6only_udp_listener(S6, S4, E6, E4, Mref);
+ {'DOWN',Mref,_,_,normal} ->
+ ok;
+ {'DOWN',Mref,_,_,Result} ->
+ %% Since we are linked we will never arrive here
+ Result;
+ Other ->
+ ?line exit({failed,{listener_unexpected,Other}})
+ end.
+
+use_ipv6_v6only_udp_sender(Port, E6, E4) ->
+ D6 = "IPv6-send.",
+ D4 = "IPv4-send.",
+ R6 = D6 ++ E6,
+ R4 = D4 ++ E4,
+ R6 = sndrcv({0,0,0,0,0,0,0,1}, Port, [inet6], D6),
+ R4 = sndrcv({127,0,0,1}, Port, [inet], D4),
+ ok.
+
+sndrcv(Ip, Port, Opts, Data) ->
+ {ok,S} = gen_udp:open(0, Opts),
+ io:format("[~w:~w] ! ~s~n", [Ip,Port,Data]),
+ ok = gen_udp:send(S, Ip, Port, Data),
+ receive
+ {udp,S,Ip,Port,RecData} ->
+ io:format("[~w:~w] : ~s~n", [Ip,Port,RecData]),
+ RecData;
+ Other ->
+ exit({failed,{sndrcv_unexpectec,Other}})
+ end.
+
+
+
type_errors(suite) ->
[];
type_errors(doc) ->
diff --git a/lib/kernel/test/interactive_shell_SUITE.erl b/lib/kernel/test/interactive_shell_SUITE.erl
index 4787f19250..36e13cec26 100644
--- a/lib/kernel/test/interactive_shell_SUITE.erl
+++ b/lib/kernel/test/interactive_shell_SUITE.erl
@@ -29,20 +29,11 @@
-export([toerl_server/3]).
init_per_testcase(_Func, Config) ->
- Dog = test_server:timetrap(test_server:seconds(60)),
- Term = case os:getenv("TERM") of
- List when is_list(List) ->
- List;
- _ ->
- "dumb"
- end,
- os:putenv("TERM","vt100"),
- [{watchdog,Dog},{term,Term}|Config].
+ Dog = test_server:timetrap(test_server:minutes(3)),
+ [{watchdog,Dog}|Config].
end_per_testcase(_Func, Config) ->
Dog = ?config(watchdog, Config),
- Term = ?config(term,Config),
- os:putenv("TERM",Term),
test_server:timetrap_cancel(Dog).
@@ -56,9 +47,19 @@ groups() ->
[].
init_per_suite(Config) ->
- Config.
+ Term = case os:getenv("TERM") of
+ List when is_list(List) ->
+ List;
+ _ ->
+ "dumb"
+ end,
+ os:putenv("TERM","vt100"),
+ DefShell = get_default_shell(),
+ [{default_shell,DefShell},{term,Term}|Config].
-end_per_suite(_Config) ->
+end_per_suite(Config) ->
+ Term = ?config(term,Config),
+ os:putenv("TERM",Term),
ok.
init_per_group(_GroupName, Config) ->
@@ -78,70 +79,118 @@ end_per_group(_GroupName, Config) ->
get_columns_and_rows(suite) -> [];
get_columns_and_rows(doc) -> ["Test that the shell can access columns and rows"];
get_columns_and_rows(Config) when is_list(Config) ->
- ?line rtnode([{putline,""},
- {putline, "2."},
- {getline, "2"},
- {putline,"io:columns()."},
-%% Behaviour change in R12B-5, returns 80
-%% {getline,"{error,enotsup}"},
- {getline,"{ok,80}"},
- {putline,"io:rows()."},
-%% Behaviour change in R12B-5, returns 24
-%% {getline,"{error,enotsup}"}
- {getline,"{ok,24}"}
- ],[]),
- ?line rtnode([{putline,""},
- {putline, "2."},
- {getline, "2"},
- {putline,"io:columns()."},
- {getline,"{ok,90}"},
- {putline,"io:rows()."},
- {getline,"{ok,40}"}],
- [],
- "stty rows 40; stty columns 90; ").
+ case proplists:get_value(default_shell,Config) of
+ old ->
+ %% Old shell tests
+ ?dbg(old_shell),
+ ?line rtnode([{putline,""},
+ {putline, "2."},
+ {getline, "2"},
+ {putline,"io:columns()."},
+ {getline_re,".*{error,enotsup}"},
+ {putline,"io:rows()."},
+ {getline_re,".*{error,enotsup}"}
+
+ ],[]),
+ ?line rtnode([{putline,""},
+ {putline, "2."},
+ {getline, "2"},
+ {putline,"io:columns()."},
+ {getline_re,".*{ok,90}"},
+ {putline,"io:rows()."},
+ {getline_re,".*{ok,40}"}],
+ [],
+ "stty rows 40; stty columns 90; ");
+ new ->
+ % New shell tests
+ ?dbg(new_shell),
+ ?line rtnode([{putline,""},
+ {putline, "2."},
+ {getline, "2"},
+ {putline,"io:columns()."},
+ %% Behaviour change in R12B-5, returns 80
+ %% {getline,"{error,enotsup}"},
+ {getline,"{ok,80}"},
+ {putline,"io:rows()."},
+ %% Behaviour change in R12B-5, returns 24
+ %% {getline,"{error,enotsup}"}
+ {getline,"{ok,24}"}
+ ],[]),
+ ?line rtnode([{putline,""},
+ {putline, "2."},
+ {getline, "2"},
+ {putline,"io:columns()."},
+ {getline,"{ok,90}"},
+ {putline,"io:rows()."},
+ {getline,"{ok,40}"}],
+ [],
+ "stty rows 40; stty columns 90; ")
+ end.
exit_initial(suite) -> [];
exit_initial(doc) -> ["Tests that exit of initial shell restarts shell"];
exit_initial(Config) when is_list(Config) ->
- ?line rtnode([{putline,""},
- {putline, "2."},
- {getline, "2"},
- {putline,"exit()."},
- {getline,""},
- {getline,"Eshell"},
- {putline,""},
- {putline,"35."},
- {getline,"35"}],[]).
+ case proplists:get_value(default_shell,Config) of
+ old ->
+ rtnode([{putline,""},
+ {putline, "2."},
+ {getline_re, ".*2"},
+ {putline,"exit()."},
+ {getline,""},
+ {getline,"Eshell"},
+ {putline,""},
+ {putline,"35."},
+ {getline_re,".*35"}],[]);
+ new ->
+ rtnode([{putline,""},
+ {putline, "2."},
+ {getline, "2"},
+ {putline,"exit()."},
+ {getline,""},
+ {getline,"Eshell"},
+ {putline,""},
+ {putline,"35."},
+ {getline_re,"35"}],[])
+ end.
job_control_local(suite) -> [];
job_control_local(doc) -> [ "Tests that local shell can be "
"started by means of job control" ];
job_control_local(Config) when is_list(Config) ->
- ?line rtnode([{putline,""},
- {putline, "2."},
- {getline, "2"},
- {putline,[7]},
- {sleep,timeout(short)},
- {putline,""},
- {getline," -->"},
- {putline,"s"},
- {putline,"c"},
- {putline_raw,""},
- {getline,"Eshell"},
- {putline_raw,""},
- {getline,"1>"},
- {putline,"35."},
- {getline,"35"}],[]).
+ case proplists:get_value(default_shell,Config) of
+ old ->
+ %% Old shell tests
+ {skip,"No new shell found"};
+ new ->
+ %% New shell tests
+ ?line rtnode([{putline,""},
+ {putline, "2."},
+ {getline, "2"},
+ {putline,[7]},
+ {sleep,timeout(short)},
+ {putline,""},
+ {getline," -->"},
+ {putline,"s"},
+ {putline,"c"},
+ {putline_raw,""},
+ {getline,"Eshell"},
+ {putline_raw,""},
+ {getline,"1>"},
+ {putline,"35."},
+ {getline,"35"}],[])
+ end.
job_control_remote(suite) -> [];
job_control_remote(doc) -> [ "Tests that remote shell can be "
"started by means of job control" ];
job_control_remote(Config) when is_list(Config) ->
- case node() of
- nonode@nohost ->
+ case {node(),proplists:get_value(default_shell,Config)} of
+ {nonode@nohost,_} ->
?line exit(not_distributed);
+ {_,old} ->
+ {skip,"No new shell found"};
_ ->
?line RNode = create_nodename(),
?line MyNode = atom_to_list(node()),
@@ -190,9 +239,11 @@ job_control_remote_noshell(doc) ->
[ "Tests that remote shell can be "
"started by means of job control to -noshell node" ];
job_control_remote_noshell(Config) when is_list(Config) ->
- case node() of
- nonode@nohost ->
+ case {node(),proplists:get_value(default_shell,Config)} of
+ {nonode@nohost,_} ->
?line exit(not_distributed);
+ {_,old} ->
+ {skip,"No new shell found"};
_ ->
?line RNode = create_nodename(),
?line NSNode = start_noshell_node(interactive_shell_noshell),
@@ -351,6 +402,33 @@ get_and_put(CPid, [{getline, Match}|T],N) ->
end
end;
+%% Hey ho copy paste from stdlib/io_proto_SUITE
+get_and_put(CPid, [{getline_re, Match}|T],N) ->
+ ?dbg({getline_re, Match}),
+ CPid ! {self(), {get_line, timeout(normal)}},
+ receive
+ {get_line, timeout} ->
+ error_logger:error_msg("~p: getline_re timeout waiting for \"~s\" "
+ "(command number ~p, skipped: ~p)~n",
+ [?MODULE, Match,N,get(getline_skipped)]),
+ {error, timeout};
+ {get_line, Data} ->
+ ?dbg({data,Data}),
+ case re:run(Data, Match,[{capture,none}]) of
+ match ->
+ erase(getline_skipped),
+ get_and_put(CPid, T,N+1);
+ _ ->
+ case get(getline_skipped) of
+ undefined ->
+ put(getline_skipped,[Data]);
+ List ->
+ put(getline_skipped,List ++ [Data])
+ end,
+ get_and_put(CPid, [{getline_re, Match}|T],N)
+ end
+ end;
+
get_and_put(CPid, [{putline_raw, Line}|T],N) ->
?dbg({putline_raw, Line}),
CPid ! {self(), {send_line, Line}},
@@ -631,6 +709,13 @@ get_data_within(Port, Timeout, Acc) ->
timeout
end.
-
-
-
+get_default_shell() ->
+ try
+ rtnode([{putline,""},
+ {putline, "whereis(user_drv)."},
+ {getline, "undefined"}],[]),
+ old
+ catch E:R ->
+ ?dbg({E,R}),
+ new
+ end.
diff --git a/lib/kernel/test/kernel.cover b/lib/kernel/test/kernel.cover
index f6967ca651..af1dd7eaad 100644
--- a/lib/kernel/test/kernel.cover
+++ b/lib/kernel/test/kernel.cover
@@ -1,3 +1,3 @@
%% -*- erlang -*-
-{incl_mods,[gen_udp,inet6_udp,inet_res,inet_dns]}.
+{incl_app,kernel,details}.
diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl
index a56746bbc4..4e93a593b3 100644
--- a/lib/kernel/test/prim_file_SUITE.erl
+++ b/lib/kernel/test/prim_file_SUITE.erl
@@ -57,6 +57,8 @@
%% System probe functions that might be handy to check from the shell
-export([unix_free/1]).
+-export([allocate/1]).
+
-include_lib("test_server/include/test_server.hrl").
-include_lib("kernel/include/file.hrl").
@@ -87,7 +89,7 @@ groups() ->
cur_dir_1a, cur_dir_1b]},
{files, [],
[{group, open}, {group, pos}, {group, file_info},
- truncate, sync, datasync, advise, large_write]},
+ truncate, sync, datasync, advise, large_write, allocate]},
{open, [],
[open1, modes, close, access, read_write, pread_write,
append, exclusive]},
@@ -1359,6 +1361,76 @@ check_large_write(Dog, Fd, _, _, []) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+allocate(suite) -> [];
+allocate(doc) -> "Tests that ?PRIM_FILE:allocate/3 at least doesn't crash.";
+allocate(Config) when is_list(Config) ->
+ ?line Dog = test_server:timetrap(test_server:seconds(5)),
+ ?line PrivDir = ?config(priv_dir, Config),
+ ?line Allocate = filename:join(PrivDir,
+ atom_to_list(?MODULE)
+ ++"_allocate.fil"),
+
+ Line1 = "Hello\n",
+ Line2 = "World!\n",
+
+ ?line {ok, Fd} = ?PRIM_FILE:open(Allocate, [write, binary]),
+ allocate_and_assert(Fd, 1, iolist_size([Line1, Line2])),
+ ?line ok = ?PRIM_FILE:write(Fd, Line1),
+ ?line ok = ?PRIM_FILE:write(Fd, Line2),
+ ?line ok = ?PRIM_FILE:close(Fd),
+
+ ?line {ok, Fd2} = ?PRIM_FILE:open(Allocate, [write, binary]),
+ allocate_and_assert(Fd2, 1, iolist_size(Line1)),
+ ?line ok = ?PRIM_FILE:write(Fd2, Line1),
+ ?line ok = ?PRIM_FILE:write(Fd2, Line2),
+ ?line ok = ?PRIM_FILE:close(Fd2),
+
+ ?line {ok, Fd3} = ?PRIM_FILE:open(Allocate, [write, binary]),
+ allocate_and_assert(Fd3, 1, iolist_size(Line1) + 1),
+ ?line ok = ?PRIM_FILE:write(Fd3, Line1),
+ ?line ok = ?PRIM_FILE:write(Fd3, Line2),
+ ?line ok = ?PRIM_FILE:close(Fd3),
+
+ ?line {ok, Fd4} = ?PRIM_FILE:open(Allocate, [write, binary]),
+ allocate_and_assert(Fd4, 1, 4 * iolist_size([Line1, Line2])),
+ ?line ok = ?PRIM_FILE:write(Fd4, Line1),
+ ?line ok = ?PRIM_FILE:write(Fd4, Line2),
+ ?line ok = ?PRIM_FILE:close(Fd4),
+
+ ?line test_server:timetrap_cancel(Dog),
+ ok.
+
+allocate_and_assert(Fd, Offset, Length) ->
+ % Just verify that calls to ?PRIM_FILE:allocate/3 don't crash or have
+ % any other negative side effect. We can't really asssert against a
+ % specific return value, because support for file space pre-allocation
+ % depends on the OS, OS version and underlying filesystem.
+ %
+ % The Linux kernel added support for fallocate() in version 2.6.23,
+ % which currently works only for the ext4, ocfs2, xfs and btrfs file
+ % systems. posix_fallocate() is available in glibc as of version
+ % 2.1.94, but it was buggy until glibc version 2.7.
+ %
+ % Mac OS X, as of version 10.3, supports the fcntl operation F_PREALLOCATE.
+ %
+ % Solaris supports posix_fallocate() but only for the UFS file system
+ % apparently (not supported for ZFS).
+ %
+ % FreeBSD 9.0 is the first FreeBSD release supporting posix_fallocate().
+ %
+ % For Windows there's apparently no way to pre-allocate file space, at
+ % least with similar API/semantics as posix_fallocate(), fallocate() or
+ % fcntl F_PREALLOCATE.
+ Result = ?PRIM_FILE:allocate(Fd, Offset, Length),
+ case os:type() of
+ {win32, _} ->
+ ?line {error, enotsup} = Result;
+ _ ->
+ ?line _ = Result
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
delete_a(suite) -> [];
delete_a(doc) -> [];
delete_a(Config) when is_list(Config) ->
diff --git a/lib/kernel/test/ram_file_SUITE.erl b/lib/kernel/test/ram_file_SUITE.erl
index ab95a3ff5f..5c4437d4d3 100644
--- a/lib/kernel/test/ram_file_SUITE.erl
+++ b/lib/kernel/test/ram_file_SUITE.erl
@@ -1,7 +1,8 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -167,7 +168,7 @@ pread_pwrite(suite) ->
pread_pwrite(doc) ->
["Test that pread/2,3 and pwrite/2,3 works."];
pread_pwrite(Config) when is_list(Config) ->
- ?line Str = "Flygande b�ckaziner s�ka hwila p� mjuqa tuvor x",
+ ?line Str = "Flygande bäckaziner söka hwila på mjuqa tuvor x",
?line Bin = list_to_binary(Str),
%%
pread_pwrite_test(?FILE_MODULE, Str, [ram, read, write]),
@@ -206,7 +207,7 @@ position(suite) ->
position(doc) ->
["Test that position/2 works."];
position(Config) when is_list(Config) ->
- ?line Str = "Att vara eller icke vara, det �r fr�gan. ",
+ ?line Str = "Att vara eller icke vara, det är frågan. ",
?line Bin = list_to_binary(Str),
%%
position_test(?FILE_MODULE, Str, [ram, read]),
@@ -287,8 +288,8 @@ truncate(suite) ->
truncate(doc) ->
["Test that truncate/1 works."];
truncate(Config) when is_list(Config) ->
- ?line Str = "M�n �dlare att lida och f�rdraga "
- ++ "ett bittert �des stygn av pilar, ",
+ ?line Str = "Mån ädlare att lida och fördraga "
+ ++ "ett bittert ödes stygn av pilar, ",
?line Bin = list_to_binary(Str),
%%
ok = truncate_test(?FILE_MODULE, Str, [ram, read, write]),
@@ -331,7 +332,7 @@ sync(suite) ->
sync(doc) ->
["Test that sync/1 at least does not crash."];
sync(Config) when is_list(Config) ->
- ?line Str = "�n att ta till vapen mot ett hav av kval. ",
+ ?line Str = "än att ta till vapen mot ett hav av kval. ",
?line Bin = list_to_binary(Str),
%%
sync_test(?FILE_MODULE, Str, [ram, read, write]),
@@ -365,8 +366,8 @@ get_set_file(doc) ->
["Tests get_file/1, set_file/2, get_file_close/1 and get_size/1."];
get_set_file(Config) when is_list(Config) ->
%% These two strings should not be of equal length.
- ?line Str = "N�r h�gan nord blir sn�bet�ckt, ",
- ?line Str2 = "f�r alla harar byta dr�kt. ",
+ ?line Str = "När högan nord blir snöbetäckt, ",
+ ?line Str2 = "får alla harar byta dräkt. ",
?line Bin = list_to_binary(Str),
?line Bin2 = list_to_binary(Str2),
%%
diff --git a/lib/kernel/test/wrap_log_reader_SUITE.erl b/lib/kernel/test/wrap_log_reader_SUITE.erl
index 96dc3e6d33..16b3a7cc1e 100644
--- a/lib/kernel/test/wrap_log_reader_SUITE.erl
+++ b/lib/kernel/test/wrap_log_reader_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -557,7 +557,7 @@ rec(M, Where) ->
M ->
ok;
Else -> ?t:fail({error, {Where, Else}})
- after 1000 -> ?t:fail({error, {Where, time_out}})
+ after 5000 -> ?t:fail({error, {Where, time_out}})
end.
pps() ->
diff --git a/lib/megaco/aclocal.m4 b/lib/megaco/aclocal.m4
new file mode 100644
index 0000000000..918e30a886
--- /dev/null
+++ b/lib/megaco/aclocal.m4
@@ -0,0 +1,1905 @@
+dnl
+dnl %CopyrightBegin%
+dnl
+dnl Copyright Ericsson AB 1998-2012. All Rights Reserved.
+dnl
+dnl The contents of this file are subject to the Erlang Public License,
+dnl Version 1.1, (the "License"); you may not use this file except in
+dnl compliance with the License. You should have received a copy of the
+dnl Erlang Public License along with this software. If not, it can be
+dnl retrieved online at http://www.erlang.org/.
+dnl
+dnl Software distributed under the License is distributed on an "AS IS"
+dnl basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+dnl the License for the specific language governing rights and limitations
+dnl under the License.
+dnl
+dnl %CopyrightEnd%
+dnl
+
+dnl
+dnl aclocal.m4
+dnl
+dnl Local macros used in configure.in. The Local Macros which
+dnl could/should be part of autoconf are prefixed LM_, macros specific
+dnl to the Erlang system are prefixed ERL_.
+dnl
+
+AC_DEFUN(LM_PRECIOUS_VARS,
+[
+
+dnl ERL_TOP
+AC_ARG_VAR(ERL_TOP, [Erlang/OTP top source directory])
+
+dnl Tools
+AC_ARG_VAR(CC, [C compiler])
+AC_ARG_VAR(CFLAGS, [C compiler flags])
+AC_ARG_VAR(STATIC_CFLAGS, [C compiler static flags])
+AC_ARG_VAR(CFLAG_RUNTIME_LIBRARY_PATH, [runtime library path linker flag passed via C compiler])
+AC_ARG_VAR(CPP, [C/C++ preprocessor])
+AC_ARG_VAR(CPPFLAGS, [C/C++ preprocessor flags])
+AC_ARG_VAR(CXX, [C++ compiler])
+AC_ARG_VAR(CXXFLAGS, [C++ compiler flags])
+AC_ARG_VAR(LD, [linker (is often overridden by configure)])
+AC_ARG_VAR(LDFLAGS, [linker flags (can be risky to set since LD may be overriden by configure)])
+AC_ARG_VAR(LIBS, [libraries])
+AC_ARG_VAR(DED_LD, [linker for Dynamic Erlang Drivers (set all DED_LD* variables or none)])
+AC_ARG_VAR(DED_LDFLAGS, [linker flags for Dynamic Erlang Drivers (set all DED_LD* variables or none)])
+AC_ARG_VAR(DED_LD_FLAG_RUNTIME_LIBRARY_PATH, [runtime library path linker flag for Dynamic Erlang Drivers (set all DED_LD* variables or none)])
+AC_ARG_VAR(LFS_CFLAGS, [large file support C compiler flags (set all LFS_* variables or none)])
+AC_ARG_VAR(LFS_LDFLAGS, [large file support linker flags (set all LFS_* variables or none)])
+AC_ARG_VAR(LFS_LIBS, [large file support libraries (set all LFS_* variables or none)])
+AC_ARG_VAR(RANLIB, [ranlib])
+AC_ARG_VAR(AR, [ar])
+AC_ARG_VAR(GETCONF, [getconf])
+
+dnl Cross system root
+AC_ARG_VAR(erl_xcomp_sysroot, [Absolute cross system root path (only used when cross compiling)])
+AC_ARG_VAR(erl_xcomp_isysroot, [Absolute cross system root include path (only used when cross compiling)])
+
+dnl Cross compilation variables
+AC_ARG_VAR(erl_xcomp_bigendian, [big endian system: yes|no (only used when cross compiling)])
+AC_ARG_VAR(erl_xcomp_double_middle_endian, [double-middle-endian system: yes|no (only used when cross compiling)])
+AC_ARG_VAR(erl_xcomp_linux_clock_gettime_correction, [clock_gettime() can be used for time correction: yes|no (only used when cross compiling)])
+AC_ARG_VAR(erl_xcomp_linux_nptl, [have Native POSIX Thread Library: yes|no (only used when cross compiling)])
+AC_ARG_VAR(erl_xcomp_linux_usable_sigusrx, [SIGUSR1 and SIGUSR2 can be used: yes|no (only used when cross compiling)])
+AC_ARG_VAR(erl_xcomp_linux_usable_sigaltstack, [have working sigaltstack(): yes|no (only used when cross compiling)])
+AC_ARG_VAR(erl_xcomp_poll, [have working poll(): yes|no (only used when cross compiling)])
+AC_ARG_VAR(erl_xcomp_kqueue, [have working kqueue(): yes|no (only used when cross compiling)])
+AC_ARG_VAR(erl_xcomp_putenv_copy, [putenv() stores key-value copy: yes|no (only used when cross compiling)])
+AC_ARG_VAR(erl_xcomp_reliable_fpe, [have reliable floating point exceptions: yes|no (only used when cross compiling)])
+AC_ARG_VAR(erl_xcomp_getaddrinfo, [have working getaddrinfo() for both IPv4 and IPv6: yes|no (only used when cross compiling)])
+AC_ARG_VAR(erl_xcomp_gethrvtime_procfs_ioctl, [have working gethrvtime() which can be used with procfs ioctl(): yes|no (only used when cross compiling)])
+AC_ARG_VAR(erl_xcomp_clock_gettime_cpu_time, [clock_gettime() can be used for retrieving process CPU time: yes|no (only used when cross compiling)])
+AC_ARG_VAR(erl_xcomp_after_morecore_hook, [__after_morecore_hook can track malloc()s core memory usage: yes|no (only used when cross compiling)])
+AC_ARG_VAR(erl_xcomp_dlsym_brk_wrappers, [dlsym(RTLD_NEXT, _) brk wrappers can track malloc()s core memory usage: yes|no (only used when cross compiling)])
+
+])
+
+AC_DEFUN(ERL_XCOMP_SYSROOT_INIT,
+[
+erl_xcomp_without_sysroot=no
+if test "$cross_compiling" = "yes"; then
+ test "$erl_xcomp_sysroot" != "" || erl_xcomp_without_sysroot=yes
+ test "$erl_xcomp_isysroot" != "" || erl_xcomp_isysroot="$erl_xcomp_sysroot"
+else
+ erl_xcomp_sysroot=
+ erl_xcomp_isysroot=
+fi
+])
+
+AC_DEFUN(LM_CHECK_GETCONF,
+[
+if test "$cross_compiling" != "yes"; then
+ AC_CHECK_PROG([GETCONF], [getconf], [getconf], [false])
+else
+ dnl First check if we got a `<HOST>-getconf' in $PATH
+ host_getconf="$host_alias-getconf"
+ AC_CHECK_PROG([GETCONF], [$host_getconf], [$host_getconf], [false])
+ if test "$GETCONF" = "false" && test "$erl_xcomp_sysroot" != ""; then
+ dnl We should perhaps give up if we have'nt found it by now, but at
+ dnl least in one Tilera MDE `getconf' under sysroot is a bourne
+ dnl shell script which we can use. We try to find `<HOST>-getconf'
+ dnl or `getconf' under sysconf, but only under sysconf since
+ dnl `getconf' in $PATH is almost guaranteed to be for the build
+ dnl machine.
+ GETCONF=
+ prfx="$erl_xcomp_sysroot"
+ AC_PATH_TOOL([GETCONF], [getconf], [false],
+ ["$prfx/usr/bin:$prfx/bin:$prfx/usr/local/bin"])
+ fi
+fi
+])
+
+dnl ----------------------------------------------------------------------
+dnl
+dnl LM_WINDOWS_ENVIRONMENT
+dnl
+dnl
+dnl Tries to determine thw windows build environment, i.e.
+dnl MIXED_CYGWIN_VC or MIXED_MSYS_VC
+dnl
+
+AC_DEFUN(LM_WINDOWS_ENVIRONMENT,
+[
+MIXED_CYGWIN=no
+MIXED_MSYS=no
+
+AC_MSG_CHECKING(for mixed cygwin or msys and native VC++ environment)
+if test "X$host" = "Xwin32" -a "x$GCC" != "xyes"; then
+ if test -x /usr/bin/cygpath; then
+ CFLAGS="-O2"
+ MIXED_CYGWIN=yes
+ AC_MSG_RESULT([Cygwin and VC])
+ MIXED_CYGWIN_VC=yes
+ CPPFLAGS="$CPPFLAGS -DERTS_MIXED_CYGWIN_VC"
+ elif test -x /usr/bin/msysinfo; then
+ CFLAGS="-O2"
+ MIXED_MSYS=yes
+ AC_MSG_RESULT([MSYS and VC])
+ MIXED_MSYS_VC=yes
+ CPPFLAGS="$CPPFLAGS -DERTS_MIXED_MSYS_VC"
+ else
+ AC_MSG_RESULT([undeterminable])
+ AC_MSG_ERROR(Seems to be mixed windows but not with cygwin, cannot handle this!)
+ fi
+else
+ AC_MSG_RESULT([no])
+ MIXED_CYGWIN_VC=no
+ MIXED_MSYS_VC=no
+fi
+AC_SUBST(MIXED_CYGWIN_VC)
+AC_SUBST(MIXED_MSYS_VC)
+
+MIXED_VC=no
+if test "x$MIXED_MSYS_VC" = "xyes" -o "x$MIXED_CYGWIN_VC" = "xyes" ; then
+ MIXED_VC=yes
+fi
+
+AC_SUBST(MIXED_VC)
+
+if test "x$MIXED_MSYS" != "xyes"; then
+ AC_MSG_CHECKING(for mixed cygwin and native MinGW environment)
+ if test "X$host" = "Xwin32" -a "x$GCC" = x"yes"; then
+ if test -x /usr/bin/cygpath; then
+ CFLAGS="-O2"
+ MIXED_CYGWIN=yes
+ AC_MSG_RESULT([yes])
+ MIXED_CYGWIN_MINGW=yes
+ CPPFLAGS="$CPPFLAGS -DERTS_MIXED_CYGWIN_MINGW"
+ else
+ AC_MSG_RESULT([undeterminable])
+ AC_MSG_ERROR(Seems to be mixed windows but not with cygwin, cannot handle this!)
+ fi
+ else
+ AC_MSG_RESULT([no])
+ MIXED_CYGWIN_MINGW=no
+ fi
+else
+ MIXED_CYGWIN_MINGW=no
+fi
+AC_SUBST(MIXED_CYGWIN_MINGW)
+
+AC_MSG_CHECKING(if we mix cygwin with any native compiler)
+if test "X$MIXED_CYGWIN" = "Xyes"; then
+ AC_MSG_RESULT([yes])
+else
+ AC_MSG_RESULT([no])
+fi
+
+AC_SUBST(MIXED_CYGWIN)
+
+AC_MSG_CHECKING(if we mix msys with another native compiler)
+if test "X$MIXED_MSYS" = "Xyes" ; then
+ AC_MSG_RESULT([yes])
+else
+ AC_MSG_RESULT([no])
+fi
+
+AC_SUBST(MIXED_MSYS)
+])
+
+dnl ----------------------------------------------------------------------
+dnl
+dnl LM_FIND_EMU_CC
+dnl
+dnl
+dnl Tries fairly hard to find a C compiler that can handle jump tables.
+dnl Defines the @EMU_CC@ variable for the makefiles and
+dnl inserts NO_JUMP_TABLE in the header if one cannot be found...
+dnl
+
+AC_DEFUN(LM_FIND_EMU_CC,
+ [AC_CACHE_CHECK(for a compiler that handles jumptables,
+ ac_cv_prog_emu_cc,
+ [
+AC_TRY_COMPILE([],[
+#if defined(__clang_major__) && __clang_major__ >= 3
+ /* clang 3.x or later is fine */
+#elif defined(__llvm__)
+#error "this version of llvm is unable to correctly compile beam_emu.c"
+#endif
+ __label__ lbl1;
+ __label__ lbl2;
+ int x = magic();
+ static void *jtab[2];
+
+ jtab[0] = &&lbl1;
+ jtab[1] = &&lbl2;
+ goto *jtab[x];
+lbl1:
+ return 1;
+lbl2:
+ return 2;
+],ac_cv_prog_emu_cc=$CC,ac_cv_prog_emu_cc=no)
+
+if test $ac_cv_prog_emu_cc = no; then
+ for ac_progname in emu_cc.sh gcc-4.2 gcc; do
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_progname; then
+ ac_cv_prog_emu_cc=$ac_dir/$ac_progname
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ if test $ac_cv_prog_emu_cc != no; then
+ break
+ fi
+ done
+fi
+
+if test $ac_cv_prog_emu_cc != no; then
+ save_CC=$CC
+ save_CFLAGS=$CFLAGS
+ save_CPPFLAGS=$CPPFLAGS
+ CC=$ac_cv_prog_emu_cc
+ CFLAGS=""
+ CPPFLAGS=""
+ AC_TRY_COMPILE([],[
+#if defined(__clang_major__) && __clang_major__ >= 3
+ /* clang 3.x or later is fine */
+#elif defined(__llvm__)
+#error "this version of llvm is unable to correctly compile beam_emu.c"
+#endif
+ __label__ lbl1;
+ __label__ lbl2;
+ int x = magic();
+ static void *jtab[2];
+
+ jtab[0] = &&lbl1;
+ jtab[1] = &&lbl2;
+ goto *jtab[x];
+ lbl1:
+ return 1;
+ lbl2:
+ return 2;
+ ],ac_cv_prog_emu_cc=$CC,ac_cv_prog_emu_cc=no)
+ CC=$save_CC
+ CFLAGS=$save_CFLAGS
+ CPPFLAGS=$save_CPPFLAGS
+fi
+])
+if test $ac_cv_prog_emu_cc = no; then
+ AC_DEFINE(NO_JUMP_TABLE,[],[Defined if no found C compiler can handle jump tables])
+ EMU_CC=$CC
+else
+ EMU_CC=$ac_cv_prog_emu_cc
+fi
+AC_SUBST(EMU_CC)
+])
+
+
+
+dnl ----------------------------------------------------------------------
+dnl
+dnl LM_PROG_INSTALL_DIR
+dnl
+dnl This macro may be used by any OTP application.
+dnl
+dnl Figure out how to create directories with parents.
+dnl (In my opinion INSTALL_DIR is a bad name, MKSUBDIRS or something is better)
+dnl
+dnl We prefer 'install -d', but use 'mkdir -p' if it exists.
+dnl If none of these methods works, we give up.
+dnl
+
+
+AC_DEFUN(LM_PROG_INSTALL_DIR,
+[AC_CACHE_CHECK(how to create a directory including parents,
+ac_cv_prog_mkdir_p,
+[
+temp_name_base=config.$$
+temp_name=$temp_name_base/x/y/z
+$INSTALL -d $temp_name >/dev/null 2>&1
+ac_cv_prog_mkdir_p=none
+if test -d $temp_name; then
+ ac_cv_prog_mkdir_p="$INSTALL -d"
+else
+ mkdir -p $temp_name >/dev/null 2>&1
+ if test -d $temp_name; then
+ ac_cv_prog_mkdir_p="mkdir -p"
+ fi
+fi
+rm -fr $temp_name_base
+])
+
+case "${ac_cv_prog_mkdir_p}" in
+ none) AC_MSG_ERROR(don't know how create directories with parents) ;;
+ *) INSTALL_DIR="$ac_cv_prog_mkdir_p" AC_SUBST(INSTALL_DIR) ;;
+esac
+])
+
+
+dnl ----------------------------------------------------------------------
+dnl
+dnl LM_PROG_PERL5
+dnl
+dnl Try to find perl version 5. If found set PERL to the absolute path
+dnl of the program, if not found set PERL to false.
+dnl
+dnl On some systems /usr/bin/perl is perl 4 and e.g.
+dnl /usr/local/bin/perl is perl 5. We try to handle this case by
+dnl putting a couple of
+dnl Tries to handle the case that there are two programs called perl
+dnl in the path and one of them is perl 5 and the other isn't.
+dnl
+AC_DEFUN(LM_PROG_PERL5,
+[AC_PATH_PROGS(PERL, perl5 perl, false,
+ /usr/local/bin:/opt/local/bin:/usr/local/gnu/bin:${PATH})
+changequote(, )dnl
+dnl[ That bracket is needed to balance the right bracket below
+if test "$PERL" = "false" || $PERL -e 'exit ($] >= 5)'; then
+changequote([, ])dnl
+ ac_cv_path_PERL=false
+ PERL=false
+dnl AC_MSG_WARN(perl version 5 not found)
+fi
+])dnl
+
+
+dnl ----------------------------------------------------------------------
+dnl
+dnl LM_DECL_SO_BSDCOMPAT
+dnl
+dnl Check if the system has the SO_BSDCOMPAT flag on sockets (linux)
+dnl
+AC_DEFUN(LM_DECL_SO_BSDCOMPAT,
+[AC_CACHE_CHECK([for SO_BSDCOMPAT declaration], ac_cv_decl_so_bsdcompat,
+AC_TRY_COMPILE([#include <sys/socket.h>], [int i = SO_BSDCOMPAT;],
+ ac_cv_decl_so_bsdcompat=yes,
+ ac_cv_decl_so_bsdcompat=no))
+
+case "${ac_cv_decl_so_bsdcompat}" in
+ "yes" ) AC_DEFINE(HAVE_SO_BSDCOMPAT,[],
+ [Define if you have SO_BSDCOMPAT flag on sockets]) ;;
+ * ) ;;
+esac
+])
+
+
+dnl ----------------------------------------------------------------------
+dnl
+dnl LM_DECL_INADDR_LOOPBACK
+dnl
+dnl Try to find declaration of INADDR_LOOPBACK, if nowhere provide a default
+dnl
+
+AC_DEFUN(LM_DECL_INADDR_LOOPBACK,
+[AC_CACHE_CHECK([for INADDR_LOOPBACK in netinet/in.h],
+ ac_cv_decl_inaddr_loopback,
+[AC_TRY_COMPILE([#include <sys/types.h>
+#include <netinet/in.h>], [int i = INADDR_LOOPBACK;],
+ac_cv_decl_inaddr_loopback=yes, ac_cv_decl_inaddr_loopback=no)
+])
+
+if test ${ac_cv_decl_inaddr_loopback} = no; then
+ AC_CACHE_CHECK([for INADDR_LOOPBACK in rpc/types.h],
+ ac_cv_decl_inaddr_loopback_rpc,
+ AC_TRY_COMPILE([#include <rpc/types.h>],
+ [int i = INADDR_LOOPBACK;],
+ ac_cv_decl_inaddr_loopback_rpc=yes,
+ ac_cv_decl_inaddr_loopback_rpc=no))
+
+ case "${ac_cv_decl_inaddr_loopback_rpc}" in
+ "yes" )
+ AC_DEFINE(DEF_INADDR_LOOPBACK_IN_RPC_TYPES_H,[],
+ [Define if you need to include rpc/types.h to get INADDR_LOOPBACK defined]) ;;
+ * )
+ AC_CACHE_CHECK([for INADDR_LOOPBACK in winsock2.h],
+ ac_cv_decl_inaddr_loopback_winsock2,
+ AC_TRY_COMPILE([#define WIN32_LEAN_AND_MEAN
+ #include <winsock2.h>],
+ [int i = INADDR_LOOPBACK;],
+ ac_cv_decl_inaddr_loopback_winsock2=yes,
+ ac_cv_decl_inaddr_loopback_winsock2=no))
+ case "${ac_cv_decl_inaddr_loopback_winsock2}" in
+ "yes" )
+ AC_DEFINE(DEF_INADDR_LOOPBACK_IN_WINSOCK2_H,[],
+ [Define if you need to include winsock2.h to get INADDR_LOOPBACK defined]) ;;
+ * )
+ # couldn't find it anywhere
+ AC_DEFINE(HAVE_NO_INADDR_LOOPBACK,[],
+ [Define if you don't have a definition of INADDR_LOOPBACK]) ;;
+ esac;;
+ esac
+fi
+])
+
+
+dnl ----------------------------------------------------------------------
+dnl
+dnl LM_STRUCT_SOCKADDR_SA_LEN
+dnl
+dnl Check if the sockaddr structure has the field sa_len
+dnl
+
+AC_DEFUN(LM_STRUCT_SOCKADDR_SA_LEN,
+[AC_CACHE_CHECK([whether struct sockaddr has sa_len field],
+ ac_cv_struct_sockaddr_sa_len,
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/socket.h>], [struct sockaddr s; s.sa_len = 10;],
+ ac_cv_struct_sockaddr_sa_len=yes, ac_cv_struct_sockaddr_sa_len=no))
+
+dnl FIXME convbreak
+case ${ac_cv_struct_sockaddr_sa_len} in
+ "no" ) AC_DEFINE(NO_SA_LEN,[1],[Define if you dont have salen]) ;;
+ *) ;;
+esac
+])
+
+dnl ----------------------------------------------------------------------
+dnl
+dnl LM_STRUCT_EXCEPTION
+dnl
+dnl Check to see whether the system supports the matherr function
+dnl and its associated type "struct exception".
+dnl
+
+AC_DEFUN(LM_STRUCT_EXCEPTION,
+[AC_CACHE_CHECK([for struct exception (and matherr function)],
+ ac_cv_struct_exception,
+AC_TRY_COMPILE([#include <math.h>],
+ [struct exception x; x.type = DOMAIN; x.type = SING;],
+ ac_cv_struct_exception=yes, ac_cv_struct_exception=no))
+
+case "${ac_cv_struct_exception}" in
+ "yes" ) AC_DEFINE(USE_MATHERR,[1],[Define if you have matherr() function and struct exception type]) ;;
+ * ) ;;
+esac
+])
+
+
+dnl ----------------------------------------------------------------------
+dnl
+dnl LM_SYS_IPV6
+dnl
+dnl Check for ipv6 support and what the in6_addr structure is called.
+dnl (early linux used in_addr6 insted of in6_addr)
+dnl
+
+AC_DEFUN(LM_SYS_IPV6,
+[AC_MSG_CHECKING(for IP version 6 support)
+AC_CACHE_VAL(ac_cv_sys_ipv6_support,
+[ok_so_far=yes
+ AC_TRY_COMPILE([#include <sys/types.h>
+#ifdef __WIN32__
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <netinet/in.h>
+#endif],
+ [struct in6_addr a6; struct sockaddr_in6 s6;], ok_so_far=yes, ok_so_far=no)
+
+if test $ok_so_far = yes; then
+ ac_cv_sys_ipv6_support=yes
+else
+ AC_TRY_COMPILE([#include <sys/types.h>
+#ifdef __WIN32__
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <netinet/in.h>
+#endif],
+ [struct in_addr6 a6; struct sockaddr_in6 s6;],
+ ac_cv_sys_ipv6_support=in_addr6, ac_cv_sys_ipv6_support=no)
+fi
+])dnl
+
+dnl
+dnl Have to use old style AC_DEFINE due to BC with old autoconf.
+dnl
+
+case ${ac_cv_sys_ipv6_support} in
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_IN6,[1],[Define if ipv6 is present])
+ ;;
+ in_addr6)
+ AC_MSG_RESULT([yes (but I am redefining in_addr6 to in6_addr)])
+ AC_DEFINE(HAVE_IN6,[1],[Define if ipv6 is present])
+ AC_DEFINE(HAVE_IN_ADDR6_STRUCT,[],[Early linux used in_addr6 instead of in6_addr, define if you have this])
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+esac
+])
+
+
+dnl ----------------------------------------------------------------------
+dnl
+dnl LM_SYS_MULTICAST
+dnl
+dnl Check for multicast support. Only checks for multicast options in
+dnl setsockopt(), no check is performed that multicasting actually works.
+dnl If options are found defines HAVE_MULTICAST_SUPPORT
+dnl
+
+AC_DEFUN(LM_SYS_MULTICAST,
+[AC_CACHE_CHECK([for multicast support], ac_cv_sys_multicast_support,
+[AC_EGREP_CPP(yes,
+[#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#if defined(IP_MULTICAST_TTL) && defined(IP_MULTICAST_LOOP) && defined(IP_MULTICAST_IF) && defined(IP_ADD_MEMBERSHIP) && defined(IP_DROP_MEMBERSHIP)
+yes
+#endif
+], ac_cv_sys_multicast_support=yes, ac_cv_sys_multicast_support=no)])
+if test $ac_cv_sys_multicast_support = yes; then
+ AC_DEFINE(HAVE_MULTICAST_SUPPORT,[1],
+ [Define if setsockopt() accepts multicast options])
+fi
+])dnl
+
+
+dnl ----------------------------------------------------------------------
+dnl
+dnl LM_DECL_SYS_ERRLIST
+dnl
+dnl Define SYS_ERRLIST_DECLARED if the variable sys_errlist is declared
+dnl in a system header file, stdio.h or errno.h.
+dnl
+
+AC_DEFUN(LM_DECL_SYS_ERRLIST,
+[AC_CACHE_CHECK([for sys_errlist declaration in stdio.h or errno.h],
+ ac_cv_decl_sys_errlist,
+[AC_TRY_COMPILE([#include <stdio.h>
+#include <errno.h>], [char *msg = *(sys_errlist + 1);],
+ ac_cv_decl_sys_errlist=yes, ac_cv_decl_sys_errlist=no)])
+if test $ac_cv_decl_sys_errlist = yes; then
+ AC_DEFINE(SYS_ERRLIST_DECLARED,[],
+ [define if the variable sys_errlist is declared in a system header file])
+fi
+])
+
+
+dnl ----------------------------------------------------------------------
+dnl
+dnl LM_CHECK_FUNC_DECL( funname, declaration [, extra includes
+dnl [, action-if-found [, action-if-not-found]]] )
+dnl
+dnl Checks if the declaration "declaration" of "funname" conflicts
+dnl with the header files idea of how the function should be
+dnl declared. It is useful on systems which lack prototypes and you
+dnl need to provide your own (e.g. when you want to take the address
+dnl of a function). The 4'th argument is expanded if conflicting,
+dnl the 5'th argument otherwise
+dnl
+dnl
+
+AC_DEFUN(LM_CHECK_FUNC_DECL,
+[AC_MSG_CHECKING([for conflicting declaration of $1])
+AC_CACHE_VAL(ac_cv_func_decl_$1,
+[AC_TRY_COMPILE([#include <stdio.h>
+$3],[$2
+char *c = (char *)$1;
+], eval "ac_cv_func_decl_$1=no", eval "ac_cv_func_decl_$1=yes")])
+if eval "test \"`echo '$ac_cv_func_decl_'$1`\" = yes"; then
+ AC_MSG_RESULT(yes)
+ ifelse([$4], , :, [$4])
+else
+ AC_MSG_RESULT(no)
+ifelse([$5], , , [$5
+])dnl
+fi
+])
+
+dnl ----------------------------------------------------------------------
+dnl
+dnl AC_DOUBLE_MIDDLE_ENDIAN
+dnl
+dnl Checks whether doubles are represented in "middle-endian" format.
+dnl Sets ac_cv_double_middle_endian={no,yes,unknown} accordingly,
+dnl as well as DOUBLE_MIDDLE_ENDIAN.
+dnl
+dnl
+
+AC_DEFUN([AC_C_DOUBLE_MIDDLE_ENDIAN],
+[AC_CACHE_CHECK(whether double word ordering is middle-endian, ac_cv_c_double_middle_endian,
+[# It does not; compile a test program.
+AC_RUN_IFELSE(
+[AC_LANG_SOURCE([[#include <stdlib.h>
+
+int
+main(void)
+{
+ int i = 0;
+ int zero = 0;
+ int bigendian;
+ int zero_index = 0;
+
+ union
+ {
+ long int l;
+ char c[sizeof (long int)];
+ } u;
+
+ /* we'll use the one with 32-bit words */
+ union
+ {
+ double d;
+ unsigned int c[2];
+ } vint;
+
+ union
+ {
+ double d;
+ unsigned long c[2];
+ } vlong;
+
+ union
+ {
+ double d;
+ unsigned short c[2];
+ } vshort;
+
+
+ /* Are we little or big endian? From Harbison&Steele. */
+ u.l = 1;
+ bigendian = (u.c[sizeof (long int) - 1] == 1);
+
+ zero_index = bigendian ? 1 : 0;
+
+ vint.d = 1.0;
+ vlong.d = 1.0;
+ vshort.d = 1.0;
+
+ if (sizeof(unsigned int) == 4)
+ {
+ if (vint.c[zero_index] != 0)
+ zero = 1;
+ }
+ else if (sizeof(unsigned long) == 4)
+ {
+ if (vlong.c[zero_index] != 0)
+ zero = 1;
+ }
+ else if (sizeof(unsigned short) == 4)
+ {
+ if (vshort.c[zero_index] != 0)
+ zero = 1;
+ }
+
+ exit (zero);
+}
+]])],
+ [ac_cv_c_double_middle_endian=no],
+ [ac_cv_c_double_middle_endian=yes],
+ [ac_cv_c_double_middle=unknown])])
+case $ac_cv_c_double_middle_endian in
+ yes)
+ m4_default([$1],
+ [AC_DEFINE([DOUBLE_MIDDLE_ENDIAN], 1,
+ [Define to 1 if your processor stores the words in a double in
+ middle-endian format (like some ARMs).])]) ;;
+ no)
+ $2 ;;
+ *)
+ m4_default([$3],
+ [AC_MSG_WARN([unknown double endianness
+presetting ac_cv_c_double_middle_endian=no (or yes) will help])]) ;;
+esac
+])# AC_C_DOUBLE_MIDDLE_ENDIAN
+
+
+dnl ----------------------------------------------------------------------
+dnl
+dnl LM_CHECK_THR_LIB
+dnl
+dnl This macro may be used by any OTP application.
+dnl
+dnl LM_CHECK_THR_LIB sets THR_LIBS, THR_DEFS, and THR_LIB_NAME. It also
+dnl checks for some pthread headers which will appear in DEFS or config.h.
+dnl
+
+AC_DEFUN(LM_CHECK_THR_LIB,
+[
+
+NEED_NPTL_PTHREAD_H=no
+
+dnl win32?
+AC_MSG_CHECKING([for native win32 threads])
+if test "X$host_os" = "Xwin32"; then
+ AC_MSG_RESULT(yes)
+ THR_DEFS="-DWIN32_THREADS"
+ THR_LIBS=
+ THR_LIB_NAME=win32_threads
+ THR_LIB_TYPE=win32_threads
+else
+ AC_MSG_RESULT(no)
+ THR_DEFS=
+ THR_LIBS=
+ THR_LIB_NAME=
+ THR_LIB_TYPE=posix_unknown
+
+dnl Try to find POSIX threads
+
+dnl The usual pthread lib...
+ AC_CHECK_LIB(pthread, pthread_create, THR_LIBS="-lpthread")
+
+dnl Very old versions of FreeBSD have pthreads in special c library, c_r...
+ if test "x$THR_LIBS" = "x"; then
+ AC_CHECK_LIB(c_r, pthread_create, THR_LIBS="-lc_r")
+ fi
+
+dnl QNX has pthreads in standard C library
+ if test "x$THR_LIBS" = "x"; then
+ AC_CHECK_FUNC(pthread_create, THR_LIBS="none_needed")
+ fi
+
+dnl On ofs1 the '-pthread' switch should be used
+ if test "x$THR_LIBS" = "x"; then
+ AC_MSG_CHECKING([if the '-pthread' switch can be used])
+ saved_cflags=$CFLAGS
+ CFLAGS="$CFLAGS -pthread"
+ AC_TRY_LINK([#include <pthread.h>],
+ pthread_create((void*)0,(void*)0,(void*)0,(void*)0);,
+ [THR_DEFS="-pthread"
+ THR_LIBS="-pthread"])
+ CFLAGS=$saved_cflags
+ if test "x$THR_LIBS" != "x"; then
+ AC_MSG_RESULT(yes)
+ else
+ AC_MSG_RESULT(no)
+ fi
+ fi
+
+ if test "x$THR_LIBS" != "x"; then
+ THR_DEFS="$THR_DEFS -D_THREAD_SAFE -D_REENTRANT -DPOSIX_THREADS"
+ THR_LIB_NAME=pthread
+ if test "x$THR_LIBS" = "xnone_needed"; then
+ THR_LIBS=
+ fi
+ case $host_os in
+ solaris*)
+ THR_DEFS="$THR_DEFS -D_POSIX_PTHREAD_SEMANTICS" ;;
+ linux*)
+ THR_DEFS="$THR_DEFS -D_POSIX_THREAD_SAFE_FUNCTIONS"
+
+ LM_CHECK_GETCONF
+ AC_MSG_CHECKING(for Native POSIX Thread Library)
+ libpthr_vsn=`$GETCONF GNU_LIBPTHREAD_VERSION 2>/dev/null`
+ if test $? -eq 0; then
+ case "$libpthr_vsn" in
+ *nptl*|*NPTL*) nptl=yes;;
+ *) nptl=no;;
+ esac
+ elif test "$cross_compiling" = "yes"; then
+ case "$erl_xcomp_linux_nptl" in
+ "") nptl=cross;;
+ yes|no) nptl=$erl_xcomp_linux_nptl;;
+ *) AC_MSG_ERROR([Bad erl_xcomp_linux_nptl value: $erl_xcomp_linux_nptl]);;
+ esac
+ else
+ nptl=no
+ fi
+ AC_MSG_RESULT($nptl)
+ if test $nptl = cross; then
+ nptl=yes
+ AC_MSG_WARN([result yes guessed because of cross compilation])
+ fi
+ if test $nptl = yes; then
+ THR_LIB_TYPE=posix_nptl
+ need_nptl_incldir=no
+ AC_CHECK_HEADER(nptl/pthread.h,
+ [need_nptl_incldir=yes
+ NEED_NPTL_PTHREAD_H=yes])
+ if test $need_nptl_incldir = yes; then
+ # Ahh...
+ nptl_path="$C_INCLUDE_PATH:$CPATH"
+ if test X$cross_compiling != Xyes; then
+ nptl_path="$nptl_path:/usr/local/include:/usr/include"
+ else
+ IROOT="$erl_xcomp_isysroot"
+ test "$IROOT" != "" || IROOT="$erl_xcomp_sysroot"
+ test "$IROOT" != "" || AC_MSG_ERROR([Don't know where to search for includes! Please set erl_xcomp_isysroot])
+ nptl_path="$nptl_path:$IROOT/usr/local/include:$IROOT/usr/include"
+ fi
+ nptl_ws_path=
+ save_ifs="$IFS"; IFS=":"
+ for dir in $nptl_path; do
+ if test "x$dir" != "x"; then
+ nptl_ws_path="$nptl_ws_path $dir"
+ fi
+ done
+ IFS=$save_ifs
+ nptl_incldir=
+ for dir in $nptl_ws_path; do
+ AC_CHECK_HEADER($dir/nptl/pthread.h,
+ nptl_incldir=$dir/nptl)
+ if test "x$nptl_incldir" != "x"; then
+ THR_DEFS="$THR_DEFS -isystem $nptl_incldir"
+ break
+ fi
+ done
+ if test "x$nptl_incldir" = "x"; then
+ AC_MSG_ERROR(Failed to locate nptl system include directory)
+ fi
+ fi
+ fi
+ ;;
+ *) ;;
+ esac
+
+ dnl We sometimes need THR_DEFS in order to find certain headers
+ dnl (at least for pthread.h on osf1).
+ saved_cppflags=$CPPFLAGS
+ CPPFLAGS="$CPPFLAGS $THR_DEFS"
+
+ dnl
+ dnl Check for headers
+ dnl
+
+ AC_CHECK_HEADER(pthread.h,
+ AC_DEFINE(HAVE_PTHREAD_H, 1, \
+[Define if you have the <pthread.h> header file.]))
+
+ dnl Some Linuxes have <pthread/mit/pthread.h> instead of <pthread.h>
+ AC_CHECK_HEADER(pthread/mit/pthread.h, \
+ AC_DEFINE(HAVE_MIT_PTHREAD_H, 1, \
+[Define if the pthread.h header file is in pthread/mit directory.]))
+
+ dnl restore CPPFLAGS
+ CPPFLAGS=$saved_cppflags
+
+ fi
+fi
+
+])
+
+AC_DEFUN(ERL_INTERNAL_LIBS,
+[
+
+ERTS_INTERNAL_X_LIBS=
+
+AC_CHECK_LIB(kstat, kstat_open,
+[AC_DEFINE(HAVE_KSTAT, 1, [Define if you have kstat])
+ERTS_INTERNAL_X_LIBS="$ERTS_INTERNAL_X_LIBS -lkstat"])
+
+AC_SUBST(ERTS_INTERNAL_X_LIBS)
+
+])
+
+AC_DEFUN(ETHR_CHK_SYNC_OP,
+[
+ AC_MSG_CHECKING([for $3-bit $1()])
+ case "$2" in
+ "1") sync_call="$1(&var);";;
+ "2") sync_call="$1(&var, ($4) 0);";;
+ "3") sync_call="$1(&var, ($4) 0, ($4) 0);";;
+ esac
+ have_sync_op=no
+ AC_TRY_LINK([],
+ [
+ $4 res;
+ volatile $4 var;
+ res = $sync_call
+ ],
+ [have_sync_op=yes])
+ test $have_sync_op = yes && $5
+ AC_MSG_RESULT([$have_sync_op])
+])
+
+AC_DEFUN(ETHR_CHK_INTERLOCKED,
+[
+ ilckd="$1"
+ AC_MSG_CHECKING([for ${ilckd}()])
+ case "$2" in
+ "1") ilckd_call="${ilckd}(var);";;
+ "2") ilckd_call="${ilckd}(var, ($3) 0);";;
+ "3") ilckd_call="${ilckd}(var, ($3) 0, ($3) 0);";;
+ "4") ilckd_call="${ilckd}(var, ($3) 0, ($3) 0, arr);";;
+ esac
+ have_interlocked_op=no
+ AC_TRY_LINK(
+ [
+ #define WIN32_LEAN_AND_MEAN
+ #include <windows.h>
+ #include <intrin.h>
+ ],
+ [
+ volatile $3 *var;
+ volatile $3 arr[2];
+
+ $ilckd_call
+ return 0;
+ ],
+ [have_interlocked_op=yes])
+ test $have_interlocked_op = yes && $4
+ AC_MSG_RESULT([$have_interlocked_op])
+])
+
+dnl ----------------------------------------------------------------------
+dnl
+dnl ERL_FIND_ETHR_LIB
+dnl
+dnl NOTE! This macro may be changed at any time! Should *only* be used by
+dnl ERTS!
+dnl
+dnl Find a thread library to use. Sets ETHR_LIBS to libraries to link
+dnl with, ETHR_X_LIBS to extra libraries to link with (same as ETHR_LIBS
+dnl except that the ethread lib itself is not included), ETHR_DEFS to
+dnl defines to compile with, ETHR_THR_LIB_BASE to the name of the
+dnl thread library which the ethread library is based on, and ETHR_LIB_NAME
+dnl to the name of the library where the ethread implementation is located.
+dnl ERL_FIND_ETHR_LIB currently searches for 'pthreads', and
+dnl 'win32_threads'. If no thread library was found ETHR_LIBS, ETHR_X_LIBS,
+dnl ETHR_DEFS, ETHR_THR_LIB_BASE, and ETHR_LIB_NAME are all set to the
+dnl empty string.
+dnl
+
+AC_DEFUN(ERL_FIND_ETHR_LIB,
+[
+
+LM_CHECK_THR_LIB
+ERL_INTERNAL_LIBS
+
+ethr_have_native_atomics=no
+ethr_have_native_spinlock=no
+ETHR_THR_LIB_BASE="$THR_LIB_NAME"
+ETHR_THR_LIB_BASE_TYPE="$THR_LIB_TYPE"
+ETHR_DEFS="$THR_DEFS"
+ETHR_X_LIBS="$THR_LIBS $ERTS_INTERNAL_X_LIBS"
+ETHR_LIBS=
+ETHR_LIB_NAME=
+
+ethr_modified_default_stack_size=
+
+dnl Name of lib where ethread implementation is located
+ethr_lib_name=ethread
+
+case "$THR_LIB_NAME" in
+
+ win32_threads)
+ ETHR_THR_LIB_BASE_DIR=win
+ # * _WIN32_WINNT >= 0x0400 is needed for
+ # TryEnterCriticalSection
+ # * _WIN32_WINNT >= 0x0403 is needed for
+ # InitializeCriticalSectionAndSpinCount
+ # The ethread lib will refuse to build if _WIN32_WINNT < 0x0403.
+ #
+ # -D_WIN32_WINNT should have been defined in $CPPFLAGS; fetch it
+ # and save it in ETHR_DEFS.
+ found_win32_winnt=no
+ for cppflag in $CPPFLAGS; do
+ case $cppflag in
+ -DWINVER*)
+ ETHR_DEFS="$ETHR_DEFS $cppflag"
+ ;;
+ -D_WIN32_WINNT*)
+ ETHR_DEFS="$ETHR_DEFS $cppflag"
+ found_win32_winnt=yes
+ ;;
+ *)
+ ;;
+ esac
+ done
+ if test $found_win32_winnt = no; then
+ AC_MSG_ERROR([-D_WIN32_WINNT missing in CPPFLAGS])
+ fi
+
+ AC_DEFINE(ETHR_WIN32_THREADS, 1, [Define if you have win32 threads])
+
+ ETHR_CHK_INTERLOCKED([_InterlockedDecrement], [1], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDDECREMENT, 1, [Define if you have _InterlockedDecrement()]))
+ ETHR_CHK_INTERLOCKED([_InterlockedDecrement_rel], [1], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDDECREMENT_REL, 1, [Define if you have _InterlockedDecrement_rel()]))
+ ETHR_CHK_INTERLOCKED([_InterlockedIncrement], [1], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDINCREMENT, 1, [Define if you have _InterlockedIncrement()]))
+ ETHR_CHK_INTERLOCKED([_InterlockedIncrement_acq], [1], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDINCREMENT_ACQ, 1, [Define if you have _InterlockedIncrement_acq()]))
+ ETHR_CHK_INTERLOCKED([_InterlockedExchangeAdd], [2], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDEXCHANGEADD, 1, [Define if you have _InterlockedExchangeAdd()]))
+ ETHR_CHK_INTERLOCKED([_InterlockedExchangeAdd_acq], [2], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDEXCHANGEADD_ACQ, 1, [Define if you have _InterlockedExchangeAdd_acq()]))
+ ETHR_CHK_INTERLOCKED([_InterlockedAnd], [2], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDAND, 1, [Define if you have _InterlockedAnd()]))
+ ETHR_CHK_INTERLOCKED([_InterlockedOr], [2], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDOR, 1, [Define if you have _InterlockedOr()]))
+ ETHR_CHK_INTERLOCKED([_InterlockedExchange], [2], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDEXCHANGE, 1, [Define if you have _InterlockedExchange()]))
+ ETHR_CHK_INTERLOCKED([_InterlockedCompareExchange], [3], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE, 1, [Define if you have _InterlockedCompareExchange()]))
+ test "$have_interlocked_op" = "yes" && ethr_have_native_atomics=yes
+ ETHR_CHK_INTERLOCKED([_InterlockedCompareExchange_acq], [3], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE_ACQ, 1, [Define if you have _InterlockedCompareExchange_acq()]))
+ test "$have_interlocked_op" = "yes" && ethr_have_native_atomics=yes
+ ETHR_CHK_INTERLOCKED([_InterlockedCompareExchange_rel], [3], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE_REL, 1, [Define if you have _InterlockedCompareExchange_rel()]))
+ test "$have_interlocked_op" = "yes" && ethr_have_native_atomics=yes
+
+ ETHR_CHK_INTERLOCKED([_InterlockedDecrement64], [1], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDDECREMENT64, 1, [Define if you have _InterlockedDecrement64()]))
+ ETHR_CHK_INTERLOCKED([_InterlockedDecrement64_rel], [1], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDDECREMENT64_REL, 1, [Define if you have _InterlockedDecrement64_rel()]))
+ ETHR_CHK_INTERLOCKED([_InterlockedIncrement64], [1], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDINCREMENT64, 1, [Define if you have _InterlockedIncrement64()]))
+ ETHR_CHK_INTERLOCKED([_InterlockedIncrement64_acq], [1], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDINCREMENT64_ACQ, 1, [Define if you have _InterlockedIncrement64_acq()]))
+ ETHR_CHK_INTERLOCKED([_InterlockedExchangeAdd64], [2], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDEXCHANGEADD64, 1, [Define if you have _InterlockedExchangeAdd64()]))
+ ETHR_CHK_INTERLOCKED([_InterlockedExchangeAdd64_acq], [2], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDEXCHANGEADD64_ACQ, 1, [Define if you have _InterlockedExchangeAdd64_acq()]))
+ ETHR_CHK_INTERLOCKED([_InterlockedAnd64], [2], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDAND64, 1, [Define if you have _InterlockedAnd64()]))
+ ETHR_CHK_INTERLOCKED([_InterlockedOr64], [2], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDOR64, 1, [Define if you have _InterlockedOr64()]))
+ ETHR_CHK_INTERLOCKED([_InterlockedExchange64], [2], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDEXCHANGE64, 1, [Define if you have _InterlockedExchange64()]))
+ ETHR_CHK_INTERLOCKED([_InterlockedCompareExchange64], [3], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE64, 1, [Define if you have _InterlockedCompareExchange64()]))
+ test "$have_interlocked_op" = "yes" && ethr_have_native_atomics=yes
+ ETHR_CHK_INTERLOCKED([_InterlockedCompareExchange64_acq], [3], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_ACQ, 1, [Define if you have _InterlockedCompareExchange64_acq()]))
+ test "$have_interlocked_op" = "yes" && ethr_have_native_atomics=yes
+ ETHR_CHK_INTERLOCKED([_InterlockedCompareExchange64_rel], [3], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_REL, 1, [Define if you have _InterlockedCompareExchange64_rel()]))
+ test "$have_interlocked_op" = "yes" && ethr_have_native_atomics=yes
+
+ ETHR_CHK_INTERLOCKED([_InterlockedCompareExchange128], [4], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE128, 1, [Define if you have _InterlockedCompareExchange128()]))
+
+ test "$ethr_have_native_atomics" = "yes" && ethr_have_native_spinlock=yes
+ ;;
+
+ pthread)
+ ETHR_THR_LIB_BASE_DIR=pthread
+ AC_DEFINE(ETHR_PTHREADS, 1, [Define if you have pthreads])
+ case $host_os in
+ openbsd*)
+ # The default stack size is insufficient for our needs
+ # on OpenBSD. We increase it to 256 kilo words.
+ ethr_modified_default_stack_size=256;;
+ linux*)
+ ETHR_DEFS="$ETHR_DEFS -D_GNU_SOURCE"
+
+ if test X$cross_compiling = Xyes; then
+ case X$erl_xcomp_linux_usable_sigusrx in
+ X) usable_sigusrx=cross;;
+ Xyes|Xno) usable_sigusrx=$erl_xcomp_linux_usable_sigusrx;;
+ *) AC_MSG_ERROR([Bad erl_xcomp_linux_usable_sigusrx value: $erl_xcomp_linux_usable_sigusrx]);;
+ esac
+ case X$erl_xcomp_linux_usable_sigaltstack in
+ X) usable_sigaltstack=cross;;
+ Xyes|Xno) usable_sigaltstack=$erl_xcomp_linux_usable_sigaltstack;;
+ *) AC_MSG_ERROR([Bad erl_xcomp_linux_usable_sigaltstack value: $erl_xcomp_linux_usable_sigaltstack]);;
+ esac
+ else
+ # FIXME: Test for actual problems instead of kernel versions
+ linux_kernel_vsn_=`uname -r`
+ case $linux_kernel_vsn_ in
+ [[0-1]].*|2.[[0-1]]|2.[[0-1]].*)
+ usable_sigusrx=no
+ usable_sigaltstack=no;;
+ 2.[[2-3]]|2.[[2-3]].*)
+ usable_sigusrx=yes
+ usable_sigaltstack=no;;
+ *)
+ usable_sigusrx=yes
+ usable_sigaltstack=yes;;
+ esac
+ fi
+
+ AC_MSG_CHECKING(if SIGUSR1 and SIGUSR2 can be used)
+ AC_MSG_RESULT($usable_sigusrx)
+ if test $usable_sigusrx = cross; then
+ usable_sigusrx=yes
+ AC_MSG_WARN([result yes guessed because of cross compilation])
+ fi
+ if test $usable_sigusrx = no; then
+ ETHR_DEFS="$ETHR_DEFS -DETHR_UNUSABLE_SIGUSRX"
+ fi
+
+ AC_MSG_CHECKING(if sigaltstack can be used)
+ AC_MSG_RESULT($usable_sigaltstack)
+ if test $usable_sigaltstack = cross; then
+ usable_sigaltstack=yes
+ AC_MSG_WARN([result yes guessed because of cross compilation])
+ fi
+ if test $usable_sigaltstack = no; then
+ ETHR_DEFS="$ETHR_DEFS -DETHR_UNUSABLE_SIGALTSTACK"
+ fi
+ ;;
+ *) ;;
+ esac
+
+ dnl We sometimes need ETHR_DEFS in order to find certain headers
+ dnl (at least for pthread.h on osf1).
+ saved_cppflags="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $ETHR_DEFS"
+
+ dnl We need the thread library in order to find some functions
+ saved_libs="$LIBS"
+ LIBS="$LIBS $ETHR_X_LIBS"
+
+ dnl
+ dnl Check for headers
+ dnl
+
+ AC_CHECK_HEADER(pthread.h, \
+ AC_DEFINE(ETHR_HAVE_PTHREAD_H, 1, \
+[Define if you have the <pthread.h> header file.]))
+
+ dnl Some Linuxes have <pthread/mit/pthread.h> instead of <pthread.h>
+ AC_CHECK_HEADER(pthread/mit/pthread.h, \
+ AC_DEFINE(ETHR_HAVE_MIT_PTHREAD_H, 1, \
+[Define if the pthread.h header file is in pthread/mit directory.]))
+
+ if test $NEED_NPTL_PTHREAD_H = yes; then
+ AC_DEFINE(ETHR_NEED_NPTL_PTHREAD_H, 1, \
+[Define if you need the <nptl/pthread.h> header file.])
+ fi
+
+ AC_CHECK_HEADER(sched.h, \
+ AC_DEFINE(ETHR_HAVE_SCHED_H, 1, \
+[Define if you have the <sched.h> header file.]))
+
+ AC_CHECK_HEADER(sys/time.h, \
+ AC_DEFINE(ETHR_HAVE_SYS_TIME_H, 1, \
+[Define if you have the <sys/time.h> header file.]))
+
+ AC_TRY_COMPILE([#include <time.h>
+ #include <sys/time.h>],
+ [struct timeval *tv; return 0;],
+ AC_DEFINE(ETHR_TIME_WITH_SYS_TIME, 1, \
+[Define if you can safely include both <sys/time.h> and <time.h>.]))
+
+
+ dnl
+ dnl Check for functions
+ dnl
+
+ AC_CHECK_FUNC(pthread_spin_lock, \
+ [ethr_have_native_spinlock=yes \
+ AC_DEFINE(ETHR_HAVE_PTHREAD_SPIN_LOCK, 1, \
+[Define if you have the pthread_spin_lock function.])])
+
+ have_sched_yield=no
+ have_librt_sched_yield=no
+ AC_CHECK_FUNC(sched_yield, [have_sched_yield=yes])
+ if test $have_sched_yield = no; then
+ AC_CHECK_LIB(rt, sched_yield,
+ [have_librt_sched_yield=yes
+ ETHR_X_LIBS="$ETHR_X_LIBS -lrt"])
+ fi
+ if test $have_sched_yield = yes || test $have_librt_sched_yield = yes; then
+ AC_DEFINE(ETHR_HAVE_SCHED_YIELD, 1, [Define if you have the sched_yield() function.])
+ AC_MSG_CHECKING([whether sched_yield() returns an int])
+ sched_yield_ret_int=no
+ AC_TRY_COMPILE([
+ #ifdef ETHR_HAVE_SCHED_H
+ #include <sched.h>
+ #endif
+ ],
+ [int sched_yield();],
+ [sched_yield_ret_int=yes])
+ AC_MSG_RESULT([$sched_yield_ret_int])
+ if test $sched_yield_ret_int = yes; then
+ AC_DEFINE(ETHR_SCHED_YIELD_RET_INT, 1, [Define if sched_yield() returns an int.])
+ fi
+ fi
+
+ have_pthread_yield=no
+ AC_CHECK_FUNC(pthread_yield, [have_pthread_yield=yes])
+ if test $have_pthread_yield = yes; then
+ AC_DEFINE(ETHR_HAVE_PTHREAD_YIELD, 1, [Define if you have the pthread_yield() function.])
+ AC_MSG_CHECKING([whether pthread_yield() returns an int])
+ pthread_yield_ret_int=no
+ AC_TRY_COMPILE([
+ #if defined(ETHR_NEED_NPTL_PTHREAD_H)
+ #include <nptl/pthread.h>
+ #elif defined(ETHR_HAVE_MIT_PTHREAD_H)
+ #include <pthread/mit/pthread.h>
+ #elif defined(ETHR_HAVE_PTHREAD_H)
+ #include <pthread.h>
+ #endif
+ ],
+ [int pthread_yield();],
+ [pthread_yield_ret_int=yes])
+ AC_MSG_RESULT([$pthread_yield_ret_int])
+ if test $pthread_yield_ret_int = yes; then
+ AC_DEFINE(ETHR_PTHREAD_YIELD_RET_INT, 1, [Define if pthread_yield() returns an int.])
+ fi
+ fi
+
+ have_pthread_rwlock_init=no
+ AC_CHECK_FUNC(pthread_rwlock_init, [have_pthread_rwlock_init=yes])
+ if test $have_pthread_rwlock_init = yes; then
+
+ ethr_have_pthread_rwlockattr_setkind_np=no
+ AC_CHECK_FUNC(pthread_rwlockattr_setkind_np,
+ [ethr_have_pthread_rwlockattr_setkind_np=yes])
+
+ if test $ethr_have_pthread_rwlockattr_setkind_np = yes; then
+ AC_DEFINE(ETHR_HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP, 1, \
+[Define if you have the pthread_rwlockattr_setkind_np() function.])
+
+ AC_MSG_CHECKING([for PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP])
+ ethr_pthread_rwlock_writer_nonrecursive_initializer_np=no
+ AC_TRY_LINK([
+ #if defined(ETHR_NEED_NPTL_PTHREAD_H)
+ #include <nptl/pthread.h>
+ #elif defined(ETHR_HAVE_MIT_PTHREAD_H)
+ #include <pthread/mit/pthread.h>
+ #elif defined(ETHR_HAVE_PTHREAD_H)
+ #include <pthread.h>
+ #endif
+ ],
+ [
+ pthread_rwlockattr_t *attr;
+ return pthread_rwlockattr_setkind_np(attr,
+ PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
+ ],
+ [ethr_pthread_rwlock_writer_nonrecursive_initializer_np=yes])
+ AC_MSG_RESULT([$ethr_pthread_rwlock_writer_nonrecursive_initializer_np])
+ if test $ethr_pthread_rwlock_writer_nonrecursive_initializer_np = yes; then
+ AC_DEFINE(ETHR_HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, 1, \
+[Define if you have the PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP rwlock attribute.])
+ fi
+ fi
+ fi
+
+ if test "$force_pthread_rwlocks" = "yes"; then
+
+ AC_DEFINE(ETHR_FORCE_PTHREAD_RWLOCK, 1, \
+[Define if you want to force usage of pthread rwlocks])
+
+ if test $have_pthread_rwlock_init = yes; then
+ AC_MSG_WARN([Forced usage of pthread rwlocks. Note that this implementation may suffer from starvation issues.])
+ else
+ AC_MSG_ERROR([User forced usage of pthread rwlock, but no such implementation was found])
+ fi
+ fi
+
+ AC_CHECK_FUNC(pthread_attr_setguardsize, \
+ AC_DEFINE(ETHR_HAVE_PTHREAD_ATTR_SETGUARDSIZE, 1, \
+[Define if you have the pthread_attr_setguardsize function.]))
+
+ linux_futex=no
+ AC_MSG_CHECKING([for Linux futexes])
+ AC_TRY_LINK([
+ #include <sys/syscall.h>
+ #include <unistd.h>
+ #include <linux/futex.h>
+ #include <sys/time.h>
+ ],
+ [
+ int i = 1;
+ syscall(__NR_futex, (void *) &i, FUTEX_WAKE, 1,
+ (void*)0,(void*)0, 0);
+ syscall(__NR_futex, (void *) &i, FUTEX_WAIT, 0,
+ (void*)0,(void*)0, 0);
+ return 0;
+ ],
+ linux_futex=yes)
+ AC_MSG_RESULT([$linux_futex])
+ test $linux_futex = yes && AC_DEFINE(ETHR_HAVE_LINUX_FUTEX, 1, [Define if you have a linux futex implementation.])
+
+ AC_CHECK_SIZEOF(int)
+ AC_CHECK_SIZEOF(long)
+ AC_CHECK_SIZEOF(long long)
+ AC_CHECK_SIZEOF(__int128_t)
+
+ if test "$ac_cv_sizeof_int" = "4"; then
+ int32="int"
+ elif test "$ac_cv_sizeof_long" = "4"; then
+ int32="long"
+ elif test "$ac_cv_sizeof_long_long" = "4"; then
+ int32="long long"
+ else
+ AC_MSG_ERROR([No 32-bit type found])
+ fi
+
+ if test "$ac_cv_sizeof_int" = "8"; then
+ int64="int"
+ elif test "$ac_cv_sizeof_long" = "8"; then
+ int64="long"
+ elif test "$ac_cv_sizeof_long_long" = "8"; then
+ int64="long long"
+ else
+ AC_MSG_ERROR([No 64-bit type found])
+ fi
+
+ int128=no
+ if test "$ac_cv_sizeof___int128_t" = "16"; then
+ int128="__int128_t"
+ fi
+
+ ETHR_CHK_SYNC_OP([__sync_val_compare_and_swap], [3], [32], [$int32], AC_DEFINE(ETHR_HAVE___SYNC_VAL_COMPARE_AND_SWAP32, 1, [Define if you have __sync_val_compare_and_swap() for 32-bit integers]))
+ test "$have_sync_op" = "yes" && ethr_have_native_atomics=yes
+ ETHR_CHK_SYNC_OP([__sync_add_and_fetch], [2], [32], [$int32], AC_DEFINE(ETHR_HAVE___SYNC_ADD_AND_FETCH32, 1, [Define if you have __sync_add_and_fetch() for 32-bit integers]))
+ ETHR_CHK_SYNC_OP([__sync_fetch_and_and], [2], [32], [$int32], AC_DEFINE(ETHR_HAVE___SYNC_FETCH_AND_AND32, 1, [Define if you have __sync_fetch_and_and() for 32-bit integers]))
+ ETHR_CHK_SYNC_OP([__sync_fetch_and_or], [2], [32], [$int32], AC_DEFINE(ETHR_HAVE___SYNC_FETCH_AND_OR32, 1, [Define if you have __sync_fetch_and_or() for 32-bit integers]))
+
+ ETHR_CHK_SYNC_OP([__sync_val_compare_and_swap], [3], [64], [$int64], AC_DEFINE(ETHR_HAVE___SYNC_VAL_COMPARE_AND_SWAP64, 1, [Define if you have __sync_val_compare_and_swap() for 64-bit integers]))
+ test "$have_sync_op" = "yes" && ethr_have_native_atomics=yes
+ ETHR_CHK_SYNC_OP([__sync_add_and_fetch], [2], [64], [$int64], AC_DEFINE(ETHR_HAVE___SYNC_ADD_AND_FETCH64, 1, [Define if you have __sync_add_and_fetch() for 64-bit integers]))
+ ETHR_CHK_SYNC_OP([__sync_fetch_and_and], [2], [64], [$int64], AC_DEFINE(ETHR_HAVE___SYNC_FETCH_AND_AND64, 1, [Define if you have __sync_fetch_and_and() for 64-bit integers]))
+ ETHR_CHK_SYNC_OP([__sync_fetch_and_or], [2], [64], [$int64], AC_DEFINE(ETHR_HAVE___SYNC_FETCH_AND_OR64, 1, [Define if you have __sync_fetch_and_or() for 64-bit integers]))
+
+ if test $int128 != no; then
+ ETHR_CHK_SYNC_OP([__sync_val_compare_and_swap], [3], [128], [$int128], AC_DEFINE(ETHR_HAVE___SYNC_VAL_COMPARE_AND_SWAP128, 1, [Define if you have __sync_val_compare_and_swap() for 128-bit integers]))
+ fi
+
+ AC_MSG_CHECKING([for a usable libatomic_ops implementation])
+ case "x$with_libatomic_ops" in
+ xno | xyes | x)
+ libatomic_ops_include=
+ ;;
+ *)
+ if test -d "${with_libatomic_ops}/include"; then
+ libatomic_ops_include="-I$with_libatomic_ops/include"
+ CPPFLAGS="$CPPFLAGS $libatomic_ops_include"
+ else
+ AC_MSG_ERROR([libatomic_ops include directory $with_libatomic_ops/include not found])
+ fi;;
+ esac
+ ethr_have_libatomic_ops=no
+ AC_TRY_LINK([#include "atomic_ops.h"],
+ [
+ volatile AO_t x;
+ AO_t y;
+ int z;
+
+ AO_nop_full();
+ AO_store(&x, (AO_t) 0);
+ z = AO_load(&x);
+ z = AO_compare_and_swap_full(&x, (AO_t) 0, (AO_t) 1);
+ ],
+ [ethr_have_native_atomics=yes
+ ethr_have_libatomic_ops=yes])
+ AC_MSG_RESULT([$ethr_have_libatomic_ops])
+ if test $ethr_have_libatomic_ops = yes; then
+ AC_CHECK_SIZEOF(AO_t, ,
+ [
+ #include <stdio.h>
+ #include "atomic_ops.h"
+ ])
+ AC_DEFINE_UNQUOTED(ETHR_SIZEOF_AO_T, $ac_cv_sizeof_AO_t, [Define to the size of AO_t if libatomic_ops is used])
+
+ AC_DEFINE(ETHR_HAVE_LIBATOMIC_OPS, 1, [Define if you have libatomic_ops atomic operations])
+ if test "x$with_libatomic_ops" != "xno" && test "x$with_libatomic_ops" != "x"; then
+ AC_DEFINE(ETHR_PREFER_LIBATOMIC_OPS_NATIVE_IMPLS, 1, [Define if you prefer libatomic_ops native ethread implementations])
+ fi
+ ETHR_DEFS="$ETHR_DEFS $libatomic_ops_include"
+ elif test "x$with_libatomic_ops" != "xno" && test "x$with_libatomic_ops" != "x"; then
+ AC_MSG_ERROR([No usable libatomic_ops implementation found])
+ fi
+
+ case "$host_cpu" in
+ sparc | sun4u | sparc64 | sun4v)
+ case "$with_sparc_memory_order" in
+ "TSO")
+ AC_DEFINE(ETHR_SPARC_TSO, 1, [Define if only run in Sparc TSO mode]);;
+ "PSO")
+ AC_DEFINE(ETHR_SPARC_PSO, 1, [Define if only run in Sparc PSO, or TSO mode]);;
+ "RMO"|"")
+ AC_DEFINE(ETHR_SPARC_RMO, 1, [Define if run in Sparc RMO, PSO, or TSO mode]);;
+ *)
+ AC_MSG_ERROR([Unsupported Sparc memory order: $with_sparc_memory_order]);;
+ esac
+ ethr_have_native_atomics=yes;;
+ i86pc | i*86 | x86_64 | amd64)
+ if test "$enable_x86_out_of_order" = "yes"; then
+ AC_DEFINE(ETHR_X86_OUT_OF_ORDER, 1, [Define if x86/x86_64 out of order instructions should be synchronized])
+ fi
+ ethr_have_native_atomics=yes;;
+ macppc | ppc | "Power Macintosh")
+ ethr_have_native_atomics=yes;;
+ tile)
+ ethr_have_native_atomics=yes;;
+ *)
+ ;;
+ esac
+
+ test ethr_have_native_atomics = "yes" && ethr_have_native_spinlock=yes
+
+ dnl Restore LIBS
+ LIBS=$saved_libs
+ dnl restore CPPFLAGS
+ CPPFLAGS=$saved_cppflags
+
+ ;;
+ *)
+ ;;
+esac
+
+AC_MSG_CHECKING([whether default stack size should be modified])
+if test "x$ethr_modified_default_stack_size" != "x"; then
+ AC_DEFINE_UNQUOTED(ETHR_MODIFIED_DEFAULT_STACK_SIZE, $ethr_modified_default_stack_size, [Define if you want to modify the default stack size])
+ AC_MSG_RESULT([yes; to $ethr_modified_default_stack_size kilo words])
+else
+ AC_MSG_RESULT([no])
+fi
+
+if test "x$ETHR_THR_LIB_BASE" != "x"; then
+ ETHR_DEFS="-DUSE_THREADS $ETHR_DEFS"
+ ETHR_LIBS="-l$ethr_lib_name -lerts_internal_r $ETHR_X_LIBS"
+ ETHR_LIB_NAME=$ethr_lib_name
+fi
+
+AC_CHECK_SIZEOF(void *)
+AC_DEFINE_UNQUOTED(ETHR_SIZEOF_PTR, $ac_cv_sizeof_void_p, [Define to the size of pointers])
+
+AC_CHECK_SIZEOF(int)
+AC_DEFINE_UNQUOTED(ETHR_SIZEOF_INT, $ac_cv_sizeof_int, [Define to the size of int])
+AC_CHECK_SIZEOF(long)
+AC_DEFINE_UNQUOTED(ETHR_SIZEOF_LONG, $ac_cv_sizeof_long, [Define to the size of long])
+AC_CHECK_SIZEOF(long long)
+AC_DEFINE_UNQUOTED(ETHR_SIZEOF_LONG_LONG, $ac_cv_sizeof_long_long, [Define to the size of long long])
+AC_CHECK_SIZEOF(__int64)
+AC_DEFINE_UNQUOTED(ETHR_SIZEOF___INT64, $ac_cv_sizeof___int64, [Define to the size of __int64])
+AC_CHECK_SIZEOF(__int128_t)
+AC_DEFINE_UNQUOTED(ETHR_SIZEOF___INT128_T, $ac_cv_sizeof___int128_t, [Define to the size of __int128_t])
+
+
+case X$erl_xcomp_bigendian in
+ X) ;;
+ Xyes|Xno) ac_cv_c_bigendian=$erl_xcomp_bigendian;;
+ *) AC_MSG_ERROR([Bad erl_xcomp_bigendian value: $erl_xcomp_bigendian]);;
+esac
+
+AC_C_BIGENDIAN
+
+if test "$ac_cv_c_bigendian" = "yes"; then
+ AC_DEFINE(ETHR_BIGENDIAN, 1, [Define if bigendian])
+fi
+
+case X$erl_xcomp_double_middle_endian in
+ X) ;;
+ Xyes|Xno|Xunknown) ac_cv_c_double_middle_endian=$erl_xcomp_double_middle_endian;;
+ *) AC_MSG_ERROR([Bad erl_xcomp_double_middle_endian value: $erl_xcomp_double_middle_endian]);;
+esac
+
+AC_C_DOUBLE_MIDDLE_ENDIAN
+
+AC_ARG_ENABLE(native-ethr-impls,
+ AS_HELP_STRING([--disable-native-ethr-impls],
+ [disable native ethread implementations]),
+[ case "$enableval" in
+ no) disable_native_ethr_impls=yes ;;
+ *) disable_native_ethr_impls=no ;;
+ esac ], disable_native_ethr_impls=no)
+
+AC_ARG_ENABLE(x86-out-of-order,
+ AS_HELP_STRING([--enable-x86-out-of-order],
+ [enable x86/x84_64 out of order support (default disabled)]))
+
+test "X$disable_native_ethr_impls" = "Xyes" &&
+ AC_DEFINE(ETHR_DISABLE_NATIVE_IMPLS, 1, [Define if you want to disable native ethread implementations])
+
+AC_ARG_ENABLE(prefer-gcc-native-ethr-impls,
+ AS_HELP_STRING([--enable-prefer-gcc-native-ethr-impls],
+ [prefer gcc native ethread implementations]),
+[ case "$enableval" in
+ yes) enable_prefer_gcc_native_ethr_impls=yes ;;
+ *) enable_prefer_gcc_native_ethr_impls=no ;;
+ esac ], enable_prefer_gcc_native_ethr_impls=no)
+
+test $enable_prefer_gcc_native_ethr_impls = yes &&
+ AC_DEFINE(ETHR_PREFER_GCC_NATIVE_IMPLS, 1, [Define if you prefer gcc native ethread implementations])
+
+AC_ARG_WITH(libatomic_ops,
+ AS_HELP_STRING([--with-libatomic_ops=PATH],
+ [specify and prefer usage of libatomic_ops in the ethread library]))
+
+AC_ARG_WITH(with_sparc_memory_order,
+ AS_HELP_STRING([--with-sparc-memory-order=TSO|PSO|RMO],
+ [specify sparc memory order (defaults to RMO)]))
+
+ETHR_X86_SSE2_ASM=no
+case "$GCC-$ac_cv_sizeof_void_p-$host_cpu" in
+ yes-4-i86pc | yes-4-i*86 | yes-4-x86_64 | yes-4-amd64)
+ AC_MSG_CHECKING([for gcc sse2 asm support])
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -msse2"
+ gcc_sse2_asm=no
+ AC_TRY_COMPILE([],
+ [
+ long long x, *y;
+ __asm__ __volatile__("movq %1, %0\n\t" : "=x"(x) : "m"(*y) : "memory");
+ ],
+ [gcc_sse2_asm=yes])
+ CFLAGS="$save_CFLAGS"
+ AC_MSG_RESULT([$gcc_sse2_asm])
+ if test "$gcc_sse2_asm" = "yes"; then
+ AC_DEFINE(ETHR_GCC_HAVE_SSE2_ASM_SUPPORT, 1, [Define if you use a gcc that supports -msse2 and understand sse2 specific asm statements])
+ ETHR_X86_SSE2_ASM=yes
+ fi
+ ;;
+ *)
+ ;;
+esac
+
+case "$GCC-$host_cpu" in
+ yes-i86pc | yes-i*86 | yes-x86_64 | yes-amd64)
+ gcc_dw_cmpxchg_asm=no
+ AC_MSG_CHECKING([for gcc double word cmpxchg asm support])
+ AC_TRY_COMPILE([],
+ [
+ char xchgd;
+ long new[2], xchg[2], *p;
+ __asm__ __volatile__(
+#if ETHR_SIZEOF_PTR == 4 && defined(__PIC__) && __PIC__
+ "pushl %%ebx\n\t"
+ "movl %8, %%ebx\n\t"
+#endif
+#if ETHR_SIZEOF_PTR == 4
+ "lock; cmpxchg8b %0\n\t"
+#else
+ "lock; cmpxchg16b %0\n\t"
+#endif
+ "setz %3\n\t"
+#if ETHR_SIZEOF_PTR == 4 && defined(__PIC__) && __PIC__
+ "popl %%ebx\n\t"
+#endif
+ : "=m"(*p), "=d"(xchg[1]), "=a"(xchg[0]), "=c"(xchgd)
+ : "m"(*p), "1"(xchg[1]), "2"(xchg[0]), "3"(new[1]),
+#if ETHR_SIZEOF_PTR == 4 && defined(__PIC__) && __PIC__
+ "r"(new[0])
+#else
+ "b"(new[0])
+#endif
+ : "cc", "memory");
+
+ ],
+ [gcc_dw_cmpxchg_asm=yes])
+ if test $gcc_dw_cmpxchg_asm = no && test $ac_cv_sizeof_void_p = 4; then
+ AC_TRY_COMPILE([],
+ [
+ char xchgd;
+ long new[2], xchg[2], *p;
+#if !defined(__PIC__) || !__PIC__
+# error nope
+#endif
+ __asm__ __volatile__(
+ "pushl %%ebx\n\t"
+ "movl (%7), %%ebx\n\t"
+ "movl 4(%7), %%ecx\n\t"
+ "lock; cmpxchg8b %0\n\t"
+ "setz %3\n\t"
+ "popl %%ebx\n\t"
+ : "=m"(*p), "=d"(xchg[1]), "=a"(xchg[0]), "=c"(xchgd)
+ : "m"(*p), "1"(xchg[1]), "2"(xchg[0]), "3"(new)
+ : "cc", "memory");
+
+ ],
+ [gcc_dw_cmpxchg_asm=yes])
+ if test "$gcc_dw_cmpxchg_asm" = "yes"; then
+ AC_DEFINE(ETHR_CMPXCHG8B_REGISTER_SHORTAGE, 1, [Define if you get a register shortage with cmpxchg8b and position independent code])
+ fi
+ fi
+ AC_MSG_RESULT([$gcc_dw_cmpxchg_asm])
+ if test "$gcc_dw_cmpxchg_asm" = "yes"; then
+ AC_DEFINE(ETHR_GCC_HAVE_DW_CMPXCHG_ASM_SUPPORT, 1, [Define if you use a gcc that supports the double word cmpxchg instruction])
+ fi;;
+ *)
+ ;;
+esac
+
+AC_DEFINE(ETHR_HAVE_ETHREAD_DEFINES, 1, \
+[Define if you have all ethread defines])
+
+AC_SUBST(ETHR_X_LIBS)
+AC_SUBST(ETHR_LIBS)
+AC_SUBST(ETHR_LIB_NAME)
+AC_SUBST(ETHR_DEFS)
+AC_SUBST(ETHR_THR_LIB_BASE)
+AC_SUBST(ETHR_THR_LIB_BASE_DIR)
+AC_SUBST(ETHR_X86_SSE2_ASM)
+
+])
+
+
+
+dnl ----------------------------------------------------------------------
+dnl
+dnl ERL_TIME_CORRECTION
+dnl
+dnl In the presence of a high resolution realtime timer Erlang can adapt
+dnl its view of time relative to this timer. On solaris such a timer is
+dnl available with the syscall gethrtime(). On other OS's a fallback
+dnl solution using times() is implemented. (However on e.g. FreeBSD times()
+dnl is implemented using gettimeofday so it doesn't make much sense to
+dnl use it there...) On second thought, it seems to be safer to do it the
+dnl other way around. I.e. only use times() on OS's where we know it will
+dnl work...
+dnl
+
+AC_DEFUN(ERL_TIME_CORRECTION,
+[if test x$ac_cv_func_gethrtime = x; then
+ AC_CHECK_FUNC(gethrtime)
+fi
+if test x$clock_gettime_correction = xunknown; then
+ AC_TRY_COMPILE([#include <time.h>],
+ [struct timespec ts;
+ long long result;
+ clock_gettime(CLOCK_MONOTONIC,&ts);
+ result = ((long long) ts.tv_sec) * 1000000000LL +
+ ((long long) ts.tv_nsec);],
+ clock_gettime_compiles=yes,
+ clock_gettime_compiles=no)
+else
+ clock_gettime_compiles=no
+fi
+
+
+AC_CACHE_CHECK([how to correct for time adjustments], erl_cv_time_correction,
+[
+case $clock_gettime_correction in
+ yes)
+ erl_cv_time_correction=clock_gettime;;
+ no|unknown)
+ case $ac_cv_func_gethrtime in
+ yes)
+ erl_cv_time_correction=hrtime ;;
+ no)
+ case $host_os in
+ linux*)
+ case $clock_gettime_correction in
+ unknown)
+ if test x$clock_gettime_compiles = xyes; then
+ if test X$cross_compiling != Xyes; then
+ linux_kernel_vsn_=`uname -r`
+ case $linux_kernel_vsn_ in
+ [[0-1]].*|2.[[0-5]]|2.[[0-5]].*)
+ erl_cv_time_correction=times ;;
+ *)
+ erl_cv_time_correction=clock_gettime;;
+ esac
+ else
+ case X$erl_xcomp_linux_clock_gettime_correction in
+ X)
+ erl_cv_time_correction=cross;;
+ Xyes|Xno)
+ if test $erl_xcomp_linux_clock_gettime_correction = yes; then
+ erl_cv_time_correction=clock_gettime
+ else
+ erl_cv_time_correction=times
+ fi;;
+ *)
+ AC_MSG_ERROR([Bad erl_xcomp_linux_clock_gettime_correction value: $erl_xcomp_linux_clock_gettime_correction]);;
+ esac
+ fi
+ else
+ erl_cv_time_correction=times
+ fi
+ ;;
+ *)
+ erl_cv_time_correction=times ;;
+ esac
+ ;;
+ *)
+ erl_cv_time_correction=none ;;
+ esac
+ ;;
+ esac
+ ;;
+esac
+])
+
+xrtlib=""
+case $erl_cv_time_correction in
+ times)
+ AC_DEFINE(CORRECT_USING_TIMES,[],
+ [Define if you do not have a high-res. timer & want to use times() instead])
+ ;;
+ clock_gettime|cross)
+ if test $erl_cv_time_correction = cross; then
+ erl_cv_time_correction=clock_gettime
+ AC_MSG_WARN([result clock_gettime guessed because of cross compilation])
+ fi
+ xrtlib="-lrt"
+ AC_DEFINE(GETHRTIME_WITH_CLOCK_GETTIME,[1],
+ [Define if you want to use clock_gettime to simulate gethrtime])
+ ;;
+esac
+dnl
+dnl Check if gethrvtime is working, and if to use procfs ioctl
+dnl or (yet to be written) write to the procfs ctl file.
+dnl
+
+AC_MSG_CHECKING([if gethrvtime works and how to use it])
+AC_TRY_RUN([
+/* gethrvtime procfs ioctl test */
+/* These need to be undef:ed to not break activation of
+ * micro level process accounting on /proc/self
+ */
+#ifdef _LARGEFILE_SOURCE
+# undef _LARGEFILE_SOURCE
+#endif
+#ifdef _FILE_OFFSET_BITS
+# undef _FILE_OFFSET_BITS
+#endif
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/signal.h>
+#include <sys/fault.h>
+#include <sys/syscall.h>
+#include <sys/procfs.h>
+#include <fcntl.h>
+
+int main() {
+ long msacct = PR_MSACCT;
+ int fd;
+ long long start, stop;
+ int i;
+ pid_t pid = getpid();
+ char proc_self[30] = "/proc/";
+
+ sprintf(proc_self+strlen(proc_self), "%lu", (unsigned long) pid);
+ if ( (fd = open(proc_self, O_WRONLY)) == -1)
+ exit(1);
+ if (ioctl(fd, PIOCSET, &msacct) < 0)
+ exit(2);
+ if (close(fd) < 0)
+ exit(3);
+ start = gethrvtime();
+ for (i = 0; i < 100; i++)
+ stop = gethrvtime();
+ if (start == 0)
+ exit(4);
+ if (start == stop)
+ exit(5);
+ exit(0); return 0;
+}
+],
+erl_gethrvtime=procfs_ioctl,
+erl_gethrvtime=false,
+[
+case X$erl_xcomp_gethrvtime_procfs_ioctl in
+ X)
+ erl_gethrvtime=cross;;
+ Xyes|Xno)
+ if test $erl_xcomp_gethrvtime_procfs_ioctl = yes; then
+ erl_gethrvtime=procfs_ioctl
+ else
+ erl_gethrvtime=false
+ fi;;
+ *)
+ AC_MSG_ERROR([Bad erl_xcomp_gethrvtime_procfs_ioctl value: $erl_xcomp_gethrvtime_procfs_ioctl]);;
+esac
+])
+
+case $erl_gethrvtime in
+ procfs_ioctl)
+ AC_DEFINE(HAVE_GETHRVTIME_PROCFS_IOCTL,[1],
+ [define if gethrvtime() works and uses ioctl() to /proc/self])
+ AC_MSG_RESULT(uses ioctl to procfs)
+ ;;
+ *)
+ if test $erl_gethrvtime = cross; then
+ erl_gethrvtime=false
+ AC_MSG_RESULT(cross)
+ AC_MSG_WARN([result 'not working' guessed because of cross compilation])
+ else
+ AC_MSG_RESULT(not working)
+ fi
+
+ dnl
+ dnl Check if clock_gettime (linux) is working
+ dnl
+
+ AC_MSG_CHECKING([if clock_gettime can be used to get process CPU time])
+ save_libs=$LIBS
+ LIBS="-lrt"
+ AC_TRY_RUN([
+ #include <stdlib.h>
+ #include <unistd.h>
+ #include <string.h>
+ #include <stdio.h>
+ #include <time.h>
+ int main() {
+ long long start, stop;
+ int i;
+ struct timespec tp;
+
+ if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp) < 0)
+ exit(1);
+ start = ((long long)tp.tv_sec * 1000000000LL) + (long long)tp.tv_nsec;
+ for (i = 0; i < 100; i++)
+ clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp);
+ stop = ((long long)tp.tv_sec * 1000000000LL) + (long long)tp.tv_nsec;
+ if (start == 0)
+ exit(4);
+ if (start == stop)
+ exit(5);
+ exit(0); return 0;
+ }
+ ],
+ erl_clock_gettime=yes,
+ erl_clock_gettime=no,
+ [
+ case X$erl_xcomp_clock_gettime_cpu_time in
+ X) erl_clock_gettime=cross;;
+ Xyes|Xno) erl_clock_gettime=$erl_xcomp_clock_gettime_cpu_time;;
+ *) AC_MSG_ERROR([Bad erl_xcomp_clock_gettime_cpu_time value: $erl_xcomp_clock_gettime_cpu_time]);;
+ esac
+ ])
+ LIBS=$save_libs
+ case $host_os in
+ linux*)
+ AC_MSG_RESULT([no; not stable])
+ LIBRT=$xrtlib
+ ;;
+ *)
+ AC_MSG_RESULT($erl_clock_gettime)
+ case $erl_clock_gettime in
+ yes)
+ AC_DEFINE(HAVE_CLOCK_GETTIME,[],
+ [define if clock_gettime() works for getting process time])
+ LIBRT=-lrt
+ ;;
+ cross)
+ erl_clock_gettime=no
+ AC_MSG_WARN([result no guessed because of cross compilation])
+ LIBRT=$xrtlib
+ ;;
+ *)
+ LIBRT=$xrtlib
+ ;;
+ esac
+ ;;
+ esac
+ AC_SUBST(LIBRT)
+ ;;
+esac
+])dnl
+
+dnl ----------------------------------------------------------------------
+dnl
+dnl LM_TRY_ENABLE_CFLAG
+dnl
+dnl
+dnl Tries a CFLAG and sees if it can be enabled without compiler errors
+dnl $1: textual cflag to add
+dnl $2: variable to store the modified CFLAG in
+dnl Usage example LM_TRY_ENABLE_CFLAG([-Werror=return-type], [CFLAGS])
+dnl
+dnl
+AC_DEFUN([LM_TRY_ENABLE_CFLAG], [
+ AC_MSG_CHECKING([if we can add $1 to $2 (via CFLAGS)])
+ saved_CFLAGS=$CFLAGS;
+ CFLAGS="$1 $$2";
+ AC_TRY_COMPILE([],[return 0;],can_enable_flag=true,can_enable_flag=false)
+ CFLAGS=$saved_CFLAGS;
+ if test "X$can_enable_flag" = "Xtrue"; then
+ AC_MSG_RESULT([yes])
+ AS_VAR_SET($2, "$1 $$2")
+ else
+ AC_MSG_RESULT([no])
+ fi
+])
+
+dnl ERL_TRY_LINK_JAVA(CLASSES, FUNCTION-BODY
+dnl [ACTION_IF_FOUND [, ACTION-IF-NOT-FOUND]])
+dnl Freely inspired by AC_TRY_LINK. (Maybe better to create a
+dnl AC_LANG_JAVA instead...)
+AC_DEFUN(ERL_TRY_LINK_JAVA,
+[java_link='$JAVAC conftest.java 1>&AC_FD_CC'
+changequote(, )dnl
+cat > conftest.java <<EOF
+$1
+class conftest { public static void main(String[] args) {
+ $2
+ ; return; }}
+EOF
+changequote([, ])dnl
+if AC_TRY_EVAL(java_link) && test -s conftest.class; then
+ ifelse([$3], , :, [rm -rf conftest*
+ $3])
+else
+ echo "configure: failed program was:" 1>&AC_FD_CC
+ cat conftest.java 1>&AC_FD_CC
+ echo "configure: PATH was $PATH" 1>&AC_FD_CC
+ifelse([$4], , , [ rm -rf conftest*
+ $4
+])dnl
+fi
+rm -f conftest*])
+#define UNSAFE_MASK 0xc0000000 /* Mask for bits that must be constant */
+
+
diff --git a/lib/megaco/configure.in b/lib/megaco/configure.in
index 722ccc3fb4..643267a154 100644
--- a/lib/megaco/configure.in
+++ b/lib/megaco/configure.in
@@ -162,6 +162,11 @@ else
fi
AC_SUBST(OTP_EXTRA_FLAGS)
+if test "x$GCC" = xyes; then
+ # Treat certain GCC warnings as errors
+ LM_TRY_ENABLE_CFLAG([-Werror=return-type], [CFLAGS])
+fi
+
dnl
dnl If ${ERL_TOP}/make/otp_ded.mk.in exists and contains DED_MK_VSN > 0,
dnl every thing releted to compiling Dynamic Erlang Drivers can be found
diff --git a/lib/megaco/doc/src/megaco_encode.xml b/lib/megaco/doc/src/megaco_encode.xml
index 410e4f3b31..4a9d63c2e3 100644
--- a/lib/megaco/doc/src/megaco_encode.xml
+++ b/lib/megaco/doc/src/megaco_encode.xml
@@ -224,22 +224,11 @@
messages.</p>
</item>
<item>
- <p>megaco_ber_bin_encoder - encode/decode ASN.1 BER
- messages. This encoder uses ASN.1 ber_bin which
- has been optimized using the bit syntax.</p>
- </item>
- <item>
<p>megaco_per_encoder - encode/decode ASN.1 PER
messages. N.B. that this format is not included in the
Megaco standard.</p>
</item>
<item>
- <p>megaco_per_bin_encoder - encode/decode ASN.1 PER
- messages. N.B. that this format is not included in the
- Megaco standard. This encoder uses ASN.1 per_bin which
- has been optimized using the bit syntax.</p>
- </item>
- <item>
<p>megaco_erl_dist_encoder - encodes messages into Erlangs
distribution format. It is rather verbose but encoding and
decoding is blinding fast. N.B. that this format is not
@@ -370,18 +359,6 @@
needs to be specified.</p>
<list type="bulleted">
<item>
- <p><c><![CDATA[[driver|_]]]></c> - make use of the asn1 driver for decode
- (ber_bin) and encode (per_bin). This option is only available for
- encoding modules: <c><![CDATA[megaco_binary_encoder]]></c>,
- <c><![CDATA[megaco_ber_bin_encoder]]></c> and <c><![CDATA[megaco_per_bin_encoder]]></c>.</p>
- <p>If this option is present in the encoding config, it <em>must</em>
- to be the <em>first</em>, unless the
- <seealso marker="#handling_versions">version3</seealso> encoding
- config is present, in which case it must come second, after
- the version3 encoding config,
- e.g. <c><![CDATA[[{version3,prev3b},driver]]]></c>.</p>
- </item>
- <item>
<p><c><![CDATA[[native]]]></c> - skips the transformation phase, i.e.
the decoded message(s) will not be transformed into our internal
form.</p>
diff --git a/lib/megaco/examples/meas/Makefile.in b/lib/megaco/examples/meas/Makefile.in
index c517fd21cf..91e342cd9a 100644
--- a/lib/megaco/examples/meas/Makefile.in
+++ b/lib/megaco/examples/meas/Makefile.in
@@ -147,12 +147,12 @@ release_docs_spec:
# ----------------------------------------------------
meas.sh.skel: meas.sh.skel.src
- @echo "transforming $< to $@"
- $(PERL) -p -e 's?%VSN%?$(VSN)? ' < $< > $@
+ $(V_colon)@echo "transforming $< to $@"
+ $(vsn_verbose)$(PERL) -p -e 's?%VSN%?$(VSN)? ' < $< > $@
mstone1.sh.skel: mstone1.sh.skel.src
- @echo "transforming $< to $@"
- $(PERL) -p -e 's?%VSN%?$(VSN)? ' < $< > $@
+ $(V_colon)@echo "transforming $< to $@"
+ $(vsn_verbose)$(PERL) -p -e 's?%VSN%?$(VSN)? ' < $< > $@
megaco_codec_transform.$(EMULATOR): megaco_codec_transform.erl
diff --git a/lib/megaco/examples/meas/megaco_codec_meas.erl b/lib/megaco/examples/meas/megaco_codec_meas.erl
index 51ee396338..65b986ccd1 100644
--- a/lib/megaco/examples/meas/megaco_codec_meas.erl
+++ b/lib/megaco/examples/meas/megaco_codec_meas.erl
@@ -176,7 +176,7 @@ display_megaco_info() ->
io:format("Megaco version: ~s (~s)~n", [Ver, FlexStr]).
display_asn1_info() ->
- AI = megaco_ber_bin_drv_media_gateway_control_v1:info(),
+ AI = megaco_ber_media_gateway_control_v1:info(),
Vsn =
case lists:keysearch(vsn, 1, AI) of
{value, {vsn, V}} when is_atom(V) ->
@@ -281,15 +281,11 @@ expand_codec(Codec) ->
[{Codec, megaco_compact_text_encoder, [flex_scanner], 3000},
{Codec, megaco_compact_text_encoder, [], 1500}];
ber ->
- [{Codec, megaco_ber_bin_encoder, [driver,native], 4000},
- {Codec, megaco_ber_bin_encoder, [native], 3000},
- {Codec, megaco_ber_bin_encoder, [driver], 3000},
- {Codec, megaco_ber_bin_encoder, [], 1000}];
+ [{Codec, megaco_ber_encoder, [native], 3000},
+ {Codec, megaco_ber_encoder, [], 1000}];
per ->
- [{Codec, megaco_per_bin_encoder, [driver,native], 4000},
- {Codec, megaco_per_bin_encoder, [native], 3000},
- {Codec, megaco_per_bin_encoder, [driver], 3000},
- {Codec, megaco_per_bin_encoder, [], 1000}];
+ [{Codec, megaco_per_encoder, [native], 3000},
+ {Codec, megaco_per_encoder, [], 1000}];
erlang ->
[
{Codec, megaco_erl_dist_encoder, [megaco_compressed,compressed], 500},
diff --git a/lib/megaco/examples/meas/megaco_codec_mstone_lib.erl b/lib/megaco/examples/meas/megaco_codec_mstone_lib.erl
index 9af88d9f50..b527ff2e89 100644
--- a/lib/megaco/examples/meas/megaco_codec_mstone_lib.erl
+++ b/lib/megaco/examples/meas/megaco_codec_mstone_lib.erl
@@ -268,7 +268,7 @@ display_megaco_info() ->
io:format("Megaco version: ~s~n", [Ver]).
display_asn1_info() ->
- AI = megaco_ber_bin_drv_media_gateway_control_v1:info(),
+ AI = megaco_ber__media_gateway_control_v1:info(),
Vsn =
case lists:keysearch(vsn, 1, AI) of
{value, {vsn, V}} when is_atom(V) ->
@@ -361,15 +361,11 @@ expand_codec(Codec, only_drv) ->
[{Codec, megaco_compact_text_encoder, [flex_scanner]},
{Codec, megaco_compact_text_encoder, [flex_scanner]}];
ber ->
- [{Codec, megaco_ber_bin_encoder, [driver,native]},
- {Codec, megaco_ber_bin_encoder, [driver]},
- {Codec, megaco_ber_bin_encoder, [driver,native]},
- {Codec, megaco_ber_bin_encoder, [driver]}];
+ [{Codec, megaco_ber_encoder, [native]},
+ {Codec, megaco_ber_encoder, []}];
per ->
- [{Codec, megaco_per_bin_encoder, [driver,native]},
- {Codec, megaco_per_bin_encoder, [native]},
- {Codec, megaco_per_bin_encoder, [driver,native]},
- {Codec, megaco_per_bin_encoder, [native]}];
+ [{Codec, megaco_per_encoder, [native]},
+ {Codec, megaco_per_encoder, []}];
erlang ->
Encoder = megaco_erl_dist_encoder,
[
@@ -390,15 +386,11 @@ expand_codec(Codec, no_drv) ->
[{Codec, megaco_compact_text_encoder, []},
{Codec, megaco_compact_text_encoder, []}];
ber ->
- [{Codec, megaco_ber_bin_encoder, [native]},
- {Codec, megaco_ber_bin_encoder, []},
- {Codec, megaco_ber_bin_encoder, [native]},
- {Codec, megaco_ber_bin_encoder, []}];
+ [{Codec, megaco_ber_encoder, [native]},
+ {Codec, megaco_ber_encoder, []}];
per ->
- [{Codec, megaco_per_bin_encoder, [native]},
- {Codec, megaco_per_bin_encoder, []},
- {Codec, megaco_per_bin_encoder, [native]},
- {Codec, megaco_per_bin_encoder, []}];
+ [{Codec, megaco_per_encoder, [native]},
+ {Codec, megaco_per_encoder, []}];
erlang ->
Encoder = megaco_erl_dist_encoder,
[
@@ -419,15 +411,11 @@ expand_codec(Codec, _) ->
[{Codec, megaco_compact_text_encoder, [flex_scanner]},
{Codec, megaco_compact_text_encoder, []}];
ber ->
- [{Codec, megaco_ber_bin_encoder, [driver,native]},
- {Codec, megaco_ber_bin_encoder, [native]},
- {Codec, megaco_ber_bin_encoder, [driver]},
- {Codec, megaco_ber_bin_encoder, []}];
+ [{Codec, megaco_ber_encoder, [native]},
+ {Codec, megaco_ber_encoder, []}];
per ->
- [{Codec, megaco_per_bin_encoder, [driver,native]},
- {Codec, megaco_per_bin_encoder, [native]},
- {Codec, megaco_per_bin_encoder, [driver]},
- {Codec, megaco_per_bin_encoder, []}];
+ [{Codec, megaco_per_encoder, [native]},
+ {Codec, megaco_per_encoder, []}];
erlang ->
Encoder = megaco_erl_dist_encoder,
[
diff --git a/lib/megaco/examples/meas/megaco_codec_transform.erl b/lib/megaco/examples/meas/megaco_codec_transform.erl
index cfe832ff26..15db165566 100644
--- a/lib/megaco/examples/meas/megaco_codec_transform.erl
+++ b/lib/megaco/examples/meas/megaco_codec_transform.erl
@@ -213,11 +213,11 @@ decode_message(compact, BinMsg) ->
Conf = [{version3,?V3}],
do_decode(Mod, Conf, BinMsg);
decode_message(ber, BinMsg) ->
- Mod = megaco_ber_bin_encoder,
+ Mod = megaco_ber_encoder,
Conf = [{version3,?V3}],
do_decode(Mod, Conf, BinMsg);
decode_message(per, BinMsg) ->
- Mod = megaco_per_bin_encoder,
+ Mod = megaco_per_encoder,
Conf = [{version3,?V3}],
do_decode(Mod, Conf, BinMsg);
decode_message(erlang, BinMsg) ->
diff --git a/lib/megaco/src/app/Makefile b/lib/megaco/src/app/Makefile
index 42030c5b1c..d18da5326a 100644
--- a/lib/megaco/src/app/Makefile
+++ b/lib/megaco/src/app/Makefile
@@ -94,10 +94,10 @@ info:
# ----------------------------------------------------
$(APP_TARGET): $(APP_SRC) ../../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
diff --git a/lib/megaco/src/app/megaco.app.src b/lib/megaco/src/app/megaco.app.src
index c0d8218ac8..0ba2a866f9 100644
--- a/lib/megaco/src/app/megaco.app.src
+++ b/lib/megaco/src/app/megaco.app.src
@@ -23,19 +23,6 @@
{modules,
[
megaco,
- megaco_ber_bin_encoder,
- megaco_ber_bin_drv_media_gateway_control_v1,
- megaco_ber_bin_drv_media_gateway_control_v2,
- megaco_ber_bin_drv_media_gateway_control_prev3a,
- megaco_ber_bin_drv_media_gateway_control_prev3b,
- megaco_ber_bin_drv_media_gateway_control_prev3c,
- megaco_ber_bin_drv_media_gateway_control_v3,
- megaco_ber_bin_media_gateway_control_v1,
- megaco_ber_bin_media_gateway_control_v2,
- megaco_ber_bin_media_gateway_control_prev3a,
- megaco_ber_bin_media_gateway_control_prev3b,
- megaco_ber_bin_media_gateway_control_prev3c,
- megaco_ber_bin_media_gateway_control_v3,
megaco_ber_encoder,
megaco_ber_media_gateway_control_v1,
megaco_ber_media_gateway_control_v2,
@@ -87,19 +74,6 @@
megaco_per_media_gateway_control_prev3b,
megaco_per_media_gateway_control_prev3c,
megaco_per_media_gateway_control_v3,
- megaco_per_bin_encoder,
- megaco_per_bin_drv_media_gateway_control_v1,
- megaco_per_bin_drv_media_gateway_control_v2,
- megaco_per_bin_drv_media_gateway_control_prev3a,
- megaco_per_bin_drv_media_gateway_control_prev3b,
- megaco_per_bin_drv_media_gateway_control_prev3c,
- megaco_per_bin_drv_media_gateway_control_v3,
- megaco_per_bin_media_gateway_control_v1,
- megaco_per_bin_media_gateway_control_v2,
- megaco_per_bin_media_gateway_control_prev3a,
- megaco_per_bin_media_gateway_control_prev3b,
- megaco_per_bin_media_gateway_control_prev3c,
- megaco_per_bin_media_gateway_control_v3,
megaco_pretty_text_encoder,
megaco_pretty_text_encoder_v1,
megaco_pretty_text_encoder_v2,
diff --git a/lib/megaco/src/binary/Makefile b/lib/megaco/src/binary/Makefile
index 695599b9dc..c1fd66b848 100644
--- a/lib/megaco/src/binary/Makefile
+++ b/lib/megaco/src/binary/Makefile
@@ -50,46 +50,22 @@ ASN1_SPECS = $(ASN1_V1_SPEC) \
ASN1_FILES = $(ASN1_SPECS:%=%.asn)
V1_SPECS = $(BER_ASN1_V1_SPEC) \
- $(BER_BIN_ASN1_V1_SPEC) \
- $(BER_BIN_DRV_ASN1_V1_SPEC) \
- $(PER_ASN1_V1_SPEC) \
- $(PER_BIN_ASN1_V1_SPEC) \
- $(PER_BIN_DRV_ASN1_V1_SPEC)
+ $(PER_ASN1_V1_SPEC)
V2_SPECS = $(BER_ASN1_V2_SPEC) \
- $(BER_BIN_ASN1_V2_SPEC) \
- $(BER_BIN_DRV_ASN1_V2_SPEC) \
- $(PER_ASN1_V2_SPEC) \
- $(PER_BIN_ASN1_V2_SPEC) \
- $(PER_BIN_DRV_ASN1_V2_SPEC)
+ $(PER_ASN1_V2_SPEC)
PREV3A_SPECS = $(BER_ASN1_PREV3A_SPEC) \
- $(BER_BIN_ASN1_PREV3A_SPEC) \
- $(BER_BIN_DRV_ASN1_PREV3A_SPEC) \
- $(PER_ASN1_PREV3A_SPEC) \
- $(PER_BIN_ASN1_PREV3A_SPEC) \
- $(PER_BIN_DRV_ASN1_PREV3A_SPEC)
+ $(PER_ASN1_PREV3A_SPEC)
PREV3B_SPECS = $(BER_ASN1_PREV3B_SPEC) \
- $(BER_BIN_ASN1_PREV3B_SPEC) \
- $(BER_BIN_DRV_ASN1_PREV3B_SPEC) \
- $(PER_ASN1_PREV3B_SPEC) \
- $(PER_BIN_ASN1_PREV3B_SPEC) \
- $(PER_BIN_DRV_ASN1_PREV3B_SPEC)
+ $(PER_ASN1_PREV3B_SPEC)
PREV3C_SPECS = $(BER_ASN1_PREV3C_SPEC) \
- $(BER_BIN_ASN1_PREV3C_SPEC) \
- $(BER_BIN_DRV_ASN1_PREV3C_SPEC) \
- $(PER_ASN1_PREV3C_SPEC) \
- $(PER_BIN_ASN1_PREV3C_SPEC) \
- $(PER_BIN_DRV_ASN1_PREV3C_SPEC)
+ $(PER_ASN1_PREV3C_SPEC)
V3_SPECS = $(BER_ASN1_V3_SPEC) \
- $(BER_BIN_ASN1_V3_SPEC) \
- $(BER_BIN_DRV_ASN1_V3_SPEC) \
$(PER_ASN1_V3_SPEC) \
- $(PER_BIN_ASN1_V3_SPEC) \
- $(PER_BIN_DRV_ASN1_V3_SPEC) \
$(PREV3A_SPECS) $(PREV3B_SPECS) $(PREV3C_SPECS)
SPECS = $(V1_SPECS) $(V2_SPECS) $(V3_SPECS)
@@ -153,12 +129,13 @@ opt: prebuild $(TARGET_FILES)
prebuild: prebuild.skip
prebuild.skip:
- @echo "Building prebuild.skip\c"
+ $(gen_verbose)
+ $(V_colon)@echo "Building prebuild.skip\c"
@touch prebuild.skip
@for a in $(SPEC_ASN1DB); do \
echo $$a >> prebuild.skip; \
done
- @echo ""
+ $(V_colon)@echo ""
v1: $(V2_SPEC_BINS)
diff --git a/lib/megaco/src/binary/depend.mk b/lib/megaco/src/binary/depend.mk
index c9ca34bcf6..2dce45981f 100644
--- a/lib/megaco/src/binary/depend.mk
+++ b/lib/megaco/src/binary/depend.mk
@@ -19,17 +19,8 @@
# Flag description:
#
-# +optimize
-# For ber_bin this means "optimize" (whatever that is),
-# but for per_bin it means that a stage in the encode
-# is done in the asn1 driver.
-#
-# +nif
-# For ber_bin this means that part of the decode is done
-# in the asn1 nif.
-#
# +asn1config
-# This is only used by the ber_bin, and means that
+# This is only used by the ber, and means that
# some partial decode functions will be created
# (as described by the asn1config file).
#
@@ -43,42 +34,18 @@ ifeq ($(MEGACO_INLINE_ASN1_RT),true)
ASN1_CT_OPTS += +inline
endif
-BER_V1_FLAGS = $(ASN1_CT_OPTS)
-BER_BIN_V1_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize
-BER_BIN_DRV_V1_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +nif
-BER_V2_FLAGS = $(ASN1_CT_OPTS)
-BER_BIN_V2_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize
-BER_BIN_DRV_V2_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +nif
-BER_PREV3A_FLAGS = $(ASN1_CT_OPTS)
-BER_BIN_PREV3A_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize
-BER_BIN_DRV_PREV3A_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +nif
-BER_PREV3B_FLAGS = $(ASN1_CT_OPTS)
-BER_BIN_PREV3B_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize
-BER_BIN_DRV_PREV3B_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +nif
-BER_PREV3C_FLAGS = $(ASN1_CT_OPTS)
-BER_BIN_PREV3C_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize
-BER_BIN_DRV_PREV3C_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +nif
-BER_V3_FLAGS = $(ASN1_CT_OPTS)
-BER_BIN_V3_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize
-BER_BIN_DRV_V3_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +nif
+BER_V1_FLAGS = $(ASN1_CT_OPTS) +asn1config
+BER_V2_FLAGS = $(ASN1_CT_OPTS) +asn1config
+BER_PREV3A_FLAGS = $(ASN1_CT_OPTS) +asn1config
+BER_PREV3B_FLAGS = $(ASN1_CT_OPTS) +asn1config
+BER_PREV3C_FLAGS = $(ASN1_CT_OPTS) +asn1config
+BER_V3_FLAGS = $(ASN1_CT_OPTS) +asn1config
PER_V1_FLAGS = $(ASN1_CT_OPTS)
-PER_BIN_V1_FLAGS = $(ASN1_CT_OPTS)
-PER_BIN_DRV_V1_FLAGS = $(ASN1_CT_OPTS) +optimize
PER_V2_FLAGS = $(ASN1_CT_OPTS)
-PER_BIN_V2_FLAGS = $(ASN1_CT_OPTS)
-PER_BIN_DRV_V2_FLAGS = $(ASN1_CT_OPTS) +optimize
PER_PREV3A_FLAGS = $(ASN1_CT_OPTS)
-PER_BIN_PREV3A_FLAGS = $(ASN1_CT_OPTS)
-PER_BIN_DRV_PREV3A_FLAGS = $(ASN1_CT_OPTS) +optimize
PER_PREV3B_FLAGS = $(ASN1_CT_OPTS)
-PER_BIN_PREV3B_FLAGS = $(ASN1_CT_OPTS)
-PER_BIN_DRV_PREV3B_FLAGS = $(ASN1_CT_OPTS) +optimize
PER_PREV3C_FLAGS = $(ASN1_CT_OPTS)
-PER_BIN_PREV3C_FLAGS = $(ASN1_CT_OPTS)
-PER_BIN_DRV_PREV3C_FLAGS = $(ASN1_CT_OPTS) +optimize
PER_V3_FLAGS = $(ASN1_CT_OPTS)
-PER_BIN_V3_FLAGS = $(ASN1_CT_OPTS)
-PER_BIN_DRV_V3_FLAGS = $(ASN1_CT_OPTS) +optimize
# --- Version 1 ---
@@ -86,119 +53,42 @@ PER_BIN_DRV_V3_FLAGS = $(ASN1_CT_OPTS) +optimize
$(BER_ASN1_V1_SPEC).erl: \
$(BER_ASN1_V1_SPEC).set.asn \
$(ASN1_V1_SPEC).asn
- @echo "$(BER_ASN1_V1_SPEC):"
- $(ERLC) -bber $(BER_V1_FLAGS) $(BER_ASN1_V1_SPEC).set.asn
+ $(V_colon)@echo "$(BER_ASN1_V1_SPEC):"
+ $(asn_verbose)$(ERLC) -bber $(BER_V1_FLAGS) $(BER_ASN1_V1_SPEC).set.asn
$(EBIN)/$(BER_ASN1_V1_SPEC).$(EMULATOR): \
$(BER_ASN1_V1_SPEC).erl
-$(BER_BIN_ASN1_V1_SPEC).erl: \
- $(BER_BIN_ASN1_V1_SPEC).set.asn \
- $(BER_BIN_ASN1_V1_SPEC).asn1config \
- $(ASN1_V1_SPEC).asn
- @echo "$(BER_BIN_ASN1_V1_SPEC):"
- $(ERLC) -bber_bin $(BER_BIN_V1_FLAGS) $(BER_BIN_ASN1_V1_SPEC).set.asn
-
-$(EBIN)/$(BER_BIN_ASN1_V1_SPEC).$(EMULATOR): \
- $(BER_BIN_ASN1_V1_SPEC).erl
-
-$(BER_BIN_DRV_ASN1_V1_SPEC).erl: \
- $(BER_BIN_DRV_ASN1_V1_SPEC).set.asn \
- $(BER_BIN_DRV_ASN1_V1_SPEC).asn1config \
- $(ASN1_V1_SPEC).asn
- @echo "$(BER_BIN_DRV_ASN1_V1_SPEC):"
- $(ERLC) -bber_bin $(BER_BIN_DRV_V1_FLAGS) $(BER_BIN_DRV_ASN1_V1_SPEC).set.asn
-
-$(EBIN)/$(BER_BIN_DRV_ASN1_V1_SPEC).$(EMULATOR): \
- $(BER_BIN_DRV_ASN1_V1_SPEC).erl
-
$(PER_ASN1_V1_SPEC).erl: \
$(PER_ASN1_V1_SPEC).set.asn \
$(ASN1_V1_SPEC).asn
- @echo "$(PER_ASN1_V1_SPEC):"
- $(ERLC) -bper $(PER_V1_FLAGS) $(PER_ASN1_V1_SPEC).set.asn
+ $(V_colon)@echo "$(PER_ASN1_V1_SPEC):"
+ $(asn_verbose)$(ERLC) -bper $(PER_V1_FLAGS) $(PER_ASN1_V1_SPEC).set.asn
$(EBIN)/$(PER_ASN1_V1_SPEC).$(EMULATOR): \
$(PER_ASN1_V1_SPEC).erl
-$(PER_BIN_ASN1_V1_SPEC).erl: \
- $(PER_BIN_ASN1_V1_SPEC).set.asn \
- $(ASN1_V1_SPEC).asn
- @echo "$(PER_BIN_ASN1_V1_SPEC):"
- $(ERLC) -bper_bin $(PER_BIN_V1_FLAGS) $(PER_BIN_ASN1_V1_SPEC).set.asn
-
-$(EBIN)/$(PER_BIN_ASN1_V1_SPEC).$(EMULATOR): \
- $(PER_BIN_ASN1_V1_SPEC).erl
-
-$(PER_BIN_DRV_ASN1_V1_SPEC).erl: \
- $(PER_BIN_DRV_ASN1_V1_SPEC).set.asn \
- $(ASN1_V1_SPEC).asn
- @echo "$(PER_BIN_DRV_ASN1_V1_SPEC):"
- $(ERLC) -bper_bin $(PER_BIN_DRV_V1_FLAGS) $(PER_BIN_DRV_ASN1_V1_SPEC).set.asn
-
-$(EBIN)/$(PER_BIN_DRV_ASN1_V1_SPEC).$(EMULATOR): \
- $(PER_BIN_DRV_ASN1_V1_SPEC).erl
-
# --- Version 2 ---
$(BER_ASN1_V2_SPEC).erl: \
$(BER_ASN1_V2_SPEC).set.asn \
$(ASN1_V2_SPEC).asn
- @echo "$(BER_ASN1_V2_SPEC):"
- $(ERLC) -bber $(BER_V2_FLAGS) $(BER_ASN1_V2_SPEC).set.asn
+ $(V_colon)@echo "$(BER_ASN1_V2_SPEC):"
+ $(asn_verbose)$(ERLC) -bber $(BER_V2_FLAGS) $(BER_ASN1_V2_SPEC).set.asn
$(EBIN)/$(BER_ASN1_V2_SPEC).$(EMULATOR): \
$(BER_ASN1_V2_SPEC).erl
-$(BER_BIN_ASN1_V2_SPEC).erl: \
- $(BER_BIN_ASN1_V2_SPEC).set.asn \
- $(BER_BIN_ASN1_V2_SPEC).asn1config \
- $(ASN1_V2_SPEC).asn
- @echo "$(BER_BIN_ASN1_V2_SPEC):"
- $(ERLC) -bber_bin $(BER_BIN_V2_FLAGS) $(BER_BIN_ASN1_V2_SPEC).set.asn
-
-$(EBIN)/$(BER_BIN_ASN1_V2_SPEC).$(EMULATOR): \
- $(BER_BIN_ASN1_V2_SPEC).erl
-
-$(BER_BIN_DRV_ASN1_V2_SPEC).erl: \
- $(BER_BIN_DRV_ASN1_V2_SPEC).set.asn \
- $(BER_BIN_DRV_ASN1_V2_SPEC).asn1config \
- $(ASN1_V2_SPEC).asn
- @echo "$(BER_BIN_DRV_ASN1_V2_SPEC):"
- $(ERLC) -bber_bin $(BER_BIN_DRV_V2_FLAGS) $(BER_BIN_DRV_ASN1_V2_SPEC).set.asn
-
-$(EBIN)/$(BER_BIN_DRV_ASN1_V2_SPEC).$(EMULATOR): \
- $(BER_BIN_DRV_ASN1_V2_SPEC).erl
-
$(PER_ASN1_V2_SPEC).erl: \
$(PER_ASN1_V2_SPEC).set.asn \
$(ASN1_V2_SPEC).asn
- @echo "$(PER_ASN1_V2_SPEC):"
- $(ERLC) -bper $(PER_V2_FLAGS) $(PER_ASN1_V2_SPEC).set.asn
+ $(V_colon)@echo "$(PER_ASN1_V2_SPEC):"
+ $(asn_verbose)$(ERLC) -bper $(PER_V2_FLAGS) $(PER_ASN1_V2_SPEC).set.asn
$(EBIN)/$(PER_ASN1_V2_SPEC).$(EMULATOR): \
$(PER_ASN1_V2_SPEC).erl
-$(PER_BIN_ASN1_V2_SPEC).erl: \
- $(PER_BIN_ASN1_V2_SPEC).set.asn \
- $(ASN1_V2_SPEC).asn
- @echo "$(PER_BIN_ASN1_V2_SPEC):"
- $(ERLC) -bper_bin $(PER_BIN_V2_FLAGS) $(PER_BIN_ASN1_V2_SPEC).set.asn
-
-$(EBIN)/$(PER_BIN_ASN1_V2_SPEC).$(EMULATOR): \
- $(PER_BIN_ASN1_V2_SPEC).erl
-
-$(PER_BIN_DRV_ASN1_V2_SPEC).erl: \
- $(PER_BIN_DRV_ASN1_V2_SPEC).set.asn \
- $(ASN1_V2_SPEC).asn
- @echo "$(PER_BIN_DRV_ASN1_V2_SPEC):"
- $(ERLC) -bper_bin $(PER_BIN_DRV_V2_FLAGS) $(PER_BIN_DRV_ASN1_V2_SPEC).set.asn
-
-$(EBIN)/$(PER_BIN_DRV_ASN1_V2_SPEC).$(EMULATOR): \
- $(PER_BIN_DRV_ASN1_V2_SPEC).erl
-
-
# --- Version 3 ---
# -- (prev3a) --
@@ -206,250 +96,93 @@ $(EBIN)/$(PER_BIN_DRV_ASN1_V2_SPEC).$(EMULATOR): \
$(BER_ASN1_PREV3A_SPEC).erl: \
$(BER_ASN1_PREV3A_SPEC).set.asn \
$(ASN1_PREV3A_SPEC).asn
- @echo "$(BER_ASN1_PREV3A_SPEC):"
- $(ERLC) -bber $(BER_PREV3A_FLAGS) $(BER_ASN1_PREV3A_SPEC).set.asn
+ $(V_colon)@echo "$(BER_ASN1_PREV3A_SPEC):"
+ $(asn_verbose)$(ERLC) -bber $(BER_PREV3A_FLAGS) $(BER_ASN1_PREV3A_SPEC).set.asn
$(EBIN)/$(BER_ASN1_PREV3A_SPEC).$(EMULATOR): \
$(BER_ASN1_PREV3A_SPEC).erl
-$(BER_BIN_ASN1_PREV3A_SPEC).erl: \
- $(BER_BIN_ASN1_PREV3A_SPEC).set.asn \
- $(BER_BIN_ASN1_PREV3A_SPEC).asn1config \
- $(ASN1_PREV3A_SPEC).asn
- @echo "$(BER_BIN_ASN1_PREV3A_SPEC):"
- $(ERLC) -bber_bin $(BER_BIN_PREV3A_FLAGS) $(BER_BIN_ASN1_PREV3A_SPEC).set.asn
-
-$(EBIN)/$(BER_BIN_ASN1_PREV3A_SPEC).$(EMULATOR): \
- $(BER_BIN_ASN1_PREV3A_SPEC).erl
-
-$(BER_BIN_DRV_ASN1_PREV3A_SPEC).erl: \
- $(BER_BIN_DRV_ASN1_PREV3A_SPEC).set.asn \
- $(BER_BIN_DRV_ASN1_PREV3A_SPEC).asn1config \
- $(ASN1_PREV3A_SPEC).asn
- @echo "$(BER_BIN_DRV_ASN1_PREV3A_SPEC):"
- $(ERLC) -bber_bin $(BER_BIN_DRV_PREV3A_FLAGS) $(BER_BIN_DRV_ASN1_PREV3A_SPEC).set.asn
-
-$(EBIN)/$(BER_BIN_DRV_ASN1_PREV3A_SPEC).$(EMULATOR): \
- $(BER_BIN_DRV_ASN1_PREV3A_SPEC).erl
-
$(PER_ASN1_PREV3A_SPEC).erl: \
$(PER_ASN1_PREV3A_SPEC).set.asn \
$(ASN1_PREV3A_SPEC).asn
- @echo "$(PER_ASN1_PREV3A_SPEC):"
- $(ERLC) -bper $(PER_PREV3A_FLAGS) $(PER_ASN1_PREV3A_SPEC).set.asn
+ $(V_colon)@echo "$(PER_ASN1_PREV3A_SPEC):"
+ $(asn_verbose)$(ERLC) -bper $(PER_PREV3A_FLAGS) $(PER_ASN1_PREV3A_SPEC).set.asn
$(EBIN)/$(PER_ASN1_PREV3A_SPEC).$(EMULATOR): \
$(PER_ASN1_PREV3A_SPEC).erl
-$(PER_BIN_ASN1_PREV3A_SPEC).erl: \
- $(PER_BIN_ASN1_PREV3A_SPEC).set.asn \
- $(ASN1_PREV3A_SPEC).asn
- @echo "$(PER_BIN_ASN1_PREV3A_SPEC):"
- $(ERLC) -bper_bin $(PER_BIN_PREV3A_FLAGS) $(PER_BIN_ASN1_PREV3A_SPEC).set.asn
-
-$(EBIN)/$(PER_BIN_ASN1_PREV3A_SPEC).$(EMULATOR): \
- $(PER_BIN_ASN1_PREV3A_SPEC).erl
-
-$(PER_BIN_DRV_ASN1_PREV3A_SPEC).erl: \
- $(PER_BIN_DRV_ASN1_PREV3A_SPEC).set.asn \
- $(ASN1_PREV3A_SPEC).asn
- @echo "$(PER_BIN_DRV_ASN1_PREV3A_SPEC):"
- $(ERLC) -bper_bin $(PER_BIN_DRV_PREV3A_FLAGS) $(PER_BIN_DRV_ASN1_PREV3A_SPEC).set.asn
-
-$(EBIN)/$(PER_BIN_DRV_ASN1_PREV3A_SPEC).$(EMULATOR): \
- $(PER_BIN_DRV_ASN1_PREV3A_SPEC).erl
# -- (prev3b) --
$(BER_ASN1_PREV3B_SPEC).erl: \
$(BER_ASN1_PREV3B_SPEC).set.asn \
$(ASN1_PREV3B_SPEC).asn
- @echo "$(BER_ASN1_PREV3B_SPEC):"
- $(ERLC) -bber $(BER_PREV3B_FLAGS) $(BER_ASN1_PREV3B_SPEC).set.asn
+ $(V_colon)@echo "$(BER_ASN1_PREV3B_SPEC):"
+ $(asn_verbose)$(ERLC) -bber $(BER_PREV3B_FLAGS) $(BER_ASN1_PREV3B_SPEC).set.asn
$(EBIN)/$(BER_ASN1_PREV3B_SPEC).$(EMULATOR): \
$(BER_ASN1_PREV3B_SPEC).erl
-$(BER_BIN_ASN1_PREV3B_SPEC).erl: \
- $(BER_BIN_ASN1_PREV3B_SPEC).set.asn \
- $(BER_BIN_ASN1_PREV3B_SPEC).asn1config \
- $(ASN1_PREV3B_SPEC).asn
- @echo "$(BER_BIN_ASN1_PREV3B_SPEC):"
- $(ERLC) -bber_bin $(BER_BIN_PREV3B_FLAGS) $(BER_BIN_ASN1_PREV3B_SPEC).set.asn
-
-$(EBIN)/$(BER_BIN_ASN1_PREV3B_SPEC).$(EMULATOR): \
- $(BER_BIN_ASN1_PREV3B_SPEC).erl
-
-$(BER_BIN_DRV_ASN1_PREV3B_SPEC).erl: \
- $(BER_BIN_DRV_ASN1_PREV3B_SPEC).set.asn \
- $(BER_BIN_DRV_ASN1_PREV3B_SPEC).asn1config \
- $(ASN1_PREV3B_SPEC).asn
- @echo "$(BER_BIN_DRV_ASN1_PREV3B_SPEC):"
- $(ERLC) -bber_bin $(BER_BIN_DRV_PREV3B_FLAGS) $(BER_BIN_DRV_ASN1_PREV3B_SPEC).set.asn
-
-$(EBIN)/$(BER_BIN_DRV_ASN1_PREV3B_SPEC).$(EMULATOR): \
- $(BER_BIN_DRV_ASN1_PREV3B_SPEC).erl
-
$(PER_ASN1_PREV3B_SPEC).erl: \
$(PER_ASN1_PREV3B_SPEC).set.asn \
$(ASN1_PREV3B_SPEC).asn
- @echo "$(PER_ASN1_PREV3B_SPEC):"
- $(ERLC) -bper $(PER_PREV3B_FLAGS) $(PER_ASN1_PREV3B_SPEC).set.asn
+ $(V_colon)@echo "$(PER_ASN1_PREV3B_SPEC):"
+ $(asn_verbose)$(ERLC) -bper $(PER_PREV3B_FLAGS) $(PER_ASN1_PREV3B_SPEC).set.asn
$(EBIN)/$(PER_ASN1_PREV3B_SPEC).$(EMULATOR): \
$(PER_ASN1_PREV3B_SPEC).erl
-$(PER_BIN_ASN1_PREV3B_SPEC).erl: \
- $(PER_BIN_ASN1_PREV3B_SPEC).set.asn \
- $(ASN1_PREV3B_SPEC).asn
- @echo "$(PER_BIN_ASN1_PREV3B_SPEC):"
- $(ERLC) -bper_bin $(PER_BIN_PREV3B_FLAGS) $(PER_BIN_ASN1_PREV3B_SPEC).set.asn
-
-$(EBIN)/$(PER_BIN_ASN1_PREV3B_SPEC).$(EMULATOR): \
- $(PER_BIN_ASN1_PREV3B_SPEC).erl
-
-$(PER_BIN_DRV_ASN1_PREV3B_SPEC).erl: \
- $(PER_BIN_DRV_ASN1_PREV3B_SPEC).set.asn \
- $(ASN1_PREV3B_SPEC).asn
- @echo "$(PER_BIN_DRV_ASN1_PREV3B_SPEC):"
- $(ERLC) -bper_bin $(PER_BIN_DRV_PREV3B_FLAGS) $(PER_BIN_DRV_ASN1_PREV3B_SPEC).set.asn
-
-$(EBIN)/$(PER_BIN_DRV_ASN1_PREV3B_SPEC).$(EMULATOR): \
- $(PER_BIN_DRV_ASN1_PREV3B_SPEC).erl
-
# -- (prev3c) --
$(BER_ASN1_PREV3C_SPEC).erl: \
$(BER_ASN1_PREV3C_SPEC).set.asn \
$(ASN1_PREV3C_SPEC).asn
- @echo "$(BER_ASN1_PREV3C_SPEC):"
- $(ERLC) -bber $(BER_PREV3C_FLAGS) $(BER_ASN1_PREV3C_SPEC).set.asn
+ $(V_colon)@echo "$(BER_ASN1_PREV3C_SPEC):"
+ $(asn_verbose)$(ERLC) -bber $(BER_PREV3C_FLAGS) $(BER_ASN1_PREV3C_SPEC).set.asn
$(EBIN)/$(BER_ASN1_PREV3C_SPEC).$(EMULATOR): \
$(BER_ASN1_PREV3C_SPEC).erl
-$(BER_BIN_ASN1_PREV3C_SPEC).erl: \
- $(BER_BIN_ASN1_PREV3C_SPEC).set.asn \
- $(BER_BIN_ASN1_PREV3C_SPEC).asn1config \
- $(ASN1_PREV3C_SPEC).asn
- @echo "$(BER_BIN_ASN1_PREV3C_SPEC):"
- $(ERLC) -bber_bin $(BER_BIN_PREV3C_FLAGS) $(BER_BIN_ASN1_PREV3C_SPEC).set.asn
-
-$(EBIN)/$(BER_BIN_ASN1_PREV3C_SPEC).$(EMULATOR): \
- $(BER_BIN_ASN1_PREV3C_SPEC).erl
-
-$(BER_BIN_DRV_ASN1_PREV3C_SPEC).erl: \
- $(BER_BIN_DRV_ASN1_PREV3C_SPEC).set.asn \
- $(BER_BIN_DRV_ASN1_PREV3C_SPEC).asn1config \
- $(ASN1_PREV3C_SPEC).asn
- @echo "$(BER_BIN_DRV_ASN1_PREV3C_SPEC):"
- $(ERLC) -bber_bin $(BER_BIN_DRV_PREV3C_FLAGS) $(BER_BIN_DRV_ASN1_PREV3C_SPEC).set.asn
-
-$(EBIN)/$(BER_BIN_DRV_ASN1_PREV3C_SPEC).$(EMULATOR): \
- $(BER_BIN_DRV_ASN1_PREV3C_SPEC).erl
-
$(PER_ASN1_PREV3C_SPEC).erl: \
$(PER_ASN1_PREV3C_SPEC).set.asn \
$(ASN1_PREV3C_SPEC).asn
- @echo "$(PER_ASN1_PREV3C_SPEC):"
- $(ERLC) -bper $(PER_PREV3C_FLAGS) $(PER_ASN1_PREV3C_SPEC).set.asn
+ $(V_colon)@echo "$(PER_ASN1_PREV3C_SPEC):"
+ $(asn_verbose)$(ERLC) -bper $(PER_PREV3C_FLAGS) $(PER_ASN1_PREV3C_SPEC).set.asn
$(EBIN)/$(PER_ASN1_PREV3C_SPEC).$(EMULATOR): \
$(PER_ASN1_PREV3C_SPEC).erl
-$(PER_BIN_ASN1_PREV3C_SPEC).erl: \
- $(PER_BIN_ASN1_PREV3C_SPEC).set.asn \
- $(ASN1_PREV3C_SPEC).asn
- @echo "$(PER_BIN_ASN1_PREV3C_SPEC):"
- $(ERLC) -bper_bin $(PER_BIN_PREV3C_FLAGS) $(PER_BIN_ASN1_PREV3C_SPEC).set.asn
-
-$(EBIN)/$(PER_BIN_ASN1_PREV3C_SPEC).$(EMULATOR): \
- $(PER_BIN_ASN1_PREV3C_SPEC).erl
-
-$(PER_BIN_DRV_ASN1_PREV3C_SPEC).erl: \
- $(PER_BIN_DRV_ASN1_PREV3C_SPEC).set.asn \
- $(ASN1_PREV3C_SPEC).asn
- @echo "$(PER_BIN_DRV_ASN1_PREV3C_SPEC):"
- $(ERLC) -bper_bin $(PER_BIN_DRV_PREV3C_FLAGS) $(PER_BIN_DRV_ASN1_PREV3C_SPEC).set.asn
-
-$(EBIN)/$(PER_BIN_DRV_ASN1_PREV3C_SPEC).$(EMULATOR): \
- $(PER_BIN_DRV_ASN1_PREV3C_SPEC).erl
-
# -- (v3) --
$(BER_ASN1_V3_SPEC).erl: \
$(BER_ASN1_V3_SPEC).set.asn \
$(ASN1_V3_SPEC).asn
- @echo "$(BER_ASN1_V3_SPEC):"
- $(ERLC) -bber $(BER_V3_FLAGS) $(BER_ASN1_V3_SPEC).set.asn
+ $(V_colon)@echo "$(BER_ASN1_V3_SPEC):"
+ $(asn_verbose)$(ERLC) -bber $(BER_V3_FLAGS) $(BER_ASN1_V3_SPEC).set.asn
$(EBIN)/$(BER_ASN1_V3_SPEC).$(EMULATOR): \
$(BER_ASN1_V3_SPEC).erl
-$(BER_BIN_ASN1_V3_SPEC).erl: \
- $(BER_BIN_ASN1_V3_SPEC).set.asn \
- $(BER_BIN_ASN1_V3_SPEC).asn1config \
- $(ASN1_V3_SPEC).asn
- @echo "$(BER_BIN_ASN1_V3_SPEC):"
- $(ERLC) -bber_bin $(BER_BIN_V3_FLAGS) $(BER_BIN_ASN1_V3_SPEC).set.asn
-
-$(EBIN)/$(BER_BIN_ASN1_V3_SPEC).$(EMULATOR): \
- $(BER_BIN_ASN1_V3_SPEC).erl
-
-$(BER_BIN_DRV_ASN1_V3_SPEC).erl: \
- $(BER_BIN_DRV_ASN1_V3_SPEC).set.asn \
- $(BER_BIN_DRV_ASN1_V3_SPEC).asn1config \
- $(ASN1_V3_SPEC).asn
- @echo "$(BER_BIN_DRV_ASN1_V3_SPEC):"
- $(ERLC) -bber_bin $(BER_BIN_DRV_V3_FLAGS) $(BER_BIN_DRV_ASN1_V3_SPEC).set.asn
-
-$(EBIN)/$(BER_BIN_DRV_ASN1_V3_SPEC).$(EMULATOR): \
- $(BER_BIN_DRV_ASN1_V3_SPEC).erl
-
$(PER_ASN1_V3_SPEC).erl: \
$(PER_ASN1_V3_SPEC).set.asn \
$(ASN1_V3_SPEC).asn
- @echo "$(PER_ASN1_V3_SPEC):"
- $(ERLC) -bper $(PER_V3_FLAGS) $(PER_ASN1_V3_SPEC).set.asn
+ $(V_colon)@echo "$(PER_ASN1_V3_SPEC):"
+ $(asn_verbose)$(ERLC) -bper $(PER_V3_FLAGS) $(PER_ASN1_V3_SPEC).set.asn
$(EBIN)/$(PER_ASN1_V3_SPEC).$(EMULATOR): \
$(PER_ASN1_V3_SPEC).erl
-$(PER_BIN_ASN1_V3_SPEC).erl: \
- $(PER_BIN_ASN1_V3_SPEC).set.asn \
- $(ASN1_V3_SPEC).asn
- @echo "$(PER_BIN_ASN1_V3_SPEC):"
- $(ERLC) -bper_bin $(PER_BIN_V3_FLAGS) $(PER_BIN_ASN1_V3_SPEC).set.asn
-
-$(EBIN)/$(PER_BIN_ASN1_V3_SPEC).$(EMULATOR): \
- $(PER_BIN_ASN1_V3_SPEC).erl
-
-$(PER_BIN_DRV_ASN1_V3_SPEC).erl: \
- $(PER_BIN_DRV_ASN1_V3_SPEC).set.asn \
- $(ASN1_V3_SPEC).asn
- @echo "$(PER_BIN_DRV_ASN1_V3_SPEC):"
- $(ERLC) -bper_bin $(PER_BIN_DRV_V3_FLAGS) $(PER_BIN_DRV_ASN1_V3_SPEC).set.asn
-
-$(EBIN)/$(PER_BIN_DRV_ASN1_V3_SPEC).$(EMULATOR): \
- $(PER_BIN_DRV_ASN1_V3_SPEC).erl
-
# -------------
$(EBIN)/megaco_ber_encoder.$(EMULATOR): megaco_ber_encoder.erl \
$(MEGACO_ENGINEDIR)/megaco_message_internal.hrl
-$(EBIN)/megaco_ber_bin_encoder.$(EMULATOR): megaco_ber_bin_encoder.erl \
- $(MEGACO_ENGINEDIR)/megaco_message_internal.hrl
-
$(EBIN)/megaco_per_encoder.$(EMULATOR): megaco_per_encoder.erl \
$(MEGACO_ENGINEDIR)/megaco_message_internal.hrl
-$(EBIN)/megaco_per_bin_encoder.$(EMULATOR): megaco_per_bin_encoder.erl \
- $(MEGACO_ENGINEDIR)/megaco_message_internal.hrl
-
$(EBIN)/megaco_binary_encoder_lib.$(EMULATOR): megaco_binary_encoder_lib.erl \
$(MEGACO_ENGINEDIR)/megaco_message_internal.hrl
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3a.asn1config b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3a.asn1config
deleted file mode 100644
index 179473717d..0000000000
--- a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3a.asn1config
+++ /dev/null
@@ -1,43 +0,0 @@
-{exclusive_decode,
- {'megaco_ber_bin_drv_media_gateway_control_prev3a',
- [
- {decode_message_trans_partial,
- [
- 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
- ]
- },
- {decode_message_acts_partial,
- ['Transaction',
- [
- {transactionRequest,
- [
- {actions,parts}
- ]
- },
- {transactionReply,
- [
- {transactionResult, [{actionReplies,parts}]}
- ]
- }
- ]
- ]
- },
- {decode_message_version,
- ['MegacoMessage',
- [
- {authHeader,undecoded},
- {mess,[{mId,undecoded},{messageBody,undecoded}]}
- ]
- ]
- },
- {decode_message_mId,
- ['MegacoMessage',
- [
- {authHeader,undecoded},
- {mess,[{messageBody,undecoded}]}
- ]
- ]
- }
- ]
- }
-}.
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3a.set.asn b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3a.set.asn
deleted file mode 100644
index b9ba7ffdb4..0000000000
--- a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3a.set.asn
+++ /dev/null
@@ -1 +0,0 @@
-MEDIA-GATEWAY-CONTROL-prev3a.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3b.asn1config b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3b.asn1config
deleted file mode 100644
index ceda97fbd1..0000000000
--- a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3b.asn1config
+++ /dev/null
@@ -1,43 +0,0 @@
-{exclusive_decode,
- {'megaco_ber_bin_drv_media_gateway_control_prev3b',
- [
- {decode_message_trans_partial,
- [
- 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
- ]
- },
- {decode_message_acts_partial,
- ['Transaction',
- [
- {transactionRequest,
- [
- {actions,parts}
- ]
- },
- {transactionReply,
- [
- {transactionResult, [{actionReplies,parts}]}
- ]
- }
- ]
- ]
- },
- {decode_message_version,
- ['MegacoMessage',
- [
- {authHeader,undecoded},
- {mess,[{mId,undecoded},{messageBody,undecoded}]}
- ]
- ]
- },
- {decode_message_mId,
- ['MegacoMessage',
- [
- {authHeader,undecoded},
- {mess,[{messageBody,undecoded}]}
- ]
- ]
- }
- ]
- }
-}.
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3b.set.asn b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3b.set.asn
deleted file mode 100644
index 0437bde310..0000000000
--- a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3b.set.asn
+++ /dev/null
@@ -1 +0,0 @@
-MEDIA-GATEWAY-CONTROL-prev3b.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3c.asn1config b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3c.asn1config
deleted file mode 100644
index d181ef44bd..0000000000
--- a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3c.asn1config
+++ /dev/null
@@ -1,43 +0,0 @@
-{exclusive_decode,
- {'megaco_ber_bin_drv_media_gateway_control_prev3c',
- [
- {decode_message_trans_partial,
- [
- 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
- ]
- },
- {decode_message_acts_partial,
- ['Transaction',
- [
- {transactionRequest,
- [
- {actions,parts}
- ]
- },
- {transactionReply,
- [
- {transactionResult, [{actionReplies,parts}]}
- ]
- }
- ]
- ]
- },
- {decode_message_version,
- ['MegacoMessage',
- [
- {authHeader,undecoded},
- {mess,[{mId,undecoded},{messageBody,undecoded}]}
- ]
- ]
- },
- {decode_message_mId,
- ['MegacoMessage',
- [
- {authHeader,undecoded},
- {mess,[{messageBody,undecoded}]}
- ]
- ]
- }
- ]
- }
-}.
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3c.set.asn b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3c.set.asn
deleted file mode 100644
index e78055fbad..0000000000
--- a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3c.set.asn
+++ /dev/null
@@ -1 +0,0 @@
-MEDIA-GATEWAY-CONTROL-prev3c.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v1.set.asn b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v1.set.asn
deleted file mode 100644
index 0f5a92dba1..0000000000
--- a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v1.set.asn
+++ /dev/null
@@ -1 +0,0 @@
-MEDIA-GATEWAY-CONTROL-v1.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v2.asn1config b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v2.asn1config
deleted file mode 100644
index 3d0cb9a019..0000000000
--- a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v2.asn1config
+++ /dev/null
@@ -1,43 +0,0 @@
-{exclusive_decode,
- {'megaco_ber_bin_drv_media_gateway_control_v2',
- [
- {decode_message_trans_partial,
- [
- 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
- ]
- },
- {decode_message_acts_partial,
- ['Transaction',
- [
- {transactionRequest,
- [
- {actions,parts}
- ]
- },
- {transactionReply,
- [
- {transactionResult, [{actionReplies,parts}]}
- ]
- }
- ]
- ]
- },
- {decode_message_version,
- ['MegacoMessage',
- [
- {authHeader,undecoded},
- {mess,[{mId,undecoded},{messageBody,undecoded}]}
- ]
- ]
- },
- {decode_message_mId,
- ['MegacoMessage',
- [
- {authHeader,undecoded},
- {mess,[{messageBody,undecoded}]}
- ]
- ]
- }
- ]
- }
-}.
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v2.set.asn b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v2.set.asn
deleted file mode 100644
index 7fc82b127f..0000000000
--- a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v2.set.asn
+++ /dev/null
@@ -1 +0,0 @@
-MEDIA-GATEWAY-CONTROL-v2.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v3.asn1config b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v3.asn1config
deleted file mode 100644
index cc662c0145..0000000000
--- a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v3.asn1config
+++ /dev/null
@@ -1,43 +0,0 @@
-{exclusive_decode,
- {'megaco_ber_bin_drv_media_gateway_control_v3',
- [
- {decode_message_trans_partial,
- [
- 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
- ]
- },
- {decode_message_acts_partial,
- ['Transaction',
- [
- {transactionRequest,
- [
- {actions,parts}
- ]
- },
- {transactionReply,
- [
- {transactionResult, [{actionReplies,parts}]}
- ]
- }
- ]
- ]
- },
- {decode_message_version,
- ['MegacoMessage',
- [
- {authHeader,undecoded},
- {mess,[{mId,undecoded},{messageBody,undecoded}]}
- ]
- ]
- },
- {decode_message_mId,
- ['MegacoMessage',
- [
- {authHeader,undecoded},
- {mess,[{messageBody,undecoded}]}
- ]
- ]
- }
- ]
- }
-}.
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v3.set.asn b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v3.set.asn
deleted file mode 100644
index 1d7950a283..0000000000
--- a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v3.set.asn
+++ /dev/null
@@ -1 +0,0 @@
-MEDIA-GATEWAY-CONTROL-v3.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_encoder.erl b/lib/megaco/src/binary/megaco_ber_bin_encoder.erl
deleted file mode 100644
index bf9926c7e5..0000000000
--- a/lib/megaco/src/binary/megaco_ber_bin_encoder.erl
+++ /dev/null
@@ -1,716 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
-%%----------------------------------------------------------------------
-%% Purpose : Handle ASN.1 BER encoding of Megaco/H.248
-%%----------------------------------------------------------------------
-
--module(megaco_ber_bin_encoder).
-
--behaviour(megaco_encoder).
-
--export([encode_message/3, decode_message/3,
- decode_mini_message/3,
-
- encode_transaction/3,
- encode_action_requests/3,
- encode_action_request/3,
- encode_action_reply/3,
-
- version_of/2]).
-
-%% Backward compatible functions:
--export([encode_message/2, decode_message/2]).
-
--include_lib("megaco/src/engine/megaco_message_internal.hrl").
-
--define(V1_ASN1_MOD, megaco_ber_bin_media_gateway_control_v1).
--define(V2_ASN1_MOD, megaco_ber_bin_media_gateway_control_v2).
--define(V3_ASN1_MOD, megaco_ber_bin_media_gateway_control_v3).
--define(PREV3A_ASN1_MOD, megaco_ber_bin_media_gateway_control_prev3a).
--define(PREV3B_ASN1_MOD, megaco_ber_bin_media_gateway_control_prev3b).
--define(PREV3C_ASN1_MOD, megaco_ber_bin_media_gateway_control_prev3c).
--define(V1_ASN1_MOD_DRV, megaco_ber_bin_drv_media_gateway_control_v1).
--define(V2_ASN1_MOD_DRV, megaco_ber_bin_drv_media_gateway_control_v2).
--define(V3_ASN1_MOD_DRV, megaco_ber_bin_drv_media_gateway_control_v3).
--define(PREV3A_ASN1_MOD_DRV, megaco_ber_bin_drv_media_gateway_control_prev3a).
--define(PREV3B_ASN1_MOD_DRV, megaco_ber_bin_drv_media_gateway_control_prev3b).
--define(PREV3C_ASN1_MOD_DRV, megaco_ber_bin_drv_media_gateway_control_prev3c).
-
--define(V1_TRANS_MOD, megaco_binary_transformer_v1).
--define(V2_TRANS_MOD, megaco_binary_transformer_v2).
--define(V3_TRANS_MOD, megaco_binary_transformer_v3).
--define(PREV3A_TRANS_MOD, megaco_binary_transformer_prev3a).
--define(PREV3B_TRANS_MOD, megaco_binary_transformer_prev3b).
--define(PREV3C_TRANS_MOD, megaco_binary_transformer_prev3c).
-
--define(BIN_LIB, megaco_binary_encoder_lib).
-
-
-%%----------------------------------------------------------------------
-%% Detect (check/get) message version
-%% Return {ok, Version} | {error, Reason}
-%%----------------------------------------------------------------------
-
-version_of([{version3,v3},driver|EC], Binary) ->
- Decoders = [?V1_ASN1_MOD_DRV, ?V2_ASN1_MOD_DRV, ?V3_ASN1_MOD_DRV],
- ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
-version_of([{version3,prev3c},driver|EC], Binary) ->
- Decoders = [?V1_ASN1_MOD_DRV, ?V2_ASN1_MOD_DRV, ?PREV3C_ASN1_MOD_DRV],
- ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
-version_of([{version3,prev3b},driver|EC], Binary) ->
- Decoders = [?V1_ASN1_MOD_DRV, ?V2_ASN1_MOD_DRV, ?PREV3B_ASN1_MOD_DRV],
- ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
-version_of([{version3,prev3a},driver|EC], Binary) ->
- Decoders = [?V1_ASN1_MOD_DRV, ?V2_ASN1_MOD_DRV, ?PREV3A_ASN1_MOD_DRV],
- ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
-version_of([{version3,v3}|EC], Binary) ->
- Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
- ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
-version_of([{version3,prev3c}|EC], Binary) ->
- Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3C_ASN1_MOD],
- ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
-version_of([{version3,prev3b}|EC], Binary) ->
- Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3B_ASN1_MOD],
- ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
-version_of([{version3,prev3a}|EC], Binary) ->
- Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3A_ASN1_MOD],
- ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
-version_of([driver|EC], Binary) ->
- Decoders = [?V1_ASN1_MOD_DRV, ?V2_ASN1_MOD_DRV, ?V3_ASN1_MOD_DRV],
- ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
-
-%% All values we need to take (special) care of has been delt with,
-%% so just pass the rest on
-version_of(EC, Binary) ->
- Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
- ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders).
-
-
-%%----------------------------------------------------------------------
-%% Convert a 'MegacoMessage' record into a binary
-%% Return {ok, Binary} | {error, Reason}
-%%----------------------------------------------------------------------
-
-
-encode_message(EC,
- #'MegacoMessage'{mess = #'Message'{version = V}} = MegaMsg) ->
- encode_message(EC, V, MegaMsg).
-
-
-%% -- Version 1 --
-
-encode_message([{version3, _},driver|EC], 1, MegaMsg) ->
- AsnMod = ?V1_ASN1_MOD_DRV,
- TransMod = ?V1_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-encode_message([driver|EC], 1, MegaMsg) ->
- AsnMod = ?V1_ASN1_MOD_DRV,
- TransMod = ?V1_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-encode_message([{version3,_}|EC], 1, MegaMsg) ->
- AsnMod = ?V1_ASN1_MOD,
- TransMod = ?V1_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-
-%% All values we need to take (special) care of has been delt with,
-%% so just pass the rest on
-encode_message(EC, 1, MegaMsg) ->
- AsnMod = ?V1_ASN1_MOD,
- TransMod = ?V1_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-
-
-%% -- Version 2 --
-
-encode_message([{version3,_},driver|EC], 2, MegaMsg) ->
- AsnMod = ?V2_ASN1_MOD_DRV,
- TransMod = ?V2_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-encode_message([driver|EC], 2, MegaMsg) ->
- AsnMod = ?V2_ASN1_MOD_DRV,
- TransMod = ?V2_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-encode_message([{version3,_}|EC], 2, MegaMsg) ->
- AsnMod = ?V2_ASN1_MOD,
- TransMod = ?V2_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-
-%% All values we need to take (special) care of has been delt with,
-%% so just pass the rest on
-encode_message(EC, 2, MegaMsg) ->
- AsnMod = ?V2_ASN1_MOD,
- TransMod = ?V2_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-
-
-%% -- Version 3 --
-
-encode_message([{version3,v3},driver|EC], 3, MegaMsg) ->
- AsnMod = ?V3_ASN1_MOD_DRV,
- TransMod = ?V3_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-encode_message([{version3,prev3c},driver|EC], 3, MegaMsg) ->
- AsnMod = ?PREV3C_ASN1_MOD_DRV,
- TransMod = ?PREV3C_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-encode_message([{version3,prev3b},driver|EC], 3, MegaMsg) ->
- AsnMod = ?PREV3B_ASN1_MOD_DRV,
- TransMod = ?PREV3B_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-encode_message([{version3,prev3a},driver|EC], 3, MegaMsg) ->
- AsnMod = ?PREV3A_ASN1_MOD_DRV,
- TransMod = ?PREV3A_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-encode_message([{version3,v3}|EC], 3, MegaMsg) ->
- AsnMod = ?V3_ASN1_MOD,
- TransMod = ?V3_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-encode_message([{version3,prev3c}|EC], 3, MegaMsg) ->
- AsnMod = ?PREV3C_ASN1_MOD,
- TransMod = ?PREV3C_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-encode_message([{version3,prev3b}|EC], 3, MegaMsg) ->
- AsnMod = ?PREV3B_ASN1_MOD,
- TransMod = ?PREV3B_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-encode_message([{version3,prev3a}|EC], 3, MegaMsg) ->
- AsnMod = ?PREV3A_ASN1_MOD,
- TransMod = ?PREV3A_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-encode_message([driver|EC], 3, MegaMsg) ->
- AsnMod = ?V3_ASN1_MOD_DRV,
- TransMod = ?V3_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-
-%% All values we need to take (special) care of has been delt with,
-%% so just pass the rest on
-encode_message(EC, 3, MegaMsg) ->
- AsnMod = ?V3_ASN1_MOD,
- TransMod = ?V3_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list).
-
-
-%%----------------------------------------------------------------------
-%% Convert a transaction (or transactions in the case of ack) record(s)
-%% into a binary
-%% Return {ok, Binary} | {error, Reason}
-%%----------------------------------------------------------------------
-
-%% encode_transaction([] = EC, 1, Trans) ->
-%% AsnMod = ?V1_ASN1_MOD,
-%% TransMod = ?V1_TRANS_MOD,
-%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
-%% io_list);
-%% encode_transaction([native] = EC, 1, Trans) ->
-%% AsnMod = ?V1_ASN1_MOD,
-%% TransMod = ?V1_TRANS_MOD,
-%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
-%% io_list);
-%% encode_transaction([driver|EC], 1, Trans) ->
-%% AsnMod = ?V1_ASN1_MOD_DRV,
-%% TransMod = ?V1_TRANS_MOD,
-%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
-%% io_list);
-%% encode_transaction(_EC, 1, _Trans) ->
-%% AsnMod = ?V1_ASN1_MOD,
-%% TransMod = ?V1_TRANS_MOD,
-%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
-%% io_list);
-%% encode_transaction([] = EC, 2, Trans) ->
-%% AsnMod = ?V2_ASN1_MOD,
-%% TransMod = ?V2_TRANS_MOD,
-%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
-%% io_list);
-%% encode_transaction([native] = EC, 2, Trans) ->
-%% AsnMod = ?V2_ASN1_MOD,
-%% TransMod = ?V2_TRANS_MOD,
-%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
-%% io_list);
-%% encode_transaction([driver|EC], 2, Trans) ->
-%% AsnMod = ?V2_ASN1_MOD_DRV,
-%% TransMod = ?V2_TRANS_MOD,
-%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
-%% io_list);
-%%encode_transaction(_EC, 2, _Trans) ->
-%% AsnMod = ?V2_ASN1_MOD,
-%% TransMod = ?V2_TRANS_MOD,
-%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
-%% io_list).
-%% encode_transaction([] = EC, 3, Trans) ->
-%% AsnMod = ?V3_ASN1_MOD,
-%% TransMod = ?V3_TRANS_MOD,
-%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
-%% io_list);
-%% encode_transaction([native] = EC, 3, Trans) ->
-%% AsnMod = ?V3_ASN1_MOD,
-%% TransMod = ?V3_TRANS_MOD,
-%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
-%% io_list);
-%% encode_transaction([driver|EC], 3, Trans) ->
-%% AsnMod = ?V3_ASN1_MOD_DRV,
-%% TransMod = ?V3_TRANS_MOD,
-%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
-%% io_list);
-%%encode_transaction(_EC, 3, _Trans) ->
-%% AsnMod = ?V3_ASN1_MOD,
-%% TransMod = ?V3_TRANS_MOD,
-%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
-%% io_list).
-encode_transaction(_EC, _V, _Trans) ->
- {error, not_implemented}.
-
-
-%%----------------------------------------------------------------------
-%% Convert a list of ActionRequest record's into a binary
-%% Return {ok, DeepIoList} | {error, Reason}
-%%----------------------------------------------------------------------
-%% encode_action_requests([] = EC, 1, ActReqs) when is_list(ActReqs) ->
-%% AsnMod = ?V1_ASN1_MOD,
-%% TransMod = ?V1_TRANS_MOD,
-%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
-%% AsnMod, TransMod,
-%% io_list);
-%% encode_action_requests([native] = EC, 1, ActReqs) when is_list(ActReqs) ->
-%% AsnMod = ?V1_ASN1_MOD,
-%% TransMod = ?V1_TRANS_MOD,
-%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
-%% AsnMod, TransMod,
-%% io_list);
-%% encode_action_requests([driver|EC], 1, ActReqs) when is_list(ActReqs) ->
-%% AsnMod = ?V1_ASN1_MOD_DRV,
-%% TransMod = ?V1_TRANS_MOD,
-%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
-%% AsnMod, TransMod,
-%% io_list);
-%% encode_action_requests(_EC, 1, ActReqs) when is_list(ActReqs) ->
-%% AsnMod = ?V1_ASN1_MOD,
-%% TransMod = ?V1_TRANS_MOD,
-%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
-%% AsnMod, TransMod,
-%% io_list);
-%% encode_action_requests([] = EC, 2, ActReqs) when is_list(ActReqs) ->
-%% AsnMod = ?V2_ASN1_MOD,
-%% TransMod = ?V2_TRANS_MOD,
-%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
-%% AsnMod, TransMod,
-%% io_list);
-%% encode_action_requests([native] = EC, 2, ActReqs) when is_list(ActReqs) ->
-%% AsnMod = ?V2_ASN1_MOD,
-%% TransMod = ?V2_TRANS_MOD,
-%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
-%% AsnMod, TransMod,
-%% io_list);
-%% encode_action_requests([driver|EC], 2, ActReqs) when is_list(ActReqs) ->
-%% AsnMod = ?V2_ASN1_MOD_DRV,
-%% TransMod = ?V2_TRANS_MOD,
-%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
-%% AsnMod, TransMod,
-%% io_list);
-%% encode_action_requests(_EC, 2, ActReqs) when is_list(ActReqs) ->
-%% AsnMod = ?V2_ASN1_MOD,
-%% TransMod = ?V2_TRANS_MOD,
-%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
-%% AsnMod, TransMod,
-%% io_list);
-%% encode_action_requests([] = EC, 3, ActReqs) when is_list(ActReqs) ->
-%% AsnMod = ?V3_ASN1_MOD,
-%% TransMod = ?V3_TRANS_MOD,
-%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
-%% AsnMod, TransMod,
-%% io_list);
-%% encode_action_requests([native] = EC, 3, ActReqs) when is_list(ActReqs) ->
-%% AsnMod = ?V3_ASN1_MOD,
-%% TransMod = ?V3_TRANS_MOD,
-%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
-%% AsnMod, TransMod,
-%% io_list);
-%% encode_action_requests([driver|EC], 3, ActReqs) when is_list(ActReqs) ->
-%% AsnMod = ?V3_ASN1_MOD_DRV,
-%% TransMod = ?V3_TRANS_MOD,
-%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
-%% AsnMod, TransMod,
-%% io_list);
-%%encode_action_requests(_EC, 3, ActReqs) when is_list(ActReqs) ->
-%% AsnMod = ?V3_ASN1_MOD,
-%% TransMod = ?V3_TRANS_MOD,
-%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
-%% AsnMod, TransMod,
-%% io_list);
-%% encode_action_requests(_EC, V, _ActReqs) ->
-%% {error, {bad_version, V}}.
-encode_action_requests(_EC, _V, _ActReqs) ->
- {error, not_implemented}.
-
-
-%%----------------------------------------------------------------------
-%% Convert a ActionRequest record into a binary
-%% Return {ok, DeepIoList} | {error, Reason}
-%%----------------------------------------------------------------------
-%% encode_action_request([] = EC, 1, ActReq) ->
-%% AsnMod = ?V1_ASN1_MOD,
-%% TransMod = ?V1_TRANS_MOD,
-%% ?BIN_LIB:encode_action_request(EC, ActReq,
-%% AsnMod, TransMod,
-%% io_list);
-%% encode_action_request([native] = EC, 1, ActReq) ->
-%% AsnMod = ?V1_ASN1_MOD,
-%% TransMod = ?V1_TRANS_MOD,
-%% ?BIN_LIB:encode_action_request(EC, ActReq,
-%% AsnMod, TransMod,
-%% io_list);
-%% encode_action_request([driver|EC], 1, ActReq) ->
-%% AsnMod = ?V1_ASN1_MOD_DRV,
-%% TransMod = ?V1_TRANS_MOD,
-%% ?BIN_LIB:encode_action_request(EC, ActReq,
-%% AsnMod, TransMod,
-%% io_list);
-%% encode_action_request(_EC, 1, ActReq) ->
-%% AsnMod = ?V1_ASN1_MOD,
-%% TransMod = ?V1_TRANS_MOD,
-%% ?BIN_LIB:encode_action_request(EC, ActReq,
-%% AsnMod, TransMod,
-%% io_list);
-%% encode_action_request([] = EC, 2, ActReq) ->
-%% AsnMod = ?V2_ASN1_MOD,
-%% TransMod = ?V2_TRANS_MOD,
-%% ?BIN_LIB:encode_action_request(EC, ActReq,
-%% AsnMod, TransMod,
-%% io_list);
-%% encode_action_request([native] = EC, 2, ActReq) ->
-%% AsnMod = ?V2_ASN1_MOD,
-%% TransMod = ?V2_TRANS_MOD,
-%% ?BIN_LIB:encode_action_request(EC, ActReq,
-%% AsnMod, TransMod,
-%% io_list);
-%% encode_action_request([driver|EC], 2, ActReq) ->
-%% AsnMod = ?V2_ASN1_MOD_DRV,
-%% TransMod = ?V2_TRANS_MOD,
-%% ?BIN_LIB:encode_action_request(EC, ActReq,
-%% AsnMod, TransMod,
-%% io_list);
-%% encode_action_request(_EC, 2, ActReq) ->
-%% AsnMod = ?V2_ASN1_MOD,
-%% TransMod = ?V2_TRANS_MOD,
-%% ?BIN_LIB:encode_action_request(EC, ActReq,
-%% AsnMod, TransMod,
-%% io_list);
-%% encode_action_request([] = EC, 3, ActReq) ->
-%% AsnMod = ?V3_ASN1_MOD,
-%% TransMod = ?V3_TRANS_MOD,
-%% ?BIN_LIB:encode_action_request(EC, ActReq,
-%% AsnMod, TransMod,
-%% io_list);
-%% encode_action_request([native] = EC, 3, ActReq) ->
-%% AsnMod = ?V3_ASN1_MOD,
-%% TransMod = ?V3_TRANS_MOD,
-%% ?BIN_LIB:encode_action_request(EC, ActReq,
-%% AsnMod, TransMod,
-%% io_list);
-%% encode_action_request([driver|EC], 3, ActReq) ->
-%% AsnMod = ?V3_ASN1_MOD_DRV,
-%% TransMod = ?V3_TRANS_MOD,
-%% ?BIN_LIB:encode_action_request(EC, ActReq,
-%% AsnMod, TransMod,
-%% io_list);
-%% encode_action_request(_EC, 3, ActReq) ->
-%% AsnMod = ?V3_ASN1_MOD,
-%% TransMod = ?V3_TRANS_MOD,
-%% ?BIN_LIB:encode_action_request(EC, ActReq,
-%% AsnMod, TransMod,
-%% io_list);
-encode_action_request(_EC, _V, _ActReq) ->
- {error, not_implemented}.
-
-
-%%----------------------------------------------------------------------
-%% Convert a action reply into a deep io list
-%% Not yest supported by this binary codec!
-%% Return {ok, DeepIoList} | {error, Reason}
-%%----------------------------------------------------------------------
-
-encode_action_reply(_EC, _V, _AcionReply) ->
- {error, not_implemented}.
-
-
-%%----------------------------------------------------------------------
-%% Convert a binary into a 'MegacoMessage' record
-%% Return {ok, MegacoMessageRecord} | {error, Reason}
-%%----------------------------------------------------------------------
-
-%% Old decode function
-decode_message(EC, Binary) ->
- decode_message(EC, 1, Binary).
-
-%% -- Dynamic version detection --
-
-%% Select from message
-decode_message([{version3,v3},driver|EC], dynamic, Binary) ->
- Mods = [{?V1_ASN1_MOD_DRV, ?V1_TRANS_MOD},
- {?V2_ASN1_MOD_DRV, ?V2_TRANS_MOD},
- {?V3_ASN1_MOD_DRV, ?V3_TRANS_MOD}],
- ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
-decode_message([{version3,prev3c},driver|EC], dynamic, Binary) ->
- Mods = [{?V1_ASN1_MOD_DRV, ?V1_TRANS_MOD},
- {?V2_ASN1_MOD_DRV, ?V2_TRANS_MOD},
- {?PREV3C_ASN1_MOD_DRV, ?PREV3C_TRANS_MOD}],
- ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
-decode_message([{version3,prev3b},driver|EC], dynamic, Binary) ->
- Mods = [{?V1_ASN1_MOD_DRV, ?V1_TRANS_MOD},
- {?V2_ASN1_MOD_DRV, ?V2_TRANS_MOD},
- {?PREV3B_ASN1_MOD_DRV, ?PREV3B_TRANS_MOD}],
- ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
-decode_message([{version3,prev3a},driver|EC], dynamic, Binary) ->
- Mods = [{?V1_ASN1_MOD_DRV, ?V1_TRANS_MOD},
- {?V2_ASN1_MOD_DRV, ?V2_TRANS_MOD},
- {?PREV3A_ASN1_MOD_DRV, ?PREV3A_TRANS_MOD}],
- ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
-decode_message([{version3,v3}|EC], dynamic, Binary) ->
- Mods = [{?V1_ASN1_MOD, ?V1_TRANS_MOD},
- {?V2_ASN1_MOD, ?V2_TRANS_MOD},
- {?V3_ASN1_MOD, ?V3_TRANS_MOD}],
- ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
-decode_message([{version3,prev3c}|EC], dynamic, Binary) ->
- Mods = [{?V1_ASN1_MOD, ?V1_TRANS_MOD},
- {?V2_ASN1_MOD, ?V2_TRANS_MOD},
- {?PREV3C_ASN1_MOD, ?PREV3C_TRANS_MOD}],
- ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
-decode_message([{version3,prev3b}|EC], dynamic, Binary) ->
- Mods = [{?V1_ASN1_MOD, ?V1_TRANS_MOD},
- {?V2_ASN1_MOD, ?V2_TRANS_MOD},
- {?PREV3B_ASN1_MOD, ?PREV3B_TRANS_MOD}],
- ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
-decode_message([{version3,prev3a}|EC], dynamic, Binary) ->
- Mods = [{?V1_ASN1_MOD, ?V1_TRANS_MOD},
- {?V2_ASN1_MOD, ?V2_TRANS_MOD},
- {?PREV3A_ASN1_MOD, ?PREV3A_TRANS_MOD}],
- ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
-decode_message([driver|EC], dynamic, Binary) ->
- Mods = [{?V1_ASN1_MOD_DRV, ?V1_TRANS_MOD},
- {?V2_ASN1_MOD_DRV, ?V2_TRANS_MOD},
- {?V3_ASN1_MOD_DRV, ?V3_TRANS_MOD}],
- ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
-
-%% All values we need to take (special) care of has been delt with,
-%% so just pass the rest on
-decode_message(EC, dynamic, Binary) ->
- Mods = [{?V1_ASN1_MOD, ?V1_TRANS_MOD},
- {?V2_ASN1_MOD, ?V2_TRANS_MOD},
- {?V3_ASN1_MOD, ?V3_TRANS_MOD}],
- ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
-
-
-%% -- Version 1 --
-
-decode_message([{version3,_},driver|EC], 1, Binary) ->
- AsnMod = ?V1_ASN1_MOD_DRV,
- TransMod = ?V1_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-decode_message([driver|EC], 1, Binary) ->
- AsnMod = ?V1_ASN1_MOD_DRV,
- TransMod = ?V1_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-decode_message([{version3,_}|EC], 1, Binary) ->
- AsnMod = ?V1_ASN1_MOD,
- TransMod = ?V1_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-
-%% All values we need to take (special) care of has been delt with,
-%% so just pass the rest on
-decode_message(EC, 1, Binary) ->
- AsnMod = ?V1_ASN1_MOD,
- TransMod = ?V1_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-
-
-%% -- Version 2 --
-
-decode_message([{version3,_},driver|EC], 2, Binary) ->
- AsnMod = ?V2_ASN1_MOD_DRV,
- TransMod = ?V2_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-decode_message([driver|EC], 2, Binary) ->
- AsnMod = ?V2_ASN1_MOD_DRV,
- TransMod = ?V2_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-decode_message([{version3,_}|EC], 2, Binary) ->
- AsnMod = ?V2_ASN1_MOD,
- TransMod = ?V2_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-
-%% All values we need to take (special) care of has been delt with,
-%% so just pass the rest on
-decode_message(EC, 2, Binary) ->
- AsnMod = ?V2_ASN1_MOD,
- TransMod = ?V2_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-
-
-%% -- Version 3 --
-
-decode_message([{version3,v3},driver|EC], 3, Binary) ->
- AsnMod = ?V3_ASN1_MOD_DRV,
- TransMod = ?V3_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-decode_message([{version3,prev3c},driver|EC], 3, Binary) ->
- AsnMod = ?PREV3C_ASN1_MOD_DRV,
- TransMod = ?PREV3C_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-decode_message([{version3,prev3b},driver|EC], 3, Binary) ->
- AsnMod = ?PREV3B_ASN1_MOD_DRV,
- TransMod = ?PREV3B_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-decode_message([{version3,prev3a},driver|EC], 3, Binary) ->
- AsnMod = ?PREV3A_ASN1_MOD_DRV,
- TransMod = ?PREV3A_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-decode_message([{version3,v3}|EC], 3, Binary) ->
- AsnMod = ?V3_ASN1_MOD,
- TransMod = ?V3_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-decode_message([{version3,prev3c}|EC], 3, Binary) ->
- AsnMod = ?PREV3C_ASN1_MOD,
- TransMod = ?PREV3C_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-decode_message([{version3,prev3b}|EC], 3, Binary) ->
- AsnMod = ?PREV3B_ASN1_MOD,
- TransMod = ?PREV3B_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-decode_message([{version3,prev3a}|EC], 3, Binary) ->
- AsnMod = ?PREV3A_ASN1_MOD,
- TransMod = ?PREV3A_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-decode_message([driver|EC], 3, Binary) ->
- AsnMod = ?V3_ASN1_MOD_DRV,
- TransMod = ?V3_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-
-%% All values we need to take (special) care of has been delt with,
-%% so just pass the rest on
-decode_message(EC, 3, Binary) ->
- AsnMod = ?V3_ASN1_MOD,
- TransMod = ?V3_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary).
-
-
-decode_mini_message([{version3,v3},driver|EC], dynamic, Bin) ->
- Mods = [?V1_ASN1_MOD_DRV,
- ?V2_ASN1_MOD_DRV,
- ?V3_ASN1_MOD_DRV],
- ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
-decode_mini_message([{version3,prev3c},driver|EC], dynamic, Bin) ->
- Mods = [?V1_ASN1_MOD_DRV,
- ?V2_ASN1_MOD_DRV,
- ?PREV3C_ASN1_MOD_DRV],
- ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
-decode_mini_message([{version3,prev3b},driver|EC], dynamic, Bin) ->
- Mods = [?V1_ASN1_MOD_DRV,
- ?V2_ASN1_MOD_DRV,
- ?PREV3B_ASN1_MOD_DRV],
- ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
-decode_mini_message([{version3,prev3a},driver|EC], dynamic, Bin) ->
- Mods = [?V1_ASN1_MOD_DRV,
- ?V2_ASN1_MOD_DRV,
- ?PREV3A_ASN1_MOD_DRV],
- ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
-decode_mini_message([{version3,v3}|EC], dynamic, Bin) ->
- Mods = [?V1_ASN1_MOD,
- ?V2_ASN1_MOD,
- ?V3_ASN1_MOD],
- ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
-decode_mini_message([{version3,prev3c}|EC], dynamic, Bin) ->
- Mods = [?V1_ASN1_MOD,
- ?V2_ASN1_MOD,
- ?PREV3C_ASN1_MOD],
- ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
-decode_mini_message([{version3,prev3b}|EC], dynamic, Bin) ->
- Mods = [?V1_ASN1_MOD,
- ?V2_ASN1_MOD,
- ?PREV3B_ASN1_MOD],
- ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
-decode_mini_message([{version3,prev3a}|EC], dynamic, Bin) ->
- Mods = [?V1_ASN1_MOD,
- ?V2_ASN1_MOD,
- ?PREV3A_ASN1_MOD],
- ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
-decode_mini_message([driver|EC], dynamic, Bin) ->
- Mods = [?V1_ASN1_MOD_DRV,
- ?V2_ASN1_MOD_DRV,
- ?V3_ASN1_MOD_DRV],
- ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
-decode_mini_message(EC, dynamic, Bin) ->
- Mods = [?V1_ASN1_MOD,
- ?V2_ASN1_MOD,
- ?V3_ASN1_MOD],
- ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
-decode_mini_message([{version3,_},driver|EC], 1, Bin) ->
- AsnMod = ?V1_ASN1_MOD_DRV,
- ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
-decode_mini_message([{version3,_}|EC], 1, Bin) ->
- AsnMod = ?V1_ASN1_MOD,
- ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
-decode_mini_message([driver|EC], 1, Bin) ->
- AsnMod = ?V1_ASN1_MOD_DRV,
- ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
-decode_mini_message(EC, 1, Bin) ->
- AsnMod = ?V1_ASN1_MOD,
- ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
-decode_mini_message([{version3,_},driver|EC], 2, Bin) ->
- AsnMod = ?V2_ASN1_MOD_DRV,
- ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
-decode_mini_message([{version3,_}|EC], 2, Bin) ->
- AsnMod = ?V2_ASN1_MOD,
- ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
-decode_mini_message([driver|EC], 2, Bin) ->
- AsnMod = ?V2_ASN1_MOD_DRV,
- ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
-decode_mini_message(EC, 2, Bin) ->
- AsnMod = ?V2_ASN1_MOD,
- ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
-decode_mini_message([{version3,v3},driver|EC], 3, Bin) ->
- AsnMod = ?V3_ASN1_MOD_DRV,
- ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
-decode_mini_message([{version3,prev3c},driver|EC], 3, Bin) ->
- AsnMod = ?PREV3C_ASN1_MOD_DRV,
- ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
-decode_mini_message([{version3,prev3b},driver|EC], 3, Bin) ->
- AsnMod = ?PREV3B_ASN1_MOD_DRV,
- ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
-decode_mini_message([{version3,prev3a},driver|EC], 3, Bin) ->
- AsnMod = ?PREV3A_ASN1_MOD_DRV,
- ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
-decode_mini_message([{version3,v3}|EC], 3, Bin) ->
- AsnMod = ?V3_ASN1_MOD,
- ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
-decode_mini_message([{version3,prev3c}|EC], 3, Bin) ->
- AsnMod = ?PREV3C_ASN1_MOD,
- ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
-decode_mini_message([{version3,prev3b}|EC], 3, Bin) ->
- AsnMod = ?PREV3B_ASN1_MOD,
- ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
-decode_mini_message([{version3,prev3a}|EC], 3, Bin) ->
- AsnMod = ?PREV3A_ASN1_MOD,
- ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
-decode_mini_message([driver|EC], 3, Bin) ->
- AsnMod = ?V3_ASN1_MOD_DRV,
- ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
-decode_mini_message(EC, 3, Bin) ->
- AsnMod = ?V3_ASN1_MOD,
- ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary).
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3a.set.asn b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3a.set.asn
deleted file mode 100644
index b9ba7ffdb4..0000000000
--- a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3a.set.asn
+++ /dev/null
@@ -1 +0,0 @@
-MEDIA-GATEWAY-CONTROL-prev3a.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3b.set.asn b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3b.set.asn
deleted file mode 100644
index 0437bde310..0000000000
--- a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3b.set.asn
+++ /dev/null
@@ -1 +0,0 @@
-MEDIA-GATEWAY-CONTROL-prev3b.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3c.asn1config b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3c.asn1config
deleted file mode 100644
index c74422b9a2..0000000000
--- a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3c.asn1config
+++ /dev/null
@@ -1,43 +0,0 @@
-{exclusive_decode,
- {'megaco_ber_bin_media_gateway_control_prev3c',
- [
- {decode_message_trans_partial,
- [
- 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
- ]
- },
- {decode_message_acts_partial,
- ['Transaction',
- [
- {transactionRequest,
- [
- {actions,parts}
- ]
- },
- {transactionReply,
- [
- {transactionResult, [{actionReplies,parts}]}
- ]
- }
- ]
- ]
- },
- {decode_message_version,
- ['MegacoMessage',
- [
- {authHeader,undecoded},
- {mess,[{mId,undecoded},{messageBody,undecoded}]}
- ]
- ]
- },
- {decode_message_mId,
- ['MegacoMessage',
- [
- {authHeader,undecoded},
- {mess,[{messageBody,undecoded}]}
- ]
- ]
- }
- ]
- }
-}.
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3c.set.asn b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3c.set.asn
deleted file mode 100644
index e78055fbad..0000000000
--- a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3c.set.asn
+++ /dev/null
@@ -1 +0,0 @@
-MEDIA-GATEWAY-CONTROL-prev3c.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v1.asn1config b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v1.asn1config
deleted file mode 100644
index e815e90948..0000000000
--- a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v1.asn1config
+++ /dev/null
@@ -1,44 +0,0 @@
-{exclusive_decode,
- {'megaco_ber_bin_media_gateway_control_v1',
- [
- {decode_message_trans_partial,
- [
- 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
- ]
- },
- {decode_message_acts_partial,
- ['Transaction',
- [
- {transactionRequest,
- [
- {actions,parts}
- ]
- },
- {transactionReply,
- [
- {transactionResult, [{actionReplies,parts}]}
- ]
- }
- ]
- ]
- },
- {decode_message_version,
- ['MegacoMessage',
- [
- {authHeader,undecoded},
- {mess,[{mId,undecoded},{messageBody,undecoded}]}
- ]
- ]
- },
- {decode_message_mId,
- ['MegacoMessage',
- [
- {authHeader,undecoded},
- {mess,[{messageBody,undecoded}]}
- ]
- ]
- }
-
- ]
- }
-}.
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v1.set.asn b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v1.set.asn
deleted file mode 100644
index 0f5a92dba1..0000000000
--- a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v1.set.asn
+++ /dev/null
@@ -1 +0,0 @@
-MEDIA-GATEWAY-CONTROL-v1.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v2.set.asn b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v2.set.asn
deleted file mode 100644
index 7fc82b127f..0000000000
--- a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v2.set.asn
+++ /dev/null
@@ -1 +0,0 @@
-MEDIA-GATEWAY-CONTROL-v2.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v3.set.asn b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v3.set.asn
deleted file mode 100644
index 1d7950a283..0000000000
--- a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v3.set.asn
+++ /dev/null
@@ -1 +0,0 @@
-MEDIA-GATEWAY-CONTROL-v3.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v2.asn1config b/lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3a.asn1config
index cc072b30ee..da67561f1b 100644
--- a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v2.asn1config
+++ b/lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3a.asn1config
@@ -1,5 +1,5 @@
{exclusive_decode,
- {'megaco_ber_bin_media_gateway_control_v2',
+ {'megaco_ber_media_gateway_control_prev3a',
[
{decode_message_trans_partial,
[
@@ -14,7 +14,7 @@
{actions,parts}
]
},
- {transactionReply,
+ {transactionReply,
[
{transactionResult, [{actionReplies,parts}]}
]
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v3.asn1config b/lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3b.asn1config
index deeb2b2da9..2f25f03d97 100644
--- a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v3.asn1config
+++ b/lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3b.asn1config
@@ -1,5 +1,5 @@
{exclusive_decode,
- {'megaco_ber_bin_media_gateway_control_v3',
+ {'megaco_ber_media_gateway_control_prev3b',
[
{decode_message_trans_partial,
[
@@ -14,7 +14,7 @@
{actions,parts}
]
},
- {transactionReply,
+ {transactionReply,
[
{transactionResult, [{actionReplies,parts}]}
]
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3a.asn1config b/lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3c.asn1config
index 456ce750ad..23c343eed0 100644
--- a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3a.asn1config
+++ b/lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3c.asn1config
@@ -1,5 +1,5 @@
{exclusive_decode,
- {'megaco_ber_bin_media_gateway_control_prev3a',
+ {'megaco_ber_media_gateway_control_prev3c',
[
{decode_message_trans_partial,
[
@@ -14,7 +14,7 @@
{actions,parts}
]
},
- {transactionReply,
+ {transactionReply,
[
{transactionResult, [{actionReplies,parts}]}
]
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v1.asn1config b/lib/megaco/src/binary/megaco_ber_media_gateway_control_v1.asn1config
index ea10a7d527..951825c0aa 100644
--- a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v1.asn1config
+++ b/lib/megaco/src/binary/megaco_ber_media_gateway_control_v1.asn1config
@@ -1,5 +1,5 @@
{exclusive_decode,
- {'megaco_ber_bin_drv_media_gateway_control_v1',
+ {'megaco_ber_media_gateway_control_v1',
[
{decode_message_trans_partial,
[
@@ -14,7 +14,7 @@
{actions,parts}
]
},
- {transactionReply,
+ {transactionReply,
[
{transactionResult, [{actionReplies,parts}]}
]
@@ -38,7 +38,7 @@
]
]
}
+
]
}
}.
-
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3b.asn1config b/lib/megaco/src/binary/megaco_ber_media_gateway_control_v3.asn1config
index fa5cd80baf..e4b1f9ece9 100644
--- a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3b.asn1config
+++ b/lib/megaco/src/binary/megaco_ber_media_gateway_control_v3.asn1config
@@ -1,5 +1,5 @@
{exclusive_decode,
- {'megaco_ber_bin_media_gateway_control_prev3b',
+ {'megaco_ber_media_gateway_control_v3',
[
{decode_message_trans_partial,
[
@@ -14,7 +14,7 @@
{actions,parts}
]
},
- {transactionReply,
+ {transactionReply,
[
{transactionResult, [{actionReplies,parts}]}
]
diff --git a/lib/megaco/src/binary/megaco_binary_encoder.erl b/lib/megaco/src/binary/megaco_binary_encoder.erl
index f825f91a45..51e167590d 100644
--- a/lib/megaco/src/binary/megaco_binary_encoder.erl
+++ b/lib/megaco/src/binary/megaco_binary_encoder.erl
@@ -241,55 +241,30 @@ encode_action_reply(_EC, _V, _AcionReply) ->
%% Return {ok, Version} | {error, Reason}
%%----------------------------------------------------------------------
-version_of([{version3,v3},driver|EC], Binary) ->
- Decoders = [megaco_ber_bin_drv_media_gateway_control_v1,
- megaco_ber_bin_drv_media_gateway_control_v2,
- megaco_ber_bin_drv_media_gateway_control_v3],
- ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
-version_of([{version3,prev3c},driver|EC], Binary) ->
- Decoders = [megaco_ber_bin_drv_media_gateway_control_v1,
- megaco_ber_bin_drv_media_gateway_control_v2,
- megaco_ber_bin_drv_media_gateway_control_prev3c],
- ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
-version_of([{version3,prev3b},driver|EC], Binary) ->
- Decoders = [megaco_ber_bin_drv_media_gateway_control_v1,
- megaco_ber_bin_drv_media_gateway_control_v2,
- megaco_ber_bin_drv_media_gateway_control_prev3b],
- ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
-version_of([{version3,prev3a},driver|EC], Binary) ->
- Decoders = [megaco_ber_bin_drv_media_gateway_control_v1,
- megaco_ber_bin_drv_media_gateway_control_v2,
- megaco_ber_bin_drv_media_gateway_control_prev3a],
- ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
-version_of([driver|EC], Binary) ->
- Decoders = [megaco_ber_bin_drv_media_gateway_control_v1,
- megaco_ber_bin_drv_media_gateway_control_v2,
- megaco_ber_bin_drv_media_gateway_control_v3],
- ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
version_of([{version3,v3}|EC], Binary) ->
- Decoders = [megaco_ber_bin_media_gateway_control_v1,
- megaco_ber_bin_media_gateway_control_v2,
- megaco_ber_bin_media_gateway_control_v3],
+ Decoders = [megaco_ber_media_gateway_control_v1,
+ megaco_ber_media_gateway_control_v2,
+ megaco_ber_media_gateway_control_v3],
?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
version_of([{version3,prev3c}|EC], Binary) ->
- Decoders = [megaco_ber_bin_media_gateway_control_v1,
- megaco_ber_bin_media_gateway_control_v2,
- megaco_ber_bin_media_gateway_control_prev3c],
+ Decoders = [megaco_ber_media_gateway_control_v1,
+ megaco_ber_media_gateway_control_v2,
+ megaco_ber_media_gateway_control_prev3c],
?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
version_of([{version3,prev3b}|EC], Binary) ->
- Decoders = [megaco_ber_bin_media_gateway_control_v1,
- megaco_ber_bin_media_gateway_control_v2,
- megaco_ber_bin_media_gateway_control_prev3b],
+ Decoders = [megaco_ber_media_gateway_control_v1,
+ megaco_ber_media_gateway_control_v2,
+ megaco_ber_media_gateway_control_prev3b],
?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
version_of([{version3,prev3a}|EC], Binary) ->
- Decoders = [megaco_ber_bin_media_gateway_control_v1,
- megaco_ber_bin_media_gateway_control_v2,
- megaco_ber_bin_media_gateway_control_prev3a],
+ Decoders = [megaco_ber_media_gateway_control_v1,
+ megaco_ber_media_gateway_control_v2,
+ megaco_ber_media_gateway_control_prev3a],
?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
version_of(EC, Binary) ->
- Decoders = [megaco_ber_bin_media_gateway_control_v1,
- megaco_ber_bin_media_gateway_control_v2,
- megaco_ber_bin_media_gateway_control_v3],
+ Decoders = [megaco_ber_media_gateway_control_v1,
+ megaco_ber_media_gateway_control_v2,
+ megaco_ber_media_gateway_control_v3],
?BIN_LIB:version_of(EC, Binary, dynamic, Decoders).
@@ -301,287 +276,153 @@ version_of(EC, Binary) ->
decode_message(EC, Binary) ->
decode_message(EC, 1, Binary).
-decode_message([{version3,v3},driver|EC], dynamic, Binary) ->
- Decoders = [{megaco_ber_bin_drv_media_gateway_control_v1,
- megaco_binary_transformer_v1},
- {megaco_ber_bin_drv_media_gateway_control_v2,
- megaco_binary_transformer_v2},
- {megaco_ber_bin_drv_media_gateway_control_v3,
- megaco_binary_transformer_v3}],
- ?BIN_LIB:decode_message_dynamic(EC, Binary, Decoders, binary);
-decode_message([{version3,prev3c},driver|EC], dynamic, Binary) ->
- Decoders = [{megaco_ber_bin_drv_media_gateway_control_v1,
- megaco_binary_transformer_v1},
- {megaco_ber_bin_drv_media_gateway_control_v2,
- megaco_binary_transformer_v2},
- {megaco_ber_bin_drv_media_gateway_control_prev3c,
- megaco_binary_transformer_prev3c}],
- ?BIN_LIB:decode_message_dynamic(EC, Binary, Decoders, binary);
-decode_message([{version3,prev3b},driver|EC], dynamic, Binary) ->
- Decoders = [{megaco_ber_bin_drv_media_gateway_control_v1,
- megaco_binary_transformer_v1},
- {megaco_ber_bin_drv_media_gateway_control_v2,
- megaco_binary_transformer_v2},
- {megaco_ber_bin_drv_media_gateway_control_prev3b,
- megaco_binary_transformer_prev3b}],
- ?BIN_LIB:decode_message_dynamic(EC, Binary, Decoders, binary);
-decode_message([{version3,prev3a},driver|EC], dynamic, Binary) ->
- Decoders = [{megaco_ber_bin_drv_media_gateway_control_v1,
- megaco_binary_transformer_v1},
- {megaco_ber_bin_drv_media_gateway_control_v2,
- megaco_binary_transformer_v2},
- {megaco_ber_bin_drv_media_gateway_control_prev3a,
- megaco_binary_transformer_prev3a}],
- ?BIN_LIB:decode_message_dynamic(EC, Binary, Decoders, binary);
-decode_message([driver|EC], dynamic, Binary) ->
- Decoders = [{megaco_ber_bin_drv_media_gateway_control_v1,
- megaco_binary_transformer_v1},
- {megaco_ber_bin_drv_media_gateway_control_v2,
- megaco_binary_transformer_v2},
- {megaco_ber_bin_drv_media_gateway_control_v3,
- megaco_binary_transformer_v3}],
- ?BIN_LIB:decode_message_dynamic(EC, Binary, Decoders, binary);
decode_message([{version3,v3}|EC], dynamic, Binary) ->
- Decoders = [{megaco_ber_bin_media_gateway_control_v1,
+ Decoders = [{megaco_ber_media_gateway_control_v1,
megaco_binary_transformer_v1},
- {megaco_ber_bin_media_gateway_control_v2,
+ {megaco_ber_media_gateway_control_v2,
megaco_binary_transformer_v2},
- {megaco_ber_bin_media_gateway_control_v3,
+ {megaco_ber_media_gateway_control_v3,
megaco_binary_transformer_v3}],
?BIN_LIB:decode_message_dynamic(EC, Binary, Decoders, binary);
decode_message([{version3,prev3c}|EC], dynamic, Binary) ->
- Decoders = [{megaco_ber_bin_media_gateway_control_v1,
+ Decoders = [{megaco_ber_media_gateway_control_v1,
megaco_binary_transformer_v1},
- {megaco_ber_bin_media_gateway_control_v2,
+ {megaco_ber_media_gateway_control_v2,
megaco_binary_transformer_v2},
- {megaco_ber_bin_media_gateway_control_prev3c,
+ {megaco_ber_media_gateway_control_prev3c,
megaco_binary_transformer_prev3c}],
?BIN_LIB:decode_message_dynamic(EC, Binary, Decoders, binary);
decode_message([{version3,prev3b}|EC], dynamic, Binary) ->
- Decoders = [{megaco_ber_bin_media_gateway_control_v1,
+ Decoders = [{megaco_ber_media_gateway_control_v1,
megaco_binary_transformer_v1},
- {megaco_ber_bin_media_gateway_control_v2,
+ {megaco_ber_media_gateway_control_v2,
megaco_binary_transformer_v2},
- {megaco_ber_bin_media_gateway_control_prev3b,
+ {megaco_ber_media_gateway_control_prev3b,
megaco_binary_transformer_prev3b}],
?BIN_LIB:decode_message_dynamic(EC, Binary, Decoders, binary);
decode_message([{version3,prev3a}|EC], dynamic, Binary) ->
- Decoders = [{megaco_ber_bin_media_gateway_control_v1,
+ Decoders = [{megaco_ber_media_gateway_control_v1,
megaco_binary_transformer_v1},
- {megaco_ber_bin_media_gateway_control_v2,
+ {megaco_ber_media_gateway_control_v2,
megaco_binary_transformer_v2},
- {megaco_ber_bin_media_gateway_control_prev3a,
+ {megaco_ber_media_gateway_control_prev3a,
megaco_binary_transformer_prev3a}],
?BIN_LIB:decode_message_dynamic(EC, Binary, Decoders, binary);
decode_message(EC, dynamic, Binary) ->
- Decoders = [{megaco_ber_bin_media_gateway_control_v1,
+ Decoders = [{megaco_ber_media_gateway_control_v1,
megaco_binary_transformer_v1},
- {megaco_ber_bin_media_gateway_control_v2,
+ {megaco_ber_media_gateway_control_v2,
megaco_binary_transformer_v2},
- {megaco_ber_bin_media_gateway_control_v3,
+ {megaco_ber_media_gateway_control_v3,
megaco_binary_transformer_v3}],
?BIN_LIB:decode_message_dynamic(EC, Binary, Decoders, binary);
%% -- Version 1 --
-decode_message([{version3,_},driver|EC], 1, Binary) ->
- AsnMod = megaco_ber_bin_drv_media_gateway_control_v1,
- TransMod = megaco_binary_transformer_v1,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-
-decode_message([driver|EC], 1, Binary) ->
- AsnMod = megaco_ber_bin_drv_media_gateway_control_v1,
- TransMod = megaco_binary_transformer_v1,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-
decode_message([{version3,_}|EC], 1, Binary) ->
- AsnMod = megaco_ber_bin_media_gateway_control_v1,
+ AsnMod = megaco_ber_media_gateway_control_v1,
TransMod = megaco_binary_transformer_v1,
?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
decode_message(EC, 1, Binary) ->
- AsnMod = megaco_ber_bin_media_gateway_control_v1,
+ AsnMod = megaco_ber_media_gateway_control_v1,
TransMod = megaco_binary_transformer_v1,
?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
%% -- Version 2 --
-decode_message([{version3,_},driver|EC], 2, Binary) ->
- AsnMod = megaco_ber_bin_drv_media_gateway_control_v2,
- TransMod = megaco_binary_transformer_v2,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-
-decode_message([driver|EC], 2, Binary) ->
- AsnMod = megaco_ber_bin_drv_media_gateway_control_v2,
- TransMod = megaco_binary_transformer_v2,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-
decode_message([{version3,_}|EC], 2, Binary) ->
- AsnMod = megaco_ber_bin_media_gateway_control_v2,
+ AsnMod = megaco_ber_media_gateway_control_v2,
TransMod = megaco_binary_transformer_v2,
?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
decode_message(EC, 2, Binary) ->
- AsnMod = megaco_ber_bin_media_gateway_control_v2,
+ AsnMod = megaco_ber_media_gateway_control_v2,
TransMod = megaco_binary_transformer_v2,
?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
%% -- Version 3 --
-decode_message([{version3,v3},driver|EC], 3, Binary) ->
- AsnMod = megaco_ber_bin_drv_media_gateway_control_v3,
- TransMod = megaco_binary_transformer_v3,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-decode_message([{version3,prev3c},driver|EC], 3, Binary) ->
- AsnMod = megaco_ber_bin_drv_media_gateway_control_prev3c,
- TransMod = megaco_binary_transformer_prev3c,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-decode_message([{version3,prev3b},driver|EC], 3, Binary) ->
- AsnMod = megaco_ber_bin_drv_media_gateway_control_prev3b,
- TransMod = megaco_binary_transformer_prev3b,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-decode_message([{version3,prev3a},driver|EC], 3, Binary) ->
- AsnMod = megaco_ber_bin_drv_media_gateway_control_prev3a,
- TransMod = megaco_binary_transformer_prev3a,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-
-decode_message([driver|EC], 3, Binary) ->
- AsnMod = megaco_ber_bin_drv_media_gateway_control_v3,
- TransMod = megaco_binary_transformer_v3,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-
decode_message([{version3,v3}|EC], 3, Binary) ->
- AsnMod = megaco_ber_bin_media_gateway_control_v3,
+ AsnMod = megaco_ber_media_gateway_control_v3,
TransMod = megaco_binary_transformer_v3,
?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
decode_message([{version3,prev3c}|EC], 3, Binary) ->
- AsnMod = megaco_ber_bin_media_gateway_control_prev3c,
+ AsnMod = megaco_ber_media_gateway_control_prev3c,
TransMod = megaco_binary_transformer_prev3c,
?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
decode_message([{version3,prev3b}|EC], 3, Binary) ->
- AsnMod = megaco_ber_bin_media_gateway_control_prev3b,
+ AsnMod = megaco_ber_media_gateway_control_prev3b,
TransMod = megaco_binary_transformer_prev3b,
?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
decode_message([{version3,prev3a}|EC], 3, Binary) ->
- AsnMod = megaco_ber_bin_media_gateway_control_prev3a,
+ AsnMod = megaco_ber_media_gateway_control_prev3a,
TransMod = megaco_binary_transformer_prev3a,
?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
decode_message(EC, 3, Binary) ->
- AsnMod = megaco_ber_bin_media_gateway_control_v3,
+ AsnMod = megaco_ber_media_gateway_control_v3,
TransMod = megaco_binary_transformer_v3,
?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary).
-decode_mini_message([{version3,v3},driver|EC], dynamic, Bin) ->
- Mods = [megaco_ber_bin_drv_media_gateway_control_v1,
- megaco_ber_bin_drv_media_gateway_control_v2,
- megaco_ber_bin_drv_media_gateway_control_v3],
- ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
-decode_mini_message([{version3,prev3c},driver|EC], dynamic, Bin) ->
- Mods = [megaco_ber_bin_drv_media_gateway_control_v1,
- megaco_ber_bin_drv_media_gateway_control_v2,
- megaco_ber_bin_drv_media_gateway_control_prev3c],
- ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
-decode_mini_message([{version3,prev3b},driver|EC], dynamic, Bin) ->
- Mods = [megaco_ber_bin_drv_media_gateway_control_v1,
- megaco_ber_bin_drv_media_gateway_control_v2,
- megaco_ber_bin_drv_media_gateway_control_prev3b],
- ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
-decode_mini_message([{version3,prev3a},driver|EC], dynamic, Bin) ->
- Mods = [megaco_ber_bin_drv_media_gateway_control_v1,
- megaco_ber_bin_drv_media_gateway_control_v2,
- megaco_ber_bin_drv_media_gateway_control_prev3a],
- ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
-decode_mini_message([driver|EC], dynamic, Bin) ->
- Mods = [megaco_ber_bin_drv_media_gateway_control_v1,
- megaco_ber_bin_drv_media_gateway_control_v2,
- megaco_ber_bin_drv_media_gateway_control_v3],
- ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
decode_mini_message([{version3,v3}|EC], dynamic, Bin) ->
- Mods = [megaco_ber_bin_media_gateway_control_v1,
- megaco_ber_bin_media_gateway_control_v2,
- megaco_ber_bin_media_gateway_control_v3],
+ Mods = [megaco_ber_media_gateway_control_v1,
+ megaco_ber_media_gateway_control_v2,
+ megaco_ber_media_gateway_control_v3],
?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
decode_mini_message([{version3,prev3c}|EC], dynamic, Bin) ->
- Mods = [megaco_ber_bin_media_gateway_control_v1,
- megaco_ber_bin_media_gateway_control_v2,
- megaco_ber_bin_media_gateway_control_prev3c],
+ Mods = [megaco_ber_media_gateway_control_v1,
+ megaco_ber_media_gateway_control_v2,
+ megaco_ber_media_gateway_control_prev3c],
?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
decode_mini_message([{version3,prev3b}|EC], dynamic, Bin) ->
- Mods = [megaco_ber_bin_media_gateway_control_v1,
- megaco_ber_bin_media_gateway_control_v2,
- megaco_ber_bin_media_gateway_control_prev3b],
+ Mods = [megaco_ber_media_gateway_control_v1,
+ megaco_ber_media_gateway_control_v2,
+ megaco_ber_media_gateway_control_prev3b],
?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
decode_mini_message([{version3,prev3a}|EC], dynamic, Bin) ->
- Mods = [megaco_ber_bin_media_gateway_control_v1,
- megaco_ber_bin_media_gateway_control_v2,
- megaco_ber_bin_media_gateway_control_prev3a],
+ Mods = [megaco_ber_media_gateway_control_v1,
+ megaco_ber_media_gateway_control_v2,
+ megaco_ber_media_gateway_control_prev3a],
?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
decode_mini_message(EC, dynamic, Bin) ->
- Mods = [megaco_ber_bin_media_gateway_control_v1,
- megaco_ber_bin_media_gateway_control_v2,
- megaco_ber_bin_media_gateway_control_v3],
+ Mods = [megaco_ber_media_gateway_control_v1,
+ megaco_ber_media_gateway_control_v2,
+ megaco_ber_media_gateway_control_v3],
?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
-decode_mini_message([{version3,_},driver|EC], 1, Bin) ->
- AsnMod = megaco_ber_bin_drv_media_gateway_control_v1,
- ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
-decode_mini_message([driver|EC], 1, Bin) ->
- AsnMod = megaco_ber_bin_drv_media_gateway_control_v1,
- ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
decode_mini_message([{version3,_}|EC], 1, Bin) ->
- AsnMod = megaco_ber_bin_media_gateway_control_v1,
+ AsnMod = megaco_ber_media_gateway_control_v1,
?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
decode_mini_message(EC, 1, Bin) ->
- AsnMod = megaco_ber_bin_media_gateway_control_v1,
+ AsnMod = megaco_ber_media_gateway_control_v1,
?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
-decode_mini_message([{version3,_},driver|EC], 2, Bin) ->
- AsnMod = megaco_ber_bin_drv_media_gateway_control_v2,
- ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
-decode_mini_message([driver|EC], 2, Bin) ->
- AsnMod = megaco_ber_bin_drv_media_gateway_control_v2,
- ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
decode_mini_message([{version3,_}|EC], 2, Bin) ->
- AsnMod = megaco_ber_bin_media_gateway_control_v2,
+ AsnMod = megaco_ber_media_gateway_control_v2,
?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
decode_mini_message(EC, 2, Bin) ->
- AsnMod = megaco_ber_bin_media_gateway_control_v2,
+ AsnMod = megaco_ber_media_gateway_control_v2,
?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
-decode_mini_message([{version3,v3},driver|EC], 3, Bin) ->
- AsnMod = megaco_ber_bin_drv_media_gateway_control_v3,
- ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
-decode_mini_message([{version3,prev3c},driver|EC], 3, Bin) ->
- AsnMod = megaco_ber_bin_drv_media_gateway_control_prev3c,
- ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
-decode_mini_message([{version3,prev3b},driver|EC], 3, Bin) ->
- AsnMod = megaco_ber_bin_drv_media_gateway_control_prev3b,
- ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
-decode_mini_message([{version3,prev3a},driver|EC], 3, Bin) ->
- AsnMod = megaco_ber_bin_drv_media_gateway_control_prev3a,
- ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
-decode_mini_message([driver|EC], 3, Bin) ->
- AsnMod = megaco_ber_bin_drv_media_gateway_control_v3,
- ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
decode_mini_message([{version3,v3}|EC], 3, Bin) ->
- AsnMod = megaco_ber_bin_media_gateway_control_v3,
+ AsnMod = megaco_ber_media_gateway_control_v3,
?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
decode_mini_message([{version3,prev3c}|EC], 3, Bin) ->
- AsnMod = megaco_ber_bin_media_gateway_control_prev3c,
+ AsnMod = megaco_ber_media_gateway_control_prev3c,
?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
decode_mini_message([{version3,prev3b}|EC], 3, Bin) ->
- AsnMod = megaco_ber_bin_media_gateway_control_prev3b,
+ AsnMod = megaco_ber_media_gateway_control_prev3b,
?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
decode_mini_message([{version3,prev3a}|EC], 3, Bin) ->
- AsnMod = megaco_ber_bin_media_gateway_control_prev3a,
+ AsnMod = megaco_ber_media_gateway_control_prev3a,
?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
decode_mini_message(EC, 3, Bin) ->
- AsnMod = megaco_ber_bin_media_gateway_control_v3,
+ AsnMod = megaco_ber_media_gateway_control_v3,
?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary).
diff --git a/lib/megaco/src/binary/megaco_binary_encoder_lib.erl b/lib/megaco/src/binary/megaco_binary_encoder_lib.erl
index 967ee93935..262889db39 100644
--- a/lib/megaco/src/binary/megaco_binary_encoder_lib.erl
+++ b/lib/megaco/src/binary/megaco_binary_encoder_lib.erl
@@ -275,7 +275,7 @@ decode_message_dynamic(_EC, _BadBin, _Mods, _Type) ->
{error, no_binary}.
-decode_message(EC, Bin, AsnMod, TransMod, binary) ->
+decode_message(EC, Bin, AsnMod, TransMod, _) ->
case asn1rt:decode(AsnMod, 'MegacoMessage', Bin) of
{ok, MegaMsg} ->
case EC of
@@ -286,19 +286,6 @@ decode_message(EC, Bin, AsnMod, TransMod, binary) ->
end;
{error, Reason} ->
{error, Reason}
- end;
-decode_message(EC, Bin, AsnMod, TransMod, io_list) ->
- ShallowIoList = erlang:binary_to_list(Bin),
- case asn1rt:decode(AsnMod, 'MegacoMessage', ShallowIoList) of
- {ok, MegaMsg} ->
- case EC of
- [native] ->
- {ok, MegaMsg};
- _ ->
- {ok, TransMod:tr_message(MegaMsg, decode, EC)}
- end;
- {error, Reason} ->
- {error, Reason}
end.
diff --git a/lib/megaco/src/binary/megaco_binary_name_resolver_prev3a.erl b/lib/megaco/src/binary/megaco_binary_name_resolver_prev3a.erl
index 72b3112053..24dc410dbe 100644
--- a/lib/megaco/src/binary/megaco_binary_name_resolver_prev3a.erl
+++ b/lib/megaco/src/binary/megaco_binary_name_resolver_prev3a.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -204,7 +204,7 @@ decode_name(_Config, Scope, Item) ->
%% to command requests from the MGC that audit
%% ObservedEventsDescriptor, and found in the
%% ObservedEventsDescriptor. See 12.2. If there are no parameters
-%% for the ObservedEvents Descriptor, then �none� shall be specified.
+%% for the ObservedEvents Descriptor, then 'none' shall be specified.
%%
%%
%% 12.1.4 Signals
@@ -225,7 +225,7 @@ decode_name(_Config, Scope, Item) ->
%%
%% BR (Brief)
%%
-%% NOTE -�SignalType may be defined such that it is dependent on
+%% NOTE - SignalType may be defined such that it is dependent on
%% the value of one or more parameters. The package MUST specify a
%% default signal type. If the default type is TO, the package MUST
%% specify a default duration which may be provisioned. A default
diff --git a/lib/megaco/src/binary/megaco_binary_name_resolver_prev3b.erl b/lib/megaco/src/binary/megaco_binary_name_resolver_prev3b.erl
index 12e673ac81..d89717c00a 100644
--- a/lib/megaco/src/binary/megaco_binary_name_resolver_prev3b.erl
+++ b/lib/megaco/src/binary/megaco_binary_name_resolver_prev3b.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -204,7 +204,7 @@ decode_name(_Config, Scope, Item) ->
%% to command requests from the MGC that audit
%% ObservedEventsDescriptor, and found in the
%% ObservedEventsDescriptor. See 12.2. If there are no parameters
-%% for the ObservedEvents Descriptor, then �none� shall be specified.
+%% for the ObservedEvents Descriptor, then 'none' shall be specified.
%%
%%
%% 12.1.4 Signals
@@ -225,7 +225,7 @@ decode_name(_Config, Scope, Item) ->
%%
%% BR (Brief)
%%
-%% NOTE -�SignalType may be defined such that it is dependent on
+%% NOTE - SignalType may be defined such that it is dependent on
%% the value of one or more parameters. The package MUST specify a
%% default signal type. If the default type is TO, the package MUST
%% specify a default duration which may be provisioned. A default
diff --git a/lib/megaco/src/binary/megaco_binary_name_resolver_prev3c.erl b/lib/megaco/src/binary/megaco_binary_name_resolver_prev3c.erl
index d08231caac..8b4192ad44 100644
--- a/lib/megaco/src/binary/megaco_binary_name_resolver_prev3c.erl
+++ b/lib/megaco/src/binary/megaco_binary_name_resolver_prev3c.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -204,7 +204,7 @@ decode_name(_Config, Scope, Item) ->
%% to command requests from the MGC that audit
%% ObservedEventsDescriptor, and found in the
%% ObservedEventsDescriptor. See 12.2. If there are no parameters
-%% for the ObservedEvents Descriptor, then �none� shall be specified.
+%% for the ObservedEvents Descriptor, then 'none' shall be specified.
%%
%%
%% 12.1.4 Signals
@@ -225,7 +225,7 @@ decode_name(_Config, Scope, Item) ->
%%
%% BR (Brief)
%%
-%% NOTE -�SignalType may be defined such that it is dependent on
+%% NOTE - SignalType may be defined such that it is dependent on
%% the value of one or more parameters. The package MUST specify a
%% default signal type. If the default type is TO, the package MUST
%% specify a default duration which may be provisioned. A default
diff --git a/lib/megaco/src/binary/megaco_binary_name_resolver_v3.erl b/lib/megaco/src/binary/megaco_binary_name_resolver_v3.erl
index c101aa15bc..20954d4c9d 100644
--- a/lib/megaco/src/binary/megaco_binary_name_resolver_v3.erl
+++ b/lib/megaco/src/binary/megaco_binary_name_resolver_v3.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -204,7 +204,7 @@ decode_name(_Config, Scope, Item) ->
%% to command requests from the MGC that audit
%% ObservedEventsDescriptor, and found in the
%% ObservedEventsDescriptor. See 12.2. If there are no parameters
-%% for the ObservedEvents Descriptor, then �none� shall be specified.
+%% for the ObservedEvents Descriptor, then 'none' shall be specified.
%%
%%
%% 12.1.4 Signals
@@ -225,7 +225,7 @@ decode_name(_Config, Scope, Item) ->
%%
%% BR (Brief)
%%
-%% NOTE -�SignalType may be defined such that it is dependent on
+%% NOTE - SignalType may be defined such that it is dependent on
%% the value of one or more parameters. The package MUST specify a
%% default signal type. If the default type is TO, the package MUST
%% specify a default duration which may be provisioned. A default
diff --git a/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3a.set.asn b/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3a.set.asn
deleted file mode 100644
index b9ba7ffdb4..0000000000
--- a/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3a.set.asn
+++ /dev/null
@@ -1 +0,0 @@
-MEDIA-GATEWAY-CONTROL-prev3a.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3b.set.asn b/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3b.set.asn
deleted file mode 100644
index 0437bde310..0000000000
--- a/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3b.set.asn
+++ /dev/null
@@ -1 +0,0 @@
-MEDIA-GATEWAY-CONTROL-prev3b.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3c.set.asn b/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3c.set.asn
deleted file mode 100644
index e78055fbad..0000000000
--- a/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3c.set.asn
+++ /dev/null
@@ -1 +0,0 @@
-MEDIA-GATEWAY-CONTROL-prev3c.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v1.set.asn b/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v1.set.asn
deleted file mode 100644
index 0f5a92dba1..0000000000
--- a/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v1.set.asn
+++ /dev/null
@@ -1 +0,0 @@
-MEDIA-GATEWAY-CONTROL-v1.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v2.set.asn b/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v2.set.asn
deleted file mode 100644
index 7fc82b127f..0000000000
--- a/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v2.set.asn
+++ /dev/null
@@ -1 +0,0 @@
-MEDIA-GATEWAY-CONTROL-v2.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v3.set.asn b/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v3.set.asn
deleted file mode 100644
index 1d7950a283..0000000000
--- a/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v3.set.asn
+++ /dev/null
@@ -1 +0,0 @@
-MEDIA-GATEWAY-CONTROL-v3.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_encoder.erl b/lib/megaco/src/binary/megaco_per_bin_encoder.erl
deleted file mode 100644
index f7280f4e04..0000000000
--- a/lib/megaco/src/binary/megaco_per_bin_encoder.erl
+++ /dev/null
@@ -1,447 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
-%%----------------------------------------------------------------------
-%% Purpose : Handle ASN.1 PER encoding of Megaco/H.248
-%%----------------------------------------------------------------------
-
--module(megaco_per_bin_encoder).
-
--behaviour(megaco_encoder).
-
--export([encode_message/3, decode_message/3,
- decode_mini_message/3,
-
- encode_transaction/3,
- encode_action_requests/3,
- encode_action_request/3,
- encode_action_reply/3,
-
- version_of/2]).
-
-%% Backward compatible functions:
--export([encode_message/2, decode_message/2]).
-
--include_lib("megaco/src/engine/megaco_message_internal.hrl").
-
--define(V1_ASN1_MOD, megaco_per_bin_media_gateway_control_v1).
--define(V2_ASN1_MOD, megaco_per_bin_media_gateway_control_v2).
--define(V3_ASN1_MOD, megaco_per_bin_media_gateway_control_v3).
--define(PREV3A_ASN1_MOD, megaco_per_bin_media_gateway_control_prev3a).
--define(PREV3B_ASN1_MOD, megaco_per_bin_media_gateway_control_prev3b).
--define(PREV3C_ASN1_MOD, megaco_per_bin_media_gateway_control_prev3c).
--define(V1_ASN1_MOD_DRV, megaco_per_bin_drv_media_gateway_control_v1).
--define(V2_ASN1_MOD_DRV, megaco_per_bin_drv_media_gateway_control_v2).
--define(V3_ASN1_MOD_DRV, megaco_per_bin_drv_media_gateway_control_v3).
--define(PREV3A_ASN1_MOD_DRV, megaco_per_bin_drv_media_gateway_control_prev3a).
--define(PREV3B_ASN1_MOD_DRV, megaco_per_bin_drv_media_gateway_control_prev3b).
--define(PREV3C_ASN1_MOD_DRV, megaco_per_bin_drv_media_gateway_control_prev3c).
-
--define(V1_TRANS_MOD, megaco_binary_transformer_v1).
--define(V2_TRANS_MOD, megaco_binary_transformer_v2).
--define(V3_TRANS_MOD, megaco_binary_transformer_v3).
--define(PREV3A_TRANS_MOD, megaco_binary_transformer_prev3a).
--define(PREV3B_TRANS_MOD, megaco_binary_transformer_prev3b).
--define(PREV3C_TRANS_MOD, megaco_binary_transformer_prev3c).
-
--define(BIN_LIB, megaco_binary_encoder_lib).
-
-
-%%----------------------------------------------------------------------
-%% Detect (check/get) message version
-%% Return {ok, Version} | {error, Reason}
-%%----------------------------------------------------------------------
-
-version_of([{version3,v3},driver|EC], Binary) ->
- Decoders = [?V1_ASN1_MOD_DRV, ?V2_ASN1_MOD_DRV, ?V3_ASN1_MOD_DRV],
- ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
-version_of([{version3,prev3c},driver|EC], Binary) ->
- Decoders = [?V1_ASN1_MOD_DRV, ?V2_ASN1_MOD_DRV, ?PREV3C_ASN1_MOD_DRV],
- ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
-version_of([{version3,prev3b},driver|EC], Binary) ->
- Decoders = [?V1_ASN1_MOD_DRV, ?V2_ASN1_MOD_DRV, ?PREV3B_ASN1_MOD_DRV],
- ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
-version_of([{version3,prev3a},driver|EC], Binary) ->
- Decoders = [?V1_ASN1_MOD_DRV, ?V2_ASN1_MOD_DRV, ?PREV3A_ASN1_MOD_DRV],
- ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
-version_of([driver|EC], Binary) ->
- Decoders = [?V1_ASN1_MOD_DRV, ?V2_ASN1_MOD_DRV, ?V3_ASN1_MOD_DRV],
- ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
-version_of([{version3,v3}|EC], Binary) ->
- Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
- ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
-version_of([{version3,prev3c}|EC], Binary) ->
- Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3C_ASN1_MOD],
- ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
-version_of([{version3,prev3b}|EC], Binary) ->
- Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3B_ASN1_MOD],
- ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
-version_of([{version3,prev3a}|EC], Binary) ->
- Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3A_ASN1_MOD],
- ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
-
-%% All values we need to take (special) care of has been delt with,
-%% so just pass the rest on
-version_of(EC, Binary) ->
- Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
- ?BIN_LIB:version_of(EC, Binary, 1, Decoders).
-
-
-%%----------------------------------------------------------------------
-%% Convert a 'MegacoMessage' record into a binary
-%% Return {ok, Binary} | {error, Reason}
-%%----------------------------------------------------------------------
-
-encode_message(EC,
- #'MegacoMessage'{mess = #'Message'{version = V}} = MegaMsg) ->
- encode_message(EC, V, MegaMsg).
-
-
-%% -- Version 1 --
-
-encode_message([{version3, _},driver|EC], 1, MegaMsg) ->
- AsnMod = ?V1_ASN1_MOD_DRV,
- TransMod = ?V1_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-encode_message([driver|EC], 1, MegaMsg) ->
- AsnMod = ?V1_ASN1_MOD_DRV,
- TransMod = ?V1_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-encode_message([{version3,_}|EC], 1, MegaMsg) ->
- AsnMod = ?V1_ASN1_MOD,
- TransMod = ?V1_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-
-%% All values we need to take (special) care of has been delt with,
-%% so just pass the rest on
-encode_message(EC, 1, MegaMsg) ->
- AsnMod = ?V1_ASN1_MOD,
- TransMod = ?V1_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-
-
-%% -- Version 2 --
-
-encode_message([{version3,_},driver|EC], 2, MegaMsg) ->
- AsnMod = ?V2_ASN1_MOD_DRV,
- TransMod = ?V2_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-encode_message([driver|EC], 2, MegaMsg) ->
- AsnMod = ?V2_ASN1_MOD_DRV,
- TransMod = ?V2_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-encode_message([{version3,_}|EC], 2, MegaMsg) ->
- AsnMod = ?V2_ASN1_MOD,
- TransMod = ?V2_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-
-%% All values we need to take (special) care of has been delt with,
-%% so just pass the rest on
-encode_message(EC, 2, MegaMsg) ->
- AsnMod = ?V2_ASN1_MOD,
- TransMod = ?V2_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-
-
-%% -- Version 3 --
-
-encode_message([{version3,v3},driver|EC], 3, MegaMsg) ->
- AsnMod = ?V3_ASN1_MOD_DRV,
- TransMod = ?V3_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-encode_message([{version3,prev3c},driver|EC], 3, MegaMsg) ->
- AsnMod = ?PREV3C_ASN1_MOD_DRV,
- TransMod = ?PREV3C_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-encode_message([{version3,prev3b},driver|EC], 3, MegaMsg) ->
- AsnMod = ?PREV3B_ASN1_MOD_DRV,
- TransMod = ?PREV3B_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-encode_message([{version3,prev3a},driver|EC], 3, MegaMsg) ->
- AsnMod = ?PREV3A_ASN1_MOD_DRV,
- TransMod = ?PREV3A_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-encode_message([driver|EC], 3, MegaMsg) ->
- AsnMod = ?V3_ASN1_MOD_DRV,
- TransMod = ?V3_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-encode_message([{version3,v3}|EC], 3, MegaMsg) ->
- AsnMod = ?V3_ASN1_MOD,
- TransMod = ?V3_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-encode_message([{version3,prev3c}|EC], 3, MegaMsg) ->
- AsnMod = ?PREV3C_ASN1_MOD,
- TransMod = ?PREV3C_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-encode_message([{version3,prev3b}|EC], 3, MegaMsg) ->
- AsnMod = ?PREV3B_ASN1_MOD,
- TransMod = ?PREV3B_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-encode_message([{version3,prev3a}|EC], 3, MegaMsg) ->
- AsnMod = ?PREV3A_ASN1_MOD,
- TransMod = ?PREV3A_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
-
-%% All values we need to take (special) care of has been delt with,
-%% so just pass the rest on
-encode_message(EC, 3, MegaMsg) ->
- AsnMod = ?V3_ASN1_MOD,
- TransMod = ?V3_TRANS_MOD,
- ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list).
-
-
-%%----------------------------------------------------------------------
-%% Convert a transaction (or transactions in the case of ack) record(s)
-%% into a binary
-%% Return {ok, Binary} | {error, Reason}
-%%----------------------------------------------------------------------
-
-%% encode_transaction([] = EC, 1, Trans) ->
-%% AsnMod = ?V1_ASN1_MOD,
-%% TransMod = ?V1_TRANS_MOD,
-%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
-%% io_list);
-%% encode_transaction([native] = EC, 1, Trans) ->
-%% AsnMod = ?V1_ASN1_MOD,
-%% TransMod = ?V1_TRANS_MOD,
-%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
-%% io_list);
-%% encode_transaction([driver|EC], 1, Trans) ->
-%% AsnMod = ?V1_ASN1_MOD_DRV,
-%% TransMod = ?V1_TRANS_MOD,
-%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
-%% io_list);
-encode_transaction(_EC, 1, _Trans) ->
- %% AsnMod = ?V1_ASN1_MOD,
- %% TransMod = ?V1_TRANS_MOD,
- %% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
- %% io_list);
- {error, not_implemented};
-
-%% encode_transaction([] = EC, 2, Trans) ->
-%% AsnMod = ?V2_ASN1_MOD,
-%% TransMod = ?V2_TRANS_MOD,
-%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
-%% io_list);
-%% encode_transaction([native] = EC, 2, Trans) ->
-%% AsnMod = ?V2_ASN1_MOD,
-%% TransMod = ?V2_TRANS_MOD,
-%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
-%% io_list);
-%% encode_transaction([driver|EC], 2, Trans) ->
-%% AsnMod = ?V2_ASN1_MOD_DRV,
-%% TransMod = ?V2_TRANS_MOD,
-%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
-%% io_list);
-encode_transaction(_EC, 2, _Trans) ->
- %% AsnMod = ?V2_ASN1_MOD,
- %% TransMod = ?V2_TRANS_MOD,
- %% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
- %% io_list).
- {error, not_implemented};
-
-%% encode_transaction([] = EC, 3, Trans) ->
-%% AsnMod = ?V3_ASN1_MOD,
-%% TransMod = ?V3_TRANS_MOD,
-%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
-%% io_list);
-%% encode_transaction([native] = EC, 3, Trans) ->
-%% AsnMod = ?V3_ASN1_MOD,
-%% TransMod = ?V3_TRANS_MOD,
-%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
-%% io_list);
-%% encode_transaction([driver|EC], 3, Trans) ->
-%% AsnMod = ?V3_ASN1_MOD_DRV,
-%% TransMod = ?V3_TRANS_MOD,
-%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
-%% io_list);
-encode_transaction(_EC, 3, _Trans) ->
- %% AsnMod = ?V3_ASN1_MOD,
- %% TransMod = ?V3_TRANS_MOD,
- %% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod, %% io_list).
- {error, not_implemented}.
-
-
-%%----------------------------------------------------------------------
-%% Convert a list of ActionRequest record's into a binary
-%% Return {ok, DeepIoList} | {error, Reason}
-%%----------------------------------------------------------------------
-encode_action_requests(_EC, 1, ActReqs) when is_list(ActReqs) ->
- %% ?BIN_LIB:encode_action_requests(EC, ActReqs,
- %% ?V1_ASN1_MOD,
- %% ?V1_TRANS_MOD,
- %% io_list);
- {error, not_implemented};
-encode_action_requests(_EC, 2, ActReqs) when is_list(ActReqs) ->
- %% ?BIN_LIB:encode_action_requests(EC, ActReqs,
- %% ?V1_ASN1_MOD,
- %% ?V1_TRANS_MOD,
- %% io_list).
- {error, not_implemented};
-encode_action_requests(_EC, 3, ActReqs) when is_list(ActReqs) ->
- %% ?BIN_LIB:encode_action_requests(EC, ActReqs,
- %% ?V1_ASN1_MOD,
- %% ?V1_TRANS_MOD,
- %% io_list).
- {error, not_implemented}.
-
-
-%%----------------------------------------------------------------------
-%% Convert a ActionRequest record into a binary
-%% Return {ok, DeepIoList} | {error, Reason}
-%%----------------------------------------------------------------------
-encode_action_request(_EC, 1, _ActReq) ->
- %% ?BIN_LIB:encode_action_request(EC, ActReq,
- %% ?V1_ASN1_MOD,
- %% ?V1_TRANS_MOD,
- %% io_list);
- {error, not_implemented};
-encode_action_request(_EC, 2, _ActReq) ->
- %% ?BIN_LIB:encode_action_request(EC, ActReq,
- %% ?V1_ASN1_MOD,
- %% ?V1_TRANS_MOD,
- %% io_list).
- {error, not_implemented};
-encode_action_request(_EC, 3, _ActReq) ->
- %% ?BIN_LIB:encode_action_request(EC, ActReq,
- %% ?V1_ASN1_MOD,
- %% ?V1_TRANS_MOD,
- %% io_list).
- {error, not_implemented}.
-
-
-%%----------------------------------------------------------------------
-%% Convert a action reply into a deep io list
-%% Not yest supported by this binary codec!
-%% Return {ok, DeepIoList} | {error, Reason}
-%%----------------------------------------------------------------------
-
-encode_action_reply(_EC, _V, _AcionReply) ->
- {error, not_implemented}.
-
-
-%%----------------------------------------------------------------------
-%% Convert a binary into a 'MegacoMessage' record
-%% Return {ok, MegacoMessageRecord} | {error, Reason}
-%%----------------------------------------------------------------------
-
-decode_message(EC, Binary) ->
- decode_message(EC, 1, Binary).
-
-%% PER does not support partial decode, so this means V1
-decode_message(EC, dynamic, Binary) ->
- decode_message(EC, 1, Binary);
-
-
-%% -- Version 1 --
-
-decode_message([{version3,_},driver|EC], 1, Binary) ->
- AsnMod = ?V1_ASN1_MOD_DRV,
- TransMod = ?V1_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-decode_message([driver|EC], 1, Binary) ->
- AsnMod = ?V1_ASN1_MOD_DRV,
- TransMod = ?V1_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-decode_message([{version3,_}|EC], 1, Binary) ->
- AsnMod = ?V1_ASN1_MOD,
- TransMod = ?V1_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-
-%% All values we need to take (special) care of has been delt with,
-%% so just pass the rest on
-decode_message(EC, 1, Binary) ->
- AsnMod = ?V1_ASN1_MOD,
- TransMod = ?V1_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-
-
-%% -- Version 2 --
-
-decode_message([{version3,_},driver|EC], 2, Binary) ->
- AsnMod = ?V2_ASN1_MOD_DRV,
- TransMod = ?V2_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-decode_message([driver|EC], 2, Binary) ->
- AsnMod = ?V2_ASN1_MOD_DRV,
- TransMod = ?V2_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-decode_message([{version3,_}|EC], 2, Binary) ->
- AsnMod = ?V2_ASN1_MOD,
- TransMod = ?V2_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-
-%% All values we need to take (special) care of has been delt with,
-%% so just pass the rest on
-decode_message(EC, 2, Binary) ->
- AsnMod = ?V2_ASN1_MOD,
- TransMod = ?V2_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-
-
-%% -- Version 3 --
-
-decode_message([{version3,v3},driver|EC], 3, Binary) ->
- AsnMod = ?V3_ASN1_MOD_DRV,
- TransMod = ?V3_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-decode_message([{version3,prev3c},driver|EC], 3, Binary) ->
- AsnMod = ?PREV3C_ASN1_MOD_DRV,
- TransMod = ?PREV3C_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-decode_message([{version3,prev3b},driver|EC], 3, Binary) ->
- AsnMod = ?PREV3B_ASN1_MOD_DRV,
- TransMod = ?PREV3B_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-decode_message([{version3,prev3a},driver|EC], 3, Binary) ->
- AsnMod = ?PREV3A_ASN1_MOD_DRV,
- TransMod = ?PREV3A_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-decode_message([driver|EC], 3, Binary) ->
- AsnMod = ?V3_ASN1_MOD_DRV,
- TransMod = ?V3_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-decode_message([{version3,v3}|EC], 3, Binary) ->
- AsnMod = ?V3_ASN1_MOD,
- TransMod = ?V3_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-decode_message([{version3,prev3c}|EC], 3, Binary) ->
- AsnMod = ?PREV3C_ASN1_MOD,
- TransMod = ?PREV3C_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-decode_message([{version3,prev3b}|EC], 3, Binary) ->
- AsnMod = ?PREV3B_ASN1_MOD,
- TransMod = ?PREV3B_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-decode_message([{version3,prev3a}|EC], 3, Binary) ->
- AsnMod = ?PREV3A_ASN1_MOD,
- TransMod = ?PREV3A_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
-
-%% All values we need to take (special) care of has been delt with,
-%% so just pass the rest on
-decode_message(EC, 3, Binary) ->
- AsnMod = ?V3_ASN1_MOD,
- TransMod = ?V3_TRANS_MOD,
- ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary).
-
-
-decode_mini_message(_EC, _Vsn, _Bin) ->
- {error, not_implemented}.
diff --git a/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3a.set.asn b/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3a.set.asn
deleted file mode 100644
index b9ba7ffdb4..0000000000
--- a/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3a.set.asn
+++ /dev/null
@@ -1 +0,0 @@
-MEDIA-GATEWAY-CONTROL-prev3a.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3b.set.asn b/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3b.set.asn
deleted file mode 100644
index 0437bde310..0000000000
--- a/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3b.set.asn
+++ /dev/null
@@ -1 +0,0 @@
-MEDIA-GATEWAY-CONTROL-prev3b.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3c.set.asn b/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3c.set.asn
deleted file mode 100644
index e78055fbad..0000000000
--- a/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3c.set.asn
+++ /dev/null
@@ -1 +0,0 @@
-MEDIA-GATEWAY-CONTROL-prev3c.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v1.set.asn b/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v1.set.asn
deleted file mode 100644
index 0f5a92dba1..0000000000
--- a/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v1.set.asn
+++ /dev/null
@@ -1 +0,0 @@
-MEDIA-GATEWAY-CONTROL-v1.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v2.set.asn b/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v2.set.asn
deleted file mode 100644
index 7fc82b127f..0000000000
--- a/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v2.set.asn
+++ /dev/null
@@ -1 +0,0 @@
-MEDIA-GATEWAY-CONTROL-v2.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v3.set.asn b/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v3.set.asn
deleted file mode 100644
index 1d7950a283..0000000000
--- a/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v3.set.asn
+++ /dev/null
@@ -1 +0,0 @@
-MEDIA-GATEWAY-CONTROL-v3.asn
diff --git a/lib/megaco/src/binary/modules.mk b/lib/megaco/src/binary/modules.mk
index a86ce2aecc..bbaf087ceb 100644
--- a/lib/megaco/src/binary/modules.mk
+++ b/lib/megaco/src/binary/modules.mk
@@ -27,19 +27,6 @@ MODULES = \
megaco_ber_media_gateway_control_prev3b \
megaco_ber_media_gateway_control_prev3c \
megaco_ber_media_gateway_control_v3 \
- megaco_ber_bin_encoder \
- megaco_ber_bin_media_gateway_control_v1 \
- megaco_ber_bin_media_gateway_control_v2 \
- megaco_ber_bin_media_gateway_control_prev3a \
- megaco_ber_bin_media_gateway_control_prev3b \
- megaco_ber_bin_media_gateway_control_prev3c \
- megaco_ber_bin_media_gateway_control_v3 \
- megaco_ber_bin_drv_media_gateway_control_v1 \
- megaco_ber_bin_drv_media_gateway_control_v2 \
- megaco_ber_bin_drv_media_gateway_control_prev3a \
- megaco_ber_bin_drv_media_gateway_control_prev3b \
- megaco_ber_bin_drv_media_gateway_control_prev3c \
- megaco_ber_bin_drv_media_gateway_control_v3 \
megaco_per_encoder \
megaco_per_media_gateway_control_v1 \
megaco_per_media_gateway_control_v2 \
@@ -47,19 +34,6 @@ MODULES = \
megaco_per_media_gateway_control_prev3b \
megaco_per_media_gateway_control_prev3c \
megaco_per_media_gateway_control_v3 \
- megaco_per_bin_encoder \
- megaco_per_bin_media_gateway_control_v1 \
- megaco_per_bin_media_gateway_control_v2 \
- megaco_per_bin_media_gateway_control_prev3a \
- megaco_per_bin_media_gateway_control_prev3b \
- megaco_per_bin_media_gateway_control_prev3c \
- megaco_per_bin_media_gateway_control_v3 \
- megaco_per_bin_drv_media_gateway_control_v1 \
- megaco_per_bin_drv_media_gateway_control_v2 \
- megaco_per_bin_drv_media_gateway_control_prev3a \
- megaco_per_bin_drv_media_gateway_control_prev3b \
- megaco_per_bin_drv_media_gateway_control_prev3c \
- megaco_per_bin_drv_media_gateway_control_v3 \
megaco_binary_name_resolver_v1 \
megaco_binary_name_resolver_v2 \
megaco_binary_name_resolver_prev3a \
@@ -85,44 +59,20 @@ ASN1_PREV3C_SPEC = MEDIA-GATEWAY-CONTROL-prev3c
ASN1_V3_SPEC = MEDIA-GATEWAY-CONTROL-v3
BER_ASN1_V1_SPEC = megaco_ber_media_gateway_control_v1
-BER_BIN_ASN1_V1_SPEC = megaco_ber_bin_media_gateway_control_v1
-BER_BIN_DRV_ASN1_V1_SPEC = megaco_ber_bin_drv_media_gateway_control_v1
PER_ASN1_V1_SPEC = megaco_per_media_gateway_control_v1
-PER_BIN_ASN1_V1_SPEC = megaco_per_bin_media_gateway_control_v1
-PER_BIN_DRV_ASN1_V1_SPEC = megaco_per_bin_drv_media_gateway_control_v1
BER_ASN1_V2_SPEC = megaco_ber_media_gateway_control_v2
-BER_BIN_ASN1_V2_SPEC = megaco_ber_bin_media_gateway_control_v2
-BER_BIN_DRV_ASN1_V2_SPEC = megaco_ber_bin_drv_media_gateway_control_v2
PER_ASN1_V2_SPEC = megaco_per_media_gateway_control_v2
-PER_BIN_ASN1_V2_SPEC = megaco_per_bin_media_gateway_control_v2
-PER_BIN_DRV_ASN1_V2_SPEC = megaco_per_bin_drv_media_gateway_control_v2
BER_ASN1_PREV3A_SPEC = megaco_ber_media_gateway_control_prev3a
-BER_BIN_ASN1_PREV3A_SPEC = megaco_ber_bin_media_gateway_control_prev3a
-BER_BIN_DRV_ASN1_PREV3A_SPEC = megaco_ber_bin_drv_media_gateway_control_prev3a
PER_ASN1_PREV3A_SPEC = megaco_per_media_gateway_control_prev3a
-PER_BIN_ASN1_PREV3A_SPEC = megaco_per_bin_media_gateway_control_prev3a
-PER_BIN_DRV_ASN1_PREV3A_SPEC = megaco_per_bin_drv_media_gateway_control_prev3a
BER_ASN1_PREV3B_SPEC = megaco_ber_media_gateway_control_prev3b
-BER_BIN_ASN1_PREV3B_SPEC = megaco_ber_bin_media_gateway_control_prev3b
-BER_BIN_DRV_ASN1_PREV3B_SPEC = megaco_ber_bin_drv_media_gateway_control_prev3b
PER_ASN1_PREV3B_SPEC = megaco_per_media_gateway_control_prev3b
-PER_BIN_ASN1_PREV3B_SPEC = megaco_per_bin_media_gateway_control_prev3b
-PER_BIN_DRV_ASN1_PREV3B_SPEC = megaco_per_bin_drv_media_gateway_control_prev3b
BER_ASN1_PREV3C_SPEC = megaco_ber_media_gateway_control_prev3c
-BER_BIN_ASN1_PREV3C_SPEC = megaco_ber_bin_media_gateway_control_prev3c
-BER_BIN_DRV_ASN1_PREV3C_SPEC = megaco_ber_bin_drv_media_gateway_control_prev3c
PER_ASN1_PREV3C_SPEC = megaco_per_media_gateway_control_prev3c
-PER_BIN_ASN1_PREV3C_SPEC = megaco_per_bin_media_gateway_control_prev3c
-PER_BIN_DRV_ASN1_PREV3C_SPEC = megaco_per_bin_drv_media_gateway_control_prev3c
BER_ASN1_V3_SPEC = megaco_ber_media_gateway_control_v3
-BER_BIN_ASN1_V3_SPEC = megaco_ber_bin_media_gateway_control_v3
-BER_BIN_DRV_ASN1_V3_SPEC = megaco_ber_bin_drv_media_gateway_control_v3
PER_ASN1_V3_SPEC = megaco_per_media_gateway_control_v3
-PER_BIN_ASN1_V3_SPEC = megaco_per_bin_media_gateway_control_v3
-PER_BIN_DRV_ASN1_V3_SPEC = megaco_per_bin_drv_media_gateway_control_v3
diff --git a/lib/megaco/src/flex/Makefile.in b/lib/megaco/src/flex/Makefile.in
index cb5f5412f4..6111cf2304 100644
--- a/lib/megaco/src/flex/Makefile.in
+++ b/lib/megaco/src/flex/Makefile.in
@@ -319,16 +319,16 @@ release_docs_spec:
$(STD_DRV).flex: megaco_flex_scanner_drv.flex.src
ifeq ($(ENABLE_MEGACO_FLEX_SCANNER_LINENO),true)
- @printf "std [flex] scanner - lineno enabled\n"
- $(PERL) -p -e \
+ $(V_colon)@printf "std [flex] scanner - lineno enabled\n"
+ $(gen_verbose)$(PERL) -p -e \
's/%FLEX_VERSION%/$(FLEX_VSN)/ ; \
s/%MEGACO_YY_LINENO_OPTION%/%option yylineno/ ; \
s/%MEGACO_YY_REENTRANT_OPTION%/\/\* %option reentrant \*\// ; \
s/%MEGACO_DUMMY_DECL_YY_LINENO%/\/* static int yylineno = 1; *\//' \
< $< > $@
else
- @printf "std [flex] scanner - lineno disabled\n"
- $(PERL) -p -e \
+ $(V_colon)@printf "std [flex] scanner - lineno disabled\n"
+ $(gen_verbose)$(PERL) -p -e \
's/%FLEX_VERSION%/$(FLEX_VSN)/ ; \
s/%MEGACO_YY_LINENO_OPTION%/\/\* %option yylineno \*\// ; \
s/%MEGACO_YY_REENTRANT_OPTION%/\/\* %option reentrant \*\// ; \
@@ -339,16 +339,16 @@ endif
$(MT_DRV).flex: megaco_flex_scanner_drv.flex.src
ifeq ($(ENABLE_MEGACO_FLEX_SCANNER_LINENO),true)
ifeq ($(ENABLE_REENTRANT_MEGACO_FLEX_SCANNER),true)
- @printf "multi-threaded reentrant [flex] scanner - lineno enabled\n"
- $(PERL) -p -e \
+ $(V_colon)@printf "multi-threaded reentrant [flex] scanner - lineno enabled\n"
+ $(gen_verbose)$(PERL) -p -e \
's/%FLEX_VERSION%/$(FLEX_VSN)/ ; \
s/%MEGACO_YY_LINENO_OPTION%/%option yylineno/ ; \
s/%MEGACO_YY_REENTRANT_OPTION%/%option reentrant/ ; \
s/%MEGACO_DUMMY_DECL_YY_LINENO%/\/* static int yylineno = 1; *\//' \
< $< > $@
else
- @printf "multi-threaded non-reentrant [flex] scanner - lineno enabled\n"
- $(PERL) -p -e \
+ $(V_colon)@printf "multi-threaded non-reentrant [flex] scanner - lineno enabled\n"
+ $(gen_verbose)$(PERL) -p -e \
's/%FLEX_VERSION%/$(FLEX_VSN)/ ; \
s/%MEGACO_YY_LINENO_OPTION%/%option yylineno/ ; \
s/%MEGACO_YY_REENTRANT_OPTION%/\/\* %option reentrant \*\// ; \
@@ -357,16 +357,16 @@ else
endif
else
ifeq ($(ENABLE_REENTRANT_MEGACO_FLEX_SCANNER),true)
- @printf "multi-threaded reentrant [flex] scanner - lineno disabled\n"
- $(PERL) -p -e \
+ $(V_colon)@printf "multi-threaded reentrant [flex] scanner - lineno disabled\n"
+ $(gen_verbose)$(PERL) -p -e \
's/%FLEX_VERSION%/$(FLEX_VSN)/ ; \
s/%MEGACO_YY_LINENO_OPTION%/\/\* %option yylineno \*\// ; \
s/%MEGACO_YY_REENTRANT_OPTION%/%option reentrant/ ; \
s/%MEGACO_DUMMY_DECL_YY_LINENO%/\/* static int yylineno = 1; - REENTRANT SCANNER*\//' \
< $< > $@
else
- @printf "multi-threaded non-reentrant [flex] scanner - lineno disabled\n"
- $(PERL) -p -e \
+ $(V_colon)@printf "multi-threaded non-reentrant [flex] scanner - lineno disabled\n"
+ $(gen_verbose)$(PERL) -p -e \
's/%FLEX_VERSION%/$(FLEX_VSN)/ ; \
s/%MEGACO_YY_LINENO_OPTION%/\/\* %option yylineno \*\// ; \
s/%MEGACO_YY_REENTRANT_OPTION%/\/\* %option reentrant \*\// ; \
@@ -376,31 +376,31 @@ endif
endif
# megaco_flex_scanner_drv.c: megaco_flex_scanner_drv.flex
-# $(LEX) $(LEX_FLAGS) -P$* -o$@ $<
+# $(V_LEX) $(LEX_FLAGS) -P$* -o$@ $<
$(STD_DRV).c: $(STD_DRV).flex
- $(LEX) $(STD_LEX_FLAGS) -P$* -o$@ $<
+ $(V_LEX) $(STD_LEX_FLAGS) -P$* -o$@ $<
$(MT_DRV).c: $(MT_DRV).flex
- $(LEX) $(MT_LEX_FLAGS) -P$* -o$@ $<
+ $(V_LEX) $(MT_LEX_FLAGS) -P$* -o$@ $<
_create_dirs := $(shell mkdir -p $(OBJDIR) $(LIBDIR))
solibs: $(SOLIBS)
$(OBJDIR)/$(STD_DRV).o: $(STD_DRV).c
- @echo "compiling std driver:"
- $(CC) -c $(STD_DRV_NAME) $(CFLAGS) -o $@ $<
+ $(V_colon)@echo "compiling std driver:"
+ $(V_CC) -c $(STD_DRV_NAME) $(CFLAGS) -o $@ $<
$(OBJDIR)/$(MT_DRV).o: $(MT_DRV).c
- @echo "compiling multi-threaded driver:"
- $(CC) -c $(MT_DRV_NAME) $(CFLAGS_MT) -o $@ $<
+ $(V_colon)@echo "compiling multi-threaded driver:"
+ $(V_CC) -c $(MT_DRV_NAME) $(CFLAGS_MT) -o $@ $<
# No need to link with -lfl as we have also defined %option noyywrap -
# and having -lfl doesn't work under Darwin for some reason. - Sean
$(LIBDIR)/$(STD_DRV).$(DED_EXT): $(OBJDIR)/$(STD_DRV).o
- @echo "linking std driver:"
- $(LD) $(LDFLAGS) -o $@ $<
+ $(V_colon)@echo "linking std driver:"
+ $(V_LD) $(LDFLAGS) -o $@ $<
$(LIBDIR)/$(MT_DRV).$(DED_EXT): $(OBJDIR)/$(MT_DRV).o
- @echo "linking multi-threaded driver:"
- $(LD) $(LDFLAGS) -o $@ $<
+ $(V_colon)@echo "linking multi-threaded driver:"
+ $(V_LD) $(LDFLAGS) -o $@ $<
diff --git a/lib/megaco/test/megaco_actions_test.erl b/lib/megaco/test/megaco_actions_test.erl
index 2efb6e834a..6d0e80281d 100644
--- a/lib/megaco/test/megaco_actions_test.erl
+++ b/lib/megaco/test/megaco_actions_test.erl
@@ -80,8 +80,7 @@ end_per_testcase(Case, Config) ->
all() ->
[pretty_text, flex_pretty_text, compact_text,
- flex_compact_text, erl_dist, erl_dist_mc, ber_bin,
- ber_bin_drv, ber_bin_native, ber_bin_drv_native].
+ flex_compact_text, erl_dist, erl_dist_mc].
groups() ->
[].
@@ -170,39 +169,6 @@ erl_dist_mc(Config) when is_list(Config) ->
req_and_rep(Config, Codec, Version, EncodingConfig).
-ber_bin(suite) ->
- [];
-ber_bin(doc) ->
- [];
-ber_bin(Config) when is_list(Config) ->
- ?SKIP(currently_not_supported_by_asn1).
-
-
-ber_bin_drv(suite) ->
- [];
-ber_bin_drv(doc) ->
- [];
-ber_bin_drv(Config) when is_list(Config) ->
- ?SKIP(currently_not_supported_by_asn1).
-
-
-ber_bin_native(suite) ->
- [];
-ber_bin_native(doc) ->
- [];
-ber_bin_native(Config) when is_list(Config) ->
- ?SKIP(currently_not_supported_by_asn1).
-
-
-ber_bin_drv_native(suite) ->
- [];
-ber_bin_drv_native(doc) ->
- [];
-ber_bin_drv_native(Config) when is_list(Config) ->
- ?SKIP(currently_not_supported_by_asn1).
-
-
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
req_and_rep(Config, Codec, _Version, EC) when is_list(Config) ->
diff --git a/lib/megaco/test/megaco_call_flow_test.erl b/lib/megaco/test/megaco_call_flow_test.erl
index b9d64ca8b2..d5888018cd 100644
--- a/lib/megaco/test/megaco_call_flow_test.erl
+++ b/lib/megaco/test/megaco_call_flow_test.erl
@@ -25,7 +25,6 @@
%% megaco_call_flow_test:compact_text().
%% megaco_call_flow_test:bin().
%% megaco_call_flow_test:asn1_ber().
-%% megaco_call_flow_test:asn1_ber_bin().
%% megaco_call_flow_test:asn1_per().
%% megaco_call_flow_test:erl_dist().
%% megaco_call_flow_test:compressed_erl_dist().
@@ -62,7 +61,7 @@ all() ->
groups() ->
[{text, [], [pretty, compact]},
{flex, [], [pretty_flex, compact_flex]},
- {binary, [], [bin, ber, ber_bin, per]}].
+ {binary, [], [bin, ber, per]}].
init_per_group(_GroupName, Config) ->
Config.
@@ -106,12 +105,6 @@ ber(Config) when is_list(Config) ->
?ACQUIRE_NODES(1, Config),
asn1_ber().
-ber_bin(suite) ->
- [];
-ber_bin(Config) when is_list(Config) ->
- ?ACQUIRE_NODES(1, Config),
- asn1_ber_bin().
-
per(suite) ->
[];
per(Config) when is_list(Config) ->
@@ -1198,8 +1191,7 @@ encoders() ->
{megaco_pretty_text_encoder, [], []},
{megaco_compact_text_encoder, [], []},
{megaco_binary_encoder, [], [native]},
- %% {megaco_ber_encoder, [], [native]},
- %% {megaco_ber_bin_encoder, [], [native]},
+ {megaco_ber_encoder, [], [native]},
{megaco_per_encoder, [], [native]},
{megaco_erl_dist_encoder, [], []},
{megaco_erl_dist_encoder, [compressed], [compressed]}
@@ -1214,7 +1206,6 @@ pretty_mod({Mod, Opt, _Opt2}) ->
megaco_compact_text_encoder -> compact_text;
megaco_binary_encoder -> asn1_ber;
megaco_ber_encoder -> asn1_ber_old;
- megaco_ber_bin_encoder -> asn1_ber_bin;
megaco_per_encoder -> asn1_per;
megaco_erl_dist_encoder when Opt == [] -> standard_erl;
megaco_erl_dist_encoder when Opt == [compressed] -> compressed_erl;
@@ -1263,13 +1254,6 @@ asn1_ber() ->
All = [encode(Slogan, Msg, Encoder) || {Slogan, Msg} <- messages()],
compute_res(All).
-asn1_ber_bin() ->
- Default = [],
- Native = [native],
- Encoder = {megaco_ber_bin_encoder, Default, Native},
- All = [encode(Slogan, Msg, Encoder) || {Slogan, Msg} <- messages()],
- compute_res(All).
-
asn1_per() ->
Default = [],
Native = [native],
@@ -1634,7 +1618,7 @@ gen_ber_header() ->
%% Generate headerfile for asn.1 BER test in C
%%----------------------------------------------------------------------
gen_ber_bin_header() ->
- Encoder = {megaco_ber_bin_encoder, [], []},
+ Encoder = {megaco_ber_encoder, [], []},
L = [{S, gen_byte_msg(Msg, Encoder)} || {S, Msg} <- messages()],
gen_header_file_binary(L).
diff --git a/lib/megaco/test/megaco_codec_prev3a_test.erl b/lib/megaco/test/megaco_codec_prev3a_test.erl
index d50e72aef1..b2316eb509 100644
--- a/lib/megaco/test/megaco_codec_prev3a_test.erl
+++ b/lib/megaco/test/megaco_codec_prev3a_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -63,12 +63,8 @@
ber_test_msgs/1,
- ber_bin_test_msgs/1,
-
per_test_msgs/1,
- per_bin_test_msgs/1,
-
erl_dist_m_test_msgs/1,
tickets/0,
@@ -280,17 +276,14 @@ groups() ->
[{group, pretty}, {group, flex_pretty},
{group, compact}, {group, flex_compact}]},
{binary, [],
- [{group, bin}, {group, ber}, {group, ber_bin},
- {group, per}, {group, per_bin}]},
+ [{group, bin}, {group, ber}, {group, per}]},
{erl_dist, [], [{group, erl_dist_m}]},
{pretty, [], [pretty_test_msgs]},
{compact, [], [compact_test_msgs]},
{flex_pretty, [], flex_pretty_cases()},
{flex_compact, [], flex_compact_cases()},
{bin, [], [bin_test_msgs]}, {ber, [], [ber_test_msgs]},
- {ber_bin, [], [ber_bin_test_msgs]},
{per, [], [per_test_msgs]},
- {per_bin, [], [per_bin_test_msgs]},
{erl_dist_m, [], [erl_dist_m_test_msgs]},
{tickets, [],
[{group, compact_tickets},
@@ -1106,17 +1099,6 @@ ber_test_msgs(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-ber_bin_test_msgs(suite) ->
- [];
-ber_bin_test_msgs(Config) when is_list(Config) ->
- ?ACQUIRE_NODES(1, Config),
- Msgs = msgs1(binary) ++ msgs4(binary) ++ msgs5(binary) ++ msgs6(binary),
- DynamicDecode = true,
- test_msgs(megaco_ber_bin_encoder, DynamicDecode, ?EC, Msgs).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
per_test_msgs(suite) ->
[];
per_test_msgs(Config) when is_list(Config) ->
@@ -1128,17 +1110,6 @@ per_test_msgs(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-per_bin_test_msgs(suite) ->
- [];
-per_bin_test_msgs(Config) when is_list(Config) ->
- ?ACQUIRE_NODES(1, Config),
- Msgs = msgs1(binary) ++ msgs4(binary) ++ msgs5(binary) ++ msgs6(binary),
- DynamicDecode = false,
- test_msgs(megaco_per_bin_encoder, DynamicDecode, ?EC, Msgs).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
erl_dist_m_test_msgs(suite) ->
[];
erl_dist_m_test_msgs(Config) when is_list(Config) ->
@@ -3133,7 +3104,7 @@ pretty_otp5068_msg1() ->
190,
asn1_NOVALUE,
{actionReplies,
- [{'ActionReply', %% Comments: Detta upprepas m�nga g�nger
+ [{'ActionReply', %% Comments: This is repeated many times.
0,
asn1_NOVALUE,
asn1_NOVALUE,
diff --git a/lib/megaco/test/megaco_codec_prev3b_test.erl b/lib/megaco/test/megaco_codec_prev3b_test.erl
index eaab8f37c1..fa24f49372 100644
--- a/lib/megaco/test/megaco_codec_prev3b_test.erl
+++ b/lib/megaco/test/megaco_codec_prev3b_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -63,12 +63,8 @@
ber_test_msgs/1,
- ber_bin_test_msgs/1,
-
per_test_msgs/1,
- per_bin_test_msgs/1,
-
erl_dist_m_test_msgs/1,
tickets/0,
@@ -296,17 +292,14 @@ groups() ->
[{group, pretty}, {group, flex_pretty},
{group, compact}, {group, flex_compact}]},
{binary, [],
- [{group, bin}, {group, ber}, {group, ber_bin},
- {group, per}, {group, per_bin}]},
+ [{group, bin}, {group, ber}, {group, per}]},
{erl_dist, [], [{group, erl_dist_m}]},
{pretty, [], [pretty_test_msgs]},
{compact, [], [compact_test_msgs]},
{flex_pretty, [], flex_pretty_cases()},
{flex_compact, [], flex_compact_cases()},
{bin, [], [bin_test_msgs]}, {ber, [], [ber_test_msgs]},
- {ber_bin, [], [ber_bin_test_msgs]},
{per, [], [per_test_msgs]},
- {per_bin, [], [per_bin_test_msgs]},
{erl_dist_m, [], [erl_dist_m_test_msgs]},
{tickets, [],
[{group, compact_tickets},
@@ -1171,16 +1164,6 @@ ber_test_msgs(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-ber_bin_test_msgs(suite) ->
- [];
-ber_bin_test_msgs(Config) when is_list(Config) ->
- ?ACQUIRE_NODES(1, Config),
- Msgs = msgs1(binary) ++ msgs4(binary) ++ msgs5(binary) ++ msgs6(binary),
- DynamicDecode = true,
- test_msgs(megaco_ber_bin_encoder, DynamicDecode, ?EC, Msgs).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
per_test_msgs(suite) ->
[];
@@ -1193,17 +1176,6 @@ per_test_msgs(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-per_bin_test_msgs(suite) ->
- [];
-per_bin_test_msgs(Config) when is_list(Config) ->
- ?ACQUIRE_NODES(1, Config),
- Msgs = msgs1(binary) ++ msgs4(binary) ++ msgs5(binary) ++ msgs6(binary),
- DynamicDecode = false,
- test_msgs(megaco_per_bin_encoder, DynamicDecode, ?EC, Msgs).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
erl_dist_m_test_msgs(suite) ->
[];
erl_dist_m_test_msgs(Config) when is_list(Config) ->
@@ -3251,7 +3223,7 @@ pretty_otp5068_msg1() ->
190,
asn1_NOVALUE,
{actionReplies,
- [{'ActionReply', %% Comments: Detta upprepas m�nga g�nger
+ [{'ActionReply', %% Comments: This is repeated many times.
0,
asn1_NOVALUE,
asn1_NOVALUE,
diff --git a/lib/megaco/test/megaco_codec_prev3c_test.erl b/lib/megaco/test/megaco_codec_prev3c_test.erl
index 7f9c0fe4e7..7f6d098ed8 100644
--- a/lib/megaco/test/megaco_codec_prev3c_test.erl
+++ b/lib/megaco/test/megaco_codec_prev3c_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -65,12 +65,8 @@
ber_test_msgs/1,
- ber_bin_test_msgs/1,
-
per_test_msgs/1,
- per_bin_test_msgs/1,
-
erl_dist_m_test_msgs/1,
tickets/0,
@@ -301,17 +297,14 @@ groups() ->
[{group, pretty}, {group, flex_pretty},
{group, compact}, {group, flex_compact}]},
{binary, [],
- [{group, bin}, {group, ber}, {group, ber_bin},
- {group, per}, {group, per_bin}]},
+ [{group, bin}, {group, ber}, {group, per}]},
{erl_dist, [], [{group, erl_dist_m}]},
{pretty, [], [pretty_test_msgs]},
{compact, [], [compact_test_msgs]},
{flex_pretty, [], flex_pretty_cases()},
{flex_compact, [], flex_compact_cases()},
{bin, [], [bin_test_msgs]}, {ber, [], [ber_test_msgs]},
- {ber_bin, [], [ber_bin_test_msgs]},
{per, [], [per_test_msgs]},
- {per_bin, [], [per_bin_test_msgs]},
{erl_dist_m, [], [erl_dist_m_test_msgs]},
{tickets, [],
[{group, compact_tickets},
@@ -823,21 +816,6 @@ ber_test_msgs(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-ber_bin_test_msgs(suite) ->
- [];
-ber_bin_test_msgs(Config) when is_list(Config) ->
- ?ACQUIRE_NODES(1, Config),
- Msgs =
- msgs1a(binary) ++
- msgs5(binary) ++
- msgs6(binary) ++
- msgs7(binary),
- DynamicDecode = true,
- test_msgs(megaco_ber_bin_encoder, DynamicDecode, ?EC, Msgs).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
per_test_msgs(suite) ->
[];
per_test_msgs(Config) when is_list(Config) ->
@@ -853,21 +831,6 @@ per_test_msgs(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-per_bin_test_msgs(suite) ->
- [];
-per_bin_test_msgs(Config) when is_list(Config) ->
- ?ACQUIRE_NODES(1, Config),
- Msgs =
- msgs1a(binary) ++
- msgs5(binary) ++
- msgs6(binary) ++
- msgs7(binary),
- DynamicDecode = false,
- test_msgs(megaco_per_bin_encoder, DynamicDecode, ?EC, Msgs).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
erl_dist_m_test_msgs(suite) ->
[];
erl_dist_m_test_msgs(Config) when is_list(Config) ->
@@ -2716,7 +2679,7 @@ pretty_otp5068_msg1() ->
190,
asn1_NOVALUE,
{actionReplies,
- [{'ActionReply', %% Comments: Detta upprepas m�nga g�nger
+ [{'ActionReply', %% Comments: This is repeated many times.
0,
asn1_NOVALUE,
asn1_NOVALUE,
diff --git a/lib/megaco/test/megaco_codec_v1_test.erl b/lib/megaco/test/megaco_codec_v1_test.erl
index e9c19605dd..3be0da3ae4 100644
--- a/lib/megaco/test/megaco_codec_v1_test.erl
+++ b/lib/megaco/test/megaco_codec_v1_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -66,12 +66,8 @@
ber_test_msgs/1,
- ber_bin_test_msgs/1,
-
per_test_msgs/1,
- per_bin_test_msgs/1,
-
erl_dist_m_test_msgs/1,
tickets/0,
@@ -476,9 +472,7 @@ groups() ->
{group, flex_compact}]},
{binary, [], [{group, bin},
{group, ber},
- {group, ber_bin},
- {group, per},
- {group, per_bin}]},
+ {group, per}]},
{erl_dist, [], [{group, erl_dist_m}]},
{pretty, [], [pretty_test_msgs]},
{compact, [], [compact_test_msgs]},
@@ -486,9 +480,7 @@ groups() ->
{flex_compact, [], flex_compact_cases()},
{bin, [], [bin_test_msgs]},
{ber, [], [ber_test_msgs]},
- {ber_bin, [], [ber_bin_test_msgs]},
{per, [], [per_test_msgs]},
- {per_bin, [], [per_bin_test_msgs]},
{erl_dist_m, [], [erl_dist_m_test_msgs]},
{tickets, [], [{group, compact_tickets},
{group, pretty_tickets},
@@ -1266,17 +1258,6 @@ ber_test_msgs(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-ber_bin_test_msgs(suite) ->
- [];
-ber_bin_test_msgs(Config) when is_list(Config) ->
- ?ACQUIRE_NODES(1, Config),
- Msgs = msgs1(),
- DynamicDecode = true,
- test_msgs(megaco_ber_bin_encoder, DynamicDecode, [], Msgs).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
per_test_msgs(suite) ->
[];
per_test_msgs(Config) when is_list(Config) ->
@@ -1288,17 +1269,6 @@ per_test_msgs(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-per_bin_test_msgs(suite) ->
- [];
-per_bin_test_msgs(Config) when is_list(Config) ->
- ?ACQUIRE_NODES(1, Config),
- Msgs = msgs1(),
- DynamicDecode = false,
- test_msgs(megaco_per_bin_encoder, DynamicDecode, [], Msgs).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
erl_dist_m_test_msgs(suite) ->
[];
erl_dist_m_test_msgs(Config) when is_list(Config) ->
@@ -3328,7 +3298,7 @@ pretty_otp5068_msg1() ->
190,
asn1_NOVALUE,
{actionReplies,
- [{'ActionReply', %% Comments: Detta upprepas m�nga g�nger
+ [{'ActionReply', %% Comments: This is repeated many times.
0,
asn1_NOVALUE,
asn1_NOVALUE,
diff --git a/lib/megaco/test/megaco_codec_v2_test.erl b/lib/megaco/test/megaco_codec_v2_test.erl
index a44f74166c..1f522504d6 100644
--- a/lib/megaco/test/megaco_codec_v2_test.erl
+++ b/lib/megaco/test/megaco_codec_v2_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -64,12 +64,8 @@
ber_test_msgs/1,
- ber_bin_test_msgs/1,
-
per_test_msgs/1,
- per_bin_test_msgs/1,
-
erl_dist_m_test_msgs/1,
tickets/0,
@@ -447,17 +443,14 @@ groups() ->
[{group, pretty}, {group, flex_pretty},
{group, compact}, {group, flex_compact}]},
{binary, [],
- [{group, bin}, {group, ber}, {group, ber_bin},
- {group, per}, {group, per_bin}]},
+ [{group, bin}, {group, ber}, {group, per}]},
{erl_dist, [], [{group, erl_dist_m}]},
{pretty, [], [pretty_test_msgs]},
{compact, [], [compact_test_msgs]},
{flex_pretty, [], flex_pretty_cases()},
{flex_compact, [], flex_compact_cases()},
{bin, [], [bin_test_msgs]}, {ber, [], [ber_test_msgs]},
- {ber_bin, [], [ber_bin_test_msgs]},
{per, [], [per_test_msgs]},
- {per_bin, [], [per_bin_test_msgs]},
{erl_dist_m, [], [erl_dist_m_test_msgs]},
{tickets, [],
[{group, compact_tickets}, {group, pretty_tickets},
@@ -1285,17 +1278,6 @@ ber_test_msgs(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-ber_bin_test_msgs(suite) ->
- [];
-ber_bin_test_msgs(Config) when is_list(Config) ->
- ?ACQUIRE_NODES(1, Config),
- Msgs = msgs1() ++ msgs4(),
- DynamicDecode = true,
- test_msgs(megaco_ber_bin_encoder, DynamicDecode, [], Msgs).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
per_test_msgs(suite) ->
[];
per_test_msgs(Config) when is_list(Config) ->
@@ -1307,17 +1289,6 @@ per_test_msgs(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-per_bin_test_msgs(suite) ->
- [];
-per_bin_test_msgs(Config) when is_list(Config) ->
- ?ACQUIRE_NODES(1, Config),
- Msgs = msgs1() ++ msgs4(),
- DynamicDecode = false,
- test_msgs(megaco_per_bin_encoder, DynamicDecode, [], Msgs).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
erl_dist_m_test_msgs(suite) ->
[];
erl_dist_m_test_msgs(Config) when is_list(Config) ->
@@ -3751,7 +3722,7 @@ pretty_otp5068_msg1() ->
190,
asn1_NOVALUE,
{actionReplies,
- [{'ActionReply', %% Comments: Detta upprepas m�nga g�nger
+ [{'ActionReply', %% Comments: This is repeated many times.
0,
asn1_NOVALUE,
asn1_NOVALUE,
diff --git a/lib/megaco/test/megaco_codec_v3_test.erl b/lib/megaco/test/megaco_codec_v3_test.erl
index 2c35ce13b3..9d564a0ae3 100644
--- a/lib/megaco/test/megaco_codec_v3_test.erl
+++ b/lib/megaco/test/megaco_codec_v3_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -56,9 +56,7 @@
flex_compact_dm_timers8/1,
bin_test_msgs/1,
ber_test_msgs/1,
- ber_bin_test_msgs/1,
per_test_msgs/1,
- per_bin_test_msgs/1,
erl_dist_m_test_msgs/1,
tickets/0,
@@ -288,17 +286,14 @@ groups() ->
[{group, pretty}, {group, flex_pretty},
{group, compact}, {group, flex_compact}]},
{binary, [],
- [{group, bin}, {group, ber}, {group, ber_bin},
- {group, per}, {group, per_bin}]},
+ [{group, bin}, {group, ber}, {group, per}]},
{erl_dist, [], [{group, erl_dist_m}]},
{pretty, [], [pretty_test_msgs]},
{compact, [], [compact_test_msgs]},
{flex_pretty, [], flex_pretty_cases()},
{flex_compact, [], flex_compact_cases()},
{bin, [], [bin_test_msgs]}, {ber, [], [ber_test_msgs]},
- {ber_bin, [], [ber_bin_test_msgs]},
{per, [], [per_test_msgs]},
- {per_bin, [], [per_bin_test_msgs]},
{erl_dist_m, [], [erl_dist_m_test_msgs]},
{tickets, [],
[{group, compact_tickets},
@@ -823,22 +818,6 @@ ber_test_msgs(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-ber_bin_test_msgs(suite) ->
- [];
-ber_bin_test_msgs(Config) when is_list(Config) ->
- ?ACQUIRE_NODES(1, Config),
- Msgs =
- msgs1a(binary) ++
- msgs5(binary) ++
- msgs6(binary) ++
- msgs7(binary) ++
- msgs8(binary),
- DynamicDecode = true,
- test_msgs(megaco_ber_bin_encoder, DynamicDecode, ?EC, Msgs).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
per_test_msgs(suite) ->
[];
per_test_msgs(Config) when is_list(Config) ->
@@ -855,22 +834,6 @@ per_test_msgs(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-per_bin_test_msgs(suite) ->
- [];
-per_bin_test_msgs(Config) when is_list(Config) ->
- ?ACQUIRE_NODES(1, Config),
- Msgs =
- msgs1a(binary) ++
- msgs5(binary) ++
- msgs6(binary) ++
- msgs7(binary) ++
- msgs8(binary),
- DynamicDecode = false,
- test_msgs(megaco_per_bin_encoder, DynamicDecode, ?EC, Msgs).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
erl_dist_m_test_msgs(suite) ->
[];
erl_dist_m_test_msgs(Config) when is_list(Config) ->
@@ -2738,7 +2701,7 @@ pretty_otp5068_msg1() ->
190,
asn1_NOVALUE,
{actionReplies,
- [{'ActionReply', %% Comments: Detta upprepas m�nga g�nger
+ [{'ActionReply', %% Comments: This is repeated many times.
0,
asn1_NOVALUE,
asn1_NOVALUE,
diff --git a/lib/megaco/test/megaco_mess_test.erl b/lib/megaco/test/megaco_mess_test.erl
index 663ac8c329..f8be96c254 100644
--- a/lib/megaco/test/megaco_mess_test.erl
+++ b/lib/megaco/test/megaco_mess_test.erl
@@ -1393,7 +1393,7 @@ rarpaop_mgc_event_sequence(text, tcp) ->
rarpaop_mgc_event_sequence(binary, tcp) ->
Port = 2945,
TranspMod = megaco_tcp,
- EncMod = megaco_ber_bin_encoder,
+ EncMod = megaco_ber_encoder,
EncConf = [],
rarpaop_mgc_event_sequence(Port, TranspMod, EncMod, EncConf).
@@ -1680,7 +1680,7 @@ rarpaop_mg_event_sequence(text, tcp) ->
rarpaop_mg_event_sequence(Port, EncMod, EncConf);
rarpaop_mg_event_sequence(binary, tcp) ->
Port = 2945,
- EncMod = megaco_ber_bin_encoder,
+ EncMod = megaco_ber_encoder,
EncConf = [],
rarpaop_mg_event_sequence(Port, EncMod, EncConf).
diff --git a/lib/megaco/test/megaco_mib_test.erl b/lib/megaco/test/megaco_mib_test.erl
index 52d99d1442..ddc74ab741 100644
--- a/lib/megaco/test/megaco_mib_test.erl
+++ b/lib/megaco/test/megaco_mib_test.erl
@@ -647,13 +647,13 @@ mk_recv_info([{text,udp}|ET], Acc) ->
{port, 2944}],
mk_recv_info(ET, [RI|Acc]);
mk_recv_info([{binary,tcp}|ET], Acc) ->
- RI = [{encoding_module, megaco_ber_bin_encoder},
+ RI = [{encoding_module, megaco_ber_encoder},
{encoding_config, []},
{transport_module, megaco_tcp},
{port, 2945}],
mk_recv_info(ET, [RI|Acc]);
mk_recv_info([{binary,udp}|ET], Acc) ->
- RI = [{encoding_module, megaco_ber_bin_encoder},
+ RI = [{encoding_module, megaco_ber_encoder},
{encoding_config, []},
{transport_module, megaco_udp},
{port, 2945}],
@@ -1013,7 +1013,7 @@ start_mg(Node, Mid, Encoding, Transport, Verbosity) ->
{encoding_config, []},
{port,2944}];
binary ->
- [{encoding_module, megaco_ber_bin_encoder},
+ [{encoding_module, megaco_ber_encoder},
{encoding_config, []},
{port,2945}]
end,
diff --git a/lib/megaco/test/megaco_test_mg.erl b/lib/megaco/test/megaco_test_mg.erl
index ecb3cedc83..947f0eebbb 100644
--- a/lib/megaco/test/megaco_test_mg.erl
+++ b/lib/megaco/test/megaco_test_mg.erl
@@ -158,7 +158,7 @@ select_encoding(pretty_text) ->
select_encoding(compact_text) ->
{megaco_compact_text_encoder, 2944};
select_encoding(binary) ->
- {megaco_ber_bin_encoder, 2945};
+ {megaco_ber_encoder, 2945};
select_encoding(erl_dist) ->
{megaco_erl_dist_encoder, 2946};
select_encoding(Encoding) ->
diff --git a/lib/megaco/test/megaco_test_mgc.erl b/lib/megaco/test/megaco_test_mgc.erl
index 13c1cebe56..a964983861 100644
--- a/lib/megaco/test/megaco_test_mgc.erl
+++ b/lib/megaco/test/megaco_test_mgc.erl
@@ -135,7 +135,7 @@ select_encoding(pretty_text) ->
select_encoding(compact_text) ->
{megaco_compact_text_encoder, 2944};
select_encoding(binary) ->
- {megaco_ber_bin_encoder, 2945};
+ {megaco_ber_encoder, 2945};
select_encoding(erl_dist) ->
{megaco_erl_dist_encoder, 2946};
select_encoding(Encoding) ->
diff --git a/lib/mnesia/src/Makefile b/lib/mnesia/src/Makefile
index 6f289433ff..53d327c11b 100644
--- a/lib/mnesia/src/Makefile
+++ b/lib/mnesia/src/Makefile
@@ -120,10 +120,10 @@ $(TARGET_FILES): $(HRL_FILES)
# ----------------------------------------------------
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
# ----------------------------------------------------
diff --git a/lib/mnesia/src/mnesia_controller.erl b/lib/mnesia/src/mnesia_controller.erl
index d488a33d67..ec67d9ec12 100644
--- a/lib/mnesia/src/mnesia_controller.erl
+++ b/lib/mnesia/src/mnesia_controller.erl
@@ -593,6 +593,12 @@ multicall(Nodes, Msg) ->
{PatchedGood, Bad}. %% Make the replies look like rpc:multicalls..
%% rpc:multicall(Nodes, ?MODULE, call, [Msg]).
+next_async_dump_log() ->
+ Interval = mnesia_monitor:get_env(dump_log_time_threshold),
+ Msg = {next_async_dump_log, time_threshold},
+ Ref = erlang:send_after(Interval, self(), Msg),
+ Ref.
+
%%%----------------------------------------------------------------------
%%% Callback functions from gen_server
%%%----------------------------------------------------------------------
@@ -614,9 +620,7 @@ init([Parent]) ->
mnesia_lib:unset(original_nodes),
mnesia_recover:connect_nodes(Diff),
- Interval = mnesia_monitor:get_env(dump_log_time_threshold),
- Msg = {async_dump_log, time_threshold},
- {ok, Ref} = timer:send_interval(Interval, Msg),
+ Ref = next_async_dump_log(),
mnesia_dumper:start_regulator(),
Empty = gb_trees:empty(),
@@ -1121,6 +1125,11 @@ handle_sync_tabs([], _From) ->
%% {stop, Reason, State} (terminate/2 is called)
%%----------------------------------------------------------------------
+handle_info({next_async_dump_log, InitBy}, State) ->
+ async_dump_log(InitBy),
+ Ref = next_async_dump_log(),
+ noreply(State#state{dump_log_timer_ref=Ref});
+
handle_info({async_dump_log, InitBy}, State) ->
Worker = #dump_log{initiated_by = InitBy},
State2 = add_worker(Worker, State),
diff --git a/lib/mnesia/src/mnesia_event.erl b/lib/mnesia/src/mnesia_event.erl
index 8085155fd5..9fd0342d31 100644
--- a/lib/mnesia/src/mnesia_event.erl
+++ b/lib/mnesia/src/mnesia_event.erl
@@ -153,7 +153,7 @@ handle_system_event({mnesia_down, Node}, State) ->
end;
handle_system_event({mnesia_overload, Details}, State) ->
- report_warning("Mnesia is overloaded: ~p~n", [Details]),
+ report_warning("Mnesia is overloaded: ~w~n", [Details]),
{ok, State};
handle_system_event({mnesia_info, Format, Args}, State) ->
diff --git a/lib/mnesia/src/mnesia_locker.erl b/lib/mnesia/src/mnesia_locker.erl
index a22c95d454..14011003d3 100644
--- a/lib/mnesia/src/mnesia_locker.erl
+++ b/lib/mnesia/src/mnesia_locker.erl
@@ -1177,9 +1177,9 @@ system_code_change(State, _Module, _OldVsn, _Extra) ->
%% AXD301 patch sort pids according to R9B sort order
%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Om R9B == true, g�rs j�mf�relsen som i R9B plain.
-%% Om R9B == false, g�rs j�mf�relsen som i alla andra releaser.
-%% cmp_tid(T1, T2) returnerar -1 om T1 < T2, 0 om T1 = T2 och 1 om T1 > T2.
+%% Om R9B == true, the comparison is done as in R9B plain.
+%% Om R9B == false, the comparison is done as in any other release.
+%% cmp_tid(T1, T2) returns -1 if T1 < T2, 0 if T1 = T2 and 1 if T1 > T2.
-define(VERSION_MAGIC, 131).
-define(ATOM_EXT, 100).
diff --git a/lib/mnesia/src/mnesia_recover.erl b/lib/mnesia/src/mnesia_recover.erl
index 4750291a10..b64f428f15 100644
--- a/lib/mnesia/src/mnesia_recover.erl
+++ b/lib/mnesia/src/mnesia_recover.erl
@@ -45,7 +45,8 @@
note_log_decision/2,
outcome/2,
start/0,
- start_garb/0,
+ next_garb/0,
+ next_check_overload/0,
still_pending/1,
sync_trans_tid_serial/1,
sync/0,
@@ -91,10 +92,38 @@ start() ->
init() ->
call(init).
-start_garb() ->
+next_garb() ->
Pid = whereis(mnesia_recover),
- {ok, _} = timer:send_interval(timer:minutes(2), Pid, garb_decisions),
- {ok, _} = timer:send_interval(timer:seconds(10), Pid, check_overload).
+ erlang:send_after(timer:minutes(2), Pid, garb_decisions).
+
+next_check_overload() ->
+ Pid = whereis(mnesia_recover),
+ erlang:send_after(timer:seconds(10), Pid, check_overload).
+
+
+do_check_overload(S) ->
+ %% Time to check if mnesia_tm is overloaded
+ case whereis(mnesia_tm) of
+ Pid when is_pid(Pid) ->
+ Threshold = 100,
+ Prev = S#state.tm_queue_len,
+ {message_queue_len, Len} =
+ process_info(Pid, message_queue_len),
+ if
+ Len > Threshold, Prev > Threshold ->
+ What = {mnesia_tm, message_queue_len, [Prev, Len]},
+ mnesia_lib:report_system_event({mnesia_overload, What}),
+ mnesia_lib:overload_set(mnesia_tm, true),
+ S#state{tm_queue_len = 0};
+ Len > Threshold ->
+ S#state{tm_queue_len = Len};
+ true ->
+ mnesia_lib:overload_set(mnesia_tm, false),
+ S#state{tm_queue_len = 0}
+ end;
+ undefined ->
+ S
+ end.
allow_garb() ->
cast(allow_garb).
@@ -853,34 +882,13 @@ handle_info({connect_nodes, Ns, From}, State) ->
handle_call({connect_nodes,Ns},From,State);
handle_info(check_overload, S) ->
- %% Time to check if mnesia_tm is overloaded
- case whereis(mnesia_tm) of
- Pid when is_pid(Pid) ->
-
- Threshold = 100,
- Prev = S#state.tm_queue_len,
- {message_queue_len, Len} =
- process_info(Pid, message_queue_len),
- if
- Len > Threshold, Prev > Threshold ->
- What = {mnesia_tm, message_queue_len, [Prev, Len]},
- mnesia_lib:report_system_event({mnesia_overload, What}),
- mnesia_lib:overload_set(mnesia_tm, true),
- {noreply, S#state{tm_queue_len = 0}};
-
- Len > Threshold ->
- {noreply, S#state{tm_queue_len = Len}};
-
- true ->
- mnesia_lib:overload_set(mnesia_tm, false),
- {noreply, S#state{tm_queue_len = 0}}
- end;
- undefined ->
- {noreply, S}
- end;
+ State2 = do_check_overload(S),
+ next_check_overload(),
+ {noreply, State2};
handle_info(garb_decisions, State) ->
do_garb_decisions(),
+ next_garb(),
{noreply, State};
handle_info({force_decision, Tid}, State) ->
diff --git a/lib/mnesia/src/mnesia_tm.erl b/lib/mnesia/src/mnesia_tm.erl
index 0af7f55c06..b5b14ac05b 100644
--- a/lib/mnesia/src/mnesia_tm.erl
+++ b/lib/mnesia/src/mnesia_tm.erl
@@ -103,7 +103,8 @@ init(Parent) ->
end,
mnesia_schema:purge_tmp_files(),
- mnesia_recover:start_garb(),
+ mnesia_recover:next_garb(),
+ mnesia_recover:next_check_overload(),
?eval_debug_fun({?MODULE, init}, [{nodes, AllOthers}]),
diff --git a/lib/observer/doc/src/notes.xml b/lib/observer/doc/src/notes.xml
index ea665eee88..4ec03782a7 100644
--- a/lib/observer/doc/src/notes.xml
+++ b/lib/observer/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2011</year>
+ <year>2004</year><year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/observer/src/Makefile b/lib/observer/src/Makefile
index 7135a6abd5..877286033e 100644
--- a/lib/observer/src/Makefile
+++ b/lib/observer/src/Makefile
@@ -114,10 +114,10 @@ clean:
rm -f errs core *~
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(TARGET_FILES): $(INTERNAL_HRL_FILES)
diff --git a/lib/observer/src/observer_app_wx.erl b/lib/observer/src/observer_app_wx.erl
index 380532e90c..72bafcc5e0 100644
--- a/lib/observer/src/observer_app_wx.erl
+++ b/lib/observer/src/observer_app_wx.erl
@@ -28,7 +28,7 @@
-include("observer_defs.hrl").
%% Import drawing wrappers
--import(observer_perf_wx, [haveGC/1,
+-import(observer_perf_wx, [haveGC/0,
setPen/2, setFont/3, setBrush/2,
strokeLine/5, strokeLines/2, drawRoundedRectangle/6,
drawText/4, getTextExtent/2]).
@@ -114,9 +114,10 @@ init([Notebook, Parent]) ->
_ -> ok
end,
- UseGC = haveGC(DrawingArea),
+ UseGC = haveGC(),
+ Version28 = ?wxMAJOR_VERSION =:= 2 andalso ?wxMINOR_VERSION =:= 8,
Font = case os:type() of
- {unix,_} when UseGC ->
+ {unix,_} when UseGC, Version28 ->
wxFont:new(12,?wxFONTFAMILY_DECORATIVE,?wxFONTSTYLE_NORMAL,?wxFONTWEIGHT_NORMAL);
_ ->
wxSystemSettings:getFont(?wxSYS_DEFAULT_GUI_FONT)
diff --git a/lib/observer/src/observer_perf_wx.erl b/lib/observer/src/observer_perf_wx.erl
index abf90ac612..54c98f3ba3 100644
--- a/lib/observer/src/observer_perf_wx.erl
+++ b/lib/observer/src/observer_perf_wx.erl
@@ -24,7 +24,7 @@
handle_event/2, handle_sync_event/3, handle_cast/2]).
%% Drawing wrappers for DC and GC areas
--export([haveGC/1,
+-export([haveGC/0,
setPen/2, setFont/3, setBrush/2,
strokeLine/5, strokeLines/2, drawRoundedRectangle/6,
drawText/4, getTextExtent/2]).
@@ -90,11 +90,12 @@ init([Notebook, Parent]) ->
_ -> ok
end,
- UseGC = haveGC(Panel),
+ UseGC = haveGC(),
+ Version28 = ?wxMAJOR_VERSION =:= 2 andalso ?wxMINOR_VERSION =:= 8,
{Font, SmallFont}
= case os:type() of
- {unix, _} when UseGC ->
- %% Def font is really small when using Graphics contexts for some reason
+ {unix, _} when UseGC, Version28 ->
+ %% Def font is really small when using Graphics contexts in 2.8
%% Hardcode it
F = wxFont:new(12,?wxFONTFAMILY_DECORATIVE,?wxFONTSTYLE_NORMAL,?wxFONTWEIGHT_BOLD),
SF = wxFont:new(10, ?wxFONTFAMILY_DECORATIVE, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_NORMAL),
@@ -524,10 +525,9 @@ colors() ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% wxDC and ?wxGC wrappers
-haveGC(Win) ->
+haveGC() ->
try
- GC = ?wxGC:create(Win),
- ?wxGC:destroy(GC),
+ wxGraphicsRenderer:getDefaultRenderer(),
true
catch _:_ -> false
end.
diff --git a/lib/observer/src/observer_pro_wx.erl b/lib/observer/src/observer_pro_wx.erl
index ee67664539..9aaf648ea2 100644
--- a/lib/observer/src/observer_pro_wx.erl
+++ b/lib/observer/src/observer_pro_wx.erl
@@ -225,7 +225,7 @@ handle_info({holder_updated, Count}, State0=#state{grid=Grid}) ->
State = update_selection(State0),
wxListCtrl:setItemCount(Grid, Count),
- wxListCtrl:refreshItems(Grid, 0, Count-1),
+ Count > 0 andalso wxListCtrl:refreshItems(Grid, 0, Count-1),
{noreply, State};
diff --git a/lib/observer/src/observer_tv_table.erl b/lib/observer/src/observer_tv_table.erl
index c41f0f006a..5d1ab2e946 100644
--- a/lib/observer/src/observer_tv_table.erl
+++ b/lib/observer/src/observer_tv_table.erl
@@ -403,7 +403,7 @@ handle_info({new_cols, New}, State = #state{grid=Grid, columns=Cols0}) ->
{noreply, State#state{columns=Cols}};
handle_info({refresh, Min, Max}, State = #state{grid=Grid}) ->
- wxListCtrl:refreshItems(Grid, Min, Max),
+ Max > 0 andalso wxListCtrl:refreshItems(Grid, Min, Max),
{noreply, State};
handle_info(refresh_interval, State = #state{pid=Pid}) ->
diff --git a/lib/observer/src/observer_wx.erl b/lib/observer/src/observer_wx.erl
index e433bea8c2..47740581f0 100644
--- a/lib/observer/src/observer_wx.erl
+++ b/lib/observer/src/observer_wx.erl
@@ -465,41 +465,36 @@ create_connect_dialog(ping, #state{frame = Frame, prev_node=Prev}) ->
cancel
end;
create_connect_dialog(connect, #state{frame = Frame}) ->
- Dialog = wxDialog:new(Frame, ?wxID_ANY, "Distribute node "),
+ Dialog = wxDialog:new(Frame, ?wxID_ANY, "Distribute node",
+ [{style, ?wxDEFAULT_FRAME_STYLE bor ?wxRESIZE_BORDER}]),
VSizer = wxBoxSizer:new(?wxVERTICAL),
- RadioBoxSizer = wxBoxSizer:new(?wxHORIZONTAL),
Choices = ["Short name", "Long name"],
- RadioBox = wxRadioBox:new(Dialog, 1, "",
- ?wxDefaultPosition,
- ?wxDefaultSize,
- Choices,
- [{majorDim, 2},
- {style, ?wxHORIZONTAL}]),
+ RadioBox = wxRadioBox:new(Dialog, 1, "", ?wxDefaultPosition, ?wxDefaultSize,
+ Choices, [{majorDim, 2}, {style, ?wxHORIZONTAL}]),
NameText = wxStaticText:new(Dialog, ?wxID_ANY, "Node name: "),
- NameCtrl = wxTextCtrl:new(Dialog, ?wxID_ANY, [{size, {200, 25}}]),
+ NameCtrl = wxTextCtrl:new(Dialog, ?wxID_ANY, [{size, {300,-1}}]),
wxTextCtrl:setValue(NameCtrl, "observer"),
CookieText = wxStaticText:new(Dialog, ?wxID_ANY, "Secret cookie: "),
- CookieCtrl = wxTextCtrl:new(Dialog, ?wxID_ANY,
- [{size, {200, 25}}, {style, ?wxTE_PASSWORD}]),
+ CookieCtrl = wxTextCtrl:new(Dialog, ?wxID_ANY,[{style, ?wxTE_PASSWORD}]),
- BtnSizer = wxDialog:createStdDialogButtonSizer(Dialog, ?wxID_DEFAULT),
- Flags = [{flag, ?wxEXPAND bor ?wxALL}, {border, 5}],
- wxSizer:add(RadioBoxSizer, RadioBox, Flags),
-
- wxSizer:add(VSizer, RadioBoxSizer, Flags),
+ BtnSizer = wxDialog:createButtonSizer(Dialog, ?wxOK bor ?wxCANCEL),
+ Dir = ?wxLEFT bor ?wxRIGHT bor ?wxDOWN,
+ Flags = [{flag, ?wxEXPAND bor Dir bor ?wxALIGN_CENTER_VERTICAL}, {border, 5}],
+ wxSizer:add(VSizer, RadioBox, Flags),
wxSizer:addSpacer(VSizer, 10),
- wxSizer:add(VSizer, NameText),
+ wxSizer:add(VSizer, NameText, [{flag, ?wxLEFT}, {border, 5}]),
wxSizer:add(VSizer, NameCtrl, Flags),
wxSizer:addSpacer(VSizer, 10),
- wxSizer:add(VSizer, CookieText),
+ wxSizer:add(VSizer, CookieText, [{flag, ?wxLEFT}, {border, 5}]),
wxSizer:add(VSizer, CookieCtrl, Flags),
wxSizer:addSpacer(VSizer, 10),
- wxSizer:add(VSizer, BtnSizer, [{flag, ?wxALIGN_LEFT}]),
+ wxSizer:add(VSizer, BtnSizer, [{proportion, 1}, {flag, ?wxEXPAND bor ?wxALL},{border, 5}]),
- wxWindow:setSizer(Dialog, VSizer),
+ wxWindow:setSizerAndFit(Dialog, VSizer),
+ wxSizer:setSizeHints(VSizer, Dialog),
CookiePath = filename:join(os:getenv("HOME"), ".erlang.cookie"),
DefaultCookie = case filelib:is_file(CookiePath) of
true ->
@@ -548,28 +543,36 @@ clean_menus(Menus, MenuBar) ->
remove_menu_items(Menus, MenuBar).
remove_menu_items([{MenuStr = "File", Menus}|Rest], MenuBar) ->
- MenuId = wxMenuBar:findMenu(MenuBar, MenuStr),
- Menu = wxMenuBar:getMenu(MenuBar, MenuId),
- Items = [wxMenu:findItem(Menu, Tag) || #create_menu{text=Tag} <- Menus],
- [wxMenu:delete(Menu, MItem) || MItem <- Items],
- case os:type() =:= {unix, darwin} of
- true ->
- wxMenuBar:remove(MenuBar, MenuId),
- wxMenu:destroy(Menu);
- false ->
- ignore
- end,
- remove_menu_items(Rest, MenuBar);
+ case wxMenuBar:findMenu(MenuBar, MenuStr) of
+ ?wxNOT_FOUND ->
+ remove_menu_items(Rest, MenuBar);
+ MenuId ->
+ Menu = wxMenuBar:getMenu(MenuBar, MenuId),
+ Items = [wxMenu:findItem(Menu, Tag) || #create_menu{text=Tag} <- Menus],
+ [wxMenu:delete(Menu, MItem) || MItem <- Items],
+ case os:type() =:= {unix, darwin} of
+ true ->
+ wxMenuBar:remove(MenuBar, MenuId),
+ wxMenu:destroy(Menu);
+ false ->
+ ignore
+ end,
+ remove_menu_items(Rest, MenuBar)
+ end;
remove_menu_items([{"Nodes", _}|_], _MB) ->
ok;
remove_menu_items([{Tag, _Menus}|Rest], MenuBar) ->
- MenuId = wxMenuBar:findMenu(MenuBar, Tag),
- Menu = wxMenuBar:getMenu(MenuBar, MenuId),
- wxMenuBar:remove(MenuBar, MenuId),
- Items = wxMenu:getMenuItems(Menu),
- [wxMenu:'Destroy'(Menu, Item) || Item <- Items],
- wxMenu:destroy(Menu),
- remove_menu_items(Rest, MenuBar);
+ case wxMenuBar:findMenu(MenuBar, Tag) of
+ ?wxNOT_FOUND ->
+ remove_menu_items(Rest, MenuBar);
+ MenuId ->
+ Menu = wxMenuBar:getMenu(MenuBar, MenuId),
+ wxMenuBar:remove(MenuBar, MenuId),
+ Items = wxMenu:getMenuItems(Menu),
+ [wxMenu:'Destroy'(Menu, Item) || Item <- Items],
+ wxMenu:destroy(Menu),
+ remove_menu_items(Rest, MenuBar)
+ end;
remove_menu_items([], _MB) ->
ok.
@@ -597,15 +600,22 @@ epmd_nodes(Names) ->
update_node_list(State = #state{menubar=MenuBar}) ->
{Nodes, NodesMenuItems} = get_nodes(),
- NodeMenuId = wxMenuBar:findMenu(MenuBar, "Nodes"),
- NodeMenu = wxMenuBar:getMenu(MenuBar, NodeMenuId),
- wx:foreach(fun(Item) -> wxMenu:'Destroy'(NodeMenu, Item) end,
- wxMenu:getMenuItems(NodeMenu)),
-
+ NodeMenu = case wxMenuBar:findMenu(MenuBar, "Nodes") of
+ ?wxNOT_FOUND ->
+ Menu = wxMenu:new(),
+ wxMenuBar:append(MenuBar, Menu, "Nodes"),
+ Menu;
+ NodeMenuId ->
+ Menu = wxMenuBar:getMenu(MenuBar, NodeMenuId),
+ wx:foreach(fun(Item) -> wxMenu:'Destroy'(Menu, Item) end,
+ wxMenu:getMenuItems(Menu)),
+ Menu
+ end,
+
Index = wx:foldl(fun(Record, Index) ->
observer_lib:create_menu_item(Record, NodeMenu, Index)
end, 0, NodesMenuItems),
-
+
Dist = case erlang:is_alive() of
true -> #create_menu{id = ?ID_PING, text = "Connect node"};
false -> #create_menu{id = ?ID_CONNECT, text = "Enable distribution"}
diff --git a/lib/observer/test/crashdump_viewer_SUITE.erl b/lib/observer/test/crashdump_viewer_SUITE.erl
index 6f882d0be9..4c04126d4f 100644
--- a/lib/observer/test/crashdump_viewer_SUITE.erl
+++ b/lib/observer/test/crashdump_viewer_SUITE.erl
@@ -34,6 +34,7 @@
-define(default_timeout, ?t:minutes(30)).
-define(sl_alloc_vsns,[r9b]).
+-define(failed_file,"failed-cases.txt").
init_per_testcase(_Case, Config) ->
DataDir = ?config(data_dir,Config),
@@ -42,9 +43,18 @@ init_per_testcase(_Case, Config) ->
catch crashdump_viewer:stop(),
Dog = ?t:timetrap(?default_timeout),
[{watchdog, Dog}|Config].
-end_per_testcase(_Case, Config) ->
+end_per_testcase(Case, Config) ->
Dog=?config(watchdog, Config),
?t:timetrap_cancel(Dog),
+ case ?config(tc_status,Config) of
+ ok ->
+ ok;
+ _Fail ->
+ File = filename:join(?config(data_dir,Config),?failed_file),
+ {ok,Fd}=file:open(File,[append]),
+ file:write(Fd,io_lib:format("~w.~n",[Case])),
+ file:close(Fd)
+ end,
ok.
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -67,15 +77,26 @@ init_per_suite(doc) ->
["Create a lot of crashdumps which can be used in the testcases below"];
init_per_suite(Config) when is_list(Config) ->
Dog = ?t:timetrap(?default_timeout),
+ delete_saved(Config),
application:start(inets), % will be using the http client later
httpc:set_options([{ipfamily,inet6fb4}]),
DataDir = ?config(data_dir,Config),
- Rels = [R || R <- [r13b,r14b], ?t:is_release_available(R)] ++ [current],
+ Rels = [R || R <- [r14b,r15b], ?t:is_release_available(R)] ++ [current],
io:format("Creating crash dumps for the following releases: ~p", [Rels]),
AllDumps = create_dumps(DataDir,Rels),
?t:timetrap_cancel(Dog),
[{dumps,AllDumps}|Config].
+delete_saved(Config) ->
+ DataDir = ?config(data_dir,Config),
+ file:delete(filename:join(DataDir,?failed_file)),
+ SaveDir = filename:join(DataDir,"save"),
+ Dumps = filelib:wildcard(filename:join(SaveDir,"*")),
+ lists:foreach(fun(F) -> file:delete(F) end, Dumps),
+ file:del_dir(SaveDir),
+ ok.
+
+
translate(suite) ->
[];
translate(doc) ->
@@ -196,6 +217,23 @@ end_per_suite(doc) ->
["Remove generated crashdumps"];
end_per_suite(Config) when is_list(Config) ->
Dumps = ?config(dumps,Config),
+ DataDir = ?config(data_dir,Config),
+ FailedFile = filename:join(DataDir,?failed_file),
+ case filelib:is_file(FailedFile) of
+ true ->
+ SaveDir = filename:join(DataDir,"save"),
+ file:make_dir(SaveDir),
+ file:copy(FailedFile,filename:join(SaveDir,?failed_file)),
+ lists:foreach(
+ fun(CD) ->
+ File = filename:basename(CD),
+ New = filename:join(SaveDir,File),
+ file:copy(CD,New)
+ end, Dumps);
+ false ->
+ ok
+ end,
+ file:delete(FailedFile),
lists:foreach(fun(CD) -> ok = file:delete(CD) end,Dumps),
lists:keydelete(dumps,1,Config).
@@ -388,7 +426,7 @@ special(Port,File) ->
%% I registered a process as aaaaaaaa in the full_dist dumps
%% to make sure it will be the first in the list when sorted
- %% on names. There are some special data here, s� I'll thoroughly
+ %% on names. There are some special data here, so I'll thoroughly
%% read the process details for this process. Other processes
%% are just briefly traversed.
{Pid,Rest1} = get_first_process(AllProcs),
@@ -568,11 +606,14 @@ expand_link(Html) ->
port_details(Port) ->
- Port1 = contents(Port,"port?port=Port<0.1>"),
- "#Port<0.1>" = title(Port1),
-
Port0 = contents(Port,"port?port=Port<0.0>"),
- "Could not find port: #Port<0.0>" = title(Port0).
+ Port1 = contents(Port,"port?port=Port<0.1>"),
+ case title(Port0) of
+ "#Port<0.0>" -> % R16 or later
+ "Could not find port: #Port<0.1>" = title(Port1);
+ "Could not find port: #Port<0.0>" -> % R15 or earlier
+ "#Port<0.1>" = title(Port1)
+ end.
is_truncated(File) ->
case filename:extension(filename:rootname(File)) of
@@ -691,6 +732,12 @@ dump_with_strange_module_name(DataDir,Rel,DumpName) ->
CD.
dump(Node,DataDir,Rel,DumpName) ->
+ case Rel of
+ _ when Rel<r15b, Rel=/=current ->
+ rpc:call(Node,os,putenv,["ERL_CRASH_DUMP_SECONDS","600"]);
+ _ ->
+ ok
+ end,
rpc:call(Node,erlang,halt,[DumpName]),
Crashdump0 = filename:join(filename:dirname(code:which(?t)),
"erl_crash_dump.n1"),
@@ -752,6 +799,7 @@ rel_opt(Rel) ->
r12b -> [{erl,[{release,"r12b_patched"}]}];
r13b -> [{erl,[{release,"r13b_patched"}]}];
r14b -> [{erl,[{release,"r14b_latest"}]}]; %naming convention changed
+ r15b -> [{erl,[{release,"r15b_latest"}]}];
current -> []
end.
@@ -764,7 +812,8 @@ dump_prefix(Rel) ->
r12b -> "r12b_dump.";
r13b -> "r13b_dump.";
r14b -> "r14b_dump.";
- current -> "r15b_dump."
+ r15b -> "r15b_dump.";
+ current -> "r16b_dump."
end.
compat_rel(Rel) ->
@@ -776,5 +825,6 @@ compat_rel(Rel) ->
r12b -> "+R12 ";
r13b -> "+R13 ";
r14b -> "+R14 ";
+ r15b -> "+R15 ";
current -> ""
end.
diff --git a/lib/odbc/aclocal.m4 b/lib/odbc/aclocal.m4
index b1cf1fe404..918e30a886 100644
--- a/lib/odbc/aclocal.m4
+++ b/lib/odbc/aclocal.m4
@@ -740,11 +740,16 @@ dnl Try to find POSIX threads
dnl The usual pthread lib...
AC_CHECK_LIB(pthread, pthread_create, THR_LIBS="-lpthread")
-dnl FreeBSD has pthreads in special c library, c_r...
+dnl Very old versions of FreeBSD have pthreads in special c library, c_r...
if test "x$THR_LIBS" = "x"; then
AC_CHECK_LIB(c_r, pthread_create, THR_LIBS="-lc_r")
fi
+dnl QNX has pthreads in standard C library
+ if test "x$THR_LIBS" = "x"; then
+ AC_CHECK_FUNC(pthread_create, THR_LIBS="none_needed")
+ fi
+
dnl On ofs1 the '-pthread' switch should be used
if test "x$THR_LIBS" = "x"; then
AC_MSG_CHECKING([if the '-pthread' switch can be used])
@@ -765,6 +770,9 @@ dnl On ofs1 the '-pthread' switch should be used
if test "x$THR_LIBS" != "x"; then
THR_DEFS="$THR_DEFS -D_THREAD_SAFE -D_REENTRANT -DPOSIX_THREADS"
THR_LIB_NAME=pthread
+ if test "x$THR_LIBS" = "xnone_needed"; then
+ THR_LIBS=
+ fi
case $host_os in
solaris*)
THR_DEFS="$THR_DEFS -D_POSIX_PTHREAD_SEMANTICS" ;;
@@ -1841,6 +1849,31 @@ case $erl_gethrvtime in
esac
])dnl
+dnl ----------------------------------------------------------------------
+dnl
+dnl LM_TRY_ENABLE_CFLAG
+dnl
+dnl
+dnl Tries a CFLAG and sees if it can be enabled without compiler errors
+dnl $1: textual cflag to add
+dnl $2: variable to store the modified CFLAG in
+dnl Usage example LM_TRY_ENABLE_CFLAG([-Werror=return-type], [CFLAGS])
+dnl
+dnl
+AC_DEFUN([LM_TRY_ENABLE_CFLAG], [
+ AC_MSG_CHECKING([if we can add $1 to $2 (via CFLAGS)])
+ saved_CFLAGS=$CFLAGS;
+ CFLAGS="$1 $$2";
+ AC_TRY_COMPILE([],[return 0;],can_enable_flag=true,can_enable_flag=false)
+ CFLAGS=$saved_CFLAGS;
+ if test "X$can_enable_flag" = "Xtrue"; then
+ AC_MSG_RESULT([yes])
+ AS_VAR_SET($2, "$1 $$2")
+ else
+ AC_MSG_RESULT([no])
+ fi
+])
+
dnl ERL_TRY_LINK_JAVA(CLASSES, FUNCTION-BODY
dnl [ACTION_IF_FOUND [, ACTION-IF-NOT-FOUND]])
dnl Freely inspired by AC_TRY_LINK. (Maybe better to create a
diff --git a/lib/odbc/c_src/Makefile.in b/lib/odbc/c_src/Makefile.in
index 026da39e6f..6572d28ee8 100644
--- a/lib/odbc/c_src/Makefile.in
+++ b/lib/odbc/c_src/Makefile.in
@@ -108,17 +108,17 @@ docs:
ifdef UNIX_TARGET
$(UNIX_TARGET): $(OBJ_DIR)/odbcserver.o
- $(CC) $(CFLAGS) -o $@ $(OBJ_DIR)/odbcserver.o $(LDFLAGS) $(LIBS)
+ $(V_CC) $(CFLAGS) -o $@ $(OBJ_DIR)/odbcserver.o $(LDFLAGS) $(LIBS)
endif
ifdef WIN32_TARGET
$(WIN32_TARGET): $(OBJ_DIR)/odbcserver.o
- $(LD) $(LDFLAGS) -o $@ $(OBJ_DIR)/odbcserver.o $(ENTRY_OBJ) \
+ $(V_LD) $(LDFLAGS) -o $@ $(OBJ_DIR)/odbcserver.o $(ENTRY_OBJ) \
$(LIBS) $(ENTRY_LDFLAGS)
endif
$(OBJ_DIR)/odbcserver.o: odbcserver.c
- $(CC) $(CFLAGS) $(INCLUDES) $(TARGET_FLAGS) -o $@ -c odbcserver.c
+ $(V_CC) $(CFLAGS) $(INCLUDES) $(TARGET_FLAGS) -o $@ -c odbcserver.c
# ----------------------------------------------------
# Release Target
diff --git a/lib/odbc/c_src/odbcserver.c b/lib/odbc/c_src/odbcserver.c
index 6d4460014f..4a7a5224e5 100644
--- a/lib/odbc/c_src/odbcserver.c
+++ b/lib/odbc/c_src/odbcserver.c
@@ -104,6 +104,7 @@
#ifdef UNIX
#include <unistd.h>
+#include <netinet/tcp.h>
#endif
#if defined WIN32
@@ -152,7 +153,7 @@ static db_result_msg db_describe_table(byte *sql, db_state *state);
/* ------------- Encode/decode functions -------- ------------------------*/
static db_result_msg encode_empty_message(void);
-static db_result_msg encode_error_message(char *reason);
+static db_result_msg encode_error_message(char *reason, char *errCode, SQLINTEGER nativeError);
static db_result_msg encode_atom_message(char *atom);
static db_result_msg encode_result(db_state *state);
static db_result_msg encode_result_set(SQLSMALLINT num_of_columns,
@@ -201,6 +202,7 @@ static byte *receive_msg(int socket);
static Boolean receive_msg_part(int socket, byte * buffer, size_t msg_len);
static Boolean send_msg_part(int socket, byte * buffer, size_t msg_len);
static void close_socket(int socket);
+static void tcp_nodelay(int sock);
#endif
static void clean_socket_lib(void);
@@ -228,7 +230,7 @@ static void init_param_statement(int cols,
static void map_dec_num_2_c_column(col_type *type, int precision,
int scale);
-static db_result_msg map_sql_2_c_column(db_column* column);
+static db_result_msg map_sql_2_c_column(db_column* column, db_state *state);
static param_array * bind_parameter_arrays(byte *buffer, int *index,
@@ -244,7 +246,7 @@ static db_result_msg retrive_scrollable_cursor_support_info(db_state
static int num_out_params(int num_of_params, param_array* params);
/* ------------- Error handling functions --------------------------------*/
-static diagnos get_diagnos(SQLSMALLINT handleType, SQLHANDLE handle);
+static diagnos get_diagnos(SQLSMALLINT handleType, SQLHANDLE handle, Boolean extendedErrors);
/* ------------- Boolean functions ---------------------------------------*/
@@ -347,7 +349,7 @@ DWORD WINAPI database_handler(const char *port)
byte *request_buffer = NULL;
db_state state =
{NULL, NULL, NULL, NULL, 0, {NULL, 0, 0},
- FALSE, FALSE, FALSE, FALSE, FALSE, FALSE};
+ FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE};
byte request_id;
#ifdef WIN32
SOCKET socket;
@@ -436,14 +438,16 @@ static db_result_msg db_connect(byte *args, db_state *state)
diagnos diagnos;
byte *connStrIn;
int erl_auto_commit_mode, erl_trace_driver,
- use_srollable_cursors, tuple_row_state, binary_strings;
+ use_srollable_cursors, tuple_row_state, binary_strings,
+ extended_errors;
erl_auto_commit_mode = args[0];
erl_trace_driver = args[1];
use_srollable_cursors = args[2];
tuple_row_state = args[3];
binary_strings = args[4];
- connStrIn = args + 5 * sizeof(byte);
+ extended_errors = args[5];
+ connStrIn = args + 6 * sizeof(byte);
if(tuple_row_state == ON) {
tuple_row(state) = TRUE;
@@ -463,6 +467,12 @@ static db_result_msg db_connect(byte *args, db_state *state)
use_srollable_cursors(state) = FALSE;
}
+ if(extended_errors == ON) {
+ extended_errors(state) = TRUE;
+ } else {
+ extended_errors(state) = FALSE;
+ }
+
init_driver(erl_auto_commit_mode, erl_trace_driver, state);
connlen = (SQLSMALLINT)strlen((const char*)connStrIn);
@@ -473,10 +483,10 @@ static db_result_msg db_connect(byte *args, db_state *state)
&stringlength2ptr, SQL_DRIVER_NOPROMPT);
if (!sql_success(result)) {
- diagnos = get_diagnos(SQL_HANDLE_DBC, connection_handle(state));
+ diagnos = get_diagnos(SQL_HANDLE_DBC, connection_handle(state), extended_errors(state));
strcat((char *)diagnos.error_msg,
" Connection to database failed.");
- msg = encode_error_message(diagnos.error_msg);
+ msg = encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError );
if(!sql_success(SQLFreeHandle(SQL_HANDLE_DBC,
connection_handle(state))))
@@ -507,8 +517,8 @@ static db_result_msg db_close_connection(db_state *state)
result = SQLDisconnect(connection_handle(state));
if (!sql_success(result)) {
- diagnos = get_diagnos(SQL_HANDLE_DBC, connection_handle(state));
- return encode_error_message(diagnos.error_msg);
+ diagnos = get_diagnos(SQL_HANDLE_DBC, connection_handle(state), extended_errors(state));
+ return encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError);
}
if(!sql_success(SQLFreeHandle(SQL_HANDLE_DBC,
@@ -534,8 +544,8 @@ static db_result_msg db_end_tran(byte compleationtype, db_state *state)
(SQLSMALLINT)compleationtype);
if (!sql_success(result)) {
- diagnos = get_diagnos(SQL_HANDLE_DBC, connection_handle(state));
- return encode_error_message(diagnos.error_msg);
+ diagnos = get_diagnos(SQL_HANDLE_DBC, connection_handle(state), extended_errors(state));
+ return encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError);
} else {
return encode_atom_message("ok");
}
@@ -570,7 +580,7 @@ static db_result_msg db_query(byte *sql, db_state *state)
/* SQL_SUCCESS_WITH_INFO at this point may indicate an error in user input. */
if (result != SQL_SUCCESS && result != SQL_NO_DATA_FOUND) {
- diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state));
+ diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state), extended_errors(state));
if(strcmp((char *)diagnos.sqlState, INFO) == 0) {
is_error[0] = 0;
strncat((char *)is_error, (char *)diagnos.error_msg,
@@ -581,12 +591,12 @@ static db_result_msg db_query(byte *sql, db_state *state)
it as we want a nice and clean Erlang API */
if((strcmp((char *)is_error, "error") == 0))
{
- msg = encode_error_message((char *)diagnos.error_msg);
+ msg = encode_error_message((char *)diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError);
clean_state(state);
return msg;
}
} else {
- msg = encode_error_message((char *)diagnos.error_msg);
+ msg = encode_error_message((char *)diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError);
clean_state(state);
return msg;
}
@@ -659,9 +669,9 @@ static db_result_msg db_select_count(byte *sql, db_state *state)
}
if(!sql_success(SQLExecDirect(statement_handle(state), sql, SQL_NTS))) {
- diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state));
+ diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state), extended_errors(state));
clean_state(state);
- return encode_error_message(diagnos.error_msg);
+ return encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError);
}
if(!sql_success(SQLNumResultCols(statement_handle(state),
@@ -801,13 +811,13 @@ static db_result_msg db_param_query(byte *buffer, db_state *state)
result = SQLExecDirect(statement_handle(state), sql, SQL_NTS);
if (!sql_success(result) || result == SQL_NO_DATA) {
- diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state));
+ diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state), extended_errors(state));
}
/* SQL_NO_DATA and SQLSTATE 00000 indicate success for
updates/deletes that affect no rows */
if(!sql_success(result) &&
!(result == SQL_NO_DATA && !strcmp((char *)diagnos.sqlState, INFO))) {
- msg = encode_error_message(diagnos.error_msg);
+ msg = encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError);
} else {
for (i = 0; i < param_status.params_processed; i++) {
switch (param_status.param_status_array[i]) {
@@ -821,8 +831,8 @@ static db_result_msg db_param_query(byte *buffer, db_state *state)
break;
default:
diagnos =
- get_diagnos(SQL_HANDLE_STMT, statement_handle(state));
- msg = encode_error_message(diagnos.error_msg);
+ get_diagnos(SQL_HANDLE_STMT, statement_handle(state), extended_errors(state));
+ msg = encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError);
i = param_status.params_processed;
break;
}
@@ -891,16 +901,16 @@ static db_result_msg db_describe_table(byte *sql, db_state *state)
DO_EXIT(EXIT_ALLOC);
if (!sql_success(SQLPrepare(statement_handle(state), sql, SQL_NTS))){
- diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state));
- msg = encode_error_message(diagnos.error_msg);
+ diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state), extended_errors(state));
+ msg = encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError);
clean_state(state);
return msg;
}
if(!sql_success(SQLNumResultCols(statement_handle(state),
&num_of_columns))) {
- diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state));
- msg = encode_error_message(diagnos.error_msg);
+ diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state), extended_errors(state));
+ msg = encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError);
clean_state(state);
return msg;
}
@@ -949,7 +959,7 @@ static db_result_msg encode_empty_message(void)
}
/* Description: Encode an error-message to send back to erlang*/
-static db_result_msg encode_error_message(char *reason)
+static db_result_msg encode_error_message(char *reason, char *errCode, SQLINTEGER nativeError )
{
int index;
db_result_msg msg;
@@ -958,6 +968,12 @@ static db_result_msg encode_error_message(char *reason)
ei_encode_version(NULL, &index);
ei_encode_tuple_header(NULL, &index, 2);
ei_encode_atom(NULL, &index, "error");
+ if (errCode)
+ {
+ ei_encode_tuple_header(NULL, &index, 3);
+ ei_encode_string(NULL, &index, errCode);
+ ei_encode_long(NULL, &index, nativeError);
+ }
ei_encode_string(NULL, &index, reason);
msg.length = index;
@@ -968,6 +984,12 @@ static db_result_msg encode_error_message(char *reason)
ei_encode_version((char *)msg.buffer, &index);
ei_encode_tuple_header((char *)msg.buffer, &index, 2);
ei_encode_atom((char *)msg.buffer, &index, "error");
+ if (errCode)
+ {
+ ei_encode_tuple_header((char *)msg.buffer, &index, 3);
+ ei_encode_string((char *)msg.buffer, &index, errCode);
+ ei_encode_long((char *)msg.buffer, &index, nativeError);
+ }
ei_encode_string((char *)msg.buffer, &index, reason);
return msg;
@@ -1011,8 +1033,8 @@ static db_result_msg encode_result(db_state *state)
if(!sql_success(SQLNumResultCols(statement_handle(state),
&num_of_columns))) {
- diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state));
- msg = encode_error_message(diagnos.error_msg);
+ diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state), extended_errors(state));
+ msg = encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError);
clean_state(state);
return msg;
}
@@ -1028,8 +1050,8 @@ static db_result_msg encode_result(db_state *state)
}
if(!sql_success(SQLRowCount(statement_handle(state), &RowCountPtr))) {
- diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state));
- msg = encode_error_message(diagnos.error_msg);
+ diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state), extended_errors(state));
+ msg = encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError);
clean_state(state);
return msg;
}
@@ -1237,7 +1259,7 @@ static db_result_msg encode_column_name_list(SQLSMALLINT num_of_columns,
(columns(state)[i]).type.sql = sql_type;
(columns(state)[i]).type.col_size = size;
- msg = map_sql_2_c_column(&columns(state)[i]);
+ msg = map_sql_2_c_column(&columns(state)[i], state);
if (msg.length > 0) {
return msg; /* An error has occurred */
} else {
@@ -1782,6 +1804,10 @@ static int connect_to_erlang(const char *port)
sin6.sin6_addr = in6addr_loopback;
if (connect(sock, (struct sockaddr*)&sin6, sizeof(sin6)) == 0) {
+ /* Enable TCP_NODELAY to disable Nagel's socket algorithm. (Removes ~40ms delay on Redhat ES 6). */
+ #ifdef UNIX
+ tcp_nodelay(sock);
+ #endif
return sock;
}
close_socket(sock);
@@ -1797,9 +1823,24 @@ static int connect_to_erlang(const char *port)
close_socket(sock);
DO_EXIT(EXIT_SOCKET_CONNECT);
}
+
+ /* Enable TCP_NODELAY to disable Nagel's socket algorithm. (Removes ~40ms delay on Redhat ES 6). */
+ #ifdef UNIX
+ tcp_nodelay(sock);
+ #endif
return sock;
}
+#ifdef UNIX
+static void tcp_nodelay(int sock)
+{
+ int flag = 1;
+ int result = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
+ if (result < 0) {
+ DO_EXIT(EXIT_SOCKET_CONNECT);
+ }
+}
+#endif
#ifdef WIN32
static void close_socket(SOCKET socket)
{
@@ -2325,7 +2366,7 @@ static void map_dec_num_2_c_column(col_type *type, int precision, int scale)
/* Description: Transform SQL columntype to C columntype. Returns a dummy
db_result_msg with length 0 on success and an errormessage otherwise.*/
-static db_result_msg map_sql_2_c_column(db_column* column)
+static db_result_msg map_sql_2_c_column(db_column* column, db_state *state)
{
db_result_msg msg;
@@ -2394,10 +2435,10 @@ static db_result_msg map_sql_2_c_column(db_column* column)
column -> type.strlen_or_indptr = (SQLLEN)NULL;
break;
case SQL_UNKNOWN_TYPE:
- msg = encode_error_message("Unknown column type");
+ msg = encode_error_message("Unknown column type", extended_error(state, ""), 0);
break;
default:
- msg = encode_error_message("Column type not supported");
+ msg = encode_error_message("Column type not supported", extended_error(state, ""), 0);
break;
}
return msg;
@@ -2506,7 +2547,7 @@ static db_column retrive_binary_data(db_column column, int column_nr,
while (result == SQL_SUCCESS_WITH_INFO) {
- diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state));
+ diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state), extended_errors(state));
if(strcmp((char *)diagnos.sqlState, TRUNCATED) == 0) {
outputlen = column.type.len - 1;
@@ -2593,10 +2634,10 @@ static db_result_msg more_result_sets(db_state *state)
/* As we found an error we do not care about any potential more result
sets */
exists_more_result_sets(state) = FALSE;
- diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state));
+ diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state), extended_errors(state));
strcat((char *)diagnos.error_msg,
"Failed to create on of the result sets");
- msg = encode_error_message(diagnos.error_msg);
+ msg = encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError);
return msg;
}
}
@@ -2613,7 +2654,7 @@ static Boolean sql_success(SQLRETURN result)
diagnostic records scaning for error messages and the sqlstate.
If this function is called when no error has ocurred only the sqlState
field may be referenced.*/
-static diagnos get_diagnos(SQLSMALLINT handleType, SQLHANDLE handle)
+static diagnos get_diagnos(SQLSMALLINT handleType, SQLHANDLE handle, Boolean extendedErrors)
{
diagnos diagnos;
SQLINTEGER nativeError;
@@ -2637,17 +2678,16 @@ static diagnos get_diagnos(SQLSMALLINT handleType, SQLHANDLE handle)
result = SQLGetDiagRec(handleType, handle, record_nr, current_sql_state,
&nativeError, current_errmsg_pos,
(SQLSMALLINT)errmsg_buffer_size, &errmsg_size);
- if(result != SQL_SUCCESS && result != SQL_NO_DATA) {
-
-
- break;
- } else {
+ if(result == SQL_SUCCESS) {
/* update the sqlstate in the diagnos record, because the SQLGetDiagRec
call succeeded */
memcpy(diagnos.sqlState, current_sql_state, SQL_STATE_SIZE);
+ diagnos.nativeError = nativeError;
errmsg_buffer_size = errmsg_buffer_size - errmsg_size;
acc_errmsg_size = acc_errmsg_size + errmsg_size;
current_errmsg_pos = current_errmsg_pos + errmsg_size;
+ } else {
+ break;
}
}
@@ -2655,7 +2695,7 @@ static diagnos get_diagnos(SQLSMALLINT handleType, SQLHANDLE handle)
strcat((char *)diagnos.error_msg,
"No SQL-driver information available.");
}
- else {
+ else if (!extendedErrors){
strcat(strcat((char *)diagnos.error_msg, " SQLSTATE IS: "),
(char *)diagnos.sqlState);
}
diff --git a/lib/odbc/c_src/odbcserver.h b/lib/odbc/c_src/odbcserver.h
index a76cedf1af..71760189e7 100644
--- a/lib/odbc/c_src/odbcserver.h
+++ b/lib/odbc/c_src/odbcserver.h
@@ -145,6 +145,7 @@ typedef struct {
typedef struct {
SQLCHAR sqlState[SQL_STATE_SIZE];
+ SQLINTEGER nativeError;
byte error_msg[MAX_ERR_MSG];
} diagnos;
@@ -179,6 +180,7 @@ typedef struct {
Boolean exists_more_result_sets;
Boolean param_query;
Boolean out_params;
+ Boolean extended_errors;
} db_state;
typedef enum {
@@ -198,3 +200,5 @@ typedef enum {
#define exists_more_result_sets(db_state) (db_state -> exists_more_result_sets)
#define param_query(db_state) (db_state -> param_query)
#define out_params(db_state) (db_state -> out_params)
+#define extended_errors(db_state) (db_state -> extended_errors)
+#define extended_error(db_state, errorcode) ( extended_errors(state) ? errorcode : NULL )
diff --git a/lib/odbc/configure.in b/lib/odbc/configure.in
index bec65c71bf..e6ba9f57f5 100644
--- a/lib/odbc/configure.in
+++ b/lib/odbc/configure.in
@@ -212,4 +212,9 @@ AC_SUBST(ODBC_INCLUDE)
fi dnl "$with_odbc" != "no"
+if test "x$GCC" = xyes; then
+ # Treat certain GCC warnings as errors
+ LM_TRY_ENABLE_CFLAG([-Werror=return-type], [CFLAGS])
+fi
+
AC_OUTPUT(c_src/$host/Makefile:c_src/Makefile.in)
diff --git a/lib/odbc/doc/src/notes.xml b/lib/odbc/doc/src/notes.xml
index 5f6cf91961..7ba0307a45 100644
--- a/lib/odbc/doc/src/notes.xml
+++ b/lib/odbc/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2011</year>
+ <year>2004</year><year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/odbc/doc/src/odbc.xml b/lib/odbc/doc/src/odbc.xml
index 8a58dc2848..a984bf4485 100644
--- a/lib/odbc/doc/src/odbc.xml
+++ b/lib/odbc/doc/src/odbc.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1999</year><year>2011</year>
+ <year>1999</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -74,8 +74,12 @@
<code type="none">
milliseconds() = integer() >= 0 </code>
<code type="none">
- common_reason() = connection_closed | term() - some kind of
- explanation of what went wrong </code>
+ common_reason() = connection_closed | extended_error() | term() - some kind of
+ explanation of what went wrong </code>
+ <code type="none">
+ extended_error() = {string(), integer(), Reason} - extended error type with ODBC
+ and native database error codes, as well as the base reason that would have been
+ returned had extended_errors not been enabled. </code>
<code type="none">
string() = list of ASCII characters </code>
<code type="none">
@@ -101,8 +105,14 @@
odbc_data_type() = sql_integer | sql_smallint | sql_tinyint |
{sql_decimal, precision(), scale()} |
{sql_numeric, precision(), scale()} |
- {sql_char, size()} | {sql_wchar, size()} | {sql_varchar, size()} | {sql_wvarchar, size()}| {sql_float, precision()} |
- {sql_wlongvarchar, size()} | {sql_float, precision()} | sql_real | sql_double | sql_bit | atom()
+ {sql_char, size()} |
+ {sql_wchar, size()} |
+ {sql_varchar, size()} |
+ {sql_wvarchar, size()}|
+ {sql_float, precision()} |
+ {sql_wlongvarchar, size()} |
+ {sql_float, precision()} |
+ sql_real | sql_double | sql_bit | atom()
</code>
<code type="none">
precision() = integer() </code>
@@ -143,7 +153,7 @@
<d>All options has default values. </d>
<v>option() = {auto_commit, on | off} | {timeout, milliseconds()}
| {binary_strings, on | off} | {tuple_row, on | off} | {scrollable_cursors, on | off} |
- {trace_driver, on | off} </v>
+ {trace_driver, on | off} | {extended_errors, on | off} </v>
<v>Ref = connection_reference() - should be used to access the connection. </v>
<v>Reason = port_program_executable_not_found | common_reason()</v>
</type>
@@ -196,6 +206,19 @@
<p>For more information about the <c>ConnectStr</c> see
description of the function SQLDriverConnect in [1].</p>
</note>
+
+ <p>The <c>extended_errors</c> option enables extended ODBC error
+ information when an operation fails. Rather than returning <c>{error, Reason}</c>,
+ the failing function will reutrn <c>{error, {ODBCErrorCode, NativeErrorCode, Reason}}</c>.
+ Note that this information is probably of little use when writing database-independent code,
+ but can be of assistance in providing more sophisticated error handling when dealing with
+ a known underlying database.
+ <list type="bulleted">
+ <item><c>ODBCErrorCode</c> is the ODBC error string returned by the ODBC driver.</item>
+ <item><c>NativeErrorCode</c> is the numberic error code returned by the underlying database. The possible values
+ and their meanings are dependent on the database being used.</item>
+ <item><c>Reason</c> is as per the <c>Reason</c> field when extended errors are not enabled.</item>
+ </list></p>
</desc>
</func>
<func>
@@ -203,7 +226,7 @@
<fsummary>Closes a connection to a database. </fsummary>
<type>
<v>Ref = connection_reference()</v>
- <v>Reason = process_not_owner_of_odbc_connection</v>
+ <v>Reason = process_not_owner_of_odbc_connection | extended_error()</v>
</type>
<desc>
<p>Closes a connection to a database. This will also
diff --git a/lib/odbc/src/Makefile b/lib/odbc/src/Makefile
index 2af65cc757..bfbda8aaf4 100644
--- a/lib/odbc/src/Makefile
+++ b/lib/odbc/src/Makefile
@@ -95,9 +95,9 @@ clean:
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
docs:
diff --git a/lib/odbc/src/odbc.erl b/lib/odbc/src/odbc.erl
index 16fdb4aabd..3eabec9ec3 100644
--- a/lib/odbc/src/odbc.erl
+++ b/lib/odbc/src/odbc.erl
@@ -810,10 +810,11 @@ connect(ConnectionReferense, ConnectionStr, Options) ->
{C_TupleRow, _} =
connection_config(tuple_row, Options),
{BinaryStrings, _} = connection_config(binary_strings, Options),
+ {ExtendedErrors, _} = connection_config(extended_errors, Options),
ODBCCmd =
[?OPEN_CONNECTION, C_AutoCommitMode, C_TraceDriver,
- C_SrollableCursors, C_TupleRow, BinaryStrings, ConnectionStr],
+ C_SrollableCursors, C_TupleRow, BinaryStrings, ExtendedErrors, ConnectionStr],
%% Send request, to open a database connection, to the control process.
case call(ConnectionReferense,
@@ -860,6 +861,8 @@ connection_default(trace_driver) ->
connection_default(scrollable_cursors) ->
{?ON, on};
connection_default(binary_strings) ->
+ {?OFF, off};
+connection_default(extended_errors) ->
{?OFF, off}.
%%-------------------------------------------------------------------------
diff --git a/lib/odbc/test/odbc_connect_SUITE.erl b/lib/odbc/test/odbc_connect_SUITE.erl
index a076c4dfff..7d732f20f7 100644
--- a/lib/odbc/test/odbc_connect_SUITE.erl
+++ b/lib/odbc/test/odbc_connect_SUITE.erl
@@ -51,7 +51,7 @@ all() ->
{group, client_dies}, connect_timeout, timeout,
many_timeouts, timeout_reset, disconnect_on_timeout,
connection_closed, disable_scrollable_cursors,
- return_rows_as_lists, api_missuse];
+ return_rows_as_lists, api_missuse, extended_errors];
Other -> {skip, Other}
end.
@@ -838,3 +838,33 @@ transaction_support_str(mysql) ->
"ENGINE = InnoDB";
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(Config) when is_list(Config)->
+ Table = ?config(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))"),
+
+ % Error case WITHOUT extended errors on...
+ case odbc:sql_query(Ref, "create table " ++ Table ++" ( id integer, data varchar(10))") of
+ {error, ErrorString} when is_list(ErrorString) -> ok
+ end,
+
+ % Now the test case with extended errors on - This should return a tuple, not a list/string now.
+ % The first element is a string that is the ODBC error string; the 2nd element is a native integer error
+ % code passed from the underlying provider driver. The last is the familiar old error string.
+ % We can't check the actual error code; as each different underlying provider will return
+ % a different value - So we just check the return types at least.
+ {ok, RefExtended} = odbc:connect(?RDBMS:connection_string(), odbc_test_lib:platform_options() ++ [{extended_errors, on}]),
+ case odbc:sql_query(RefExtended, "create table " ++ Table ++" ( id integer, data varchar(10))") of
+ {error, {ODBCCodeString, NativeCodeNum, ShortErrorString}} when is_list(ODBCCodeString), is_number(NativeCodeNum), is_list(ShortErrorString) -> ok
+ end,
+
+ ok = odbc:disconnect(Ref),
+ ok = odbc:disconnect(RefExtended).
diff --git a/lib/odbc/test/odbc_data_type_SUITE.erl b/lib/odbc/test/odbc_data_type_SUITE.erl
index d61a91f973..2d33546622 100644
--- a/lib/odbc/test/odbc_data_type_SUITE.erl
+++ b/lib/odbc/test/odbc_data_type_SUITE.erl
@@ -1,7 +1,8 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -1469,7 +1470,7 @@ utf8(Config) when is_list(Config) ->
odbc:sql_query(Ref, "CREATE TABLE " ++ Table ++ "(FIELD text)"),
- Latin1Data = ["���������",
+ Latin1Data = ["ÖÄÅÄÖÅäöå",
"testasdf",
"Row 3",
"Row 4",
@@ -1564,7 +1565,7 @@ timestamp(Config) when is_list(Config) ->
%%------------------------------------------------------------------------
w_char_support(Ref, Table, CharType, Size) ->
- Latin1Data = ["���������",
+ Latin1Data = ["ÖÄÅÄÖÅäöå",
"testasdf",
"Row 3",
"Row 4",
diff --git a/lib/odbc/vsn.mk b/lib/odbc/vsn.mk
index 3bb2fe5bce..585b92b2d2 100644
--- a/lib/odbc/vsn.mk
+++ b/lib/odbc/vsn.mk
@@ -1 +1 @@
-ODBC_VSN = 2.10.13
+ODBC_VSN = 2.10.14
diff --git a/lib/orber/COSS/CosNaming/Makefile b/lib/orber/COSS/CosNaming/Makefile
index 769c08a9e9..814062034c 100644
--- a/lib/orber/COSS/CosNaming/Makefile
+++ b/lib/orber/COSS/CosNaming/Makefile
@@ -117,7 +117,7 @@ clean:
rm -f errs core *~
$(APP_TARGET): $(APP_SRC)
- sed -e 's;%VSN%;$(VSN);' $(APP_SRC) > $(APP_TARGET)
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $(APP_SRC) > $(APP_TARGET)
docs:
@@ -125,10 +125,10 @@ docs:
# Special Build Targets
# ----------------------------------------------------
IDL-GENERATED: cos_naming_ext.idl cos_naming.idl
- erlc $(ERL_IDL_FLAGS) +'{this,"CosNaming::NamingContext"}' \
+ $(gen_verbose)erlc $(ERL_IDL_FLAGS) +'{this,"CosNaming::NamingContext"}' \
+'{this,"CosNaming::NamingContextExt"}' cos_naming_ext.idl
- erlc $(ERL_IDL_FLAGS) +'{this,"CosNaming::NamingContext"}' cos_naming.idl
- >IDL-GENERATED
+ $(V_at)erlc $(ERL_IDL_FLAGS) +'{this,"CosNaming::NamingContext"}' cos_naming.idl
+ $(V_at)>IDL-GENERATED
$(GEN_FILES): IDL-GENERATED
diff --git a/lib/orber/c_src/Makefile.in b/lib/orber/c_src/Makefile.in
index 9970642a9f..126ed8af21 100644
--- a/lib/orber/c_src/Makefile.in
+++ b/lib/orber/c_src/Makefile.in
@@ -56,10 +56,10 @@ debug opt: $(OBJDIR) orber
ifeq ($(findstring win32,$(TARGET)),win32)
orber:
- echo "Nothing to build on NT"
+ $(V_colon)echo "Nothing to build on NT"
else
orber:
- echo "Nothing to build"
+ $(V_colon)echo "Nothing to build"
endif
clean:
@@ -74,7 +74,7 @@ $(OBJDIR):
-mkdir -p $(OBJDIR)
$(OBJDIR)/%.o: %.c
- $(CC) -c -o $@ $(ALL_CFLAGS) $<
+ $(V_CC) -c -o $@ $(ALL_CFLAGS) $<
# ----------------------------------------------------
# Release Target
diff --git a/lib/orber/doc/src/ch_idl_to_erlang_mapping.xml b/lib/orber/doc/src/ch_idl_to_erlang_mapping.xml
index 964ae3e92d..1fd2f644cb 100644
--- a/lib/orber/doc/src/ch_idl_to_erlang_mapping.xml
+++ b/lib/orber/doc/src/ch_idl_to_erlang_mapping.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2010</year>
+ <year>1997</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -1142,7 +1142,8 @@ handle_info(_Info, State) ->
module, and <c>lookup</c> in <c>DB_Administrator_impl.erl</c><em>and</em><c>DB_CommonUser_impl.erl</c>. But wait, is that really necessary? Actually,
it is not. We simple use the IC compile option <em>impl</em>:</p>
<pre>
-$ <input>erlc +'{{impl, "DB::CommonUser"}, "DBUser_impl"}' +'{{impl, "DB::Administrator"}, "DBUser_impl"}' DB.idl</input>
+$ <input>erlc +'{{impl, "DB::CommonUser"}, "DBUser_impl"}'\
+ +'{{impl, "DB::Administrator"}, "DBUser_impl"}' DB.idl</input>
$ <input>erlc *.erl</input>
</pre>
<p>Instead of creating, and not the least, maintaining two call-back modules,
diff --git a/lib/orber/examples/Stack/Makefile b/lib/orber/examples/Stack/Makefile
index f1a5106a7b..1cbb983cd6 100644
--- a/lib/orber/examples/Stack/Makefile
+++ b/lib/orber/examples/Stack/Makefile
@@ -104,8 +104,8 @@ docs:
test: $(TEST_TARGET_FILES)
IDL-GENERATED: stack.idl
- erlc $(ERL_IDL_FLAGS) stack.idl
- >IDL-GENERATED
+ $(gen_verbose)erlc $(ERL_IDL_FLAGS) stack.idl
+ $(V_at)>IDL-GENERATED
$(GEN_FILES): IDL-GENERATED
diff --git a/lib/orber/src/Makefile b/lib/orber/src/Makefile
index 72610def2b..1c6781e5fd 100644
--- a/lib/orber/src/Makefile
+++ b/lib/orber/src/Makefile
@@ -200,8 +200,7 @@ ERL_COMPILE_FLAGS += $(ERL_IDL_FLAGS) \
+'{attribute,insert,app_vsn,"orber_$(ORBER_VSN)"}' \
-D'ORBVSN="$(ORBER_VSN)"'
-ASN_FLAGS = -bber_bin +der +compact_bit_string +optimize \
- +nowarn_unused_record
+ASN_FLAGS = -bber +der +compact_bit_string +nowarn_unused_record
# ----------------------------------------------------
# Targets
@@ -216,10 +215,10 @@ clean:
rm -f errs core *~
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(ORBER_VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(ORBER_VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(ORBER_VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(ORBER_VSN);' $< > $@
docs:
@@ -228,17 +227,17 @@ docs:
# ----------------------------------------------------
IDL-GENERATED: $(ERL_TOP)/lib/ic/include/erlang.idl CORBA.idl OrberIFR.idl
- erlc $(ERL_IDL_FLAGS) $(ERL_TOP)/lib/ic/include/erlang.idl
- erlc $(ERL_IDL_FLAGS) CORBA.idl
- erlc $(ERL_IDL_FLAGS) +'{this,"Orber::IFR"}' OrberIFR.idl
- >IDL-GENERATED
+ $(gen_verbose)erlc $(ERL_IDL_FLAGS) $(ERL_TOP)/lib/ic/include/erlang.idl
+ $(V_at)erlc $(ERL_IDL_FLAGS) CORBA.idl
+ $(V_at)erlc $(ERL_IDL_FLAGS) +'{this,"Orber::IFR"}' OrberIFR.idl
+ $(V_at)>IDL-GENERATED
$(GEN_ERL_FILES): IDL-GENERATED
$(TARGET_FILES): IDL-GENERATED
$(GEN_ASN_ERL) $(GEN_ASN_HRL): OrberCSIv2.asn1 OrberCSIv2.set.asn
- erlc $(ERL_COMPILE_FLAGS) $(ASN_FLAGS) +'{inline,"OrberCSIv2"}' OrberCSIv2.set.asn
- rm -f $(GEN_ASN_ERL:%.erl=%.beam)
+ $(asn_verbose)erlc $(ERL_COMPILE_FLAGS) $(ASN_FLAGS) +'{inline,"OrberCSIv2"}' OrberCSIv2.set.asn
+ $(V_at)rm -f $(GEN_ASN_ERL:%.erl=%.beam)
# erlc $(ERL_COMPILE_FLAGS) $(ASN_FLAGS) OrberCSIv2.asn1 ;\
# erlc $(GEN_ASN_ERL)
diff --git a/lib/orber/src/orber_iiop_net.erl b/lib/orber/src/orber_iiop_net.erl
index 2eed0b538a..33e02e3c04 100644
--- a/lib/orber/src/orber_iiop_net.erl
+++ b/lib/orber/src/orber_iiop_net.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -415,11 +415,10 @@ handle_info({'EXIT', Pid, _Reason}, State) when is_pid(Pid) ->
ref = Ref, options = Options, proxy_options = POpts}] ->
ets:delete(?CONNECTION_DB, Pid),
unlink(Pid),
- NewListen = new_listen_socket(Type, Listen, Port, Options),
- {ok, NewPid} = orber_iiop_socketsup:start_accept(Type, NewListen,
+ {ok, NewPid} = orber_iiop_socketsup:start_accept(Type, Listen,
Ref, POpts),
link(NewPid),
- ets:insert(?CONNECTION_DB, #listen{pid = NewPid, socket = NewListen,
+ ets:insert(?CONNECTION_DB, #listen{pid = NewPid, socket = Listen,
port = Port, type = Type,
ref = Ref, options = Options,
proxy_options = POpts}),
@@ -445,23 +444,6 @@ handle_info({'EXIT', Pid, _Reason}, State) when is_pid(Pid) ->
handle_info(_, State) ->
{noreply, State}.
-new_listen_socket(normal, ListenFd, _Port, _Options) ->
- ListenFd;
-new_listen_socket(ssl, ListenFd, Port, Options) ->
- Generation = orber_env:ssl_generation(),
- if
- Generation > 2 ->
- ListenFd;
- true ->
- case is_process_alive(ssl:pid(ListenFd)) of
- true ->
- ListenFd;
- _ ->
- {ok, Listen, _NP} = orber_socket:listen(ssl, Port, Options, true),
- Listen
- end
- end.
-
from_list(List) ->
from_list(List, queue:new()).
diff --git a/lib/os_mon/c_src/Makefile.in b/lib/os_mon/c_src/Makefile.in
index e728e43a09..51569f6ec9 100644
--- a/lib/os_mon/c_src/Makefile.in
+++ b/lib/os_mon/c_src/Makefile.in
@@ -93,28 +93,28 @@ docs:
# ----------------------------------------------------
$(BINDIR)/win32sysinfo.exe: $(OBJDIR)/win32sysinfo.o $(ENTRY_OBJ)
- $(LD) $(LDFLAGS) $(ENTRY_LDFLAGS) -o $@ $(OBJDIR)/win32sysinfo.o $(ENTRY_OBJ)
+ $(V_LD) $(LDFLAGS) $(ENTRY_LDFLAGS) -o $@ $(OBJDIR)/win32sysinfo.o $(ENTRY_OBJ)
$(BINDIR)/nteventlog.exe: $(EVLOG_OBJECTS)
- $(LD) $(LDFLAGS) $(ENTRY_LDFLAGS) -o $@ $(EVLOG_OBJECTS) $(ENTRY_OBJ)
+ $(V_LD) $(LDFLAGS) $(ENTRY_LDFLAGS) -o $@ $(EVLOG_OBJECTS) $(ENTRY_OBJ)
$(BINDIR)/ferrule: $(OBJDIR)/ferrule.o
- $(LD) $(LDFLAGS) -o $@ $<
+ $(V_LD) $(LDFLAGS) -o $@ $<
$(BINDIR)/mod_syslog: $(OBJDIR)/mod_syslog.o
- $(LD) $(LDFLAGS) -o $@ $<
+ $(V_LD) $(LDFLAGS) -o $@ $<
$(BINDIR)/memsup: $(OBJDIR)/memsup.o
- $(LD) $(LDFLAGS) -o $@ $<
+ $(V_LD) $(LDFLAGS) -o $@ $<
$(BINDIR)/cpu_sup: $(OBJDIR)/cpu_sup.o
- $(LD) $(LDFLAGS) -o $@ $< $(CPU_SUP_LIBS)
+ $(V_LD) $(LDFLAGS) -o $@ $< $(CPU_SUP_LIBS)
$(OBJDIR)/%.o: %.c
- $(CC) -c -o $@ $(ALL_CFLAGS) $<
+ $(V_CC) -c -o $@ $(ALL_CFLAGS) $<
$(OBJDIR)/%.o: nteventlog/%.c
- $(CC) -c -o $@ $(ALL_CFLAGS) $<
+ $(V_CC) -c -o $@ $(ALL_CFLAGS) $<
$(OBJDIR)/memsup.o: memsup.h
diff --git a/lib/os_mon/mibs/Makefile b/lib/os_mon/mibs/Makefile
index 3e24c3d373..19f3dc8367 100644
--- a/lib/os_mon/mibs/Makefile
+++ b/lib/os_mon/mibs/Makefile
@@ -67,16 +67,16 @@ OTP_MIBDIR = $(shell if test -d ../../otp_mibs; then echo otp_mibs; \
else echo sasl; fi)
$(SNMP_BIN_TARGET_DIR)/OTP-REG.bin: $(ERL_TOP)/lib/$(OTP_MIBDIR)/mibs/OTP-REG.mib
- $(ERLC) -pa $(SNMP_TOOLKIT)/ebin -I $(SNMP_TOOLKIT)/priv/mibs $(SNMP_FLAGS) -o $(SNMP_BIN_TARGET_DIR) $<
+ $(snmp_verbose)$(ERLC) -pa $(SNMP_TOOLKIT)/ebin -I $(SNMP_TOOLKIT)/priv/mibs $(SNMP_FLAGS) -o $(SNMP_BIN_TARGET_DIR) $<
$(SNMP_BIN_TARGET_DIR)/OTP-TC.bin: $(ERL_TOP)/lib/$(OTP_MIBDIR)/mibs/OTP-TC.mib
- $(ERLC) -pa $(SNMP_TOOLKIT)/ebin -I $(SNMP_TOOLKIT)/priv/mibs $(SNMP_FLAGS) -o $(SNMP_BIN_TARGET_DIR) $<
+ $(snmp_verbose)$(ERLC) -pa $(SNMP_TOOLKIT)/ebin -I $(SNMP_TOOLKIT)/priv/mibs $(SNMP_FLAGS) -o $(SNMP_BIN_TARGET_DIR) $<
$(SNMP_BIN_TARGET_DIR)/OTP-MIB.bin: $(ERL_TOP)/lib/$(OTP_MIBDIR)/mibs/OTP-MIB.mib
- $(ERLC) -pa $(SNMP_TOOLKIT)/ebin -I $(SNMP_TOOLKIT)/priv/mibs $(SNMP_FLAGS) -o $(SNMP_BIN_TARGET_DIR) $<
+ $(snmp_verbose)$(ERLC) -pa $(SNMP_TOOLKIT)/ebin -I $(SNMP_TOOLKIT)/priv/mibs $(SNMP_FLAGS) -o $(SNMP_BIN_TARGET_DIR) $<
v1/%.mib.v1: %.mib
- $(ERL_TOP)/lib/snmp/bin/snmp-v2tov1 -o $@ $<
+ $(gen_verbose)$(ERL_TOP)/lib/snmp/bin/snmp-v2tov1 -o $@ $<
$(SNMP_BIN_TARGET_DIR)/OTP-OS-MON-MIB.bin: \
$(SNMP_BIN_TARGET_DIR)/OTP-REG.bin \
diff --git a/lib/os_mon/src/Makefile b/lib/os_mon/src/Makefile
index 864d7a09d4..9fc888e552 100644
--- a/lib/os_mon/src/Makefile
+++ b/lib/os_mon/src/Makefile
@@ -78,10 +78,10 @@ docs:
# ----------------------------------------------------
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
#-------------------------------------------------------
# Special dependencies
diff --git a/lib/os_mon/src/os_mon.erl b/lib/os_mon/src/os_mon.erl
index df1eccb064..19acae9f0e 100644
--- a/lib/os_mon/src/os_mon.erl
+++ b/lib/os_mon/src/os_mon.erl
@@ -176,9 +176,7 @@ services({unix, sunos}) ->
services({unix, _}) -> % Other unix.
[cpu_sup, disksup, memsup];
services({win32, _}) ->
- [disksup, memsup, os_sup, sysinfo];
-services(_) ->
- [].
+ [disksup, memsup, os_sup, sysinfo].
server_name(cpu_sup) -> cpu_sup;
server_name(disksup) -> disksup;
diff --git a/lib/otp_mibs/mibs/Makefile b/lib/otp_mibs/mibs/Makefile
index 703c4b3ed4..7f43ef31a6 100644
--- a/lib/otp_mibs/mibs/Makefile
+++ b/lib/otp_mibs/mibs/Makefile
@@ -68,7 +68,7 @@ docs:
# ----------------------------------------------------
v1/%.mib.v1: %.mib
- $(ERL_TOP)/lib/snmp/bin/snmp-v2tov1 -o $@ $<
+ $(gen_verbose)$(ERL_TOP)/lib/snmp/bin/snmp-v2tov1 -o $@ $<
# ----------------------------------------------------
# Release Target
diff --git a/lib/otp_mibs/src/Makefile b/lib/otp_mibs/src/Makefile
index 03298d39d5..4f03d0228a 100644
--- a/lib/otp_mibs/src/Makefile
+++ b/lib/otp_mibs/src/Makefile
@@ -84,10 +84,10 @@ docs:
# ----------------------------------------------------
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
# ----------------------------------------------------
# Release Target
diff --git a/lib/parsetools/include/yeccpre.hrl b/lib/parsetools/include/yeccpre.hrl
index 3672394fc5..e4c3ba52be 100644
--- a/lib/parsetools/include/yeccpre.hrl
+++ b/lib/parsetools/include/yeccpre.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -36,7 +36,7 @@ parse_and_scan({M, F, A}) ->
-spec format_error(any()) -> [char() | list()].
format_error(Message) ->
- case io_lib:deep_char_list(Message) of
+ case io_lib:deep_unicode_char_list(Message) of
true ->
Message;
_ ->
@@ -164,7 +164,7 @@ yecctoken_location(Token) ->
yecctoken2string({atom, _, A}) -> io_lib:write(A);
yecctoken2string({integer,_,N}) -> io_lib:write(N);
yecctoken2string({float,_,F}) -> io_lib:write(F);
-yecctoken2string({char,_,C}) -> io_lib:write_char(C);
+yecctoken2string({char,_,C}) -> io_lib:write_unicode_char(C);
yecctoken2string({var,_,V}) -> io_lib:format("~s", [V]);
yecctoken2string({string,_,S}) -> io_lib:write_unicode_string(S);
yecctoken2string({reserved_symbol, _, A}) -> io_lib:write(A);
diff --git a/lib/parsetools/src/Makefile b/lib/parsetools/src/Makefile
index 4f199da8ee..7b63475231 100644
--- a/lib/parsetools/src/Makefile
+++ b/lib/parsetools/src/Makefile
@@ -78,10 +78,10 @@ docs:
# ----------------------------------------------------
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
# ----------------------------------------------------
# Release Target
diff --git a/lib/parsetools/src/esyntax.yrl b/lib/parsetools/src/esyntax.yrl
deleted file mode 100644
index 1ecb54f0a7..0000000000
--- a/lib/parsetools/src/esyntax.yrl
+++ /dev/null
@@ -1,360 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-Nonterminals
-add_op attribute basic_type bif_test
-case_expr clause_body
-clause_guard clause_head comp_op cr_clause cr_clauses expr expr_tail
-exprs farity farity_list form formal_parameter_list function
-function_call function_clause guard guard_call guard_expr
-guard_expr_list guard_exprs guard_expr_tail guard_expr_tuple
-guard_parameter_list
-guard_tests guard_test if_clause if_clauses if_expr list match_expr
-mult_op parameter_list pattern patterns pattern_list pattern_tail pattern_tuple
-prefix_op receive_expr send_expr tuple.
-
-Terminals
-'!' '(' ')' '*' '+' ',' '-' '->' '/' '/=' ':' ';' '<' '=' '=/=' '=:='
-'=<' '==' '>' '>=' '[' ']' 'after' 'band' 'begin' 'bnot'
-'bor' 'bsl' 'bsr' 'bxor' 'case' 'catch' 'div' 'end' 'if' 'of'
-'receive' 'rem' 'when' '{' '|' '}' atom float integer string var.
-% 'receive' 'rem' 'true' 'when' '{' '|' '}' atom float integer string var.
-
-Rootsymbol form.
-
-Endsymbol dot.
-
-Unary 0 'catch'.
-Right 200 '='.
-Right 200 '!'.
-Left 300 add_op.
-Left 400 mult_op.
-Unary 500 prefix_op.
-
-
-add_op -> '+' : '$1'.
-add_op -> '-' : '$1'.
-add_op -> 'bor' : '$1'.
-add_op -> 'bxor' : '$1'.
-add_op -> 'bsl' : '$1'.
-add_op -> 'bsr' : '$1'.
-
-comp_op -> '==' : '$1'.
-comp_op -> '/=' : '$1'.
-comp_op -> '=<' : '$1'.
-comp_op -> '<' : '$1'.
-comp_op -> '>=' : '$1'.
-comp_op -> '>' : '$1'.
-comp_op -> '=:=' : '$1'.
-comp_op -> '=/=' : '$1'.
-
-mult_op -> '*' : '$1'.
-mult_op -> '/' : '$1'.
-mult_op -> 'div' : '$1'.
-mult_op -> 'rem' : '$1'.
-mult_op -> 'band' : '$1'.
-
-prefix_op -> '+' : '$1'.
-prefix_op -> '-' : '$1'.
-prefix_op -> 'bnot' : '$1'.
-
-
-basic_type -> atom : '$1'.
-basic_type -> float : '$1'.
-basic_type -> integer : '$1'.
-basic_type -> string : '$1'.
-basic_type -> var : '$1'.
-% basic_type -> 'true' : {atom, element(2, '$1'), 'true'}.
-
-
-pattern -> basic_type : '$1'.
-pattern -> pattern_list : '$1'.
-pattern -> pattern_tuple : '$1'.
-
-pattern_list -> '[' ']' : {nil, element(2, '$1')}.
-pattern_list -> '[' pattern pattern_tail ']' :
- {cons, element(2, '$1'), '$2', '$3'}.
-
-pattern_tail -> '|' pattern : '$2'.
-pattern_tail -> ',' pattern pattern_tail :
- {cons, element(2, '$2'), '$2', '$3'}.
-pattern_tail -> '$empty' : {nil, 0}.
-
-pattern_tuple -> '{' '}' : {tuple, element(2, '$1'), []}.
-pattern_tuple -> '{' patterns '}' : {tuple, element(2, '$1'), '$2'}.
-
-patterns -> pattern : ['$1'].
-patterns -> pattern ',' patterns : ['$1' | '$3'].
-
-
-expr -> basic_type : '$1'.
-expr -> list : '$1'.
-expr -> tuple : '$1'.
-expr -> function_call : '$1'.
-
-expr -> expr add_op expr :
- {Op, Pos} = '$2',
- {arith, Pos, Op, '$1', '$3'}.
-expr -> expr mult_op expr :
- {Op, Pos} = '$2',
- {arith, Pos, Op, '$1', '$3'}.
-expr -> prefix_op expr:
- case '$2' of
- {float, Pos, N} ->
- case '$1' of
- {'-', _} ->
- {float, Pos, -N};
- {'+', _} ->
- {float, Pos, N};
- {Op, Pos1} ->
- {arith, Pos1, Op, {float, Pos, N}}
- end;
- {integer, Pos, N} ->
- case '$1' of
- {'-', _} ->
- {integer, Pos, -N};
- {'+', _} ->
- {integer, Pos, N};
- {Op, Pos1} ->
- {arith, Pos1, Op, {integer, Pos, N}}
- end;
- _ ->
- {Op, Pos} = '$1',
- {arith, Pos, Op, '$2'}
- end.
-
-expr -> '(' expr ')' : '$2'.
-expr -> 'begin' exprs 'end' : {block, element(2, '$1'), '$2'}.
-expr -> 'catch' expr : {'catch', element(2, '$1'), '$2'}.
-
-expr -> case_expr : '$1'.
-expr -> if_expr : '$1'.
-expr -> receive_expr : '$1'.
-expr -> match_expr : '$1'.
-expr -> send_expr : '$1'.
-
-
-list -> '[' ']' : {nil, element(2, '$1')}.
-list -> '[' expr expr_tail ']' : {cons, element(2, '$1'), '$2', '$3'}.
-
-expr_tail -> '|' expr : '$2'.
-expr_tail -> ',' expr expr_tail : {cons, element(2, '$2'), '$2', '$3'}.
-expr_tail -> '$empty' : {nil, 0}.
-
-tuple -> '{' '}' : {tuple, element(2, '$1'), []}.
-tuple -> '{' exprs '}' : {tuple, element(2, '$1'), '$2'}.
-
-
-function_call -> atom '(' parameter_list ')' :
- case erl_parse:erlang_bif(element(3, '$1'), length('$3')) of
- true ->
- {bif, element(2, '$1'), element(3, '$1'), '$3'};
- false ->
- {call, element(2, '$1'), [], element(3, '$1'), '$3'}
- end.
-function_call -> atom ':' atom '(' parameter_list ')' :
- {call, element(2, '$1'), element(3, '$1'), element(3, '$3'), '$5'}.
-
-parameter_list -> exprs : '$1'.
-parameter_list -> '$empty' : [].
-
-
-case_expr -> 'case' expr 'of' cr_clauses 'end' :
- {'case', element(2, '$1'), '$2', '$4'}.
-
-cr_clause -> pattern clause_guard clause_body :
- {clause, element(2, '$1'), ['$1'], '$2', '$3'}.
-
-cr_clauses -> cr_clause : ['$1'].
-cr_clauses -> cr_clause ';' cr_clauses : ['$1' | '$3'].
-
-if_expr -> 'if' if_clauses 'end' : {'if', element(2, '$1'), '$2'}.
-
-if_clause -> guard clause_body : {clause, element(2, hd('$2')), '$1', '$2'}.
-
-if_clauses -> if_clause : ['$1'].
-if_clauses -> if_clause ';' if_clauses : ['$1' | '$3'].
-
-receive_expr -> 'receive' 'after' expr clause_body 'end' :
- {'receive', element(2, '$1'), [], '$3', '$4'}.
-receive_expr -> 'receive' cr_clauses 'end' :
- {'receive', element(2, '$1'), '$2'}.
-receive_expr -> 'receive' cr_clauses 'after' expr clause_body 'end' :
- {'receive', element(2, '$1'), '$2', '$4', '$5'}.
-
-
-match_expr -> expr '=' expr :
- case erl_parse:is_term('$1') of
- true ->
- {match, element(2, '$1'), '$1', '$3'};
- false ->
- throw({error, {element(2, '$1'), yecc, "illegal lhs in match **"}})
- end.
-
-send_expr -> expr '!' expr :
- Pos = element(2, '$1'),
- {send, Pos, '$1', '$3'}.
-
-
-exprs -> expr : ['$1'].
-exprs -> expr ',' exprs : ['$1' | '$3'].
-
-
-guard_expr -> basic_type : '$1'.
-guard_expr -> guard_expr_list : '$1'.
-guard_expr -> guard_expr_tuple : '$1'.
-guard_expr -> guard_call : '$1'.
-guard_expr -> '(' guard_expr ')' : '$2'.
-guard_expr -> guard_expr add_op guard_expr :
- {Op, Pos} = '$2',
- {arith, Pos, Op, '$1', '$3'}.
-guard_expr -> guard_expr mult_op guard_expr :
- {Op, Pos} = '$2',
- {arith, Pos, Op, '$1', '$3'}.
-guard_expr -> prefix_op guard_expr:
- case '$2' of
- {float, Pos, N} ->
- case '$1' of
- {'-', _} ->
- {float, Pos, -N};
- {'+', _} ->
- {float, Pos, N};
- {Op, Pos1} ->
- {arith, Pos1, Op, {float, Pos, N}}
- end;
- {integer, Pos, N} ->
- case '$1' of
- {'-', _} ->
- {integer, Pos, -N};
- {'+', _} ->
- {integer, Pos, N};
- {Op, Pos1} ->
- {arith, Pos1, Op, {integer, Pos, N}}
- end;
- _ ->
- {Op, Pos} = '$1',
- {arith, Pos, Op, '$2'}
- end.
-
-guard_expr_list -> '[' ']' : {nil, element(2, '$1')}.
-guard_expr_list -> '[' guard_expr guard_expr_tail ']' :
- {cons, element(2, '$1'), '$2', '$3'}.
-
-guard_expr_tail -> '|' guard_expr : '$2'.
-guard_expr_tail -> ',' guard_expr guard_expr_tail :
- {cons, element(2, '$2'), '$2', '$3'}.
-guard_expr_tail -> '$empty' : {nil, 0}.
-
-guard_expr_tuple -> '{' '}' : {tuple, element(2, '$1'), []}.
-guard_expr_tuple -> '{' guard_exprs '}' : {tuple, element(2, '$1'), '$2'}.
-
-guard_exprs -> guard_expr : ['$1'].
-guard_exprs -> guard_expr ',' guard_exprs : ['$1' | '$3'].
-
-
-guard_call -> atom '(' guard_parameter_list ')' :
- case erl_parse:erlang_guard_bif(element(3, '$1'), length('$3')) of
- true ->
- {bif, element(2, '$1'), element(3, '$1'), '$3'};
- false ->
- throw({error, {element(2, '$1'), yecc, "illegal test in guard **"}})
- end.
-
-guard_parameter_list -> guard_exprs : '$1'.
-guard_parameter_list -> '$empty' : [].
-
-
-bif_test -> atom '(' guard_parameter_list ')' :
- case erl_parse:erlang_guard_test(element(3, '$1'), length('$3')) of
- true ->
- {test, element(2, '$1'), element(3, '$1'), '$3'};
- false ->
- throw({error, {element(2, '$1'), yecc, "illegal test in guard **"}})
- end.
-
-
-guard_test -> bif_test : '$1'.
-guard_test -> guard_expr comp_op guard_expr :
- {Op, Pos} = '$2',
- {comp, Pos, Op, '$1', '$3'}.
-
-guard_tests -> guard_test : ['$1'].
-guard_tests -> guard_test ',' guard_tests : ['$1' | '$3'].
-
-% guard -> 'true' : [].
-guard -> atom :
- case '$1' of
- {atom, _, true} ->
- [];
- _ ->
- throw({error, {element(2, '$1'), yecc, "illegal test in guard **"}})
- end.
-guard -> guard_tests : '$1'.
-
-
-function_clause -> clause_head clause_guard clause_body :
- {Name, Line, Arity, Parameters} = '$1',
- {function, Line, Name, Arity,
- [{clause, element(2, hd('$3')), Parameters, '$2', '$3'}]}.
-
-clause_head -> atom '(' formal_parameter_list ')' :
- {element(3, '$1'), element(2, '$1'), length('$3'), '$3'}.
-
-formal_parameter_list -> patterns : '$1'.
-formal_parameter_list -> '$empty' : [].
-
-clause_guard -> 'when' guard : '$2'.
-clause_guard -> '$empty' : [].
-
-clause_body -> '->' exprs: '$2'.
-
-
-function -> function_clause : '$1'.
-function -> function_clause ';' function :
- case '$1' of
- {function, Pos1, Name1, Arity1, [Clause]} ->
- case '$3' of
- {function, _, Name1, Arity2, Clauses} ->
- if
- Arity1 /= Arity2 ->
- throw({error, {Pos1, yecc,
- io_lib:format('arity conflict in definition of ~w',
- [Name1])}});
- true ->
- {function, Pos1, Name1, Arity1, [Clause | Clauses]}
- end;
- _ ->
- throw({error, {Pos1, yecc,
- io_lib:format('missing final dot in def of ~w/~w',
- [Name1, Arity1])}})
- end
- end.
-
-
-attribute -> atom : element(3, '$1').
-attribute -> '[' farity_list ']' : '$2'.
-
-farity_list -> farity : ['$1'].
-farity_list -> farity ',' farity_list : ['$1' | '$3'].
-
-farity -> atom '/' integer : {element(3, '$1'), element(3, '$3')}.
-
-
-form -> '-' atom '(' attribute ')' :
- {attribute, element(2, '$2'), element(3, '$2'), '$4'}.
-form -> function : '$1'.
diff --git a/lib/parsetools/src/leex.erl b/lib/parsetools/src/leex.erl
index cdf20461d9..bbef4053b4 100644
--- a/lib/parsetools/src/leex.erl
+++ b/lib/parsetools/src/leex.erl
@@ -58,6 +58,7 @@
gfile=[], % Graph file
module, % Module name
opts=[], % Options
+ encoding=none, % Encoding of Xrl file
% posix=false, % POSIX regular expressions
errors=[],
warnings=[]
@@ -146,7 +147,9 @@ format_error({regexp,E})->
end,
["bad regexp `",Es,"'"];
format_error(ignored_characters) ->
- "ignored characters".
+ "ignored characters";
+format_error(cannot_parse) ->
+ io_lib:fwrite("cannot parse; probably encoding mismatch", []).
%%%
%%% Local functions
@@ -298,10 +301,10 @@ pack_warnings([]) ->
report_errors(St) ->
when_opt(fun () ->
foreach(fun({File,{none,Mod,E}}) ->
- io:fwrite("~s: ~s\n",
+ io:fwrite("~s: ~ts\n",
[File,Mod:format_error(E)]);
({File,{Line,Mod,E}}) ->
- io:fwrite("~s:~w: ~s\n",
+ io:fwrite("~s:~w: ~ts\n",
[File,Line,Mod:format_error(E)])
end, sort(St#leex.errors))
end, report_errors, St#leex.opts).
@@ -316,11 +319,11 @@ report_warnings(St) ->
ShouldReport = member(report_warnings, St#leex.opts) orelse ReportWerror,
when_bool(fun () ->
foreach(fun({File,{none,Mod,W}}) ->
- io:fwrite("~s: ~s~s\n",
+ io:fwrite("~s: ~s~ts\n",
[File,Prefix,
Mod:format_error(W)]);
({File,{Line,Mod,W}}) ->
- io:fwrite("~s:~w: ~s~s\n",
+ io:fwrite("~s:~w: ~s~ts\n",
[File,Line,Prefix,
Mod:format_error(W)])
end, sort(St#leex.warnings))
@@ -396,17 +399,18 @@ verbose_print(St, Format, Args) ->
parse_file(St0) ->
case file:open(St0#leex.xfile, [read]) of
{ok,Xfile} ->
+ St1 = St0#leex{encoding = epp:set_encoding(Xfile)},
try
- verbose_print(St0, "Parsing file ~s, ", [St0#leex.xfile]),
+ verbose_print(St1, "Parsing file ~s, ", [St1#leex.xfile]),
%% We KNOW that errors throw so we can ignore them here.
- {ok,Line1,St1} = parse_head(Xfile, St0),
- {ok,Line2,Macs,St2} = parse_defs(Xfile, Line1, St1),
- {ok,Line3,REAs,Actions,St3} =
- parse_rules(Xfile, Line2, Macs, St2),
- {ok,Code,St4} = parse_code(Xfile, Line3, St3),
- verbose_print(St1, "contained ~w rules.~n", [length(REAs)]),
- {ok,REAs,Actions,Code,St4}
- after file:close(Xfile)
+ {ok,Line1,St2} = parse_head(Xfile, St1),
+ {ok,Line2,Macs,St3} = parse_defs(Xfile, Line1, St2),
+ {ok,Line3,REAs,Actions,St4} =
+ parse_rules(Xfile, Line2, Macs, St3),
+ {ok,Code,St5} = parse_code(Xfile, Line3, St4),
+ verbose_print(St5, "contained ~w rules.~n", [length(REAs)]),
+ {ok,REAs,Actions,Code,St5}
+ after ok = file:close(Xfile)
end;
{error,Error} ->
add_error({none,leex,{file_error,Error}}, St0)
@@ -415,7 +419,7 @@ parse_file(St0) ->
%% parse_head(File, State) -> {ok,NextLine,State}.
%% Parse the head of the file. Skip all comments and blank lines.
-parse_head(Ifile, St) -> {ok,nextline(Ifile, 0),St}.
+parse_head(Ifile, St) -> {ok,nextline(Ifile, 0, St),St}.
%% parse_defs(File, Line, State) -> {ok,NextLine,Macros,State}.
%% Parse the macro definition section of a file. This must exist.
@@ -423,7 +427,7 @@ parse_head(Ifile, St) -> {ok,nextline(Ifile, 0),St}.
parse_defs(Ifile, {ok,?DEFS_HEAD ++ Rest,L}, St) ->
St1 = warn_ignored_chars(L, Rest, St),
- parse_defs(Ifile, nextline(Ifile, L), [], St1);
+ parse_defs(Ifile, nextline(Ifile, L, St), [], St1);
parse_defs(_, {ok,_,L}, St) ->
add_error({L,leex,missing_defs}, St);
parse_defs(_, {eof,L}, St) ->
@@ -435,7 +439,7 @@ parse_defs(Ifile, {ok,Chars,L}=Line, Ms, St) ->
case re:run(Chars, MS, [{capture,all_but_first,list}]) of
{match,[Name,Def]} ->
%%io:fwrite("~p = ~p\n", [Name,Def]),
- parse_defs(Ifile, nextline(Ifile, L), [{Name,Def}|Ms], St);
+ parse_defs(Ifile, nextline(Ifile, L, St), [{Name,Def}|Ms], St);
_ -> {ok,Line,Ms,St} % Anything else
end;
parse_defs(_, Line, Ms, St) ->
@@ -446,7 +450,7 @@ parse_defs(_, Line, Ms, St) ->
parse_rules(Ifile, {ok,?RULE_HEAD ++ Rest,L}, Ms, St) ->
St1 = warn_ignored_chars(L, Rest, St),
- parse_rules(Ifile, nextline(Ifile, L), Ms, [], [], 0, St1);
+ parse_rules(Ifile, nextline(Ifile, L, St), Ms, [], [], 0, St1);
parse_rules(_, {ok,_,L}, _, St) ->
add_error({L,leex,missing_rules}, St);
parse_rules(_, {eof,L}, _, St) ->
@@ -464,7 +468,7 @@ parse_rules(Ifile, NextLine, Ms, REAs, As, N, St) ->
case collect_rule(Ifile, Chars, L0) of
{ok,Re,Atoks,L1} ->
{ok,REA,A,St1} = parse_rule(Re, L0, Atoks, Ms, N, St),
- parse_rules(Ifile, nextline(Ifile, L1), Ms,
+ parse_rules(Ifile, nextline(Ifile, L1, St), Ms,
[REA|REAs], [A|As], N+1, St1);
{error,E} -> add_error(E, St)
end;
@@ -497,8 +501,10 @@ collect_rule(Ifile, Chars, L0) ->
{error,E,_} -> {error,E}
end.
+collect_action(_Ifile, {error, _}, L, _Cont0) ->
+ {error, {L, leex, cannot_parse}, ignored_end_line};
collect_action(Ifile, Chars, L0, Cont0) ->
- case erl_scan:tokens(Cont0, Chars, L0) of
+ case erl_scan:tokens(Cont0, Chars, L0, [unicode]) of
{done,{ok,Toks,_},_} -> {ok,Toks,L0};
{done,{eof,_},_} -> {eof,L0};
{done,{error,E,_},_} -> {error,E,L0};
@@ -560,29 +566,32 @@ parse_code(Ifile, {ok,?CODE_HEAD ++ Rest,CodeL}, St) ->
St1 = warn_ignored_chars(CodeL, Rest, St),
{ok, CodePos} = file:position(Ifile, cur),
%% Just count the lines; copy the code from file to file later.
- NCodeLines = count_lines(Ifile, 0),
+ EndCodeLine = count_lines(Ifile, CodeL, St),
+ NCodeLines = EndCodeLine - CodeL,
{ok,{CodeL,CodePos,NCodeLines},St1};
parse_code(_, {ok,_,L}, St) ->
add_error({L,leex,missing_code}, St);
parse_code(_, {eof,L}, St) ->
add_error({L,leex,missing_code}, St).
-count_lines(File, N) ->
+count_lines(File, N, St) ->
case io:get_line(File, leex) of
eof -> N;
- _Line -> count_lines(File, N+1)
+ {error, _} -> add_error({N+1, leex, cannot_parse}, St);
+ _Line -> count_lines(File, N+1, St)
end.
-%% nextline(InputFile, PrevLineNo) -> {ok,Chars,LineNo} | {eof,LineNo}.
+%% nextline(InputFile, PrevLineNo, State) -> {ok,Chars,LineNo} | {eof,LineNo}.
%% Get the next line skipping comment lines and blank lines.
-nextline(Ifile, L) ->
+nextline(Ifile, L, St) ->
case io:get_line(Ifile, leex) of
eof -> {eof,L};
+ {error, _} -> add_error({L+1, leex, cannot_parse}, St);
Chars ->
case substr(Chars, span(Chars, " \t\n")+1) of
- [$%|_Rest] -> nextline(Ifile, L+1);
- [] -> nextline(Ifile, L+1);
+ [$%|_Rest] -> nextline(Ifile, L+1, St);
+ [] -> nextline(Ifile, L+1, St);
_Other -> {ok,Chars,L+1}
end
end.
@@ -1289,19 +1298,21 @@ out_file(St0, DFA, DF, Actions, Code) ->
try
case file:open(St0#leex.efile, [write]) of
{ok,Ofile} ->
+ set_encoding(St0, Ofile),
try
+ output_encoding_comment(Ofile, St0),
output_file_directive(Ofile, St0#leex.ifile, 0),
out_file(Ifile, Ofile, St0, DFA, DF, Actions,
Code, 1),
verbose_print(St0, "ok~n", []),
St0
- after file:close(Ofile)
+ after ok = file:close(Ofile)
end;
{error,Error} ->
verbose_print(St0, "error~n", []),
add_error({none,leex,{file_error,Error}}, St0)
end
- after file:close(Ifile)
+ after ok = file:close(Ifile)
end;
{{error,Error},Ifile} ->
add_error(Ifile, {none,leex,{file_error,Error}}, St0)
@@ -1310,7 +1321,9 @@ out_file(St0, DFA, DF, Actions, Code) ->
open_inc_file(State) ->
Ifile = State#leex.ifile,
case file:open(Ifile, [read]) of
- {ok,F} -> {ok,F};
+ {ok,F} ->
+ _ = epp:set_encoding(F),
+ {ok,F};
Error -> {Error,Ifile}
end.
@@ -1328,6 +1341,7 @@ inc_file_name(Filename) ->
out_file(Ifile, Ofile, St, DFA, DF, Actions, Code, L) ->
case io:get_line(Ifile, leex) of
eof -> output_file_directive(Ofile, St#leex.ifile, L);
+ {error, _} -> add_error(St#leex.ifile, {L, leex, cannot_parse}, St);
Line ->
case substr(Line, 1, 5) of
"##mod" -> out_module(Ofile, St);
@@ -1347,14 +1361,23 @@ out_erlang_code(File, St, Code, L) ->
output_file_directive(File, St#leex.xfile, CodeL),
{ok,Xfile} = file:open(St#leex.xfile, [read]),
try
+ set_encoding(St, Xfile),
{ok,_} = file:position(Xfile, CodePos),
- {ok,_} = file:copy(Xfile, File)
+ ok = file_copy(Xfile, File)
after
- file:close(Xfile)
+ ok = file:close(Xfile)
end,
io:nl(File),
output_file_directive(File, St#leex.ifile, L).
+file_copy(From, To) ->
+ case io:get_line(From, leex) of
+ eof -> ok;
+ Line when is_list(Line) ->
+ io:fwrite(To, "~ts", [Line]),
+ file_copy(From, To)
+ end.
+
out_dfa(File, St, DFA, Code, DF, L) ->
{_CodeL,_CodePos,NCodeLines} = Code,
%% Three file attributes before this one...
@@ -1569,7 +1592,7 @@ out_dfa_graph(St, DFA, DF) ->
io:fwrite(Gfile, "}~n", []),
verbose_print(St, "ok~n", []),
St
- after file:close(Gfile)
+ after ok = file:close(Gfile)
end;
{error,Error} ->
verbose_print(St, "error~n", []),
@@ -1610,6 +1633,16 @@ dfa_edgelabel(Cranges) ->
(C) -> [quote(C)]
end, Cranges) ++ "]".
+set_encoding(#leex{encoding = none}, File) ->
+ ok = io:setopts(File, [{encoding, epp:default_encoding()}]);
+set_encoding(#leex{encoding = E}, File) ->
+ ok = io:setopts(File, [{encoding, E}]).
+
+output_encoding_comment(_File, #leex{encoding = none}) ->
+ ok;
+output_encoding_comment(File, #leex{encoding = Encoding}) ->
+ io:fwrite(File, <<"%% ~s\n">>, [epp:encoding_to_string(Encoding)]).
+
output_file_directive(File, Filename, Line) ->
io:fwrite(File, <<"-file(~s, ~w).\n">>,
[format_filename(Filename), Line]).
diff --git a/lib/parsetools/src/yecc.erl b/lib/parsetools/src/yecc.erl
index b0792a6ed8..dbb7d025ae 100644
--- a/lib/parsetools/src/yecc.erl
+++ b/lib/parsetools/src/yecc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -42,6 +42,7 @@
includefile,
includefile_version,
module,
+ encoding = none,
options = [],
verbose = false,
file_attrs = true,
@@ -224,7 +225,11 @@ format_error({unused_nonterminal, Nonterminal}) ->
[format_symbol(Nonterminal)]);
format_error({unused_terminal, Terminal}) ->
io_lib:fwrite("terminal symbol ~s not used",
- [format_symbol(Terminal)]).
+ [format_symbol(Terminal)]);
+format_error({bad_symbol, String}) ->
+ io_lib:fwrite("bad symbol ~ts", [String]);
+format_error(cannot_parse) ->
+ io_lib:fwrite("cannot parse; possibly encoding mismatch", []).
file(File) ->
file(File, [report_errors, report_warnings]).
@@ -257,7 +262,7 @@ yecc(Infile, Outfile, Verbose) ->
yecc(Infile, Outfile, Verbose, []).
yecc(Infilex, Outfilex, Verbose, Includefilex) ->
- statistics(runtime),
+ _ = statistics(runtime),
case file(Infilex, [{parserfile, Outfilex},
{verbose, Verbose},
{report, true},
@@ -407,7 +412,9 @@ infile(Parent, Infilex, Options) ->
St = case file:open(St0#yecc.infile, [read, read_ahead]) of
{ok, Inport} ->
try
- outfile(St0#yecc{inport = Inport})
+ Encoding = epp:set_encoding(Inport),
+ St1 = St0#yecc{inport = Inport, encoding = Encoding},
+ outfile(St1)
after
ok = file:close(Inport)
end;
@@ -428,6 +435,8 @@ outfile(St0) ->
case file:open(St0#yecc.outfile, [write, delayed_write]) of
{ok, Outport} ->
try
+ %% Set the same encoding as infile:
+ set_encoding(St0, Outport),
generate(St0#yecc{outport = Outport, line = 1})
catch
throw: St1 ->
@@ -466,13 +475,14 @@ timeit(Name, Fun, St0) ->
-define(PASS(P), {P, fun P/1}).
generate(St0) ->
+ St1 = output_encoding_comment(St0),
Passes = [?PASS(parse_grammar), ?PASS(check_grammar),
?PASS(states_and_goto_table), ?PASS(parse_actions),
?PASS(action_conflicts), ?PASS(write_file)],
- F = case member(time, St0#yecc.options) of
+ F = case member(time, St1#yecc.options) of
true ->
io:fwrite(<<"Generating parser from grammar in ~s\n">>,
- [format_filename(St0#yecc.infile)]),
+ [format_filename(St1#yecc.infile)]),
fun timeit/3;
false ->
fun(_Name, Fn, St) -> Fn(St) end
@@ -484,13 +494,13 @@ generate(St0) ->
true -> throw(St2)
end
end,
- foldl(Fun, St0, Passes).
+ foldl(Fun, St1, Passes).
parse_grammar(St) ->
parse_grammar(St#yecc.inport, 1, St).
parse_grammar(Inport, Line, St) ->
- {NextLine, Grammar} = read_grammar(Inport, Line),
+ {NextLine, Grammar} = read_grammar(Inport, St, Line),
parse_grammar(Grammar, Inport, NextLine, St).
parse_grammar(eof, _Inport, _NextLine, St) ->
@@ -523,6 +533,8 @@ parse_grammar({rule, Rule, Tokens}, St0) ->
St#yecc{rules_list = [RuleDef | St#yecc.rules_list]};
parse_grammar({prec, Prec}, St) ->
St#yecc{prec = Prec ++ St#yecc.prec};
+parse_grammar({#symbol{}, [{string,Line,String}]}, St) ->
+ add_error(Line, {bad_symbol, String}, St);
parse_grammar({#symbol{line = Line, name = Name}, Symbols}, St) ->
CF = fun(I) ->
case element(I, St) of
@@ -543,12 +555,17 @@ parse_grammar({#symbol{line = Line, name = Name}, Symbols}, St) ->
_ -> add_warning(Line, bad_declaration, St)
end.
-read_grammar(Inport, Line) ->
+read_grammar(Inport, St, Line) ->
case yeccscan:scan(Inport, '', Line) of
{eof, NextLine} ->
{NextLine, eof};
{error, {ErrorLine, Mod, What}, NextLine} ->
{NextLine, {error, ErrorLine, {error, Mod, What}}};
+ {error, terminated} ->
+ throw(St);
+ {error, _} ->
+ File = St#yecc.infile,
+ throw(add_error(File, none, cannot_parse, St));
{ok, Input, NextLine} ->
{NextLine, case yeccparser:parse(Input) of
{error, {ErrorLine, Mod, Message}} ->
@@ -738,9 +755,9 @@ states_and_goto_table(St0) ->
create_precedence_table(St).
parse_actions(St) ->
- erase(), % the pd is used when decoding lookahead sets
+ _ = erase(), % the pd is used when decoding lookahead sets
ParseActions = compute_parse_actions(St#yecc.n_states, St, []),
- erase(),
+ _ = erase(),
St#yecc{parse_actions = ParseActions, state_tab = []}.
action_conflicts(St0) ->
@@ -841,10 +858,10 @@ report_errors(St) ->
case member(report_errors, St#yecc.options) of
true ->
foreach(fun({File,{none,Mod,E}}) ->
- io:fwrite(<<"~s: ~s\n">>,
+ io:fwrite(<<"~s: ~ts\n">>,
[File,Mod:format_error(E)]);
({File,{Line,Mod,E}}) ->
- io:fwrite(<<"~s:~w: ~s\n">>,
+ io:fwrite(<<"~s:~w: ~ts\n">>,
[File,Line,Mod:format_error(E)])
end, sort(St#yecc.errors));
false ->
@@ -861,11 +878,11 @@ report_warnings(St) ->
case member(report_warnings, St#yecc.options) orelse ReportWerror of
true ->
foreach(fun({File,{none,Mod,W}}) ->
- io:fwrite(<<"~s: ~s~s\n">>,
+ io:fwrite(<<"~s: ~s~ts\n">>,
[File,Prefix,
Mod:format_error(W)]);
({File,{Line,Mod,W}}) ->
- io:fwrite(<<"~s:~w: ~s~s\n">>,
+ io:fwrite(<<"~s:~w: ~s~ts\n">>,
[File,Line,Prefix,
Mod:format_error(W)])
end, sort(St#yecc.warnings));
@@ -1024,7 +1041,7 @@ compute_states(St0) ->
rp_info = RulePointerInfo,
goto = GotoTab},
- erase(),
+ _ = erase(),
EndsymCode = code_terminal(StC#yecc.endsymbol, StC#yecc.symbol_tab),
{StateId, State0} = compute_state([{EndsymCode, 1}], Tables),
@@ -1923,9 +1940,10 @@ output_prelude(Outport, Inport, St0) when St0#yecc.includefile =:= [] ->
{St20, 0, no_erlang_code};
Next_line ->
St_10 = output_file_directive(St20, Infile, Next_line-1),
- Nmbr_of_lines = include1([], Inport, Outport),
- {St_10, Nmbr_of_lines,
- {last_erlang_code_line, Next_line+Nmbr_of_lines}}
+ Last_line = include1([], Inport, Outport, Infile,
+ Next_line, St_10),
+ Nmbr_of_lines = Last_line - Next_line,
+ {St_10, Nmbr_of_lines, {last_erlang_code_line, Last_line}}
end,
St30 = nl(St25),
IncludeFile =
@@ -1946,13 +1964,13 @@ output_prelude(Outport, Inport, St0) ->
{St30, N_lines_1, no_erlang_code};
Next_line ->
St = output_file_directive(St30, Infile, Next_line-1),
- Nmbr_of_lines = include1([], Inport, Outport),
- {St, Nmbr_of_lines + N_lines_1,
- {last_erlang_code_line, Next_line+Nmbr_of_lines}}
+ Last_line = include1([], Inport, Outport, Infile, Next_line, St),
+ Nmbr_of_lines = Last_line - Next_line,
+ {St, Nmbr_of_lines + N_lines_1, {last_erlang_code_line, Last_line}}
end.
output_header(St0) ->
- lists:foldl(fun(Str, St) -> fwrite(St, <<"~s\n">>, [Str])
+ lists:foldl(fun(Str, St) -> fwrite(St, <<"~ts\n">>, [Str])
end, St0, St0#yecc.header).
output_goto(St, [{_Nonterminal, []} | Go], StateInfo) ->
@@ -2250,8 +2268,8 @@ output_inlined(St0, FunctionName, Reduce, Infile) ->
[append(["[", tl(A), " | __Stack]"])])
end,
St = St40#yecc{line = St40#yecc.line + NLines},
- fwrite(St, <<" [begin\n ~s\n end | ~s].\n\n">>,
- [pp_tokens(Tokens, Line0), Stack]).
+ fwrite(St, <<" [begin\n ~ts\n end | ~s].\n\n">>,
+ [pp_tokens(Tokens, Line0, St#yecc.encoding), Stack]).
inlined_function_name(State, "Cat") ->
inlined_function_name(State, "");
@@ -2421,24 +2439,24 @@ include(St, File, Outport) ->
{error, Reason} ->
throw(add_error(File, none, {file_error, Reason}, St));
{ok, Inport} ->
+ _ = epp:set_encoding(Inport),
Line = io:get_line(Inport, ''),
- N_lines = include1(Line, Inport, Outport),
- file:close(Inport),
- N_lines
+ try include1(Line, Inport, Outport, File, 1, St) - 1
+ after ok = file:close(Inport)
+ end
end.
-include1(Line, Inport, Outport) ->
- include1(Line, Inport, Outport, 0).
-
-include1(eof, _, _, Nmbr_of_lines) ->
- Nmbr_of_lines;
-include1(Line, Inport, Outport, Nmbr_of_lines) ->
+include1(eof, _, _, _File, L, _St) ->
+ L;
+include1({error, _}=_Error, _Inport, _Outport, File, L, St) ->
+ throw(add_error(File, L, cannot_parse, St));
+include1(Line, Inport, Outport, File, L, St) ->
Incr = case member($\n, Line) of
true -> 1;
false -> 0
end,
io:put_chars(Outport, Line),
- include1(io:get_line(Inport, ''), Inport, Outport, Nmbr_of_lines + Incr).
+ include1(io:get_line(Inport, ''), Inport, Outport, File, L + Incr, St).
includefile_version([]) ->
{1,4};
@@ -2465,18 +2483,22 @@ parse_file(Epp) ->
end.
%% Keeps the line breaks of the original code.
-pp_tokens(Tokens, Line0) ->
- concat(pp_tokens1(Tokens, Line0, [])).
+pp_tokens(Tokens, Line0, Enc) ->
+ concat(pp_tokens1(Tokens, Line0, Enc, [])).
-pp_tokens1([], _Line0, _T0) ->
+pp_tokens1([], _Line0, _Enc, _T0) ->
[];
-pp_tokens1([T | Ts], Line0, T0) ->
+pp_tokens1([T | Ts], Line0, Enc, T0) ->
Line = element(2, T),
- [pp_sep(Line, Line0, T0), pp_symbol(T) | pp_tokens1(Ts, Line, T)].
+ [pp_sep(Line, Line0, T0), pp_symbol(T, Enc)|pp_tokens1(Ts, Line, Enc, T)].
-pp_symbol({var,_,Var}) -> Var;
-pp_symbol({_,_,Symbol}) -> io_lib:fwrite(<<"~p">>, [Symbol]);
-pp_symbol({Symbol, _}) -> Symbol.
+pp_symbol({var,_,Var}, _Enc) -> Var;
+pp_symbol({string,_,String}, latin1) ->
+ io_lib:write_unicode_string_as_latin1(String);
+pp_symbol({string,_,String}, _Enc) -> io_lib:write_unicode_string(String);
+pp_symbol({_,_,Symbol}, latin1) -> io_lib:fwrite(<<"~p">>, [Symbol]);
+pp_symbol({_,_,Symbol}, _Enc) -> io_lib:fwrite(<<"~tp">>, [Symbol]);
+pp_symbol({Symbol, _}, _Enc) -> Symbol.
pp_sep(Line, Line0, T0) when Line > Line0 ->
["\n " | pp_sep(Line - 1, Line0, T0)];
@@ -2485,6 +2507,16 @@ pp_sep(_Line, _Line0, {'.',_}) ->
pp_sep(_Line, _Line0, _T0) ->
" ".
+set_encoding(#yecc{encoding = none}, Port) ->
+ ok = io:setopts(Port, [{encoding, epp:default_encoding()}]);
+set_encoding(#yecc{encoding = E}, Port) ->
+ ok = io:setopts(Port, [{encoding, E}]).
+
+output_encoding_comment(#yecc{encoding = none}=St) ->
+ St;
+output_encoding_comment(#yecc{encoding = Encoding}=St) ->
+ fwrite(St, <<"%% ~s\n">>, [epp:encoding_to_string(Encoding)]).
+
output_file_directive(St, Filename, Line) when St#yecc.file_attrs ->
fwrite(St, <<"-file(~s, ~w).\n">>,
[format_filename(Filename), Line]);
@@ -2529,7 +2561,7 @@ format_assoc(nonassoc) ->
format_symbol(Symbol) ->
String = concat([Symbol]),
- case erl_scan:string(String) of
+ case erl_scan:string(String, 1, [unicode]) of
{ok, [{atom, _, _}], _} ->
io_lib:fwrite(<<"~w">>, [Symbol]);
{ok, [{Word, _}], _} when Word =/= ':', Word =/= '->' ->
diff --git a/lib/parsetools/src/yeccscan.erl b/lib/parsetools/src/yeccscan.erl
index d7ec3ba8d3..9e0e85143a 100644
--- a/lib/parsetools/src/yeccscan.erl
+++ b/lib/parsetools/src/yeccscan.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -24,7 +24,7 @@ scan(Inport) ->
scan(Inport, '', 1).
scan(Inport, Prompt, Line1) ->
- case catch io:scan_erl_form(Inport, Prompt, Line1) of
+ case catch io:scan_erl_form(Inport, Prompt, Line1, [unicode]) of
{eof, Line2} ->
{eof, Line2};
{ok, Tokens, Line2} ->
@@ -34,6 +34,8 @@ scan(Inport, Prompt, Line1) ->
_ ->
{ok, lex(Tokens), Line2}
end;
+ {error, Reason} ->
+ {error, Reason};
{error, Descriptor, Line2} ->
{error, Descriptor, Line2};
{'EXIT', Why} ->
diff --git a/lib/parsetools/test/leex_SUITE.erl b/lib/parsetools/test/leex_SUITE.erl
index 1e50aedf07..4a0f70ba71 100644
--- a/lib/parsetools/test/leex_SUITE.erl
+++ b/lib/parsetools/test/leex_SUITE.erl
@@ -1,7 +1,8 @@
+%% -*- coding: latin-1 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -42,7 +43,9 @@
-export([
file/1, compile/1, syntax/1,
- pt/1, man/1, ex/1, ex2/1, not_yet/1]).
+ pt/1, man/1, ex/1, ex2/1, not_yet/1,
+
+ otp_10302/1]).
% Default timetrap timeout (set in init_per_testcase).
-define(default_timeout, ?t:minutes(1)).
@@ -63,7 +66,8 @@ all() ->
groups() ->
[{checks, [], [file, compile, syntax]},
- {examples, [], [pt, man, ex, ex2, not_yet]}].
+ {examples, [], [pt, man, ex, ex2, not_yet]},
+ {tickets, [], [otp_10302]}].
init_per_suite(Config) ->
Config.
@@ -875,6 +879,111 @@ not_yet(Config) when is_list(Config) ->
ok.
+otp_10302(doc) ->
+ "OTP-10302. Unicode characters scanner/parser.";
+otp_10302(suite) -> [];
+otp_10302(Config) when is_list(Config) ->
+ Dir = ?privdir,
+ Filename = filename:join(Dir, "file.xrl"),
+ Ret = [return, {report, true}],
+
+ ok = file:write_file(Filename,<<
+ "%% coding: UTF-8\n"
+ "�"
+ >>),
+ {error,[{_,[{2,leex,cannot_parse}]}],[]} =
+ leex:file(Filename, Ret),
+
+ ok = file:write_file(Filename,<<
+ "%% coding: UTF-8\n"
+ "Definitions.\n"
+ "�"
+ >>),
+ {error,[{_,[{3,leex,cannot_parse}]}],[]} = leex:file(Filename, Ret),
+
+ ok = file:write_file(Filename,<<
+ "%% coding: UTF-8\n"
+ "Definitions.\n"
+ "A = a\n"
+ "L = [{A}-{Z}]\n"
+ "Z = z\n"
+ "Rules.\n"
+ "{L}+ : {token,{list_to_atom(TokenChars),H�pp}}.\n"
+ >>),
+ {error,[{_,[{7,leex,cannot_parse}]}],[]} = leex:file(Filename, Ret),
+
+ ok = file:write_file(Filename,<<
+ "%% coding: UTF-8\n"
+ "Definitions.\n"
+ "A = a\n"
+ "L = [{A}-{Z}]\n"
+ "Z = z\n"
+ "Rules.\n"
+ "{L}+ : {token,{list_to_atom(TokenChars)}}.\n"
+ "Erlang code.\n"
+ "-export([t/0]).\n"
+ "t() ->\n"
+ " H�pp\n"
+ >>),
+ {error,[{_,[{11,leex,cannot_parse}]}],[]} = leex:file(Filename, Ret),
+
+ Mini = <<"Definitions.\n"
+ "D = [0-9]\n"
+ "Rules.\n"
+ "{L}+ : {token,{word,TokenLine,TokenChars}}.\n"
+ "Erlang code.\n">>,
+ LeexPre = filename:join(Dir, "leexinc.hrl"),
+ ?line ok = file:write_file(LeexPre, <<"%% coding: UTF-8\n �">>),
+ PreErrors = run_test(Config, Mini, LeexPre),
+ {error,[{IncludeFile,[{2,leex,cannot_parse}]}],[]} = PreErrors,
+ "leexinc.hrl" = filename:basename(IncludeFile),
+
+ Ts = [{uni_1,
+ <<"%% coding: UTF-8\n"
+ "Definitions.\n"
+ "A = a\n"
+ "L = [{A}-{Z}]\n"
+ "Z = z\n"
+ "Rules.\n"
+ "{L}+ : {token,{list_to_atom(TokenChars),\n"
+ "begin Häpp = foo, Häpp end,"
+ " 'Häpp',\"\\x{400}B\",\"örn_Ѐ\"}}.\n"
+ "Erlang code.\n"
+ "-export([t/0]).\n"
+ "t() ->\n"
+ " %% Häpp, 'Häpp',\"\\x{400}B\",\"örn_Ѐ\"\n"
+ " {ok, [R], 1} = string(\"tip\"),\n"
+ " {tip,foo,'Häpp',[1024,66],[246,114,110,95,1024]} = R,\n"
+ " Häpp = foo,\n"
+ " {tip, Häpp, 'Häpp',\"\\x{400}B\",\"örn_Ѐ\"} = R,\n"
+ " ok.\n">>,
+ default,
+ ok},
+ {uni_2,
+ <<"%% coding: Latin-1\n"
+ "Definitions.\n"
+ "A = a\n"
+ "L = [{A}-{Z}]\n"
+ "Z = z\n"
+ "Rules.\n"
+ "{L}+ : {token,{list_to_atom(TokenChars),\n"
+ "begin H�pp = foo, H�pp end,"
+ " 'H�pp',\"\\x{400}B\",\"örn_Ѐ\"}}.\n"
+ "Erlang code.\n"
+ "-export([t/0]).\n"
+ "t() ->\n"
+ " %% H�pp, 'H�pp',\"\\x{400}B\",\"örn_Ѐ\"\n"
+ " {ok, [R], 1} = string(\"tip\"),\n"
+ " {tip,foo,'H�pp',[1024,66],[195,182,114,110,95,208,128]} = R,\n"
+ " H�pp = foo,\n"
+ " {tip, H�pp, 'H�pp',\"\\x{400}B\",\"örn_Ѐ\"} = R,\n"
+ " ok.\n">>,
+ default,
+ ok}],
+ run(Config, Ts),
+
+ ok.
+
unwritable(Fname) ->
{ok, Info} = file:read_file_info(Fname),
Mode = Info#file_info.mode - 8#00200,
diff --git a/lib/parsetools/test/yecc_SUITE.erl b/lib/parsetools/test/yecc_SUITE.erl
index 3d26adf1be..c306dbe833 100644
--- a/lib/parsetools/test/yecc_SUITE.erl
+++ b/lib/parsetools/test/yecc_SUITE.erl
@@ -1,7 +1,8 @@
+%% -*- coding: latin-1 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -48,7 +49,7 @@
otp_5369/1, otp_6362/1, otp_7945/1, otp_8483/1, otp_8486/1,
- otp_7292/1, otp_7969/1, otp_8919/1]).
+ otp_7292/1, otp_7969/1, otp_8919/1, otp_10302/1]).
% Default timetrap timeout (set in init_per_testcase).
-define(default_timeout, ?t:minutes(1)).
@@ -75,7 +76,7 @@ groups() ->
[empty, prec, yeccpre, lalr, old_yecc, other_examples]},
{bugs, [],
[otp_5369, otp_6362, otp_7945, otp_8483, otp_8486]},
- {improvements, [], [otp_7292, otp_7969, otp_8919]}].
+ {improvements, [], [otp_7292, otp_7969, otp_8919, otp_10302]}].
init_per_suite(Config) ->
Config.
@@ -1815,6 +1816,153 @@ otp_8919(Config) when is_list(Config) ->
"syntax error before: \"hello\"" = lists:flatten(Mod:format_error(Mess)),
ok.
+otp_10302(doc) ->
+ "OTP-10302. Unicode characters scanner/parser.";
+otp_10302(suite) -> [];
+otp_10302(Config) when is_list(Config) ->
+ Dir = ?privdir,
+ Filename = filename:join(Dir, "OTP-10302.yrl"),
+ Ret = [return, {report, true}],
+ Mini1 = <<"%% coding: utf-8
+ Nonterminals H�pp.
+ nt -> t.">>,
+ ok = file:write_file(Filename, Mini1),
+ %% This could (and should) be refined:
+ {error,[{Filename,[{2,Mod1,Err1}]}],[]} =
+ yecc:file(Filename, Ret),
+ "cannot translate from UTF-8" = Mod1:format_error(Err1),
+
+ Mini2 = <<"%% coding: Utf-8
+ Nonterminals Hopp.
+ Terminals t.
+ Rootsymbol Hopp.
+
+ Hopp -> t.
+
+ Erlang code.
+
+ t() ->
+ H�pp.">>,
+ ok = file:write_file(Filename, Mini2),
+ {error,[{Filename,[{11,Mod2,Err2}]}],[]} =
+ yecc:file(Filename, Ret),
+ "cannot parse; possibly encoding mismatch" = Mod2:format_error(Err2),
+
+ Mini3 = <<"%% coding: latin-1
+ Nonterminals Hopp.
+ Terminals t.
+ Rootsymbol Hopp.
+
+ Hopp -> t.
+
+ Erlang code.
+
+ t() ->
+ H�pp.">>,
+ ok = file:write_file(Filename, Mini3),
+ YeccPre = filename:join(Dir, "yeccpre.hrl"),
+ ok = file:write_file(YeccPre, [<<"%% coding: UTF-8\n �.\n">>]),
+ Inc = [{includefile,YeccPre}],
+ {error,[{_,[{2,yecc,cannot_parse}]}],[]} =
+ yecc:file(Filename, Inc ++ Ret),
+
+ ok = file:write_file(Filename,
+ <<"%% coding: UTF-8
+ Nonterminals Hopp.
+ Terminals t.
+ Rootsymbol \"örn_Ѐ\".
+ Hopp -> t : '$1'.">>),
+ {error,[{Filename,[{4,yecc,{bad_symbol,"�rn_"++[1024]}}]}],[]} =
+ yecc:file(Filename, Ret),
+
+ ok = file:write_file(Filename,
+ <<"%% coding: UTF-8
+ Nonterminals Hopp.
+ Terminals t.
+ Rootsymbol Hopp.
+ Endsymbol \"örn_Ѐ\".
+ Hopp -> t : '$1'.">>),
+ {error,[{Filename,[{5,yecc,{bad_symbol,"�rn_"++[1024]}}]}],[]} =
+ yecc:file(Filename, Ret),
+
+ ok = file:write_file(Filename,
+ <<"%% coding: UTF-8
+ Nonterminals Hopp.
+ Terminals t.
+ Rootsymbol Hopp.
+ Expect \"örn_Ѐ\".
+ Hopp -> t : '$1'.">>),
+ {error,[{Filename,[{5,yecc,{bad_symbol,"�rn_"++[1024]}}]}],[]} =
+ yecc:file(Filename, Ret),
+
+ ok = file:write_file(Filename,
+ <<"%% coding: UTF-8
+ Nonterminals Hopp.
+ Terminals t.
+ Rootsymbol Hopp.
+ States \"örn_Ѐ\".
+ Hopp -> t : '$1'.">>),
+ {error,[{Filename,[{5,yecc,{bad_symbol,"�rn_"++[1024]}}]}],[]} =
+ yecc:file(Filename, Ret),
+
+ Ts = [{otp_10302_1,<<"
+ %% coding: UTF-8
+ Header \"%% örn_Ѐ\" \"%% \\x{400}B\".
+ Nonterminals Häpp list.
+ Terminals element.
+ Rootsymbol Häpp.
+
+ Häpp -> list : '$1'.
+
+ list -> element : '$1'.
+ list -> list element :
+ begin
+ Häpp = foo,
+ {Häpp, 'Häpp',\"\\x{400}B\",\"örn_Ѐ\"}
+ end.
+
+ Erlang code.
+
+ -export([t/0]).
+
+ t() ->
+ L = [{element, 1}, {element,2}],
+ {ok, R} = parse(L),
+ Häpp = foo,
+ {_,_,[1024,66],[246,114,110,95,1024]} = R,
+ {Häpp,'Häpp',\"\\x{400}B\",\"örn_Ѐ\"} = R,
+ ok.
+ ">>,default,ok},
+ {otp_10302_2,<<"
+ %% coding: Latin-1
+ Nonterminals H�pp list.
+ Terminals element.
+ Rootsymbol H�pp.
+
+ H�pp -> list : '$1'.
+
+ list -> element : '$1'.
+ list -> list element :
+ begin
+ H�pp = foo,
+ {H�pp, 'H�pp',\"\\x{400}B\",\"örn_Ѐ\"}
+ end.
+
+ Erlang code.
+
+ -export([t/0]).
+
+ t() ->
+ L = [{element, 1}, {element,2}],
+ {ok, R} = parse(L),
+ H�pp = foo,
+ {_,_,[1024,66],[195,182,114,110,95,208,128]} = R,
+ {H�pp,'H�pp',\"\\x{400}B\",\"örn_Ѐ\"} = R,
+ ok.
+ ">>,default,ok}],
+ run(Config, Ts),
+ ok.
+
yeccpre_size() ->
yeccpre_size(default_yeccpre()).
diff --git a/lib/percept/doc/src/notes.xml b/lib/percept/doc/src/notes.xml
index 1ac1a5ab62..dd70cfe994 100644
--- a/lib/percept/doc/src/notes.xml
+++ b/lib/percept/doc/src/notes.xml
@@ -32,6 +32,21 @@
</header>
<p>This document describes the changes made to the Percept application.</p>
+<section><title>Percept 0.8.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Add missing modules in app-file</p>
+ <p>
+ Own Id: OTP-10439</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Percept 0.8.6.1</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/percept/src/Makefile b/lib/percept/src/Makefile
index 253a8c2da3..6bf0af9dc6 100644
--- a/lib/percept/src/Makefile
+++ b/lib/percept/src/Makefile
@@ -80,10 +80,10 @@ clean:
rm -f errs core *~
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
docs:
diff --git a/lib/percept/src/percept.app.src b/lib/percept/src/percept.app.src
index 7b20093ece..cf4a9fc438 100644
--- a/lib/percept/src/percept.app.src
+++ b/lib/percept/src/percept.app.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
%%
%% The 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/percept/vsn.mk b/lib/percept/vsn.mk
index 9267a41055..f868246f7b 100644
--- a/lib/percept/vsn.mk
+++ b/lib/percept/vsn.mk
@@ -1 +1 @@
-PERCEPT_VSN = 0.8.6.1
+PERCEPT_VSN = 0.8.7
diff --git a/lib/pman/src/Makefile b/lib/pman/src/Makefile
index fa01fe7238..eb0413bdbc 100644
--- a/lib/pman/src/Makefile
+++ b/lib/pman/src/Makefile
@@ -85,10 +85,10 @@ clean:
rm -f errs core *~
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
docs:
diff --git a/lib/public_key/asn1/AuthenticationFramework.asn1 b/lib/public_key/asn1/AuthenticationFramework.asn1
new file mode 100644
index 0000000000..3754486473
--- /dev/null
+++ b/lib/public_key/asn1/AuthenticationFramework.asn1
@@ -0,0 +1,367 @@
+AuthenticationFramework {joint-iso-itu-t ds(5) module(1)
+ authenticationFramework(7) 6} DEFINITIONS ::=
+BEGIN
+
+-- EXPORTS All
+-- The types and values defined in this module are exported for use in the other ASN.1 modules contained
+-- within the Directory Specifications, and for the use of other applications which will use them to access
+-- Directory services. Other applications may use them for their own purposes, but this will not constrain
+-- extensions and modifications needed to maintain or improve the Directory service.
+IMPORTS
+ id-at, id-nf, id-oc, informationFramework, selectedAttributeTypes,
+ basicAccessControl, certificateExtensions
+ FROM UsefulDefinitions {joint-iso-itu-t ds(5) module(1)
+ usefulDefinitions(0) 6}
+ Name, ATTRIBUTE, OBJECT-CLASS, NAME-FORM, top
+ FROM InformationFramework informationFramework
+ UniqueIdentifier, octetStringMatch, commonName, UnboundedDirectoryString
+ FROM SelectedAttributeTypes selectedAttributeTypes
+ certificateExactMatch, certificatePairExactMatch, certificateListExactMatch,
+ KeyUsage, GeneralNames, CertificatePoliciesSyntax,
+ algorithmIdentifierMatch, CertPolicyId
+ FROM CertificateExtensions certificateExtensions;
+
+-- parameterized types
+ENCRYPTED{ToBeEnciphered} ::=
+ BIT STRING
+ (CONSTRAINED BY {
+ -- shall be the result of applying an encipherment procedure
+ -- to the BER-encoded octets of a value of --ToBeEnciphered})
+
+HASH{ToBeHashed} ::= SEQUENCE {
+ algorithmIdentifier AlgorithmIdentifier{{SupportedAlgorithms}},
+ hashValue
+ BIT STRING
+ (CONSTRAINED BY {
+ -- shall be the result of applying a hashing procedure to the DER-encoded octets
+ -- of a value of -- ToBeHashed})
+}
+
+ENCRYPTED-HASH{ToBeSigned} ::=
+ BIT STRING
+ (CONSTRAINED BY {
+ -- shall be the result of applying a hashing procedure to the DER-encoded (see 6.1) octets
+ -- of a value of --ToBeSigned -- and then applying an encipherment procedure to those octets --})
+
+SIGNATURE{ToBeSigned} ::= SEQUENCE {
+ algorithmIdentifier AlgorithmIdentifier{{SupportedAlgorithms}},
+ encrypted ENCRYPTED-HASH{ToBeSigned}
+}
+
+SIGNED{ToBeSigned} ::= SEQUENCE {
+ toBeSigned ToBeSigned,
+ COMPONENTS OF SIGNATURE{ToBeSigned}
+}
+
+-- public-key certificate definition
+Certificate ::= SIGNED{CertificateContent}
+
+CertificateContent ::= SEQUENCE {
+ version [0] Version DEFAULT v1,
+ serialNumber CertificateSerialNumber,
+ signature AlgorithmIdentifier{{SupportedAlgorithms}},
+ issuer Name,
+ validity Validity,
+ subject Name,
+ subjectPublicKeyInfo SubjectPublicKeyInfo,
+ issuerUniqueIdentifier [1] IMPLICIT UniqueIdentifier OPTIONAL,
+ -- if present, version shall be v2 or v3
+ subjectUniqueIdentifier [2] IMPLICIT UniqueIdentifier OPTIONAL,
+ -- if present, version shall be v2 or v3
+ extensions [3] Extensions OPTIONAL
+ -- If present, version shall be v3
+}
+
+Version ::= INTEGER {v1(0), v2(1), v3(2)}
+
+CertificateSerialNumber ::= INTEGER
+
+AlgorithmIdentifier{ALGORITHM:SupportedAlgorithms} ::= SEQUENCE {
+ algorithm ALGORITHM.&id({SupportedAlgorithms}),
+ parameters ALGORITHM.&Type({SupportedAlgorithms}{@algorithm}) OPTIONAL
+}
+
+-- Definition of the following information object set is deferred, perhaps to standardized
+-- profiles or to protocol implementation conformance statements. The set is required to
+-- specify a table constraint on the parameters component of AlgorithmIdentifier.
+SupportedAlgorithms ALGORITHM ::=
+ {...}
+
+Validity ::= SEQUENCE {notBefore Time,
+ notAfter Time
+}
+
+SubjectPublicKeyInfo ::= SEQUENCE {
+ algorithm AlgorithmIdentifier{{SupportedAlgorithms}},
+ subjectPublicKey BIT STRING
+}
+
+Time ::= CHOICE {utcTime UTCTime,
+ generalizedTime GeneralizedTime
+}
+
+Extensions ::= SEQUENCE OF Extension
+
+-- For those extensions where ordering of individual extensions within the SEQUENCE is significant, the
+-- specification of those individual extensions shall include the rules for the significance of the order therein
+Extension ::= SEQUENCE {
+ extnId EXTENSION.&id({ExtensionSet}),
+ critical BOOLEAN DEFAULT FALSE,
+ extnValue
+ OCTET STRING
+ (CONTAINING EXTENSION.&ExtnType({ExtensionSet}{@extnId})
+ ENCODED BY
+ der)
+}
+
+der OBJECT IDENTIFIER ::=
+ {joint-iso-itu-t asn1(1) ber-derived(2) distinguished-encoding(1)}
+
+ExtensionSet EXTENSION ::=
+ {...}
+
+EXTENSION ::= CLASS {&id OBJECT IDENTIFIER UNIQUE,
+ &ExtnType
+}WITH SYNTAX {SYNTAX &ExtnType
+ IDENTIFIED BY &id
+}
+
+ALGORITHM ::= CLASS {&Type OPTIONAL,
+ &id OBJECT IDENTIFIER UNIQUE
+}WITH SYNTAX {[&Type]
+ IDENTIFIED BY &id
+}
+
+-- other PKI certificate constructs
+Certificates ::= SEQUENCE {
+ userCertificate Certificate,
+ certificationPath ForwardCertificationPath OPTIONAL
+}
+
+CertificationPath ::= SEQUENCE {
+ userCertificate Certificate,
+ theCACertificates SEQUENCE OF CertificatePair OPTIONAL
+}
+
+ForwardCertificationPath ::= SEQUENCE OF CrossCertificates
+
+CrossCertificates ::= SET OF Certificate
+
+PkiPath ::= SEQUENCE OF Certificate
+
+-- certificate revocation list (CRL)
+CertificateList ::=
+ SIGNED{CertificateListContent}
+
+CertificateListContent ::= SEQUENCE {
+ version Version OPTIONAL,
+ -- if present, version shall be v2
+ signature AlgorithmIdentifier{{SupportedAlgorithms}},
+ issuer Name,
+ thisUpdate Time,
+ nextUpdate Time OPTIONAL,
+ revokedCertificates
+ SEQUENCE OF
+ SEQUENCE {serialNumber CertificateSerialNumber,
+ revocationDate Time,
+ crlEntryExtensions Extensions OPTIONAL} OPTIONAL,
+ crlExtensions [0] Extensions OPTIONAL
+}
+
+-- PKI object classes
+pkiUser OBJECT-CLASS ::= {
+ SUBCLASS OF {top}
+ KIND auxiliary
+ MAY CONTAIN {userCertificate}
+ ID id-oc-pkiUser
+}
+
+pkiCA OBJECT-CLASS ::= {
+ SUBCLASS OF {top}
+ KIND auxiliary
+ MAY CONTAIN
+ {cACertificate | certificateRevocationList | authorityRevocationList |
+ crossCertificatePair}
+ ID id-oc-pkiCA
+}
+
+cRLDistributionPoint OBJECT-CLASS ::= {
+ SUBCLASS OF {top}
+ KIND structural
+ MUST CONTAIN {commonName}
+ MAY CONTAIN
+ {certificateRevocationList | authorityRevocationList | deltaRevocationList}
+ ID id-oc-cRLDistributionPoint
+}
+
+cRLDistPtNameForm NAME-FORM ::= {
+ NAMES cRLDistributionPoint
+ WITH ATTRIBUTES {commonName}
+ ID id-nf-cRLDistPtNameForm
+}
+
+deltaCRL OBJECT-CLASS ::= {
+ SUBCLASS OF {top}
+ KIND auxiliary
+ MAY CONTAIN {deltaRevocationList}
+ ID id-oc-deltaCRL
+}
+
+cpCps OBJECT-CLASS ::= {
+ SUBCLASS OF {top}
+ KIND auxiliary
+ MAY CONTAIN {certificatePolicy | certificationPracticeStmt}
+ ID id-oc-cpCps
+}
+
+pkiCertPath OBJECT-CLASS ::= {
+ SUBCLASS OF {top}
+ KIND auxiliary
+ MAY CONTAIN {pkiPath}
+ ID id-oc-pkiCertPath
+}
+
+-- PKI directory attributes
+userCertificate ATTRIBUTE ::= {
+ WITH SYNTAX Certificate
+ EQUALITY MATCHING RULE certificateExactMatch
+ ID id-at-userCertificate
+}
+
+cACertificate ATTRIBUTE ::= {
+ WITH SYNTAX Certificate
+ EQUALITY MATCHING RULE certificateExactMatch
+ ID id-at-cAcertificate
+}
+
+crossCertificatePair ATTRIBUTE ::= {
+ WITH SYNTAX CertificatePair
+ EQUALITY MATCHING RULE certificatePairExactMatch
+ ID id-at-crossCertificatePair
+}
+
+CertificatePair ::= SEQUENCE {
+ forward [0] Certificate OPTIONAL,
+ reverse [1] Certificate OPTIONAL
+ -- at least one of the pair shall be present
+}
+(WITH COMPONENTS {
+ ...,
+ forward PRESENT
+ } | WITH COMPONENTS {
+ ...,
+ reverse PRESENT
+ })
+
+certificateRevocationList ATTRIBUTE ::= {
+ WITH SYNTAX CertificateList
+ EQUALITY MATCHING RULE certificateListExactMatch
+ ID id-at-certificateRevocationList
+}
+
+authorityRevocationList ATTRIBUTE ::= {
+ WITH SYNTAX CertificateList
+ EQUALITY MATCHING RULE certificateListExactMatch
+ ID id-at-authorityRevocationList
+}
+
+deltaRevocationList ATTRIBUTE ::= {
+ WITH SYNTAX CertificateList
+ EQUALITY MATCHING RULE certificateListExactMatch
+ ID id-at-deltaRevocationList
+}
+
+supportedAlgorithms ATTRIBUTE ::= {
+ WITH SYNTAX SupportedAlgorithm
+ EQUALITY MATCHING RULE algorithmIdentifierMatch
+ ID id-at-supportedAlgorithms
+}
+
+SupportedAlgorithm ::= SEQUENCE {
+ algorithmIdentifier AlgorithmIdentifier{{SupportedAlgorithms}},
+ intendedUsage [0] KeyUsage OPTIONAL,
+ intendedCertificatePolicies [1] CertificatePoliciesSyntax OPTIONAL
+}
+
+certificationPracticeStmt ATTRIBUTE ::= {
+ WITH SYNTAX InfoSyntax
+ ID id-at-certificationPracticeStmt
+}
+
+InfoSyntax ::= CHOICE {
+ content UnboundedDirectoryString,
+ pointer SEQUENCE {name GeneralNames,
+ hash HASH{HashedPolicyInfo} OPTIONAL}
+}
+
+POLICY ::= TYPE-IDENTIFIER
+
+HashedPolicyInfo ::= POLICY.&Type({Policies})
+
+Policies POLICY ::=
+ {...} -- Defined by implementors
+
+certificatePolicy ATTRIBUTE ::= {
+ WITH SYNTAX PolicySyntax
+ ID id-at-certificatePolicy
+}
+
+PolicySyntax ::= SEQUENCE {
+ policyIdentifier PolicyID,
+ policySyntax InfoSyntax
+}
+
+PolicyID ::= CertPolicyId
+
+pkiPath ATTRIBUTE ::= {WITH SYNTAX PkiPath
+ ID id-at-pkiPath
+}
+
+userPassword ATTRIBUTE ::= {
+ WITH SYNTAX OCTET STRING(SIZE (0..MAX))
+ EQUALITY MATCHING RULE octetStringMatch
+ ID id-at-userPassword
+}
+
+-- object identifier assignments
+-- object classes
+id-oc-cRLDistributionPoint OBJECT IDENTIFIER ::=
+ {id-oc 19}
+
+id-oc-pkiUser OBJECT IDENTIFIER ::= {id-oc 21}
+
+id-oc-pkiCA OBJECT IDENTIFIER ::= {id-oc 22}
+
+id-oc-deltaCRL OBJECT IDENTIFIER ::= {id-oc 23}
+
+id-oc-cpCps OBJECT IDENTIFIER ::= {id-oc 30}
+
+id-oc-pkiCertPath OBJECT IDENTIFIER ::= {id-oc 31}
+
+-- name forms
+id-nf-cRLDistPtNameForm OBJECT IDENTIFIER ::= {id-nf 14}
+
+-- directory attributes
+id-at-userPassword OBJECT IDENTIFIER ::= {id-at 35}
+
+id-at-userCertificate OBJECT IDENTIFIER ::= {id-at 36}
+
+id-at-cAcertificate OBJECT IDENTIFIER ::= {id-at 37}
+
+id-at-authorityRevocationList OBJECT IDENTIFIER ::= {id-at 38}
+
+id-at-certificateRevocationList OBJECT IDENTIFIER ::= {id-at 39}
+
+id-at-crossCertificatePair OBJECT IDENTIFIER ::= {id-at 40}
+
+id-at-supportedAlgorithms OBJECT IDENTIFIER ::= {id-at 52}
+
+id-at-deltaRevocationList OBJECT IDENTIFIER ::= {id-at 53}
+
+id-at-certificationPracticeStmt OBJECT IDENTIFIER ::= {id-at 68}
+
+id-at-certificatePolicy OBJECT IDENTIFIER ::= {id-at 69}
+
+id-at-pkiPath OBJECT IDENTIFIER ::= {id-at 70}
+
+END -- AuthenticationFramework
diff --git a/lib/public_key/asn1/InformationFramework.asn1 b/lib/public_key/asn1/InformationFramework.asn1
new file mode 100644
index 0000000000..4aed43a39e
--- /dev/null
+++ b/lib/public_key/asn1/InformationFramework.asn1
@@ -0,0 +1,682 @@
+InformationFramework {joint-iso-itu-t ds(5) module(1) informationFramework(1)
+ 6} DEFINITIONS ::=
+BEGIN
+
+-- EXPORTS All
+-- The types and values defined in this module are exported for use in the other ASN.1 modules contained
+-- within the Directory Specifications, and for the use of other applications which will use them to access
+-- Directory services. Other applications may use them for their own purposes, but this will not constrain
+-- extensions and modifications needed to maintain or improve the Directory service.
+IMPORTS
+ -- from ITU-T Rec. X.501 | ISO/IEC 9594-2
+ directoryAbstractService, id-ar, id-at, id-mr, id-nf, id-oa, id-oc,
+ id-sc, selectedAttributeTypes, serviceAdministration
+ FROM UsefulDefinitions {joint-iso-itu-t ds(5) module(1)
+ usefulDefinitions(0) 6}
+ SearchRule
+ FROM ServiceAdministration serviceAdministration
+ -- from ITU-T Rec. X.511 | ISO/IEC 9594-3
+ TypeAndContextAssertion
+ FROM DirectoryAbstractService directoryAbstractService
+ -- from ITU-T Rec. X.520 | ISO/IEC 9594-6
+ booleanMatch, commonName, generalizedTimeMatch, generalizedTimeOrderingMatch,
+ integerFirstComponentMatch, integerMatch, integerOrderingMatch,
+ objectIdentifierFirstComponentMatch, UnboundedDirectoryString
+ FROM SelectedAttributeTypes selectedAttributeTypes;
+
+-- attribute data types
+Attribute{ATTRIBUTE:SupportedAttributes} ::= SEQUENCE {
+ type ATTRIBUTE.&id({SupportedAttributes}),
+ values
+ SET SIZE (0..MAX) OF ATTRIBUTE.&Type({SupportedAttributes}{@type}),
+ valuesWithContext
+ SET SIZE (1..MAX) OF
+ SEQUENCE {value ATTRIBUTE.&Type({SupportedAttributes}{@type}),
+ contextList SET SIZE (1..MAX) OF Context} OPTIONAL
+}
+
+AttributeType ::= ATTRIBUTE.&id
+
+AttributeValue ::= ATTRIBUTE.&Type
+
+Context ::= SEQUENCE {
+ contextType CONTEXT.&id({SupportedContexts}),
+ contextValues
+ SET SIZE (1..MAX) OF CONTEXT.&Type({SupportedContexts}{@contextType}),
+ fallback BOOLEAN DEFAULT FALSE
+}
+
+AttributeValueAssertion ::= SEQUENCE {
+ type ATTRIBUTE.&id({SupportedAttributes}),
+ assertion
+ ATTRIBUTE.&equality-match.&AssertionType
+ ({SupportedAttributes}{@type}),
+ assertedContexts
+ CHOICE {allContexts [0] NULL,
+ selectedContexts [1] SET SIZE (1..MAX) OF ContextAssertion
+ } OPTIONAL
+}
+
+ContextAssertion ::= SEQUENCE {
+ contextType CONTEXT.&id({SupportedContexts}),
+ contextValues
+ SET SIZE (1..MAX) OF
+ CONTEXT.&Assertion({SupportedContexts}{@contextType})
+}
+
+AttributeTypeAssertion ::= SEQUENCE {
+ type ATTRIBUTE.&id({SupportedAttributes}),
+ assertedContexts SEQUENCE SIZE (1..MAX) OF ContextAssertion OPTIONAL
+}
+
+-- Definition of the following information object set is deferred, perhaps to standardized
+-- profiles or to protocol implementation conformance statements. The set is required to
+-- specify a table constraint on the values component of Attribute, the value component
+-- of AttributeTypeAndValue, and the assertion component of AttributeValueAssertion.
+SupportedAttributes ATTRIBUTE ::=
+ {objectClass | aliasedEntryName, ...}
+
+-- Definition of the following information object set is deferred, perhaps to standardized
+-- profiles or to protocol implementation conformance statements. The set is required to
+-- specify a table constraint on the context specifications
+SupportedContexts CONTEXT ::=
+ {...}
+
+-- naming data types
+Name ::= CHOICE { -- only one possibility for now --rdnSequence RDNSequence
+}
+
+RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+
+DistinguishedName ::= RDNSequence
+
+RelativeDistinguishedName ::=
+ SET SIZE (1..MAX) OF AttributeTypeAndDistinguishedValue
+
+AttributeTypeAndDistinguishedValue ::= SEQUENCE {
+ type ATTRIBUTE.&id({SupportedAttributes}),
+ value ATTRIBUTE.&Type({SupportedAttributes}{@type}),
+ primaryDistinguished BOOLEAN DEFAULT TRUE,
+ valuesWithContext
+ SET SIZE (1..MAX) OF
+ SEQUENCE {distingAttrValue
+ [0] ATTRIBUTE.&Type({SupportedAttributes}{@type})
+ OPTIONAL,
+ contextList SET SIZE (1..MAX) OF Context} OPTIONAL
+}
+
+-- subtree data types
+SubtreeSpecification ::= SEQUENCE {
+ base [0] LocalName DEFAULT {},
+ COMPONENTS OF ChopSpecification,
+ specificationFilter [4] Refinement OPTIONAL
+}
+
+-- empty sequence specifies whole administrative area
+LocalName ::= RDNSequence
+
+ChopSpecification ::= SEQUENCE {
+ specificExclusions
+ [1] SET SIZE (1..MAX) OF
+ CHOICE {chopBefore [0] LocalName,
+ chopAfter [1] LocalName} OPTIONAL,
+ minimum [2] BaseDistance DEFAULT 0,
+ maximum [3] BaseDistance OPTIONAL
+}
+
+BaseDistance ::= INTEGER(0..MAX)
+
+Refinement ::= CHOICE {
+ item [0] OBJECT-CLASS.&id,
+ and [1] SET SIZE (1..MAX) OF Refinement,
+ or [2] SET SIZE (1..MAX) OF Refinement,
+ not [3] Refinement
+}
+
+-- OBJECT-CLASS information object class specification
+OBJECT-CLASS ::= CLASS {
+ &Superclasses OBJECT-CLASS OPTIONAL,
+ &kind ObjectClassKind DEFAULT structural,
+ &MandatoryAttributes ATTRIBUTE OPTIONAL,
+ &OptionalAttributes ATTRIBUTE OPTIONAL,
+ &id OBJECT IDENTIFIER UNIQUE
+}
+WITH SYNTAX {
+ [SUBCLASS OF &Superclasses]
+ [KIND &kind]
+ [MUST CONTAIN &MandatoryAttributes]
+ [MAY CONTAIN &OptionalAttributes]
+ ID &id
+}
+
+ObjectClassKind ::= ENUMERATED {abstract(0), structural(1), auxiliary(2)}
+
+-- object classes
+top OBJECT-CLASS ::= {
+ KIND abstract
+ MUST CONTAIN {objectClass}
+ ID id-oc-top
+}
+
+alias OBJECT-CLASS ::= {
+ SUBCLASS OF {top}
+ MUST CONTAIN {aliasedEntryName}
+ ID id-oc-alias
+}
+
+parent OBJECT-CLASS ::= {KIND abstract
+ ID id-oc-parent
+}
+
+child OBJECT-CLASS ::= {KIND auxiliary
+ ID id-oc-child
+}
+
+-- ATTRIBUTE information object class specification
+ATTRIBUTE ::= CLASS {
+ &derivation ATTRIBUTE OPTIONAL,
+ &Type OPTIONAL, -- either &Type or &derivation required
+ &equality-match MATCHING-RULE OPTIONAL,
+ &ordering-match MATCHING-RULE OPTIONAL,
+ &substrings-match MATCHING-RULE OPTIONAL,
+ &single-valued BOOLEAN DEFAULT FALSE,
+ &collective BOOLEAN DEFAULT FALSE,
+ &dummy BOOLEAN DEFAULT FALSE,
+ -- operational extensions
+ &no-user-modification BOOLEAN DEFAULT FALSE,
+ &usage AttributeUsage DEFAULT userApplications,
+ &id OBJECT IDENTIFIER UNIQUE
+}
+WITH SYNTAX {
+ [SUBTYPE OF &derivation]
+ [WITH SYNTAX &Type]
+ [EQUALITY MATCHING RULE &equality-match]
+ [ORDERING MATCHING RULE &ordering-match]
+ [SUBSTRINGS MATCHING RULE &substrings-match]
+ [SINGLE VALUE &single-valued]
+ [COLLECTIVE &collective]
+ [DUMMY &dummy]
+ [NO USER MODIFICATION &no-user-modification]
+ [USAGE &usage]
+ ID &id
+}
+
+AttributeUsage ::= ENUMERATED {
+ userApplications(0), directoryOperation(1), distributedOperation(2),
+ dSAOperation(3)}
+
+-- attributes
+objectClass ATTRIBUTE ::= {
+ WITH SYNTAX OBJECT IDENTIFIER
+ EQUALITY MATCHING RULE objectIdentifierMatch
+ ID id-at-objectClass
+}
+
+aliasedEntryName ATTRIBUTE ::= {
+ WITH SYNTAX DistinguishedName
+ EQUALITY MATCHING RULE distinguishedNameMatch
+ SINGLE VALUE TRUE
+ ID id-at-aliasedEntryName
+}
+
+-- MATCHING-RULE information object class specification
+MATCHING-RULE ::= CLASS {
+ &ParentMatchingRules MATCHING-RULE OPTIONAL,
+ &AssertionType OPTIONAL,
+ &uniqueMatchIndicator ATTRIBUTE OPTIONAL,
+ &id OBJECT IDENTIFIER UNIQUE
+}
+WITH SYNTAX {
+ [PARENT &ParentMatchingRules]
+ [SYNTAX &AssertionType]
+ [UNIQUE-MATCH-INDICATOR &uniqueMatchIndicator]
+ ID &id
+}
+
+-- matching rules
+objectIdentifierMatch MATCHING-RULE ::= {
+ SYNTAX OBJECT IDENTIFIER
+ ID id-mr-objectIdentifierMatch
+}
+
+distinguishedNameMatch MATCHING-RULE ::= {
+ SYNTAX DistinguishedName
+ ID id-mr-distinguishedNameMatch
+}
+
+MAPPING-BASED-MATCHING{SelectedBy, BOOLEAN:combinable, MappingResult,
+ OBJECT IDENTIFIER:matchingRule} ::= CLASS {
+ &selectBy SelectedBy OPTIONAL,
+ &ApplicableTo ATTRIBUTE,
+ &subtypesIncluded BOOLEAN DEFAULT TRUE,
+ &combinable BOOLEAN(combinable),
+ &mappingResults MappingResult OPTIONAL,
+ &userControl BOOLEAN DEFAULT FALSE,
+ &exclusive BOOLEAN DEFAULT TRUE,
+ &matching-rule MATCHING-RULE.&id(matchingRule),
+ &id OBJECT IDENTIFIER UNIQUE
+}
+WITH SYNTAX {
+ [SELECT BY &selectBy]
+ APPLICABLE TO &ApplicableTo
+ [SUBTYPES INCLUDED &subtypesIncluded]
+ COMBINABLE &combinable
+ [MAPPING RESULTS &mappingResults]
+ [USER CONTROL &userControl]
+ [EXCLUSIVE &exclusive]
+ MATCHING RULE &matching-rule
+ ID &id
+}
+
+-- NAME-FORM information object class specification
+NAME-FORM ::= CLASS {
+ &namedObjectClass OBJECT-CLASS,
+ &MandatoryAttributes ATTRIBUTE,
+ &OptionalAttributes ATTRIBUTE OPTIONAL,
+ &id OBJECT IDENTIFIER UNIQUE
+}
+WITH SYNTAX {
+ NAMES &namedObjectClass
+ WITH ATTRIBUTES &MandatoryAttributes
+ [AND OPTIONALLY &OptionalAttributes]
+ ID &id
+}
+
+-- STRUCTURE-RULE class and DIT structure rule data types
+DITStructureRule ::= SEQUENCE {
+ ruleIdentifier RuleIdentifier,
+ -- shall be unique within the scope of the subschema
+ nameForm NAME-FORM.&id,
+ superiorStructureRules SET SIZE (1..MAX) OF RuleIdentifier OPTIONAL
+}
+
+RuleIdentifier ::= INTEGER
+
+STRUCTURE-RULE ::= CLASS {
+ &nameForm NAME-FORM,
+ &SuperiorStructureRules STRUCTURE-RULE OPTIONAL,
+ &id RuleIdentifier
+}
+WITH SYNTAX {
+ NAME FORM &nameForm
+ [SUPERIOR RULES &SuperiorStructureRules]
+ ID &id
+}
+
+-- DIT content rule data type and CONTENT-RULE class
+DITContentRule ::= SEQUENCE {
+ structuralObjectClass OBJECT-CLASS.&id,
+ auxiliaries SET SIZE (1..MAX) OF OBJECT-CLASS.&id OPTIONAL,
+ mandatory [1] SET SIZE (1..MAX) OF ATTRIBUTE.&id OPTIONAL,
+ optional [2] SET SIZE (1..MAX) OF ATTRIBUTE.&id OPTIONAL,
+ precluded [3] SET SIZE (1..MAX) OF ATTRIBUTE.&id OPTIONAL
+}
+
+CONTENT-RULE ::= CLASS {
+ &structuralClass OBJECT-CLASS.&id UNIQUE,
+ &Auxiliaries OBJECT-CLASS OPTIONAL,
+ &Mandatory ATTRIBUTE OPTIONAL,
+ &Optional ATTRIBUTE OPTIONAL,
+ &Precluded ATTRIBUTE OPTIONAL
+}
+WITH SYNTAX {
+ STRUCTURAL OBJECT-CLASS &structuralClass
+ [AUXILIARY OBJECT-CLASSES &Auxiliaries]
+ [MUST CONTAIN &Mandatory]
+ [MAY CONTAIN &Optional]
+ [MUST-NOT CONTAIN &Precluded]
+}
+
+CONTEXT ::= CLASS {
+ &Type ,
+ &DefaultValue OPTIONAL,
+ &Assertion OPTIONAL,
+ &absentMatch BOOLEAN DEFAULT TRUE,
+ &id OBJECT IDENTIFIER UNIQUE
+}
+WITH SYNTAX {
+ WITH SYNTAX &Type
+ [DEFAULT-VALUE &DefaultValue]
+ [ASSERTED AS &Assertion]
+ [ABSENT-MATCH &absentMatch]
+ ID &id
+}
+
+DITContextUse ::= SEQUENCE {
+ attributeType ATTRIBUTE.&id,
+ mandatoryContexts [1] SET SIZE (1..MAX) OF CONTEXT.&id OPTIONAL,
+ optionalContexts [2] SET SIZE (1..MAX) OF CONTEXT.&id OPTIONAL
+}
+
+DIT-CONTEXT-USE-RULE ::= CLASS {
+ &attributeType ATTRIBUTE.&id UNIQUE,
+ &Mandatory CONTEXT OPTIONAL,
+ &Optional CONTEXT OPTIONAL
+}
+WITH SYNTAX {
+ ATTRIBUTE TYPE &attributeType
+ [MANDATORY CONTEXTS &Mandatory]
+ [OPTIONAL CONTEXTS &Optional]
+}
+
+FRIENDS ::= CLASS {
+ &anchor ATTRIBUTE.&id UNIQUE,
+ &Friends ATTRIBUTE
+}WITH SYNTAX {ANCHOR &anchor
+ FRIENDS &Friends
+}
+
+-- system schema information objects
+-- object classes
+subentry OBJECT-CLASS ::= {
+ SUBCLASS OF {top}
+ KIND structural
+ MUST CONTAIN {commonName | subtreeSpecification}
+ ID id-sc-subentry
+}
+
+subentryNameForm NAME-FORM ::= {
+ NAMES subentry
+ WITH ATTRIBUTES {commonName}
+ ID id-nf-subentryNameForm
+}
+
+subtreeSpecification ATTRIBUTE ::= {
+ WITH SYNTAX SubtreeSpecification
+ USAGE directoryOperation
+ ID id-oa-subtreeSpecification
+}
+
+administrativeRole ATTRIBUTE ::= {
+ WITH SYNTAX OBJECT-CLASS.&id
+ EQUALITY MATCHING RULE objectIdentifierMatch
+ USAGE directoryOperation
+ ID id-oa-administrativeRole
+}
+
+createTimestamp ATTRIBUTE ::= {
+ WITH SYNTAX GeneralizedTime
+ -- as per 46.3 b) or c) of ITU-T Rec. X.680 | ISO/IEC 8824-1
+ EQUALITY MATCHING RULE generalizedTimeMatch
+ ORDERING MATCHING RULE generalizedTimeOrderingMatch
+ SINGLE VALUE TRUE
+ NO USER MODIFICATION TRUE
+ USAGE directoryOperation
+ ID id-oa-createTimestamp
+}
+
+modifyTimestamp ATTRIBUTE ::= {
+ WITH SYNTAX GeneralizedTime
+ -- as per 46.3 b) or c) of ITU-T Rec. X.680 | ISO/IEC 8824-1
+ EQUALITY MATCHING RULE generalizedTimeMatch
+ ORDERING MATCHING RULE generalizedTimeOrderingMatch
+ SINGLE VALUE TRUE
+ NO USER MODIFICATION TRUE
+ USAGE directoryOperation
+ ID id-oa-modifyTimestamp
+}
+
+subschemaTimestamp ATTRIBUTE ::= {
+ WITH SYNTAX GeneralizedTime
+ -- as per 46.3 b) or c) of ITU-T Rec. X.680 | ISO/IEC 8824-1
+ EQUALITY MATCHING RULE generalizedTimeMatch
+ ORDERING MATCHING RULE generalizedTimeOrderingMatch
+ SINGLE VALUE TRUE
+ NO USER MODIFICATION TRUE
+ USAGE directoryOperation
+ ID id-oa-subschemaTimestamp
+}
+
+creatorsName ATTRIBUTE ::= {
+ WITH SYNTAX DistinguishedName
+ EQUALITY MATCHING RULE distinguishedNameMatch
+ SINGLE VALUE TRUE
+ NO USER MODIFICATION TRUE
+ USAGE directoryOperation
+ ID id-oa-creatorsName
+}
+
+modifiersName ATTRIBUTE ::= {
+ WITH SYNTAX DistinguishedName
+ EQUALITY MATCHING RULE distinguishedNameMatch
+ SINGLE VALUE TRUE
+ NO USER MODIFICATION TRUE
+ USAGE directoryOperation
+ ID id-oa-modifiersName
+}
+
+subschemaSubentryList ATTRIBUTE ::= {
+ WITH SYNTAX DistinguishedName
+ EQUALITY MATCHING RULE distinguishedNameMatch
+ SINGLE VALUE TRUE
+ NO USER MODIFICATION TRUE
+ USAGE directoryOperation
+ ID id-oa-subschemaSubentryList
+}
+
+accessControlSubentryList ATTRIBUTE ::= {
+ WITH SYNTAX DistinguishedName
+ EQUALITY MATCHING RULE distinguishedNameMatch
+ NO USER MODIFICATION TRUE
+ USAGE directoryOperation
+ ID id-oa-accessControlSubentryList
+}
+
+collectiveAttributeSubentryList ATTRIBUTE ::= {
+ WITH SYNTAX DistinguishedName
+ EQUALITY MATCHING RULE distinguishedNameMatch
+ NO USER MODIFICATION TRUE
+ USAGE directoryOperation
+ ID id-oa-collectiveAttributeSubentryList
+}
+
+contextDefaultSubentryList ATTRIBUTE ::= {
+ WITH SYNTAX DistinguishedName
+ EQUALITY MATCHING RULE distinguishedNameMatch
+ NO USER MODIFICATION TRUE
+ USAGE directoryOperation
+ ID id-oa-contextDefaultSubentryList
+}
+
+serviceAdminSubentryList ATTRIBUTE ::= {
+ WITH SYNTAX DistinguishedName
+ EQUALITY MATCHING RULE distinguishedNameMatch
+ NO USER MODIFICATION TRUE
+ USAGE directoryOperation
+ ID id-oa-serviceAdminSubentryList
+}
+
+hasSubordinates ATTRIBUTE ::= {
+ WITH SYNTAX BOOLEAN
+ EQUALITY MATCHING RULE booleanMatch
+ SINGLE VALUE TRUE
+ NO USER MODIFICATION TRUE
+ USAGE directoryOperation
+ ID id-oa-hasSubordinates
+}
+
+accessControlSubentry OBJECT-CLASS ::= {
+ KIND auxiliary
+ ID id-sc-accessControlSubentry
+}
+
+collectiveAttributeSubentry OBJECT-CLASS ::= {
+ KIND auxiliary
+ ID id-sc-collectiveAttributeSubentry
+}
+
+collectiveExclusions ATTRIBUTE ::= {
+ WITH SYNTAX OBJECT IDENTIFIER
+ EQUALITY MATCHING RULE objectIdentifierMatch
+ USAGE directoryOperation
+ ID id-oa-collectiveExclusions
+}
+
+contextAssertionSubentry OBJECT-CLASS ::= {
+ KIND auxiliary
+ MUST CONTAIN {contextAssertionDefaults}
+ ID id-sc-contextAssertionSubentry
+}
+
+contextAssertionDefaults ATTRIBUTE ::= {
+ WITH SYNTAX TypeAndContextAssertion
+ EQUALITY MATCHING RULE objectIdentifierFirstComponentMatch
+ USAGE directoryOperation
+ ID id-oa-contextAssertionDefault
+}
+
+serviceAdminSubentry OBJECT-CLASS ::= {
+ KIND auxiliary
+ MUST CONTAIN {searchRules}
+ ID id-sc-serviceAdminSubentry
+}
+
+searchRules ATTRIBUTE ::= {
+ WITH SYNTAX SearchRuleDescription
+ EQUALITY MATCHING RULE integerFirstComponentMatch
+ USAGE directoryOperation
+ ID id-oa-searchRules
+}
+
+SearchRuleDescription ::= SEQUENCE {
+ COMPONENTS OF SearchRule,
+ name [28] SET SIZE (1..MAX) OF UnboundedDirectoryString OPTIONAL,
+ description [29] UnboundedDirectoryString OPTIONAL
+}
+
+hierarchyLevel ATTRIBUTE ::= {
+ WITH SYNTAX HierarchyLevel
+ EQUALITY MATCHING RULE integerMatch
+ ORDERING MATCHING RULE integerOrderingMatch
+ SINGLE VALUE TRUE
+ NO USER MODIFICATION TRUE
+ USAGE directoryOperation
+ ID id-oa-hierarchyLevel
+}
+
+HierarchyLevel ::= INTEGER
+
+hierarchyBelow ATTRIBUTE ::= {
+ WITH SYNTAX HierarchyBelow
+ EQUALITY MATCHING RULE booleanMatch
+ SINGLE VALUE TRUE
+ NO USER MODIFICATION TRUE
+ USAGE directoryOperation
+ ID id-oa-hierarchyBelow
+}
+
+HierarchyBelow ::= BOOLEAN
+
+hierarchyParent ATTRIBUTE ::= {
+ WITH SYNTAX DistinguishedName
+ EQUALITY MATCHING RULE distinguishedNameMatch
+ SINGLE VALUE TRUE
+ USAGE directoryOperation
+ ID id-oa-hierarchyParent
+}
+
+hierarchyTop ATTRIBUTE ::= {
+ WITH SYNTAX DistinguishedName
+ EQUALITY MATCHING RULE distinguishedNameMatch
+ SINGLE VALUE TRUE
+ USAGE directoryOperation
+ ID id-oa-hierarchyTop
+}
+
+-- object identifier assignments
+-- object classes
+id-oc-top OBJECT IDENTIFIER ::=
+ {id-oc 0}
+
+id-oc-alias OBJECT IDENTIFIER ::= {id-oc 1}
+
+id-oc-parent OBJECT IDENTIFIER ::= {id-oc 28}
+
+id-oc-child OBJECT IDENTIFIER ::= {id-oc 29}
+
+-- attributes
+id-at-objectClass OBJECT IDENTIFIER ::= {id-at 0}
+
+id-at-aliasedEntryName OBJECT IDENTIFIER ::= {id-at 1}
+
+-- matching rules
+id-mr-objectIdentifierMatch OBJECT IDENTIFIER ::= {id-mr 0}
+
+id-mr-distinguishedNameMatch OBJECT IDENTIFIER ::= {id-mr 1}
+
+-- operational attributes
+id-oa-excludeAllCollectiveAttributes OBJECT IDENTIFIER ::=
+ {id-oa 0}
+
+id-oa-createTimestamp OBJECT IDENTIFIER ::= {id-oa 1}
+
+id-oa-modifyTimestamp OBJECT IDENTIFIER ::= {id-oa 2}
+
+id-oa-creatorsName OBJECT IDENTIFIER ::= {id-oa 3}
+
+id-oa-modifiersName OBJECT IDENTIFIER ::= {id-oa 4}
+
+id-oa-administrativeRole OBJECT IDENTIFIER ::= {id-oa 5}
+
+id-oa-subtreeSpecification OBJECT IDENTIFIER ::= {id-oa 6}
+
+id-oa-collectiveExclusions OBJECT IDENTIFIER ::= {id-oa 7}
+
+id-oa-subschemaTimestamp OBJECT IDENTIFIER ::= {id-oa 8}
+
+id-oa-hasSubordinates OBJECT IDENTIFIER ::= {id-oa 9}
+
+id-oa-subschemaSubentryList OBJECT IDENTIFIER ::= {id-oa 10}
+
+id-oa-accessControlSubentryList OBJECT IDENTIFIER ::= {id-oa 11}
+
+id-oa-collectiveAttributeSubentryList OBJECT IDENTIFIER ::= {id-oa 12}
+
+id-oa-contextDefaultSubentryList OBJECT IDENTIFIER ::= {id-oa 13}
+
+id-oa-contextAssertionDefault OBJECT IDENTIFIER ::= {id-oa 14}
+
+id-oa-serviceAdminSubentryList OBJECT IDENTIFIER ::= {id-oa 15}
+
+id-oa-searchRules OBJECT IDENTIFIER ::= {id-oa 16}
+
+id-oa-hierarchyLevel OBJECT IDENTIFIER ::= {id-oa 17}
+
+id-oa-hierarchyBelow OBJECT IDENTIFIER ::= {id-oa 18}
+
+id-oa-hierarchyParent OBJECT IDENTIFIER ::= {id-oa 19}
+
+id-oa-hierarchyTop OBJECT IDENTIFIER ::= {id-oa 20}
+
+-- subentry classes
+id-sc-subentry OBJECT IDENTIFIER ::= {id-sc 0}
+
+id-sc-accessControlSubentry OBJECT IDENTIFIER ::= {id-sc 1}
+
+id-sc-collectiveAttributeSubentry OBJECT IDENTIFIER ::= {id-sc 2}
+
+id-sc-contextAssertionSubentry OBJECT IDENTIFIER ::= {id-sc 3}
+
+id-sc-serviceAdminSubentry OBJECT IDENTIFIER ::= {id-sc 4}
+
+-- Name forms
+id-nf-subentryNameForm OBJECT IDENTIFIER ::= {id-nf 16}
+
+-- administrative roles
+id-ar-autonomousArea OBJECT IDENTIFIER ::= {id-ar 1}
+
+id-ar-accessControlSpecificArea OBJECT IDENTIFIER ::= {id-ar 2}
+
+id-ar-accessControlInnerArea OBJECT IDENTIFIER ::= {id-ar 3}
+
+id-ar-subschemaAdminSpecificArea OBJECT IDENTIFIER ::= {id-ar 4}
+
+id-ar-collectiveAttributeSpecificArea OBJECT IDENTIFIER ::= {id-ar 5}
+
+id-ar-collectiveAttributeInnerArea OBJECT IDENTIFIER ::= {id-ar 6}
+
+id-ar-contextDefaultSpecificArea OBJECT IDENTIFIER ::= {id-ar 7}
+
+id-ar-serviceSpecificArea OBJECT IDENTIFIER ::= {id-ar 8}
+
+END -- InformationFramework
diff --git a/lib/public_key/asn1/Makefile b/lib/public_key/asn1/Makefile
index 4bd043ee5d..f765906b3b 100644
--- a/lib/public_key/asn1/Makefile
+++ b/lib/public_key/asn1/Makefile
@@ -40,7 +40,8 @@ RELSYSDIR = $(RELEASE_PATH)/lib/public_key-$(VSN)
ASN_TOP = OTP-PUB-KEY PKCS-FRAME
ASN_MODULES = PKIX1Explicit88 PKIX1Implicit88 PKIX1Algorithms88 \
- PKIXAttributeCertificate PKCS-1 PKCS-3 PKCS-8 PKCS5v2-0 OTP-PKIX
+ PKIXAttributeCertificate PKCS-1 PKCS-3 PKCS-7 PKCS-8 PKCS-10 PKCS5v2-0 OTP-PKIX \
+ InformationFramework
ASN_ASNS = $(ASN_MODULES:%=%.asn1)
ASN_ERLS = $(ASN_TOP:%=%.erl)
ASN_HRLS = $(ASN_TOP:%=%.hrl)
@@ -65,7 +66,7 @@ EBIN = ../ebin
EXTRA_ERLC_FLAGS =
ERL_COMPILE_FLAGS += $(EXTRA_ERLC_FLAGS)
-ASN_FLAGS = -bber_bin +der +compact_bit_string +optimize +noobj +asn1config +inline +nif
+ASN_FLAGS = -bber +der +compact_bit_string +noobj +asn1config +inline
# ----------------------------------------------------
# Targets
@@ -80,10 +81,10 @@ clean:
docs:
%.erl %.hrl: %.set.asn
- erlc $(ASN_FLAGS) $<
+ $(asn_verbose)erlc $(ASN_FLAGS) $<
$(INCLUDE)/%.hrl: %.hrl
- cp -p $< $@
+ $(gen_verbose)cp -p $< $@
# ----------------------------------------------------
# Release Target
@@ -112,9 +113,12 @@ OTP-PUB-KEY.asn1db: PKIX1Algorithms88.asn1 \
PKIXAttributeCertificate.asn1 \
PKCS-1.asn1\
PKCS-3.asn1\
+ PKCS-7.asn1\
+ PKCS-10.asn1\
+ InformationFramework.asn1\
OTP-PKIX.asn1
$(EBIN)/PKCS-FRAME.beam: PKCS-FRAME.erl PKCS-FRAME.hrl
-PKCS-FRAME.erl PKCS-FRAME.hrl: PKCS-FRAME.asn1db
-PKCS-FRAME.asn1db: PKCS-8.asn1\
- PKCS5v2-0.asn1 \ No newline at end of file
+PKCS-FRAME.erl PKCS-FRAME.hrl: PKCS-FRAME.asn1db
+PKCS-FRAME.asn1db: PKCS5v2-0.asn1\
+ PKCS-8.asn1\
diff --git a/lib/public_key/asn1/OTP-PUB-KEY.asn1config b/lib/public_key/asn1/OTP-PUB-KEY.asn1config
index 86f4c54748..9ca30564af 100644
--- a/lib/public_key/asn1/OTP-PUB-KEY.asn1config
+++ b/lib/public_key/asn1/OTP-PUB-KEY.asn1config
@@ -1,2 +1,3 @@
{exclusive_decode,{'OTP-PUB-KEY',
- [{decode_TBSCert_exclusive,['Certificate',[{tbsCertificate,undecoded}]]}]}}.
+ [{decode_TBSCert_exclusive,['Certificate',[{tbsCertificate,undecoded}]]},
+ {decode_TBSCertList_exclusive,['CertificateList',[{tbsCertList,undecoded}]]}]}}.
diff --git a/lib/public_key/asn1/OTP-PUB-KEY.set.asn b/lib/public_key/asn1/OTP-PUB-KEY.set.asn
index 5c76d13115..f8fb318c93 100644
--- a/lib/public_key/asn1/OTP-PUB-KEY.set.asn
+++ b/lib/public_key/asn1/OTP-PUB-KEY.set.asn
@@ -6,3 +6,5 @@ PKIX1Algorithms88.asn1
PKCS-1.asn1
PKCS-3.asn1
DSS.asn1
+PKCS-7.asn1
+PKCS-10.asn1
diff --git a/lib/public_key/asn1/PKCS-10.asn1 b/lib/public_key/asn1/PKCS-10.asn1
new file mode 100644
index 0000000000..333104d230
--- /dev/null
+++ b/lib/public_key/asn1/PKCS-10.asn1
@@ -0,0 +1,70 @@
+PKCS-10 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1)
+pkcs-10(10) modules(1) pkcs-10(1)}
+
+-- $Revision: 1.3 $ --
+
+DEFINITIONS IMPLICIT TAGS ::=
+
+BEGIN
+
+-- EXPORTS All --
+-- All types and values defined in this module are exported for use
+-- in other ASN.1 modules.
+
+IMPORTS
+
+--informationFramework, authenticationFramework
+-- FROM UsefulDefinitions {joint-iso-itu-t(2) ds(5) module(1)
+-- usefulDefinitions(0) 3}
+
+ ATTRIBUTE
+ FROM InformationFramework informationFramework
+
+ Name
+ FROM PKIX1Explicit88 --InformationFramework informationFramework
+
+ ALGORITHM
+ FROM PKCS-7; --AuthenticationFramework authenticationFramework;
+
+-- Certificate requests
+
+CertificationRequestInfo ::= SEQUENCE {
+ version INTEGER { v1(0) } (v1,...),
+ subject Name,
+ subjectPKInfo SubjectPublicKeyInfo-PKCS-10{{ PKInfoAlgorithms }},
+ attributes [0] Attributes{{ CRIAttributes }}
+}
+
+SubjectPublicKeyInfo-PKCS-10 {ALGORITHM: IOSet} ::= SEQUENCE {
+ algorithm AlgorithmIdentifierPKCS-10{{IOSet}},
+ subjectPublicKey BIT STRING
+}
+
+PKInfoAlgorithms ALGORITHM ::= {
+ ... -- add any locally defined algorithms here -- }
+
+Attributes { ATTRIBUTE:IOSet } ::= SET OF AttributePKCS-10{{ IOSet }}
+
+CRIAttributes ATTRIBUTE ::= {
+... -- add any locally defined attributes here -- }
+
+AttributePKCS-10 { ATTRIBUTE:IOSet } ::= SEQUENCE {
+ type ATTRIBUTE.&id({IOSet}),
+ values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{@type})
+}
+
+CertificationRequest ::= SEQUENCE {
+ certificationRequestInfo CertificationRequestInfo,
+ signatureAlgorithm AlgorithmIdentifierPKCS-10{{ SignatureAlgorithms }},
+ signature BIT STRING
+}
+
+AlgorithmIdentifierPKCS-10 {ALGORITHM:IOSet } ::= SEQUENCE {
+ algorithm ALGORITHM.&id({IOSet}),
+ parameters ALGORITHM.&Type({IOSet}{@algorithm}) OPTIONAL
+}
+
+SignatureAlgorithms ALGORITHM ::= {
+ ... -- add any locally defined algorithms here -- }
+
+END
diff --git a/lib/public_key/asn1/PKCS-7.asn1 b/lib/public_key/asn1/PKCS-7.asn1
new file mode 100644
index 0000000000..a6dfd57d80
--- /dev/null
+++ b/lib/public_key/asn1/PKCS-7.asn1
@@ -0,0 +1,387 @@
+PKCS-7 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-7(7)
+ modules(0) pkcs-7(1)}
+
+DEFINITIONS EXPLICIT TAGS ::=
+BEGIN
+
+--
+-- 3. Definitions
+--
+
+-- EXPORTS All;
+
+IMPORTS
+
+informationFramework, authenticationFramework
+ FROM UsefulDefinitions {joint-iso-itu-t ds(5) module(1)
+ usefulDefinitions(0) 3}
+
+ ATTRIBUTE
+ FROM InformationFramework informationFramework
+
+ Name, Certificate, CertificateSerialNumber,
+ CertificateList, Time
+ FROM PKIX1Explicit88; -- AuthenticationFramework authenticationFramework;
+
+-- contentType, messageDigest, signingTime
+-- , counterSignature
+-- FROM PKCS-9 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1)
+-- pkcs-9(9) modules(0) pkcs-9(1)};
+--
+-- 6. Useful types
+--
+
+-- inlined from AuthenticationFramework
+
+ALGORITHM ::= CLASS {&Type OPTIONAL,
+ &id OBJECT IDENTIFIER UNIQUE
+}WITH SYNTAX {[&Type]
+ IDENTIFIED BY &id
+}
+
+-- inlined from PKCS-9
+
+pkcs-9 OBJECT IDENTIFIER ::= {iso(1) member-body(2) us(840)
+ rsadsi(113549) pkcs(1) 9}
+
+contentType ATTRIBUTE ::= {
+ WITH SYNTAX ContentType
+-- EQUALITY MATCHING RULE objectIdentifierMatch
+ SINGLE VALUE TRUE
+ ID pkcs-9-at-contentType
+}
+
+pkcs-9-at-contentType OBJECT IDENTIFIER ::= {pkcs-9 3}
+pkcs-9-at-messageDigest OBJECT IDENTIFIER ::= {pkcs-9 4}
+pkcs-9-at-signingTime OBJECT IDENTIFIER ::= {pkcs-9 5}
+pkcs-9-at-counterSignature OBJECT IDENTIFIER ::= {pkcs-9 6}
+
+counterSignature ATTRIBUTE ::= {
+ WITH SYNTAX SignerInfo
+ ID pkcs-9-at-counterSignature
+}
+messageDigest ATTRIBUTE ::= {
+ WITH SYNTAX MessageDigest
+-- EQUALITY MATCHING RULE octetStringMatch
+ SINGLE VALUE TRUE
+ ID pkcs-9-at-messageDigest
+}
+
+MessageDigest ::= OCTET STRING
+
+signingTime ATTRIBUTE ::= {
+ WITH SYNTAX SigningTime
+-- EQUALITY MATCHING RULE signingTimeMatch
+ SINGLE VALUE TRUE
+ ID pkcs-9-at-signingTime
+}
+
+SigningTime ::= Time -- imported from ISO/IEC 9594-8
+
+
+-- Also defined in X.509
+-- Redeclared here as a parameterized type
+AlgorithmIdentifierPKSC-7 {ALGORITHM:IOSet} ::= SEQUENCE {
+ algorithm ALGORITHM.&id({IOSet}),
+ parameters ALGORITHM.&Type({IOSet}{@algorithm}) OPTIONAL
+}
+
+-- Also defined in X.501
+-- Redeclared here as a parameterized type
+AttributePKCS-7 { ATTRIBUTE:IOSet } ::= SEQUENCE {
+ type ATTRIBUTE.&id({IOSet}),
+ values SET SIZE (1..MAX) OF ATTRIBUTE.&Type({IOSet}{@type})
+}
+
+CertificateRevocationLists ::=
+ SET OF CertificateList
+
+Certificates ::=
+ SEQUENCE OF Certificate
+
+CRLSequence ::=
+ SEQUENCE OF CertificateList
+
+ContentEncryptionAlgorithmIdentifier ::=
+ AlgorithmIdentifierPKSC-7 {{ContentEncryptionAlgorithms}}
+
+ContentEncryptionAlgorithms ALGORITHM ::= {
+ ... -- add any application-specific algorithms here
+}
+
+DigestAlgorithmIdentifier ::=
+ AlgorithmIdentifierPKSC-7 {{DigestAlgorithms}}
+
+DigestAlgorithms ALGORITHM ::= {
+ ... -- add any application-specific algorithms here
+}
+
+DigestEncryptionAlgorithmIdentifier ::=
+ AlgorithmIdentifierPKSC-7 {{DigestEncryptionAlgorithms}}
+
+DigestEncryptionAlgorithms ALGORITHM ::= {
+ ... -- add any application-specific algorithms here
+}
+
+ExtendedCertificateOrCertificate ::= CHOICE {
+ certificate Certificate, -- X.509
+ extendedCertificate [0] IMPLICIT ExtendedCertificate -- PKCS#6
+}
+
+ExtendedCertificate ::= Certificate -- cheating
+
+ExtendedCertificatesAndCertificates ::=
+ SET OF ExtendedCertificateOrCertificate
+
+IssuerAndSerialNumber ::= SEQUENCE {
+ issuer Name,
+ serialNumber CertificateSerialNumber
+}
+
+KeyEncryptionAlgorithmIdentifier ::=
+ AlgorithmIdentifierPKSC-7 {{KeyEncryptionAlgorithms}}
+
+KeyEncryptionAlgorithms ALGORITHM ::= {
+ ... -- add any application-specific algorithms here
+}
+
+--
+-- 7. General syntax
+--
+
+ContentInfo ::= SEQUENCE {
+-- contentType ContentType,
+ contentType CONTENTS.&id({Contents}),
+ content [0] EXPLICIT CONTENTS.&Type({Contents}{@contentType})
+OPTIONAL
+}
+
+CONTENTS ::= TYPE-IDENTIFIER
+
+Contents CONTENTS ::= {
+ {Data IDENTIFIED BY data} |
+ {SignedData IDENTIFIED BY signedData} |
+ {EnvelopedData IDENTIFIED BY envelopedData} |
+ {SignedAndEnvelopedData IDENTIFIED BY signedAndEnvelopedData} |
+ {DigestedData IDENTIFIED BY digestedData} |
+ {EncryptedData IDENTIFIED BY encryptedData},
+ ... -- add any application-specific types/contents here
+}
+
+ContentType ::= CONTENTS.&id({Contents})
+
+--
+-- 8. Data content type
+--
+
+Data ::= OCTET STRING
+
+--
+-- 9. Signed-data content type
+--
+
+SignedData ::= SEQUENCE {
+-- version INTEGER {sdVer1(1), sdVer2(2)} (sdVer1 | sdVer2),
+ version INTEGER {sdVer1(1), sdVer2(2)},
+ digestAlgorithms
+ DigestAlgorithmIdentifiers,
+ contentInfo ContentInfo,
+ certificates CHOICE {
+ certSet [0] IMPLICIT ExtendedCertificatesAndCertificates,
+ certSequence [2] IMPLICIT Certificates
+ } OPTIONAL,
+ crls CHOICE {
+ crlSet [1] IMPLICIT CertificateRevocationLists,
+ crlSequence [3] IMPLICIT CRLSequence
+ } OPTIONAL,
+ signerInfos SignerInfos
+} (WITH COMPONENTS { ..., version (sdVer1),
+ digestAlgorithms (WITH COMPONENTS { ..., daSet PRESENT }),
+ certificates (WITH COMPONENTS { ..., certSequence ABSENT }),
+ crls (WITH COMPONENTS { ..., crlSequence ABSENT }),
+ signerInfos (WITH COMPONENTS { ..., siSet PRESENT })
+ } |
+ WITH COMPONENTS { ..., version (sdVer2),
+ digestAlgorithms (WITH COMPONENTS { ..., daSequence PRESENT }),
+ certificates (WITH COMPONENTS { ..., certSet ABSENT }),
+ crls (WITH COMPONENTS { ..., crlSet ABSENT }),
+ signerInfos (WITH COMPONENTS { ..., siSequence PRESENT })
+})
+
+SignerInfos ::= CHOICE {
+ siSet SET OF SignerInfo,
+ siSequence SEQUENCE OF SignerInfo
+}
+
+DigestAlgorithmIdentifiers ::= CHOICE {
+ daSet SET OF DigestAlgorithmIdentifier,
+ daSequence SEQUENCE OF DigestAlgorithmIdentifier
+}
+
+SignerInfo ::= SEQUENCE {
+-- version INTEGER {siVer1(1), siVer2(2)} (siVer1 | siVer2),
+ version INTEGER {siVer1(1), siVer2(2)},
+ issuerAndSerialNumber
+ IssuerAndSerialNumber,
+ digestAlgorithm DigestAlgorithmIdentifier,
+ authenticatedAttributes CHOICE {
+ aaSet [0] IMPLICIT SET OF AttributePKCS-7 {{Authenticated}},
+ aaSequence [2] EXPLICIT SEQUENCE OF AttributePKCS-7 {{Authenticated}}
+ -- Explicit because easier to compute digest on sequence of attributes and then reuse
+ -- encoded sequence in aaSequence.
+ } OPTIONAL,
+ digestEncryptionAlgorithm
+ DigestEncryptionAlgorithmIdentifier,
+ encryptedDigest EncryptedDigest,
+ unauthenticatedAttributes CHOICE {
+ uaSet [1] IMPLICIT SET OF AttributePKCS-7 {{Unauthenticated}},
+ uaSequence [3] IMPLICIT SEQUENCE OF AttributePKCS-7 {{Unauthenticated}}
+ } OPTIONAL
+} (WITH COMPONENTS { ..., version (siVer1),
+ authenticatedAttributes (WITH COMPONENTS { ..., aaSequence ABSENT }),
+ unauthenticatedAttributes (WITH COMPONENTS { ..., uaSequence ABSENT })
+} | WITH COMPONENTS { ..., version (siVer2),
+ authenticatedAttributes (WITH COMPONENTS { ..., aaSet ABSENT }),
+ unauthenticatedAttributes (WITH COMPONENTS { ..., uaSet ABSENT })
+})
+
+Authenticated ATTRIBUTE ::= {
+ contentType |
+ messageDigest,
+ ..., -- add application-specific attributes here
+ signingTime
+}
+
+Unauthenticated ATTRIBUTE ::= {
+ contentType |
+ messageDigest,
+ ..., -- add application-specific attributes here
+ counterSignature
+-- ..., add application-specific attributes here
+-- counterSignature
+}
+
+EncryptedDigest ::= OCTET STRING
+
+DigestInfo ::= SEQUENCE {
+ digestAlgorithm DigestAlgorithmIdentifier,
+ digest Digest
+}
+
+Digest ::= OCTET STRING
+
+--
+-- 10. Enveloped-data content type
+--
+
+EnvelopedData ::= SEQUENCE {
+-- version INTEGER {edVer0(0), edVer1(1)} (edVer0 | edVer1),
+ version INTEGER {edVer0(0), edVer1(1)},
+ recipientInfos RecipientInfos,
+ encryptedContentInfo
+ EncryptedContentInfo
+} (WITH COMPONENTS { ..., version (edVer0),
+ recipientInfos (WITH COMPONENTS { ..., riSet PRESENT })
+} | WITH COMPONENTS { ..., version (edVer1),
+ recipientInfos (WITH COMPONENTS { ..., riSequence PRESENT })
+})
+
+RecipientInfos ::= CHOICE {
+ riSet SET OF RecipientInfo,
+ riSequence SEQUENCE OF RecipientInfo
+}
+
+EncryptedContentInfo ::= SEQUENCE {
+ contentType ContentType,
+ contentEncryptionAlgorithm
+ ContentEncryptionAlgorithmIdentifier,
+ encryptedContent
+ [0] IMPLICIT EncryptedContent OPTIONAL
+}
+
+EncryptedContent ::= OCTET STRING
+
+RecipientInfo ::= SEQUENCE {
+-- version INTEGER {riVer0(0)} (riVer0),
+ version INTEGER {riVer0(0)},
+ issuerAndSerialNumber
+ IssuerAndSerialNumber,
+ keyEncryptionAlgorithm
+ KeyEncryptionAlgorithmIdentifier,
+ encryptedKey EncryptedKey
+}
+
+EncryptedKey ::= OCTET STRING
+
+--
+-- 11. Signed-and-enveloped-data content type
+--
+
+SignedAndEnvelopedData ::= SEQUENCE {
+-- version INTEGER {seVer1(1), seVer2(2)} (seVer1 | seVer2),
+ version INTEGER {seVer1(1), seVer2(2)},
+ recipientInfos RecipientInfos,
+ digestAlgorithms
+ DigestAlgorithmIdentifiers,
+ encryptedContentInfo
+ EncryptedContentInfo,
+ certificates CHOICE {
+ certSet [0] IMPLICIT ExtendedCertificatesAndCertificates,
+ certSequence [2] IMPLICIT Certificates
+ } OPTIONAL,
+ crls CHOICE {
+ crlSet [1] IMPLICIT CertificateRevocationLists,
+ crlSequence [3] IMPLICIT CRLSequence
+ } OPTIONAL,
+ signerInfos SignerInfos
+} (WITH COMPONENTS { ..., version (seVer1),
+ recipientInfos (WITH COMPONENTS { ..., riSet PRESENT }),
+ digestAlgorithms (WITH COMPONENTS { ..., daSet PRESENT }),
+ certificates (WITH COMPONENTS { ..., certSequence ABSENT }),
+ crls (WITH COMPONENTS { ..., crlSequence ABSENT }),
+ signerInfos (WITH COMPONENTS { ..., siSet PRESENT })
+} |
+ WITH COMPONENTS { ..., version (seVer2),
+ recipientInfos (WITH COMPONENTS { ..., riSequence PRESENT }),
+ digestAlgorithms (WITH COMPONENTS { ..., daSequence PRESENT }),
+ certificates (WITH COMPONENTS { ..., certSet ABSENT }),
+ crls (WITH COMPONENTS { ..., crlSet ABSENT }),
+ signerInfos (WITH COMPONENTS { ..., siSequence PRESENT })
+})
+
+--
+-- 12. Digested-data content type
+--pbeWithSHAAnd3-KeyTripleDES-CBC
+
+DigestedData ::= SEQUENCE {
+-- version INTEGER {ddVer0(0)} (ddVer0),
+ version INTEGER {ddVer0(0)},
+ digestAlgorithm DigestAlgorithmIdentifier,
+ contentInfo ContentInfo,
+ digest Digest
+}
+
+--
+-- 13. Encrypted-data content type
+--
+
+EncryptedData ::= SEQUENCE {
+-- version INTEGER {edVer0(0)} (edVer0),
+ version INTEGER {edVer0(0)},
+ encryptedContentInfo EncryptedContentInfo
+}
+
+--
+-- 14. Object Identifiers
+--
+
+pkcs-7 OBJECT IDENTIFIER ::=
+ { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 7 }
+data OBJECT IDENTIFIER ::= { pkcs-7 1 }
+signedData OBJECT IDENTIFIER ::= { pkcs-7 2 }
+envelopedData OBJECT IDENTIFIER ::= { pkcs-7 3 }
+signedAndEnvelopedData OBJECT IDENTIFIER ::= { pkcs-7 4 }
+digestedData OBJECT IDENTIFIER ::= { pkcs-7 5 }
+encryptedData OBJECT IDENTIFIER ::= { pkcs-7 6 }
+
+END
diff --git a/lib/public_key/asn1/PKIX1Explicit88.asn1 b/lib/public_key/asn1/PKIX1Explicit88.asn1
index 03e9da3e05..91758d7269 100644
--- a/lib/public_key/asn1/PKIX1Explicit88.asn1
+++ b/lib/public_key/asn1/PKIX1Explicit88.asn1
@@ -206,13 +206,12 @@ DomainComponent ::= IA5String
-- Legacy attributes
-pkcs-9 OBJECT IDENTIFIER ::=
- { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 }
-
id-emailAddress AttributeType ::= { pkcs-9 1 }
EmailAddress ::= IA5String (SIZE (1..ub-emailaddress-length))
+-- Legacy attributes
+
-- naming data types --
Name ::= CHOICE { -- only one possibility for now --
diff --git a/lib/public_key/asn1/SelectedAttributeTypes.asn1 b/lib/public_key/asn1/SelectedAttributeTypes.asn1
new file mode 100644
index 0000000000..3ef7077370
--- /dev/null
+++ b/lib/public_key/asn1/SelectedAttributeTypes.asn1
@@ -0,0 +1,1575 @@
+SelectedAttributeTypes {joint-iso-itu-t ds(5) module(1)
+ selectedAttributeTypes(5) 6} DEFINITIONS ::=
+BEGIN
+
+-- EXPORTS All
+-- The types and values defined in this module are exported for use in the other ASN.1 modules contained
+-- within the Directory Specifications, and for the use of other applications which will use them to access
+-- Directory services. Other applications may use them for their own purposes, but this will not constrain
+-- extensions and modifications needed to maintain or improve the Directory service.
+IMPORTS
+ -- from ITU-T Rec. X.501 | ISO/IEC 9594-2
+ directoryAbstractService, id-at, id-avc, id-cat, id-mr, id-not, id-pr,
+ informationFramework, serviceAdministration
+ FROM UsefulDefinitions {joint-iso-itu-t ds(5) module(1)
+ usefulDefinitions(0) 6}
+ Attribute{}, ATTRIBUTE, AttributeType, AttributeValueAssertion, CONTEXT,
+ ContextAssertion, DistinguishedName, distinguishedNameMatch,
+ MAPPING-BASED-MATCHING{}, MATCHING-RULE, OBJECT-CLASS,
+ objectIdentifierMatch, SupportedAttributes
+ FROM InformationFramework informationFramework
+ AttributeCombination, ContextCombination, MRMapping
+ FROM ServiceAdministration serviceAdministration
+ -- from ITU-T Rec. X.511 | ISO/IEC 9594-3
+ FilterItem, HierarchySelections, SearchControlOptions, ServiceControlOptions
+ FROM DirectoryAbstractService directoryAbstractService
+ -- from ITU-T Rec. X.411 | ISO/IEC 10021-4
+ G3FacsimileNonBasicParameters
+ FROM MTSAbstractService {joint-iso-itu-t mhs(6) mts(3) modules(0)
+ mts-abstract-service(1) version-1999(1)};
+
+/*from IETF RFC 3727
+
+The following import is provided for information only (see 7.2.16), it is not referenced by any ASN.1 construct within these Directory Specifications. Note that the ASN.1 module in RFC 3727 imports from the InformationFramework module of edition 4 of ITU-T Rec. X.501 | ISO/IEC 9594-2. A specification importing from both these Directory Specifications and from RFC 3727 should take corrective actions, e.g., by making a copy of the ASN.1 module of
+RFC 3727 and then update the IMPORT statement.
+
+ allComponentsMatch, componentFilterMatch, directoryComponentsMatch, presentMatch, rdnMatch
+ FROM ComponentMatching {iso(1) 2 36 79672281 xed(3) module (0)
+ component-matching(4)} */
+-- Directory string type
+UnboundedDirectoryString ::= CHOICE {
+ teletexString TeletexString(SIZE (1..MAX)),
+ printableString PrintableString(SIZE (1..MAX)),
+ bmpString BMPString(SIZE (1..MAX)),
+ universalString UniversalString(SIZE (1..MAX)),
+ uTF8String UTF8String(SIZE (1..MAX))
+}
+
+DirectoryString{INTEGER:maxSize} ::= CHOICE {
+ teletexString TeletexString(SIZE (1..maxSize)),
+ printableString PrintableString(SIZE (1..maxSize)),
+ bmpString BMPString(SIZE (1..maxSize)),
+ universalString UniversalString(SIZE (1..maxSize)),
+ uTF8String UTF8String(SIZE (1..maxSize))
+}
+
+-- Attribute types
+knowledgeInformation ATTRIBUTE ::= {
+ WITH SYNTAX UnboundedDirectoryString
+ EQUALITY MATCHING RULE caseIgnoreMatch
+ ID id-at-knowledgeInformation
+}
+
+name ATTRIBUTE ::= {
+ WITH SYNTAX UnboundedDirectoryString
+ EQUALITY MATCHING RULE caseIgnoreMatch
+ SUBSTRINGS MATCHING RULE caseIgnoreSubstringsMatch
+ ID id-at-name
+}
+
+commonName ATTRIBUTE ::= {
+ SUBTYPE OF name
+ WITH SYNTAX UnboundedDirectoryString
+ ID id-at-commonName
+}
+
+surname ATTRIBUTE ::= {
+ SUBTYPE OF name
+ WITH SYNTAX UnboundedDirectoryString
+ ID id-at-surname
+}
+
+givenName ATTRIBUTE ::= {
+ SUBTYPE OF name
+ WITH SYNTAX UnboundedDirectoryString
+ ID id-at-givenName
+}
+
+initials ATTRIBUTE ::= {
+ SUBTYPE OF name
+ WITH SYNTAX UnboundedDirectoryString
+ ID id-at-initials
+}
+
+generationQualifier ATTRIBUTE ::= {
+ SUBTYPE OF name
+ WITH SYNTAX UnboundedDirectoryString
+ ID id-at-generationQualifier
+}
+
+uniqueIdentifier ATTRIBUTE ::= {
+ WITH SYNTAX UniqueIdentifier
+ EQUALITY MATCHING RULE bitStringMatch
+ ID id-at-uniqueIdentifier
+}
+
+UniqueIdentifier ::= BIT STRING
+
+dnQualifier ATTRIBUTE ::= {
+ WITH SYNTAX PrintableString
+ EQUALITY MATCHING RULE caseIgnoreMatch
+ ORDERING MATCHING RULE caseIgnoreOrderingMatch
+ SUBSTRINGS MATCHING RULE caseIgnoreSubstringsMatch
+ ID id-at-dnQualifier
+}
+
+serialNumber ATTRIBUTE ::= {
+ WITH SYNTAX PrintableString(SIZE (1..MAX))
+ EQUALITY MATCHING RULE caseIgnoreMatch
+ SUBSTRINGS MATCHING RULE caseIgnoreSubstringsMatch
+ ID id-at-serialNumber
+}
+
+pseudonym ATTRIBUTE ::= {
+ SUBTYPE OF name
+ WITH SYNTAX UnboundedDirectoryString
+ ID id-at-pseudonym
+}
+
+uUIDPair ATTRIBUTE ::= {
+ WITH SYNTAX UUIDPair
+ EQUALITY MATCHING RULE uUIDPairMatch
+ ID id-at-uuidpair
+}
+
+UUIDPair ::= SEQUENCE {issuerUUID UUID,
+ subjectUUID UUID
+}
+
+UUID ::= OCTET STRING(SIZE (16)) -- UUID format only
+
+
+countryName ATTRIBUTE ::= {
+ SUBTYPE OF name
+ WITH SYNTAX CountryName
+ SINGLE VALUE TRUE
+ ID id-at-countryName
+}
+
+CountryName ::= PrintableString(SIZE (2)) -- ISO 3166 codes only
+
+
+localityName ATTRIBUTE ::= {
+ SUBTYPE OF name
+ WITH SYNTAX UnboundedDirectoryString
+ ID id-at-localityName
+}
+
+collectiveLocalityName ATTRIBUTE ::= {
+ SUBTYPE OF localityName
+ COLLECTIVE TRUE
+ ID id-at-collectiveLocalityName
+}
+
+stateOrProvinceName ATTRIBUTE ::= {
+ SUBTYPE OF name
+ WITH SYNTAX UnboundedDirectoryString
+ ID id-at-stateOrProvinceName
+}
+
+collectiveStateOrProvinceName ATTRIBUTE ::= {
+ SUBTYPE OF stateOrProvinceName
+ COLLECTIVE TRUE
+ ID id-at-collectiveStateOrProvinceName
+}
+
+streetAddress ATTRIBUTE ::= {
+ WITH SYNTAX UnboundedDirectoryString
+ EQUALITY MATCHING RULE caseIgnoreMatch
+ SUBSTRINGS MATCHING RULE caseIgnoreSubstringsMatch
+ ID id-at-streetAddress
+}
+
+collectiveStreetAddress ATTRIBUTE ::= {
+ SUBTYPE OF streetAddress
+ COLLECTIVE TRUE
+ ID id-at-collectiveStreetAddress
+}
+
+houseIdentifier ATTRIBUTE ::= {
+ WITH SYNTAX UnboundedDirectoryString
+ EQUALITY MATCHING RULE caseIgnoreMatch
+ SUBSTRINGS MATCHING RULE caseIgnoreSubstringsMatch
+ ID id-at-houseIdentifier
+}
+
+organizationName ATTRIBUTE ::= {
+ SUBTYPE OF name
+ WITH SYNTAX UnboundedDirectoryString
+ ID id-at-organizationName
+}
+
+collectiveOrganizationName ATTRIBUTE ::= {
+ SUBTYPE OF organizationName
+ COLLECTIVE TRUE
+ ID id-at-collectiveOrganizationName
+}
+
+organizationalUnitName ATTRIBUTE ::= {
+ SUBTYPE OF name
+ WITH SYNTAX UnboundedDirectoryString
+ ID id-at-organizationalUnitName
+}
+
+collectiveOrganizationalUnitName ATTRIBUTE ::= {
+ SUBTYPE OF organizationalUnitName
+ COLLECTIVE TRUE
+ ID id-at-collectiveOrganizationalUnitName
+}
+
+title ATTRIBUTE ::= {
+ SUBTYPE OF name
+ WITH SYNTAX UnboundedDirectoryString
+ ID id-at-title
+}
+
+description ATTRIBUTE ::= {
+ WITH SYNTAX UnboundedDirectoryString
+ EQUALITY MATCHING RULE caseIgnoreMatch
+ SUBSTRINGS MATCHING RULE caseIgnoreSubstringsMatch
+ ID id-at-description
+}
+
+searchGuide ATTRIBUTE ::= {WITH SYNTAX Guide
+ ID id-at-searchGuide
+}
+
+Guide ::= SET {
+ objectClass [0] OBJECT-CLASS.&id OPTIONAL,
+ criteria [1] Criteria
+}
+
+Criteria ::= CHOICE {
+ type [0] CriteriaItem,
+ and [1] SET OF Criteria,
+ or [2] SET OF Criteria,
+ not [3] Criteria
+}
+
+CriteriaItem ::= CHOICE {
+ equality [0] AttributeType,
+ substrings [1] AttributeType,
+ greaterOrEqual [2] AttributeType,
+ lessOrEqual [3] AttributeType,
+ approximateMatch [4] AttributeType
+}
+
+enhancedSearchGuide ATTRIBUTE ::= {
+ WITH SYNTAX EnhancedGuide
+ ID id-at-enhancedSearchGuide
+}
+
+EnhancedGuide ::= SEQUENCE {
+ objectClass [0] OBJECT-CLASS.&id,
+ criteria [1] Criteria,
+ subset
+ [2] INTEGER {baseObject(0), oneLevel(1), wholeSubtree(2)} DEFAULT oneLevel
+}
+
+businessCategory ATTRIBUTE ::= {
+ WITH SYNTAX UnboundedDirectoryString
+ EQUALITY MATCHING RULE caseIgnoreMatch
+ SUBSTRINGS MATCHING RULE caseIgnoreSubstringsMatch
+ ID id-at-businessCategory
+}
+
+postalAddress ATTRIBUTE ::= {
+ WITH SYNTAX PostalAddress
+ EQUALITY MATCHING RULE caseIgnoreListMatch
+ SUBSTRINGS MATCHING RULE caseIgnoreListSubstringsMatch
+ ID id-at-postalAddress
+}
+
+PostalAddress ::= SEQUENCE SIZE (1..MAX) OF UnboundedDirectoryString
+
+collectivePostalAddress ATTRIBUTE ::= {
+ SUBTYPE OF postalAddress
+ COLLECTIVE TRUE
+ ID id-at-collectivePostalAddress
+}
+
+postalCode ATTRIBUTE ::= {
+ WITH SYNTAX UnboundedDirectoryString
+ EQUALITY MATCHING RULE caseIgnoreMatch
+ SUBSTRINGS MATCHING RULE caseIgnoreSubstringsMatch
+ ID id-at-postalCode
+}
+
+collectivePostalCode ATTRIBUTE ::= {
+ SUBTYPE OF postalCode
+ COLLECTIVE TRUE
+ ID id-at-collectivePostalCode
+}
+
+postOfficeBox ATTRIBUTE ::= {
+ WITH SYNTAX UnboundedDirectoryString
+ EQUALITY MATCHING RULE caseIgnoreMatch
+ SUBSTRINGS MATCHING RULE caseIgnoreSubstringsMatch
+ ID id-at-postOfficeBox
+}
+
+collectivePostOfficeBox ATTRIBUTE ::= {
+ SUBTYPE OF postOfficeBox
+ COLLECTIVE TRUE
+ ID id-at-collectivePostOfficeBox
+}
+
+physicalDeliveryOfficeName ATTRIBUTE ::= {
+ WITH SYNTAX UnboundedDirectoryString
+ EQUALITY MATCHING RULE caseIgnoreMatch
+ SUBSTRINGS MATCHING RULE caseIgnoreSubstringsMatch
+ ID id-at-physicalDeliveryOfficeName
+}
+
+collectivePhysicalDeliveryOfficeName ATTRIBUTE ::= {
+ SUBTYPE OF physicalDeliveryOfficeName
+ COLLECTIVE TRUE
+ ID id-at-collectivePhysicalDeliveryOfficeName
+}
+
+telephoneNumber ATTRIBUTE ::= {
+ WITH SYNTAX TelephoneNumber
+ EQUALITY MATCHING RULE telephoneNumberMatch
+ SUBSTRINGS MATCHING RULE telephoneNumberSubstringsMatch
+ ID id-at-telephoneNumber
+}
+
+TelephoneNumber ::= PrintableString(SIZE (1..ub-telephone-number))
+
+-- String complying with ITU-T Rec. E.123 only
+ub-telephone-number INTEGER ::=
+ 32
+
+collectiveTelephoneNumber ATTRIBUTE ::= {
+ SUBTYPE OF telephoneNumber
+ COLLECTIVE TRUE
+ ID id-at-collectiveTelephoneNumber
+}
+
+telexNumber ATTRIBUTE ::= {
+ WITH SYNTAX TelexNumber
+ ID id-at-telexNumber
+}
+
+TelexNumber ::= SEQUENCE {
+ telexNumber PrintableString(SIZE (1..ub-telex-number)),
+ countryCode PrintableString(SIZE (1..ub-country-code)),
+ answerback PrintableString(SIZE (1..ub-answerback))
+}
+
+ub-telex-number INTEGER ::= 14
+
+ub-country-code INTEGER ::= 4
+
+ub-answerback INTEGER ::= 8
+
+collectiveTelexNumber ATTRIBUTE ::= {
+ SUBTYPE OF telexNumber
+ COLLECTIVE TRUE
+ ID id-at-collectiveTelexNumber
+}
+
+facsimileTelephoneNumber ATTRIBUTE ::= {
+ WITH SYNTAX FacsimileTelephoneNumber
+ EQUALITY MATCHING RULE facsimileNumberMatch
+ SUBSTRINGS MATCHING RULE facsimileNumberSubstringsMatch
+ ID id-at-facsimileTelephoneNumber
+}
+
+FacsimileTelephoneNumber ::= SEQUENCE {
+ telephoneNumber TelephoneNumber,
+ parameters G3FacsimileNonBasicParameters OPTIONAL
+}
+
+collectiveFacsimileTelephoneNumber ATTRIBUTE ::= {
+ SUBTYPE OF facsimileTelephoneNumber
+ COLLECTIVE TRUE
+ ID id-at-collectiveFacsimileTelephoneNumber
+}
+
+x121Address ATTRIBUTE ::= {
+ WITH SYNTAX X121Address
+ EQUALITY MATCHING RULE numericStringMatch
+ SUBSTRINGS MATCHING RULE numericStringSubstringsMatch
+ ID id-at-x121Address
+}
+
+X121Address ::= NumericString(SIZE (1..ub-x121-address))
+
+-- String as defined by ITU-T Rec. X.121
+ub-x121-address INTEGER ::= 15
+
+internationalISDNNumber ATTRIBUTE ::= {
+ WITH SYNTAX InternationalISDNNumber
+ EQUALITY MATCHING RULE numericStringMatch
+ SUBSTRINGS MATCHING RULE numericStringSubstringsMatch
+ ID id-at-internationalISDNNumber
+}
+
+InternationalISDNNumber ::=
+ NumericString(SIZE (1..ub-international-isdn-number))
+
+-- String complying with ITU-T Rec. E.164 only
+ub-international-isdn-number INTEGER ::=
+ 16
+
+collectiveInternationalISDNNumber ATTRIBUTE ::= {
+ SUBTYPE OF internationalISDNNumber
+ COLLECTIVE TRUE
+ ID id-at-collectiveInternationalISDNNumber
+}
+
+registeredAddress ATTRIBUTE ::= {
+ SUBTYPE OF postalAddress
+ WITH SYNTAX PostalAddress
+ ID id-at-registeredAddress
+}
+
+destinationIndicator ATTRIBUTE ::= {
+ WITH SYNTAX DestinationIndicator
+ EQUALITY MATCHING RULE caseIgnoreMatch
+ SUBSTRINGS MATCHING RULE caseIgnoreSubstringsMatch
+ ID id-at-destinationIndicator
+}
+
+DestinationIndicator ::= PrintableString(SIZE (1..MAX))
+
+-- alphabetical characters only
+communicationsService ATTRIBUTE ::= {
+ WITH SYNTAX CommunicationsService
+ EQUALITY MATCHING RULE objectIdentifierMatch
+ ID id-at-communicationsService
+}
+
+CommunicationsService ::= OBJECT IDENTIFIER
+
+communicationsNetwork ATTRIBUTE ::= {
+ WITH SYNTAX CommunicationsNetwork
+ EQUALITY MATCHING RULE objectIdentifierMatch
+ SINGLE VALUE TRUE
+ ID id-at-communicationsNetwork
+}
+
+CommunicationsNetwork ::= OBJECT IDENTIFIER
+
+preferredDeliveryMethod ATTRIBUTE ::= {
+ WITH SYNTAX PreferredDeliveryMethod
+ SINGLE VALUE TRUE
+ ID id-at-preferredDeliveryMethod
+}
+
+PreferredDeliveryMethod ::=
+ SEQUENCE OF
+ INTEGER {any-delivery-method(0), mhs-delivery(1), physical-delivery(2),
+ telex-delivery(3), teletex-delivery(4), g3-facsimile-delivery(5),
+ g4-facsimile-delivery(6), ia5-terminal-delivery(7),
+ videotex-delivery(8), telephone-delivery(9)}
+
+presentationAddress ATTRIBUTE ::= {
+ WITH SYNTAX PresentationAddress
+ EQUALITY MATCHING RULE presentationAddressMatch
+ SINGLE VALUE TRUE
+ ID id-at-presentationAddress
+}
+
+PresentationAddress ::= SEQUENCE {
+ pSelector [0] OCTET STRING OPTIONAL,
+ sSelector [1] OCTET STRING OPTIONAL,
+ tSelector [2] OCTET STRING OPTIONAL,
+ nAddresses [3] SET SIZE (1..MAX) OF OCTET STRING
+}
+
+supportedApplicationContext ATTRIBUTE ::= {
+ WITH SYNTAX OBJECT IDENTIFIER
+ EQUALITY MATCHING RULE objectIdentifierMatch
+ ID id-at-supportedApplicationContext
+}
+
+protocolInformation ATTRIBUTE ::= {
+ WITH SYNTAX ProtocolInformation
+ EQUALITY MATCHING RULE protocolInformationMatch
+ ID id-at-protocolInformation
+}
+
+ProtocolInformation ::= SEQUENCE {
+ nAddress OCTET STRING,
+ profiles SET OF OBJECT IDENTIFIER
+}
+
+distinguishedName ATTRIBUTE ::= {
+ WITH SYNTAX DistinguishedName
+ EQUALITY MATCHING RULE distinguishedNameMatch
+ ID id-at-distinguishedName
+}
+
+member ATTRIBUTE ::= {SUBTYPE OF distinguishedName
+ ID id-at-member
+}
+
+uniqueMember ATTRIBUTE ::= {
+ WITH SYNTAX NameAndOptionalUID
+ EQUALITY MATCHING RULE uniqueMemberMatch
+ ID id-at-uniqueMember
+}
+
+NameAndOptionalUID ::= SEQUENCE {
+ dn DistinguishedName,
+ uid UniqueIdentifier OPTIONAL
+}
+
+owner ATTRIBUTE ::= {SUBTYPE OF distinguishedName
+ ID id-at-owner
+}
+
+roleOccupant ATTRIBUTE ::= {
+ SUBTYPE OF distinguishedName
+ ID id-at-roleOccupant
+}
+
+seeAlso ATTRIBUTE ::= {SUBTYPE OF distinguishedName
+ ID id-at-seeAlso
+}
+
+dmdName ATTRIBUTE ::= {
+ SUBTYPE OF name
+ WITH SYNTAX UnboundedDirectoryString
+ ID id-at-dmdName
+}
+
+-- Attributes for tag-based identification
+tagOid ATTRIBUTE ::= {
+ WITH SYNTAX OBJECT IDENTIFIER
+ EQUALITY MATCHING RULE objectIdentifierMatch
+ SINGLE VALUE TRUE
+ ID id-at-tagOid
+}
+
+uiiFormat ATTRIBUTE ::= {
+ WITH SYNTAX UnboundedDirectoryString
+ SINGLE VALUE TRUE
+ ID id-at-uiiFormat
+}
+
+uiiInUrn ATTRIBUTE ::= {
+ WITH SYNTAX UTF8String
+ EQUALITY MATCHING RULE caseExactMatch
+ SINGLE VALUE TRUE
+ ID id-at-uiiInUrn
+}
+
+contentUri ATTRIBUTE ::= {
+ WITH SYNTAX UnboundedDirectoryString
+ ID id-at-contentUri
+}
+
+-- Notification attributes
+dSAProblem ATTRIBUTE ::= {
+ WITH SYNTAX OBJECT IDENTIFIER
+ EQUALITY MATCHING RULE objectIdentifierMatch
+ ID id-not-dSAProblem
+}
+
+searchServiceProblem ATTRIBUTE ::= {
+ WITH SYNTAX OBJECT IDENTIFIER
+ EQUALITY MATCHING RULE objectIdentifierMatch
+ SINGLE VALUE TRUE
+ ID id-not-searchServiceProblem
+}
+
+serviceType ATTRIBUTE ::= {
+ WITH SYNTAX OBJECT IDENTIFIER
+ EQUALITY MATCHING RULE objectIdentifierMatch
+ SINGLE VALUE TRUE
+ ID id-not-serviceType
+}
+
+attributeTypeList ATTRIBUTE ::= {
+ WITH SYNTAX OBJECT IDENTIFIER
+ EQUALITY MATCHING RULE objectIdentifierMatch
+ ID id-not-attributeTypeList
+}
+
+matchingRuleList ATTRIBUTE ::= {
+ WITH SYNTAX OBJECT IDENTIFIER
+ EQUALITY MATCHING RULE objectIdentifierMatch
+ ID id-not-matchingRuleList
+}
+
+filterItem ATTRIBUTE ::= {
+ WITH SYNTAX FilterItem
+ ID id-not-filterItem
+}
+
+attributeCombinations ATTRIBUTE ::= {
+ WITH SYNTAX AttributeCombination
+ ID id-not-attributeCombinations
+}
+
+contextTypeList ATTRIBUTE ::= {
+ WITH SYNTAX OBJECT IDENTIFIER
+ EQUALITY MATCHING RULE objectIdentifierMatch
+ ID id-not-contextTypeList
+}
+
+contextList ATTRIBUTE ::= {
+ WITH SYNTAX ContextAssertion
+ ID id-not-contextList
+}
+
+contextCombinations ATTRIBUTE ::= {
+ WITH SYNTAX ContextCombination
+ ID id-not-contextCombinations
+}
+
+hierarchySelectList ATTRIBUTE ::= {
+ WITH SYNTAX HierarchySelections
+ SINGLE VALUE TRUE
+ ID id-not-hierarchySelectList
+}
+
+searchControlOptionsList ATTRIBUTE ::= {
+ WITH SYNTAX SearchControlOptions
+ SINGLE VALUE TRUE
+ ID id-not-searchControlOptionsList
+}
+
+serviceControlOptionsList ATTRIBUTE ::= {
+ WITH SYNTAX ServiceControlOptions
+ SINGLE VALUE TRUE
+ ID id-not-serviceControlOptionsList
+}
+
+multipleMatchingLocalities ATTRIBUTE ::= {
+ WITH SYNTAX MultipleMatchingLocalities
+ ID id-not-multipleMatchingLocalities
+}
+
+MultipleMatchingLocalities ::= SEQUENCE {
+ matchingRuleUsed MATCHING-RULE.&id OPTIONAL,
+ attributeList SEQUENCE OF AttributeValueAssertion
+}
+
+proposedRelaxation ATTRIBUTE ::= {
+ WITH SYNTAX MRMappings
+ ID id-not-proposedRelaxation
+}
+
+MRMappings ::= SEQUENCE OF MRMapping
+
+appliedRelaxation ATTRIBUTE ::= {
+ WITH SYNTAX OBJECT IDENTIFIER
+ EQUALITY MATCHING RULE objectIdentifierMatch
+ ID id-not-appliedRelaxation
+}
+
+-- Matching rules
+caseExactMatch MATCHING-RULE ::= {
+ SYNTAX UnboundedDirectoryString
+ ID id-mr-caseExactMatch
+}
+
+caseIgnoreMatch MATCHING-RULE ::= {
+ SYNTAX UnboundedDirectoryString
+ ID id-mr-caseIgnoreMatch
+}
+
+caseExactOrderingMatch MATCHING-RULE ::= {
+ SYNTAX UnboundedDirectoryString
+ ID id-mr-caseExactOrderingMatch
+}
+
+caseIgnoreOrderingMatch MATCHING-RULE ::= {
+ SYNTAX UnboundedDirectoryString
+ ID id-mr-caseIgnoreOrderingMatch
+}
+
+caseExactSubstringsMatch MATCHING-RULE ::= {
+ SYNTAX SubstringAssertion -- only the PrintableString choice
+ ID id-mr-caseExactSubstringsMatch
+}
+
+caseIgnoreSubstringsMatch MATCHING-RULE ::= {
+ SYNTAX SubstringAssertion
+ ID id-mr-caseIgnoreSubstringsMatch
+}
+
+SubstringAssertion ::=
+ SEQUENCE OF
+ CHOICE {initial [0] UnboundedDirectoryString,
+ any [1] UnboundedDirectoryString,
+ final [2] UnboundedDirectoryString,
+ control Attribute{{SupportedAttributes}}
+ } -- Used to specify interpretation of the following items
+
+-- at most one initial and one final component
+numericStringMatch MATCHING-RULE ::= {
+ SYNTAX NumericString
+ ID id-mr-numericStringMatch
+}
+
+numericStringOrderingMatch MATCHING-RULE ::= {
+ SYNTAX NumericString
+ ID id-mr-numericStringOrderingMatch
+}
+
+numericStringSubstringsMatch MATCHING-RULE ::= {
+ SYNTAX SubstringAssertion
+ ID id-mr-numericStringSubstringsMatch
+}
+
+caseIgnoreListMatch MATCHING-RULE ::= {
+ SYNTAX CaseIgnoreList
+ ID id-mr-caseIgnoreListMatch
+}
+
+CaseIgnoreList ::= SEQUENCE OF UnboundedDirectoryString
+
+caseIgnoreListSubstringsMatch MATCHING-RULE ::= {
+ SYNTAX SubstringAssertion
+ ID id-mr-caseIgnoreListSubstringsMatch
+}
+
+storedPrefixMatch MATCHING-RULE ::= {
+ SYNTAX UnboundedDirectoryString
+ ID id-mr-storedPrefixMatch
+}
+
+booleanMatch MATCHING-RULE ::= {SYNTAX BOOLEAN
+ ID id-mr-booleanMatch
+}
+
+integerMatch MATCHING-RULE ::= {SYNTAX INTEGER
+ ID id-mr-integerMatch
+}
+
+integerOrderingMatch MATCHING-RULE ::= {
+ SYNTAX INTEGER
+ ID id-mr-integerOrderingMatch
+}
+
+bitStringMatch MATCHING-RULE ::= {
+ SYNTAX BIT STRING
+ ID id-mr-bitStringMatch
+}
+
+octetStringMatch MATCHING-RULE ::= {
+ SYNTAX OCTET STRING
+ ID id-mr-octetStringMatch
+}
+
+octetStringOrderingMatch MATCHING-RULE ::= {
+ SYNTAX OCTET STRING
+ ID id-mr-octetStringOrderingMatch
+}
+
+octetStringSubstringsMatch MATCHING-RULE ::= {
+ SYNTAX OctetSubstringAssertion
+ ID id-mr-octetStringSubstringsMatch
+}
+
+OctetSubstringAssertion ::=
+ SEQUENCE OF
+ CHOICE {initial [0] OCTET STRING,
+ any [1] OCTET STRING,
+ final [2] OCTET STRING}
+
+-- at most one initial and one final component
+telephoneNumberMatch MATCHING-RULE ::= {
+ SYNTAX TelephoneNumber
+ ID id-mr-telephoneNumberMatch
+}
+
+telephoneNumberSubstringsMatch MATCHING-RULE ::= {
+ SYNTAX SubstringAssertion
+ ID id-mr-telephoneNumberSubstringsMatch
+}
+
+presentationAddressMatch MATCHING-RULE ::= {
+ SYNTAX PresentationAddress
+ ID id-mr-presentationAddressMatch
+}
+
+uniqueMemberMatch MATCHING-RULE ::= {
+ SYNTAX NameAndOptionalUID
+ ID id-mr-uniqueMemberMatch
+}
+
+protocolInformationMatch MATCHING-RULE ::= {
+ SYNTAX OCTET STRING
+ ID id-mr-protocolInformationMatch
+}
+
+facsimileNumberMatch MATCHING-RULE ::= {
+ SYNTAX TelephoneNumber
+ ID id-mr-facsimileNumberMatch
+}
+
+facsimileNumberSubstringsMatch MATCHING-RULE ::= {
+ SYNTAX SubstringAssertion
+ ID id-mr-facsimileNumberSubstringsMatch
+}
+
+uUIDPairMatch MATCHING-RULE ::= {SYNTAX UUIDPair
+ ID id-mr-uuidpairmatch
+}
+
+uTCTimeMatch MATCHING-RULE ::= {SYNTAX UTCTime
+ ID id-mr-uTCTimeMatch
+}
+
+uTCTimeOrderingMatch MATCHING-RULE ::= {
+ SYNTAX UTCTime
+ ID id-mr-uTCTimeOrderingMatch
+}
+
+generalizedTimeMatch MATCHING-RULE ::= {
+ SYNTAX GeneralizedTime
+ -- as per 46.3 b) or c) of ITU-T Rec. X.680 | ISO/IEC 8824-1
+ ID id-mr-generalizedTimeMatch
+}
+
+generalizedTimeOrderingMatch MATCHING-RULE ::= {
+ SYNTAX GeneralizedTime
+ -- as per 46.3 b) or c) of ITU-T Rec. X.680 | ISO/IEC 8824-1
+ ID id-mr-generalizedTimeOrderingMatch
+}
+
+systemProposedMatch MATCHING-RULE ::= {ID id-mr-systemProposedMatch
+}
+
+integerFirstComponentMatch MATCHING-RULE ::= {
+ SYNTAX INTEGER
+ ID id-mr-integerFirstComponentMatch
+}
+
+objectIdentifierFirstComponentMatch MATCHING-RULE ::= {
+ SYNTAX OBJECT IDENTIFIER
+ ID id-mr-objectIdentifierFirstComponentMatch
+}
+
+directoryStringFirstComponentMatch MATCHING-RULE ::= {
+ SYNTAX UnboundedDirectoryString
+ ID id-mr-directoryStringFirstComponentMatch
+}
+
+wordMatch MATCHING-RULE ::= {
+ SYNTAX UnboundedDirectoryString
+ ID id-mr-wordMatch
+}
+
+keywordMatch MATCHING-RULE ::= {
+ SYNTAX UnboundedDirectoryString
+ ID id-mr-keywordMatch
+}
+
+generalWordMatch MATCHING-RULE ::= {
+ SYNTAX SubstringAssertion
+ ID id-mr-generalWordMatch
+}
+
+sequenceMatchType ATTRIBUTE ::= {
+ WITH SYNTAX SequenceMatchType
+ SINGLE VALUE TRUE
+ ID id-cat-sequenceMatchType
+} -- defaulting to sequenceExact
+
+SequenceMatchType ::= ENUMERATED {
+ sequenceExact(0), sequenceDeletion(1), sequenceRestrictedDeletion(2),
+ sequencePermutation(3), sequencePermutationAndDeletion(4),
+ sequenceProviderDefined(5)}
+
+wordMatchTypes ATTRIBUTE ::= {
+ WITH SYNTAX WordMatchTypes
+ SINGLE VALUE TRUE
+ ID id-cat-wordMatchType
+} -- defaulting to wordExact
+
+WordMatchTypes ::= ENUMERATED {
+ wordExact(0), wordTruncated(1), wordPhonetic(2), wordProviderDefined(3)
+}
+
+characterMatchTypes ATTRIBUTE ::= {
+ WITH SYNTAX CharacterMatchTypes
+ SINGLE VALUE TRUE
+ ID id-cat-characterMatchTypes
+}
+
+CharacterMatchTypes ::= ENUMERATED {
+ characterExact(0), characterCaseIgnore(1), characterMapped(2)}
+
+selectedContexts ATTRIBUTE ::= {
+ WITH SYNTAX ContextAssertion
+ ID id-cat-selectedContexts
+}
+
+approximateStringMatch MATCHING-RULE ::= {ID id-mr-approximateStringMatch
+}
+
+ignoreIfAbsentMatch MATCHING-RULE ::= {ID id-mr-ignoreIfAbsentMatch
+}
+
+nullMatch MATCHING-RULE ::= {ID id-mr-nullMatch
+}
+
+ZONAL-MATCHING ::=
+ MAPPING-BASED-MATCHING{ZonalSelect, TRUE, ZonalResult, zonalMatch.&id}
+
+ZonalSelect ::= SEQUENCE OF AttributeType
+
+ZonalResult ::= ENUMERATED {
+ cannot-select-mapping(0), zero-mappings(2), multiple-mappings(3)}
+
+zonalMatch MATCHING-RULE ::= {
+ UNIQUE-MATCH-INDICATOR multipleMatchingLocalities
+ ID id-mr-zonalMatch
+}
+
+-- Contexts
+languageContext CONTEXT ::= {
+ WITH SYNTAX LanguageContextSyntax
+ ID id-avc-language
+}
+
+LanguageContextSyntax ::= PrintableString(SIZE (2..3)) -- ISO 639-2 codes only
+
+
+temporalContext CONTEXT ::= {
+ WITH SYNTAX TimeSpecification
+ ASSERTED AS TimeAssertion
+ ID id-avc-temporal
+}
+
+TimeSpecification ::= SEQUENCE {
+ time
+ CHOICE {absolute
+ SEQUENCE {startTime [0] GeneralizedTime OPTIONAL,
+ endTime [1] GeneralizedTime OPTIONAL},
+ periodic SET SIZE (1..MAX) OF Period},
+ notThisTime BOOLEAN DEFAULT FALSE,
+ timeZone TimeZone OPTIONAL
+}
+
+Period ::= SEQUENCE {
+ timesOfDay [0] SET SIZE (1..MAX) OF DayTimeBand OPTIONAL,
+ days
+ [1] CHOICE {intDay SET OF INTEGER,
+ bitDay
+ BIT STRING {sunday(0), monday(1), tuesday(2), wednesday(3),
+ thursday(4), friday(5), saturday(6)},
+ dayOf XDayOf} OPTIONAL,
+ weeks
+ [2] CHOICE {allWeeks NULL,
+ intWeek SET OF INTEGER,
+ bitWeek
+ BIT STRING {week1(0), week2(1), week3(2), week4(3), week5(4)}
+ } OPTIONAL,
+ months
+ [3] CHOICE {allMonths NULL,
+ intMonth SET OF INTEGER,
+ bitMonth
+ BIT STRING {january(0), february(1), march(2), april(3),
+ may(4), june(5), july(6), august(7),
+ september(8), october(9), november(10),
+ december(11)}} OPTIONAL,
+ years [4] SET OF INTEGER(1000..MAX) OPTIONAL
+}
+
+XDayOf ::= CHOICE {
+ first [1] NamedDay,
+ second [2] NamedDay,
+ third [3] NamedDay,
+ fourth [4] NamedDay,
+ fifth [5] NamedDay
+}
+
+NamedDay ::= CHOICE {
+ intNamedDays
+ ENUMERATED {sunday(1), monday(2), tuesday(3), wednesday(4), thursday(5),
+ friday(6), saturday(7)},
+ bitNamedDays
+ BIT STRING {sunday(0), monday(1), tuesday(2), wednesday(3), thursday(4),
+ friday(5), saturday(6)}
+}
+
+DayTimeBand ::= SEQUENCE {
+ startDayTime [0] DayTime DEFAULT {hour 0},
+ endDayTime [1] DayTime DEFAULT {hour 23, minute 59, second 59}
+}
+
+DayTime ::= SEQUENCE {
+ hour [0] INTEGER(0..23),
+ minute [1] INTEGER(0..59) DEFAULT 0,
+ second [2] INTEGER(0..59) DEFAULT 0
+}
+
+TimeZone ::= INTEGER(-12..12)
+
+TimeAssertion ::= CHOICE {
+ now NULL,
+ at GeneralizedTime,
+ between
+ SEQUENCE {startTime [0] GeneralizedTime,
+ endTime [1] GeneralizedTime OPTIONAL,
+ entirely BOOLEAN DEFAULT FALSE}
+}
+
+localeContext CONTEXT ::= {
+ WITH SYNTAX LocaleContextSyntax
+ ID id-avc-locale
+}
+
+LocaleContextSyntax ::= CHOICE {
+ localeID1 OBJECT IDENTIFIER,
+ localeID2 UnboundedDirectoryString
+}
+
+ldapAttributeOptionContext CONTEXT ::= {
+ WITH SYNTAX AttributeOptionList
+ ASSERTED AS AttributeOptionList
+ ABSENT-MATCH FALSE
+ ID id-avc-ldapAttributeOption
+}
+
+AttributeOptionList ::= SEQUENCE OF UTF8String
+
+-- Object identifier assignments
+-- object identifiers assigned in other modules are shown in comments
+-- Attributes
+-- id-at-objectClass OBJECT IDENTIFIER ::= {id-at 0}
+-- id-at-aliasedEntryName OBJECT IDENTIFIER ::= {id-at 1}
+-- id-at-encryptedAliasedEntryName OBJECT IDENTIFIER ::= {id-at 1 2}
+id-at-knowledgeInformation OBJECT IDENTIFIER ::=
+ {id-at 2}
+
+id-at-commonName OBJECT IDENTIFIER ::= {id-at 3}
+
+-- id-at-encryptedCommonName OBJECT IDENTIFIER ::= {id-at 3 2}
+id-at-surname OBJECT IDENTIFIER ::=
+ {id-at 4}
+
+-- id-at-encryptedSurname OBJECT IDENTIFIER ::= {id-at 4 2}
+id-at-serialNumber OBJECT IDENTIFIER ::=
+ {id-at 5}
+
+-- id-at-encryptedSerialNumbe r OBJECT IDENTIFIER ::= {id-at 5 2}
+id-at-countryName OBJECT IDENTIFIER ::=
+ {id-at 6}
+
+-- id-at-encryptedCountryName OBJECT IDENTIFIER ::= {id-at 6 2}
+id-at-localityName OBJECT IDENTIFIER ::=
+ {id-at 7}
+
+-- id-at-encryptedLocalityName OBJECT IDENTIFIER ::= {id-at 7 2}
+id-at-collectiveLocalityName OBJECT IDENTIFIER ::=
+ {id-at 7 1}
+
+-- id-at-encryptedCollectiveLocalityName OBJECT IDENTIFIER ::= {id-at 7 1 2}
+id-at-stateOrProvinceName OBJECT IDENTIFIER ::=
+ {id-at 8}
+
+-- id-at-encryptedStateOrProvinceName OBJECT IDENTIFIER ::= {id-at 8 2}
+id-at-collectiveStateOrProvinceName OBJECT IDENTIFIER ::=
+ {id-at 8 1}
+
+-- id-at-encryptedCollectiveStateOrProvinceName OBJECT IDENTIFIER ::= {id-at 8 1 2}
+id-at-streetAddress OBJECT IDENTIFIER ::=
+ {id-at 9}
+
+-- id-at-encryptedStreetAddress OBJECT IDENTIFIER ::= {id-at 9 2}
+id-at-collectiveStreetAddress OBJECT IDENTIFIER ::=
+ {id-at 9 1}
+
+-- id-at-encryptedCollectiveStreetAddress OBJECT IDENTIFIER ::= {id-at 9 1 2}
+id-at-organizationName OBJECT IDENTIFIER ::=
+ {id-at 10}
+
+-- id-at-encryptedOrganizationName OBJECT IDENTIFIER ::= {id-at 10 2}
+id-at-collectiveOrganizationName OBJECT IDENTIFIER ::=
+ {id-at 10 1}
+
+-- id-at-encryptedCollectiveOrganizationName OBJECT IDENTIFIER ::= {id-at 10 1 2}
+id-at-organizationalUnitName OBJECT IDENTIFIER ::=
+ {id-at 11}
+
+-- id-at-encryptedOrganizationalUnitName OBJECT IDENTIFIER ::= {id-at 11 2}
+id-at-collectiveOrganizationalUnitName OBJECT IDENTIFIER ::=
+ {id-at 11 1}
+
+-- id-at-encryptedCollectiveOrganizationalUnitNam OBJECT IDENTIFIER ::= {id-at 11 1 2}
+id-at-title OBJECT IDENTIFIER ::=
+ {id-at 12}
+
+-- id-at-encryptedTitle OBJECT IDENTIFIER ::= {id-at 12 2}
+id-at-description OBJECT IDENTIFIER ::=
+ {id-at 13}
+
+-- id-at-encryptedDescription OBJECT IDENTIFIER ::= {id-at 13 2}
+id-at-searchGuide OBJECT IDENTIFIER ::=
+ {id-at 14}
+
+-- id-at-encryptedSearchGuide OBJECT IDENTIFIER ::= {id-at 14 2}
+id-at-businessCategory OBJECT IDENTIFIER ::=
+ {id-at 15}
+
+-- id-at-encryptedBusinessCategory OBJECT IDENTIFIER ::= {id-at 15 2}
+id-at-postalAddress OBJECT IDENTIFIER ::=
+ {id-at 16}
+
+-- id-at-encryptedPostalAddress OBJECT IDENTIFIER ::= {id-at 16 2}
+id-at-collectivePostalAddress OBJECT IDENTIFIER ::=
+ {id-at 16 1}
+
+-- id-at-encryptedCollectivePostalAddress OBJECT IDENTIFIER ::= {id-at 16 1 2}
+id-at-postalCode OBJECT IDENTIFIER ::=
+ {id-at 17}
+
+-- id-at-encryptedPostalCode OBJECT IDENTIFIER ::= {id-at 17 2}
+id-at-collectivePostalCode OBJECT IDENTIFIER ::=
+ {id-at 17 1}
+
+-- id-at-encryptedCollectivePostalCode OBJECT IDENTIFIER ::= {id-at 17 1 2}
+id-at-postOfficeBox OBJECT IDENTIFIER ::=
+ {id-at 18}
+
+id-at-collectivePostOfficeBox OBJECT IDENTIFIER ::= {id-at 18 1}
+
+-- id-at-encryptedPostOfficeBox OBJECT IDENTIFIER ::= {id-at 18 2}
+-- id-at-encryptedCollectivePostOfficeBox OBJECT IDENTIFIER ::= {id-at 18 1 2}
+id-at-physicalDeliveryOfficeName OBJECT IDENTIFIER ::=
+ {id-at 19}
+
+id-at-collectivePhysicalDeliveryOfficeName OBJECT IDENTIFIER ::= {id-at 19 1}
+
+-- id-at-encryptedPhysicalDeliveryOfficeName OBJECT IDENTIFIER ::= {id-at 19 2}
+-- id-at-encryptedCollectivePhysicalDeliveryOfficeName OBJECT IDENTIFIER ::= {id-at 19 1 2}
+id-at-telephoneNumber OBJECT IDENTIFIER ::=
+ {id-at 20}
+
+-- id-at-encryptedTelephoneNumber OBJECT IDENTIFIER ::= {id-at 20 2}
+id-at-collectiveTelephoneNumber OBJECT IDENTIFIER ::=
+ {id-at 20 1}
+
+-- id-at-encryptedCollectiveTelephoneNumber OBJECT IDENTIFIER ::= {id-at 20 1 2}
+id-at-telexNumber OBJECT IDENTIFIER ::=
+ {id-at 21}
+
+-- id-at-encryptedTelexNumber OBJECT IDENTIFIER ::= {id-at 21 2}
+id-at-collectiveTelexNumber OBJECT IDENTIFIER ::=
+ {id-at 21 1}
+
+-- id-at-encryptedCollectiveTelexNumber OBJECT IDENTIFIER ::= {id-at 21 1 2}
+-- id-at-teletexTerminalIdentifier OBJECT IDENTIFIER ::= {id-at 22}
+-- id-at-encryptedTeletexTerminalIdentifier OBJECT IDENTIFIER ::= {id-at 22 2}
+-- id-at-collectiveTeletexTerminalIdentifier OBJECT IDENTIFIER ::= {id-at 22 1}
+-- id-at-encryptedCollectiveTeletexTerminalIdentifier OBJECT IDENTIFIER ::= {id-at 22 1 2}
+id-at-facsimileTelephoneNumber OBJECT IDENTIFIER ::=
+ {id-at 23}
+
+-- id-at-encryptedFacsimileTelephoneNumber OBJECT IDENTIFIER ::= {id-at 23 2}
+id-at-collectiveFacsimileTelephoneNumber OBJECT IDENTIFIER ::=
+ {id-at 23 1}
+
+-- id-at-encryptedCollectiveFacsimileTelephoneNumber OBJECT IDENTIFIER ::= {id-at 23 1 2}
+id-at-x121Address OBJECT IDENTIFIER ::=
+ {id-at 24}
+
+-- id-at-encryptedX121Address OBJECT IDENTIFIER ::= {id-at 24 2}
+id-at-internationalISDNNumber OBJECT IDENTIFIER ::=
+ {id-at 25}
+
+-- id-at-encryptedInternationalISDNNumber OBJECT IDENTIFIER ::= {id-at 25 2}
+id-at-collectiveInternationalISDNNumber OBJECT IDENTIFIER ::=
+ {id-at 25 1}
+
+-- id-at-encryptedCollectiveInternationalISDNNumber OBJECT IDENTIFIER ::= {id-at 25 1 2}
+id-at-registeredAddress OBJECT IDENTIFIER ::=
+ {id-at 26}
+
+-- id-at-encryptedRegisteredAddress OBJECT IDENTIFIER ::= {id-at 26 2}
+id-at-destinationIndicator OBJECT IDENTIFIER ::=
+ {id-at 27}
+
+-- id-at-encryptedDestinationIndicator OBJECT IDENTIFIER ::= {id-at 27 2}
+id-at-preferredDeliveryMethod OBJECT IDENTIFIER ::=
+ {id-at 28}
+
+-- id-at-encryptedPreferredDeliveryMethod OBJECT IDENTIFIER ::= {id-at 28 2}
+id-at-presentationAddress OBJECT IDENTIFIER ::=
+ {id-at 29}
+
+-- id-at-encryptedPresentationAddress OBJECT IDENTIFIER ::= {id-at 29 2}
+id-at-supportedApplicationContext OBJECT IDENTIFIER ::=
+ {id-at 30}
+
+-- id-at-encryptedSupportedApplicationContext OBJECT IDENTIFIER ::= {id-at 30 2}
+id-at-member OBJECT IDENTIFIER ::=
+ {id-at 31}
+
+-- id-at-encryptedMember OBJECT IDENTIFIER ::= {id-at 31 2}
+id-at-owner OBJECT IDENTIFIER ::=
+ {id-at 32}
+
+-- id-at-encryptedOwner OBJECT IDENTIFIER ::= {id-at 32 2}
+id-at-roleOccupant OBJECT IDENTIFIER ::=
+ {id-at 33}
+
+-- id-at-encryptedRoleOccupant OBJECT IDENTIFIER ::= {id-at 33 2}
+id-at-seeAlso OBJECT IDENTIFIER ::=
+ {id-at 34}
+
+-- id-at-encryptedSeeAlso OBJECT IDENTIFIER ::= {id-at 34 2}
+-- id-at-userPassword OBJECT IDENTIFIER ::= {id-at 35} X.509|Part8
+-- id-at-encryptedUserPassword OBJECT IDENTIFIER ::= {id-at 35 2}
+-- id-at-userCertificate OBJECT IDENTIFIER ::= {id-at 36} X.509|Part8
+-- id-at-encryptedUserCertificate OBJECT IDENTIFIER ::= {id-at 36 2}
+-- id-at-cACertificate OBJECT IDENTIFIER ::= {id-at 37} X.509|Part8
+-- id-at-encryptedCACertificate OBJECT IDENTIFIER ::= {id-at 37 2}
+-- id-at-authorityRevocationList OBJECT IDENTIFIER ::= {id-at 38} X.509|Part8
+-- id-at-encryptedAuthorityRevocationList OBJECT IDENTIFIER ::= {id-at 38 2}
+-- id-at-certificateRevocationList OBJECT IDENTIFIER ::= {id-at 39} X.509|Part8
+-- id-at-encryptedCertificateRevocationList OBJECT IDENTIFIER ::= {id-at 39 2}
+-- id-at-crossCertificatePair OBJECT IDENTIFIER ::= {id-at 40} X.509|Part8
+-- id-at-encryptedCrossCertificatePair OBJECT IDENTIFIER ::= {id-at 40 2}
+id-at-name OBJECT IDENTIFIER ::=
+ {id-at 41}
+
+id-at-givenName OBJECT IDENTIFIER ::= {id-at 42}
+
+-- id-at-encryptedGivenName OBJECT IDENTIFIER ::= {id-at 42 2}
+id-at-initials OBJECT IDENTIFIER ::=
+ {id-at 43}
+
+-- id-at-encryptedInitials OBJECT IDENTIFIER ::= {id-at 43 2}
+id-at-generationQualifier OBJECT IDENTIFIER ::=
+ {id-at 44}
+
+-- id-at-encryptedGenerationQualifier OBJECT IDENTIFIER ::= {id-at 44 2}
+id-at-uniqueIdentifier OBJECT IDENTIFIER ::=
+ {id-at 45}
+
+-- id-at-encryptedUniqueIdentifier OBJECT IDENTIFIER ::= {id-at 45 2}
+id-at-dnQualifier OBJECT IDENTIFIER ::=
+ {id-at 46}
+
+-- id-at-encryptedDnQualifier OBJECT IDENTIFIER ::= {id-at 46 2}
+id-at-enhancedSearchGuide OBJECT IDENTIFIER ::=
+ {id-at 47}
+
+-- id-at-encryptedEnhancedSearchGuide OBJECT IDENTIFIER ::= {id-at 47 2}
+id-at-protocolInformation OBJECT IDENTIFIER ::=
+ {id-at 48}
+
+-- id-at-encryptedProtocolInformation OBJECT IDENTIFIER ::= {id-at 48 2}
+id-at-distinguishedName OBJECT IDENTIFIER ::=
+ {id-at 49}
+
+-- id-at-encryptedDistinguishedName OBJECT IDENTIFIER ::= {id-at 49 2}
+id-at-uniqueMember OBJECT IDENTIFIER ::=
+ {id-at 50}
+
+-- id-at-encryptedUniqueMember OBJECT IDENTIFIER ::= {id-at 50 2}
+id-at-houseIdentifier OBJECT IDENTIFIER ::=
+ {id-at 51}
+
+-- id-at-encryptedHouseIdentifier OBJECT IDENTIFIER ::= {id-at 51 2}
+-- id-at-supportedAlgorithms OBJECT IDENTIFIER ::= {id-at 52} X.509|Part8
+-- id-at-encryptedSupportedAlgorithms OBJECT IDENTIFIER ::= {id-at 52 2}
+-- id-at-deltaRevocationList OBJECT IDENTIFIER ::= {id-at 53} X.509|Part8
+-- id-at-encryptedDeltaRevocationList OBJECT IDENTIFIER ::= {id-at 53 2}
+id-at-dmdName OBJECT IDENTIFIER ::=
+ {id-at 54}
+
+-- id-at-encryptedDmdName OBJECT IDENTIFIER ::= {id-at 54 2}
+-- id-at-clearance OBJECT IDENTIFIER ::= {id-at 55}
+-- id-at-encryptedClearance OBJECT IDENTIFIER ::= {id-at 55 2}
+-- id-at-defaultDirQop OBJECT IDENTIFIER ::= {id-at 56}
+-- id-at-encryptedDefaultDirQop OBJECT IDENTIFIER ::= {id-at 56 2}
+-- id-at-attributeIntegrityInfo OBJECT IDENTIFIER ::= {id-at 57}
+-- id-at-encryptedAttributeIntegrityInfo OBJECT IDENTIFIER ::= {id-at 57 2}
+-- id-at-attributeCertificate OBJECT IDENTIFIER ::= {id-at 58} X.509|Part8
+-- id-at-encryptedAttributeCertificate OBJECT IDENTIFIER ::= {id-at 58 2}
+-- id-at-attributeCertificateRevocationList OBJECT IDENTIFIER ::= {id-at 59} X.509|Part8
+-- id-at-encryptedAttributeCertificateRevocationList OBJECT IDENTIFIER ::= {id-at 59 2}
+-- id-at-confKeyInfo OBJECT IDENTIFIER ::= {id-at 60}
+-- id-at-encryptedConfKeyInfo OBJECT IDENTIFIER ::= {id-at 60 2}
+-- id-at-aACertificate OBJECT IDENTIFIER ::= {id-at 61} X.509|Part8
+-- id-at-attributeDescriptorCertificate OBJECT IDENTIFIER ::= {id-at 62} X.509|Part8
+-- id-at-attributeAuthorityRevocationList OBJECT IDENTIFIER ::= {id-at 63} X.509|Part8
+-- id-at-family-information OBJECT IDENTIFIER ::= {id-at 64}
+id-at-pseudonym OBJECT IDENTIFIER ::=
+ {id-at 65}
+
+id-at-communicationsService OBJECT IDENTIFIER ::= {id-at 66}
+
+id-at-communicationsNetwork OBJECT IDENTIFIER ::= {id-at 67}
+
+-- id-at-certificationPracticeStmt OBJECT IDENTIFIER ::= {id-at 68} X.509|Part8
+-- id-at-certificatePolicy OBJECT IDENTIFIER ::= {id-at 69} X.509|Part8
+-- id-at-pkiPath OBJECT IDENTIFIER ::= {id-at 70} X.509|Part8
+-- id-at-privPolicy OBJECT IDENTIFIER ::= {id-at 71} X.509|Part8
+-- id-at-role OBJECT IDENTIFIER ::= {id-at 72} X.509|Part8
+-- id-at-delegationPath OBJECT IDENTIFIER ::= {id-at 73} X.509|Part8
+-- id-at-protPrivPolicy OBJECT IDENTIFIER ::= {id-at 74} X.509|Part8
+-- id-at-xMLPrivilegeInfo OBJECT IDENTIFIER ::= {id-at 75} X.509|Part8
+-- id-at-xmlPrivPolicy OBJECT IDENTIFIER ::= {id-at 76} X.509|Part8
+id-at-uuidpair OBJECT IDENTIFIER ::=
+ {id-at 77}
+
+id-at-tagOid OBJECT IDENTIFIER ::= {id-at 78}
+
+id-at-uiiFormat OBJECT IDENTIFIER ::= {id-at 79}
+
+id-at-uiiInUrn OBJECT IDENTIFIER ::= {id-at 80}
+
+id-at-contentUri OBJECT IDENTIFIER ::= {id-at 81}
+
+-- id-at-permission OBJECT IDENTIFIER ::= {id-at 82} X.509|Part8
+-- Control attributes
+id-cat-sequenceMatchType OBJECT IDENTIFIER ::=
+ {id-cat 1}
+
+id-cat-wordMatchType OBJECT IDENTIFIER ::= {id-cat 2}
+
+id-cat-characterMatchTypes OBJECT IDENTIFIER ::= {id-cat 3}
+
+id-cat-selectedContexts OBJECT IDENTIFIER ::= {id-cat 4}
+
+-- Notification attributes
+id-not-dSAProblem OBJECT IDENTIFIER ::= {id-not 0}
+
+id-not-searchServiceProblem OBJECT IDENTIFIER ::= {id-not 1}
+
+id-not-serviceType OBJECT IDENTIFIER ::= {id-not 2}
+
+id-not-attributeTypeList OBJECT IDENTIFIER ::= {id-not 3}
+
+id-not-matchingRuleList OBJECT IDENTIFIER ::= {id-not 4}
+
+id-not-filterItem OBJECT IDENTIFIER ::= {id-not 5}
+
+id-not-attributeCombinations OBJECT IDENTIFIER ::= {id-not 6}
+
+id-not-contextTypeList OBJECT IDENTIFIER ::= {id-not 7}
+
+id-not-contextList OBJECT IDENTIFIER ::= {id-not 8}
+
+id-not-contextCombinations OBJECT IDENTIFIER ::= {id-not 9}
+
+id-not-hierarchySelectList OBJECT IDENTIFIER ::= {id-not 10}
+
+id-not-searchControlOptionsList OBJECT IDENTIFIER ::= {id-not 11}
+
+id-not-serviceControlOptionsList OBJECT IDENTIFIER ::= {id-not 12}
+
+id-not-multipleMatchingLocalities OBJECT IDENTIFIER ::= {id-not 13}
+
+id-not-proposedRelaxation OBJECT IDENTIFIER ::= {id-not 14}
+
+id-not-appliedRelaxation OBJECT IDENTIFIER ::= {id-not 15}
+
+-- Problem definitions
+id-pr-targetDsaUnavailable OBJECT IDENTIFIER ::=
+ {id-pr 1}
+
+id-pr-dataSourceUnavailable OBJECT IDENTIFIER ::= {id-pr 2}
+
+id-pr-unidentifiedOperation OBJECT IDENTIFIER ::= {id-pr 3}
+
+id-pr-unavailableOperation OBJECT IDENTIFIER ::= {id-pr 4}
+
+id-pr-searchAttributeViolation OBJECT IDENTIFIER ::= {id-pr 5}
+
+id-pr-searchAttributeCombinationViolation OBJECT IDENTIFIER ::= {id-pr 6}
+
+id-pr-searchValueNotAllowed OBJECT IDENTIFIER ::= {id-pr 7}
+
+id-pr-missingSearchAttribute OBJECT IDENTIFIER ::= {id-pr 8}
+
+id-pr-searchValueViolation OBJECT IDENTIFIER ::= {id-pr 9}
+
+id-pr-attributeNegationViolation OBJECT IDENTIFIER ::= {id-pr 10}
+
+id-pr-searchValueRequired OBJECT IDENTIFIER ::= {id-pr 11}
+
+id-pr-invalidSearchValue OBJECT IDENTIFIER ::= {id-pr 12}
+
+id-pr-searchContextViolation OBJECT IDENTIFIER ::= {id-pr 13}
+
+id-pr-searchContextCombinationViolation OBJECT IDENTIFIER ::= {id-pr 14}
+
+id-pr-missingSearchContext OBJECT IDENTIFIER ::= {id-pr 15}
+
+id-pr-searchContextValueViolation OBJECT IDENTIFIER ::= {id-pr 16}
+
+id-pr-searchContextValueRequired OBJECT IDENTIFIER ::= {id-pr 17}
+
+id-pr-invalidContextSearchValue OBJECT IDENTIFIER ::= {id-pr 18}
+
+id-pr-unsupportedMatchingRule OBJECT IDENTIFIER ::= {id-pr 19}
+
+id-pr-attributeMatchingViolation OBJECT IDENTIFIER ::= {id-pr 20}
+
+id-pr-unsupportedMatchingUse OBJECT IDENTIFIER ::= {id-pr 21}
+
+id-pr-matchingUseViolation OBJECT IDENTIFIER ::= {id-pr 22}
+
+id-pr-hierarchySelectForbidden OBJECT IDENTIFIER ::= {id-pr 23}
+
+id-pr-invalidHierarchySelect OBJECT IDENTIFIER ::= {id-pr 24}
+
+id-pr-unavailableHierarchySelect OBJECT IDENTIFIER ::= {id-pr 25}
+
+id-pr-invalidSearchControlOptions OBJECT IDENTIFIER ::= {id-pr 26}
+
+id-pr-invalidServiceControlOptions OBJECT IDENTIFIER ::= {id-pr 27}
+
+id-pr-searchSubsetViolation OBJECT IDENTIFIER ::= {id-pr 28}
+
+id-pr-unmatchedKeyAttributes OBJECT IDENTIFIER ::= {id-pr 29}
+
+id-pr-ambiguousKeyAttributes OBJECT IDENTIFIER ::= {id-pr 30}
+
+id-pr-unavailableRelaxationLevel OBJECT IDENTIFIER ::= {id-pr 31}
+
+id-pr-emptyHierarchySelection OBJECT IDENTIFIER ::= {id-pr 32}
+
+id-pr-administratorImposedLimit OBJECT IDENTIFIER ::= {id-pr 33}
+
+id-pr-permanentRestriction OBJECT IDENTIFIER ::= {id-pr 34}
+
+id-pr-temporaryRestriction OBJECT IDENTIFIER ::= {id-pr 35}
+
+id-pr-relaxationNotSupported OBJECT IDENTIFIER ::= {id-pr 36}
+
+-- Matching rules
+-- id-mr-objectIdentifierMatch OBJECT IDENTIFIER ::= {id-mr 0} X.501|Part2
+-- id-mr-distinguishedNameMatch OBJECT IDENTIFIER ::= {id-mr 1} X.501|Part2
+id-mr-caseIgnoreMatch OBJECT IDENTIFIER ::=
+ {id-mr 2}
+
+id-mr-caseIgnoreOrderingMatch OBJECT IDENTIFIER ::= {id-mr 3}
+
+id-mr-caseIgnoreSubstringsMatch OBJECT IDENTIFIER ::= {id-mr 4}
+
+id-mr-caseExactMatch OBJECT IDENTIFIER ::= {id-mr 5}
+
+id-mr-caseExactOrderingMatch OBJECT IDENTIFIER ::= {id-mr 6}
+
+id-mr-caseExactSubstringsMatch OBJECT IDENTIFIER ::= {id-mr 7}
+
+id-mr-numericStringMatch OBJECT IDENTIFIER ::= {id-mr 8}
+
+id-mr-numericStringOrderingMatch OBJECT IDENTIFIER ::= {id-mr 9}
+
+id-mr-numericStringSubstringsMatch OBJECT IDENTIFIER ::= {id-mr 10}
+
+id-mr-caseIgnoreListMatch OBJECT IDENTIFIER ::= {id-mr 11}
+
+id-mr-caseIgnoreListSubstringsMatch OBJECT IDENTIFIER ::= {id-mr 12}
+
+id-mr-booleanMatch OBJECT IDENTIFIER ::= {id-mr 13}
+
+id-mr-integerMatch OBJECT IDENTIFIER ::= {id-mr 14}
+
+id-mr-integerOrderingMatch OBJECT IDENTIFIER ::= {id-mr 15}
+
+id-mr-bitStringMatch OBJECT IDENTIFIER ::= {id-mr 16}
+
+id-mr-octetStringMatch OBJECT IDENTIFIER ::= {id-mr 17}
+
+id-mr-octetStringOrderingMatch OBJECT IDENTIFIER ::= {id-mr 18}
+
+id-mr-octetStringSubstringsMatch OBJECT IDENTIFIER ::= {id-mr 19}
+
+id-mr-telephoneNumberMatch OBJECT IDENTIFIER ::= {id-mr 20}
+
+id-mr-telephoneNumberSubstringsMatch OBJECT IDENTIFIER ::= {id-mr 21}
+
+id-mr-presentationAddressMatch OBJECT IDENTIFIER ::= {id-mr 22}
+
+id-mr-uniqueMemberMatch OBJECT IDENTIFIER ::= {id-mr 23}
+
+id-mr-protocolInformationMatch OBJECT IDENTIFIER ::= {id-mr 24}
+
+id-mr-uTCTimeMatch OBJECT IDENTIFIER ::= {id-mr 25}
+
+id-mr-uTCTimeOrderingMatch OBJECT IDENTIFIER ::= {id-mr 26}
+
+id-mr-generalizedTimeMatch OBJECT IDENTIFIER ::= {id-mr 27}
+
+id-mr-generalizedTimeOrderingMatch OBJECT IDENTIFIER ::= {id-mr 28}
+
+id-mr-integerFirstComponentMatch OBJECT IDENTIFIER ::= {id-mr 29}
+
+id-mr-objectIdentifierFirstComponentMatch OBJECT IDENTIFIER ::= {id-mr 30}
+
+id-mr-directoryStringFirstComponentMatch OBJECT IDENTIFIER ::= {id-mr 31}
+
+id-mr-wordMatch OBJECT IDENTIFIER ::= {id-mr 32}
+
+id-mr-keywordMatch OBJECT IDENTIFIER ::= {id-mr 33}
+
+-- id-mr-certificateExactMatch OBJECT IDENTIFIER ::= {id-mr 34} X.509|Part8
+-- id-mr-certificateMatch OBJECT IDENTIFIER ::= {id-mr 35} X.509|Part8
+-- id-mr-certificatePairExactMatch OBJECT IDENTIFIER ::= {id-mr 36} X.509|Part8
+-- id-mr-certificatePairMatch OBJECT IDENTIFIER ::= {id-mr 37} X.509|Part8
+-- id-mr-certificateListExactMatch OBJECT IDENTIFIER ::= {id-mr 38} X.509|Part8
+-- id-mr-certificateListMatch OBJECT IDENTIFIER ::= {id-mr 39} X.509|Part8
+-- id-mr-algorithmIdentifierMatch OBJECT IDENTIFIER ::= {id-mr 40} X.509|Part8
+id-mr-storedPrefixMatch OBJECT IDENTIFIER ::=
+ {id-mr 41}
+
+-- id-mr-attributeCertificateMatch OBJECT IDENTIFIER ::= {id-mr 42} X.509|Part8
+-- id-mr-readerAndKeyIDMatch OBJECT IDENTIFIER ::= {id-mr 43}
+-- id-mr-attributeIntegrityMatch OBJECT IDENTIFIER ::= {id-mr 44}
+-- id-mr-attributeCertificateExactMatch OBJECT IDENTIFIER ::= {id-mr 45} X.509|Part8
+-- id-mr-holderIssuerMatch OBJECT IDENTIFIER ::= {id-mr 46} X.509|Part8
+id-mr-systemProposedMatch OBJECT IDENTIFIER ::=
+ {id-mr 47}
+
+id-mr-generalWordMatch OBJECT IDENTIFIER ::= {id-mr 48}
+
+id-mr-approximateStringMatch OBJECT IDENTIFIER ::= {id-mr 49}
+
+id-mr-ignoreIfAbsentMatch OBJECT IDENTIFIER ::= {id-mr 50}
+
+id-mr-nullMatch OBJECT IDENTIFIER ::= {id-mr 51}
+
+id-mr-zonalMatch OBJECT IDENTIFIER ::= {id-mr 52}
+
+-- id-mr-authAttIdMatch OBJECT IDENTIFIER ::= {id-mr 53} X.509|Part8
+-- id-mr-roleSpecCertIdMatch OBJECT IDENTIFIER ::= {id-mr 54} X.509|Part8
+-- id-mr-basicAttConstraintsMatch OBJECT IDENTIFIER ::= {id-mr 55} X.509|Part8
+-- id-mr-delegatedNameConstraintsMatch OBJECT IDENTIFIER ::= {id-mr 56} X.509|Part8
+-- id-mr-timeSpecMatch OBJECT IDENTIFIER ::= {id-mr 57} X.509|Part8
+-- id-mr-attDescriptorMatch OBJECT IDENTIFIER ::= {id-mr 58} X.509|Part8
+-- id-mr-acceptableCertPoliciesMatch OBJECT IDENTIFIER ::= {id-mr 59} X.509|Part8
+-- id-mr-policyMatch OBJECT IDENTIFIER ::= {id-mr 60} X.509|Part8
+-- id-mr-delegationPathMatch OBJECT IDENTIFIER ::= {id-mr 61} X.509|Part8
+-- id-mr-pkiPathMatch OBJECT IDENTIFIER ::= {id-mr 62} X.509|Part8
+id-mr-facsimileNumberMatch OBJECT IDENTIFIER ::=
+ {id-mr 63}
+
+id-mr-facsimileNumberSubstringsMatch OBJECT IDENTIFIER ::= {id-mr 64}
+
+-- id-mr-enhancedCertificateMatch OBJECT IDENTIFIER ::= {id-mr 65} X.509|Part8
+-- id-mr-sOAIdentifierMatch OBJECT IDENTIFIER ::= {id-mr 66} X.509|Part8
+-- id-mr-extensionPresenceMatch OBJECT IDENTIFIER ::= {id-mr 67} X.509|Part8
+id-mr-uuidpairmatch OBJECT IDENTIFIER ::=
+ {id-mr 68}
+
+-- id-mr-dualStringMatch OBJECT IDENTIFIER ::= {id-mr 69} X.509|Part8
+-- contexts
+id-avc-language OBJECT IDENTIFIER ::=
+ {id-avc 0}
+
+id-avc-temporal OBJECT IDENTIFIER ::= {id-avc 1}
+
+id-avc-locale OBJECT IDENTIFIER ::= {id-avc 2}
+
+-- id-avc-attributeValueSecurityLabelContext OBJECT IDENTIFIER ::= {id-avc 3}
+-- id-avc-attributeValueIntegrityInfoContext OBJECT IDENTIFIER ::= {id-avc 4}
+id-avc-ldapAttributeOption OBJECT IDENTIFIER ::=
+ {id-avc 5}
+
+END -- SelectedAttributeTypes
diff --git a/lib/public_key/asn1/UsefulDefinitions.asn1 b/lib/public_key/asn1/UsefulDefinitions.asn1
new file mode 100644
index 0000000000..a200aac6e2
--- /dev/null
+++ b/lib/public_key/asn1/UsefulDefinitions.asn1
@@ -0,0 +1,234 @@
+UsefulDefinitions {joint-iso-itu-t ds(5) module(1) usefulDefinitions(0) 3}
+DEFINITIONS ::=
+BEGIN
+
+-- EXPORTS All -
+-- The types and values defined in this module are exported for use in the other ASN.1 modules contained
+-- within the Directory Specifications, and for the use of other applications which will use them to access
+-- Directory services. Other applications may use them for their own purposes, but this will not constrain
+-- extensions and modifications needed to maintain or improve the Directory service.
+ID ::= OBJECT IDENTIFIER
+
+ds ID ::= {joint-iso-itu-t ds(5)}
+
+-- categories of information object
+module ID ::= {ds 1}
+
+serviceElement ID ::= {ds 2}
+
+applicationContext ID ::= {ds 3}
+
+attributeType ID ::= {ds 4}
+
+attributeSyntax ID ::= {ds 5}
+
+objectClass ID ::= {ds 6}
+
+-- attributeSet ID ::= {ds 7}
+algorithm ID ::= {ds 8}
+
+abstractSyntax ID ::= {ds 9}
+
+-- object ID ::= {ds 10}
+-- port ID ::= {ds 11}
+dsaOperationalAttribute ID ::=
+ {ds 12}
+
+matchingRule ID ::= {ds 13}
+
+knowledgeMatchingRule ID ::= {ds 14}
+
+nameForm ID ::= {ds 15}
+
+group ID ::= {ds 16}
+
+subentry ID ::= {ds 17}
+
+operationalAttributeType ID ::= {ds 18}
+
+operationalBinding ID ::= {ds 19}
+
+schemaObjectClass ID ::= {ds 20}
+
+schemaOperationalAttribute ID ::= {ds 21}
+
+administrativeRoles ID ::= {ds 23}
+
+accessControlAttribute ID ::= {ds 24}
+
+rosObject ID ::= {ds 25}
+
+contract ID ::= {ds 26}
+
+package ID ::= {ds 27}
+
+accessControlSchemes ID ::= {ds 28}
+
+certificateExtension ID ::= {ds 29}
+
+managementObject ID ::= {ds 30}
+
+attributeValueContext ID ::= {ds 31}
+
+-- securityExchange ID ::= {ds 32}
+idmProtocol ID ::= {ds 33}
+
+problem ID ::= {ds 34}
+
+notification ID ::= {ds 35}
+
+matchingRestriction ID ::=
+ {ds 36} -- None are currently defined by this specification
+
+controlAttributeType ID ::= {ds 37}
+
+-- modules
+usefulDefinitions ID ::= {module usefulDefinitions(0) 3}
+
+informationFramework ID ::= {module informationFramework(1) 3}
+
+directoryAbstractService ID ::= {module directoryAbstractService(2) 3}
+
+distributedOperations ID ::= {module distributedOperations(3) 3}
+
+protocolObjectIdentifiers ID ::= {module protocolObjectIdentifiers(4) 3}
+
+selectedAttributeTypes ID ::= {module selectedAttributeTypes(5) 3}
+
+selectedObjectClasses ID ::= {module selectedObjectClasses(6) 3}
+
+authenticationFramework ID ::= {module authenticationFramework(7) 3}
+
+algorithmObjectIdentifiers ID ::= {module algorithmObjectIdentifiers(8) 3}
+
+directoryObjectIdentifiers ID ::= {module directoryObjectIdentifiers(9) 3}
+
+upperBounds ID ::= {module upperBounds(10) 3}
+
+dap ID ::= {module dap(11) 3}
+
+dsp ID ::= {module dsp(12) 3}
+
+distributedDirectoryOIDs ID ::= {module distributedDirectoryOIDs(13) 3}
+
+directoryShadowOIDs ID ::= {module directoryShadowOIDs(14) 3}
+
+directoryShadowAbstractService ID ::=
+ {module directoryShadowAbstractService(15) 3}
+
+disp ID ::= {module disp(16) 3}
+
+dop ID ::= {module dop(17) 3}
+
+opBindingManagement ID ::= {module opBindingManagement(18) 3}
+
+opBindingOIDs ID ::= {module opBindingOIDs(19) 3}
+
+hierarchicalOperationalBindings ID ::=
+ {module hierarchicalOperationalBindings(20) 3}
+
+dsaOperationalAttributeTypes ID ::= {module dsaOperationalAttributeTypes(22) 3}
+
+schemaAdministration ID ::= {module schemaAdministration(23) 3}
+
+basicAccessControl ID ::= {module basicAccessControl(24) 3}
+
+directoryOperationalBindingTypes ID ::=
+ {module directoryOperationalBindingTypes(25) 3}
+
+certificateExtensions ID ::= {module certificateExtensions(26) 0}
+
+directoryManagement ID ::= {module directoryManagement(27) 1}
+
+enhancedSecurity ID ::= {module enhancedSecurity(28) 1}
+
+iDMProtocolSpecification ID ::= {module iDMProtocolSpecification(30) 4}
+
+directoryIDMProtocols ID ::= {module directoryIDMProtocols(31) 4}
+
+-- directorySecurityExchanges ID ::= {module directorySecurityExchanges (29) 1}
+-- synonyms
+id-oc ID ::=
+ objectClass
+
+id-at ID ::= attributeType
+
+id-as ID ::= abstractSyntax
+
+id-mr ID ::= matchingRule
+
+id-nf ID ::= nameForm
+
+id-sc ID ::= subentry
+
+id-oa ID ::= operationalAttributeType
+
+id-ob ID ::= operationalBinding
+
+id-doa ID ::= dsaOperationalAttribute
+
+id-kmr ID ::= knowledgeMatchingRule
+
+id-soc ID ::= schemaObjectClass
+
+id-soa ID ::= schemaOperationalAttribute
+
+id-ar ID ::= administrativeRoles
+
+id-aca ID ::= accessControlAttribute
+
+id-ac ID ::= applicationContext
+
+id-rosObject ID ::= rosObject
+
+id-contract ID ::= contract
+
+id-package ID ::= package
+
+id-acScheme ID ::= accessControlSchemes
+
+id-ce ID ::= certificateExtension
+
+id-mgt ID ::= managementObject
+
+id-idm ID ::= idmProtocol
+
+id-avc ID ::= attributeValueContext
+
+-- id-se ID ::= securityExchange
+id-pr ID ::= problem
+
+id-not ID ::= notification
+
+id-mre ID ::= matchingRestriction
+
+id-cat ID ::= controlAttributeType
+
+-- obsolete module identifiers
+-- usefulDefinition ID ::= {module 0}
+-- informationFramework ID ::= {module 1}
+-- directoryAbstractService ID ::= {module 2}
+-- distributedOperations ID ::= {module 3}
+-- protocolObjectIdentifiers ID ::= {module 4}
+-- selectedAttributeTypes ID ::= {module 5}
+-- selectedObjectClasses ID ::= {module 6}
+-- authenticationFramework ID ::= {module 7}
+-- algorithmObjectIdentifiers ID ::= {module 8}
+-- directoryObjectIdentifiers ID ::= {module 9}
+-- upperBounds ID ::= {module 10}
+-- dap ID ::= {module 11}
+-- dsp ID ::= {module 12}
+-- distributedDirectoryObjectIdentifiers ID ::= {module 13}
+-- unused module identifiers
+-- directoryShadowOIDs ID ::= {module 14}
+-- directoryShadowAbstractService ID ::= {module 15}
+-- disp ID ::= {module 16}
+-- dop ID ::= {module 17}
+-- opBindingManagement ID ::= {module 18}
+-- opBindingOIDs ID ::= {module 19}
+-- hierarchicalOperationalBindings ID ::= {module 20}
+-- dsaOperationalAttributeTypes ID ::= {module 22}
+-- schemaAdministration ID ::= {module 23}
+-- basicAccessControl ID ::= {module 24}
+-- operationalBindingOIDs ID ::= {module 25}
+END -- UsefulDefinitions
diff --git a/lib/public_key/doc/src/cert_records.xml b/lib/public_key/doc/src/cert_records.xml
index ad4f5812cb..f01f7dbaf5 100644
--- a/lib/public_key/doc/src/cert_records.xml
+++ b/lib/public_key/doc/src/cert_records.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2008</year>
- <year>2011</year>
+ <year>2013</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -34,10 +34,12 @@
<file>cert_records.xml</file>
</header>
- <p>This chapter briefly describes erlang records derived from asn1
- specifications used to handle X509 certificates. The intent is to
- describe the data types and not to specify the meaning of each
- component for this we refer you to RFC 5280.
+ <p>This chapter briefly describes erlang records derived from ASN1
+ specifications used to handle <c> X509 certificates</c> and <c>CertificationRequest</c>.
+ The intent is to describe the data types and not to specify the meaning of each
+ component for this we refer you to <url
+ href="http://www.ietf.org/rfc/rfc5280.txt">RFC 5280</url> and
+ <url href="http://www.rsa.com/rsalabs/node.asp?id=2124">PKCS-10</url>.
</p>
<p>Use the following include directive to get access to the
@@ -45,7 +47,7 @@
<code> -include_lib("public_key/include/public_key.hrl"). </code>
- <p>The used asn1 specifications are available <c>asn1</c> subdirectory
+ <p>The used ASN1 specifications are available <c>asn1</c> subdirectory
of the application <c>public_key</c>.
</p>
@@ -59,7 +61,7 @@
follows here.</p>
<p><c>oid() - a tuple of integers
- as generated by the asn1 compiler.</c></p>
+ as generated by the ASN1 compiler.</c></p>
<p><c>time() = uct_time() | general_time()</c></p>
@@ -98,7 +100,7 @@
#'Certificate'{
tbsCertificate, % #'TBSCertificate'{}
signatureAlgorithm, % #'AlgorithmIdentifier'{}
- signature % {0, binary()} - asn1 compact bitstring
+ signature % {0, binary()} - ASN1 compact bitstring
}.
#'TBSCertificate'{
@@ -116,7 +118,7 @@
#'AlgorithmIdentifier'{
algorithm, % oid()
- parameters % asn1_der_encoded()
+ parameters % der_encoded()
}.
</code>
@@ -124,7 +126,7 @@
#'OTPCertificate'{
tbsCertificate, % #'OTPTBSCertificate'{}
signatureAlgorithm, % #'SignatureAlgorithm'
- signature % {0, binary()} - asn1 compact bitstring
+ signature % {0, binary()} - ASN1 compact bitstring
}.
#'OTPTBSCertificate'{
@@ -134,7 +136,7 @@
issuer, % {rdnSequence, [#AttributeTypeAndValue'{}]}
validity, % #'Validity'{}
subject, % {rdnSequence, [#AttributeTypeAndValue'{}]}
- subjectPublicKeyInfo, % #'SubjectPublicKeyInfo'{}
+ subjectPublicKeyInfo, % #'OTPSubjectPublicKeyInfo'{}
issuerUniqueID, % binary() | asn1_novalue
subjectUniqueID, % binary() | asn1_novalue
extensions % [#'Extension'{}]
@@ -287,7 +289,7 @@ oid names see table below. Ex: ?'id-dsa-with-sha1'</p>
#'Extension'{
extnID, % id_extensions() | oid()
critical, % boolean()
- extnValue % asn1_der_encoded()
+ extnValue % der_encoded()
}.
</code>
@@ -369,7 +371,7 @@ oid names see table below. Ex: ?'id-dsa-with-sha1'</p>
<row>
<cell align="left" valign="middle">id-ce-cRLDistributionPoints</cell>
- <cell align="left" valign="middle">#'DistributionPoint'{}</cell>
+ <cell align="left" valign="middle">[#'DistributionPoint'{}]</cell>
</row>
<row>
@@ -458,7 +460,7 @@ oid names see table below. Ex: ?'id-dsa-with-sha1'</p>
#'Attribute'{
type, % oid()
- values % [asn1_der_encoded()]
+ values % [der_encoded()]
}).
#'BasicConstraints'{
@@ -483,9 +485,10 @@ oid names see table below. Ex: ?'id-dsa-with-sha1'</p>
}).
#'DistributionPoint'{
- distributionPoint, % general_name() | [#AttributeTypeAndValue{}]
+ distributionPoint, % {fullName, [general_name()]} | {nameRelativeToCRLIssuer,
+ [#AttributeTypeAndValue{}]}
reasons, % [dist_reason()]
- cRLIssuer % general_name()
+ cRLIssuer % [general_name()]
}).
</code>
@@ -527,7 +530,7 @@ oid names see table below. Ex: ?'id-dsa-with-sha1'</p>
#'CertificateList'{
tbsCertList, % #'TBSCertList{}
signatureAlgorithm, % #'AlgorithmIdentifier'{}
- signature % {0, binary()} - asn1 compact bitstring
+ signature % {0, binary()} - ASN1 compact bitstring
}).
#'TBSCertList'{
@@ -586,7 +589,8 @@ oid names see table below. Ex: ?'id-dsa-with-sha1'</p>
<code>
#'IssuingDistributionPoint'{
- distributionPoint, % general_name() | [#AttributeTypeAndValue'{}]
+ distributionPoint, % {fullName, [general_name()]} | {nameRelativeToCRLIssuer,
+ [#AttributeTypeAndValue'{}]}
onlyContainsUserCerts, % boolean()
onlyContainsCACerts, % boolean()
onlySomeReasons, % [dist_reason()]
@@ -630,6 +634,40 @@ oid names see table below. Ex: ?'id-dsa-with-sha1'</p>
aACompromise
</c></p>
</section>
-
+
+ <section>
+ <marker id="PKCS10"></marker>
+ <title>PKCS#10 Certification Request</title>
+ <code>
+#'CertificationRequest'{
+ certificationRequestInfo #'CertificationRequestInfo'{},
+ signatureAlgorithm #'CertificationRequest_signatureAlgorithm'{}}.
+ signature {0, binary()} - ASN1 compact bitstring
+ }
+
+#'CertificationRequestInfo'{
+ version atom(),
+ subject {rdnSequence, [#AttributeTypeAndValue'{}]} ,
+ subjectPKInfo #'CertificationRequestInfo_subjectPKInfo'{},
+ attributes [#AttributeTypeAndValue'{}]
+ }
+
+#'CertificationRequestInfo_subjectPKInfo'{
+ algorithm #'CertificationRequestInfo_subjectPKInfo_algorithm'{}
+ subjectPublicKey {0, binary()} - ASN1 compact bitstring
+ }
+
+#'CertificationRequestInfo_subjectPKInfo_algorithm'{
+ algorithm = oid(),
+ parameters = der_encoded()
+}
+
+#'CertificationRequest_signatureAlgorithm'{
+ algorithm = oid(),
+ parameters = der_encoded()
+ }
+ </code>
+ </section>
+
</section>
</chapter>
diff --git a/lib/public_key/doc/src/introduction.xml b/lib/public_key/doc/src/introduction.xml
index a21fcf3576..4b59cc2245 100644
--- a/lib/public_key/doc/src/introduction.xml
+++ b/lib/public_key/doc/src/introduction.xml
@@ -1,11 +1,11 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE chapter SYSTEM "chapter.dtd">
<chapter>
<header>
<copyright>
<year>2008</year>
- <year>2011</year>
+ <year>2013</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -36,23 +36,26 @@
<section>
<title>Purpose</title>
- <p> This application provides an API to public key infrastructure
- from RFC 3280 (X.509 certificates) and public key formats defined
- by the PKCS-standard.</p>
+ <p> public_key deals with public key related file formats, digital
+ signatures and <url href="http://www.ietf.org/rfc/rfc5280.txt">
+ X-509 certificates</url>. It is a library application that
+ provides encode/decode, sign/verify, encrypt/decrypt and similar
+ functionality, it does not read or write files it expects or returns
+ file contents or partial file contents as binaries.
+ </p>
</section>
<section>
<title>Prerequisites</title>
- <p>It is assumed that the reader is familiar with the Erlang
- programming language, concepts of OTP and has a basic understanding
- of the concepts of using public keys.</p>
+ <p>It is assumed that the reader has a basic understanding
+ of the concepts of using public keys and digital certificates.</p>
</section>
<section>
<title>Performance tips</title>
- <p>The public_key decode and encode functions will try to use the nifs
- which are in the asn1 compilers runtime modules if they can be found.
- So for the best performance you want to have the asn1 application in the
+ <p>The public_key decode and encode functions will try to use the NIFs
+ which are in the ASN1 compilers runtime modules if they can be found.
+ So for the best performance you want to have the ASN1 application in the
path of your system. </p>
</section>
diff --git a/lib/public_key/doc/src/notes.xml b/lib/public_key/doc/src/notes.xml
index d895042570..a5e8beedf0 100644
--- a/lib/public_key/doc/src/notes.xml
+++ b/lib/public_key/doc/src/notes.xml
@@ -34,6 +34,41 @@
<file>notes.xml</file>
</header>
+<section><title>Public_Key 0.17</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ ssh_decode now handles comments, at the end of the line,
+ containing withe spaces correctly</p>
+ <p>
+ Own Id: OTP-9361</p>
+ </item>
+ <item>
+ <p>
+ Add missing references to sha224 and sha384</p>
+ <p>
+ Own Id: OTP-9362 Aux Id: seq12116 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ public_key now supports PKCS-10 and includes exprimental
+ support for PKCS-7</p>
+ <p>
+ Own Id: OTP-10509 Aux Id: kunagi-291 [202] </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Public_Key 0.16</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/public_key/doc/src/part.xml b/lib/public_key/doc/src/part.xml
index ea3123b5bd..08fa4eec58 100644
--- a/lib/public_key/doc/src/part.xml
+++ b/lib/public_key/doc/src/part.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2008</year>
- <year>2011</year>
+ <year>2013</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -32,8 +32,10 @@
</header>
<description>
<p> This application provides an API to public key infrastructure
- from RFC 3280 (X.509 certificates) and some public key formats defined
- by the PKCS-standard. </p>
+ from <url href="http://www.ietf.org/rfc/rfc5280.txt">RFC
+ 5280</url> (X.509 certificates) and public key formats defined by
+ the <url href="http://www.rsa.com/rsalabs/node.asp?id=2124">
+ PKCS-standard</url></p>
</description>
<xi:include href="introduction.xml"/>
<xi:include href="public_key_records.xml"/>
diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml
index 5c227557f2..5864de2d57 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>2012</year>
+ <year>2013</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -33,12 +33,30 @@
<module>public_key</module>
<modulesummary> API module for public key infrastructure.</modulesummary>
<description>
- <p>This module provides functions to handle public key infrastructure
- from RFC 5280 - X.509 certificates and some parts of the PKCS-standard.
+ <p>This module provides functions to handle public key infrastructure. It can
+ encode/decode different file formats (PEM, openssh), sign and verify digital signatures and validate
+ certificate paths and certificate revocation lists.
</p>
</description>
<section>
+ <title>public_key</title>
+
+ <list type="bulleted">
+ <item>public_key requires the crypto application.</item>
+
+ <item>Supports <url href="http://www.ietf.org/rfc/rfc5280.txt">RFC 5280 </url> -
+ Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile </item>
+ <item>Supports <url href="http://www.rsa.com/rsalabs/node.asp?id=2125"> PKCS-1 </url> - RSA Cryptography Standard </item>
+ <item>Supports <url href="http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf"> DSA</url>- Digital Signature Algorithm</item>
+ <item>Supports <url href="http://www.rsa.com/rsalabs/node.asp?id=2126"> PKCS-3 </url> - Diffie-Hellman Key Agreement Standard </item>
+ <item>Supports <url href="http://www.rsa.com/rsalabs/node.asp?id=2127"> PKCS-5</url> - Password-Based Cryptography Standard </item>
+ <item>Supports <url href="http://www.rsa.com/rsalabs/node.asp?id=2130"> PKCS-8</url> - Private-Key Information Syntax Standard</item>
+ <item>Supports <url href="http://www.rsa.com/rsalabs/node.asp?id=2132"> PKCS-10</url> - Certification Request Syntax Standard</item>
+ </list>
+ </section>
+
+ <section>
<title>COMMON DATA TYPES </title>
<note><p>All records used in this manual
@@ -58,10 +76,13 @@
<p><code>boolean() = true | false</code></p>
- <p><code>string = [bytes()]</code></p>
+ <p><code>string() = [bytes()]</code></p>
+
+ <p><code>der_encoded() = binary()</code></p>
- <p><code>pki_asn1_type() = 'Certificate' | 'RSAPrivateKey'| 'RSAPublicKey'
- 'DSAPrivateKey' | 'DSAPublicKey' | 'DHParameter' | 'SubjectPublicKeyInfo'| 'PrivateKeyInfo'</code></p>
+ <p><code>pki_asn1_type() = 'Certificate' | 'RSAPrivateKey'| 'RSAPublicKey' |
+ 'DSAPrivateKey' | 'DSAPublicKey' | 'DHParameter' | 'SubjectPublicKeyInfo' |
+ 'PrivateKeyInfo' | 'CertificationRequest'</code></p>
<p><code>pem_entry () = {pki_asn1_type(), binary(), %% DER or encrypted DER
not_encrypted | cipher_info()} </code></p>
@@ -86,6 +107,9 @@
<p><code> dss_digest_type() = 'sha' </code></p>
+ <p><code> crl_reason() = unspecified | keyCompromise | cACompromise | affiliationChanged | superseded | cessationOfOperation | certificateHold | privilegeWithdrawn | aACompromise
+ </code></p>
+
<p><code> ssh_file() = openssh_public_key | rfc4716_public_key |
known_hosts | auth_keys </code></p>
@@ -150,7 +174,7 @@
<func>
<name>der_decode(Asn1type, Der) -> term()</name>
- <fsummary> Decodes a public key asn1 der encoded entity.</fsummary>
+ <fsummary> Decodes a public key ASN.1 DER encoded entity.</fsummary>
<type>
<v>Asn1Type = atom()</v>
<d> ASN.1 type present in the public_key applications
@@ -158,7 +182,7 @@
<v>Der = der_encoded()</v>
</type>
<desc>
- <p> Decodes a public key ASN.1 der encoded entity.</p>
+ <p> Decodes a public key ASN.1 DER encoded entity.</p>
</desc>
</func>
@@ -180,14 +204,14 @@
<func>
<name>pem_decode(PemBin) -> [pem_entry()]</name>
<fsummary>Decode PEM binary data and return
- entries as ASN.1 der encoded entities. </fsummary>
+ entries as ASN.1 DER encoded entities. </fsummary>
<type>
<v>PemBin = binary()</v>
<d>Example {ok, PemBin} = file:read_file("cert.pem").</d>
</type>
<desc>
<p>Decode PEM binary data and return
- entries as ASN.1 der encoded entities.</p>
+ entries as ASN.1 DER encoded entities.</p>
</desc>
</func>
@@ -211,8 +235,8 @@
<v> Password = string() </v>
</type>
<desc>
- <p>Decodes a pem entry. pem_decode/1 returns a list of pem
- entries. Note that if the pem entry is of type
+ <p>Decodes a PEM entry. pem_decode/1 returns a list of PEM
+ entries. Note that if the PEM entry is of type
'SubjectPublickeyInfo' it will be further decoded to an
rsa_public_key() or dsa_public_key().</p>
</desc>
@@ -221,7 +245,7 @@
<func>
<name>pem_entry_encode(Asn1Type, Entity) -> pem_entry()</name>
<name>pem_entry_encode(Asn1Type, Entity, {CipherInfo, Password}) -> pem_entry()</name>
- <fsummary> Creates a pem entry that can be fed to pem_encode/1.</fsummary>
+ <fsummary> Creates a PEM entry that can be fed to pem_encode/1.</fsummary>
<type>
<v>Asn1Type = pki_asn1_type()</v>
<v>Entity = term()</v>
@@ -235,7 +259,7 @@
<v>Password = string()</v>
</type>
<desc>
- <p> Creates a pem entry that can be feed to pem_encode/1.</p>
+ <p> Creates a PEM entry that can be feed to pem_encode/1.</p>
</desc>
</func>
@@ -265,12 +289,12 @@
<func>
<name>pkix_decode_cert(Cert, otp|plain) -> #'Certificate'{} | #'OTPCertificate'{}</name>
- <fsummary> Decodes an ASN.1 der encoded pkix x509 certificate.</fsummary>
+ <fsummary> Decodes an ASN.1 DER encoded PKIX x509 certificate.</fsummary>
<type>
<v>Cert = der_encoded()</v>
</type>
<desc>
- <p>Decodes an ASN.1 der encoded pkix certificate. The otp option
+ <p>Decodes an ASN.1 DER encoded PKIX certificate. The otp option
will use the customized ASN.1 specification OTP-PKIX.asn1 for
decoding and also recursively decode most of the standard
parts.</p>
@@ -279,14 +303,15 @@
<func>
<name>pkix_encode(Asn1Type, Entity, otp | plain) -> der_encoded()</name>
- <fsummary>Der encodes a pkix x509 certificate or part of such a
+ <fsummary>DER encodes a PKIX x509 certificate or part of such a
certificate.</fsummary>
<type>
<v>Asn1Type = atom()</v>
<d>The ASN.1 type can be 'Certificate', 'OTPCertificate' or a subtype of either .</d>
+ <v>Entity = #'Certificate'{} | #'OTPCertificate'{} | a valid subtype</v>
</type>
<desc>
- <p>Der encodes a pkix x509 certificate or part of such a
+ <p>DER encodes a PKIX x509 certificate or part of such a
certificate. This function must be used for encoding certificates or parts of certificates
that are decoded/created in the otp format, whereas for the plain format this
function will directly call der_encode/2. </p>
@@ -356,18 +381,104 @@
</desc>
</func>
- <!-- <func> -->
- <!-- <name>pkix_path_validation()</name> -->
- <!-- <fsummary> Performs a basic path validation according to RFC 5280.</fsummary> -->
- <!-- <type> -->
- <!-- <v></v> -->
- <!-- </type> -->
- <!-- <desc> -->
- <!-- <p> Performs a basic path validation according to RFC 5280.</p> -->
- <!-- </desc> -->
- <!-- </func> -->
+ <func>
+ <name>pkix_path_validation(TrustedCert, CertChain, Options) -> {ok, {PublicKeyInfo, PolicyTree}} | {error, {bad_cert, Reason}} </name>
+ <fsummary> Performs a basic path validation according to RFC 5280.</fsummary>
+ <type>
+ <v> TrustedCert = #'OTPCertificate'{} | der_encode() | unknown_ca | selfsigned_peer </v>
+ <d>Normally a trusted certificate but it can also be one of the path validation
+ errors <c>unknown_ca </c> or <c>selfsigned_peer </c> that can be discovered while
+ constructing the input to this function and that should be run through the <c>verify_fun</c>.</d>
+ <v> CertChain = [der_encode()]</v>
+ <d>A list of DER encoded certificates in trust order ending with the peer certificate.</d>
+ <v> Options = proplists:proplists()</v>
+ <v>PublicKeyInfo = {?'rsaEncryption' | ?'id-dsa',
+ rsa_public_key() | integer(), 'NULL' | 'Dss-Parms'{}}</v>
+ <v> PolicyTree = term() </v>
+ <d>At the moment this will always be an empty list as Policies are not currently supported</d>
+ <v> Reason = cert_expired | invalid_issuer | invalid_signature | unknown_ca |
+ selfsigned_peer | name_not_permitted | missing_basic_constraint | invalid_key_usage | crl_reason()
+ </v>
+ </type>
+ <desc>
+ <p>
+ Performs a basic path validation according to
+ <url href="http://www.ietf.org/rfc/rfc5280.txt">RFC 5280.</url>
+ However CRL validation is done separately by <seealso
+ marker="public_key#pkix_crls_validate-3">pkix_crls_validate/3 </seealso> and should be called
+ from the supplied <c>verify_fun</c>
+ </p>
+
+ <taglist>
+ <p> Available options are: </p>
+
+ <tag>{verify_fun, fun()}</tag>
+ <item>
+ <p>The fun should be defined as:</p>
+
+ <code>
+fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
+ {extension, #'Extension'{}},
+ InitialUserState :: term()) ->
+ {valid, UserState :: term()} | {valid_peer, UserState :: term()} |
+ {fail, Reason :: term()} | {unknown, UserState :: term()}.
+ </code>
+
+ <p>If the verify callback fun returns {fail, Reason}, the
+ verification process is immediately stopped. If the verify
+ callback fun returns {valid, UserState}, the verification
+ process is continued, this can be used to accept specific path
+ validation errors such as <c>selfsigned_peer</c> as well as
+ verifying application specific extensions. If called with an
+ extension unknown to the user application the return value
+ {unknown, UserState} should be used.</p>
+
+ </item>
+ <tag>{max_path_length, integer()}</tag>
+ <item>
+ The <c>max_path_length</c> is the maximum number of non-self-issued
+ intermediate certificates that may follow the peer certificate
+ in a valid certification path. So if <c>max_path_length</c> is 0 the PEER must
+ be signed by the trusted ROOT-CA directly, if 1 the path can
+ be PEER, CA, ROOT-CA, if it is 2 PEER, CA, CA, ROOT-CA and so
+ on.
+ </item>
+ </taglist>
+ </desc>
+ </func>
+
+ <func>
+ <name>pkix_crls_validate(OTPCertificate, DPAndCRLs, Options) -> CRLStatus()</name>
+ <fsummary> Performs CRL validation.</fsummary>
+ <type>
+ <v> OTPCertificate = #'OTPCertificate'{}</v>
+ <v> DPAndCRLs = [{DP::#'DistributionPoint'{} ,CRL::#'CertificateList'{}}] </v>
+ <v> Options = proplists:proplists()</v>
+ <v> CRLStatus() = valid | {bad_cert, revocation_status_undetermined} |
+ {bad_cert, {revoked, crl_reason()}}</v>
+ </type>
+ <desc>
+ <p> Performs CRL validation. It is intended to be called from
+ the verify fun of <seealso marker="public_key#pkix_path_validation-3"> pkix_path_validation/3
+ </seealso></p>
+ <taglist>
+ <p> Available options are: </p>
+ <tag>{update_crl, fun()}</tag>
+ <item>
+ <p>The fun has the following type spec:</p>
+
+ <code> fun(#'DistributionPoint'{}, #'CertificateList'{}) -> #'CertificateList'{}</code>
+
+ <p>The fun should use the information in the distribution point to acesses
+ the lates possible version of the CRL. If this fun is not specified
+ public_key will use the default implementation:
+ </p>
+ <code> fun(_DP, CRL) -> CRL end</code>
+ </item>
+ </taglist>
+ </desc>
+ </func>
-
<func>
<name>pkix_sign(#'OTPTBSCertificate'{}, Key) -> der_encode()</name>
<fsummary>Signs certificate.</fsummary>
@@ -388,7 +499,7 @@
<v>Key = rsa_public_key() | dsa_public_key()</v>
</type>
<desc>
- <p> Verify pkix x.509 certificate signature.</p>
+ <p> Verify PKIX x.509 certificate signature.</p>
</desc>
</func>
diff --git a/lib/public_key/doc/src/public_key_records.xml b/lib/public_key/doc/src/public_key_records.xml
index bb90290266..e39ad0ec64 100644
--- a/lib/public_key/doc/src/public_key_records.xml
+++ b/lib/public_key/doc/src/public_key_records.xml
@@ -1,11 +1,11 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE chapter SYSTEM "chapter.dtd">
<chapter>
<header>
<copyright>
<year>2008</year>
- <year>2011</year>
+ <year>2013</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -34,7 +34,7 @@
<file>public_key_records.xml</file>
</header>
- <p>This chapter briefly describes Erlang records derived from asn1
+ <p>This chapter briefly describes Erlang records derived from ASN1
specifications used to handle public and private keys. The intent
is to describe the data types and not to specify the meaning of
each component for this we refer you to the relevant standards and RFCs.</p>
@@ -67,9 +67,9 @@
}.
#'OtherPrimeInfo'{
- prime, % integer()
- exponent, % integer()
- coefficient % integer()
+ prime, % integer()
+ exponent, % integer()
+ coefficient % integer()
}.
</code>
diff --git a/lib/public_key/doc/src/using_public_key.xml b/lib/public_key/doc/src/using_public_key.xml
index f0eaeb8654..5d9f1536d9 100644
--- a/lib/public_key/doc/src/using_public_key.xml
+++ b/lib/public_key/doc/src/using_public_key.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2011</year><year>2011</year>
+ <year>2011</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -21,7 +21,7 @@
</legalnotice>
- <title>Using the public_key API</title>
+ <title>Getting Started</title>
<file>using_public_key.xml</file>
</header>
@@ -40,7 +40,7 @@
<section>
<title>PEM files</title>
- <p> Pulic key data (keys, certificates etc) may be stored in PEM format. PEM files
+ <p> Public key data (keys, certificates etc) may be stored in PEM format. PEM files
comes from the Private Enhanced Mail Internet standard and has a
structure that looks like this:</p>
@@ -63,7 +63,7 @@
<code>1> {ok, PemBin} = file:read_file("dsa.pem").
{ok,&lt;&lt;"-----BEGIN DSA PRIVATE KEY-----\nMIIBuw"...&gt;&gt;}</code>
- <p>This PEM file only has one entry a private DSA key.</p>
+ <p>This PEM file only has one entry, a private DSA key.</p>
<code>2> [DSAEntry] = public_key:pem_decode(PemBin).
[{'DSAPrivateKey',&lt;&lt;48,130,1,187,2,1,0,2,129,129,0,183,
179,230,217,37,99,144,157,21,228,204,
diff --git a/lib/public_key/include/public_key.hrl b/lib/public_key/include/public_key.hrl
index 2475295974..4d1d510f29 100644
--- a/lib/public_key/include/public_key.hrl
+++ b/lib/public_key/include/public_key.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -68,17 +68,32 @@
-record(revoke_state, {
reasons_mask,
cert_status,
- interim_reasons_mask
+ interim_reasons_mask,
+ valid_ext
}).
+
+-define(unspecified, 0).
+-define(keyCompromise, 1).
+-define(cACompromise, 2).
+-define(affiliationChanged, 3).
+-define(superseded, 4).
+-define(cessationOfOperation, 5).
+-define(certificateHold, 6).
+-define(removeFromCRL, 8).
+-define(privilegeWithdrawn, 9).
+-define(aACompromise, 10).
+
-type public_key() :: rsa_public_key() | dsa_public_key().
-type rsa_public_key() :: #'RSAPublicKey'{}.
-type rsa_private_key() :: #'RSAPrivateKey'{}.
-type dsa_private_key() :: #'DSAPrivateKey'{}.
-type dsa_public_key() :: {integer(), #'Dss-Parms'{}}.
+-type der_encoded() :: binary().
+-type decrypt_der() :: binary().
-type pki_asn1_type() :: 'Certificate' | 'RSAPrivateKey' | 'RSAPublicKey'
| 'DSAPrivateKey' | 'DSAPublicKey' | 'DHParameter'
- | 'SubjectPublicKeyInfo'.
+ | 'SubjectPublicKeyInfo' | 'CertificationRequest' | 'CertificateList'.
-type pem_entry() :: {pki_asn1_type(), binary(), %% DER or Encrypted DER
not_encrypted | {Cipher :: string(), Salt :: binary()}}.
-type asn1_type() :: atom(). %% see "OTP-PUB-KEY.hrl
diff --git a/lib/public_key/src/Makefile b/lib/public_key/src/Makefile
index d5cd13d81a..b8ad68ecc7 100644
--- a/lib/public_key/src/Makefile
+++ b/lib/public_key/src/Makefile
@@ -44,7 +44,8 @@ MODULES = \
pubkey_ssh \
pubkey_pbe \
pubkey_cert \
- pubkey_cert_records
+ pubkey_cert_records \
+ pubkey_crl
HRL_FILES = $(INCLUDE)/public_key.hrl
@@ -91,10 +92,10 @@ clean:
docs:
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
# ----------------------------------------------------
# Release Target
diff --git a/lib/public_key/src/pubkey_cert.erl b/lib/public_key/src/pubkey_cert.erl
index f9e2025479..f53c94b334 100644
--- a/lib/public_key/src/pubkey_cert.erl
+++ b/lib/public_key/src/pubkey_cert.erl
@@ -26,10 +26,11 @@
-export([init_validation_state/3, prepare_for_next_cert/2,
validate_time/3, validate_signature/6,
validate_issuer/4, validate_names/6,
- validate_revoked_status/3, validate_extensions/4,
+ validate_extensions/4,
normalize_general_name/1, digest_type/1, is_self_signed/1,
is_issuer/2, issuer_id/2, is_fixed_dh_cert/1,
- verify_data/1, verify_fun/4]).
+ verify_data/1, verify_fun/4, select_extension/2, match_name/3,
+ extensions_list/1, cert_auth_key_id/1, time_str_2_gregorian_sec/1]).
-define(NULL, 0).
@@ -204,17 +205,6 @@ validate_names(OtpCert, Permit, Exclude, Last, UserState, VerifyFun) ->
end.
%%--------------------------------------------------------------------
--spec validate_revoked_status(#'OTPCertificate'{}, term(), fun()) ->
- term().
-%%
-%% Description: Check if certificate has been revoked.
-%%--------------------------------------------------------------------
-validate_revoked_status(_OtpCert, UserState, _VerifyFun) ->
- %% TODO: Implement or leave for application?!
- %% valid |
- %% throw({bad_cert, cert_revoked})
- UserState.
-%%--------------------------------------------------------------------
-spec validate_extensions(#'OTPCertificate'{}, #path_validation_state{},
term(), fun())->
{#path_validation_state{}, UserState :: term()}.
@@ -256,8 +246,10 @@ is_self_signed(#'OTPCertificate'{tbsCertificate=
%%
%% Description: Checks if <Issuer> issued <Candidate>.
%%--------------------------------------------------------------------
-is_issuer({rdnSequence, Issuer}, {rdnSequence, Candidate}) ->
- is_dir_name(Issuer, Candidate, true).
+is_issuer({rdnSequence, _} = Issuer, {rdnSequence, _} = Candidate) ->
+ {rdnSequence, IssuerDirName} = normalize_general_name(Issuer),
+ {rdnSequence, CandidateDirName} = normalize_general_name(Candidate),
+ is_dir_name(IssuerDirName, CandidateDirName, true).
%%--------------------------------------------------------------------
-spec issuer_id(#'OTPCertificate'{}, self | other) ->
{ok, {integer(), term()}} | {error, issuer_not_found}.
@@ -307,9 +299,9 @@ verify_fun(Otpcert, Result, UserState0, VerifyFun) ->
{valid,UserState} ->
UserState;
{fail, Reason} ->
- case Result of
+ case Reason of
{bad_cert, _} ->
- throw(Result);
+ throw(Reason);
_ ->
throw({bad_cert, Reason})
end;
@@ -321,6 +313,91 @@ verify_fun(Otpcert, Result, UserState0, VerifyFun) ->
UserState
end
end.
+%%--------------------------------------------------------------------
+-spec select_extension(Oid ::tuple(),[#'Extension'{}]) ->
+ #'Extension'{} | undefined.
+%%
+%% Description: Extracts a specific extension from a list of extensions.
+%%--------------------------------------------------------------------
+select_extension(_, []) ->
+ undefined;
+select_extension(Id, [#'Extension'{extnID = Id} = Extension | _]) ->
+ Extension;
+select_extension(Id, [_ | Extensions]) ->
+ select_extension(Id, Extensions).
+
+%%--------------------------------------------------------------------
+%% TODO:
+%%
+%% Description:
+%%--------------------------------------------------------------------
+match_name(rfc822Name, Name, [PermittedName | Rest]) ->
+ match_name(fun is_valid_host_or_domain/2, Name, PermittedName, Rest);
+
+match_name(directoryName, DirName, [PermittedName | Rest]) ->
+ match_name(fun is_rdnSeq/2, DirName, PermittedName, Rest);
+
+match_name(uniformResourceIdentifier, URI, [PermittedName | Rest]) ->
+ case split_uri(URI) of
+ incomplete ->
+ false;
+ {_, _, Host, _, _} ->
+ match_name(fun is_valid_host_or_domain/2, Host,
+ PermittedName, Rest)
+ end;
+
+match_name(emailAddress, Name, [PermittedName | Rest]) ->
+ Fun = fun(Email, PermittedEmail) ->
+ is_valid_email_address(Email, PermittedEmail,
+ string:tokens(PermittedEmail,"@"))
+ end,
+ match_name(Fun, Name, PermittedName, Rest);
+
+match_name(dNSName, Name, [PermittedName | Rest]) ->
+ Fun = fun(Domain, [$.|Domain]) -> true;
+ (Name1,Name2) ->
+ lists:suffix(string:to_lower(Name2),
+ string:to_lower(Name1))
+ end,
+ match_name(Fun, Name, [$.|PermittedName], Rest);
+
+match_name(x400Address, OrAddress, [PermittedAddr | Rest]) ->
+ match_name(fun is_or_address/2, OrAddress, PermittedAddr, Rest);
+
+match_name(ipAdress, IP, [PermittedIP | Rest]) ->
+ Fun = fun([IP1, IP2, IP3, IP4],
+ [IP5, IP6, IP7, IP8, M1, M2, M3, M4]) ->
+ is_permitted_ip([IP1, IP2, IP3, IP4],
+ [IP5, IP6, IP7, IP8],
+ [M1, M2, M3, M4]);
+ ([IP1, IP2, IP3, IP4, IP5, IP6, IP7, IP8,
+ IP9, IP10, IP11, IP12, IP13, IP14, IP15, IP16],
+ [IP17, IP18, IP19, IP20, IP21, IP22, IP23, IP24,
+ IP25, IP26, IP27, IP28, IP29, IP30, IP31, IP32,
+ M1, M2, M3, M4, M5, M6, M7, M8,
+ M9, M10, M11, M12, M13, M14, M15, M16]) ->
+ is_permitted_ip([IP1, IP2, IP3, IP4, IP5, IP6, IP7, IP8,
+ IP9, IP10, IP11, IP12, IP13,
+ IP14, IP15, IP16],
+ [IP17, IP18, IP19, IP20, IP21, IP22, IP23,
+ IP24,IP25, IP26, IP27, IP28, IP29, IP30,
+ IP31, IP32],
+ [M1, M2, M3, M4, M5, M6, M7, M8, M9, M10,
+ M11, M12, M13, M14, M15, M16]);
+ (_,_) ->
+ false
+ end,
+ match_name(Fun, IP, PermittedIP, Rest).
+
+match_name(Fun, Name, PermittedName, []) ->
+ Fun(Name, PermittedName);
+match_name(Fun, Name, PermittedName, [Head | Tail]) ->
+ case Fun(Name, PermittedName) of
+ true ->
+ true;
+ false ->
+ match_name(Fun, Name, Head, Tail)
+ end.
%%--------------------------------------------------------------------
%%% Internal functions
@@ -332,7 +409,7 @@ do_normalize_general_name(Issuer) ->
(Atter) ->
Atter
end,
- lists:sort(lists:map(Normalize, Issuer)).
+ lists:map(Normalize, Issuer).
%% See rfc3280 4.1.2.6 Subject: regarding emails.
extract_email({rdnSequence, List}) ->
@@ -477,13 +554,6 @@ strip_spaces(String) ->
string:tokens(String, " ")),
string:strip(NewString).
-select_extension(_, []) ->
- undefined;
-select_extension(Id, [#'Extension'{extnID = Id} = Extension | _]) ->
- Extension;
-select_extension(Id, [_ | Extensions]) ->
- select_extension(Id, Extensions).
-
%% No extensions present
validate_extensions(OtpCert, asn1_NOVALUE, ValidationState, ExistBasicCon,
SelfSigned, UserState, VerifyFun) ->
@@ -503,18 +573,16 @@ validate_extensions(OtpCert, [], ValidationState =
true ->
{ValidationState#path_validation_state{max_path_length = Len - 1},
UserState0};
- %% basic_constraint must appear in certs used for digital sign
- %% see 4.2.1.10 in rfc 3280
false ->
- UserState = verify_fun(OtpCert, {bad_cert, missing_basic_constraint},
- UserState0, VerifyFun),
- case SelfSigned of
+ %% basic_constraint must appear in certs used for digital sign
+ %% see 4.2.1.10 in rfc 3280
+ case is_digitally_sign_cert(OtpCert) of
true ->
- {ValidationState, UserState};
- false ->
- {ValidationState#path_validation_state{max_path_length =
- Len - 1},
- UserState}
+ missing_basic_constraints(OtpCert, SelfSigned,
+ ValidationState, VerifyFun,
+ UserState0, Len);
+ false -> %% Example CRL signer only
+ {ValidationState, UserState0}
end
end;
@@ -861,74 +929,6 @@ type_subtree_names(Type, SubTrees) ->
[Name || #'GeneralSubtree'{base = {TreeType, Name}} <- SubTrees,
TreeType =:= Type].
-match_name(rfc822Name, Name, [PermittedName | Rest]) ->
- match_name(fun is_valid_host_or_domain/2, Name, PermittedName, Rest);
-
-match_name(directoryName, DirName, [PermittedName | Rest]) ->
- match_name(fun is_rdnSeq/2, DirName, PermittedName, Rest);
-
-match_name(uniformResourceIdentifier, URI, [PermittedName | Rest]) ->
- case split_uri(URI) of
- incomplete ->
- false;
- {_, _, Host, _, _} ->
- match_name(fun is_valid_host_or_domain/2, Host,
- PermittedName, Rest)
- end;
-
-match_name(emailAddress, Name, [PermittedName | Rest]) ->
- Fun = fun(Email, PermittedEmail) ->
- is_valid_email_address(Email, PermittedEmail,
- string:tokens(PermittedEmail,"@"))
- end,
- match_name(Fun, Name, PermittedName, Rest);
-
-match_name(dNSName, Name, [PermittedName | Rest]) ->
- Fun = fun(Domain, [$.|Domain]) -> true;
- (Name1,Name2) ->
- lists:suffix(string:to_lower(Name2),
- string:to_lower(Name1))
- end,
- match_name(Fun, Name, [$.|PermittedName], Rest);
-
-match_name(x400Address, OrAddress, [PermittedAddr | Rest]) ->
- match_name(fun is_or_address/2, OrAddress, PermittedAddr, Rest);
-
-match_name(ipAdress, IP, [PermittedIP | Rest]) ->
- Fun = fun([IP1, IP2, IP3, IP4],
- [IP5, IP6, IP7, IP8, M1, M2, M3, M4]) ->
- is_permitted_ip([IP1, IP2, IP3, IP4],
- [IP5, IP6, IP7, IP8],
- [M1, M2, M3, M4]);
- ([IP1, IP2, IP3, IP4, IP5, IP6, IP7, IP8,
- IP9, IP10, IP11, IP12, IP13, IP14, IP15, IP16],
- [IP17, IP18, IP19, IP20, IP21, IP22, IP23, IP24,
- IP25, IP26, IP27, IP28, IP29, IP30, IP31, IP32,
- M1, M2, M3, M4, M5, M6, M7, M8,
- M9, M10, M11, M12, M13, M14, M15, M16]) ->
- is_permitted_ip([IP1, IP2, IP3, IP4, IP5, IP6, IP7, IP8,
- IP9, IP10, IP11, IP12, IP13,
- IP14, IP15, IP16],
- [IP17, IP18, IP19, IP20, IP21, IP22, IP23,
- IP24,IP25, IP26, IP27, IP28, IP29, IP30,
- IP31, IP32],
- [M1, M2, M3, M4, M5, M6, M7, M8, M9, M10,
- M11, M12, M13, M14, M15, M16]);
- (_,_) ->
- false
- end,
- match_name(Fun, IP, PermittedIP, Rest).
-
-match_name(Fun, Name, PermittedName, []) ->
- Fun(Name, PermittedName);
-match_name(Fun, Name, PermittedName, [Head | Tail]) ->
- case Fun(Name, PermittedName) of
- true ->
- true;
- false ->
- match_name(Fun, Name, Head, Tail)
- end.
-
is_permitted_ip([], [], []) ->
true;
is_permitted_ip([CandidatIp | CandidatIpRest],
@@ -1037,3 +1037,25 @@ is_dh(?'dhpublicnumber')->
true;
is_dh(_) ->
false.
+
+is_digitally_sign_cert(OtpCert) ->
+ TBSCert = OtpCert#'OTPCertificate'.tbsCertificate,
+ Extensions = extensions_list(TBSCert#'OTPTBSCertificate'.extensions),
+ case pubkey_cert:select_extension(?'id-ce-keyUsage', Extensions) of
+ undefined ->
+ false;
+ #'Extension'{extnValue = KeyUse} ->
+ lists:member(keyCertSign, KeyUse)
+ end.
+
+missing_basic_constraints(OtpCert, SelfSigned, ValidationState, VerifyFun, UserState0,Len) ->
+ UserState = verify_fun(OtpCert, {bad_cert, missing_basic_constraint},
+ UserState0, VerifyFun),
+ case SelfSigned of
+ true ->
+ {ValidationState, UserState};
+ false ->
+ {ValidationState#path_validation_state{max_path_length =
+ Len - 1},
+ UserState}
+ end.
diff --git a/lib/public_key/src/pubkey_cert_records.erl b/lib/public_key/src/pubkey_cert_records.erl
index 33fe940ea2..98004c71a3 100644
--- a/lib/public_key/src/pubkey_cert_records.erl
+++ b/lib/public_key/src/pubkey_cert_records.erl
@@ -119,7 +119,7 @@ encode_supportedPublicKey(#'OTPSubjectPublicKeyInfo'{algorithm= PA =
subjectPublicKey = SPK0}) ->
Type = supportedPublicKeyAlgorithms(Algo),
{ok, SPK} = 'OTP-PUB-KEY':encode(Type, SPK0),
- #'OTPSubjectPublicKeyInfo'{subjectPublicKey = {0,list_to_binary(SPK)}, algorithm=PA}.
+ #'OTPSubjectPublicKeyInfo'{subjectPublicKey = {0,SPK}, algorithm=PA}.
%%% Extensions
@@ -161,7 +161,7 @@ decode_extensions(Exts) ->
case extension_id(Id) of
undefined -> Ext;
Type ->
- {ok, Value} = 'OTP-PUB-KEY':decode(Type, list_to_binary(Value0)),
+ {ok, Value} = 'OTP-PUB-KEY':decode(Type, iolist_to_binary(Value0)),
Ext#'Extension'{extnValue=transform(Value,decode)}
end
end, Exts).
@@ -176,7 +176,7 @@ encode_extensions(Exts) ->
Type ->
Value1 = transform(Value0,encode),
{ok, Value} = 'OTP-PUB-KEY':encode(Type, Value1),
- Ext#'Extension'{extnValue=list_to_binary(Value)}
+ Ext#'Extension'{extnValue=Value}
end
end, Exts).
diff --git a/lib/public_key/src/pubkey_crl.erl b/lib/public_key/src/pubkey_crl.erl
new file mode 100644
index 0000000000..3e4c3c8b6d
--- /dev/null
+++ b/lib/public_key/src/pubkey_crl.erl
@@ -0,0 +1,701 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2012. All Rights Reserved.
+%%
+%% The 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(pubkey_crl).
+
+-include("public_key.hrl").
+
+-export([validate/7, init_revokation_state/0, fresh_crl/3, verify_crl_signature/4,
+ is_delta_crl/1, combines/2, match_one/2]).
+
+-record(userstate, {dpcrls,
+ idp
+ }).
+
+validate(OtpCert, OtherDPCRLs, DP, {DerCRL, CRL}, {DerDeltaCRL, DeltaCRL},
+ Options, RevokedState0) ->
+ RevokedState =
+ case verify_crl(OtpCert, DP, CRL, DerCRL, DeltaCRL,
+ DerDeltaCRL, OtherDPCRLs, Options, RevokedState0) of
+ {valid, Revoked, DeltaRevoked, RevokedState1, IDP} ->
+ TBSCert = OtpCert#'OTPCertificate'.tbsCertificate,
+ SerialNumber = TBSCert#'OTPTBSCertificate'.serialNumber,
+ CertIssuer = TBSCert#'OTPTBSCertificate'.issuer,
+ TBSCRL = CRL#'CertificateList'.tbsCertList,
+ CRLIssuer = TBSCRL#'TBSCertList'.issuer,
+ AltNames = subject_alt_names(TBSCert#'OTPTBSCertificate'.extensions),
+ revoked_status(DP, IDP, {directoryName, CRLIssuer},
+ [ {directoryName, CertIssuer} | AltNames], SerialNumber, Revoked,
+ DeltaRevoked, RevokedState1);
+ {invalid, Revoked} ->
+ Revoked
+ end,
+ crl_status(RevokedState).
+
+init_revokation_state() ->
+ #revoke_state{reasons_mask = sets:new(),
+ interim_reasons_mask = sets:new(),
+ cert_status = unrevoked}.
+
+fresh_crl(_, {undefined, undefined}, _) ->
+ %% Typically happens when there is no delta CRL that covers a CRL
+ no_fresh_crl;
+
+fresh_crl(DP, {_, #'CertificateList'{tbsCertList = TBSCRL}} = CRL, CallBack) ->
+ Now = calendar:datetime_to_gregorian_seconds(calendar:universal_time()),
+ UpdateTime =
+ pubkey_cert:time_str_2_gregorian_sec(TBSCRL#'TBSCertList'.nextUpdate),
+ case Now >= UpdateTime of
+ true ->
+ case CallBack(DP, CRL) of
+ CRL ->
+ no_fresh_crl;
+ NewCRL ->
+ fresh_crl(DP, NewCRL, CallBack)
+ end;
+ false ->
+ {fresh, CRL}
+ end.
+
+is_delta_crl(#'CertificateList'{tbsCertList = TBSCRL}) ->
+ Extensions = TBSCRL#'TBSCertList'.crlExtensions,
+ case pubkey_cert:select_extension(?'id-ce-deltaCRLIndicator',
+ Extensions) of
+ undefined ->
+ false;
+ _ ->
+ true
+ end.
+
+combines(CRL, DeltaCRL) ->
+ check_crl_num(CRL, DeltaCRL) andalso
+ check_delta_issuer_and_scope(CRL, DeltaCRL).
+
+crl_status(State)->
+ %% Fun argument is to enable future implementation of CRL checking
+ %% that does not care about all possible reasons.
+ crl_status(State, fun all_reasons/0).
+
+crl_status({skip, #revoke_state{cert_status = Status} = RevokedState}, _) ->
+ {undetermined, status(Status), RevokedState};
+
+crl_status(#revoke_state{cert_status = unrevoked = Status,
+ valid_ext = false} = RevokedState, _) ->
+ {undetermined, Status, RevokedState};
+
+crl_status(#revoke_state{cert_status = Status,
+ valid_ext = false}, _) ->
+ {finished, status(Status)};
+
+crl_status(#revoke_state{reasons_mask = Mask,
+ cert_status = Status,
+ valid_ext = true} = RevokedState, Fun) ->
+ case is_all_reasons(Mask, Fun) of
+ true ->
+ {finished, status(Status)};
+ false when (Status == unrevoked) ->
+ {undetermined, Status, RevokedState};
+ _ ->
+ {finished ,status(Status)}
+ end.
+
+verify_crl(OtpCert, DP, CRL, DerCRL, DeltaCRL, DerDeltaCRL, OtherDPCRLs,
+ Options, State0) ->
+ #'CertificateList'{tbsCertList =
+ #'TBSCertList'{crlExtensions = Extensions,
+ revokedCertificates = TmpRevoked}
+ } = CRL,
+ Revoked = revoked(TmpRevoked),
+ IDP = issuing_distribution_point(Extensions),
+
+ DeltaRevoked = delta_revoked(DeltaCRL),
+
+ ValidExt = verify_extensions(Extensions) and
+ verify_extensions(Revoked),
+
+ IntMask = compute_interim_reasons_mask(DP, IDP),
+
+ RevokedState =
+ State0#revoke_state{interim_reasons_mask = IntMask,
+ valid_ext = ValidExt},
+
+ {Fun, AdditionalArgs} = IssuerFun = proplists:get_value(issuer_fun, Options),
+
+ try verify_issuer_and_scope(OtpCert, DP, IDP, CRL) of
+ {ok, Issuer} ->
+ case Fun(DP, CRL, Issuer, AdditionalArgs) of
+ {ok, TrustedOtpCert, Path} ->
+ verify_mask_and_signatures(Revoked, DeltaRevoked,
+ RevokedState,
+ CRL, DerCRL, DeltaCRL, DerDeltaCRL,
+ IssuerFun, TrustedOtpCert, Path, OtherDPCRLs, IDP);
+ _ ->
+ {invalid, State0#revoke_state{valid_ext = ValidExt}}
+ end;
+ {error, issuer_not_found} ->
+ case Fun(DP, CRL, issuer_not_found, AdditionalArgs) of
+ {ok, TrustedOtpCert, Path} ->
+ verify_mask_and_signatures(Revoked, DeltaRevoked,
+ RevokedState, CRL, DerCRL, DeltaCRL,
+ DerDeltaCRL, IssuerFun,
+ TrustedOtpCert, Path, OtherDPCRLs, IDP);
+ _ ->
+ {invalid, {skip, State0}}
+ end
+ catch
+ throw:{bad_crl, invalid_issuer} ->
+ {invalid, {skip, State0}};
+ throw:_ ->
+ {invalid, State0#revoke_state{valid_ext = ValidExt}}
+ end.
+
+verify_mask_and_signatures(Revoked, DeltaRevoked, RevokedState, CRL, DerCRL, DeltaCRL, DerDeltaCRL,
+ IssuerFun, TrustedOtpCert, Path, OtherDPCRLs, IDP) ->
+
+ ReasonsMask = sets:union(RevokedState#revoke_state.reasons_mask,
+ RevokedState#revoke_state.interim_reasons_mask),
+ try
+ verify_interim_reasons_mask(RevokedState),
+ true = verify_crl_signatures(CRL, DerCRL, DeltaCRL, DerDeltaCRL,
+ TrustedOtpCert, Path, IssuerFun, OtherDPCRLs, IDP),
+ {valid, Revoked, DeltaRevoked, RevokedState#revoke_state{reasons_mask = ReasonsMask}, IDP}
+ catch
+ throw:_ ->
+ {invalid, RevokedState};
+ error:{badmatch, _} ->
+ {invalid, RevokedState}
+ end.
+
+
+verify_crl_signatures(CRL, DerCRL, DeltaCRL, DerDeltaCRL, TrustedOtpCert, Path,
+ IssuerFun, OtherDPCRLs, IDP) ->
+ try
+ VerifyFunAndState =
+ {fun(_, {bad_cert, _} = Reason, _UserState) ->
+ {fail, Reason};
+ (_,{extension, _}, UserState) ->
+ {unknown, UserState};
+ (_Cert, valid, UserState) ->
+ {valid, UserState};
+ (Cert, valid_peer, UserState) ->
+ case verify_crl_keybit(Cert, cRLSign) of
+ true ->
+ handle_crlsigner(Cert, IssuerFun, UserState);
+ false ->
+ {fail, crl_sign_bit_not_set}
+ end
+ end, #userstate{dpcrls = OtherDPCRLs, idp = IDP}},
+
+ {ok, {{_,Key, KeyParams},_}} =
+ public_key:pkix_path_validation(TrustedOtpCert, Path,
+ [{verify_fun, VerifyFunAndState}]),
+ true = verify_crl_signature(CRL, DerCRL, Key, KeyParams),
+ true = verify_crl_signature(DeltaCRL, DerDeltaCRL, Key, KeyParams)
+ catch
+ error:{badmatch, _} ->
+ false
+ end.
+
+handle_crlsigner(OtpCert, IssuerFun, #userstate{idp = IDP} = UserState) ->
+ case verify_crl_keybit(OtpCert, keyCertSign) of
+ true ->
+ {valid, UserState};
+ false ->
+ case not is_indirect_crl(IDP) andalso not public_key:pkix_is_self_signed(OtpCert) of
+ true ->
+ validate_crl_signing_cert(OtpCert, IssuerFun, UserState);
+ false ->
+ {valid, UserState}
+ end
+ end.
+
+validate_crl_signing_cert(_, _,#userstate{dpcrls = []} = UserState) ->
+ {valid, UserState};
+validate_crl_signing_cert(OtpCert, IssuerFun, #userstate{dpcrls = CRLInfo} = UserState) ->
+ case public_key:pkix_crls_validate(OtpCert, CRLInfo, [{issuer_fun, IssuerFun}]) of
+ valid ->
+ {valid, UserState};
+ Reason ->
+ {fail, Reason}
+ end.
+
+delta_revoked(undefined)->
+ [];
+delta_revoked(#'CertificateList'{tbsCertList =
+ #'TBSCertList'{revokedCertificates
+ = DeltaRevoked}}) ->
+ revoked(DeltaRevoked).
+
+revoked(asn1_NOVALUE) ->
+ [];
+revoked(Revoked) ->
+ Revoked.
+
+revoked_status(DP, IDP, CRLIssuer, Names, SerialNumber, Revoked, DeltaRevoked, RevokedState0) ->
+ DefaultIssuer0 = default_issuer(CRLIssuer, DeltaRevoked),
+ RevokedState1 = check_revoked(DP, IDP, DefaultIssuer0, Names, SerialNumber, DeltaRevoked, RevokedState0),
+ RevokedState = case RevokedState1#revoke_state.cert_status of
+ unrevoked when RevokedState1#revoke_state.cert_status =/= removeFromCRL ->
+ DefaultIssuer = default_issuer(CRLIssuer, Revoked),
+ check_revoked(DP, IDP, DefaultIssuer, Names, SerialNumber,
+ Revoked, RevokedState1);
+ _ ->
+ RevokedState1
+ end,
+ case RevokedState#revoke_state.cert_status of
+ removeFromCRL ->
+ RevokedState#revoke_state{cert_status = unrevoked};
+ _ ->
+ RevokedState
+ end.
+
+default_issuer(_, []) ->
+ undefined;
+default_issuer(Default, [#'TBSCertList_revokedCertificates_SEQOF'{crlEntryExtensions = Extensions}| _]) ->
+ case extension_value(?'id-ce-certificateIssuer', 'GeneralNames', Extensions) of
+ undefined ->
+ [pubkey_cert_records:transform(Default, decode)];
+ GeneralNames ->
+ gen_names(GeneralNames)
+ end.
+
+is_all_reasons(Mask, AllReasonsFun) ->
+ AllReasons = AllReasonsFun(),
+ case sets:is_subset(AllReasons, Mask) of
+ true ->
+ true;
+ false ->
+ %% As the "uspecified" reason should not
+ %% be explicitly used according to RFC 3280
+ %% and the conformance tests have test cases
+ %% that should succed, and that does not specify
+ %% "unspecified", we tolorate that it is not included.
+ sets:is_subset(sets:del_element(unspecified, AllReasons), Mask)
+ end.
+
+all_reasons() ->
+ sets:from_list([unspecified, keyCompromise,
+ cACompromise, affiliationChanged, superseded,
+ cessationOfOperation, certificateHold,
+ privilegeWithdrawn, aACompromise]).
+
+verify_issuer_and_scope(#'OTPCertificate'{tbsCertificate = TBSCert} = Cert,
+ #'DistributionPoint'{cRLIssuer = DPIssuer} = DP, IDP,
+ #'CertificateList'{tbsCertList = TBSCRL} = CRL)
+ when DPIssuer =/= asn1_NOVALUE ->
+ CRLIssuer = pubkey_cert_records:transform(TBSCRL#'TBSCertList'.issuer, decode),
+ Issuer = dp_crlissuer_to_issuer(DPIssuer),
+ case pubkey_cert:is_issuer(Issuer, CRLIssuer) and is_indirect_crl(IDP) of
+ true ->
+ verify_scope(Cert, DP, IDP),
+ issuer_id(Cert, CRL);
+ false ->
+ %% otherwise verify that the CRL issuer matches the certificate issuer
+ verify_issuer_and_scope(Cert, DP#'DistributionPoint'{
+ distributionPoint = [TBSCert#'OTPTBSCertificate'.issuer],
+ cRLIssuer = asn1_NOVALUE},
+ IDP, CRL)
+ end;
+verify_issuer_and_scope(#'OTPCertificate'{tbsCertificate = TBSCert}= Cert,
+ DP, IDP,
+ #'CertificateList'{tbsCertList = TBSCRL}) ->
+ CRLIssuer = pubkey_cert_records:transform(TBSCRL#'TBSCertList'.issuer, decode),
+ CertIssuer = TBSCert#'OTPTBSCertificate'.issuer,
+ case pubkey_cert:is_issuer(CertIssuer, CRLIssuer) of
+ true ->
+ verify_scope(Cert, DP, IDP),
+ issuer_id(Cert);
+ false ->
+ throw({bad_crl, invalid_issuer})
+ end.
+
+dp_crlissuer_to_issuer(DPCRLIssuer) ->
+ [{directoryName, Issuer}] = pubkey_cert_records:transform(DPCRLIssuer, decode),
+ Issuer.
+
+is_indirect_crl(#'IssuingDistributionPoint'{indirectCRL = Value})->
+ Value;
+is_indirect_crl(_) ->
+ false.
+
+verify_scope(_,_, undefined) ->
+ ok;
+verify_scope(#'OTPCertificate'{tbsCertificate = TBSCert}, #'DistributionPoint'{cRLIssuer = DPIssuer} = DP, IDP) ->
+ CertIssuer = TBSCert#'OTPTBSCertificate'.issuer,
+ Names = case gen_names(DPIssuer) of
+ [{directoryName, TNames}] ->
+ TNames;
+ Other ->
+ Other
+ end,
+ DPName = dp_names(DP#'DistributionPoint'.distributionPoint, Names, CertIssuer),
+ IDPName = dp_names(IDP#'IssuingDistributionPoint'.distributionPoint, Names, CertIssuer),
+ verify_scope(DPName, IDPName, Names, TBSCert, IDP).
+
+verify_scope(asn1_NOVALUE, _, asn1_NOVALUE, _, _) ->
+ throw({bad_crl, scope_error1});
+verify_scope(asn1_NOVALUE, IDPName, DPIssuerNames, TBSCert, IDP) ->
+ verify_dp_name(IDPName, DPIssuerNames),
+ verify_dp_bools(TBSCert, IDP);
+
+verify_scope(DPName, IDPName, _, TBSCert, IDP) ->
+ verify_dp_name(IDPName, DPName),
+ verify_dp_bools(TBSCert, IDP).
+
+dp_names(asn1_NOVALUE, _, _) ->
+ asn1_NOVALUE;
+dp_names({fullName, Name}, _, _) ->
+ gen_names(Name);
+dp_names({nameRelativeToCRLIssuer, Fragment}, asn1_NOVALUE, {rdnSequence, RelativeDestinguistNames}) ->
+ [{directoryName, {rdnSequence, RelativeDestinguistNames ++
+ [lists:map(fun(AttrAndValue) ->
+ pubkey_cert_records:transform(AttrAndValue, decode)
+ end, Fragment)]}}];
+dp_names({nameRelativeToCRLIssuer, Fragment},{rdnSequence, RelativeDestinguistNames}, _) ->
+ [{directoryName, {rdnSequence, RelativeDestinguistNames ++
+ [lists:map(fun(AttrAndValue) ->
+ pubkey_cert_records:transform(AttrAndValue, decode)
+ end, Fragment)]}}];
+dp_names([{rdnSequence, _}] = Name0, _,_) ->
+ [Name] = pubkey_cert_records:transform(Name0, decode),
+ [{directoryName, Name}].
+
+gen_names(asn1_NOVALUE) ->
+ asn1_NOVALUE;
+gen_names([]) ->
+ [];
+gen_names([{NameType, Name} | Rest]) ->
+ [ {NameType, pubkey_cert_records:transform(Name, decode)} | gen_names(Rest)].
+
+verify_dp_name(asn1_NOVALUE, _) ->
+ ok;
+
+verify_dp_name(IDPNames, DPorIssuerNames) ->
+ case match_one(DPorIssuerNames, IDPNames) of
+ true ->
+ ok;
+ false ->
+ throw({bad_crl, scope_error})
+ end.
+
+match_one([], _) ->
+ false;
+match_one([{Type, Name} | Names], CandidateNames) ->
+ Candidates = [NameName || {NameType, NameName} <- CandidateNames, NameType == Type],
+ case Candidates of
+ [] ->
+ false;
+ [_|_] -> case pubkey_cert:match_name(Type, Name, Candidates) of
+ true ->
+ true;
+ false ->
+ match_one(Names, CandidateNames)
+ end
+ end.
+
+verify_dp_bools(TBSCert, IDP) ->
+ BasicConstraints =
+ pubkey_cert:select_extension(?'id-ce-basicConstraints',
+ TBSCert#'OTPTBSCertificate'.extensions),
+
+ case verify_onlyContainsUserCerts(BasicConstraints, IDP) andalso
+ verify_onlyContainsCACerts(BasicConstraints, IDP) andalso
+ verify_onlyContainsAttributeCerts(IDP) of
+ true ->
+ ok;
+ _ ->
+ throw({bad_crl, scope_error})
+ end.
+
+verify_onlyContainsUserCerts(
+ #'Extension'{extnValue = #'BasicConstraints'{cA = true}},
+ #'IssuingDistributionPoint'{onlyContainsUserCerts = true}) ->
+ false;
+verify_onlyContainsUserCerts(_,_) ->
+ true.
+
+verify_onlyContainsCACerts(
+ #'Extension'{extnValue = #'BasicConstraints'{cA = true}},
+ #'IssuingDistributionPoint'{onlyContainsCACerts = true}) ->
+ true;
+verify_onlyContainsCACerts(_,#'IssuingDistributionPoint'{onlyContainsCACerts = true}) ->
+ false;
+verify_onlyContainsCACerts(_,_) ->
+ true.
+
+verify_onlyContainsAttributeCerts(
+ #'IssuingDistributionPoint'{onlyContainsAttributeCerts = Bool}) ->
+ not Bool.
+
+check_crl_num(#'CertificateList'{tbsCertList = TBSCRL},
+ #'CertificateList'{tbsCertList = TBSDeltaCRL})->
+ Extensions = TBSCRL#'TBSCertList'.crlExtensions,
+ DeltaExtensions = TBSDeltaCRL#'TBSCertList'.crlExtensions,
+
+ try
+ CRLNum = assert_extension_value(?'id-ce-cRLNumber', 'CRLNumber', Extensions),
+ DeltaBaseNum = assert_extension_value(?'id-ce-deltaCRLIndicator',
+ 'CRLNumber', DeltaExtensions),
+ DeltaCRLNum = assert_extension_value(?'id-ce-cRLNumber', 'CRLNumber', DeltaExtensions),
+ (CRLNum >= DeltaBaseNum) andalso (CRLNum < DeltaCRLNum)
+ catch
+ throw:no_extension_present ->
+ false
+ end;
+check_crl_num(_,_) ->
+ false.
+
+
+extension_value(Extension, ExtType, Extensions) ->
+ case pubkey_cert:select_extension(Extension, Extensions) of
+ #'Extension'{extnValue = Value} ->
+ public_key:der_decode(ExtType, list_to_binary(Value));
+ _ ->
+ undefined
+ end.
+
+
+assert_extension_value(Extension, ExtType, Extensions) ->
+ case extension_value(Extension, ExtType, Extensions) of
+ undefined ->
+ throw(no_extension_present);
+ Value ->
+ Value
+ end.
+
+check_delta_issuer_and_scope(_, undefined) ->
+ true;
+check_delta_issuer_and_scope(#'CertificateList'{tbsCertList = TBSCRL},
+ #'CertificateList'{tbsCertList = TBSDeltaCRL}) ->
+ case pubkey_cert:is_issuer(TBSCRL#'TBSCertList'.issuer,
+ TBSDeltaCRL#'TBSCertList'.issuer) of
+ true ->
+ check_delta_scope(TBSCRL, TBSDeltaCRL);
+ false ->
+ false
+ end.
+
+check_delta_scope(#'TBSCertList'{crlExtensions = Extensions},
+ #'TBSCertList'{crlExtensions = DeltaExtensions})->
+ IDP = issuing_distribution_point(Extensions),
+ DeltaIDP = issuing_distribution_point(DeltaExtensions),
+
+ AuthKey = authority_key_identifier(Extensions),
+ DeltaAuthKey = authority_key_identifier(DeltaExtensions),
+ is_match(IDP, DeltaIDP) andalso is_match(AuthKey, DeltaAuthKey).
+
+is_match(X, X) ->
+ true;
+is_match(_,_) ->
+ false.
+
+compute_interim_reasons_mask(#'DistributionPoint'{reasons = asn1_NOVALUE},
+ #'IssuingDistributionPoint'{onlySomeReasons =
+ asn1_NOVALUE}) ->
+ all_reasons();
+compute_interim_reasons_mask(#'DistributionPoint'{reasons = asn1_NOVALUE},
+ undefined) ->
+ all_reasons();
+
+compute_interim_reasons_mask(#'DistributionPoint'{reasons = asn1_NOVALUE},
+ #'IssuingDistributionPoint'{onlySomeReasons =
+ IDPReasons}) ->
+ sets:from_list(IDPReasons);
+compute_interim_reasons_mask(#'DistributionPoint'{reasons = DPReasons},
+ #'IssuingDistributionPoint'{onlySomeReasons =
+ asn1_NOVALUE}) ->
+ sets:from_list(DPReasons);
+compute_interim_reasons_mask(#'DistributionPoint'{reasons = DPReasons},
+ undefined) ->
+ sets:from_list(DPReasons);
+compute_interim_reasons_mask(#'DistributionPoint'{reasons = DPReasons},
+ #'IssuingDistributionPoint'{onlySomeReasons =
+ IDPReasons}) ->
+ sets:intersection(sets:from_list(DPReasons), sets:from_list(IDPReasons)).
+
+verify_interim_reasons_mask(#revoke_state{reasons_mask = Mask,
+ interim_reasons_mask = IntMask}) ->
+ case sets:fold(fun(Element, Acc) ->
+ case sets:is_element(Element, Mask) of
+ true ->
+ Acc;
+ false ->
+ true
+ end
+ end, false, IntMask) of
+ true ->
+ ok;
+ false ->
+ throw({bad_crl, mask_error})
+ end.
+
+verify_crl_signature(undefined, undefined, _,_) ->
+ true;
+verify_crl_signature(CRL, DerCRL, Key, KeyParams) ->
+ {DigestType, PlainText, Signature} = extract_crl_verify_data(CRL, DerCRL),
+ case Key of
+ #'RSAPublicKey'{} ->
+ public_key:verify(PlainText, DigestType, Signature, Key);
+ _ ->
+ public_key:verify(PlainText, DigestType, Signature,
+ {Key, KeyParams})
+ end.
+extract_crl_verify_data(CRL, DerCRL) ->
+ {0, Signature} = CRL#'CertificateList'.signature,
+ #'AlgorithmIdentifier'{algorithm = SigAlg} =
+ CRL#'CertificateList'.signatureAlgorithm,
+ PlainText = encoded_tbs_crl(DerCRL),
+ DigestType = pubkey_cert:digest_type(SigAlg),
+ {DigestType, PlainText, Signature}.
+
+encoded_tbs_crl(CRL) ->
+ {ok, PKIXCRL} =
+ 'OTP-PUB-KEY':decode_TBSCertList_exclusive(CRL),
+ {'CertificateList',
+ {'CertificateList_tbsCertList', EncodedTBSCertList}, _, _} = PKIXCRL,
+ EncodedTBSCertList.
+
+check_revoked(_,_,_,_,_,[], State) ->
+ State;
+check_revoked(#'DistributionPoint'{cRLIssuer = DPIssuer} = DP, IDP, DefaultIssuer0, Names, SerialNr,
+ [#'TBSCertList_revokedCertificates_SEQOF'{userCertificate =
+ SerialNr,
+ crlEntryExtensions =
+ Extensions}| Rest],
+ State) ->
+ Reason = revoked_reason(Extensions),
+ case (DPIssuer =/= asn1_NOVALUE) and is_indirect_crl(IDP) of
+ true ->
+ handle_indirect_crl_check(DP, IDP, DefaultIssuer0, Names, SerialNr, Extensions, Reason, Rest, State);
+ false ->
+ State#revoke_state{cert_status = Reason}
+ end;
+
+check_revoked(DP, IDP, DefaultIssuer0, Names, SerialNr,
+ [#'TBSCertList_revokedCertificates_SEQOF'{crlEntryExtensions =
+ Extensions}| Rest], State) ->
+ DefaultIssuer = case extension_value(?'id-ce-certificateIssuer', 'GeneralNames', Extensions) of
+ undefined ->
+ DefaultIssuer0;
+ GeneralNames ->
+ gen_names(GeneralNames)
+ end,
+ check_revoked(DP, IDP, DefaultIssuer, Names, SerialNr, Rest, State).
+
+handle_indirect_crl_check(DP, IDP, DefaultIssuer0, Names, SerialNr, Extensions, Reason, Rest, State) ->
+ case check_crl_issuer_extension(Names, Extensions, DefaultIssuer0) of
+ {true, _} ->
+ State#revoke_state{cert_status = Reason};
+ {false, DefaultIssuer} ->
+ check_revoked(DP, IDP, DefaultIssuer, Names, SerialNr, Rest, State)
+ end.
+
+check_crl_issuer_extension(Names, Extensions, Default0) ->
+ case extension_value(?'id-ce-certificateIssuer', 'GeneralNames', Extensions) of
+ undefined ->
+ {match_one(Default0, Names), Default0};
+ GeneralNames ->
+ Default = gen_names(GeneralNames),
+ {match_one(Default, Names), Default}
+ end.
+
+revoked_reason(Extensions) ->
+ case extension_value(?'id-ce-cRLReasons', 'CRLReason', Extensions) of
+ undefined ->
+ unspecified;
+ Value ->
+ Value
+ end.
+
+verify_crl_keybit(#'OTPCertificate'{tbsCertificate = TBS}, Bit) ->
+ case pubkey_cert:select_extension( ?'id-ce-keyUsage',
+ TBS#'OTPTBSCertificate'.extensions) of
+ #'Extension'{extnID = ?'id-ce-keyUsage',
+ extnValue = KeyUse} ->
+ lists:member(Bit, KeyUse);
+ _ ->
+ true
+ end.
+
+issuer_id(Cert, #'CertificateList'{tbsCertList = TBSCRL}) ->
+ Extensions =
+ pubkey_cert:extensions_list(TBSCRL#'TBSCertList'.crlExtensions),
+ case authority_key_identifier(Extensions) of
+ undefined ->
+ issuer_id(Cert);
+ #'AuthorityKeyIdentifier'{authorityCertIssuer = asn1_NOVALUE,
+ authorityCertSerialNumber = asn1_NOVALUE} ->
+ issuer_id(Cert);
+ #'AuthorityKeyIdentifier'{authorityCertIssuer = Issuer,
+ authorityCertSerialNumber = Nr} ->
+ {ok, {Nr, Issuer}}
+ end.
+
+issuer_id(#'OTPCertificate'{} = Cert) ->
+ case public_key:pkix_is_self_signed(Cert) of
+ true ->
+ public_key:pkix_issuer_id(Cert, self);
+ false ->
+ public_key:pkix_issuer_id(Cert, other)
+ end.
+
+status(unrevoked) ->
+ unrevoked;
+status(Reason) ->
+ {revoked, Reason}.
+
+verify_extensions([#'TBSCertList_revokedCertificates_SEQOF'{crlEntryExtensions = Ext} | Rest]) ->
+ verify_extensions(pubkey_cert:extensions_list(Ext)) and verify_extensions(Rest);
+verify_extensions([]) ->
+ true;
+verify_extensions([#'Extension'{critical = true, extnID = Id} | Rest]) ->
+ case lists:member(Id, [?'id-ce-authorityKeyIdentifier',
+ ?'id-ce-issuerAltName',
+ ?'id-ce-cRLNumber',
+ ?'id-ce-certificateIssuer',
+ ?'id-ce-deltaCRLIndicator',
+ ?'id-ce-issuingDistributionPoint',
+ ?'id-ce-freshestCRL']) of
+ true ->
+ verify_extensions(Rest);
+ false ->
+ false
+ end;
+verify_extensions([_Ext | Rest]) ->
+ verify_extensions(Rest).
+
+issuing_distribution_point(Extensions) ->
+ Enc = extension_value(?'id-ce-issuingDistributionPoint',
+ 'IssuingDistributionPoint', Extensions),
+ pubkey_cert_records:transform(Enc, decode).
+
+authority_key_identifier(Extensions) ->
+ Enc = extension_value(?'id-ce-authorityKeyIdentifier',
+ 'AuthorityKeyIdentifier', Extensions),
+ pubkey_cert_records:transform(Enc, decode).
+
+subject_alt_names(Extensions) ->
+ Enc = extension_value(?'id-ce-subjectAltName',
+ 'GeneralNames', Extensions),
+ case Enc of
+ undefined ->
+ [];
+ _ ->
+ pubkey_cert_records:transform(Enc, decode)
+ end.
diff --git a/lib/public_key/src/pubkey_pem.erl b/lib/public_key/src/pubkey_pem.erl
index 910473d629..6bdc35fb79 100644
--- a/lib/public_key/src/pubkey_pem.erl
+++ b/lib/public_key/src/pubkey_pem.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -167,6 +167,8 @@ split_lines(Bin) ->
%% Ignore white space at end of line
join_entry([<<"-----END ", _/binary>>| Lines], Entry) ->
{lists:reverse(Entry), Lines};
+join_entry([<<"-----END X509 CRL-----", _/binary>>| Lines], Entry) ->
+ {lists:reverse(Entry), Lines};
join_entry([Line | Lines], Entry) ->
join_entry(Lines, [Line | Entry]).
@@ -194,7 +196,14 @@ pem_start('SubjectPublicKeyInfo') ->
pem_start('DSAPrivateKey') ->
<<"-----BEGIN DSA PRIVATE KEY-----">>;
pem_start('DHParameter') ->
- <<"-----BEGIN DH PARAMETERS-----">>.
+ <<"-----BEGIN DH PARAMETERS-----">>;
+pem_start('CertificationRequest') ->
+ <<"-----BEGIN CERTIFICATE REQUEST-----">>;
+pem_start('ContentInfo') ->
+ <<"-----BEGIN PKCS7-----">>;
+pem_start('CertificateList') ->
+ <<"-----BEGIN X509 CRL-----">>.
+
pem_end(<<"-----BEGIN CERTIFICATE-----">>) ->
<<"-----END CERTIFICATE-----">>;
pem_end(<<"-----BEGIN RSA PRIVATE KEY-----">>) ->
@@ -211,6 +220,12 @@ pem_end(<<"-----BEGIN PRIVATE KEY-----">>) ->
<<"-----END PRIVATE KEY-----">>;
pem_end(<<"-----BEGIN ENCRYPTED PRIVATE KEY-----">>) ->
<<"-----END ENCRYPTED PRIVATE KEY-----">>;
+pem_end(<<"-----BEGIN CERTIFICATE REQUEST-----">>) ->
+ <<"-----END CERTIFICATE REQUEST-----">>;
+pem_end(<<"-----BEGIN PKCS7-----">>) ->
+ <<"-----END PKCS7-----">>;
+pem_end(<<"-----BEGIN X509 CRL-----">>) ->
+ <<"-----END X509 CRL-----">>;
pem_end(_) ->
undefined.
@@ -229,7 +244,13 @@ asn1_type(<<"-----BEGIN DH PARAMETERS-----">>) ->
asn1_type(<<"-----BEGIN PRIVATE KEY-----">>) ->
'PrivateKeyInfo';
asn1_type(<<"-----BEGIN ENCRYPTED PRIVATE KEY-----">>) ->
- 'EncryptedPrivateKeyInfo'.
+ 'EncryptedPrivateKeyInfo';
+asn1_type(<<"-----BEGIN CERTIFICATE REQUEST-----">>) ->
+ 'CertificationRequest';
+asn1_type(<<"-----BEGIN PKCS7-----">>) ->
+ 'ContentInfo';
+asn1_type(<<"-----BEGIN X509 CRL-----">>) ->
+ 'CertificateList'.
pem_decrypt() ->
<<"Proc-Type: 4,ENCRYPTED">>.
diff --git a/lib/public_key/src/public_key.app.src b/lib/public_key/src/public_key.app.src
index 4cc81ea573..9f0677606d 100644
--- a/lib/public_key/src/public_key.app.src
+++ b/lib/public_key/src/public_key.app.src
@@ -7,6 +7,7 @@
pubkey_ssh,
pubkey_cert,
pubkey_cert_records,
+ pubkey_crl,
'OTP-PUB-KEY',
'PKCS-FRAME'
]},
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index d5df53e848..9b7d98728f 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -42,7 +42,8 @@
pkix_issuer_id/2,
pkix_normalize_name/1,
pkix_path_validation/3,
- ssh_decode/2, ssh_encode/2
+ ssh_decode/2, ssh_encode/2,
+ pkix_crls_validate/3
]).
-type rsa_padding() :: 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding'
@@ -50,6 +51,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 crl_reason() :: unspecified | keyCompromise | cACompromise | affiliationChanged | superseded
+ | cessationOfOperation | certificateHold | privilegeWithdrawn | aACompromise.
-define(UINT32(X), X:32/unsigned-big-integer).
-define(DER_NULL, <<5, 0>>).
@@ -428,9 +431,9 @@ pkix_verify(DerCert, #'RSAPublicKey'{} = RSAKey)
verify(PlainText, DigestType, Signature, RSAKey).
%%--------------------------------------------------------------------
--spec pkix_is_issuer(Cert::binary()| #'OTPCertificate'{},
- IssuerCert::binary()|
- #'OTPCertificate'{}) -> boolean().
+-spec pkix_is_issuer(Cert :: der_encoded()| #'OTPCertificate'{} | #'CertificateList'{},
+ IssuerCert :: der_encoded()|
+ #'OTPCertificate'{}) -> boolean().
%%
%% Description: Checks if <IssuerCert> issued <Cert>.
%%--------------------------------------------------------------------
@@ -443,7 +446,11 @@ pkix_is_issuer(Cert, IssuerCert) when is_binary(IssuerCert) ->
pkix_is_issuer(#'OTPCertificate'{tbsCertificate = TBSCert},
#'OTPCertificate'{tbsCertificate = Candidate}) ->
pubkey_cert:is_issuer(TBSCert#'OTPTBSCertificate'.issuer,
- Candidate#'OTPTBSCertificate'.subject).
+ Candidate#'OTPTBSCertificate'.subject);
+pkix_is_issuer(#'CertificateList'{tbsCertList = TBSCRL},
+ #'OTPCertificate'{tbsCertificate = Candidate}) ->
+ pubkey_cert:is_issuer(Candidate#'OTPTBSCertificate'.subject,
+ pubkey_cert_records:transform(TBSCRL#'TBSCertList'.issuer, decode)).
%%--------------------------------------------------------------------
-spec pkix_is_self_signed(Cert::binary()| #'OTPCertificate'{}) -> boolean().
@@ -502,7 +509,7 @@ pkix_normalize_name(Issuer) ->
%%--------------------------------------------------------------------
-spec pkix_path_validation(Cert::binary()| #'OTPCertificate'{} | atom(),
CertChain :: [binary()] ,
- Options :: list()) ->
+ Options :: proplists:proplist()) ->
{ok, {PublicKeyInfo :: term(),
PolicyTree :: term()}} |
{error, {bad_cert, Reason :: term()}}.
@@ -511,7 +518,7 @@ pkix_normalize_name(Issuer) ->
pkix_path_validation(PathErr, [Cert | Chain], Options0) when is_atom(PathErr)->
{VerifyFun, Userstat0} =
proplists:get_value(verify_fun, Options0, ?DEFAULT_VERIFYFUN),
- Otpcert = pkix_decode_cert(Cert, otp),
+ Otpcert = otp_cert(Cert),
Reason = {bad_cert, PathErr},
try VerifyFun(Otpcert, Reason, Userstat0) of
{valid, Userstate} ->
@@ -537,6 +544,27 @@ pkix_path_validation(#'OTPCertificate'{} = TrustedCert, CertChain, Options)
Options),
path_validation(CertChain, ValidationState).
+%--------------------------------------------------------------------
+-spec pkix_crls_validate(#'OTPCertificate'{},
+ [{DP::#'DistributionPoint'{} ,CRL::#'CertificateList'{}}],
+ Options :: proplists:proplist()) -> valid | {bad_cert, revocation_status_undetermined}
+ | {bad_cert, {revoked, crl_reason()}}.
+
+%% Description: Performs a basic path validation according to RFC 5280.
+%%--------------------------------------------------------------------
+pkix_crls_validate(OtpCert, [{_,_,_} |_] = DPAndCRLs, Options) ->
+ pkix_crls_validate(OtpCert, DPAndCRLs, DPAndCRLs,
+ Options, pubkey_crl:init_revokation_state());
+
+pkix_crls_validate(OtpCert, DPAndCRLs0, Options) ->
+ CallBack = proplists:get_value(update_crl, Options, fun(_, CurrCRL) ->
+ CurrCRL
+ end),
+ DPAndCRLs = sort_dp_crls(DPAndCRLs0, CallBack),
+ pkix_crls_validate(OtpCert, DPAndCRLs, DPAndCRLs,
+ Options, pubkey_crl:init_revokation_state()).
+
+
%%--------------------------------------------------------------------
-spec ssh_decode(binary(), public_key | ssh_file()) -> [{public_key(), Attributes::list()}].
%%
@@ -611,12 +639,13 @@ path_validation([DerCert | Rest], ValidationState = #path_validation_state{
{error, Reason}
end;
-path_validation([DerCert | _] = Path,
+path_validation([Cert | _] = Path,
#path_validation_state{user_state = UserState0,
verify_fun = VerifyFun} =
ValidationState) ->
Reason = {bad_cert, max_path_length_reached},
- OtpCert = pkix_decode_cert(DerCert, otp),
+ OtpCert = otp_cert(Cert),
+
try VerifyFun(OtpCert, Reason, UserState0) of
{valid, UserState} ->
path_validation(Path,
@@ -630,7 +659,7 @@ path_validation([DerCert | _] = Path,
{error, Reason}
end.
-validate(DerCert, #path_validation_state{working_issuer_name = Issuer,
+validate(Cert, #path_validation_state{working_issuer_name = Issuer,
working_public_key = Key,
working_public_key_parameters =
KeyParams,
@@ -641,31 +670,31 @@ validate(DerCert, #path_validation_state{working_issuer_name = Issuer,
verify_fun = VerifyFun} =
ValidationState0) ->
- OtpCert = pkix_decode_cert(DerCert, otp),
+ OtpCert = otp_cert(Cert),
- UserState1 = pubkey_cert:validate_time(OtpCert, UserState0, VerifyFun),
+ {ValidationState1, UserState1} =
+ pubkey_cert:validate_extensions(OtpCert, ValidationState0, UserState0,
+ VerifyFun),
- UserState2 = pubkey_cert:validate_issuer(OtpCert, Issuer, UserState1, VerifyFun),
+ %% We want the key_usage extension to be checked before we validate
+ %% other things so that CRL validation errors will comply to standard
+ %% test suite description
- UserState3 = pubkey_cert:validate_names(OtpCert, Permit, Exclude, Last,
- UserState2,VerifyFun),
+ UserState2 = pubkey_cert:validate_time(OtpCert, UserState1, VerifyFun),
- UserState4 = pubkey_cert:validate_revoked_status(OtpCert, UserState3, VerifyFun),
-
- {ValidationState1, UserState5} =
- pubkey_cert:validate_extensions(OtpCert, ValidationState0, UserState4,
- VerifyFun),
+ UserState3 = pubkey_cert:validate_issuer(OtpCert, Issuer, UserState2, VerifyFun),
- %% We want the key_usage extension to be checked before we validate
- %% the signature.
- UserState6 = pubkey_cert:validate_signature(OtpCert, DerCert,
- Key, KeyParams, UserState5, VerifyFun),
+ UserState4 = pubkey_cert:validate_names(OtpCert, Permit, Exclude, Last,
+ UserState3, VerifyFun),
+
+ UserState5 = pubkey_cert:validate_signature(OtpCert, der_cert(Cert),
+ Key, KeyParams, UserState4, VerifyFun),
UserState = case Last of
false ->
- pubkey_cert:verify_fun(OtpCert, valid, UserState6, VerifyFun);
+ pubkey_cert:verify_fun(OtpCert, valid, UserState5, VerifyFun);
true ->
pubkey_cert:verify_fun(OtpCert, valid_peer,
- UserState6, VerifyFun)
+ UserState5, VerifyFun)
end,
ValidationState =
@@ -676,3 +705,110 @@ validate(DerCert, #path_validation_state{working_issuer_name = Issuer,
sized_binary(Binary) ->
Size = size(Binary),
<<?UINT32(Size), Binary/binary>>.
+
+otp_cert(Der) when is_binary(Der) ->
+ pkix_decode_cert(Der, otp);
+otp_cert(#'OTPCertificate'{} =Cert) ->
+ Cert.
+
+der_cert(#'OTPCertificate'{} = Cert) ->
+ pkix_encode('OTPCertificate', Cert, otp);
+der_cert(Der) when is_binary(Der) ->
+ Der.
+
+pkix_crls_validate(_, [],_, _, _) ->
+ {bad_cert, revocation_status_undetermined};
+pkix_crls_validate(OtpCert, [{DP, CRL, DeltaCRL} | Rest], All, Options, RevokedState0) ->
+ CallBack = proplists:get_value(update_crl, Options, fun(_, CurrCRL) ->
+ CurrCRL
+ end),
+ case pubkey_crl:fresh_crl(DP, CRL, CallBack) of
+ {fresh, CRL} ->
+ do_pkix_crls_validate(OtpCert, [{DP, CRL, DeltaCRL} | Rest],
+ All, Options, RevokedState0);
+ {fresh, NewCRL} ->
+ NewAll = [{DP, NewCRL, DeltaCRL} | All -- [{DP, CRL, DeltaCRL}]],
+ do_pkix_crls_validate(OtpCert, [{DP, NewCRL, DeltaCRL} | Rest],
+ NewAll, Options, RevokedState0);
+ no_fresh_crl ->
+ pkix_crls_validate(OtpCert, Rest, All, Options, RevokedState0)
+ end.
+
+do_pkix_crls_validate(OtpCert, [{DP, CRL, DeltaCRL} | Rest], All, Options, RevokedState0) ->
+ OtherDPCRLs = All -- [{DP, CRL, DeltaCRL}],
+ case pubkey_crl:validate(OtpCert, OtherDPCRLs, DP, CRL, DeltaCRL, Options, RevokedState0) of
+ {undetermined, _, _} when Rest == []->
+ {bad_cert, revocation_status_undetermined};
+ {undetermined, _, RevokedState} when Rest =/= []->
+ pkix_crls_validate(OtpCert, Rest, All, Options, RevokedState);
+ {finished, unrevoked} ->
+ valid;
+ {finished, Status} ->
+ {bad_cert, Status}
+ end.
+
+sort_dp_crls(DpsAndCrls, FreshCB) ->
+ Sorted = do_sort_dp_crls(DpsAndCrls, dict:new()),
+ sort_crls(Sorted, FreshCB, []).
+
+do_sort_dp_crls([], Dict) ->
+ dict:to_list(Dict);
+do_sort_dp_crls([{DP, CRL} | Rest], Dict0) ->
+ Dict = try dict:fetch(DP, Dict0) of
+ _ ->
+ dict:append(DP, CRL, Dict0)
+ catch _:_ ->
+ dict:store(DP, [CRL], Dict0)
+ end,
+ do_sort_dp_crls(Rest, Dict).
+
+sort_crls([], _, Acc) ->
+ Acc;
+
+sort_crls([{DP, AllCRLs} | Rest], FreshCB, Acc)->
+ {DeltaCRLs, CRLs} = do_sort_crls(AllCRLs),
+ DpsAndCRLs = combine(CRLs, DeltaCRLs, DP, FreshCB, []),
+ sort_crls(Rest, FreshCB, DpsAndCRLs ++ Acc).
+
+do_sort_crls(CRLs) ->
+ lists:partition(fun({_, CRL}) ->
+ pubkey_crl:is_delta_crl(CRL)
+ end, CRLs).
+
+combine([], _,_,_,Acc) ->
+ Acc;
+combine([{_, CRL} = Entry | CRLs], DeltaCRLs, DP, FreshCB, Acc) ->
+ DeltaCRL = combine(CRL, DeltaCRLs),
+ case pubkey_crl:fresh_crl(DP, DeltaCRL, FreshCB) of
+ no_fresh_crl ->
+ combine(CRLs, DeltaCRLs, DP, FreshCB, [{DP, Entry, {undefined, undefined}} | Acc]);
+ {fresh, NewDeltaCRL} ->
+ combine(CRLs, DeltaCRLs, DP, FreshCB, [{DP, Entry, NewDeltaCRL} | Acc])
+ end.
+
+combine(CRL, DeltaCRLs) ->
+ Deltas = lists:filter(fun({_,DeltaCRL}) ->
+ pubkey_crl:combines(CRL, DeltaCRL)
+ end, DeltaCRLs),
+ case Deltas of
+ [] ->
+ {undefined, undefined};
+ [Delta] ->
+ Delta;
+ [_,_|_] ->
+ Fun =
+ fun({_, #'CertificateList'{tbsCertList = FirstTBSCRL}} = CRL1,
+ {_, #'CertificateList'{tbsCertList = SecondTBSCRL}} = CRL2) ->
+ Time1 = pubkey_cert:time_str_2_gregorian_sec(
+ FirstTBSCRL#'TBSCertList'.thisUpdate),
+ Time2 = pubkey_cert:time_str_2_gregorian_sec(
+ SecondTBSCRL#'TBSCertList'.thisUpdate),
+ case Time1 > Time2 of
+ true ->
+ CRL1;
+ false ->
+ CRL2
+ end
+ end,
+ lists:foldl(Fun, hd(Deltas), tl(Deltas))
+ end.
diff --git a/lib/public_key/test/erl_make_certs.erl b/lib/public_key/test/erl_make_certs.erl
index 254aa6d2f9..95e288cd71 100644
--- a/lib/public_key/test/erl_make_certs.erl
+++ b/lib/public_key/test/erl_make_certs.erl
@@ -137,10 +137,10 @@ decode_key(PemBin, Pw) ->
encode_key(Key = #'RSAPrivateKey'{}) ->
{ok, Der} = 'OTP-PUB-KEY':encode('RSAPrivateKey', Key),
- {'RSAPrivateKey', list_to_binary(Der), not_encrypted};
+ {'RSAPrivateKey', Der, not_encrypted};
encode_key(Key = #'DSAPrivateKey'{}) ->
{ok, Der} = 'OTP-PUB-KEY':encode('DSAPrivateKey', Key),
- {'DSAPrivateKey', list_to_binary(Der), not_encrypted}.
+ {'DSAPrivateKey', Der, not_encrypted}.
make_tbs(SubjectKey, Opts) ->
Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))),
@@ -234,7 +234,7 @@ extensions(Opts) ->
end.
default_extensions(Exts) ->
- Def = [{key_usage,undefined},
+ Def = [{key_usage, default},
{subject_altname, undefined},
{issuer_altname, undefined},
{basic_constraints, default},
@@ -265,6 +265,11 @@ extension({basic_constraints, Data}) ->
#'Extension'{extnID = ?'id-ce-basicConstraints',
extnValue = Data}
end;
+
+extension({key_usage, default}) ->
+ #'Extension'{extnID = ?'id-ce-keyUsage',
+ extnValue = [keyCertSign], critical = true};
+
extension({Id, Data, Critical}) ->
#'Extension'{extnID = Id, extnValue = Data, critical = Critical}.
diff --git a/lib/public_key/test/pbe_SUITE.erl b/lib/public_key/test/pbe_SUITE.erl
index 380a67db7b..8fba1e8cd3 100644
--- a/lib/public_key/test/pbe_SUITE.erl
+++ b/lib/public_key/test/pbe_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -19,72 +19,16 @@
-module(pbe_SUITE).
--include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct.hrl").
-include_lib("public_key/include/public_key.hrl").
%% Note: This directive should only be used in test suites.
-compile(export_all).
-%% Test server callback functions
-%%--------------------------------------------------------------------
-%% Function: init_per_suite(Config) -> Config
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Initialization before the whole suite
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
-%%--------------------------------------------------------------------
-init_per_suite(Config) ->
- try crypto:start() of
- ok ->
- Config
- catch _:_ ->
- {skip, "Crypto did not start"}
- end.
-%%--------------------------------------------------------------------
-%% Function: end_per_suite(Config) -> _
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after the whole suite
-%%--------------------------------------------------------------------
-end_per_suite(_Config) ->
- application:stop(crypto).
-
-%%--------------------------------------------------------------------
-%% Function: init_per_testcase(TestCase, Config) -> Config
-%% Case - atom()
-%% Name of the test case that is about to be run.
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%%
-%% Description: Initialization before each test case
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
-%% Description: Initialization before each test case
-%%--------------------------------------------------------------------
-init_per_testcase(_TestCase, Config) ->
- Config.
%%--------------------------------------------------------------------
-%% Function: end_per_testcase(TestCase, Config) -> _
-%% Case - atom()
-%% Name of the test case that is about to be run.
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after each test case
+%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
-end_per_testcase(_TestCase, _Config) ->
- ok.
-%%--------------------------------------------------------------------
-%% Function: all(Clause) -> TestCases
-%% Clause - atom() - suite | doc
-%% TestCases - [Case]
-%% Case - atom()
-%% Name of a test case.
-%% Description: Returns a list of all test cases in this test suite
-%%--------------------------------------------------------------------
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
@@ -96,17 +40,40 @@ all() ->
groups() ->
[].
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ try crypto:start() of
+ ok ->
+ Config
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ application:stop(crypto).
+
+%%--------------------------------------------------------------------
+
init_per_group(_GroupName, Config) ->
Config.
end_per_group(_GroupName, Config) ->
Config.
+%%--------------------------------------------------------------------
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+
+end_per_testcase(_TestCase, _Config) ->
+ ok.
-%% Test cases starts here.
%%--------------------------------------------------------------------
-pbdkdf1(doc) ->
- ["Test with PKCS #5 PBKDF1 Test Vectors"];
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+pbdkdf1() ->
+ [{doc,"Test with PKCS #5 PBKDF1 Test Vectors"}].
pbdkdf1(Config) when is_list(Config) ->
%%Password = "password"
%% = (0x)70617373776F7264
@@ -126,8 +93,8 @@ pbdkdf1(Config) when is_list(Config) ->
16#4A, 16#3D, 16#2A, 16#20, _/binary>> =
pubkey_pbe:pbdkdf1(Password, Salt, Count, sha).
-pbdkdf2(doc) ->
- ["Test with PKCS #5 PBKDF2 Test Vectors"];
+pbdkdf2() ->
+ [{doc,"Test with PKCS #5 PBKDF2 Test Vectors"}].
pbdkdf2(Config) when is_list(Config) ->
%% Input:
%% P = "password" (8 octets)
@@ -225,28 +192,28 @@ pbdkdf2(Config) when is_list(Config) ->
= pubkey_pbe:pbdkdf2("pass\0word",
"sa\0lt", 4096, 16, fun crypto:sha_mac/3, 20).
-encrypted_private_key_info(doc) ->
- ["Tests reading a EncryptedPrivateKeyInfo file encrypted with different ciphers"];
+encrypted_private_key_info() ->
+ [{doc,"Tests reading a EncryptedPrivateKeyInfo file encrypted with different ciphers"}].
encrypted_private_key_info(Config) when is_list(Config) ->
Datadir = ?config(data_dir, Config),
{ok, PemDes} = file:read_file(filename:join(Datadir, "des_cbc_enc_key.pem")),
PemDesEntry = public_key:pem_decode(PemDes),
- test_server:format("Pem entry: ~p" , [PemDesEntry]),
+ ct:print("Pem entry: ~p" , [PemDesEntry]),
[{'PrivateKeyInfo', _, {"DES-CBC",_}} = PubEntry0] = PemDesEntry,
KeyInfo = public_key:pem_entry_decode(PubEntry0, "password"),
{ok, Pem3Des} = file:read_file(filename:join(Datadir, "des_ede3_cbc_enc_key.pem")),
Pem3DesEntry = public_key:pem_decode(Pem3Des),
- test_server:format("Pem entry: ~p" , [Pem3DesEntry]),
+ ct:print("Pem entry: ~p" , [Pem3DesEntry]),
[{'PrivateKeyInfo', _, {"DES-EDE3-CBC",_}} = PubEntry1] = Pem3DesEntry,
KeyInfo = public_key:pem_entry_decode(PubEntry1, "password"),
{ok, PemRc2} = file:read_file(filename:join(Datadir, "rc2_cbc_enc_key.pem")),
PemRc2Entry = public_key:pem_decode(PemRc2),
- test_server:format("Pem entry: ~p" , [PemRc2Entry]),
+ ct:print("Pem entry: ~p" , [PemRc2Entry]),
[{'PrivateKeyInfo', _, {"RC2-CBC",_}} = PubEntry2] = PemRc2Entry,
KeyInfo = public_key:pem_entry_decode(PubEntry2, "password"),
diff --git a/lib/public_key/test/pkits_SUITE.erl b/lib/public_key/test/pkits_SUITE.erl
index e59f299399..d901adaadd 100644
--- a/lib/public_key/test/pkits_SUITE.erl
+++ b/lib/public_key/test/pkits_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -23,16 +23,18 @@
-module(pkits_SUITE).
--compile(export_all).
-
-include_lib("public_key/include/public_key.hrl").
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
-define(error(Format,Args), error(Format,Args,?FILE,?LINE)).
-define(warning(Format,Args), warning(Format,Args,?FILE,?LINE)).
-define(CERTS, "pkits/certs").
-define(MIME, "pkits/smime").
-define(CONV, "pkits/smime-pem").
+-define(CRL, "pkits/crls").
-define(NIST1, "2.16.840.1.101.3.2.1.48.1").
-define(NIST2, "2.16.840.1.101.3.2.1.48.2").
@@ -42,10 +44,13 @@
-define(NIST6, "2.16.840.1.101.3.2.1.48.6").
-record(verify_state, {
- certs_db,
- crl_info,
+ crls,
+ crl_paths,
revoke_state}).
-%%
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
suite() ->
[{ct_hooks,[ts_install_cth]}].
@@ -54,9 +59,9 @@ all() ->
{group, validity_periods},
{group, verifying_name_chaining},
{group, verifying_paths_with_self_issued_certificates},
- %%{group, basic_certificate_revocation_tests},
- %%{group, delta_crls},
- %%{group, distribution_points},
+ {group, basic_certificate_revocation_tests},
+ {group, delta_crls},
+ {group, distribution_points},
{group, verifying_basic_constraints},
{group, key_usage},
{group, name_constraints},
@@ -72,20 +77,22 @@ groups() ->
[invalid_name_chain, whitespace_name_chain, capitalization_name_chain,
uid_name_chain, attrib_name_chain, string_name_chain]},
{verifying_paths_with_self_issued_certificates, [],
- [basic_valid, %%basic_invalid,
- crl_signing_valid, crl_signing_invalid]},
- %% {basic_certificate_revocation_tests, [],
- %% [missing_CRL, revoked_CA, revoked_peer, invalid_CRL_signature,
- %% invalid_CRL_issuer, invalid_CRL, valid_CRL,
- %% unknown_CRL_extension, old_CRL, fresh_CRL, valid_serial,
- %% invalid_serial, valid_seperate_keys, invalid_separate_keys]},
- %% {delta_crls, [], [delta_without_crl, valid_delta_crls, invalid_delta_crls]},
- %% {distribution_points, [], [valid_distribution_points,
- %% valid_distribution_points_no_issuing_distribution_point,
- %% invalid_distribution_points, valid_only_contains,
- %% invalid_only_contains, valid_only_some_reasons,
- %% invalid_only_some_reasons, valid_indirect_crl,
- %% invalid_indirect_crl, valid_crl_issuer, invalid_crl_issuer]},
+ [basic_valid, basic_invalid, crl_signing_valid, crl_signing_invalid]},
+ {basic_certificate_revocation_tests, [],
+ [missing_CRL,
+ revoked_CA,
+ revoked_peer,
+ invalid_CRL_signature,
+ invalid_CRL_issuer, invalid_CRL, valid_CRL,
+ unknown_CRL_extension, old_CRL, fresh_CRL, valid_serial,
+ invalid_serial, valid_seperate_keys, invalid_separate_keys]},
+ {delta_crls, [], [delta_without_crl, valid_delta_crls, invalid_delta_crls]},
+ {distribution_points, [], [valid_distribution_points,
+ valid_distribution_points_no_issuing_distribution_point,
+ invalid_distribution_points, valid_only_contains,
+ invalid_only_contains, valid_only_some_reasons,
+ invalid_only_some_reasons, valid_indirect_crl,
+ invalid_indirect_crl, valid_crl_issuer, invalid_crl_issuer]},
{verifying_basic_constraints,[],
[missing_basic_constraints, valid_basic_constraint, invalid_path_constraints,
valid_path_constraints]},
@@ -102,12 +109,25 @@ groups() ->
[unknown_critical_extension, unknown_not_critical_extension]}
].
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ try crypto:start() of
+ ok ->
+ crypto_support_check(Config)
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ application:stop(crypto).
+
+%%--------------------------------------------------------------------
init_per_group(_GroupName, Config) ->
Config.
end_per_group(_GroupName, Config) ->
Config.
-
+%%--------------------------------------------------------------------
init_per_testcase(_Func, Config) ->
Datadir = proplists:get_value(data_dir, Config),
put(datadir, Datadir),
@@ -116,143 +136,105 @@ init_per_testcase(_Func, Config) ->
end_per_testcase(_Func, Config) ->
Config.
-init_per_suite(Config) ->
- try crypto:start() of
- ok ->
- crypto_support_check(Config)
- catch _:_ ->
- {skip, "Crypto did not start"}
- end.
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
-end_per_suite(_Config) ->
- application:stop(crypto).
-
-%%-----------------------------------------------------------------------------
-valid_rsa_signature(doc) ->
- ["Test rsa signatur verification"];
-valid_rsa_signature(suite) ->
- [];
+%%--------------------------- signature_verification--------------------------------------------------
+valid_rsa_signature() ->
+ [{doc, "Test rsa signatur verification"}].
valid_rsa_signature(Config) when is_list(Config) ->
run([{ "4.1.1", "Valid Certificate Path Test1 EE", ok}]).
-invalid_rsa_signature(doc) ->
- ["Test rsa signatur verification"];
-invalid_rsa_signature(suite) ->
- [];
+invalid_rsa_signature() ->
+ [{doc,"Test rsa signatur verification"}].
invalid_rsa_signature(Config) when is_list(Config) ->
run([{ "4.1.2", "Invalid CA Signature Test2 EE", {bad_cert,invalid_signature}},
{ "4.1.3", "Invalid EE Signature Test3 EE", {bad_cert,invalid_signature}}]).
-valid_dsa_signature(doc) ->
- ["Test dsa signatur verification"];
-valid_dsa_signature(suite) ->
- [];
+valid_dsa_signature() ->
+ [{doc,"Test dsa signatur verification"}].
valid_dsa_signature(Config) when is_list(Config) ->
run([{ "4.1.4", "Valid DSA Signatures Test4 EE", ok},
{ "4.1.5", "Valid DSA Parameter Inheritance Test5 EE", ok}]).
-invalid_dsa_signature(doc) ->
- ["Test dsa signatur verification"];
-invalid_dsa_signature(suite) ->
- [];
+invalid_dsa_signature() ->
+ [{doc,"Test dsa signatur verification"}].
invalid_dsa_signature(Config) when is_list(Config) ->
run([{ "4.1.6", "Invalid DSA Signature Test6 EE",{bad_cert,invalid_signature}}]).
-%%-----------------------------------------------------------------------------
-not_before_invalid(doc) ->
- [""];
-not_before_invalid(suite) ->
- [];
+
+%%-----------------------------validity_periods------------------------------------------------
+not_before_invalid() ->
+ [{doc,"Test valid periods"}].
not_before_invalid(Config) when is_list(Config) ->
run([{ "4.2.1", "Invalid CA notBefore Date Test1 EE",{bad_cert, cert_expired}},
{ "4.2.2", "Invalid EE notBefore Date Test2 EE",{bad_cert, cert_expired}}]).
-not_before_valid(doc) ->
- [""];
-not_before_valid(suite) ->
- [];
+not_before_valid() ->
+ [{doc,"Test valid periods"}].
not_before_valid(Config) when is_list(Config) ->
run([{ "4.2.3", "Valid pre2000 UTC notBefore Date Test3 EE", ok},
{ "4.2.4", "Valid GeneralizedTime notBefore Date Test4 EE", ok}]).
-not_after_invalid(doc) ->
- [""];
-not_after_invalid(suite) ->
- [];
+not_after_invalid() ->
+ [{doc,"Test valid periods"}].
not_after_invalid(Config) when is_list(Config) ->
run([{ "4.2.5", "Invalid CA notAfter Date Test5 EE", {bad_cert, cert_expired}},
{ "4.2.6", "Invalid EE notAfter Date Test6 EE", {bad_cert, cert_expired}},
{ "4.2.7", "Invalid pre2000 UTC EE notAfter Date Test7 EE",{bad_cert, cert_expired}}]).
-not_after_valid(doc) ->
- [""];
-not_after_valid(suite) ->
- [];
+not_after_valid() ->
+ [{doc,"Test valid periods"}].
not_after_valid(Config) when is_list(Config) ->
run([{ "4.2.8", "Valid GeneralizedTime notAfter Date Test8 EE", ok}]).
-%%-----------------------------------------------------------------------------
-invalid_name_chain(doc) ->
- [""];
-invalid_name_chain(suite) ->
- [];
+
+%%----------------------------verifying_name_chaining-------------------------------------------------
+invalid_name_chain() ->
+ [{doc,"Test name chaining"}].
invalid_name_chain(Config) when is_list(Config) ->
run([{ "4.3.1", "Invalid Name Chaining Test1 EE", {bad_cert, invalid_issuer}},
{ "4.3.2", "Invalid Name Chaining Order Test2 EE", {bad_cert, invalid_issuer}}]).
-whitespace_name_chain(doc) ->
- [""];
-whitespace_name_chain(suite) ->
- [];
+whitespace_name_chain() ->
+ [{doc,"Test name chaining"}].
whitespace_name_chain(Config) when is_list(Config) ->
run([{ "4.3.3", "Valid Name Chaining Whitespace Test3 EE", ok},
{ "4.3.4", "Valid Name Chaining Whitespace Test4 EE", ok}]).
-capitalization_name_chain(doc) ->
- [""];
-capitalization_name_chain(suite) ->
- [];
+capitalization_name_chain() ->
+ [{doc,"Test name chaining"}].
capitalization_name_chain(Config) when is_list(Config) ->
run([{ "4.3.5", "Valid Name Chaining Capitalization Test5 EE",ok}]).
-uid_name_chain(doc) ->
- [""];
-uid_name_chain(suite) ->
- [];
+uid_name_chain() ->
+ [{doc,"Test name chaining"}].
uid_name_chain(Config) when is_list(Config) ->
run([{ "4.3.6", "Valid Name UIDs Test6 EE",ok}]).
-attrib_name_chain(doc) ->
- [""];
-attrib_name_chain(suite) ->
- [];
+attrib_name_chain() ->
+ [{doc,"Test name chaining"}].
attrib_name_chain(Config) when is_list(Config) ->
run([{ "4.3.7", "Valid RFC3280 Mandatory Attribute Types Test7 EE", ok},
{ "4.3.8", "Valid RFC3280 Optional Attribute Types Test8 EE", ok}]).
-string_name_chain(doc) ->
- [""];
-string_name_chain(suite) ->
- [];
+string_name_chain() ->
+ [{doc,"Test name chaining"}].
string_name_chain(Config) when is_list(Config) ->
run([{ "4.3.9", "Valid UTF8String Encoded Names Test9 EE", ok},
%%{ "4.3.10", "Valid Rollover from PrintableString to UTF8String Test10 EE", ok},
{ "4.3.11", "Valid UTF8String Case Insensitive Match Test11 EE", ok}]).
-%%-----------------------------------------------------------------------------
-
-basic_valid(doc) ->
- [""];
-basic_valid(suite) ->
- [];
+%%----------------------------verifying_paths_with_self_issued_certificates-------------------------------------------------
+basic_valid() ->
+ [{doc,"Test self issued certificates"}].
basic_valid(Config) when is_list(Config) ->
run([{ "4.5.1", "Valid Basic Self-Issued Old With New Test1 EE", ok},
{ "4.5.3", "Valid Basic Self-Issued New With Old Test3 EE", ok},
{ "4.5.4", "Valid Basic Self-Issued New With Old Test4 EE", ok}
]).
-basic_invalid(doc) ->
- [""];
-basic_invalid(suite) ->
- [];
+basic_invalid() ->
+ [{doc,"Test self issued certificates"}].
basic_invalid(Config) when is_list(Config) ->
run([{"4.5.2", "Invalid Basic Self-Issued Old With New Test2 EE",
{bad_cert, {revoked, keyCompromise}}},
@@ -260,84 +242,63 @@ basic_invalid(Config) when is_list(Config) ->
{bad_cert, {revoked, keyCompromise}}}
]).
-crl_signing_valid(doc) ->
- [""];
-crl_signing_valid(suite) ->
- [];
+crl_signing_valid() ->
+ [{doc,"Test self issued certificates"}].
crl_signing_valid(Config) when is_list(Config) ->
run([{ "4.5.6", "Valid Basic Self-Issued CRL Signing Key Test6 EE", ok}]).
-crl_signing_invalid(doc) ->
- [""];
-crl_signing_invalid(suite) ->
- [];
+crl_signing_invalid() ->
+ [{doc,"Test self issued certificates"}].
crl_signing_invalid(Config) when is_list(Config) ->
- run([%% { "4.5.7", "Invalid Basic Self-Issued CRL Signing Key Test7 EE",
- %% {bad_cert, {revoked, keyCompromise}}},
+ run([{ "4.5.7", "Invalid Basic Self-Issued CRL Signing Key Test7 EE",
+ {bad_cert, {revoked, keyCompromise}}},
{ "4.5.8", "Invalid Basic Self-Issued CRL Signing Key Test8 EE",
{bad_cert, invalid_key_usage}}
]).
-%%-----------------------------------------------------------------------------
-missing_CRL(doc) ->
- [""];
-missing_CRL(suite) ->
- [];
+%%-----------------------------basic_certificate_revocation_tests------------------------------------------------
+missing_CRL() ->
+ [{doc,"Test basic CRL handling"}].
missing_CRL(Config) when is_list(Config) ->
- run([{ "4.4.1", "Missing CRL Test1 EE",{bad_cert,
+ run([{ "4.4.1", "Invalid Missing CRL Test1 EE",{bad_cert,
revocation_status_undetermined}}]).
-revoked_CA(doc) ->
- [""];
-revoked_CA(suite) ->
- [];
+revoked_CA() ->
+ [{doc,"Test basic CRL handling"}].
revoked_CA(Config) when is_list(Config) ->
run([{ "4.4.2", "Invalid Revoked CA Test2 EE", {bad_cert,
{revoked, keyCompromise}}}]).
-revoked_peer(doc) ->
- [""];
-revoked_peer(suite) ->
- [];
+revoked_peer() ->
+ [{doc,"Test basic CRL handling"}].
revoked_peer(Config) when is_list(Config) ->
- run([{ "4.4.3", "Invalid Revoked EE Test3 EE", {bad_cert,
- {revoked, keyCompromise}}}]).
+ run([{ "4.4.3", "Invalid Revoked EE Test3 EE",
+ {bad_cert, {revoked, keyCompromise}}}]).
-invalid_CRL_signature(doc) ->
- [""];
-invalid_CRL_signature(suite) ->
- [];
+invalid_CRL_signature() ->
+ [{doc,"Test basic CRL handling"}].
invalid_CRL_signature(Config) when is_list(Config) ->
run([{ "4.4.4", "Invalid Bad CRL Signature Test4 EE",
- {bad_cert, revocation_status_undetermined}}]).
-
-invalid_CRL_issuer(doc) ->
- [""];
-invalid_CRL_issuer(suite) ->
- [];
+ {bad_cert, revocation_status_undetermined}}]).
+invalid_CRL_issuer() ->
+ [{doc,"Test basic CRL handling"}].
invalid_CRL_issuer(Config) when is_list(Config) ->
run({ "4.4.5", "Invalid Bad CRL Issuer Name Test5 EE",
{bad_cert, revocation_status_undetermined}}).
-invalid_CRL(doc) ->
- [""];
-invalid_CRL(suite) ->
- [];
+invalid_CRL() ->
+ [{doc,"Test basic CRL handling"}].
invalid_CRL(Config) when is_list(Config) ->
run([{ "4.4.6", "Invalid Wrong CRL Test6 EE",
{bad_cert, revocation_status_undetermined}}]).
-valid_CRL(doc) ->
- [""];
-valid_CRL(suite) ->
- [];
+valid_CRL() ->
+ [{doc,"Test basic CRL handling"}].
valid_CRL(Config) when is_list(Config) ->
run([{ "4.4.7", "Valid Two CRLs Test7 EE", ok}]).
-unknown_CRL_extension(doc) ->
- [""];
-unknown_CRL_extension(suite) ->
- [];
+unknown_CRL_extension() ->
+ [{doc,"Test basic CRL handling"}].
unknown_CRL_extension(Config) when is_list(Config) ->
run([{ "4.4.8", "Invalid Unknown CRL Entry Extension Test8 EE",
{bad_cert, {revoked, keyCompromise}}},
@@ -346,27 +307,21 @@ unknown_CRL_extension(Config) when is_list(Config) ->
{ "4.4.10", "Invalid Unknown CRL Extension Test10 EE",
{bad_cert, revocation_status_undetermined}}]).
-old_CRL(doc) ->
- [""];
-old_CRL(suite) ->
- [];
+old_CRL() ->
+ [{doc,"Test basic CRL handling"}].
old_CRL(Config) when is_list(Config) ->
run([{ "4.4.11", "Invalid Old CRL nextUpdate Test11 EE",
{bad_cert, revocation_status_undetermined}},
{ "4.4.12", "Invalid pre2000 CRL nextUpdate Test12 EE",
{bad_cert, revocation_status_undetermined}}]).
-fresh_CRL(doc) ->
- [""];
-fresh_CRL(suite) ->
- [];
+fresh_CRL() ->
+ [{doc,"Test basic CRL handling"}].
fresh_CRL(Config) when is_list(Config) ->
run([{ "4.4.13", "Valid GeneralizedTime CRL nextUpdate Test13 EE", ok}]).
-valid_serial(doc) ->
- [""];
-valid_serial(suite) ->
- [];
+valid_serial() ->
+ [{doc,"Test basic CRL handling"}].
valid_serial(Config) when is_list(Config) ->
run([
{ "4.4.14", "Valid Negative Serial Number Test14 EE",ok},
@@ -374,38 +329,30 @@ valid_serial(Config) when is_list(Config) ->
{ "4.4.17", "Valid Long Serial Number Test17 EE", ok}
]).
-invalid_serial(doc) ->
- [""];
-invalid_serial(suite) ->
- [];
+invalid_serial() ->
+ [{doc,"Test basic CRL handling"}].
invalid_serial(Config) when is_list(Config) ->
run([{ "4.4.15", "Invalid Negative Serial Number Test15 EE",
{bad_cert, {revoked, keyCompromise}}},
{ "4.4.18", "Invalid Long Serial Number Test18 EE",
{bad_cert, {revoked, keyCompromise}}}]).
-valid_seperate_keys(doc) ->
- [""];
-valid_seperate_keys(suite) ->
- [];
+valid_seperate_keys() ->
+ [{doc,"Test basic CRL handling"}].
valid_seperate_keys(Config) when is_list(Config) ->
run([{ "4.4.19", "Valid Separate Certificate and CRL Keys Test19 EE", ok}]).
-invalid_separate_keys(doc) ->
- [""];
-invalid_separate_keys(suite) ->
- [];
+invalid_separate_keys() ->
+ [{doc,"Test basic CRL handling"}].
invalid_separate_keys(Config) when is_list(Config) ->
- run([{ "4.4.20", "Invalid Separate Certificate and CRL Keys Test20",
+ run([{ "4.4.20", "Invalid Separate Certificate and CRL Keys Test20 EE",
{bad_cert, {revoked, keyCompromise}}},
- { "4.4.21", "Invalid Separate Certificate and CRL Keys Test21",
+ { "4.4.21", "Invalid Separate Certificate and CRL Keys Test21 EE",
{bad_cert, revocation_status_undetermined}}
]).
-%%-----------------------------------------------------------------------------
-missing_basic_constraints(doc) ->
- [""];
-missing_basic_constraints(suite) ->
- [];
+%%----------------------------verifying_basic_constraints-------------------------------------------------
+missing_basic_constraints() ->
+ [{doc,"Basic constraint tests"}].
missing_basic_constraints(Config) when is_list(Config) ->
run([{ "4.6.1", "Invalid Missing basicConstraints Test1 EE",
{bad_cert, missing_basic_constraint}},
@@ -414,17 +361,13 @@ missing_basic_constraints(Config) when is_list(Config) ->
{ "4.6.3", "Invalid cA False Test3 EE",
{bad_cert, missing_basic_constraint}}]).
-valid_basic_constraint(doc) ->
- [""];
-valid_basic_constraint(suite) ->
- [];
+valid_basic_constraint() ->
+ [{doc,"Basic constraint tests"}].
valid_basic_constraint(Config) when is_list(Config) ->
run([{"4.6.4", "Valid basicConstraints Not Critical Test4 EE", ok}]).
-invalid_path_constraints(doc) ->
- [""];
-invalid_path_constraints(suite) ->
- [];
+invalid_path_constraints() ->
+ [{doc,"Basic constraint tests"}].
invalid_path_constraints(Config) when is_list(Config) ->
run([{ "4.6.5", "Invalid pathLenConstraint Test5 EE", {bad_cert, max_path_length_reached}},
{ "4.6.6", "Invalid pathLenConstraint Test6 EE", {bad_cert, max_path_length_reached}},
@@ -435,10 +378,8 @@ invalid_path_constraints(Config) when is_list(Config) ->
{ "4.6.16", "Invalid Self-Issued pathLenConstraint Test16 EE",
{bad_cert, max_path_length_reached}}]).
-valid_path_constraints(doc) ->
- [""];
-valid_path_constraints(suite) ->
- [];
+valid_path_constraints() ->
+ [{doc,"Basic constraint tests"}].
valid_path_constraints(Config) when is_list(Config) ->
run([{ "4.6.7", "Valid pathLenConstraint Test7 EE", ok},
{ "4.6.8", "Valid pathLenConstraint Test8 EE", ok},
@@ -447,60 +388,54 @@ valid_path_constraints(Config) when is_list(Config) ->
{ "4.6.15", "Valid Self-Issued pathLenConstraint Test15 EE", ok},
{ "4.6.17", "Valid Self-Issued pathLenConstraint Test17 EE", ok}]).
-%%-----------------------------------------------------------------------------
-invalid_key_usage(doc) ->
- [""];
-invalid_key_usage(suite) ->
- [];
+%%-----------------------------key_usage------------------------------------------------
+invalid_key_usage() ->
+ [{doc,"Key usage tests"}].
invalid_key_usage(Config) when is_list(Config) ->
run([{ "4.7.1", "Invalid keyUsage Critical keyCertSign False Test1 EE",
{bad_cert,invalid_key_usage} },
{ "4.7.2", "Invalid keyUsage Not Critical keyCertSign False Test2 EE",
- {bad_cert,invalid_key_usage}}
- %% { "4.7.4", "Invalid keyUsage Critical cRLSign False Test4 EE",
- %% {bad_cert, revocation_status_undetermined}},
- %% { "4.7.5", "Invalid keyUsage Not Critical cRLSign False Test5 EE",
- %% {bad_cert, revocation_status_undetermined}}
+ {bad_cert,invalid_key_usage}},
+ { "4.7.4", "Invalid keyUsage Critical cRLSign False Test4 EE",
+ {bad_cert, invalid_key_usage}},
+ { "4.7.5", "Invalid keyUsage Not Critical cRLSign False Test5 EE",
+ {bad_cert, invalid_key_usage}}
]).
-valid_key_usage(doc) ->
- [""];
-valid_key_usage(suite) ->
- [];
+valid_key_usage() ->
+ [{doc,"Key usage tests"}].
valid_key_usage(Config) when is_list(Config) ->
run([{ "4.7.3", "Valid keyUsage Not Critical Test3 EE", ok}]).
%%-----------------------------------------------------------------------------
-certificate_policies(doc) -> [""];
-certificate_policies(suite) -> [];
+certificate_policies() ->
+ [{doc,"Not supported yet"}].
certificate_policies(Config) when is_list(Config) ->
- run(certificate_policies()).
+ run(certificate_policies_tests()).
%%-----------------------------------------------------------------------------
-require_explicit_policy(doc) -> [""];
-require_explicit_policy(suite) -> [];
+require_explicit_policy() ->
+ [{doc,"Not supported yet"}].
require_explicit_policy(Config) when is_list(Config) ->
- run(require_explicit_policy()).
+ run(require_explicit_policy_tests()).
%%-----------------------------------------------------------------------------
-policy_mappings(doc) -> [""];
-policy_mappings(suite) -> [];
+policy_mappings() ->
+ [{doc,"Not supported yet"}].
policy_mappings(Config) when is_list(Config) ->
- run(policy_mappings()).
+ run(policy_mappings_tests()).
%%-----------------------------------------------------------------------------
-inhibit_policy_mapping(doc) -> [""];
-inhibit_policy_mapping(suite) -> [];
+inhibit_policy_mapping() ->
+ [{doc,"Not supported yet"}].
inhibit_policy_mapping(Config) when is_list(Config) ->
- run(inhibit_policy_mapping()).
+ run(inhibit_policy_mapping_tests()).
%%-----------------------------------------------------------------------------
-inhibit_any_policy(doc) -> [""];
-inhibit_any_policy(suite) -> [];
+inhibit_any_policy() ->
+ [{doc,"Not supported yet"}].
inhibit_any_policy(Config) when is_list(Config) ->
- run(inhibit_any_policy()).
-%%-----------------------------------------------------------------------------
+ run(inhibit_any_policy_tests()).
+%%-------------------------------name_constraints----------------------------------------------
-valid_DN_name_constraints(doc) ->
- [""];
-valid_DN_name_constraints(suite) ->
- [];
+valid_DN_name_constraints() ->
+ [{doc, "Name constraints tests"}].
valid_DN_name_constraints(Config) when is_list(Config) ->
run([{ "4.13.1", "Valid DN nameConstraints Test1 EE", ok},
{ "4.13.4", "Valid DN nameConstraints Test4 EE", ok},
@@ -511,10 +446,8 @@ valid_DN_name_constraints(Config) when is_list(Config) ->
{ "4.13.18", "Valid DN nameConstraints Test18 EE", ok},
{ "4.13.19", "Valid DN nameConstraints Test19 EE", ok}]).
-invalid_DN_name_constraints(doc) ->
- [""];
-invalid_DN_name_constraints(suite) ->
- [];
+invalid_DN_name_constraints() ->
+ [{doc,"Name constraints tests"}].
invalid_DN_name_constraints(Config) when is_list(Config) ->
run([{ "4.13.2", "Invalid DN nameConstraints Test2 EE", {bad_cert, name_not_permitted}},
{ "4.13.3", "Invalid DN nameConstraints Test3 EE", {bad_cert, name_not_permitted}},
@@ -530,20 +463,15 @@ invalid_DN_name_constraints(Config) when is_list(Config) ->
{ "4.13.20", "Invalid DN nameConstraints Test20 EE",
{bad_cert, name_not_permitted}}]).
-valid_rfc822_name_constraints(doc) ->
- [""];
-valid_rfc822_name_constraints(suite) ->
- [];
+valid_rfc822_name_constraints() ->
+ [{doc,"Name constraints tests"}].
valid_rfc822_name_constraints(Config) when is_list(Config) ->
run([{ "4.13.21", "Valid RFC822 nameConstraints Test21 EE", ok},
{ "4.13.23", "Valid RFC822 nameConstraints Test23 EE", ok},
{ "4.13.25", "Valid RFC822 nameConstraints Test25 EE", ok}]).
-
-invalid_rfc822_name_constraints(doc) ->
- [""];
-invalid_rfc822_name_constraints(suite) ->
- [];
+invalid_rfc822_name_constraints() ->
+ [{doc,"Name constraints tests"}].
invalid_rfc822_name_constraints(Config) when is_list(Config) ->
run([{ "4.13.22", "Invalid RFC822 nameConstraints Test22 EE",
{bad_cert, name_not_permitted}},
@@ -552,71 +480,54 @@ invalid_rfc822_name_constraints(Config) when is_list(Config) ->
{ "4.13.26", "Invalid RFC822 nameConstraints Test26 EE",
{bad_cert, name_not_permitted}}]).
-valid_DN_and_rfc822_name_constraints(doc) ->
- [""];
-valid_DN_and_rfc822_name_constraints(suite) ->
- [];
+valid_DN_and_rfc822_name_constraints() ->
+ [{doc,"Name constraints tests"}].
valid_DN_and_rfc822_name_constraints(Config) when is_list(Config) ->
run([{ "4.13.27", "Valid DN and RFC822 nameConstraints Test27 EE", ok}]).
-invalid_DN_and_rfc822_name_constraints(doc) ->
- [""];
-invalid_DN_and_rfc822_name_constraints(suite) ->
- [];
+invalid_DN_and_rfc822_name_constraints() ->
+ [{doc,"Name constraints tests"}].
invalid_DN_and_rfc822_name_constraints(Config) when is_list(Config) ->
run([{ "4.13.28", "Invalid DN and RFC822 nameConstraints Test28 EE",
{bad_cert, name_not_permitted}},
{ "4.13.29", "Invalid DN and RFC822 nameConstraints Test29 EE",
{bad_cert, name_not_permitted}}]).
-valid_dns_name_constraints(doc) ->
- [""];
-valid_dns_name_constraints(suite) ->
- [];
+valid_dns_name_constraints() ->
+ [{doc,"Name constraints tests"}].
valid_dns_name_constraints(Config) when is_list(Config) ->
run([{ "4.13.30", "Valid DNS nameConstraints Test30 EE", ok},
{ "4.13.32", "Valid DNS nameConstraints Test32 EE", ok}]).
-invalid_dns_name_constraints(doc) ->
- [""];
-invalid_dns_name_constraints(suite) ->
- [];
+invalid_dns_name_constraints() ->
+ [{doc,"Name constraints tests"}].
invalid_dns_name_constraints(Config) when is_list(Config) ->
run([{ "4.13.31", "Invalid DNS nameConstraints Test31 EE", {bad_cert, name_not_permitted}},
{ "4.13.33", "Invalid DNS nameConstraints Test33 EE", {bad_cert, name_not_permitted}},
{ "4.13.38", "Invalid DNS nameConstraints Test38 EE", {bad_cert, name_not_permitted}}]).
-valid_uri_name_constraints(doc) ->
- [""];
-valid_uri_name_constraints(suite) ->
- [];
+valid_uri_name_constraints() ->
+ [{doc,"Name constraints tests"}].
valid_uri_name_constraints(Config) when is_list(Config) ->
run([{ "4.13.34", "Valid URI nameConstraints Test34 EE", ok},
{ "4.13.36", "Valid URI nameConstraints Test36 EE", ok}]).
-invalid_uri_name_constraints(doc) ->
- [""];
-invalid_uri_name_constraints(suite) ->
- [];
+invalid_uri_name_constraints() ->
+ [{doc,"Name constraints tests"}].
invalid_uri_name_constraints(Config) when is_list(Config) ->
run([{ "4.13.35", "Invalid URI nameConstraints Test35 EE",{bad_cert, name_not_permitted}},
{ "4.13.37", "Invalid URI nameConstraints Test37 EE",{bad_cert, name_not_permitted}}]).
-%%-----------------------------------------------------------------------------
-delta_without_crl(doc) ->
- [""];
-delta_without_crl(suite) ->
- [];
+%%------------------------------delta_crls-----------------------------------------------
+delta_without_crl() ->
+ [{doc,"Delta CRL tests"}].
delta_without_crl(Config) when is_list(Config) ->
run([{ "4.15.1", "Invalid deltaCRLIndicator No Base Test1 EE",{bad_cert,
revocation_status_undetermined}},
{"4.15.10", "Invalid delta-CRL Test10 EE", {bad_cert,
revocation_status_undetermined}}]).
-
-valid_delta_crls(doc) ->
- [""];
-valid_delta_crls(suite) ->
- [];
+valid_delta_crls() ->
+ [{doc,"Delta CRL tests"}].
valid_delta_crls(Config) when is_list(Config) ->
run([{ "4.15.2", "Valid delta-CRL Test2 EE", ok},
{ "4.15.5", "Valid delta-CRL Test5 EE", ok},
@@ -624,22 +535,17 @@ valid_delta_crls(Config) when is_list(Config) ->
{ "4.15.8", "Valid delta-CRL Test8 EE", ok}
]).
-invalid_delta_crls(doc) ->
- [""];
-invalid_delta_crls(suite) ->
- [];
+invalid_delta_crls() ->
+ [{doc,"Delta CRL tests"}].
invalid_delta_crls(Config) when is_list(Config) ->
run([{ "4.15.3", "Invalid delta-CRL Test3 EE", {bad_cert,{revoked, keyCompromise}}},
{ "4.15.4", "Invalid delta-CRL Test4 EE", {bad_cert,{revoked, keyCompromise}}},
{ "4.15.6", "Invalid delta-CRL Test6 EE", {bad_cert,{revoked, keyCompromise}}},
{ "4.15.9", "Invalid delta-CRL Test9 EE", {bad_cert,{revoked, keyCompromise}}}]).
-%%-----------------------------------------------------------------------------
-
-valid_distribution_points(doc) ->
- [""];
-valid_distribution_points(suite) ->
- [];
+%%---------------------------distribution_points--------------------------------------------------
+valid_distribution_points() ->
+ [{doc,"CRL Distribution Point tests"}].
valid_distribution_points(Config) when is_list(Config) ->
run([{ "4.14.1", "Valid distributionPoint Test1 EE", ok},
{ "4.14.4", "Valid distributionPoint Test4 EE", ok},
@@ -647,18 +553,14 @@ valid_distribution_points(Config) when is_list(Config) ->
{ "4.14.7", "Valid distributionPoint Test7 EE", ok}
]).
-valid_distribution_points_no_issuing_distribution_point(doc) ->
- [""];
-valid_distribution_points_no_issuing_distribution_point(suite) ->
- [];
+valid_distribution_points_no_issuing_distribution_point() ->
+ [{doc,"CRL Distribution Point tests"}].
valid_distribution_points_no_issuing_distribution_point(Config) when is_list(Config) ->
- run([{ "4.14.10", "Valid No issuingDistributionPoint Test10", ok}
+ run([{ "4.14.10", "Valid No issuingDistributionPoint Test10 EE", ok}
]).
-invalid_distribution_points(doc) ->
- [""];
-invalid_distribution_points(suite) ->
- [];
+invalid_distribution_points() ->
+ [{doc,"CRL Distribution Point tests"}].
invalid_distribution_points(Config) when is_list(Config) ->
run([{ "4.14.2", "Invalid distributionPoint Test2 EE", {bad_cert,{revoked, keyCompromise}}},
{ "4.14.3", "Invalid distributionPoint Test3 EE", {bad_cert,
@@ -670,40 +572,31 @@ invalid_distribution_points(Config) when is_list(Config) ->
revocation_status_undetermined}}
]).
-valid_only_contains(doc) ->
- [""];
-valid_only_contains(suite) ->
- [];
+valid_only_contains() ->
+ [{doc,"CRL Distribution Point tests"}].
valid_only_contains(Config) when is_list(Config) ->
- run([{ "4.14.13", "Valid onlyContainsCACerts CRL Test13 EE", ok}]).
-
+ run([{ "4.14.13", "Valid only Contains CA Certs Test13 EE", ok}]).
-invalid_only_contains(doc) ->
- [""];
-invalid_only_contains(suite) ->
- [];
+invalid_only_contains() ->
+ [{doc,"CRL Distribution Point tests"}].
invalid_only_contains(Config) when is_list(Config) ->
- run([{ "4.14.11", "Invalid onlyContainsUserCerts CRL Test11 EE",
+ run([{ "4.14.11", "Invalid onlyContainsUserCerts Test11 EE",
{bad_cert, revocation_status_undetermined}},
- { "4.14.12", "Invalid onlyContainsCACerts CRL Test12 EE",
+ { "4.14.12", "Invalid onlyContainsCACerts Test12 EE",
{bad_cert, revocation_status_undetermined}},
{ "4.14.14", "Invalid onlyContainsAttributeCerts Test14 EE",
{bad_cert, revocation_status_undetermined}}
]).
-valid_only_some_reasons(doc) ->
- [""];
-valid_only_some_reasons(suite) ->
- [];
+valid_only_some_reasons() ->
+ [{doc,"CRL Distribution Point tests"}].
valid_only_some_reasons(Config) when is_list(Config) ->
run([{ "4.14.18", "Valid onlySomeReasons Test18 EE", ok},
{ "4.14.19", "Valid onlySomeReasons Test19 EE", ok}
]).
-invalid_only_some_reasons(doc) ->
- [""];
-invalid_only_some_reasons(suite) ->
- [];
+invalid_only_some_reasons() ->
+ [{doc,"CRL Distribution Point tests"}].
invalid_only_some_reasons(Config) when is_list(Config) ->
run([{ "4.14.15", "Invalid onlySomeReasons Test15 EE",
{bad_cert,{revoked, keyCompromise}}},
@@ -717,20 +610,16 @@ invalid_only_some_reasons(Config) when is_list(Config) ->
{bad_cert,{revoked, affiliationChanged}}}
]).
-valid_indirect_crl(doc) ->
- [""];
-valid_indirect_crl(suite) ->
- [];
+valid_indirect_crl() ->
+ [{doc,"CRL Distribution Point tests"}].
valid_indirect_crl(Config) when is_list(Config) ->
run([{ "4.14.22", "Valid IDP with indirectCRL Test22 EE", ok},
{ "4.14.24", "Valid IDP with indirectCRL Test24 EE", ok},
{ "4.14.25", "Valid IDP with indirectCRL Test25 EE", ok}
]).
-invalid_indirect_crl(doc) ->
- [""];
-invalid_indirect_crl(suite) ->
- [];
+invalid_indirect_crl() ->
+ [{doc,"CRL Distribution Point tests"}].
invalid_indirect_crl(Config) when is_list(Config) ->
run([{ "4.14.23", "Invalid IDP with indirectCRL Test23 EE",
{bad_cert,{revoked, keyCompromise}}},
@@ -738,20 +627,16 @@ invalid_indirect_crl(Config) when is_list(Config) ->
{bad_cert, revocation_status_undetermined}}
]).
-valid_crl_issuer(doc) ->
- [""];
-valid_crl_issuer(suite) ->
- [];
+valid_crl_issuer() ->
+ [{doc,"CRL Distribution Point tests"}].
valid_crl_issuer(Config) when is_list(Config) ->
- run([{ "4.14.28", "Valid cRLIssuer Test28 EE", ok}%%,
- %%{ "4.14.29", "Valid cRLIssuer Test29 EE", ok},
- %%{ "4.14.33", "Valid cRLIssuer Test33 EE", ok}
+ run([{ "4.14.28", "Valid cRLIssuer Test28 EE", ok},
+ { "4.14.29", "Valid cRLIssuer Test29 EE", ok},
+ { "4.14.33", "Valid cRLIssuer Test33 EE", ok}
]).
-invalid_crl_issuer(doc) ->
- [""];
-invalid_crl_issuer(suite) ->
- [];
+invalid_crl_issuer() ->
+ [{doc,"CRL Distribution Point tests"}].
invalid_crl_issuer(Config) when is_list(Config) ->
run([
{ "4.14.27", "Invalid cRLIssuer Test27 EE", {bad_cert, revocation_status_undetermined}},
@@ -761,44 +646,36 @@ invalid_crl_issuer(Config) when is_list(Config) ->
{ "4.14.35", "Invalid cRLIssuer Test35 EE", {bad_cert, revocation_status_undetermined}}
]).
-
-%%distribution_points() ->
- %%{ "4.14", "Distribution Points" },
-%% [
- %% Although this test is valid it has a circular dependency. As a result
- %% an attempt is made to reursively checks a CRL path and rejected due to
- %% a CRL path validation error. PKITS notes suggest this test does not
- %% need to be run due to this issue.
-%% { "4.14.30", "Valid cRLIssuer Test30", 54 }].
+%% Although this test is valid it has a circular dependency. As a result
+%% an attempt is made to reursively checks a CRL path and rejected due to
+%% a CRL path validation error. PKITS notes suggest this test does not
+%% need to be run due to this issue.
+%% { "4.14.30", "Valid cRLIssuer Test30", 54 }
-%%-----------------------------------------------------------------------------
+%%-------------------------------private_certificate_extensions----------------------------------------------
-unknown_critical_extension(doc) ->
- [""];
-unknown_critical_extension(suite) ->
- [];
+unknown_critical_extension() ->
+ [{doc,"Test that a cert with an unknown critical extension is recjected"}].
unknown_critical_extension(Config) when is_list(Config) ->
run([{ "4.16.2", "Invalid Unknown Critical Certificate Extension Test2 EE",
{bad_cert,unknown_critical_extension}}]).
-unknown_not_critical_extension(doc) ->
- [""];
-unknown_not_critical_extension(suite) ->
- [];
+unknown_not_critical_extension() ->
+ [{doc,"Test that a not critical unknown extension is ignored"}].
unknown_not_critical_extension(Config) when is_list(Config) ->
run([{ "4.16.1", "Valid Unknown Not Critical Certificate Extension Test1 EE", ok}]).
-%%-----------------------------------------------------------------------------
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
+
run(Tests) ->
[TA] = read_certs("Trust Anchor Root Certificate"),
run(Tests, TA).
run({Chap, Test, Result}, TA) ->
CertChain = cas(Chap) ++ read_certs(Test),
- lists:foreach(fun(C) ->
- io:format("CERT: ~p~n", [public_key:pkix_decode_cert(C, otp)])
- end, CertChain),
Options = path_validation_options(TA, Chap,Test),
try public_key:pkix_path_validation(TA, CertChain, Options) of
{Result, _} -> ok;
@@ -825,7 +702,7 @@ run([],_) -> ok.
path_validation_options(TA, Chap, Test) ->
case needs_crl_options(Chap) of
true ->
- crl_options(TA, Test);
+ crl_options(TA, Chap, Test);
false ->
Fun =
fun(_,{bad_cert, _} = Reason, _) ->
@@ -839,6 +716,56 @@ path_validation_options(TA, Chap, Test) ->
[{verify_fun, {Fun, []}}]
end.
+read_certs(Test) ->
+ File = cert_file(Test),
+ Ders = erl_make_certs:pem_to_der(File),
+ [Cert || {'Certificate', Cert, not_encrypted} <- Ders].
+
+read_crls(Test) ->
+ File = crl_file(Test),
+ Ders = erl_make_certs:pem_to_der(File),
+ [CRL || {'CertificateList', CRL, not_encrypted} <- Ders].
+
+cert_file(Test) ->
+ file(?CONV, lists:append(string:tokens(Test, " -")) ++ ".pem").
+
+crl_file(Test) ->
+ file(?CRL, lists:append(string:tokens(Test, " -")) ++ ".pem").
+
+
+file(Sub,File) ->
+ TestDir = case get(datadir) of
+ undefined -> "./pkits_SUITE_data";
+ Dir when is_list(Dir) ->
+ Dir
+ end,
+ AbsFile = filename:join([TestDir,Sub,File]),
+ case filelib:is_file(AbsFile) of
+ true -> ok;
+ false ->
+ ?error("Couldn't read data from ~p ~n",[AbsFile])
+ end,
+ AbsFile.
+
+error(Format, Args, File0, Line) ->
+ File = filename:basename(File0),
+ Pid = group_leader(),
+ Pid ! {failed, File, Line},
+ io:format(Pid, "~s(~p): ERROR"++Format, [File,Line|Args]).
+
+warning(Format, Args, File0, Line) ->
+ File = filename:basename(File0),
+ io:format("~s(~p): Warning "++Format, [File,Line|Args]).
+
+crypto_support_check(Config) ->
+ try crypto:sha256(<<"Test">>) of
+ _ ->
+ Config
+ catch error:notsup ->
+ crypto:stop(),
+ {skip, "To old version of openssl"}
+ end.
+
needs_crl_options("4.4" ++ _) ->
true;
needs_crl_options("4.5" ++ _) ->
@@ -854,54 +781,69 @@ needs_crl_options("4.15" ++ _) ->
needs_crl_options(_) ->
false.
-crl_options(TA, Test) ->
- case read_crls(Test) of
- [] ->
- [];
- CRLs ->
- Fun =
- fun(_,{bad_cert, _} = Reason, _) ->
- {fail, Reason};
- (_,{extension,
- #'Extension'{extnID = ?'id-ce-cRLDistributionPoints',
- extnValue = Value}}, UserState0) ->
- UserState = update_crls(Value, UserState0),
+crl_options(_TA, Chap, _Test) ->
+ CRLNames = crl_names(Chap),
+ CRLs = crls(CRLNames),
+ Paths = lists:map(fun(CRLName) -> crl_path(CRLName) end, CRLNames),
+
+ ct:print("Paths ~p ~n Names ~p ~n", [Paths, CRLNames]),
+ Fun =
+ fun(_,{bad_cert, _} = Reason, _) ->
+ {fail, Reason};
+ (_,{extension,
+ #'Extension'{extnID = ?'id-ce-cRLDistributionPoints',
+ extnValue = Value}}, UserState0) ->
+ UserState = update_crls(Value, UserState0),
+ {valid, UserState};
+ (_,{extension, _}, UserState) ->
+ {unknown, UserState};
+ (OtpCert, Valid, UserState) when Valid == valid;
+ Valid == valid_peer ->
+ DerCRLs = UserState#verify_state.crls,
+ Paths = UserState#verify_state.crl_paths,
+ Crls = [{DerCRL, public_key:der_decode('CertificateList',
+ DerCRL)} || DerCRL <- DerCRLs],
+
+ CRLInfo0 = crl_info(OtpCert, Crls, []),
+ CRLInfo = lists:reverse(CRLInfo0),
+ PathDb = crl_path_db(lists:reverse(Crls), Paths, []),
+
+ Fun = fun(DP, CRLtoValidate, Id, PathDb0) ->
+ trusted_cert_and_path(DP, CRLtoValidate, Id, PathDb0)
+ end,
+
+ case CRLInfo of
+ [] ->
{valid, UserState};
- (_,{extension, _}, UserState) ->
- {unknown, UserState};
- (OtpCert, Valid, UserState) when Valid == valid;
- Valid == valid_peer ->
- {ErlCerts, CRLs} = UserState#verify_state.crl_info,
- CRLInfo0 =
- crl_info(OtpCert,
- ErlCerts,[{DerCRL, public_key:der_decode('CertificateList',
- DerCRL)} || DerCRL <- CRLs],
- []),
- CRLInfo = lists:reverse(CRLInfo0),
- Certs = UserState#verify_state.certs_db,
- Fun = fun(DP, CRLtoValidate, Id, CertsDb) ->
- trusted_cert_and_path(DP, CRLtoValidate, Id, CertsDb)
- end,
- Ignore = ignore_sign_test_when_building_path(Test),
+ [_|_] ->
case public_key:pkix_crls_validate(OtpCert, CRLInfo,
- [{issuer_fun,{Fun, {Ignore, Certs}}}]) of
+ [{issuer_fun,{Fun, PathDb}}]) of
valid ->
{valid, UserState};
Reason ->
{fail, Reason}
end
- end,
+ end
+ end,
- Certs = read_certs(Test),
- ErlCerts = [public_key:pkix_decode_cert(Cert, otp) || Cert <- Certs],
+ [{verify_fun, {Fun, #verify_state{crls = CRLs,
+ crl_paths = Paths}}}].
- [{verify_fun, {Fun, #verify_state{certs_db = [TA| Certs],
- crl_info = {ErlCerts, CRLs}}}}]
- end.
+crl_path_db([], [], Acc) ->
+ Acc;
+crl_path_db([{_, CRL} |CRLs], [Path | Paths], Acc) ->
+ CertPath = lists:flatten(lists:map(fun([]) ->
+ [];
+ (CertFile) ->
+ ct:print("Certfile ~p", [CertFile]),
+ read_certs(CertFile)
+ end, Path)),
+ crl_path_db(CRLs, Paths, [{CRL, CertPath}| Acc]).
-crl_info(_, _, [], Acc) ->
+
+crl_info(_, [], Acc) ->
Acc;
-crl_info(OtpCert, Certs, [{_, #'CertificateList'{tbsCertList =
+crl_info(OtpCert, [{_, #'CertificateList'{tbsCertList =
#'TBSCertList'{issuer = Issuer,
crlExtensions = CRLExtensions}}}
= CRL | Rest], Acc) ->
@@ -910,22 +852,36 @@ crl_info(OtpCert, Certs, [{_, #'CertificateList'{tbsCertList =
ExtList = pubkey_cert:extensions_list(CRLExtensions),
DPs = case pubkey_cert:select_extension(?'id-ce-cRLDistributionPoints', Extensions) of
#'Extension'{extnValue = Value} ->
- lists:map(fun(Point) -> pubkey_cert_records:transform(Point, decode) end, Value);
- _ ->
- case same_issuer(OtpCert, Issuer) of
- true ->
- [make_dp(ExtList, asn1_NOVALUE, Issuer)];
- false ->
- [make_dp(ExtList, Issuer, ignore)]
- end
+ lists:foldl(fun(Point, Acc0) ->
+ Dp = pubkey_cert_records:transform(Point, decode),
+ IDP = pubkey_cert:select_extension(?'id-ce-issuingDistributionPoint',
+ Extensions),
+ case Dp#'DistributionPoint'.cRLIssuer of
+ asn1_NOVALUE ->
+ [Dp | Acc0];
+ DpCRLIssuer ->
+ CRLIssuer = dp_crlissuer_to_issuer(DpCRLIssuer),
+ CertIssuer = OtpTBSCert#'OTPTBSCertificate'.issuer,
+ case pubkey_cert:is_issuer(CRLIssuer, CertIssuer) of
+ true ->
+ [Dp | Acc0];
+ false when (IDP =/= undefined) ->
+ Acc0;
+ false ->
+ [Dp | Acc0]
+ end
+ end
+ end, [], Value);
+ _ ->
+ case same_issuer(OtpCert, Issuer) of
+ true ->
+ [make_dp(ExtList, asn1_NOVALUE, Issuer)];
+ false ->
+ [make_dp(ExtList, Issuer, ignore)]
+ end
end,
DPsCRLs = lists:map(fun(DP) -> {DP, CRL} end, DPs),
- crl_info(OtpCert, Certs, Rest, DPsCRLs ++ Acc).
-
-ignore_sign_test_when_building_path("Invalid Bad CRL Signature Test4") ->
- true;
-ignore_sign_test_when_building_path(_) ->
- false.
+ crl_info(OtpCert, Rest, DPsCRLs ++ Acc).
same_issuer(OTPCert, Issuer) ->
DecIssuer = pubkey_cert_records:transform(Issuer, decode),
@@ -957,200 +913,23 @@ mk_issuer_dp(Issuer, _) ->
update_crls(_, State) ->
State.
-trusted_cert_and_path(DP, CRL, Id, {Ignore, CertsList}) ->
- case crl_issuer(crl_issuer_name(DP), CRL, Id, CertsList, CertsList, Ignore) of
- {ok, IssuerCert, DerIssuerCert} ->
- Certs = [{public_key:pkix_decode_cert(Cert, otp), Cert} || Cert <- CertsList],
- CertChain = build_chain(Certs, Certs, IssuerCert, Ignore, [DerIssuerCert]),
- {ok, public_key:pkix_decode_cert(hd(CertChain), otp), CertChain};
- Other ->
- Other
- end.
-
-crl_issuer_name(#'DistributionPoint'{cRLIssuer = asn1_NOVALUE}) ->
- undefined;
-crl_issuer_name(#'DistributionPoint'{cRLIssuer = [{directoryName, Issuer}]}) ->
- pubkey_cert_records:transform(Issuer, decode).
+trusted_cert_and_path(_, #'CertificateList'{} = CRL, _, PathDb) ->
+ [TrustedDERCert] = read_certs(crl_root_cert()),
+ TrustedCert = public_key:pkix_decode_cert(TrustedDERCert, otp),
-build_chain([],_, _, _,Acc) ->
- Acc;
-
-build_chain([{First, DerFirst}|Certs], All, Cert, Ignore, Acc) ->
- case public_key:pkix_is_self_signed(Cert) andalso is_test_root(Cert) of
- true ->
- Acc;
- false ->
- case public_key:pkix_is_issuer(Cert, First)
- %%andalso check_extension_cert_signer(First)
- andalso is_signer(First, Cert, Ignore)
- of
- true ->
- build_chain(All, All, First, Ignore, [DerFirst | Acc]);
- false ->
- build_chain(Certs, All, Cert, Ignore, Acc)
- end
- end.
-
-is_signer(_,_, true) ->
- true;
-is_signer(Signer, #'OTPCertificate'{} = Cert,_) ->
- TBSCert = Signer#'OTPCertificate'.tbsCertificate,
- PublicKeyInfo = TBSCert#'OTPTBSCertificate'.subjectPublicKeyInfo,
- PublicKey = PublicKeyInfo#'OTPSubjectPublicKeyInfo'.subjectPublicKey,
- AlgInfo = PublicKeyInfo#'OTPSubjectPublicKeyInfo'.algorithm,
- PublicKeyParams = AlgInfo#'PublicKeyAlgorithm'.parameters,
- try pubkey_cert:validate_signature(Cert, public_key:pkix_encode('OTPCertificate',
- Cert, otp),
- PublicKey, PublicKeyParams, true, ?DEFAULT_VERIFYFUN) of
- true ->
- true
- catch
- _:_ ->
- false
- end;
-is_signer(Signer, #'CertificateList'{} = CRL, _) ->
- TBSCert = Signer#'OTPCertificate'.tbsCertificate,
- PublicKeyInfo = TBSCert#'OTPTBSCertificate'.subjectPublicKeyInfo,
- PublicKey = PublicKeyInfo#'OTPSubjectPublicKeyInfo'.subjectPublicKey,
- AlgInfo = PublicKeyInfo#'OTPSubjectPublicKeyInfo'.algorithm,
- PublicKeyParams = AlgInfo#'PublicKeyAlgorithm'.parameters,
- pubkey_crl:verify_crl_signature(CRL, public_key:pkix_encode('CertificateList',
- CRL, plain),
- PublicKey, PublicKeyParams).
-
-is_test_root(OtpCert) ->
- TBSCert = OtpCert#'OTPCertificate'.tbsCertificate,
- {rdnSequence, AtterList} = TBSCert#'OTPTBSCertificate'.issuer,
- lists:member([{'AttributeTypeAndValue',{2,5,4,3},{printableString,"Trust Anchor"}}],
- AtterList).
-
-check_extension_cert_signer(OtpCert) ->
- TBSCert = OtpCert#'OTPCertificate'.tbsCertificate,
- Extensions = TBSCert#'OTPTBSCertificate'.extensions,
- case pubkey_cert:select_extension(?'id-ce-keyUsage', Extensions) of
- #'Extension'{extnValue = KeyUse} ->
- lists:member(keyCertSign, KeyUse);
- _ ->
- true
- end.
-
-check_extension_crl_signer(OtpCert) ->
- TBSCert = OtpCert#'OTPCertificate'.tbsCertificate,
- Extensions = TBSCert#'OTPTBSCertificate'.extensions,
- case pubkey_cert:select_extension(?'id-ce-keyUsage', Extensions) of
- #'Extension'{extnValue = KeyUse} ->
- lists:member(cRLSign, KeyUse);
- _ ->
- true
+ case lists:keysearch(CRL, 1, PathDb) of
+ {_, {CRL, [ _| _] = Path}} ->
+ {ok, TrustedCert, [TrustedDERCert | Path]};
+ {_, {CRL, []}} ->
+ {ok, TrustedCert, [TrustedDERCert]}
end.
-crl_issuer(undefined, CRL, issuer_not_found, _, CertsList, Ignore) ->
- crl_issuer(CRL, CertsList, Ignore);
-
-crl_issuer(IssuerName, CRL, issuer_not_found, CertsList, CertsList, Ignore) ->
- crl_issuer(IssuerName, CRL, IssuerName, CertsList, CertsList, Ignore);
-
-crl_issuer(undefined, CRL, Id, [Cert | Rest], All, false) ->
- ErlCert = public_key:pkix_decode_cert(Cert, otp),
- TBSCertificate = ErlCert#'OTPCertificate'.tbsCertificate,
- SerialNumber = TBSCertificate#'OTPTBSCertificate'.serialNumber,
- Issuer = public_key:pkix_normalize_name(
- TBSCertificate#'OTPTBSCertificate'.subject),
- Bool = is_signer(ErlCert, CRL, false),
- case {SerialNumber, Issuer} of
- Id when Bool == true ->
- {ok, ErlCert, Cert};
- _ ->
- crl_issuer(undefined, CRL, Id, Rest, All, false)
- end;
-
-crl_issuer(IssuerName, CRL, Id, [Cert | Rest], All, false) ->
- ErlCert = public_key:pkix_decode_cert(Cert, otp),
- TBSCertificate = ErlCert#'OTPCertificate'.tbsCertificate,
- SerialNumber = TBSCertificate#'OTPTBSCertificate'.serialNumber,
- %%Issuer = public_key:pkix_normalize_name(
- %% TBSCertificate#'OTPTBSCertificate'.subject),
- Bool = is_signer(ErlCert, CRL, false),
- case {SerialNumber, IssuerName} of
- Id when Bool == true ->
- {ok, ErlCert, Cert};
- {_, IssuerName} when Bool == true ->
- {ok, ErlCert, Cert};
- _ ->
- crl_issuer(IssuerName, CRL, Id, Rest, All, false)
- end;
-
-crl_issuer(undefined, CRL, _, [], CertsList, Ignore) ->
- crl_issuer(CRL, CertsList, Ignore);
-crl_issuer(CRLName, CRL, _, [], CertsList, Ignore) ->
- crl_issuer(CRLName, CRL, CertsList, Ignore).
-
-
-crl_issuer(_, [],_) ->
- {error, issuer_not_found};
-crl_issuer(CRL, [Cert | Rest], Ignore) ->
- ErlCert = public_key:pkix_decode_cert(Cert, otp),
- case public_key:pkix_is_issuer(CRL, ErlCert) andalso
- check_extension_crl_signer(ErlCert) andalso
- is_signer(ErlCert, CRL, Ignore)
- of
- true ->
- {ok, ErlCert,Cert};
- false ->
- crl_issuer(CRL, Rest, Ignore)
- end.
-
-crl_issuer(_,_, [],_) ->
- {error, issuer_not_found};
-crl_issuer(IssuerName, CRL, [Cert | Rest], Ignore) ->
- ErlCert = public_key:pkix_decode_cert(Cert, otp),
- TBSCertificate = ErlCert#'OTPCertificate'.tbsCertificate,
- Issuer = public_key:pkix_normalize_name(
- TBSCertificate#'OTPTBSCertificate'.subject),
-
- case
- public_key:pkix_is_issuer(CRL, ErlCert) andalso
- check_extension_crl_signer(ErlCert) andalso
- is_signer(ErlCert, CRL, Ignore)
- of
- true ->
- case pubkey_cert:is_issuer(Issuer, IssuerName) of
- true ->
- {ok, ErlCert,Cert};
- false ->
- crl_issuer(IssuerName, CRL, Rest, Ignore)
- end;
- false ->
- crl_issuer(IssuerName, CRL, Rest, Ignore)
- end.
-
-read_certs(Test) ->
- File = test_file(Test),
- Ders = erl_make_certs:pem_to_der(File),
- [Cert || {'Certificate', Cert, not_encrypted} <- Ders].
-
-read_crls(Test) ->
- File = test_file(Test),
- Ders = erl_make_certs:pem_to_der(File),
- [CRL || {'CertificateList', CRL, not_encrypted} <- Ders].
-test_file(Test) ->
- io:format("TEST: ~p~n", [Test]),
- file(?CONV, lists:append(string:tokens(Test, " -")) ++ ".pem").
+dp_crlissuer_to_issuer(DPCRLIssuer) ->
+ [{directoryName, Issuer}] = pubkey_cert_records:transform(DPCRLIssuer, decode),
+ Issuer.
-file(Sub,File) ->
- TestDir = case get(datadir) of
- undefined -> "./pkits_SUITE_data";
- Dir when is_list(Dir) ->
- Dir
- end,
- AbsFile = filename:join([TestDir,Sub,File]),
- case filelib:is_file(AbsFile) of
- true -> ok;
- false ->
- ?error("Couldn't read data from ~p ~n",[AbsFile])
- end,
- AbsFile.
+%%%%%%%%%%%%%%% CA mappings %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cas(Chap) ->
CAS = intermidiate_cas(Chap),
@@ -1242,17 +1021,15 @@ intermidiate_cas(Chap) when Chap == "4.6.2" ->
intermidiate_cas(Chap) when Chap == "4.6.3" ->
["basicConstraints Not Critical cA False CA Cert"];
-intermidiate_cas(Chap) when Chap == "4.5.2";
- Chap == "4.5.5" ->
- ["Basic Self-Issued New Key CA Cert"];
-
-intermidiate_cas(Chap) when Chap == "4.5.1" ->
+intermidiate_cas(Chap) when Chap == "4.5.1";
+ Chap == "4.5.2" ->
["Basic Self-Issued New Key OldWithNew CA Cert", "Basic Self-Issued New Key CA Cert"];
intermidiate_cas(Chap) when Chap == "4.5.3" ->
["Basic Self-Issued Old Key NewWithOld CA Cert", "Basic Self-Issued Old Key CA Cert"];
-intermidiate_cas(Chap) when Chap == "4.5.4" ->
+intermidiate_cas(Chap) when Chap == "4.5.4";
+ Chap == "4.5.5" ->
["Basic Self-Issued Old Key CA Cert"];
intermidiate_cas(Chap) when Chap == "4.13.1";
@@ -1301,9 +1078,6 @@ intermidiate_cas(Chap) when Chap == "4.13.19" ->
["nameConstraints DN1 Self-Issued CA Cert",
"nameConstraints DN1 CA Cert"];
-intermidiate_cas(Chap) when Chap == "4.5.6" ->
- ["Basic Self-Issued CRL Signing Key CA Cert"];
-
intermidiate_cas(Chap) when Chap == "4.7.1";
Chap == "4.7.4" ->
["keyUsage Critical keyCertSign False CA Cert"];
@@ -1387,29 +1161,349 @@ intermidiate_cas(Chap) when Chap == "4.6.16" ->
"pathLenConstraint0 Self-Issued CA Cert",
"pathLenConstraint0 CA Cert"];
-intermidiate_cas(Chap) when Chap == "4.5.7";
- Chap == "4.5.8"
- ->
- ["Basic Self-Issued CRL Signing Key CRL Cert",
- "Basic Self-Issued CRL Signing Key CA Cert"].
+intermidiate_cas(Chap) when Chap == "4.4.1" ->
+ ["No CRL CA Cert"];
-error(Format, Args, File0, Line) ->
- File = filename:basename(File0),
- Pid = group_leader(),
- Pid ! {failed, File, Line},
- io:format(Pid, "~s(~p): ERROR"++Format, [File,Line|Args]).
+intermidiate_cas(Chap) when Chap == "4.4.2" ->
+ ["Revoked subCA Cert", "Good CA Cert"];
-warning(Format, Args, File0, Line) ->
- File = filename:basename(File0),
- io:format("~s(~p): Warning "++Format, [File,Line|Args]).
+intermidiate_cas(Chap) when Chap == "4.4.3" ->
+ ["Good CA Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.4.4" ->
+ ["Bad CRL Signature CA Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.4.5" ->
+ ["Bad CRL Issuer Name CA Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.4.6" ->
+ ["Wrong CRL CA Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.4.7" ->
+ ["Two CRLs CA Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.4.8" ->
+ ["Unknown CRL Entry Extension CA Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.4.9";
+ Chap == "4.4.10" ->
+ ["Unknown CRL Extension CA Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.4.11" ->
+ ["Old CRL nextUpdate CA Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.4.12" ->
+ ["pre2000 CRL nextUpdate CA Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.4.13" ->
+ ["GeneralizedTime CRL nextUpdate CA Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.4.14";
+ Chap == "4.4.15" ->
+ ["Negative Serial Number CA Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.4.16";
+ Chap == "4.4.17";
+ Chap == "4.4.18" ->
+ ["Long Serial Number CA Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.4.19";
+ Chap == "4.4.20" ->
+ ["Separate Certificate and CRL Keys Certificate Signing CA Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.4.21" ->
+ ["Separate Certificate and CRL Keys CA2 Certificate Signing CA Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.14.1";
+ Chap == "4.14.2";
+ Chap == "4.14.3";
+ Chap == "4.14.4" ->
+ ["distributionPoint1 CA Cert"];
+intermidiate_cas(Chap) when Chap == "4.14.5";
+ Chap == "4.14.6";
+ Chap == "4.14.7";
+ Chap == "4.14.8";
+ Chap == "4.14.9" ->
+ ["distributionPoint2 CA Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.14.10" ->
+ ["No issuingDistributionPoint CA Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.14.11" ->
+ ["onlyContainsUserCerts CA Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.14.12";
+ Chap == "4.14.13" ->
+ ["onlyContainsCACerts CA Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.14.14" ->
+ ["onlyContainsAttributeCerts CA Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.14.15";
+ Chap == "4.14.16" ->
+ ["onlySomeReasons CA1 Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.14.17" ->
+ ["onlySomeReasons CA2 Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.14.18" ->
+ ["onlySomeReasons CA3 Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.14.19";
+ Chap == "4.14.20";
+ Chap == "4.14.21" ->
+ ["onlySomeReasons CA4 Cert"];
+intermidiate_cas(Chap) when Chap == "4.14.22";
+ Chap == "4.14.23" ->
+ ["indirectCRL CA1 Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.14.24";
+ Chap == "4.14.25";
+ Chap == "4.14.26" ->
+ ["indirectCRL CA2 Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.14.27" ->
+ ["indirectCRL CA2 Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.14.28";
+ Chap == "4.14.29" ->
+ ["indirectCRL CA3 Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.14.31";
+ Chap == "4.14.32";
+ Chap == "4.14.33" ->
+ ["indirectCRL CA6 Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.14.34";
+ Chap == "4.14.35" ->
+ ["indirectCRL CA5 Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.15.1" ->
+ ["deltaCRLIndicator No Base CA Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.15.2";
+ Chap == "4.15.3";
+ Chap == "4.15.4";
+ Chap == "4.15.5";
+ Chap == "4.15.6";
+ Chap == "4.15.7" ->
+ ["deltaCRL CA1 Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.15.8";
+ Chap == "4.15.9" ->
+ ["deltaCRL CA2 Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.15.10" ->
+ ["deltaCRL CA3 Cert"];
+
+intermidiate_cas(Chap) when Chap == "4.5.6";
+ Chap == "4.5.7" ->
+ ["Basic Self-Issued CRL Signing Key CA Cert"];
+intermidiate_cas(Chap) when Chap == "4.5.8" ->
+ ["Basic Self-Issued CRL Signing Key CRL Cert"].
+
+
+%%%%%%%%%%%%%%% CRL mappings %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+crl_names("4.4.1") ->
+ ["Trust Anchor Root CRL"];
+crl_names("4.4.2") ->
+ ["Trust Anchor Root CRL", "Good CA CRL", "Revoked subCA CRL"];
+crl_names("4.4.3") ->
+ ["Trust Anchor Root CRL", "Good CA CRL", "Revoked subCA CRL"];
+crl_names("4.4.4") ->
+ ["Trust Anchor Root CRL", "Bad CRL Signature CA CRL"];
+crl_names("4.4.5") ->
+ ["Trust Anchor Root CRL", "Bad CRL Issuer Name CA CRL"];
+crl_names("4.4.6") ->
+ ["Trust Anchor Root CRL", "Wrong CRL CA CRL"];
+crl_names("4.4.7") ->
+ ["Trust Anchor Root CRL", "Two CRLs CA Good CRL", "Two CRLs CA Bad CRL"];
+crl_names("4.4.8") ->
+ ["Trust Anchor Root CRL", "Unknown CRL Entry Extension CA CRL"];
+crl_names(Chap) when Chap == "4.4.9";
+ Chap == "4.4.10"->
+ ["Trust Anchor Root CRL", "Unknown CRL Extension CA CRL"];
+crl_names("4.4.11") ->
+ ["Trust Anchor Root CRL", "Old CRL nextUpdate CA CRL"];
+crl_names("4.4.12") ->
+ ["Trust Anchor Root CRL", "pre2000 CRL nextUpdate CA CRL"];
+crl_names("4.4.13") ->
+ ["Trust Anchor Root CRL", "GeneralizedTime CRL nextUpdate CA CRL"];
+crl_names(Chap) when Chap == "4.4.14";
+ Chap == "4.4.15"->
+ ["Trust Anchor Root CRL", "Negative Serial Number CA CRL"];
+crl_names(Chap) when Chap == "4.4.16";
+ Chap == "4.4.17";
+ Chap == "4.4.18" ->
+ ["Trust Anchor Root CRL", "Long Serial Number CA CRL"];
+crl_names(Chap)when Chap == "4.4.19";
+ Chap == "4.4.20" ->
+ ["Trust Anchor Root CRL", "Separate Certificate and CRL Keys CRL"];
+crl_names("4.4.21") ->
+ ["Trust Anchor Root CRL", "Separate Certificate and CRL Keys CA2 CRL"];
+crl_names(Chap) when Chap == "4.5.1";
+ Chap == "4.5.2"->
+ ["Trust Anchor Root CRL", "Basic Self-Issued New Key CA CRL"];
+crl_names(Chap) when Chap == "4.5.3";
+ Chap == "4.5.4";
+ Chap == "4.5.5" ->
+ ["Trust Anchor Root CRL", "Basic Self-Issued Old Key Self-Issued Cert CRL",
+ "Basic Self-Issued Old Key CA CRL"];
+crl_names(Chap) when Chap == "4.5.6";
+ Chap == "4.5.7";
+ Chap == "4.5.8" ->
+ ["Trust Anchor Root CRL", "Basic Self-Issued CRL Signing Key CRL Cert CRL",
+ "Basic Self-Issued CRL Signing Key CA CRL"
+ ];
+crl_names("4.7.4") ->
+ ["Trust Anchor Root CRL", "keyUsage Critical cRLSign False CA CRL"];
+crl_names("4.7.5") ->
+ ["Trust Anchor Root CRL", "keyUsage Not Critical cRLSign False CA CRL"];
+crl_names(Chap) when Chap == "4.14.1";
+ Chap == "4.14.2";
+ Chap == "4.14.3";
+ Chap == "4.14.4" ->
+ ["Trust Anchor Root CRL", "distributionPoint1 CA CRL"];
+crl_names(Chap) when Chap == "4.14.5";
+ Chap == "4.14.6";
+ Chap == "4.14.7";
+ Chap == "4.14.8";
+ Chap == "4.14.9" ->
+ ["Trust Anchor Root CRL", "distributionPoint2 CA CRL"];
+crl_names("4.14.10") ->
+ ["Trust Anchor Root CRL", "No issuingDistributionPoint CA CRL"];
+crl_names("4.14.11") ->
+ ["Trust Anchor Root CRL", "onlyContainsUserCerts CA CRL"];
+crl_names(Chap) when Chap == "4.14.12";
+ Chap == "4.14.13" ->
+ ["Trust Anchor Root CRL", "onlyContainsCACerts CA CRL"];
+crl_names("4.14.14") ->
+ ["Trust Anchor Root CRL", "onlyContainsAttributeCerts CA CRL"];
+crl_names(Chap) when Chap == "4.14.15";
+ Chap == "4.14.16" ->
+ ["Trust Anchor Root CRL", "onlySomeReasons CA1 compromise CRL",
+ "onlySomeReasons CA1 other reasons CRL"];
+crl_names("4.14.17") ->
+ ["Trust Anchor Root CRL",
+ "onlySomeReasons CA2 CRL1", "onlySomeReasons CA2 CRL2"];
+crl_names("4.14.18") ->
+ ["Trust Anchor Root CRL",
+ "onlySomeReasons CA3 compromise CRL", "onlySomeReasons CA3 other reasons CRL"];
+crl_names(Chap) when Chap == "4.14.19";
+ Chap == "4.14.20";
+ Chap == "4.14.21" ->
+ ["Trust Anchor Root CRL", "onlySomeReasons CA4 compromise CRL",
+ "onlySomeReasons CA4 other reasons CRL"];
+crl_names(Chap) when Chap == "4.14.22";
+ Chap == "4.14.23";
+ Chap == "4.14.24";
+ Chap == "4.14.25";
+ Chap == "4.14.26" ->
+ ["Trust Anchor Root CRL", "indirectCRL CA1 CRL"];
+crl_names("4.14.27") ->
+ ["Trust Anchor Root CRL", "Good CA CRL"];
+
+crl_names(Chap) when Chap == "4.14.28";
+ Chap == "4.14.29" ->
+ ["Trust Anchor Root CRL", "indirectCRL CA3 CRL", "indirectCRL CA3 cRLIssuer CRL"];
+crl_names("4.14.30") ->
+ ["Trust Anchor Root CRL", "indirectCRL CA4 cRLIssuer CRL"];
+crl_names(Chap) when Chap == "4.14.31";
+ Chap == "4.14.32";
+ Chap == "4.14.33";
+ Chap == "4.14.34";
+ Chap == "4.14.35" ->
+ ["Trust Anchor Root CRL", "indirectCRL CA5 CRL"];
+crl_names("4.15.1") ->
+ ["Trust Anchor Root CRL", "deltaCRLIndicator No Base CA CRL"];
+crl_names(Chap) when Chap == "4.15.2";
+ Chap == "4.15.3";
+ Chap == "4.15.4";
+ Chap == "4.15.5";
+ Chap == "4.15.6";
+ Chap == "4.15.7" ->
+ ["Trust Anchor Root CRL", "deltaCRL CA1 CRL", "deltaCRL CA1 deltaCRL"];
+crl_names(Chap) when Chap == "4.15.8";
+ Chap == "4.15.9" ->
+ ["Trust Anchor Root CRL", "deltaCRL CA2 CRL", "deltaCRL CA2 deltaCRL"];
+crl_names("4.15.10") ->
+ ["Trust Anchor Root CRL", "deltaCRL CA3 CRL", "deltaCRL CA3 deltaCRL"].
+
+crl_root_cert() ->
+ "Trust Anchor Root Certificate".
+
+crl_path("Trust Anchor Root CRL") ->
+ []; %% Signed directly by crl_root_cert
+crl_path("Revoked subCA CRL") ->
+ ["Good CA Cert", "Revoked subCA Cert"];
+crl_path("indirectCRL CA3 cRLIssuer CRL") ->
+ ["indirectCRL CA3 Cert", "indirectCRL CA3 cRLIssuer Cert"];
+crl_path("Two CRLs CA Good CRL") ->
+ ["Two CRLs CA Cert"];
+crl_path("Two CRLs CA Bad CRL") ->
+ ["Two CRLs CA Cert"];
+crl_path("Separate Certificate and CRL Keys CRL") ->
+ ["Separate Certificate and CRL Keys CRL Signing Cert"];
+crl_path("Separate Certificate and CRL Keys CA2 CRL") ->
+ ["Separate Certificate and CRL Keys CA2 CRL Signing Cert"];
+crl_path("Basic Self-Issued Old Key Self-Issued Cert CRL") ->
+ ["Basic Self-Issued Old Key CA Cert"];
+crl_path("Basic Self-Issued Old Key CA CRL") ->
+ ["Basic Self-Issued Old Key CA Cert", "Basic Self-Issued Old Key NewWithOld CA Cert"];
+
+crl_path("Basic Self-Issued CRL Signing Key CRL Cert CRL") ->
+ ["Basic Self-Issued CRL Signing Key CA Cert"];
+crl_path("Basic Self-Issued CRL Signing Key CA CRL") ->
+ ["Basic Self-Issued CRL Signing Key CA Cert", "Basic Self-Issued CRL Signing Key CRL Cert"];
+
+crl_path("onlySomeReasons CA1 compromise CRL") ->
+ ["onlySomeReasons CA1 Cert"];
+crl_path("onlySomeReasons CA1 other reasons CRL") ->
+ ["onlySomeReasons CA1 Cert"];
+crl_path("onlySomeReasons CA3 other reasons CRL") ->
+ ["onlySomeReasons CA3 Cert"];
+crl_path("onlySomeReasons CA3 compromise CRL") ->
+ ["onlySomeReasons CA3 Cert"];
+crl_path("onlySomeReasons CA4 compromise CRL") ->
+ ["onlySomeReasons CA4 Cert"];
+crl_path("onlySomeReasons CA4 other reasons CRL") ->
+ ["onlySomeReasons CA4 Cert"];
+crl_path("Basic Self-Issued New Key CA CRL") ->
+ ["Basic Self-Issued New Key CA Cert"];
+crl_path("deltaCRL CA1 deltaCRL") ->
+ crl_path("deltaCRL CA2 CRL");
+crl_path("deltaCRL CA2 deltaCRL") ->
+ crl_path("deltaCRL CA2 CRL");
+crl_path("deltaCRL CA3 deltaCRL") ->
+ crl_path("deltaCRL CA3 CRL");
+crl_path(CRL) when CRL == "onlySomeReasons CA2 CRL1";
+ CRL == "onlySomeReasons CA2 CRL2" ->
+ ["onlySomeReasons CA2 Cert"];
+
+crl_path(CRL) ->
+ L = length(CRL),
+ Base = string:sub_string(CRL, 1, L -3),
+ [Base ++ "Cert"].
+
+crls(CRLS) ->
+ lists:foldl(fun([], Acc) ->
+ Acc;
+ (CRLFile, Acc) ->
+ [CRL] = read_crls(CRLFile),
+ [CRL | Acc]
+ end, [], CRLS).
+
+
+%% TODO: If we implement policy support
%% Certificate policy tests need special handling. They can have several
%% sub tests and we need to check the outputs are correct.
-certificate_policies() ->
+certificate_policies_tests() ->
%%{ "4.8", "Certificate Policies" },
[{"4.8.1.1", "All Certificates Same Policy Test1", "-policy anyPolicy -explicit_policy", "True", ?NIST1, ?NIST1, 0},
- {"4.8.1.2", "All Certificates Same Policy Test1", "-policy ?NIST1 -explicit_policy", "True", ?NIST1, ?NIST1, 0},
+ {"4.8.1.2", "All Certificates Same Policy Test1", "-policy ?NIST1BasicSelfIssuedCRLSigningKeyCACert.pem -explicit_policy", "True", ?NIST1, ?NIST1, 0},
{"4.8.1.3", "All Certificates Same Policy Test1", "-policy ?NIST2 -explicit_policy", "True", ?NIST1, "<empty>", 43},
{"4.8.1.4", "All Certificates Same Policy Test1", "-policy ?NIST1 -policy ?NIST2 -explicit_policy", "True", ?NIST1, ?NIST1, 0},
{"4.8.2.1", "All Certificates No Policies Test2", "-policy anyPolicy", "False", "<empty>", "<empty>", 0},
@@ -1443,7 +1537,7 @@ certificate_policies() ->
{"4.8.18.2", "User Notice Qualifier Test18", "-policy ?NIST2", "True", "?NIST1:?NIST2", "?NIST2", 0},
{"4.8.19", "User Notice Qualifier Test19", "-policy anyPolicy", "False", "?NIST1", "?NIST1", 0},
{"4.8.20", "CPS Pointer Qualifier Test20", "-policy anyPolicy -explicit_policy", "True", "?NIST1", "?NIST1", 0}].
-require_explicit_policy() ->
+require_explicit_policy_tests() ->
%%{ "4.9", "Require Explicit Policy" },
[{"4.9.1", "Valid RequireExplicitPolicy Test1", "-policy anyPolicy", "False", "<empty>", "<empty>", 0},
{"4.9.2", "Valid RequireExplicitPolicy Test2", "-policy anyPolicy", "False", "<empty>", "<empty>", 0},
@@ -1453,7 +1547,7 @@ require_explicit_policy() ->
{"4.9.6", "Valid Self-Issued requireExplicitPolicy Test6", "-policy anyPolicy", "False", "<empty>", "<empty>", 0},
{"4.9.7", "Invalid Self-Issued requireExplicitPolicy Test7", "-policy anyPolicy", "True", "<empty>", "<empty>", 43},
{"4.9.8", "Invalid Self-Issued requireExplicitPolicy Test8", "-policy anyPolicy", "True", "<empty>", "<empty>", 43}].
-policy_mappings() ->
+policy_mappings_tests() ->
%%{ "4.10", "Policy Mappings" },
[{"4.10.1.1", "Valid Policy Mapping Test1", "-policy ?NIST1", "True", "?NIST1", "?NIST1", 0},
{"4.10.1.2", "Valid Policy Mapping Test1", "-policy ?NIST2", "True", "?NIST1", "<empty>", 43},
@@ -1483,7 +1577,7 @@ policy_mappings() ->
%% TODO: check notice display
{"4.10.14", "Valid Policy Mapping Test14", "-policy anyPolicy", "True", "?NIST1", "?NIST1", 0}].
-inhibit_policy_mapping() ->
+inhibit_policy_mapping_tests() ->
%%{ "4.11", "Inhibit Policy Mapping" },
[{"4.11.1", "Invalid inhibitPolicyMapping Test1", "-policy anyPolicy", "True", "<empty>", "<empty>", 43},
{"4.11.2", "Valid inhibitPolicyMapping Test2", "-policy anyPolicy", "True", "?NIST1", "?NIST1", 0},
@@ -1496,7 +1590,7 @@ inhibit_policy_mapping() ->
{"4.11.9", "Invalid Self-Issued inhibitPolicyMapping Test9", "-policy anyPolicy", "True", "<empty>", "<empty>", 43},
{"4.11.10", "Invalid Self-Issued inhibitPolicyMapping Test10", "-policy anyPolicy", "True", "<empty>", "<empty>", 43},
{"4.11.11", "Invalid Self-Issued inhibitPolicyMapping Test11", "-policy anyPolicy", "True", "<empty>", "<empty>", 43}].
-inhibit_any_policy() ->
+inhibit_any_policy_tests() ->
%%{ "4.12", "Inhibit Any Policy" },
[{"4.12.1", "Invalid inhibitAnyPolicy Test1", "-policy anyPolicy", "True", "<empty>", "<empty>", 43},
{"4.12.2", "Valid inhibitAnyPolicy Test2", "-policy anyPolicy", "True", "?NIST1", "?NIST1", 0},
@@ -1509,12 +1603,3 @@ inhibit_any_policy() ->
{"4.12.8", "Invalid Self-Issued inhibitAnyPolicy Test8", 43 },
{"4.12.9", "Valid Self-Issued inhibitAnyPolicy Test9", ok},
{"4.12.10", "Invalid Self-Issued inhibitAnyPolicy Test10", 43 }].
-
-crypto_support_check(Config) ->
- try crypto:sha256(<<"Test">>) of
- _ ->
- Config
- catch error:notsup ->
- crypto:stop(),
- {skip, "To old version of openssl"}
- end.
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/BadCRLIssuerNameCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/BadCRLIssuerNameCACRL.pem
new file mode 100644
index 0000000000..a4cf643928
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/BadCRLIssuerNameCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzDCBtQIBATANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEiMCAGA1UEAxMZSW5jb3JyZWN0IENS
+TCBJc3N1ZXIgTmFtZRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAvMC0w
+HwYDVR0jBBgwFoAUEXLyNV0E1Q5KIAcHQSj9lHAAHHEwCgYDVR0UBAMCAQEwDQYJ
+KoZIhvcNAQELBQADggEBAIIk/+6+dqID/yKmKYDaVgXh/yLWZO4uV1m6OYRSrdfa
+8aqYcgwChIaIIX465VDCpGO2LMOXV1Z/COerJguUNRGaiSQCSrsIpNGGZTQE+HNN
+C5mabMfPuSVaBgBMzQZTY3ggLNr6x1G7dXlm+Fpo+q/fSznBVsGFHCgtp53FJHBi
+Xcd3LTBFyZLiyhITqm2xvTwyzl/URcDYBp+tWTmn7ZxADdoThK7OkY2U13O0vxKj
+/haiS1NuVbX2QkS+eH399jGQHAHiBOFlRPs8FGdshTWOJxmLMMTIuS7cIEH3Oz8t
+b1Go7j4qHIYr/b2uKHb9RBMFNRKsZfqVKEQ+1J8TPNc=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/BadCRLSignatureCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/BadCRLSignatureCACRL.pem
new file mode 100644
index 0000000000..e17fac1f20
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/BadCRLSignatureCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBxzCBsAIBATANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEdMBsGA1UEAxMUQmFkIENSTCBTaWdu
+YXR1cmUgQ0EXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqgLzAtMB8GA1Ud
+IwQYMBaAFDGLNY2eRGEwFN7nCy4UGUgk2/m9MAoGA1UdFAQDAgEBMA0GCSqGSIb3
+DQEBCwUAA4IBAQFsPfAbIcqMI+lzJmY396TIwn2ubAkQgm95U712CIuw00auDjGM
+iebAOLbNLgSktivN23rc5rPxSOqeWsNfgVxwCPKvBv7v4PsLQhzK2OyonV5Cmdl1
+biEymv88bEUcEnibvH3O0Lg3RySMNjPYqZgPfwF9b0iTYeb2JYk+lX+m3WGr5UPg
+M9nuC6sychRxGgF1AQOd/N6spvgSAazEyNqCWhcwdrOeM+HEDPAFOOFAhmCp+jjh
+Fgh2E2Gq1vbxGSzzKlRBDrO1hovT9XhvEa2SjopbWMbfOR/wPTjxEImIQDWw69RL
+KnTL/OdnUXifoSNJIJK3ffPTSG5AEHFUm6j+
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/BadSignedCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/BadSignedCACRL.pem
new file mode 100644
index 0000000000..58c89f81c6
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/BadSignedCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBwDCBqQIBATANBgkqhkiG9w0BAQsFADBGMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEWMBQGA1UEAxMNQmFkIFNpZ25lZCBD
+QRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAvMC0wHwYDVR0jBBgwFoAU
+e90QO0rgyN1EhU6IPFqLzZkik68wCgYDVR0UBAMCAQEwDQYJKoZIhvcNAQELBQAD
+ggEBAEBt9Jji+aprAMfoXE8zclIPjs520FFAXSPqsJt77l8vTA50oUbD0sILCDfA
+raU16Pm3lIT3wuEAUmM7luTzG5Kg5qbgyv9cLm3rSJOADZCw6oahFAEbZyqOsgfP
+QYRy9EOeg8TUc6EPrlZhTrZzf2kgmDeL6WxTz2Len415oFf6JsDNMLcHSQkDzmdi
+OxYXDA2w5khPrzX0cxbMpmZVJiQksdKJg/RGGCqNJVcZwTqAZFNzSldJvx7fqQPI
+SkcKznfT/cczC37Q2uCupIyG4cntiRdIztkHiKQFRkiUxIMQA3ky3t+ib3lZDnl2
+VwGLcmmYuu4ScsqL+OP0ZjpzZKM=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/BadnotAfterDateCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/BadnotAfterDateCACRL.pem
new file mode 100644
index 0000000000..3c952437ce
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/BadnotAfterDateCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBxzCBsAIBATANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEdMBsGA1UEAxMUQmFkIG5vdEFmdGVy
+IERhdGUgQ0EXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqgLzAtMB8GA1Ud
+IwQYMBaAFCwO/ffuPPOkZuznBZ+Is+LPdEbYMAoGA1UdFAQDAgEBMA0GCSqGSIb3
+DQEBCwUAA4IBAQBcYZ4ucABlH6Z0XtJMAmcrX6txzEawWpikzfzapuRe0YBL6IHm
+LRqW+vpBfR5vSQ2PBLXFJA9eVpJjjBieF9USt58DsvTF1nuPMJCk1WhxfDrE/hWy
+vR3tnLW38c6e4+omJN9fotQilw+sq32j1yQjnR4KU+VxMs6sgs1W2XmmWpTP+fQw
+W9ukAXGzwQNmBb4mbOjLDVv3fXxzVI5gK8bhcxh83cfmHMkI+dp1g4nAxQ5gRTaw
+2ypGWph9170Z1Y/W6eznbNGA40YreXqqZeq8ujpjYlksC6tpQkOp8lBJGwi7fKaI
+IxV4vXSSbExz7A4CFQ1zYx1ciciCGWcyOyqx
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/BadnotBeforeDateCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/BadnotBeforeDateCACRL.pem
new file mode 100644
index 0000000000..fb4bf11a7c
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/BadnotBeforeDateCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIByDCBsQIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEeMBwGA1UEAxMVQmFkIG5vdEJlZm9y
+ZSBEYXRlIENBFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoC8wLTAfBgNV
+HSMEGDAWgBRjPrwanvuh8lmhL0uV/ubeVriGQDAKBgNVHRQEAwIBATANBgkqhkiG
+9w0BAQsFAAOCAQEAnN6H352YCy4U82Ndz+iFkIxTLVmwiMi00RViqbziNXLSYbbX
+MpJsCPn93wGhEOokDcJBoWq6/2QeHHmEs9rN758+loP1P1R27wgicrcPIEbT0+BT
+st0TYtZExQoXWVe5QtyTa4cNR7Wz88ga1xf3GyngnjFAHmAWrU4IOpxhKvs2FOS1
+zPaxzdgvNZyxvltIUt6zujlAxDf3wJK9qWyZSt7ORob8RVaAJR12UA60qyVbA2HX
+BdAavTzVJatY2AjtnIiFWAmtI3s/jIvLLNX5yUVVDSEDCI3zWY5YR/URyf4uViEk
+qyy8PQ83mVkpTjaWRxjFrcIvwlUvmRlHTvp2NQ==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/BasicSelfIssuedCRLSigningKeyCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/BasicSelfIssuedCRLSigningKeyCACRL.pem
new file mode 100644
index 0000000000..9a34f8a612
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/BasicSelfIssuedCRLSigningKeyCACRL.pem
@@ -0,0 +1,13 @@
+-----BEGIN X509 CRL-----
+MIIB+zCB5AIBATANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEtMCsGA1UEAxMkQmFzaWMgU2VsZi1J
+c3N1ZWQgQ1JMIFNpZ25pbmcgS2V5IENBFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEw
+ODMwMDBaMCIwIAIBAxcNMTAwMTAxMDgzMDAwWjAMMAoGA1UdFQQDCgEBoC8wLTAf
+BgNVHSMEGDAWgBQkwVVx+p7hIYUq8K1hpxW51U1DFzAKBgNVHRQEAwIBATANBgkq
+hkiG9w0BAQsFAAOCAQEAE4g/85gXzIM9TYVxAXxgc8KwavltVn6wFCluy5zwxGRz
+lpJXjJWctmJ+Z1qPVlL/K8aOW+YW+keL5zcINUYHxipyQLt+W7qeFDivq5ABgK62
+qpZ6tpwTa02IXkUDixs2QVXM7vXLrHlYacLGjIti+LUP3R7y3fLSjg3BMZcvwA17
+0N1YhfYZrNVwfwqv2H58HIdo5+SSCcUGZe9sbkqRINta3/OKnlS5e7Y4KW5I65oT
+2eX4iPmPNR6NqNv6D+mMXxt6uJGw8NRA2NqO8MS8UqkA6bmZldcdkefcJ5ETJu8r
+xewaq22gblqFL2vdcM/JJ61rcuPVZTqChfDyaQu/rg==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/BasicSelfIssuedCRLSigningKeyCRLCertCRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/BasicSelfIssuedCRLSigningKeyCRLCertCRL.pem
new file mode 100644
index 0000000000..447b7ec511
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/BasicSelfIssuedCRLSigningKeyCRLCertCRL.pem
@@ -0,0 +1,15 @@
+-----BEGIN X509 CRL-----
+MIICZjCCAU4CAQEwDQYJKoZIhvcNAQELBQAwXTELMAkGA1UEBhMCVVMxHzAdBgNV
+BAoTFlRlc3QgQ2VydGlmaWNhdGVzIDIwMTExLTArBgNVBAMTJEJhc2ljIFNlbGYt
+SXNzdWVkIENSTCBTaWduaW5nIEtleSBDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMx
+MDgzMDAwWqCBvDCBuTAfBgNVHSMEGDAWgBQpmkUuNpWd7PJeVJwT1dn2RJEsEzCB
+iQYDVR0cAQH/BH8wfaB7oHmkdzB1MQswCQYDVQQGEwJVUzEfMB0GA1UEChMWVGVz
+dCBDZXJ0aWZpY2F0ZXMgMjAxMTFFMEMGA1UEAxM8U2VsZi1Jc3N1ZWQgQ2VydCBE
+UCBmb3IgQmFzaWMgU2VsZi1Jc3N1ZWQgQ1JMIFNpZ25pbmcgS2V5IENBMAoGA1Ud
+FAQDAgEBMA0GCSqGSIb3DQEBCwUAA4IBAQAnpcVORfH/FTHsCl1sjvHIvPQTdrMI
+73pWCshHQB8/eCwDmTg+xFk7n4KCYSRgbN6ingc4wzbnLkb1WPmw80aXbqd4Tg+/
+U9T0ANxSewLBeW0zUFFcW5LjqrxCJVV4IMDXh+D6F+M8uEWE8/UGzpz3qkIBfW/a
+KHQszpVl7i9x0MhjHFAXkJbCuB7ymXntYfbSQNHvMWwbPW+nt0HadbJqjJy4FH4V
+kaSg/tkFa1StClKjm3T+GDhISPpDWthGUmS4n9cmj4QnPSd6E57d+ix0hb5oqQAg
+DYeL9/xaN7fOIzuGknzE3+p19OT8vNhvp7mRoMpZpzPtm0so48EXagMx
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/BasicSelfIssuedNewKeyCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/BasicSelfIssuedNewKeyCACRL.pem
new file mode 100644
index 0000000000..9c3d7d42ab
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/BasicSelfIssuedNewKeyCACRL.pem
@@ -0,0 +1,13 @@
+-----BEGIN X509 CRL-----
+MIIB8zCB3AIBATANBgkqhkiG9w0BAQsFADBVMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTElMCMGA1UEAxMcQmFzaWMgU2VsZi1J
+c3N1ZWQgTmV3IEtleSBDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWjAi
+MCACAQMXDTEwMDEwMTA4MzAwMFowDDAKBgNVHRUEAwoBAaAvMC0wHwYDVR0jBBgw
+FoAUoPzALOtV7pIGbKke6V9fop9iI5UwCgYDVR0UBAMCAQEwDQYJKoZIhvcNAQEL
+BQADggEBAHAue0P1w9Vgt/mvhideeiLl2unmfJC0JKCIBeeWXl0CYW5jcSrshCwZ
+dHRM5uhs8RQCNRnJIrhwuRUvh9SaDsZGFWqAlOdYbkaXdzbX1cyTigQ0tCNTN+aD
+FxGTm+CWxi6awN2a2ZcOzZ3KuB8D7q0b1mVtnMFsvV7JEMyxZRWFm5/8yJAliOKc
+8wrWtDfbpkU6c1P0l2bPzvmDirISAKwj2IwibkbQimbISwt1b/jijPOQgiArom5S
+sHzZh2DI9xdDBXLImkJveUGF1d8zIngbvyn19Iz7bT8mJVANx2K0U6kC3ODgov8b
+ARv87w9CDE+nCZz505ZS1f/pVtswcPg=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/BasicSelfIssuedOldKeyCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/BasicSelfIssuedOldKeyCACRL.pem
new file mode 100644
index 0000000000..3f330c715a
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/BasicSelfIssuedOldKeyCACRL.pem
@@ -0,0 +1,13 @@
+-----BEGIN X509 CRL-----
+MIIB8zCB3AIBATANBgkqhkiG9w0BAQsFADBVMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTElMCMGA1UEAxMcQmFzaWMgU2VsZi1J
+c3N1ZWQgT2xkIEtleSBDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWjAi
+MCACAQQXDTEwMDEwMTA4MzAwMFowDDAKBgNVHRUEAwoBAaAvMC0wHwYDVR0jBBgw
+FoAUiF++PzU5ZprrTcImGyaxKie1CCowCgYDVR0UBAMCAQEwDQYJKoZIhvcNAQEL
+BQADggEBALJPjOBcvrNJea5bTdcDaUR+3rWdWzwAFlIFN29RBQgnnwGyoPnMhBaI
+MBMMxrzPQiqc908w+4E82FSbeVKbutPPjs4izG8wE3jwPk5GmWPKozrZZ3Eliqd1
+9Kx1he6yCDnPpHZ6D4qm6qyy/xmspL7X3W40Dz56ldxu3DECDIrDACjdnu9PERDu
+acqDQPFKbcaZeCY9QX9/vsG+vrWH+HxEkzA/S9tyojYSLfVLvYubBd0OAWhTqqR6
+5h2Gx6z7DH6/1vtctb0HGg2VY7bVjpL0YhwXoTjZZXbWlLH1l7N+fP2cH5eqDwwF
+DRhIRhasjSucbUzOFXoc3dmBrOKwtjM=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/BasicSelfIssuedOldKeySelfIssuedCertCRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/BasicSelfIssuedOldKeySelfIssuedCertCRL.pem
new file mode 100644
index 0000000000..8fa388cd45
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/BasicSelfIssuedOldKeySelfIssuedCertCRL.pem
@@ -0,0 +1,15 @@
+-----BEGIN X509 CRL-----
+MIICVjCCAT4CAQEwDQYJKoZIhvcNAQELBQAwVTELMAkGA1UEBhMCVVMxHzAdBgNV
+BAoTFlRlc3QgQ2VydGlmaWNhdGVzIDIwMTExJTAjBgNVBAMTHEJhc2ljIFNlbGYt
+SXNzdWVkIE9sZCBLZXkgQ0EXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqg
+gbQwgbEwHwYDVR0jBBgwFoAU3Q11jVNoEsTLFUDAFIYUFjChvq8wgYEGA1UdHAEB
+/wR3MHWgc6BxpG8wbTELMAkGA1UEBhMCVVMxHzAdBgNVBAoTFlRlc3QgQ2VydGlm
+aWNhdGVzIDIwMTExPTA7BgNVBAMTNFNlbGYtSXNzdWVkIENlcnQgRFAgZm9yIEJh
+c2ljIFNlbGYtSXNzdWVkIE9sZCBLZXkgQ0EwCgYDVR0UBAMCAQEwDQYJKoZIhvcN
+AQELBQADggEBAMCggIi2OzR9WO+bNMEVT0PdVnX9lNyjIAmJZj6g/SECKy85ZQp/
+Xs5YY43xxXswtJ+70cQGunzXIXd22a5xTlGlcM0orE2WIbDaoJskD3D5HKPCb6MR
+C0XwhV6KGmB+H/rb77EnHEHTHQ6SwKfSaVSVrVkaGD4HYHAKiOqOzkInultUR04p
+jTJ3watfZyB+L9Xmfj+Bz/GvTCDdYOQfs9uXhWH+C7HQPe8uXD1C1tSDD9+XnUHo
+rScJkZkZpExsGvF8ngtjp+0SUmCTM7VejHtKWD2l4KO+TkjEM9PG0+Hf75iOq9eO
+UdA7iu/ozw7EbowpmABJmeVSiWD9S4/deBc=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/DSACACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/DSACACRL.pem
new file mode 100644
index 0000000000..7d1d13a767
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/DSACACRL.pem
@@ -0,0 +1,7 @@
+-----BEGIN X509 CRL-----
+MIHeMIGeAgEBMAkGByqGSM44BAMwPzELMAkGA1UEBhMCVVMxHzAdBgNVBAoTFlRl
+c3QgQ2VydGlmaWNhdGVzIDIwMTExDzANBgNVBAMTBkRTQSBDQRcNMTAwMTAxMDgz
+MDAwWhcNMzAxMjMxMDgzMDAwWqAvMC0wHwYDVR0jBBgwFoAUj5DGjHToewzIWcd9
+PFtUWWAlC7EwCgYDVR0UBAMCAQEwCQYHKoZIzjgEAwMwADAtAhQCMhWXnJJuf+2W
+pXCHP72o0SdqdAIVAMsLFa667x5ODKAkIlFPI/Ge57Hj
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/DSAParametersInheritedCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/DSAParametersInheritedCACRL.pem
new file mode 100644
index 0000000000..545293a0db
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/DSAParametersInheritedCACRL.pem
@@ -0,0 +1,8 @@
+-----BEGIN X509 CRL-----
+MIHyMIGzAgEBMAkGByqGSM44BAMwVDELMAkGA1UEBhMCVVMxHzAdBgNVBAoTFlRl
+c3QgQ2VydGlmaWNhdGVzIDIwMTExJDAiBgNVBAMTG0RTQSBQYXJhbWV0ZXJzIElu
+aGVyaXRlZCBDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAvMC0wHwYD
+VR0jBBgwFoAUZYGfcDqMrfZDHcjnj1WO6Evbh+IwCgYDVR0UBAMCAQEwCQYHKoZI
+zjgEAwMvADAsAhQ80F0tKnVM5ABE7rErqs6hgIc8gAIULN+1q3I9zEFZqSneZHjR
+yXC3FZQ=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/GeneralizedTimeCRLnextUpdateCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/GeneralizedTimeCRLnextUpdateCACRL.pem
new file mode 100644
index 0000000000..cab3080a90
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/GeneralizedTimeCRLnextUpdateCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB1DCBvQIBATANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEoMCYGA1UEAxMfR2VuZXJpemVkVGlt
+ZSBDUkwgbmV4dFVwZGF0ZSBDQRcNMTAwMTAxMDgzMDAwWhgPMjA1MDAxMDExMjAx
+MDBaoC8wLTAfBgNVHSMEGDAWgBR+KnXvDDbHS+cg2X9hSEeOEoMaLDAKBgNVHRQE
+AwIBATANBgkqhkiG9w0BAQsFAAOCAQEAkJf/F0AFe6ViIe9vaZwlRWs2cge1PnzK
+viLSchMF7AdYTAPq0hfWo34GTEw1e0k3KTIJlnj+fD3wpnhTA3qt3YzyS+wvdSZL
+e2Ogr4CvWKWbHi+5klCk5cJBkT5+SRZQErgATVyQYkcSYHYR8iPZ3izeSuoCPq8z
+KSBdZqgRqdJuPftmcbi4XI30zAJCDmMxuC++D3uTc8NHA6DrtAf4p2Iv0f33jtYo
+CsFBEVKpYd/0At1yxRDJ1MvKsiHZM3Pb2Ygoi5koy2gaNE34l128etEN6U0cZ7iy
+A5OYdxjNKkR1Xvk33eje3ixCOvsidtMSb7446sL6w2zQHQDJITAzcg==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/GoodCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/GoodCACRL.pem
new file mode 100644
index 0000000000..f482eae237
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/GoodCACRL.pem
@@ -0,0 +1,13 @@
+-----BEGIN X509 CRL-----
+MIICADCB6QIBATANBgkqhkiG9w0BAQsFADBAMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEQMA4GA1UEAxMHR29vZCBDQRcNMTAw
+MTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWjBEMCACAQ4XDTEwMDEwMTA4MzAwMFow
+DDAKBgNVHRUEAwoBATAgAgEPFw0xMDAxMDEwODMwMDFaMAwwCgYDVR0VBAMKAQGg
+LzAtMB8GA1UdIwQYMBaAFFgBhCQbvCtSlEo9pRByFFH1rzrJMAoGA1UdFAQDAgEB
+MA0GCSqGSIb3DQEBCwUAA4IBAQA9vPMLiinD8G7FaoTsu8T2jUrTi1OLPHxKnrlB
+rAP/eHa+VQV1HJfY5Gjq1dpNgzZqDIgQM5QHPm0aSgMN7Ultx+XzbxRswLnwgQrZ
+7f76Tlky1I+jz7/p3AEynrNR72v64SZt46UhpSuWBHoF1uEVtgirTZNfOEaGUJTN
+OaTA5U55/iw9BKjHN0e/Vd7OGnrk5h6FsgWOiasGn6/tym9teDt/L2hlOdsZsvX1
+KPc0ExUHVjJIUBYTooqyy/CuTzFHla6RYVYvJuRF5qYCxa0GTZK3ImCtJ3XfsGdf
+LEJDZ7T17xBQHucMvIVLm6vY44WUy7PqQhZJskhJMEvj01ZE
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/GoodsubCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/GoodsubCACRL.pem
new file mode 100644
index 0000000000..04790063da
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/GoodsubCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBvTCBpgIBATANBgkqhkiG9w0BAQsFADBDMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTETMBEGA1UEAxMKR29vZCBzdWJDQRcN
+MTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAvMC0wHwYDVR0jBBgwFoAUMgcs
+nnRdLV0pu7F6jTsVUrR9QngwCgYDVR0UBAMCAQEwDQYJKoZIhvcNAQELBQADggEB
+AEbJGAG0MzgAYBNHSm7qI/hQO0cVg2FSkzuKdKB4zp0Jl2hvgjJKAEnU1QMkCyW1
+7B1srXRhjyLp8lvBZPWtXtev7QSkNV9ysUiNDdg+FThP9WVsf+zPu2+UuYn57A0U
+0NeWGv0DeoZG1mzRq5DcvLk98o3ErZug8ABzaUlprx8yGvzqw5abyj7AgeXvp5fs
+0Jo+ya4e8aFrBx/8k2gPvGTv5AOaa2+tLFQsVOm4PUQk1ANklm+CIlOz5hvvZgTp
+UXaiY/BrYCSV+N7MFXNH/75HUm4PPLFr5LgI/whOgR6bFC3e/5kTdQpVBwGBNvNy
+OEp8bA7ViIqbseokJI3q29w=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/GoodsubCAPanyPolicyMapping1to2CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/GoodsubCAPanyPolicyMapping1to2CACRL.pem
new file mode 100644
index 0000000000..ed9ac1744d
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/GoodsubCAPanyPolicyMapping1to2CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB1TCBvgIBATANBgkqhkiG9w0BAQsFADBbMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTErMCkGA1UEAxMiR29vZCBzdWJDQSBQ
+YW55UG9saWN5IE1hcHBpbmcgMXRvMhcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgz
+MDAwWqAvMC0wHwYDVR0jBBgwFoAUW3N5meOuBtOKpjNOFHjkoB2x5MkwCgYDVR0U
+BAMCAQEwDQYJKoZIhvcNAQELBQADggEBAKKfTLLrhhr5sQTxYh0/59xGeCAPDiAb
+hZVIWXYrEy3HdaKVI786DjInVHDAHrpvO+pL52/unPqNZAFSpNpk8+4otR2/c9lu
+7EtForVhzkCVgO+bnGnLPqgYKq91tLD/NtB4OdfXlezP1LN4f4j8yHwmkJ9kv5bS
+op2gs30YZo4f5rgRFvDFzL0bYMzHcY/NVLqnHPp+8NqPsNAdyWl/90QjCG6Fj636
+8D7SQQpDY4Qrq0raGpsspyYkMeshUhLiEb8A2rnaen0dhrG8+5W2WP0zNoSQvKH8
+D2JLtZK+l75rRRZm5V9PNrza+ZfjbEABUmJjJ/LOkLiyNna789a2+9g=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/LongSerialNumberCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/LongSerialNumberCACRL.pem
new file mode 100644
index 0000000000..d0d3787427
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/LongSerialNumberCACRL.pem
@@ -0,0 +1,13 @@
+-----BEGIN X509 CRL-----
+MIIB/zCB6AIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEeMBwGA1UEAxMVTG9uZyBTZXJpYWwg
+TnVtYmVyIENBFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaMDUwMwIUfwEC
+AwQFBgcICQoLDA0ODxAREhMXDTEwMDEwMTA4MzAwMFowDDAKBgNVHRUEAwoBAaAv
+MC0wHwYDVR0jBBgwFoAUC2O3R67CBzIbf2/jOrjqC//XZKQwCgYDVR0UBAMCAQEw
+DQYJKoZIhvcNAQELBQADggEBAAT3AsJOgrvo4ohLomVgQey2sS6xh4bvK/qZmx4v
+czM1U9QpS7uO1QDgIkdxd7nGEtPqhzhjm5Uyw/M5FJwW0pOu5sRG9I/QvYgaTTbe
+u6CCwpL4fxJ42EjKicKdWvZ8+iQONDhcmHzIsvJJcg4vSkWc0S7CYwcrdbAn/KnW
+ru/Jnh4lGUxoj6GDYrroSCrPQqXk9rCTxq+wH5Ck8WQ3UyXLkVzuxWdBrNQ0Gwag
+dAh4u1o+3e+ta5V/WtQTZaSb71A0GvLqZpynu/pWDCQ8fkguvKbP55CuQLCnnukw
+nFs7zIlDlBQCYOgqvjswdzwZDSRliZD035oLDHPgSIeiWY0=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/Mapping1to2CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/Mapping1to2CACRL.pem
new file mode 100644
index 0000000000..5aa18e1b89
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/Mapping1to2CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBwjCBqwIBATANBgkqhkiG9w0BAQsFADBIMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEYMBYGA1UEAxMPTWFwcGluZyAxdG8y
+IENBFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoC8wLTAfBgNVHSMEGDAW
+gBSZxXhpyz0zdsKZrETlsA7+ufTbxzAKBgNVHRQEAwIBATANBgkqhkiG9w0BAQsF
+AAOCAQEAHDBNYlKeVrvQoU9wdLhmD2iI+pNFkNB0O/BJXY59wp/DFV+gyygyE1sC
+qnwOPMiKR+u9zypXr3+YbG/L0YeZuzzaFbHrm4ZYPcCRzaz0YVm7ZhbI+ea+moVW
+R5BgVfFUkfCiGNYQ5nxKif7WeYcCK+Aiy1eQ7e4munvJ5jzDrRiiZiBPRfY29FPh
+0qkp9TRqPLpY4oYwaGxe9UMKqvVdohBYqUUfdB2tgjeVlDct+MokpYL7wpnrQBTy
+yzgYpZ+GELYzhhn1Oc6PkIrYxc1h3O+tIg85uII/qFOC9qOslH0qPiVqEzwckAhZ
+HX8PPcXxLhO62X4BdaMgJhgHdUrW0g==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/MappingFromanyPolicyCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/MappingFromanyPolicyCACRL.pem
new file mode 100644
index 0000000000..4d6c9d0aaa
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/MappingFromanyPolicyCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzDCBtQIBATANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEiMCAGA1UEAxMZTWFwcGluZyBGcm9t
+IGFueVBvbGljeSBDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAvMC0w
+HwYDVR0jBBgwFoAUaHMU4As0z3JA2pSW1hWreqRvLowwCgYDVR0UBAMCAQEwDQYJ
+KoZIhvcNAQELBQADggEBAKZyiDbM1h05WJkyjY/Ri6vJfUyXeHPdkeLm2K+DuxVs
+VOreMcdvbKCDm+VjAud129+ou9CUFZUn2vPwhZ5+W6Z7ohzUoo8QeWGoWkvlY/yU
+/Hf4qR6QOxUATGr/f9u3ptsbVjBKEhD66Q/OvXgiBFNzOdZOqKuuI/x/rnXyOSo4
+pYJ/RecUb1m9WaVjO1eKQCGImMbrHTnIOziAg47/IdCztubxtWwtV8jmd/zi5E+0
+FO/lBnFyyghqNjPnML0LHQUM8Lr1EnFU9Lg2m/QFg2rWghrWadYKoa6lroPKhdMn
+hTL+BnTZkrwlJ7OtCI1wQD1NHIJmiL6lDBFT6TMH1P0=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/MappingToanyPolicyCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/MappingToanyPolicyCACRL.pem
new file mode 100644
index 0000000000..a4a369c179
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/MappingToanyPolicyCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIByjCBswIBATANBgkqhkiG9w0BAQsFADBQMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEgMB4GA1UEAxMXTWFwcGluZyBUbyBh
+bnlQb2xpY3kgQ0EXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqgLzAtMB8G
+A1UdIwQYMBaAFBQs7ZPxHhpwFZSLLZO0mNK3BQisMAoGA1UdFAQDAgEBMA0GCSqG
+SIb3DQEBCwUAA4IBAQAMdZWbfYwoDdwrkj0e1LjvvPiIXbBMwxuNhXG1LAaqazMF
+B3SM4/6IQ5kqLD4mXL6VTe1W3Ovu5L8DjbkXHckkq585B2s73Mwl9Ymlx7/MFahd
+taFST1d8AEQqxgBjcQ6imlEPtgJNboJqcbNS3/R/xau8OMXmY/kuSyTiMqeVq0jl
+ePVLDFrrLYaovKT0nG+7mN/afE+kyQxXaRk722ypf+38K4HHUAZwadRKPa8exyKz
+KNS8wFYjlrrua93qbpkDzmZ02gjkUJByCeBTqvkEbabUqLGfFhPJ8w/LFJiubwlI
+CmoYEAKpfR4393Uizsg6T+mHAaJmeIocAsoZBWvR
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/MissingbasicConstraintsCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/MissingbasicConstraintsCACRL.pem
new file mode 100644
index 0000000000..e84c210970
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/MissingbasicConstraintsCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzjCBtwIBATANBgkqhkiG9w0BAQsFADBUMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEkMCIGA1UEAxMbTWlzc2luZyBiYXNp
+Y0NvbnN0cmFpbnRzIENBFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoC8w
+LTAfBgNVHSMEGDAWgBQwVrwVEY1PxibGtZyhcJLS+U8NeTAKBgNVHRQEAwIBATAN
+BgkqhkiG9w0BAQsFAAOCAQEADdJ1BXt1/rZ+Je0fEAOWJOx/zAciiWeBWaa5WMnq
+H4fvy//4+r57ZLVCN87f0fnxBSGk2bs2qZA7tkLMtVyRU12cjYsTXzqIA7w+lMGx
+Tsel+hDHGdJjAL5X7xDMOX3kfX/I5lruE+nKCxaGXWV3peJkaVdfw/qzkR7/3Woz
+aa5B7soNJv8sGyflwJCMUgAfaHZa6LopIRZ2GpmDhDYiXtujZC4NoLhKaq3LgQgF
+Y8gjpJtW7dEs7HQo33OeC4s2u8Q6T0pJkG6Xi7rGArplXTklb0MFjrEN6quGlYNC
+00HSsvG4Pf+2IPKUf4P6I0QW2CAnZqfprIPGok3Sy6tfJw==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/NameOrderCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/NameOrderCACRL.pem
new file mode 100644
index 0000000000..9aab5ae9dd
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/NameOrderCACRL.pem
@@ -0,0 +1,14 @@
+-----BEGIN X509 CRL-----
+MIICDjCB9wIBATANBgkqhkiG9w0BAQsFADCBkzELMAkGA1UEBhMCVVMxHzAdBgNV
+BAoTFlRlc3QgQ2VydGlmaWNhdGVzIDIwMTExIzAhBgNVBAsTGk9yZ2FuaXphdGlv
+bmFsIFVuaXQgTmFtZSAxMSMwIQYDVQQLExpPcmdhbml6YXRpb25hbCBVbml0IE5h
+bWUgMjEZMBcGA1UEAxMQTmFtZSBPcmRlcmluZyBDQRcNMTAwMTAxMDgzMDAwWhcN
+MzAxMjMxMDgzMDAwWqAvMC0wHwYDVR0jBBgwFoAUv0qLgZtNjBQxjFvpzN0v6HkS
+UVAwCgYDVR0UBAMCAQEwDQYJKoZIhvcNAQELBQADggEBABkyacQyoBQE5YZL2K2Q
+0f637287irENIuJeWpv9MsXXsZZfN//UeOfwIdnhAMQCx1GeEbCdAPAKkBxI3Jn2
+AVtxqytV8F7xqUiUpYRw6g2B0jjsJoaFP4AoY+BGk5/4oLwj2MzNyNcYFb/KPPgc
+Pwq4T0IR7qMz60d2lZzLhWWz50jOmvwvyxFbOcYwh1RmLB7KKcwAaPeSwlCxThQS
+sugsqHuq3K+pi7KTShAV2UWRupDOGlVyPYAuo3n4G2LmwPmwmYmnG3+KS1Azyj8B
+ywYDiAPQyG10rufsDF3GEpJzIOPt7VHv8z2SthTPmVfDFrkwshOQsb+PrltGP9bC
+V/s=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/NegativeSerialNumberCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/NegativeSerialNumberCACRL.pem
new file mode 100644
index 0000000000..62dbbc8db4
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/NegativeSerialNumberCACRL.pem
@@ -0,0 +1,13 @@
+-----BEGIN X509 CRL-----
+MIIB8DCB2QIBATANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEiMCAGA1UEAxMZTmVnYXRpdmUgU2Vy
+aWFsIE51bWJlciBDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWjAiMCAC
+Af8XDTEwMDEwMTA4MzAwMFowDDAKBgNVHRUEAwoBAaAvMC0wHwYDVR0jBBgwFoAU
+YuQuNcYPxeiR0AvBjd62r9qI2T8wCgYDVR0UBAMCAQEwDQYJKoZIhvcNAQELBQAD
+ggEBABjkQVYJziJmvShgFK3XecyOCYDlSPShr+vgrGFBQpyi/FePWU0yot93064/
+lRSHgzS8B9yvXPJBygOGT/hbmNG/88Evu2Z1LoEOLTzq+Sbf6LahfqDpkvdf6SjM
+wy4udr0g7dVOjHQg9DM+HDij7tc150o6P0e9++0CgpXuRNQKYKRq3qn4KjBq9Yph
+S/MpUEY70hgZaL+XTbyvti83Y8nPqrVIz3VRcG7GLHAmYb3cGwf/8zNL8lpOhzOU
+MoTwN+TcRWvMlYWYoyfaaGxA+Ak3wcPsIHhHLxTyXucXGQPjrmiGqK9H6BOUZT4q
+HupHV4TbUwMoW+FXISGPVvz3ECA=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/NoPoliciesCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/NoPoliciesCACRL.pem
new file mode 100644
index 0000000000..42ee928471
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/NoPoliciesCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBwTCBqgIBATANBgkqhkiG9w0BAQsFADBHMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEXMBUGA1UEAxMOTm8gUG9saWNpZXMg
+Q0EXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqgLzAtMB8GA1UdIwQYMBaA
+FEIkA+2lS3acl5hcdOoFOhv8NeScMAoGA1UdFAQDAgEBMA0GCSqGSIb3DQEBCwUA
+A4IBAQBuELGhtxMeER+HyzT997rCWtWbXV9HT6zgfU9AUTX2pDoNFn9iGfFkLaJm
+rSkQro17ogzl9xrF2EvdgMSSw6YxRU7MbMMmF2lXC+IbScdtAGgdURnGF/C3Omao
+dGbXXI+3gUM5YSlPqGToDB2j7tBAC+THt8Knxq1NLeRt9cXpztX/UF+B4u62ylHo
+q6jV4KLlWksRGwtEF9w/2iiQv08zz92ySgL4Z/CbBMQfX73iq6SjPFOJm1CpA0BR
+QFN33H1OC8WMHaoV8M7DBGpudcWzHZpuq9ikjLdlCmDuGEyJgceneOe6e7vsupe2
+DGRGvgwmJbJI/XbCbLnwSW3Xdsp2
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/NoissuingDistributionPointCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/NoissuingDistributionPointCACRL.pem
new file mode 100644
index 0000000000..789099d061
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/NoissuingDistributionPointCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB0TCBugIBATANBgkqhkiG9w0BAQsFADBXMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEnMCUGA1UECxMeTm8gaXNzdWluZ0Rp
+c3RyaWJ1dGlvblBvaW50IENBFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBa
+oC8wLTAfBgNVHSMEGDAWgBSzy1S/ap38n8cxDpIMp0drmQCfMTAKBgNVHRQEAwIB
+ATANBgkqhkiG9w0BAQsFAAOCAQEAqnXhjxLsCflfSGLvYk06S6AP9+nEuFtbqXDP
++T4URhv2PZ583f7hg0jEd1/SZqyNxrZk6cNNMR2DYPCX8XsP3c0lKf1wVoielyl1
+bSPCTifm0z8pJr9ORD7XHDZ4F8s/nv08f+GJmYUaE036Nw++wNMqi016tw+TrHa1
+s9jSwUvlzjg/om6n0EMTWnWTnEHngdrGkV63kuo+4yymlsEALlgmIUp41bOiWzFo
+aYxsFd2k+ZAGvv5mB1Qimcp8C1ssInLczcDQ5Un329OAz83nrgdCZcYkFBAR1A46
+p+16zuw55BiQp3gByK1NVTssEcBOkDm/M1DgS+CtE8xkfKnR6g==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/OldCRLnextUpdateCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/OldCRLnextUpdateCACRL.pem
new file mode 100644
index 0000000000..d9591e5cf1
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/OldCRLnextUpdateCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIByDCBsQIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEeMBwGA1UEAxMVT2xkIENSTCBuZXh0
+VXBkYXRlIENBFw0xMDAxMDEwODMwMDBaFw0xMDAxMDIwODMwMDBaoC8wLTAfBgNV
+HSMEGDAWgBTO2h/aWsyOl/ogFSlPrJaNKs14EzAKBgNVHRQEAwIBATANBgkqhkiG
+9w0BAQsFAAOCAQEANLTjtSL1Q3Ya29eHHAMhRdlEtcNF5CMpIUxvS3eQjTH0RxIR
+EWfDguJmX5gAeyHgegi0W4E1e5qArzpestM9nXMZypQ0GuOLEqQ8QfV4UTp5B3Ng
+gdgrxRTIdlpkEG43G93gZBmZ7u+HHbBtoBM270gFtluBXTnLbs6cHsZRn3p5jOCc
+Ll/YQBCO42iRjmww2mYKy5dB18geb0YZHlKL3FbZ1JhfZlvmHilBvBSx9uy5qZgZ
+HwlONqnePLkbK+0PyLaooa5NJXmusGVuZVC9x5gzwO+ZHun8fZ8aHIDDO9RtOv5U
+6r2J4kRp8Nw6zM4yWeQOD0GfRFlsq/OM3lHgPg==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/P12Mapping1to3CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/P12Mapping1to3CACRL.pem
new file mode 100644
index 0000000000..f590198a12
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/P12Mapping1to3CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBxjCBrwIBATANBgkqhkiG9w0BAQsFADBMMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEcMBoGA1UEAxMTUDEyIE1hcHBpbmcg
+MXRvMyBDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAvMC0wHwYDVR0j
+BBgwFoAU/PSNYTMygHx9NYfeX1L7afEdwRIwCgYDVR0UBAMCAQEwDQYJKoZIhvcN
+AQELBQADggEBADWFF9y8VCunmgrr/9sJCD19KF6FofJOEV4U6zjPju5N/4b3Txoc
+LiClRWHYyRqHjOlLvAOik0mopqcUhwGqQG3MpU56R8LEKScgQQiacPuSeRSflRRo
+nxGs/90yJrq9s59EN5oZH+AnhJ07R2kq1PFLMGR6MY6B4A4MZony01/BPG4EfpRn
+W270ehb6FEYIc514vHyJ65s8KfUx01BsMSTwS75LJFEmnM6pRLzZzbESQEo/5/BN
+ttRRwrNt7TlwY7zs+oSDjUEpQ4K7tbfuQtIqiGm2VsY1O8kZWYmg+eUTUplcLoEZ
+LuAkicZCYw+YPcorZ+m9nL8FbxnrPm2LjJM=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/P12Mapping1to3subCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/P12Mapping1to3subCACRL.pem
new file mode 100644
index 0000000000..acc5cde185
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/P12Mapping1to3subCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIByTCBsgIBATANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEfMB0GA1UEAxMWUDEyIE1hcHBpbmcg
+MXRvMyBzdWJDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAvMC0wHwYD
+VR0jBBgwFoAUvnsTk6Hkm8UnPDBT16XJ5lqWejQwCgYDVR0UBAMCAQEwDQYJKoZI
+hvcNAQELBQADggEBALLR4At4E9ny2pPCIb4rLKvVRs10lszGrH8NVo1jhuugSyMS
+wMYPWuZbUw+rpN/YwFFkM5R256ITwtEttgHkWoa3CetBBRYF6UPIMyZp0KRDQAZC
+SwPU89QvP5H8KHuB3Zg4bg1wrXZTP9vjTjxf65UQhc2S3zj1M+TBv94h5J5cHSY+
+Q9Nz5iRoxEJv55/TWa7UQYBwaDbPxdb+twKEhdocjTZRYub2LhKRlY9nmTTiM/J5
+wE0RYNQsPiUkZuNELh7ZxPCp9Gk5KqbE0qUSO7KYiPEUj5mK4F+j2Mwb6nsoT9gt
+lrN/kqlyXJMhf1wRux12aUXN9Ia92lW6WrI7iH4=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/P12Mapping1to3subsubCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/P12Mapping1to3subsubCACRL.pem
new file mode 100644
index 0000000000..d000a06282
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/P12Mapping1to3subsubCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzDCBtQIBATANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEiMCAGA1UEAxMZUDEyIE1hcHBpbmcg
+MXRvMyBzdWJzdWJDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAvMC0w
+HwYDVR0jBBgwFoAUAF05Pg/lqipeLfauaCqtM5s9m3MwCgYDVR0UBAMCAQEwDQYJ
+KoZIhvcNAQELBQADggEBABqrLgpbtj/1buUK3kRN35sQe3KtFggWeg1MO7BkQtue
+zRD3ajIwDOBbemqCmEj8w4TdlDzTiEVpaa4k4UqlcTINMdlc8AbSzs4IjZvg2Mxu
+RcGm6+Kr8YfltOSeJk1zdQve5V9ft76TSGOZqK0Q4rTYRuuTipe3EnwJUdvyTR0u
+gmPO5XTMHnyecCJoUAHFmqEy5EAjgANJ9t0DwPzK+BIPDn76PmjKd0zhd5rAhQzm
+FhgGSyUAZMLAnPrpYTJtTW+QM92qJPxOMWvDAMVTJxUrZmfaDSEOFUnoTi6yADaR
+Mu8MWB8W9CRmxNShdUht4CGu5R03u6DGBoT70fkbn2g=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/P1Mapping1to234CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/P1Mapping1to234CACRL.pem
new file mode 100644
index 0000000000..376de8c6e4
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/P1Mapping1to234CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBxzCBsAIBATANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEdMBsGA1UEAxMUUDEgTWFwcGluZyAx
+dG8yMzQgQ0EXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqgLzAtMB8GA1Ud
+IwQYMBaAFJULAalJeKp22n8JDayIFPn190eSMAoGA1UdFAQDAgEBMA0GCSqGSIb3
+DQEBCwUAA4IBAQCqaCGQVcOhNGIvLyAEZ6u7CZSlusbOFE1T7cL10Z0XpNwHIU2e
+dzV4pmt0Y3tAJyR0FIXlqZbxq6fm/S5U4cWoM62jk4PzFGu9HaocJNNOIK0Opfuk
+TwwMOpYN/6IH74iy22lb2Wdgike7G9bCWl7nvMVZw5I7OIGyy/oqkhqjtWFLC9nD
+fYRIwfG3HPD8Kc2GMVc/iTalLDe3OUcsSGTrqCg0OwGckH+CdiXQk5MfV61bwICQ
+RxURNAqzCqYhNSrDH/qcGId/3mN/LzpoBr4SVRMZhMw0MpUWSTGwe1wnarhxaSoD
+VRHuoceqwHtU+s3AzFxHRXDbv/0xHECrkNjX
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/P1Mapping1to234subCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/P1Mapping1to234subCACRL.pem
new file mode 100644
index 0000000000..316b5ba594
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/P1Mapping1to234subCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIByjCBswIBATANBgkqhkiG9w0BAQsFADBQMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEgMB4GA1UEAxMXUDEgTWFwcGluZyAx
+dG8yMzQgc3ViQ0EXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqgLzAtMB8G
+A1UdIwQYMBaAFAMX5ZUA/So5eK/LRvZAmGUKAu27MAoGA1UdFAQDAgEBMA0GCSqG
+SIb3DQEBCwUAA4IBAQDCUm9OtS/rVGX56aFpRteKjEE8VKLOCXIecUda5ewyHw6a
+JRpUhGBguzOjY60yM8isBHYefdfjM4usLfZniy6NtfJ2S7yProWY7P4IYUsWgrMn
+2tXBp0LnyyWarx1f2NSeBJbsQKiw8fXLsygMnd8ISb6eA1AGKfZfxmeC4PM2Hl4/
+KbKdvxs7UWT4jD0WolZyOpjr/Ffh/uAKZB/TVks8j7ZENODT2lUc5KxmDbMCHEUp
+pd5GyRrXKJjdMMMUK/VUxOr1K22eW1FgBmx1zUiT9Uhen/bS5WXtfhVGqm1q468F
+jrPVC+/FBoFjuHU5tcxtNup3cLH6Vm4Y/v5+u2u+
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/P1anyPolicyMapping1to2CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/P1anyPolicyMapping1to2CACRL.pem
new file mode 100644
index 0000000000..709a1368ac
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/P1anyPolicyMapping1to2CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzjCBtwIBATANBgkqhkiG9w0BAQsFADBUMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEkMCIGA1UEAxMbUDFhbnlQb2xpY3kg
+TWFwcGluZyAxdG8yIENBFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoC8w
+LTAfBgNVHSMEGDAWgBQfAigoMo5KhPi4i0HxXXvoJVJrhjAKBgNVHRQEAwIBATAN
+BgkqhkiG9w0BAQsFAAOCAQEABhVsmwrFO9I1+fkjbJM7OfRp8BbNFRh0Mhb/ky6K
+g4U6YuwlEQP6KzM3QyOyQPIh7CAljCBxJpJkXrfm29RJY3OqS4THg+FfEmIcU+MV
+1TrRd8CI6ufBCdoG0SUUsS2W1CZFjbQNEl/xAfMUkuJi2T0lbCCsb1y0lpGrFW1l
+k2HLwq3qbikjZyWhoD/k6ho1yIEg4uT03GyJUm/n7Ij4DThK7mJP5vu9VD8rGwU3
+XXsoD62oMo2duCLrH4Uj5U+k/RbYb3zdbq+6xb4WLkt9MC3zWK3NtiVWIr9Q3XjV
+3uz8fErny04GW1dGGQQn+U50ZLjCA3bG78hbyCxv07zp6g==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/PanyPolicyMapping1to2CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/PanyPolicyMapping1to2CACRL.pem
new file mode 100644
index 0000000000..c039b47889
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/PanyPolicyMapping1to2CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzTCBtgIBATANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEjMCEGA1UEAxMaUGFueVBvbGljeSBN
+YXBwaW5nIDF0bzIgQ0EXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqgLzAt
+MB8GA1UdIwQYMBaAFEcDJy9DPcUv2ZKsx9J20DPG+Xe7MAoGA1UdFAQDAgEBMA0G
+CSqGSIb3DQEBCwUAA4IBAQBQVc02PPmQX4EhnPqxh12Tk5NseAryd0o8bmViilep
+uCpk+roAUOXLvKHg43alw0d+OsPA435KTBLKs5hR1lrEjEqE0AW56jqYbdCmei19
+XbaaGc7hrBbraDuFqAeobbZ2jwDxN2MQqIOT5omzfyyVLUzVKNyNsxvOVCoke+ya
+n29eMlOzv61ZesITDJlkrqTEyjwaRHUQtfthv4TB0sPIP5NmLq9ThYqhaVjsEtK5
+4bS6XP6xsVw4uyPrwStEgPPAbrYZyyRVNrNJigAyEKw59Kl5GQPefAm+mAo+x5D9
+aZDC+5MDbHU4CcjPPzbX5iocBgz3rEazHL1CJbIflrlh
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP1234CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP1234CACRL.pem
new file mode 100644
index 0000000000..ef2c47424e
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP1234CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBxDCBrQIBATANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEaMBgGA1UEAxMRUG9saWNpZXMgUDEy
+MzQgQ0EXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqgLzAtMB8GA1UdIwQY
+MBaAFPb9qYwmLLTP1tPr1B6tkmoduyRQMAoGA1UdFAQDAgEBMA0GCSqGSIb3DQEB
+CwUAA4IBAQDVVwwWNj9cO5+4t4+7LgMKvD8IGEKTakoiouH5na732HehNDO/mHzA
+cEKjj5MgEdx2JLghyLAtDsD4LTzdCANAftXnGeZJVcATUbjSecgPg5wFLLp9/mg4
+Fb5mIQeTUkYcrswC6Wa/P3vLJfu7L0vJwg6tPwnkFHw9NqsuzFqmQvrlrRtzLaDQ
+zlvg6BZkDCXSK+7gqQ84F4WJZCV9laVkymfM1ih0wXWby0VWlvAZK8SoWc6W7rep
+6dePGKx1V/lgJkYbxvMROoRKmoXSoHdxPktChC9KL0LievdasDF5/HZ5UgKNcE3n
+65jwDBq9nnOQfhhPm2WeLNlVbzY1Mzjg
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP1234subCAP123CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP1234subCAP123CRL.pem
new file mode 100644
index 0000000000..5cb4f07fdf
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP1234subCAP123CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIByzCBtAIBATANBgkqhkiG9w0BAQsFADBRMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEhMB8GA1UEAxMYUG9saWNpZXMgUDEy
+MzQgc3ViQ0FQMTIzFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoC8wLTAf
+BgNVHSMEGDAWgBS5qlCBpjRmUWidQu4piGrsHMh89zAKBgNVHRQEAwIBATANBgkq
+hkiG9w0BAQsFAAOCAQEAfV2uyHCfgiXrwk21BBpCMPiQmJ5erAU2QRfYd/IzoTgx
+sMGttr8QexaLY7rfY8K9Ju7t428gmoFYScIB8AITUCh+Z9l+wx3egQxCC9twjgRt
+zS/1ys8I2nK9CmA26ClY7TAL2ztIjFDcS+S1/tZlJxi26il6EpTjDkb4altMcwYD
+0dy7EW8Y/JAvFGBkziG9FiDThEdYK/hyDtceBEGDcWJP2s4CBOIigzdEkllFJe33
+ugx2AhLvGvHPzpyOzUPxlbKkkkoBjtU5WUl0v1PSiAa/OqXxXjOb1uuMUsHutbdM
+51I6VkQkncKEKN03OTkCgwthFM4GN5rurT02zD0KBw==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP1234subsubCAP123P12CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP1234subsubCAP123P12CRL.pem
new file mode 100644
index 0000000000..4f33bf88f8
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP1234subsubCAP123P12CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB0TCBugIBATANBgkqhkiG9w0BAQsFADBXMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEnMCUGA1UEAxMeUG9saWNpZXMgUDEy
+MzQgc3Vic3ViQ0FQMTIzUDEyFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBa
+oC8wLTAfBgNVHSMEGDAWgBRO9F6h+Qgwe2WsksARCyzTtJYHHjAKBgNVHRQEAwIB
+ATANBgkqhkiG9w0BAQsFAAOCAQEAO3mUa/hz4u9id4j6HNSVrunOClJfxtxgVK//
+BhUHRP7DLt9PfridxGqVOENl4KKUp3Is8JDXhsQLfalp+SXUEjUNIW9tK1XGT8RM
+KuyPXfYNvK0ki8RLZBrOObwuz1bwCIr8suJnlbuO2PizZiYkd9JkPpmI4Ql7wvKQ
+qtZG/D9gMSKw8YYU0BBD38C1DBcx9zX8Juq1of2wA1bRO4+1r7d1caiauSNDICLM
+6K+5veVzXPbdi9AiCym0q2DafSijAO/tyVI7viGFriA1XXPyW4IgJTlYwj6C7bNE
+spPxDeHZOYGjSRYwnOVwl5FetLBZeXPnb+oCUueETTdCap53mg==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP123CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP123CACRL.pem
new file mode 100644
index 0000000000..9badaf1180
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP123CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBwzCBrAIBATANBgkqhkiG9w0BAQsFADBJMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEZMBcGA1UEAxMQUG9saWNpZXMgUDEy
+MyBDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAvMC0wHwYDVR0jBBgw
+FoAUjCgK2g0JFGLuPT2WuHGTEonq6GMwCgYDVR0UBAMCAQEwDQYJKoZIhvcNAQEL
+BQADggEBAF+cFlwOZpoC7aoNCsV8ISlb/o86hb45QuGdajlLv/vTDAstyF6123qR
+3dE5/YuJ4FTgjZqNt6iBOMIaauFE9nTeQ/G7WhB6yGOtna9QrTIIWQfi3kyuONC5
+1+YUr/dj9wBJgHXQhO1ugdweVdstePbTe0iRl1ZGG+Hs/xT5r7wji24hhtjyXoAJ
+J9A2NQoLt7wD4OBOKQUHarYY24xpnVcWryWxfS2HGdsiWfyrdVMSTzoZnIqI3kzW
+VvbVj99ShHKFmIQMqBuZZGQCrXlts5G6mknQK9TNCHCJZwX41S5Tw/dd5X+Ujdyz
+knTDjuehdwjtDecV5Dh0q0nORth5X+s=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP123subCAP12CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP123subCAP12CRL.pem
new file mode 100644
index 0000000000..bfa6e83f6c
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP123subCAP12CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIByTCBsgIBATANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEfMB0GA1UEAxMWUG9saWNpZXMgUDEy
+MyBzdWJDQVAxMhcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAvMC0wHwYD
+VR0jBBgwFoAUzgDa/aqTQPjAoHmtwXjOHdcn9p4wCgYDVR0UBAMCAQEwDQYJKoZI
+hvcNAQELBQADggEBAEBeDNTliwQBVeWRQ3NDLEUH3xNSHfAr8itMFr1gMI8YaS7e
+qYMtIZnedQ7o1A10abrH6X4li/8UDL+7o98CTcd02D2Hrvc+QXT++nIJ5oFbt0qJ
+iOVXGQ5ZXVxSaNif729zjcAmgGKcHtVtxPvf9CgmnQ78hA6mx0ugFHs4QSmecsMt
+umd0V1AsscRGzTjvN0YCVBPpZPy/oxLU6pYp6XAmqC1UHPv8Ny1/unMz7cYoam/0
+83KZJHp8I4FSzkdhrFyLjKaaVxwWioLyQUTwrzR/qzaU1Eyk+KipzKVh470kuItM
+cDnV0OXOPuJR1XA3yhdLZU0aMtwd28WZ1Y4myPQ=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP123subsubCAP12P1CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP123subsubCAP12P1CRL.pem
new file mode 100644
index 0000000000..f8a920a1be
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP123subsubCAP12P1CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzjCBtwIBATANBgkqhkiG9w0BAQsFADBUMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEkMCIGA1UEAxMbUG9saWNpZXMgUDEy
+MyBzdWJzdWJDQVAxMlAxFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoC8w
+LTAfBgNVHSMEGDAWgBTkGz5Gt+bIqdjt0TN/BeHxXRIkwjAKBgNVHRQEAwIBATAN
+BgkqhkiG9w0BAQsFAAOCAQEAZg1qheMvRGkd/jBrdaoWnRb0iEuPZw9Ij5k64ZeI
+JUmMeWjKKFnLBsC0MIrEtR3NPqMU6tfZH3mmeCzJ6pjo0IozkN1OnMYFqwxrfn1T
++d/yM4fYBb12oesd7n1+c36hlHKd7dxi1xUAwCIABnX/17odaOCD9ikA2sq5XfqS
+p4Z7IUPd+i/8dF3Pkfm+cpPJaNdpdd2sxx4mmbsGcL9+2xIwhfiVavawZe0MZYxw
+kPhNVL8zL6kYUCRvB7J2hEwu1MWH3paED9MIkKyS0zVdzfg4DojApNP/nwL3JHIf
+DVscEQo6mY+6hhhOYApDNF6y81BRqasImFItcLp/fgE4tQ==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP123subsubCAP2P2CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP123subsubCAP2P2CRL.pem
new file mode 100644
index 0000000000..cbbe9d03b1
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP123subsubCAP2P2CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzjCBtwIBATANBgkqhkiG9w0BAQsFADBUMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEkMCIGA1UEAxMbUG9saWNpZXMgUDEy
+MyBzdWJzdWJDQVAxMlAyFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoC8w
+LTAfBgNVHSMEGDAWgBTp/LZeVhROBh3RMv2IYGsQ+AUbaTAKBgNVHRQEAwIBATAN
+BgkqhkiG9w0BAQsFAAOCAQEAYcCBk7Si8nv8UU/B0/YbctjIyBk8VOtKhIFbRunt
+alE+/Vc/c77r0Y1CfVII/DOAFcB872KtQuWyl5p8uVlVwmDlL1BKmz35mD2PS10i
+NsuofkZTp97xrRZbA1k+zqMshOzmEXReNrR/qliJpTPlH1YMNV5IN02HNYZ8+6mn
+BzAs4e8/xS2cO9ktya0ZwAqwH3ksD+etLL/MIj/3BAL9HRMOC+RcKktWkVZKqYq/
+AAzn3HlvnTUZi2OW81ABtFl2hYSJEyBcKjrSoDuZ4Utk5AuxOsLwa0hH4da+/4nx
+OreMrYjymG9FpLVq+RhVYMdJSzp8c2CU7rgN0Pap7sQY/A==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP123subsubsubCAP12P2P1CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP123subsubsubCAP12P2P1CRL.pem
new file mode 100644
index 0000000000..2a6a21b33b
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP123subsubsubCAP12P2P1CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB0zCBvAIBATANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEpMCcGA1UEAxMgUG9saWNpZXMgUDEy
+MyBzdWJzdWJzdWJDQVAxMlAyUDEXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAw
+MFqgLzAtMB8GA1UdIwQYMBaAFIkgF4T7rLsJ195eXp5o9jlQH0CIMAoGA1UdFAQD
+AgEBMA0GCSqGSIb3DQEBCwUAA4IBAQAVS+qKdu5cTu1Y/7f1Yci/ULGAtX4oYox6
+0LYSSXpOl1BzTNMxUCp30N382djQEYODR8vROlVXDyEaHwMC8Dyn+YreG+1eHODk
+Mq/Hc59ckRW17LDJpyBew1535EVQa6LtC6bD72AQ1Fd+hzH90WNNQCMb4xQ6eOnF
+T1pSoKoopsA2NH3zTBVrtq1n6K7FOojGqKdO7oYqill+bRdMoYSNKQx1lskS9E1b
+lQftEmE8AAlU+Q1zV5IiiSpoEXe8/nbyTwSbYvaUHmmBgwCOdgnpJiG6TvwjcFh/
+zIQiGotG9zQszNrO7GPpvc9wQ+o2uN1Luilv1P0FRw0PBHMwmwUJ
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP12CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP12CACRL.pem
new file mode 100644
index 0000000000..1af85735f5
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP12CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBwjCBqwIBATANBgkqhkiG9w0BAQsFADBIMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEYMBYGA1UEAxMPUG9saWNpZXMgUDEy
+IENBFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoC8wLTAfBgNVHSMEGDAW
+gBTYXzXimsE3KibOg8xzDnAVKjriMTAKBgNVHRQEAwIBATANBgkqhkiG9w0BAQsF
+AAOCAQEAUiAHin1qZsRcAQcRXu9l1qnbsNYeC32w7Y8SR7o7SLMBjrLfpzTt3u31
+UGBH/9CfynTV2n3wVuJoCCFTdkgRn08X+Oc2sK/8g+oKvTwmoLQv0lktEsFvOFC0
+4/5wB94qkPysqGKKPj0ADujY5GBWb64Z9V6ehvxACTzKhPCNc7auvTLZEymtWW2H
+4C6nZGjUuuoZbd1Y20d0u5/18MySt5HCfKyoIfA75dsnuL7RJVFvrjcXxH40cXs8
++xizlf66wdIVeWCAr8RV4bPFmlC7fAF3UjC4MoE1RQqbWuYig79F7RS29s6XNWiq
+A0W7puTYGKoCpIUETmzBSDOsNpcfIg==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP12subCAP1CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP12subCAP1CRL.pem
new file mode 100644
index 0000000000..c96f12103b
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP12subCAP1CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBxzCBsAIBATANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEdMBsGA1UEAxMUUG9saWNpZXMgUDEy
+IHN1YkNBUDEXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqgLzAtMB8GA1Ud
+IwQYMBaAFCKe1w64SM4JDjpdvtZNWCNWjcvWMAoGA1UdFAQDAgEBMA0GCSqGSIb3
+DQEBCwUAA4IBAQCPniPRTYwvNO1eFZjaR7nnHYFDRh7cAd2EsYgmh9W7kjeafaZt
+vLCnzQv82LN47Ki1z/2KWraLSRduP8qnY4wGOdRsahnrl/ss2wjMB6UiFp+Un6IA
+AKEM5MLgZwvjsadAADqJXonGzB1Eh2xmHGqZloU5V5FDewbjem/scf3yufvahMvr
+ZSjBsSUMCBfIewJq7JRkwSgyip4K/t9UBJBbsfkOOR5/rEgaZyyfI86nGhg0GawS
+FHw1fAPcG6vEKnsyyHU9JhzjtQYUi3JiZO2BamFAXfJkDOhCWfkR4ywhRUP5bqAE
+q4GAriFrKPKYB3Fp4nAhbLi4bhV4kUS+lWoT
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP12subsubCAP1P2CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP12subsubCAP1P2CRL.pem
new file mode 100644
index 0000000000..4dd0f2fca0
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP12subsubCAP1P2CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzDCBtQIBATANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEiMCAGA1UEAxMZUG9saWNpZXMgUDEy
+IHN1YnN1YkNBUDFQMhcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAvMC0w
+HwYDVR0jBBgwFoAUx6U3p9D6JOV839vyXWnb7sr2me4wCgYDVR0UBAMCAQEwDQYJ
+KoZIhvcNAQELBQADggEBAKWuXLxMM7H4MkbAsQLa1RgeuDYC5FLy5mzt/UsidYqx
+rSK7vX19l658Lz1NEcq25gXzJlfOG8ZIAUkO/SXwi1IwqOU2QVkn6nJnXYP0J0c8
+QEzxYlYEC/DHDTEUltH2ZoIuOoozIT6NHw8+2/XBBjatS1nL10bhwvzRXirGFKGN
+BtASLRZeHaU0y/n2KkBuusn3HFyErzRskNRLPOTk3Lt0/RB8nbrRxUUZJXAaZJIr
+4Kj4LcatDgdgXCZ2MEC/mCByKwFiwh5RgMQqPPLMhGBRSPfPD5hVKVL2iGu8qSxK
+kkLZkwrGL9U/1mXtcajUpz+r28iLP4uJnCxt9ZBVIcg=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP2subCA2CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP2subCA2CRL.pem
new file mode 100644
index 0000000000..d2e6b8d3db
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP2subCA2CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBxTCBrgIBATANBgkqhkiG9w0BAQsFADBLMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEbMBkGA1UEAxMSUG9saWNpZXMgUDIg
+c3ViQ0EyFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoC8wLTAfBgNVHSME
+GDAWgBQXLOoDuAd3gT1lpb8zH8x60pj8vjAKBgNVHRQEAwIBATANBgkqhkiG9w0B
+AQsFAAOCAQEASUNpb/KK0iBuFV/Y7HRxjqNfJAhSRjOxNrEMtuql/YucrqQKFs2f
+AcbNwEWPPdW7KEd2bhyUBlJJ1g0mWCPu+bHNv9IND3bsioXiStlDblymVm/ShJ0i
+f3VWT47L0Lb6Ppye2r+A486Q468clSbDv2pj+vAPqFqUaSr5iN+Y/WTxUtAs34Dx
+qDRWP9lye1OzlLnMJSf/ZVYHdS/KmnsR9YIIeI7pNqtPf9ilDBe6Va51tpVfHnp3
+OLQersoyyDApH5KCQQv0/+4EPqZjmAcO+ALDg4Q92vfzbULImJW6rMD6dlEtITlu
+iful4K0ey6Jngy/6qFTtI/jJgzNmxsR6Zw==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP2subCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP2subCACRL.pem
new file mode 100644
index 0000000000..02c8fa43d4
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP2subCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBxDCBrQIBATANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEaMBgGA1UEAxMRUG9saWNpZXMgUDIg
+c3ViQ0EXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqgLzAtMB8GA1UdIwQY
+MBaAFF48hHOeMHBycZiugTYZ2yIOfK8DMAoGA1UdFAQDAgEBMA0GCSqGSIb3DQEB
+CwUAA4IBAQAIgjc4iT1LVOUqEO9SLZgx9MpR4Vt3gTa3JciJH+czDui7YgsT688m
+8/dqZXCxTkt9JYPQGABYYhwxsQC2oyjG2jercknnJ+XHk4JV2wN/XO9ItNhI+OvA
+rnKtzk6Rpf7pS3SSjeU3XR5UIOiMM2JoWGvtUhwq7b5RaLk36Z0gGp9x/3LaGDBA
+FTred1LnWgYQCO7jTGWfDT4xIJr0FqA1RNLb+xvkmA1lmhjZ20lw8HXHgFsfvb4L
+ADFkLzFQ6p/zuleXBDe8U5lusCqjls0cTaiNCdpPXuJ1I4hkPYu0raquxjC7VoM8
+LWcIpRna9gUu8sSD7k7N+NDdQSM+Op+P
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP3CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP3CACRL.pem
new file mode 100644
index 0000000000..0eac63d37a
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/PoliciesP3CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBwTCBqgIBATANBgkqhkiG9w0BAQsFADBHMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEXMBUGA1UEAxMOUG9saWNpZXMgUDMg
+Q0EXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqgLzAtMB8GA1UdIwQYMBaA
+FNgFqyygi8OS3Mataj+/88aY5dz9MAoGA1UdFAQDAgEBMA0GCSqGSIb3DQEBCwUA
+A4IBAQCwxaqJWjJraTqw0xo+dvcx3uD3LYUe9aJqKvZTbNqLT23k7U62qcWUz59N
+Rprnl0q9aemI80Mk/Vk4WAr9weTsOytXrNML4Rgk4Sb+WjU4OSlUZbBka1YS41Y4
+xiZzhQYrL391uyDD/FLsehWJmkO9JqeydLT1A1lAuX9m3f59PJ6waXJMMwySszDI
+T2e56JR6Vt3659YRpNScJmDKWc3wdHagNvmtn4Z/c+TtO+JN11doMwx/92uV+nic
+GVVPJQqKZDvNfK/hLxBo3nKBpXJUrU4AyYCbpe4idc6CxYMAy95UqUlFV72pnndm
+E5RRfI4x2a+BTvs8HNSX3LpruISg
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/RFC3280MandatoryAttributeTypesCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/RFC3280MandatoryAttributeTypesCACRL.pem
new file mode 100644
index 0000000000..49582a3282
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/RFC3280MandatoryAttributeTypesCACRL.pem
@@ -0,0 +1,14 @@
+-----BEGIN X509 CRL-----
+MIICDjCB9wIBATANBgkqhkiG9w0BAQsFADCBkzELMAkGA1UEBhMCVVMxHzAdBgNV
+BAoTFlRlc3QgQ2VydGlmaWNhdGVzIDIwMTExEzARBgoJkiaJk/IsZAEZFgNnb3Yx
+IDAeBgoJkiaJk/IsZAEZFhB0ZXN0Y2VydGlmaWNhdGVzMREwDwYDVQQIEwhNYXJ5
+bGFuZDEMMAoGA1UEBRMDMzQ1MQswCQYDVQQuEwJDQRcNMTAwMTAxMDgzMDAwWhcN
+MzAxMjMxMDgzMDAwWqAvMC0wHwYDVR0jBBgwFoAU8FEYYu/OQce3sGd0awK8Mgoz
+meswCgYDVR0UBAMCAQEwDQYJKoZIhvcNAQELBQADggEBAFqTS/IzHJiqF28DiO+F
+v++AFZ/b8cYN6B5eoSoZYBg2C7pV+5UEL0+hQlper2e6TUIEkMpSU7Y6VWc2okpS
+YR+2bNCsIDX/RB2DYzyEGgqwoBmbeTCE/bIbcxjoSUOP7YlI4wD4XgOISwVOBZoK
+Mc+341k1iHhwI0OFHv3XVHqwegy5RVcgYhWcq/H9ARUvD3+a5HDdBGTCP4r8aCcD
+46zDEsBRYVJNPsyk4cnBsR/8nh8Bufy8PWuArb+s1ZSQ0PMgtwfrvqPCM+wnl/+Z
+gN3UiKvlBG2lSrTxhOelPGvoNZrr6Z8Uw8rl1EXcLvPTJsqR17snRwWCWLR6ewAc
+XbI=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/RFC3280OptionalAttributeTypesCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/RFC3280OptionalAttributeTypesCACRL.pem
new file mode 100644
index 0000000000..106a0215db
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/RFC3280OptionalAttributeTypesCACRL.pem
@@ -0,0 +1,14 @@
+-----BEGIN X509 CRL-----
+MIICGzCCAQMCAQEwDQYJKoZIhvcNAQELBQAwgZ8xCzAJBgNVBAYTAlVTMR8wHQYD
+VQQKExZUZXN0IENlcnRpZmljYXRlcyAyMDExMRUwEwYDVQQHEwxHYWl0aGVyc2J1
+cmcxDTALBgNVBCoTBEpvaG4xCjAIBgNVBCsTAVExEzARBgNVBEETCkZpY3RpdGlv
+dXMxCzAJBgNVBAQTAkNBMQwwCgYDVQQsEwNJSUkxDTALBgNVBAwTBE0uRC4XDTEw
+MDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqgLzAtMB8GA1UdIwQYMBaAFJtubz+K
+p/TntYwxW86ZS5EcfHy9MAoGA1UdFAQDAgEBMA0GCSqGSIb3DQEBCwUAA4IBAQBB
+32Yrko9n8ahvFVhspRmxscM7BMFLDBPKByEzJomnbztKvfw1bn4lsO39UIuBQgbS
+u+w1ZEnc3FcTvU0KjPNUA8e3eiuRzhct1XtqCPo7OmtFZDP7HQaCC0M7bxLiD56K
+00ww0RoiC8Vx0TI8+A+dZIQH1g19xShQ2WGquQLC26Wcf4FeXCTS/aaPeCGurbKD
+RBpShJHmZ2zFUZy0Wyu/FG+LMQpJf/ypy5dzYO94rHYMOdjfk4q17d9rLbtzyIZl
+GIOuZHdlBJi1uVKKOWFJHc1KIEbf2dc3AOfRAcZnvWZ9cBJpm51VC3FNPjqBtxVm
+OSHxymJkNoLCs4Rr1cCL
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/RevokedsubCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/RevokedsubCACRL.pem
new file mode 100644
index 0000000000..f07d7b88bf
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/RevokedsubCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBwDCBqQIBATANBgkqhkiG9w0BAQsFADBGMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEWMBQGA1UEAxMNUmV2b2tlZCBzdWJD
+QRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAvMC0wHwYDVR0jBBgwFoAU
+lm+SmaDpdnS7X9T4+xnZzx0FoO8wCgYDVR0UBAMCAQEwDQYJKoZIhvcNAQELBQAD
+ggEBAB+FPq0gPzR/ldksUu2y1NFGBtliXqr8+2YkuC3znY6aUv+jZG4MgXN/m30I
+hs7lxydqbF2ubdw6Er9PhmvJcnH92BREyAAUHt3zzHbCK8WKmwdofIK/tFrXr0XO
+eGPfmfmm8oHJREcNQ2ftaCvq7eTy61KqVno+p4KNKLPxWvR2uahuhFxgIXZlJVQF
+lSIPCEPGT+t+tSxFQ7RevCv9jl9KFIf8hEWpLxjxY44uucZlQaLFV0oRiiuB7Cq3
+xYM0xa8uZ5/xuBu9MJ1TKg+LWqp6dwd3BRo4BxbBHOwNeUJ+PtaR23AAoiL7s5mt
+bsFxXB0TfszCLEmLmFFfkuB6m6k=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/RolloverfromPrintableStringtoUTF8StringCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/RolloverfromPrintableStringtoUTF8StringCACRL.pem
new file mode 100644
index 0000000000..912b6c8b8f
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/RolloverfromPrintableStringtoUTF8StringCACRL.pem
@@ -0,0 +1,13 @@
+-----BEGIN X509 CRL-----
+MIIB4TCBygIBATANBgkqhkiG9w0BAQsFADBnMQswCQYDVQQGEwJVUzEfMB0GA1UE
+CgwWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTE3MDUGA1UEAwwuUm9sbG92ZXIgZnJv
+bSBQcmludGFibGVTdHJpbmcgdG8gVVRGOFN0cmluZyBDQRcNMTAwMTAxMDgzMDAw
+WhcNMzAxMjMxMDgzMDAwWqAvMC0wHwYDVR0jBBgwFoAUtW1PKD/Hu7GYpKml0Khb
+Xkp0s+cwCgYDVR0UBAMCAQEwDQYJKoZIhvcNAQELBQADggEBAFPDLO8fJtAH7E7z
+iHWXjzFLzoHGbLXSioC2TDR+Fm3hAOwdSphltknYwSxA0SyKeru8c8RVOu0fd7dS
+CaXmFaYL9CE4HREg1zFtuSPsElkhuZgi5N2cijO4oXUgdJsssFe3O/jWTBixJONF
+ZoAu4pjxi1mcNYDK5jn45jB25RNnjvhTm84I0o5/RQOp9vzpT5V60F3npWI8m7PQ
+UswjVucpjvslv2rPZEN5DldNgg+/W/qElgRFa+loYjeJyYRftsknzt8F1g2fzC7i
+k7fJTv0ZgFOk3tdUZhFHC3DNcwb6uscyTEdodNzaPhqoNHgUBdCqbUq0zZQXsIz4
+Sfp0ZJk=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/SeparateCertificateandCRLKeysCA2CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/SeparateCertificateandCRLKeysCA2CRL.pem
new file mode 100644
index 0000000000..e3b1f68960
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/SeparateCertificateandCRLKeysCA2CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB2DCBwQIBATANBgkqhkiG9w0BAQsFADBeMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEuMCwGA1UEAxMlU2VwYXJhdGUgQ2Vy
+dGlmaWNhdGUgYW5kIENSTCBLZXlzIENBMhcNMTAwMTAxMDgzMDAwWhcNMzAxMjMx
+MDgzMDAwWqAvMC0wHwYDVR0jBBgwFoAUE4Q9hI8eqnyBd18x3c1g85eX2bEwCgYD
+VR0UBAMCAQEwDQYJKoZIhvcNAQELBQADggEBAKN55WtVRJBOZvbUAlZXukKilUzr
+4Z8lHcq4fiql8hc6UUhmYAc/7MdfDa3NqgbUoVg7aUngm52yLgXubmnMztA5Vqum
+CXiNSmJ5AVWh7GCs8pdMHFLpFqnh1y4RTpt4AjYFC+xc18gSrsyDKWv7YEYVyQG7
+GHA9JEMm3SpSgh3B872L+neVTTMrO/bHKl54QGGp1tasaLdTkRVB/002yGBraVvE
+zfC7szqOc5v0tl4e3VrUBcNfn4QTDvl5PfrovZdPJP3Ys7139K38+kT/2YwCJ6M4
+EOAhyfzVSTgvuFoB+UlYIt10c5GA7J7pDJr4PCGTzR1K7XesSFuZCbD5Ddo=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/SeparateCertificateandCRLKeysCRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/SeparateCertificateandCRLKeysCRL.pem
new file mode 100644
index 0000000000..9e3ca350cc
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/SeparateCertificateandCRLKeysCRL.pem
@@ -0,0 +1,13 @@
+-----BEGIN X509 CRL-----
+MIIB/DCB5QIBATANBgkqhkiG9w0BAQsFADBeMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEuMCwGA1UEAxMlU2VwYXJhdGUgQ2Vy
+dGlmaWNhdGUgYW5kIENSTCBLZXlzIENBMRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMx
+MDgzMDAwWjAiMCACAQIXDTEwMDEwMTA4MzAwMFowDDAKBgNVHRUEAwoBAaAvMC0w
+HwYDVR0jBBgwFoAUcopDCwRbPT3EVeGDxp/fkMrq914wCgYDVR0UBAMCAQEwDQYJ
+KoZIhvcNAQELBQADggEBADQCnzJmc0jLQFb6EQ2iJDMcxrSuJftSikSCoKvuRTTH
++4cqd+xjh+kkZ1FCCmG6mY/hlnLTlKYqJlrJuu/vhHZP6XYwqkrtyx23ORmAOyq7
+SAuTvPBOPRo9HyvVWWHITgAKA90A0XUK+/zg1MRKgqqslTOaNXCqhu+nvshCtLx6
+MLsCYH5LVs3GimWfsT7wSpF4cqI4QyfZLJDtGz++9M7s03LvH6QNfQ0qrSaOdCfk
+hsdtNEzNFOOy34JejUZIDie83zj7Vgr1v6Gx+c5xkoDemggV/wzLYi7Si45JQBrJ
+trqjdLNOoS7QFadH/Vw7zL06Fahe2uUOOsXac76NQl4=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/TrustAnchorRootCRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/TrustAnchorRootCRL.pem
new file mode 100644
index 0000000000..114e6e1cbf
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/TrustAnchorRootCRL.pem
@@ -0,0 +1,13 @@
+-----BEGIN X509 CRL-----
+MIIB4zCBzAIBATANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEVMBMGA1UEAxMMVHJ1c3QgQW5jaG9y
+Fw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaMCIwIAIBaBcNMTAwMTAxMDgz
+MDAwWjAMMAoGA1UdFQQDCgEBoC8wLTAfBgNVHSMEGDAWgBTkfV/RXJWGCCwFrr51
+tmWn2V2oZjAKBgNVHRQEAwIBATANBgkqhkiG9w0BAQsFAAOCAQEAqxkdtbsha7bh
+TM3wtzeelTjR1IGQgK4R8Psc2fw2NOydlq8PeSc3qitHV6m4dqHzchQlytYprOK4
+dRitEh+RYY4UKUNu+OQQ5VFLSvuC0Wv3xn2w29VqpQtavBFfJ8Lst9520pece6x8
+6fB9L6VP4YNGIrLc+7hEjEDALJs+ttPoxNNXGMApQQi5xyZEksXQAo60ZdH/r95l
+dVCa7U2OVXO1MCuZlWQRlql0Bi3CzE26cW1jccEdU6yQ0ONKNuROR+6NsXZ2Qm2C
+lHEGWFJAZ/CWB7NjQ9maNkoioZb4IB2AKPKBcb0mT3TYspgT8zcZSP5DLC8iVOrc
+x2SLSvd35g==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/TwoCRLsCABadCRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/TwoCRLsCABadCRL.pem
new file mode 100644
index 0000000000..526eb1f6e1
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/TwoCRLsCABadCRL.pem
@@ -0,0 +1,13 @@
+-----BEGIN X509 CRL-----
+MIIB7jCB1wIBATANBgkqhkiG9w0BAQsFADBQMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEgMB4GA1UEAxMXQmFkIENSTCBmb3Ig
+VHdvIENSTHMgQ0EXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFowIjAgAgEB
+Fw0xMDAxMDEwODMwMDBaMAwwCgYDVR0VBAMKAQGgLzAtMB8GA1UdIwQYMBaAFBCh
+AdaZnYDjbf3n7ndLX/FJ2TxTMAoGA1UdFAQDAgEBMA0GCSqGSIb3DQEBCwUAA4IB
+AQB+8PsN24d0Zz4YP749N8IiCoLpju5Z7O2yP6C4n3XwSRKExXK5ROwg9adTW556
+L44a0aChbR1b7Mnz/du0vx67O0D6hMRhS7ICuiI+pkpovJsVnT2QdObWBlls2Bic
+e+iSX+eIlXHcURQc0ZkhvKiiDYgxeSo4RvxknjaauHKdIA1DQC1G2IFU+Izjg7j0
+pS5yeLaGtz7azDmrChRrP+XRCDjsSuihtS9dtDRTyUwRYjhU6plkHjjwvXaFh3EW
+ZQWN0LVL7m7M2MtXUPlKYlEG8SpcrfBS25aBg4tRLRo8w/iWY0Z3HcRYYj9HiZhU
+3Yo0R0Z2apWmbVVmxNJQy+jA
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/TwoCRLsCAGoodCRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/TwoCRLsCAGoodCRL.pem
new file mode 100644
index 0000000000..7bffa1d5cd
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/TwoCRLsCAGoodCRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBvjCBpwIBATANBgkqhkiG9w0BAQsFADBEMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEUMBIGA1UEAxMLVHdvIENSTHMgQ0EX
+DTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqgLzAtMB8GA1UdIwQYMBaAFBCh
+AdaZnYDjbf3n7ndLX/FJ2TxTMAoGA1UdFAQDAgEBMA0GCSqGSIb3DQEBCwUAA4IB
+AQAWgigQQEvB+tF9ELpYI007J23N+XwGsg5vz8wIxMsi5Sa3NDkUCZ8ByXClFLRp
+zIM650GcrIDpZCHPhfgT9bU2b2LX/4vVdSy/aI7tC+nd70UPKeH4SU7sVwAJmKQD
+NRnWLJp7VXl79yR51SEMKrwNpgoFmblJHKcLyNr8NrwmLmS/5mpGaeri0bEh53cy
+Zv9dvJI6Nvh30wbYtcEtURtCSHWYlIYs8cQML4IsYcQbWSX8uS4XqSnaUVwYKtFT
+HdUX46XIkuGdKeExJKbWXb9R9JJcCG85Qn+mfX+Z0XatgOxGpmuzJ/JbEqxPS+w0
+25GOIJTaYjoDxoOmVIpJZGcZ
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/UIDCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/UIDCACRL.pem
new file mode 100644
index 0000000000..c94eb68a11
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/UIDCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBuTCBogIBATANBgkqhkiG9w0BAQsFADA/MQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEPMA0GA1UEAxMGVUlEIENBFw0xMDAx
+MDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoC8wLTAfBgNVHSMEGDAWgBQQP8UEMPHY
+QzaFeVyMjYud7i8cqTAKBgNVHRQEAwIBATANBgkqhkiG9w0BAQsFAAOCAQEARJT8
+6342NMtFGT+8uvbJJ26LNypeqnke2LqSnfunR258riLofJj2E5r1NS7Ew5YjWdZH
+3BiwowR/IRuFqlj1l7gDB6L9YFVbNuJrC41UxIBzGMa2zHtTXxe610TC987XcbbT
+O4ccPzvQ3MEfiY7odLNkOpKfOHUTgOvPfpo/8X/jofZp0kBTH7q31S4XKH1XHBab
+H2kyudXTJmNkSXOdXlclPdZ1wdtt5hi/i5mYMQYnwVgQoburqiAt1LurPrOi6zgK
+JmfT7ELdKocAa0nRCBMMTZLknEAVubFfI1ViKGMGwolmVIQjlJrI7h6RMh4bUEVI
+eDsOknaIs9a+DRxKNA==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/UTF8StringCaseInsensitiveMatchCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/UTF8StringCaseInsensitiveMatchCACRL.pem
new file mode 100644
index 0000000000..a6c2055e8e
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/UTF8StringCaseInsensitiveMatchCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB1zCBwAIBATANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJVUzEfMB0GA1UE
+CgwWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEtMCsGA1UEAwwkVVRGOFN0cmluZyBD
+YXNlIEluc2Vuc2l0aXZlIE1hdGNoIENBFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEw
+ODMwMDBaoC8wLTAfBgNVHSMEGDAWgBRg3xjRyqlQkhEXIUTSd/Vqraa+eDAKBgNV
+HRQEAwIBATANBgkqhkiG9w0BAQsFAAOCAQEAfnKj08ZVDYA3KZCzOUW4VvkN0rgV
+qYukj5p80KK3oRJtQjiMB7M+BrG/Nu2ReWIrB2vSyryurZD2QeTcJOr68b0I/VLV
+uz4/b1/AlXgvUywrMiaXKrW/dApifr70HDghgvyCwQ1SDST/jFNBmrC//H61A3NG
+PenyRN+GkvTzlOIoJcqZ4PRX7J28D9lesW4m8Z+k7o/mF0c2F2lBMG+yzTh9ZB5W
+eaqvmY63gKTu3GRUHET6/SE2HI1fgioVFPDutr5b1uh9ACA60X+Lkg6MBhPqPGdY
+UQXKBt92Nd1aHg18VydBY9+6yBEvlQfpZyaQ/Sx7TL0SSwzKlcGDwXvVXA==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/UTF8StringEncodedNamesCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/UTF8StringEncodedNamesCACRL.pem
new file mode 100644
index 0000000000..2bfdb97dcc
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/UTF8StringEncodedNamesCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBwDCBqQIBATANBgkqhkiG9w0BAQsFADBGMQswCQYDVQQGEwJVUzEfMB0GA1UE
+CgwWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEWMBQGA1UEAwwNVVRGOFN0cmluZyBD
+QRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAvMC0wHwYDVR0jBBgwFoAU
+O2dbRPINp0h9cymMk5/VJOMSYCYwCgYDVR0UBAMCAQEwDQYJKoZIhvcNAQELBQAD
+ggEBAE2uI86u6pYfkenx+nHcN7B8ymkICJpPJlIqNfjteDVjwz9D2ra89nHKdXRE
+83ftELk0cXxN4qEuylBI+2V/WUNjll1VsTqvRSGDFu6KhjZHEjbdGHu2Z+tT7E9a
+72X3hxYJEDycSTlaR4OvFUWeKksPaKXt6HdhV7AQUHT9KbewgLDekpPKj1O1tjzs
+/NN2mt0mBqbm9dzi4oL2PezZLfEOpa1BXQR9r37HWKmDxO4SixOGNaOd+jplpzhy
+PDqftcMmgRZnKesEvKcXul1GRxreqhaF+dlvluKwzRgC9Z0x8iS8HyoqlCzdGy8x
+OuRJvqqfg0aPDn/waUA0pF7Qfwo=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/UnknownCRLEntryExtensionCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/UnknownCRLEntryExtensionCACRL.pem
new file mode 100644
index 0000000000..dfee3b2056
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/UnknownCRLEntryExtensionCACRL.pem
@@ -0,0 +1,13 @@
+-----BEGIN X509 CRL-----
+MIICCjCB8wIBATANBgkqhkiG9w0BAQsFADBXMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEnMCUGA1UEAxMeVW5rbm93biBDUkwg
+RW50cnkgRXh0ZW5zaW9uIENBFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBa
+MDcwNQIBARcNMTAwMTAxMDgzMDAwWjAhMAoGA1UdFQQDCgEBMBMGCWCGSAFlAgEM
+AgEB/wQDAgEAoC8wLTAfBgNVHSMEGDAWgBQAphnLoS1NKC8i89JMN8//TDDN6jAK
+BgNVHRQEAwIBATANBgkqhkiG9w0BAQsFAAOCAQEAIGIA0Yful35UcVgnqPFFJiLX
+VB8WXGbleSexbAb9EgxCCpffOaMuaq51McJ+Rjspyjmn0SEnbnpeKmNbmYtnQjn0
+OxNp/Yy5ZwjufitxKb9JgFLBhfpJ2BU9H5MgPEmXA+aZf5ojGPh/2afwJKE/9H22
+wemiZlYlpA5aN7PYqWHfEPE2bd4Ey7RHleuCRpfDHx2EgumLSRYjm9q++THgGOgu
+C59aDH3vvuAItfh9eVHTYxxjRm9kjIC/RCrCvQRclRGN/SoPDBys9RQxv1iklvN2
+rLH+Os+0BB3L67GMsAFQhWXCFU6U9Yubm/mErDVFOwsmuMNNKgojKkuqAhxZzQ==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/UnknownCRLExtensionCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/UnknownCRLExtensionCACRL.pem
new file mode 100644
index 0000000000..8d7158e411
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/UnknownCRLExtensionCACRL.pem
@@ -0,0 +1,13 @@
+-----BEGIN X509 CRL-----
+MIICBDCB7QIBATANBgkqhkiG9w0BAQsFADBRMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEhMB8GA1UEAxMYVW5rbm93biBDUkwg
+RXh0ZW5zaW9uIENBFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaMCIwIAIB
+ARcNMTAwMTAxMDgzMDAwWjAMMAoGA1UdFQQDCgEBoEQwQjAfBgNVHSMEGDAWgBT9
+//4ZTdsMncWi2IJW67DZEGHjMTATBglghkgBZQIBDAIBAf8EAwIBADAKBgNVHRQE
+AwIBATANBgkqhkiG9w0BAQsFAAOCAQEAsguh6rQBEGU98+Fqtl5R79QDu51NuNZF
+H2otyBt8ZPFJkif8J/pquv09GgIMFsMbAtMGkVPNYEjnQ6MHSWYE2SxTYeIfOnQb
+JiED6NtncdUGsoXt2g+9gJTDdVPjl8z9p1j1QEdp6c/XEj2gEVGDkM2iAy/3QImN
+kqrG1n1QtiAOUQ1oZoIk6NnGfAvRQ5/eNZafTa7vm805Q11tE6mT8XwbUX9Cs/lL
+X5h3h7DATdVfDPYwac9NZ8rrof7FQ/jXB4p2P5PM/U2vqEM8YTuRhW2w+jGzBFY6
+ef7bd7LrSoWExjczcmVuIZDqrxYsdAc4TJbQUm8B28FkdM4NzVo2Bg==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/WrongCRLCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/WrongCRLCACRL.pem
new file mode 100644
index 0000000000..114e6e1cbf
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/WrongCRLCACRL.pem
@@ -0,0 +1,13 @@
+-----BEGIN X509 CRL-----
+MIIB4zCBzAIBATANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEVMBMGA1UEAxMMVHJ1c3QgQW5jaG9y
+Fw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaMCIwIAIBaBcNMTAwMTAxMDgz
+MDAwWjAMMAoGA1UdFQQDCgEBoC8wLTAfBgNVHSMEGDAWgBTkfV/RXJWGCCwFrr51
+tmWn2V2oZjAKBgNVHRQEAwIBATANBgkqhkiG9w0BAQsFAAOCAQEAqxkdtbsha7bh
+TM3wtzeelTjR1IGQgK4R8Psc2fw2NOydlq8PeSc3qitHV6m4dqHzchQlytYprOK4
+dRitEh+RYY4UKUNu+OQQ5VFLSvuC0Wv3xn2w29VqpQtavBFfJ8Lst9520pece6x8
+6fB9L6VP4YNGIrLc+7hEjEDALJs+ttPoxNNXGMApQQi5xyZEksXQAo60ZdH/r95l
+dVCa7U2OVXO1MCuZlWQRlql0Bi3CzE26cW1jccEdU6yQ0ONKNuROR+6NsXZ2Qm2C
+lHEGWFJAZ/CWB7NjQ9maNkoioZb4IB2AKPKBcb0mT3TYspgT8zcZSP5DLC8iVOrc
+x2SLSvd35g==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/anyPolicyCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/anyPolicyCACRL.pem
new file mode 100644
index 0000000000..d8cd6550ee
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/anyPolicyCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBvzCBqAIBATANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEVMBMGA1UEAxMMYW55UG9saWN5IENB
+Fw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoC8wLTAfBgNVHSMEGDAWgBS7
+yd7IHJXnQuKQoo6uA1yrJGB+hTAKBgNVHRQEAwIBATANBgkqhkiG9w0BAQsFAAOC
+AQEAW7i6zdMI6ytGpku8kYKf2WVx9tqIMFh+vvcagsWR/9oPNp1kXgdfv/tfRS9F
+JRQ3RVYaKY2bWDVc8ISsrwZpBMe3RjfDEdqAyuNcy4B/C+O7OAtyNinAvtsYASAU
+gfDoW3s1V53iLbLDfY1uRCq7F78dHwjuuIob+tpHFR9EVUx3MgkPAyq8oLrbDdaV
+FAsq2XTgry00qj82bR0rSY7UdNMOhDy32qeoH4ZEEh0XHdBEM3xuMjwn6x6J2SiV
+96FDpO+UNcTr/VeV9sx0xJAJOqmSU+e8nL8FKCGhm02fI9CIZBV4TOICDgacRgOn
++aSLkS+XcWlyrkZL2FakdOWiXQ==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/basicConstraintsCriticalcAFalseCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/basicConstraintsCriticalcAFalseCACRL.pem
new file mode 100644
index 0000000000..b5726c158e
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/basicConstraintsCriticalcAFalseCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB2DCBwQIBATANBgkqhkiG9w0BAQsFADBeMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEuMCwGA1UEAxMlYmFzaWNDb25zdHJh
+aW50cyBDcml0aWNhbCBjQSBGYWxzZSBDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMx
+MDgzMDAwWqAvMC0wHwYDVR0jBBgwFoAUcN9ELwOZHBdzGPI2PBQ00AnR8u0wCgYD
+VR0UBAMCAQEwDQYJKoZIhvcNAQELBQADggEBAFaK4KYhrGo/o9KPU/OnZGglN4vq
+uuAH6a9XjvSUA/de1oHyAxw6rgxrjBo1pgtdLgSqXuYXMeqyVjZV5ew58wd7f0vG
+u06a6f3TOX3ScNZYY9/u1VRsX8/y3kKUg2+EQdr7vYCjhSIc2SLqpAnku150OwB9
+GZG7y/NRjqX9AyecyCJm16G/w9fA4+tndtvBvvDIwYn+LGrse5cgka4iR+CWzsIj
+cA17nCnhg3n88NSXrIsre1LI1YBKEHrIqbTpDglDxtJcdTtF+5/new5L+vftj0Rv
+8bR8NQPo5DBNJ5C9GnCjQgVSyMnQNhD3+LUDDScGs0QVg981FI6tusPFZpE=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/basicConstraintsNotCriticalCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/basicConstraintsNotCriticalCACRL.pem
new file mode 100644
index 0000000000..3dfeb7ca4c
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/basicConstraintsNotCriticalCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB0zCBvAIBATANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEpMCcGA1UEAxMgYmFzaWNDb25zdHJh
+aW50cyBOb3QgQ3JpdGljYWwgQ0EXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAw
+MFqgLzAtMB8GA1UdIwQYMBaAFAqkuTBDrEPINAITz+9V6L9wn0avMAoGA1UdFAQD
+AgEBMA0GCSqGSIb3DQEBCwUAA4IBAQBY/ZWklRmCU6F7pRzO8mrG3iaF2gp4Qyse
+QLf/yzlYy5XdbwzhwiClQ7EwxA9jaGD8EKopJL9sMh53QBZFivrXUP+O09cHRlMI
+SCyonmbdvnOUDwoky9YY4KrC0YI+mhbOpe6LQJcRgj2ge5C1i+UsQmUZapOUvXaI
+f5rc1TlLg4mlxYSQT9jnLV3aAwt4i6cwitTkpbYPolvjsHqfRQ2/aLLd59SNnIlv
+pdso7IaAW3aoo38dJ8ZyJZBwNAwR3dmi4oIOivHX6FwDgxNdhVIN5X/VsMeNbRu/
+mD1HePYlexWjcMfsVRx9oVsIVoT0i8dAXEnefM7n1XOadWnaW8Di
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/basicConstraintsNotCriticalcAFalseCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/basicConstraintsNotCriticalcAFalseCACRL.pem
new file mode 100644
index 0000000000..36b9df8549
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/basicConstraintsNotCriticalcAFalseCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB3DCBxQIBATANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEyMDAGA1UEAxMpYmFzaWNDb25zdHJh
+aW50cyBOb3QgQ3JpdGljYWwgY0EgRmFsc2UgQ0EXDTEwMDEwMTA4MzAwMFoXDTMw
+MTIzMTA4MzAwMFqgLzAtMB8GA1UdIwQYMBaAFDnQm7dPKTe+07CKdupqns3vRr5Y
+MAoGA1UdFAQDAgEBMA0GCSqGSIb3DQEBCwUAA4IBAQB5jwS9LsJUqzevwbstTFfJ
+TrsCQBjg8kn30zn2Yi0+ff92y1zfpzK3MSFfq9olKCKSpoKdwgLTZVXiHsO44X4d
+cIzo03knrnXX6wAQH0b/GXlbvQ9fEZaylTxMV7mO38UgIs9cWXdqjlsgAy37qOBT
+L5Dn2xUp2u/+QcbwyLOGP7/shriabGHlepclCQI6BxIor8gJz2zCxtovV90j7WL0
+8nF8wMwVv89hu38b92uORIQDamYDRTigiOYS5FPTirqoReA9lUdQ+hd3KaS1S/YE
+w7fmNEbkdCMg4hHAYnR0xW54Bp9bea2ANRJmdwUCz930q3XqPS8OJt/PZgOAmdYa
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/deltaCRLCA1CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/deltaCRLCA1CRL.pem
new file mode 100644
index 0000000000..338d64cd37
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/deltaCRLCA1CRL.pem
@@ -0,0 +1,16 @@
+-----BEGIN X509 CRL-----
+MIIChDCCAWwCAQEwDQYJKoZIhvcNAQELBQAwRTELMAkGA1UEBhMCVVMxHzAdBgNV
+BAoTFlRlc3QgQ2VydGlmaWNhdGVzIDIwMTExFTATBgNVBAMTDGRlbHRhQ1JMIENB
+MRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWjBmMCACAQIXDTEwMDEwMTA4
+MzAwMFowDDAKBgNVHRUEAwoBATAgAgEEFw0xMDAxMDEwODMwMDBaMAwwCgYDVR0V
+BAMKAQYwIAIBBRcNMTAwMTAxMDgzMDAwWjAMMAoGA1UdFQQDCgEGoIGKMIGHMB8G
+A1UdIwQYMBaAFHcYI+V2hMgUlD+C0IHqdLHgpC8zMFgGA1UdLgRRME8wTaBLoEmk
+RzBFMQswCQYDVQQGEwJVUzEfMB0GA1UEChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAx
+MTEVMBMGA1UEAxMMZGVsdGFDUkwgQ0ExMAoGA1UdFAQDAgEBMA0GCSqGSIb3DQEB
+CwUAA4IBAQCEUqY7TzVnZWYlyrtBszCIhhTKhr7tH5UHvoZkNs8lzeBMqtUDZvd6
+o0mB7WSv5R+t8tGleNhn4isudltqLAWZxxZNnht04o3YZTwKS/NRNAinBoQfZnmw
+abMmledsFuF2JrA3XYOZ5NWdlah8/MPUAKRoI0Dw7qxmLL/exsz5OAKh3qjXlzwJ
+Bdm4CYCO3DH58BQk6oJKVlqCY3ZsCuvtvjNHnLpkXAKRQ+t/OsHWssYkEVX5FizE
+WE6G6XMMcQtb2gN0QwzO8o3xyFGYyy1gkEuB+yzmqHqLYTlRZd5IvRxYYoqHbrce
+x7ROIMJEsNFw5k+b7qWYLo703GOsCxD0
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/deltaCRLCA1deltaCRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/deltaCRLCA1deltaCRL.pem
new file mode 100644
index 0000000000..4c306accba
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/deltaCRLCA1deltaCRL.pem
@@ -0,0 +1,15 @@
+-----BEGIN X509 CRL-----
+MIICWjCCAUICAQEwDQYJKoZIhvcNAQELBQAwRTELMAkGA1UEBhMCVVMxHzAdBgNV
+BAoTFlRlc3QgQ2VydGlmaWNhdGVzIDIwMTExFTATBgNVBAMTDGRlbHRhQ1JMIENB
+MRcNMTEwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWjCBiDAgAgEDFw0xMDA2MDEw
+ODMwMDBaMAwwCgYDVR0VBAMKAQEwIAIBBBcNMTAwNjAxMDgzMDAwWjAMMAoGA1Ud
+FQQDCgEIMCACAQUXDTEwMDEwMTA4MzAwMFowDDAKBgNVHRUEAwoBATAgAgEGFw0x
+MDA2MDEwODMwMDBaMAwwCgYDVR0VBAMKAQigPjA8MB8GA1UdIwQYMBaAFHcYI+V2
+hMgUlD+C0IHqdLHgpC8zMA0GA1UdGwEB/wQDAgEBMAoGA1UdFAQDAgEFMA0GCSqG
+SIb3DQEBCwUAA4IBAQAFVo99MjLWWcc8kdu/qveAAPZgvgHBAQqOygCNbu4J704l
+Ab9wHTJoNvghxK7iGsCGd2O7l1ODdooPWNcY3NVkY2soZmevk5F19MQX7fr4HrLp
+Dtcdfbby1PG2TX0MttfwpGDh8yfO1SFjkclmoP8f1f8mrmulJcy/sXK+H478JHO1
+lycEzMsvgGj2HCZvRziR+g3nH2AVMra4r6u+oo1ctwcWWGRkhfuyeBBJWDMh3T61
+gIbdB+Atjs3QBscvjPdU+F5XyuaBLbwEBYJOoTeSKTxfDVeYnPFghHyenItJsmII
+5IPocdTk/6/RB0wtDlMQwjNUXxe0/3WoHVy8bUQZ
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/deltaCRLCA2CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/deltaCRLCA2CRL.pem
new file mode 100644
index 0000000000..b4090dfee4
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/deltaCRLCA2CRL.pem
@@ -0,0 +1,15 @@
+-----BEGIN X509 CRL-----
+MIICQDCCASgCAQEwDQYJKoZIhvcNAQELBQAwRTELMAkGA1UEBhMCVVMxHzAdBgNV
+BAoTFlRlc3QgQ2VydGlmaWNhdGVzIDIwMTExFTATBgNVBAMTDGRlbHRhQ1JMIENB
+MhcNMTAwNjAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWjAiMCACAQIXDTEwMDEwMTA4
+MzAwMFowDDAKBgNVHRUEAwoBAaCBijCBhzAfBgNVHSMEGDAWgBR82Pa+A0zOz7c/
+oRm7M6u11437xDBYBgNVHS4EUTBPME2gS6BJpEcwRTELMAkGA1UEBhMCVVMxHzAd
+BgNVBAoTFlRlc3QgQ2VydGlmaWNhdGVzIDIwMTExFTATBgNVBAMTDGRlbHRhQ1JM
+IENBMjAKBgNVHRQEAwIBAjANBgkqhkiG9w0BAQsFAAOCAQEA57Gy4XXEzOgR+KG2
+Yc4w8HgmX79ERY3s082LNYuSwFrA3D7hoCa+tX8tuXbF6Kgb+wocIFROzk7r+ZIp
+PegSzJQcKWoVCQiuHUfBt3MVZLojeM4n8ThfMbPOnf+Si+V4YgEcBGcgKt/pxEnZ
+d1dJu+rB+TSyUk4QuJ5X2DJn4ne+2Wf6mzoZKakJp61aDD5QxysbN/52R9QR/wdg
+awyL5mtu/8U342t+4sFbLm7X/pyDcPkp9on2ORsKGIBGGr3QoHItIAZn2ghPsT6a
+5YYcJOUm/pZwBeKoZyQ+s9Lhon5HOWs5aE3KwFdS5vo1zpB2Ps9Sv4ud2+O135oG
+tuFQTA==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/deltaCRLCA2deltaCRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/deltaCRLCA2deltaCRL.pem
new file mode 100644
index 0000000000..d305bae0ab
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/deltaCRLCA2deltaCRL.pem
@@ -0,0 +1,13 @@
+-----BEGIN X509 CRL-----
+MIIB8jCB2wIBATANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEVMBMGA1UEAxMMZGVsdGFDUkwgQ0Ey
+Fw0xMTAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaMCIwIAIBAhcNMTAwMTAxMDgz
+MDAwWjAMMAoGA1UdFQQDCgEBoD4wPDAfBgNVHSMEGDAWgBR82Pa+A0zOz7c/oRm7
+M6u11437xDANBgNVHRsBAf8EAwIBATAKBgNVHRQEAwIBAzANBgkqhkiG9w0BAQsF
+AAOCAQEAWX5v6H6qmSiro3ZgYkvIi4WDhAzCpjMNElzQ7rs+mPh/1B/2CSAv+B9Q
+RXHJvMYS0XEwfvTy3N5vAhY6QMNhPKJcepJHVmng0NMOBn3DMJJ7nobJKAA95ls8
+/BP+nNjVHoq7RnLivTxvXOijGGCJACg3st64CByuwcbNcJdEJkI0usFnLEoA8W9Z
+G47VSzeORnf3EmA4IZERhS7NY3+91CDRb8R0CO0u8sVVPPWMltdN0WYSnQA9D4oV
+hOEunai3vsrn7DVSsoTrIWz7zxgIgxk+6sfaWhGIKVLW34lIdA2geMWt446/maWg
+E/O9OWirLi1qY7bp8BcCUe9UL/cfOQ==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/deltaCRLCA3CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/deltaCRLCA3CRL.pem
new file mode 100644
index 0000000000..084e49127f
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/deltaCRLCA3CRL.pem
@@ -0,0 +1,14 @@
+-----BEGIN X509 CRL-----
+MIICHDCCAQQCAQEwDQYJKoZIhvcNAQELBQAwRTELMAkGA1UEBhMCVVMxHzAdBgNV
+BAoTFlRlc3QgQ2VydGlmaWNhdGVzIDIwMTExFTATBgNVBAMTDGRlbHRhQ1JMIENB
+MxcNMTAwMTAxMDgzMDAwWhcNMTAwNjAxMDgzMDAwWqCBijCBhzAfBgNVHSMEGDAW
+gBTvY9OoTrH532HiDcMFo5gY0pOZ5zBYBgNVHS4EUTBPME2gS6BJpEcwRTELMAkG
+A1UEBhMCVVMxHzAdBgNVBAoTFlRlc3QgQ2VydGlmaWNhdGVzIDIwMTExFTATBgNV
+BAMTDGRlbHRhQ1JMIENBMzAKBgNVHRQEAwIBATANBgkqhkiG9w0BAQsFAAOCAQEA
+XB3lEAs1DWFKrU3BzflSTtmiCa5KzMZrXpDmqHt7+kWNjEMUS17TsvkrfGWOcEFJ
+9MzmGUqAuD9Z0q5kxVVNRuZhG8K9U+biCmMVFtKzxFGbz/vJkcKaroB/ukiqNQlv
+DTSKebUJJm5g0rc06LVGic+YgK2pcCwm4BsdmcCEYV3mlIhUOUA48Ww0WemFKPTw
+9A1V3URGpOzrMJYJOJff0IOVjdyGwSc+xHCtbJG4xV+/Qe1/9yYn+RqHQXUo0C7D
+GJNSr+OcpXX8urZQp4ZVQRz3OTs4eb2xRK1ZPj9Xhiv98iZwo38GaFGvMhOHv7gv
+C13eDAq4KnlQgz/wpxmHog==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/deltaCRLCA3deltaCRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/deltaCRLCA3deltaCRL.pem
new file mode 100644
index 0000000000..db02c94369
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/deltaCRLCA3deltaCRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzjCBtwIBATANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEVMBMGA1UEAxMMZGVsdGFDUkwgQ0Ez
+Fw0xMDA2MDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoD4wPDAfBgNVHSMEGDAWgBTv
+Y9OoTrH532HiDcMFo5gY0pOZ5zANBgNVHRsBAf8EAwIBAjAKBgNVHRQEAwIBAzAN
+BgkqhkiG9w0BAQsFAAOCAQEAy7ylas55kqoznlqWS9cO6Q/EC7dPiZKF4Szp326L
+qCs4kd16Vbi3mhz7BP2iHSjO0AlaMnmGSYOlnzQEtuD6NlQB1RhuWH1kCWAaQPXU
+4K4nMJduHuGjopkIxnN8BGPfXGbeOJfl0FDQM84vkRCJ4Owq233JvEIDCEhdkYsO
+wQr+dUqPNkR1lz7fGtskqpe3aotkQ3DrS/1wuBRuTmXLKDZy63IdAe+TTp8yugnl
+9QEdYEXvMgLChLe57ZaOFVCE8349rkhikvnFWIfc1st2EsBrOaOwqFUrZReVg6qx
+wxDSf2FoINaLIX7ECkEBBmQh9SyEz8BXwaboI8z08ovRzg==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/deltaCRLIndicatorNoBaseCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/deltaCRLIndicatorNoBaseCACRL.pem
new file mode 100644
index 0000000000..781db0a18d
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/deltaCRLIndicatorNoBaseCACRL.pem
@@ -0,0 +1,13 @@
+-----BEGIN X509 CRL-----
+MIIB3jCBxwIBATANBgkqhkiG9w0BAQsFADBVMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTElMCMGA1UEAxMcZGVsdGFDUkxJbmRp
+Y2F0b3IgTm8gQmFzZSBDQRcNMTAwNTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqA+
+MDwwHwYDVR0jBBgwFoAU9Dh2Jauk4xzAyHWMjRNrYyO2ioEwDQYDVR0bAQH/BAMC
+AQEwCgYDVR0UBAMCAQUwDQYJKoZIhvcNAQELBQADggEBAJOY+1gmjxVv2D6HNyPt
+vKA7Gk7seNkgnSPoPR24Ao0znff3gjJGgz6r0TY7IIF+ddgjmu4l6BpkS2fN2Uow
+BCFEAD/0lK0RPtuyUCdbFiSHtNQlbpbxEK0iwDAw2YoYQZBP6qobz3IIjxIZjQou
+XlOIRoXE8Lg0QHFHQF58+Bs7Exk5kU8bwCalEL36OcGihMb9wXuuJTvSuXypU5v6
+kDwwrvxx06w9O2WYC8dqriObG8Uz04+Xt6alCmcj/sU2rop6BZMheZ8bKSHXCPWB
+FWIubsW25os4rHlxDz+DmXAcRCyIyrQxz9ERTDjPhKhAUPXz+baG38/oqA3bVMn4
+HKo=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/distributionPoint1CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/distributionPoint1CACRL.pem
new file mode 100644
index 0000000000..dc27f6b6fd
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/distributionPoint1CACRL.pem
@@ -0,0 +1,16 @@
+-----BEGIN X509 CRL-----
+MIICfTCCAWUCAQEwDQYJKoZIhvcNAQELBQAwTjELMAkGA1UEBhMCVVMxHzAdBgNV
+BAoTFlRlc3QgQ2VydGlmaWNhdGVzIDIwMTExHjAcBgNVBAsTFWRpc3RyaWJ1dGlv
+blBvaW50MSBDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWjAiMCACAQIX
+DTEwMDEwMTA4MzAwMFowDDAKBgNVHRUEAwoBAaCBvjCBuzAfBgNVHSMEGDAWgBQR
+MHO9jXAogtJvz9I37c3rI5Hb7zCBiwYDVR0cAQH/BIGAMH6gfKB6pHgwdjELMAkG
+A1UEBhMCVVMxHzAdBgNVBAoTFlRlc3QgQ2VydGlmaWNhdGVzIDIwMTExHjAcBgNV
+BAsTFWRpc3RyaWJ1dGlvblBvaW50MSBDQTEmMCQGA1UEAxMdQ1JMMSBvZiBkaXN0
+cmlidXRpb25Qb2ludDEgQ0EwCgYDVR0UBAMCAQEwDQYJKoZIhvcNAQELBQADggEB
+ACrxG+l579by89QJva16Yro3XPJ9lXu/l8cgQpoaHZifIG9TnaWxb4WFwSBIbOqp
+rbQW7N580RJBH2SqiiUmCu6Acg2ryKfywGULkFFd0ZYMBrhtHQe7T0SJq0NFtMlZ
+A9Vgia3Tqhiam3c1oJeZnETcn35b5qLAmr+EaRpXDT4Mflqwub0kgwal6p9wmuH5
+vs4dc98l/Ub+J+ve8yVmMVq/0YSGv5Z2IjX2V9iWdjcZPnAC3BaOMvm40zy5cOWJ
+FaXii7M41MgR4d8ZMQn/UQGb2CMypm207QW3yNbuI7+/0y0vxJDo2k84ktw6sAda
+dQBSIAUmYp0Rsdtg9TwZE00=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/distributionPoint2CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/distributionPoint2CACRL.pem
new file mode 100644
index 0000000000..1ebde75c29
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/distributionPoint2CACRL.pem
@@ -0,0 +1,14 @@
+-----BEGIN X509 CRL-----
+MIICJTCCAQ0CAQEwDQYJKoZIhvcNAQELBQAwTjELMAkGA1UEBhMCVVMxHzAdBgNV
+BAoTFlRlc3QgQ2VydGlmaWNhdGVzIDIwMTExHjAcBgNVBAsTFWRpc3RyaWJ1dGlv
+blBvaW50MiBDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWjAiMCACAQIX
+DTEwMDEwMTA4MzAwMFowDDAKBgNVHRUEAwoBAaBnMGUwHwYDVR0jBBgwFoAURGzu
+229/605Jf3j+zeUYoOy7YGswNgYDVR0cAQH/BCwwKqAooSYwJAYDVQQDEx1DUkwx
+IG9mIGRpc3RyaWJ1dGlvblBvaW50MiBDQTAKBgNVHRQEAwIBATANBgkqhkiG9w0B
+AQsFAAOCAQEAD560RltKzGwM+LefEKN9n+UE6uNAoPwiNSYPGe9Qcu9WXsG11CqZ
+O1saNKTu0+bMx11WU3qRDyGpWZidaW0/x60RcSMR/X/RGoZw2hlixluvHpIBQwYf
+H2V2PE+OjNIeXBF9uEAV5KuBRb/Yre7GlCoXJM1j9WZRCHKwVYZ2xNog9R8STNs5
+fw4kynvydxQ6U8KjUxJeBmb6PiAf64Mcf9AXUCjakwAKJgw2zptKV75QrEEwpnVj
+sv7A5HqoMS7mLwPV2dznH+rHn/0IJp1FuS9YNs4L7oTyKZYlriy7U5pmsHHajGIc
+6g5+w/GiX51Emsi7RXjAvfpu/9MisG29PQ==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/indirectCRLCA1CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/indirectCRLCA1CRL.pem
new file mode 100644
index 0000000000..c9de28ecb9
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/indirectCRLCA1CRL.pem
@@ -0,0 +1,13 @@
+-----BEGIN X509 CRL-----
+MIIB9zCB4AIBATANBgkqhkiG9w0BAQsFADBIMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEYMBYGA1UEAxMPaW5kaXJlY3RDUkwg
+Q0ExFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaMCIwIAIBAhcNMTAwMTAx
+MDgzMDAwWjAMMAoGA1UdFQQDCgEBoEAwPjAfBgNVHSMEGDAWgBQl+K/8r7apGht5
+S9vLZCyLS7EVzTAPBgNVHRwBAf8EBTADhAH/MAoGA1UdFAQDAgEBMA0GCSqGSIb3
+DQEBCwUAA4IBAQALqiVAlWG4BlkRVLdCVDqUtfpcaK8JLzEqoQUm4fS+Y+mdf9uA
+Q8+l8aQmcGeh/Gkufzp4bwsxkkxL81qTvuvDm4UV5q4TYz3aaWtzE/ewNWzLyLjA
+FQafw0u0ZTdXs5Z7R03DlwrGH27ZmMqjue8uV060HNTVUzWJjnSwxZ2FZ1gY6Rbe
+F0cmOk3ym2/1h61sWgBZRLG5vIGZkJe/An/pJyGL68bKTnyaPeYdKm0knt/yGGbo
+24bdwhzVLbzPIq6n8JCNWhO5r9pcmhR+XdrgddIpS341f9S41j82WGfwLCnc0pBX
+6PxVxMdDQ1qLQAbzCU3OCE98HtTv7IpDCUdi
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/indirectCRLCA3CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/indirectCRLCA3CRL.pem
new file mode 100644
index 0000000000..607f7bf989
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/indirectCRLCA3CRL.pem
@@ -0,0 +1,14 @@
+-----BEGIN X509 CRL-----
+MIICMjCCARoCAQEwDQYJKoZIhvcNAQELBQAwSDELMAkGA1UEBhMCVVMxHzAdBgNV
+BAoTFlRlc3QgQ2VydGlmaWNhdGVzIDIwMTExGDAWBgNVBAsTD2luZGlyZWN0Q1JM
+IENBMxcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqCBnTCBmjAfBgNVHSME
+GDAWgBRIk1R9xG0w/y1XRXEk30wFn0oALTBrBgNVHRwBAf8EYTBfoF2gW6RZMFcx
+CzAJBgNVBAYTAlVTMR8wHQYDVQQKExZUZXN0IENlcnRpZmljYXRlcyAyMDExMRgw
+FgYDVQQLEw9pbmRpcmVjdENSTCBDQTMxDTALBgNVBAMTBENSTDEwCgYDVR0UBAMC
+AQEwDQYJKoZIhvcNAQELBQADggEBACvzWPSm982N1bxs5RW+yTNbWoZ1NBGEvAUX
+B80kE0PTfchM1HbkPh4SkkVarj2/alnN4E7cMWzlq1qhc76WR4ApjPZmCW4zlw1e
+a229Eh3s15IX+CZcBEza5mQIHc5mnn2v80MPJCS7W53lvPlrD3T85bv3w3uX8UZi
+AkR4wCC12Rbnm4fEtgkIxuB7FrKb0SWf6ygBn+Tcv27CGSF9YBhVsXEyGAA8qt9N
+1eBJrRGBu1xG6rYEuW5OQgGhZgV3QhxEqUxhatPtYT8bcR07S3PrGx9Y+Mh+o9Mw
+LuHM6OiDiRdd2nRUmWWpZGOgdTKEJ0eFrqOnxHPPF3bhhiJs0hE=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/indirectCRLCA3cRLIssuerCRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/indirectCRLCA3cRLIssuerCRL.pem
new file mode 100644
index 0000000000..a366a243ba
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/indirectCRLCA3cRLIssuerCRL.pem
@@ -0,0 +1,15 @@
+-----BEGIN X509 CRL-----
+MIICajCCAVICAQEwDQYJKoZIhvcNAQELBQAwUjELMAkGA1UEBhMCVVMxHzAdBgNV
+BAoTFlRlc3QgQ2VydGlmaWNhdGVzIDIwMTExIjAgBgNVBAsTGWluZGlyZWN0Q1JM
+IENBMyBjUkxJc3N1ZXIXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqggcsw
+gcgwHwYDVR0jBBgwFoAUkdE5mMnvT1RlihhSLXwSEgpsd40wgZgGA1UdHAEB/wSB
+jTCBiqCBhKCBgaR/MH0xCzAJBgNVBAYTAlVTMR8wHQYDVQQKExZUZXN0IENlcnRp
+ZmljYXRlcyAyMDExMSIwIAYDVQQLExlpbmRpcmVjdENSTCBDQTMgY1JMSXNzdWVy
+MSkwJwYDVQQDEyBpbmRpcmVjdCBDUkwgZm9yIGluZGlyZWN0Q1JMIENBM4QB/zAK
+BgNVHRQEAwIBATANBgkqhkiG9w0BAQsFAAOCAQEANA7Z476bqcNnf7wWi2LE7Gws
+3Nz3U+G05Yp4xMLc4gYoKj/W+mjvsbXzJ2sjU8D2e3qHu3p0lIsFP+ZXXhvi4CEv
+3lIMQQE8/pPGxtqGDSnKRstdZPq2JvqisZFieChKH469G7yrHNMKD6C4MkQs27gj
+3cybk3G5fEGmpE5xVwHb1m2P/wD3vzkQVU6+T+RD8FPlZbqJRZEdIg/RSBQNXjbY
+ZIvKCkfl6w63f39NgMYSsfUM2g4jiv8PAoAR/RmDHgvylCoc8E2KDWiTFss/502e
+hhNTwMhEGS+Aze381vRThygIpqw29m4My844a8XVX2jZ8y6GGoiwqdby8U4wwg==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/indirectCRLCA4cRLIssuerCRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/indirectCRLCA4cRLIssuerCRL.pem
new file mode 100644
index 0000000000..596762cdbb
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/indirectCRLCA4cRLIssuerCRL.pem
@@ -0,0 +1,15 @@
+-----BEGIN X509 CRL-----
+MIICajCCAVICAQEwDQYJKoZIhvcNAQELBQAwUjELMAkGA1UEBhMCVVMxHzAdBgNV
+BAoTFlRlc3QgQ2VydGlmaWNhdGVzIDIwMTExIjAgBgNVBAsTGWluZGlyZWN0Q1JM
+IENBNCBjUkxJc3N1ZXIXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqggcsw
+gcgwHwYDVR0jBBgwFoAU8wjrbbnFoBCk2gRF/696R68RwLkwgZgGA1UdHAEB/wSB
+jTCBiqCBhKCBgaR/MH0xCzAJBgNVBAYTAlVTMR8wHQYDVQQKExZUZXN0IENlcnRp
+ZmljYXRlcyAyMDExMSIwIAYDVQQLExlpbmRpcmVjdENSTCBDQTQgY1JMSXNzdWVy
+MSkwJwYDVQQDEyBpbmRpcmVjdCBDUkwgZm9yIGluZGlyZWN0Q1JMIENBNIQB/zAK
+BgNVHRQEAwIBATANBgkqhkiG9w0BAQsFAAOCAQEAKRPyrIpC9HqbA9TytL4xuspW
+lO0Ihz0TyIs8bWEMPSanD0tdGsO8v1QQrv/XSVeAPiDcPvwFtX47TpbPJxJQBV5/
+AfGEAJ/o5Jl9ah2yuA3Qd1UZkL85V/XJgnqxpqJeLRQoQ3PeT0rlnQUM2fru3LrF
+AZn9lpxyqfqPsNbcDwwf0dbtGOvwUC2KTkXueizW0VEFgxRmRcielTglQXSV+Y1Y
+/MLqly+BHpWOko7BnfR6Ukfod6O8vyPwhUm0VW7AxPNH/qbqcpJjMnwCN8Bzp5LL
+UfQ6pkmCRWESbba14wXPuhoPM3OhzBzpGrBMeRpml96Tf3Q6xho0V/QmOaAs8g==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/indirectCRLCA5CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/indirectCRLCA5CRL.pem
new file mode 100644
index 0000000000..fdab0bd2f1
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/indirectCRLCA5CRL.pem
@@ -0,0 +1,35 @@
+-----BEGIN X509 CRL-----
+MIIGJTCCBQ0CAQEwDQYJKoZIhvcNAQELBQAwSDELMAkGA1UEBhMCVVMxHzAdBgNV
+BAoTFlRlc3QgQ2VydGlmaWNhdGVzIDIwMTExGDAWBgNVBAsTD2luZGlyZWN0Q1JM
+IENBNRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWjCCAt4wIAIBARcNMTAw
+MTAxMDgzMDAwWjAMMAoGA1UdFQQDCgEBMHoCAQIXDTEwMDEwMTA4MzAwMFowZjAK
+BgNVHRUEAwoBATBYBgNVHR0BAf8ETjBMpEowSDELMAkGA1UEBhMCVVMxHzAdBgNV
+BAoTFlRlc3QgQ2VydGlmaWNhdGVzIDIwMTExGDAWBgNVBAMTD2luZGlyZWN0Q1JM
+IENBNjAgAgEDFw0xMDAxMDEwODMwMDBaMAwwCgYDVR0VBAMKAQEwIAIBBBcNMTAw
+MTAxMDgzMDAwWjAMMAoGA1UdFQQDCgEBMHoCAQUXDTEwMDEwMTA4MzAwMFowZjAK
+BgNVHRUEAwoBATBYBgNVHR0BAf8ETjBMpEowSDELMAkGA1UEBhMCVVMxHzAdBgNV
+BAoTFlRlc3QgQ2VydGlmaWNhdGVzIDIwMTExGDAWBgNVBAMTD2luZGlyZWN0Q1JM
+IENBNzAgAgEGFw0xMDAxMDEwODMwMDBaMAwwCgYDVR0VBAMKAQEwIAIBBxcNMTAw
+MTAxMDgzMDAwWjAMMAoGA1UdFQQDCgEBMHoCAQgXDTEwMDEwMTA4MzAwMFowZjAK
+BgNVHRUEAwoBATBYBgNVHR0BAf8ETjBMpEowSDELMAkGA1UEBhMCVVMxHzAdBgNV
+BAoTFlRlc3QgQ2VydGlmaWNhdGVzIDIwMTExGDAWBgNVBAMTD2luZGlyZWN0Q1JM
+IENBNjAgAgEJFw0xMDAxMDEwODMwMDBaMAwwCgYDVR0VBAMKAQEwegIBChcNMTAw
+MTAxMDgzMDAwWjBmMAoGA1UdFQQDCgEBMFgGA1UdHQEB/wROMEykSjBIMQswCQYD
+VQQGEwJVUzEfMB0GA1UEChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEYMBYGA1UE
+AxMPaW5kaXJlY3RDUkwgQ0E1MCACAQsXDTEwMDEwMTA4MzAwMFowDDAKBgNVHRUE
+AwoBAaCCAa0wggGpMB8GA1UdIwQYMBaAFIH3qr1IdVmAsM/fIxid2JNGghazMIIB
+eAYDVR0cAQH/BIIBbDCCAWigggFhoIIBXaR1MHMxCzAJBgNVBAYTAlVTMR8wHQYD
+VQQKExZUZXN0IENlcnRpZmljYXRlcyAyMDExMRgwFgYDVQQLEw9pbmRpcmVjdENS
+TCBDQTUxKTAnBgNVBAMTIGluZGlyZWN0IENSTCBmb3IgaW5kaXJlY3RDUkwgQ0E2
+pHUwczELMAkGA1UEBhMCVVMxHzAdBgNVBAoTFlRlc3QgQ2VydGlmaWNhdGVzIDIw
+MTExGDAWBgNVBAsTD2luZGlyZWN0Q1JMIENBNTEpMCcGA1UEAxMgaW5kaXJlY3Qg
+Q1JMIGZvciBpbmRpcmVjdENSTCBDQTekbTBrMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEYMBYGA1UECxMPaW5kaXJlY3RDUkwg
+Q0E1MSEwHwYDVQQDExhDUkwxIGZvciBpbmRpcmVjdENSTCBDQTWEAf8wCgYDVR0U
+BAMCAQEwDQYJKoZIhvcNAQELBQADggEBAD511WYLf3F/LVZg+HVRImOIHZrYvfUb
+QGXr1qzVVk86bLrZqrPNXo6+dCj/pZJrP35VxvrcapftonBK2FucTiMzWyg5WXI0
+lh3i/7BOlopDezS1m0T/vPhEYJM4ymyhbEY7vjLQWeTWEvcQIW0QGfVRpFzMzkwe
+FcIq6QleFY3hfOWT72oAdZHiweeNPc3/XMPFFkZ/3Tp52Mt1OOq49Xk8HneV/F06
+tZGefG3DrvQbkqBHF3p2qjWrwtNUHlqxJ5uCYf0UKMtwKp3KLTJgphrCOApaPapD
+Dixk3loTgU9P/PO5XAP8s+tTdwjYlYPDan/Uxi1PpwdxUZ/ghuFaW9Q=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy0CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy0CACRL.pem
new file mode 100644
index 0000000000..f6f50228e7
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy0CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBxzCBsAIBATANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEdMBsGA1UEAxMUaW5oaWJpdEFueVBv
+bGljeTAgQ0EXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqgLzAtMB8GA1Ud
+IwQYMBaAFBigoHpq/2qdhYIkzcMmhfi/ijcGMAoGA1UdFAQDAgEBMA0GCSqGSIb3
+DQEBCwUAA4IBAQB+ePMn32XQoMZZJrXrnElaigAgYnqRtRguHjnlJXmaftw3lk++
+PSQPSKUxKtuvbuczbt+jMJhTngohIIfbPfEYrSEe6kolUODSJK4Vdp+ja2jfD9ba
+VrmoHNH5JOLCm4HqaV6Cba3rKH8F+0rlw49q6YTS7otMBaaPgfVPMtketW2okiNK
+YBVOVSdC4XuxuZQZE3rz8u+T9QcOm12eMNJU/pXhFjOaagtqU1xtqEBO3LOsbMym
+uTRGJO8VoWdYNxe/jedXiAMASJlx4BQo0hJDm16wlubz4S0Ac9gHYNrFD6laVDph
+B5eNCGxHDSJkxhNtbW9ztHgQcT18pxOV4mHy
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy1CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy1CACRL.pem
new file mode 100644
index 0000000000..ad1941263c
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy1CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBxzCBsAIBATANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEdMBsGA1UEAxMUaW5oaWJpdEFueVBv
+bGljeTEgQ0EXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqgLzAtMB8GA1Ud
+IwQYMBaAFNimnieXEcOO1Bkh1yC8nO2he/LTMAoGA1UdFAQDAgEBMA0GCSqGSIb3
+DQEBCwUAA4IBAQBM2rRjH0dKX4Ay7xIJONSV1tyQoFaznksb2FKUgatoMTtF/Tbx
+WqANV/RsKCYjHc7wAlyn0LCfxyIvIGSLQTUk3+Dyk0yESy/Cz0R93eCeI2y+MZ7j
+BHz+jCEgOeV4ilL0Y2hTmHOQGBkrFfa/tWA2tAejAZmnozFhgQcfenUMXWc5uU3N
+CMS7n67+hUUE3kQ5qw5L3GtxUytXOdG4CUa96yPcMKJgJ1W4fk7FkAAGt2IM4lDM
++c3gS0+TfewBtGFPfu0kDt+0gLX/SdGGJhBnYCuoAicXhshNmhOjchP3Auo6pZHP
+0uto4/XnOnHKUanX+Cg7D++JqCa1FzShSjUn
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy1subCA1CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy1subCA1CRL.pem
new file mode 100644
index 0000000000..cc49e37c54
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy1subCA1CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIByzCBtAIBATANBgkqhkiG9w0BAQsFADBRMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEhMB8GA1UEAxMYaW5oaWJpdEFueVBv
+bGljeTEgc3ViQ0ExFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoC8wLTAf
+BgNVHSMEGDAWgBR0oNVY2StT0iuwzV1xxqG/Q6fIFTAKBgNVHRQEAwIBATANBgkq
+hkiG9w0BAQsFAAOCAQEAcdszKmraUaBp3w473eShNoALBZ1aj31fBfibxZPvtlwG
+BECryi8bmOwXZwKUE8Pr1MeQVtHYgDJhBscq9F8scmBwbmp/kRnBdN9Dgq7fe9Yd
+lke45ULwXOLkX+MdbWcNMX0OILkySpw+zpIDX1HCNeL0QKz+bXwouqgAnpj1IIFL
+yx56Vl/AGQ7S0jkR1emdZJudenGiCKkDqImjORjteSO852f04/83n6iNYDLcDzki
+uxyd+n00PMhqjiG44a5o+rAfOiJBbxv3eDMNQo7mhnTHUZnAq+3bSSQcJqCQBTNC
+zLna0kwa38h1WeQWbekOJGO2kiFd1pTss+mPmvpCBA==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy1subCA2CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy1subCA2CRL.pem
new file mode 100644
index 0000000000..846500d7af
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy1subCA2CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIByzCBtAIBATANBgkqhkiG9w0BAQsFADBRMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEhMB8GA1UEAxMYaW5oaWJpdEFueVBv
+bGljeTEgc3ViQ0EyFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoC8wLTAf
+BgNVHSMEGDAWgBSMBdzffmTbYr7bS1FkjGpm2FyjozAKBgNVHRQEAwIBATANBgkq
+hkiG9w0BAQsFAAOCAQEAsrP3R/bTvBLXn8NE+Qcr0Cr7ETparxT+Grm80Py+H77E
+UR6eT9/tvIJYTNYzpw7zEUB4vYeVqMJCZoPtP26Lkv30BLAkWEQ/kaM9720aG1pH
+sGUCpSwpnZkZeEhUW//IvCb9Ubf/aMAE+NpvLnYHBB2hQdckW8hCrMubc6jfQL2K
+DTEhwuFs8p81I2OXuA//qk9PrQlnI0dsFenmRCbSpZj3CzIjwuPbv4J2JKthNgb9
+xuFT97kzKFYa77JP+Skcicva4o0A94WVkCtcAv8FrHPNNapflzcE6edP5Y5R97SK
+yflBco+Kk8eEzkWleh3wLh04+CEoj9JYMEA+1ICv8w==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy1subCAIAP5CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy1subCAIAP5CRL.pem
new file mode 100644
index 0000000000..7ebae31c23
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy1subCAIAP5CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzjCBtwIBATANBgkqhkiG9w0BAQsFADBUMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEkMCIGA1UEAxMbaW5oaWJpdEFueVBv
+bGljeTEgc3ViQ0FJQVA1Fw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoC8w
+LTAfBgNVHSMEGDAWgBSJBFR0BmCz9wBuoGGOFfu+UgIGJjAKBgNVHRQEAwIBATAN
+BgkqhkiG9w0BAQsFAAOCAQEAGOaiustpHjlRoLea0ROpIk9v5o+dhhyD281DHP68
+cahcHEEDBsFZ+08KXnho7vLW55E2mnOZpjD+YAw5M1UpuZmKHgHTg14FfZhrZjco
+LjkcUC8hlCOc2ZfIpv23+Sh4dtR/iglXo5KqDiBbii0VPndtZ0M0XgTfLe+3vp1l
+ofMF2I3jkMfQSgyFMihCzguRCgjr2g8TAcX1KxaRyQD5NtelpY3f7juQo7RD3AdF
+hiZdjnCY6qtgQ/9ju/6dkWl2vNOVWQBLJ1aieo2o1UT5PiJXoMlKBbuYZpecyNRa
+bdRFkCoSybqi+qAZ0S39CBZQGuU7Une7xne9cXK+M05J8w==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy1subsubCA2CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy1subsubCA2CRL.pem
new file mode 100644
index 0000000000..669df318fe
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy1subsubCA2CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzjCBtwIBATANBgkqhkiG9w0BAQsFADBUMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEkMCIGA1UEAxMbaW5oaWJpdEFueVBv
+bGljeTEgc3Vic3ViQ0EyFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoC8w
+LTAfBgNVHSMEGDAWgBQRfcCcinb5STP3pIFLjjB1lTvoiDAKBgNVHRQEAwIBATAN
+BgkqhkiG9w0BAQsFAAOCAQEArE0ESZ1xjjGSyPpJ2Ru9aEVl6UtjKC1vctLfDCZD
+eLTLipnD0R6vsDscUna4h22okIeP9AEeLEOvpX5Oi0bVNhU0w6O2xP0Tc/Cfuole
+HgH4ZUJcKob6/2DpXLSayUNNL1zY8I/OS+lfsetIqOhp78xLiR0ghyeOagnkH99r
+a9eT9iCCUe/XO/N0gMOjsPkh5qOGC6gg9/XwsECc1BYf3HGzU10IC/C4rrxgrwQx
+YmpA+WDMQpEmDFXxect/9gARsgny4irJ0++2rFI1WdWKFEmMkO/l9B6GRYCjNQJX
+cS0JH8PWhv3DjvUoEeBIFDDJJwquskVZWwP6TbkfEqut+A==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy5CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy5CACRL.pem
new file mode 100644
index 0000000000..7c053d1c8a
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy5CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBxzCBsAIBATANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEdMBsGA1UEAxMUaW5oaWJpdEFueVBv
+bGljeTUgQ0EXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqgLzAtMB8GA1Ud
+IwQYMBaAFMAmgedp1p188L3VnapTDmX5nMsKMAoGA1UdFAQDAgEBMA0GCSqGSIb3
+DQEBCwUAA4IBAQCXIcfQLBFOcgt5m7Q9laH1FvfjTwZ1s2tC3d3NzBGRJRqo4lFB
+sb3PvwFL96EwopImZofRByNNmtdA1E6FS5dyiaDjOD8u9f02ZnL3PpAkuTTMyA+l
+iGSo7ZEvwYMPjWdtiN0SGLlpoVbTbAcUx4zjHOby1H6TiZcexSrf6ndRtYzR9I/0
+3jzFnqPcSIVQeB/gSrSWMj9j1gYO/UQGf6H8/YXadnYzoh7+C2lbwk27mpb0d8sc
+EkGJPa0iimLbKCmprPG5iHE0y6yUltjSia8fsubGfzNkMaJWsFepd/HMoXWC68hS
+0fI5vvDTIzHqFMAF6cZ8ddHMNbFA4XDD24FW
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy5subCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy5subCACRL.pem
new file mode 100644
index 0000000000..5c6e19906c
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy5subCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIByjCBswIBATANBgkqhkiG9w0BAQsFADBQMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEgMB4GA1UEAxMXaW5oaWJpdEFueVBv
+bGljeTUgc3ViQ0EXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqgLzAtMB8G
+A1UdIwQYMBaAFGyZqbYF675wSTZMWJoi6BSIhS/bMAoGA1UdFAQDAgEBMA0GCSqG
+SIb3DQEBCwUAA4IBAQCfcJ8e+tup8Fr+n+Wg9FB/0V86blpBUsRvV6juNBKzuyuz
+b4iY4BZM1flYt9OF043DVHi7xN7BcQ7YGBal/day/v9GisD3Ia8qYdtyRCb0y70V
+6jiVJ1FVolO5New51aMcNAzmdCvmqvsj2KBm5y1zJmBwF+MeKrOk23kL4jOpX06y
+Yjfbs1xCbub01wBmE/t+rL/FZdFamC+uh3XfBUw6vCrDNvdtN31n522EV8I3ifru
+ByIJ7RgtjgeIDfCOND3TZ3i+OTEcn4XrMW+Y3BYiRKhLEpxrHkxNdgOK1ouC0HuI
+QlE/DkaDnw9rj6NnI9wlZTMCbmsSkn28VrkArw7y
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy5subsubCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy5subsubCACRL.pem
new file mode 100644
index 0000000000..793cf1291a
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitAnyPolicy5subsubCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzTCBtgIBATANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEjMCEGA1UEAxMaaW5oaWJpdEFueVBv
+bGljeTUgc3Vic3ViQ0EXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqgLzAt
+MB8GA1UdIwQYMBaAFDHhP/xiboBlzal5EAArbola6AXDMAoGA1UdFAQDAgEBMA0G
+CSqGSIb3DQEBCwUAA4IBAQBBNQhxoz5IzMcomKNxeSnmWdgwCCbynAR5YVIt4vqS
+zbN+H6DPt7UbaqhpgJTAedphGYOiVm+LYOehKXMYp6ZF2iHFC7yZ4/tbozh3hqY5
+5G1Zf2c2cXsCI9cI+uXB3jk0h1RgxaBRoAST6PS8HQJvUXM0T3QyApj2ELLjlvHx
++OrJ7XfsmOzliH8pfVdnKGzp2piSiJhdiiV/egX23AXvvQq5k3Tb0oUWo54BAso3
+2eXyypSbPTbxQXVqq4bjsVs/F7h0xgFRlwK4YPbmcpZqM1TXl0f8l/KqnFV+ZOmL
+aXghz7oTvQoFmJodMyzgWtvR4LRWnVj2v53K6AO/Jvrx
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping0CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping0CACRL.pem
new file mode 100644
index 0000000000..c709a56df7
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping0CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIByzCBtAIBATANBgkqhkiG9w0BAQsFADBRMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEhMB8GA1UEAxMYaW5oaWJpdFBvbGlj
+eU1hcHBpbmcwIENBFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoC8wLTAf
+BgNVHSMEGDAWgBRYNyYHkYRgrO72QD6lK/z/lx2d2zAKBgNVHRQEAwIBATANBgkq
+hkiG9w0BAQsFAAOCAQEAvS17Fvl0x0lQNKsr9O7mk57ThTYOMkhSLLVLYCrox6vO
+B/wLW2wLJKrJ//n/VFqEGncKHNgwyF0tiBNhm9qEGp+LSbKwN/NT/ZffUmuer74d
+iUIQr7fvQYATGGY8f8a3GlQ451Wnw4LTOpfTfIOdH611ql5bQg9zsZsoamXa0WZ+
+Q9WLA9rT2AAQDWE+6jhD6PfhMZlfrOwfQ0oZJX+EDkiQ0N1BAhURxMxzflrWeedF
+nRHOyZrlIzqZ9rqaIaTcPkn3Q90fxREys2AgX59Fyp76iT3lsYpPWUytnt7e0NpY
+sZTGdW5W8/vh1jYAMhuBJNzTfk0Ilf71Le+qxQVFQA==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping0subCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping0subCACRL.pem
new file mode 100644
index 0000000000..50f92f4a14
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping0subCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzjCBtwIBATANBgkqhkiG9w0BAQsFADBUMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEkMCIGA1UEAxMbaW5oaWJpdFBvbGlj
+eU1hcHBpbmcwIHN1YkNBFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoC8w
+LTAfBgNVHSMEGDAWgBT/tHNiUo1cljpakK4avLg8eYFjHjAKBgNVHRQEAwIBATAN
+BgkqhkiG9w0BAQsFAAOCAQEArr+kgBiRhrD9A0eGhC60oEuT+oe4x7jNWNet8W+g
+U6eESV36XCGgh37RfZtL6k40uiXm+WNM5Tir3iLaoUVR675FIWTn8deelq410jkk
+RTbEz8ikqYH/MGilEhLEfaYteQu8kqGETlDmFbmcjriRWulMGVOc7yKMIrKGRKWY
+oZXN+MB4zjkepwlJtef6ZtwNa+QkYENfLSu0fNu+MU+aqnwyLqsqNqV6paPViltB
+c47TqfXNtm18NtKDYjXdPgiLfmk0qZ+WSQK9mz2v2NSsHq7G8IeOYJ5BuaXDs3df
+fyZrzQxOFaaRNLor0m5T8HKIM4HtHVuLGioqQRGLyX5zUA==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P12CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P12CACRL.pem
new file mode 100644
index 0000000000..ec32a575b2
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P12CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzzCBuAIBATANBgkqhkiG9w0BAQsFADBVMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTElMCMGA1UEAxMcaW5oaWJpdFBvbGlj
+eU1hcHBpbmcxIFAxMiBDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAv
+MC0wHwYDVR0jBBgwFoAUTWd+jd05Ga/oJt4OATR4sXUQ2qQwCgYDVR0UBAMCAQEw
+DQYJKoZIhvcNAQELBQADggEBAOTAmNbgjGjQ7urj0qwWnSMCHeyF9To1md3H2IWh
+CNZaepq/e7ALmIDr7viy2FfyNnmBi0SWz4b/3ddI+NhylyuhBX7b+hHIBcAbyuym
+ZprJeuNjk53T2KoUGrOUnRGAoUKY8I1mNrXb2oQ5+keKUevF1G4OYsjoH2i/YU/p
+xf9xMwd4fKjRZuIS62MMJBXOQgWPXu3q1K2U12M1EHJ+Uzm0vgYf54vL35Zczo1T
+42ue5Wkt2tFgiQlN5betiQhuXPSNoEcX54l3oRfo/QS2cFKzaQEYFrS4Khdy590X
+16eGQeXouMpeCARjGbBeUoVWa/qFm+40nOXtBftQOtUuGJc=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P12subCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P12subCACRL.pem
new file mode 100644
index 0000000000..8313d770c7
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P12subCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB0jCBuwIBATANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEoMCYGA1UEAxMfaW5oaWJpdFBvbGlj
+eU1hcHBpbmcxIFAxMiBzdWJDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAw
+WqAvMC0wHwYDVR0jBBgwFoAUqiaUHWQPfgW8XWCNB1f8cJVmbOcwCgYDVR0UBAMC
+AQEwDQYJKoZIhvcNAQELBQADggEBAGhzR1y9MeY8/io6ssFZCHWXI8r8OoPogUgA
++Zmv2YJAGwg2FY/ID9nYmyntsT1bsAfzPubQJJGsg6+izEwcjNGaq9S8W2doUJ/5
+LQVpPBYydzpRm9CkW+YlpxTdYxlXLJOlZOxQbAob7dUdViUgbu3bVQq0oMlgjz3z
+uMwHv4yp4xOD45CQbwALHVAoVkayZ6ESltquwQBSOaRATkbTRl7BdNcssrh9TTMS
+YYhcnWHQd4e1KWdJLb8ZSgYpAAoLLV+4QSR3B64O4vy95xwcG71puEs/RLDgW7MY
+pEnbOsL1TDq7ZjYfAHyxFXZKe7XEFknnu7A5cNjoSr65szamIn0=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P12subCAIPM5CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P12subCAIPM5CRL.pem
new file mode 100644
index 0000000000..3d86355fa7
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P12subCAIPM5CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB1jCBvwIBATANBgkqhkiG9w0BAQsFADBcMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEsMCoGA1UEAxMjaW5oaWJpdFBvbGlj
+eU1hcHBpbmcxIFAxMiBzdWJDQUlQTTUXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4
+MzAwMFqgLzAtMB8GA1UdIwQYMBaAFB0Ez3YnB48iO8L0gi7u5t0TgHtTMAoGA1Ud
+FAQDAgEBMA0GCSqGSIb3DQEBCwUAA4IBAQCT97ZZ9/3xeVKS7ylodjmyfxLqZ+7V
+iezI4cQFmH7cWThgfMefgj1664LrHOuiY/4bhvk1LHQj1c5pFbUYLc5hprEiv3dn
+OJejWo7PxTY47hkXIntlElUyYb/mxUPxiklQ7FEbE7RFSOTi5MZNrHgd+JITUa6x
+jPfDI0z/GO/Jo4RPZos2Iu1hVLN++sU8iMVMe7/sIoOrNw/lwudUfo+cZEKWi7xv
++1ICLtnK0XoPBTxNzb/i8cOZrjggiKole9mFEAZrs5P5dfytRTVFje+d4Aj6lYr6
+4smUCABSDWhLcyI2OLIt5taw1BigwfOsGvjMsRVgRuF/3U3LRHf+8o1M
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P12subsubCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P12subsubCACRL.pem
new file mode 100644
index 0000000000..4c8450f3b7
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P12subsubCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB1TCBvgIBATANBgkqhkiG9w0BAQsFADBbMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTErMCkGA1UEAxMiaW5oaWJpdFBvbGlj
+eU1hcHBpbmcxIFAxMiBzdWJzdWJDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgz
+MDAwWqAvMC0wHwYDVR0jBBgwFoAU14BcE4uOQXa6CrVzceijQIB0DtEwCgYDVR0U
+BAMCAQEwDQYJKoZIhvcNAQELBQADggEBAB8d26fH9sOi6DPVWkJSNU1UltmljVsq
+Z9FBaQQxT+XSQDuAxW3VxeL55+/62jWO/O8/xvfw4egnAoTjtDfOrHFCEk7AlIgX
+vdGeXe7l4sHgbaq6l/z4EDsQU7SoukhtrjUVUTz7ksLjJwraVbBc8Kun/Umpj2sc
+ZEFrn/PMyibfXkeJ5aWTosLuEyKBag/Ln7hhl4nN6LDnafj+sxvhIlPGKKE1B66S
+h+wbhxZ6QvqOGfdYlcjRwXpdRPiF2/DJApIjF3eV7CkMM8tMo0myD+xQWwjPkNPw
+29n2FmWxfSmGBhbRkJ/nPGid50jCG/1UOrtN9+pQpRS3Tpky/zFtkvo=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P12subsubCAIPM5CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P12subsubCAIPM5CRL.pem
new file mode 100644
index 0000000000..2ed760a1e5
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P12subsubCAIPM5CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB2TCBwgIBATANBgkqhkiG9w0BAQsFADBfMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEvMC0GA1UEAxMmaW5oaWJpdFBvbGlj
+eU1hcHBpbmcxIFAxMiBzdWJzdWJDQUlQTTUXDTEwMDEwMTA4MzAwMFoXDTMwMTIz
+MTA4MzAwMFqgLzAtMB8GA1UdIwQYMBaAFBKHGzVn8LyhoDa6FagpGe0am1twMAoG
+A1UdFAQDAgEBMA0GCSqGSIb3DQEBCwUAA4IBAQBRQeh+mh86ONreRF9oNGE+z0lr
+y1ZYBiri/f8kk7y1GbwNB6LG+M8Fve7pe8pvtawSMfGnEbaHqdOf1jzSeOQXvSBb
+htuZ+DO9kOVDRyysBLNDWTSgA7BC/MI0JwrHnUMq6twutmQ0aPe0hHZu3DdydeRt
+ncUQ6qa+dNiZ2RJCpcXwKcGPLJnafDpICui8VPRJKgj4bcdtpFICoCmnB3iqbLKe
+9s2XyNtHxfJPOW4HSASB82rWcTzNA6Px0FwXm+8TKpkopS1dlZ6cd/nYhJCj1i26
+wxRDAx634CAzhWoGaYtrE2P5epcOEnh4G49ybfPmua8RWxTyi5CvhBhtrtXp
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P1CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P1CACRL.pem
new file mode 100644
index 0000000000..f231fe784a
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P1CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzjCBtwIBATANBgkqhkiG9w0BAQsFADBUMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEkMCIGA1UEAxMbaW5oaWJpdFBvbGlj
+eU1hcHBpbmcxIFAxIENBFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoC8w
+LTAfBgNVHSMEGDAWgBS+tp29KX8aodmL4aSAaIMorUrwATAKBgNVHRQEAwIBATAN
+BgkqhkiG9w0BAQsFAAOCAQEAUv+vJlKK7TKlyO/T/yrf26BwpHa6dJHReqjLh6e/
+iXSXPSDXvuDrj+uNAIL4o8s8X5y7h5+ivYEDyZi2lnrCsj75+IuJIBfeHnfdeCo5
+rsa2Hml6bhJX0OuZRkMlg1qDMYlN3EEqcpobXWd/TfL3RB+vw/V7WwC/F5vx5UkT
+mH0jpI0glDOOIaQIDhgXerdEMuZ4FpSdAiUtj6icPYmbaGMY+We8X07ztyv2RQsK
+frTxkyAHRM8fC79LlQzzCvTPcV9wkwKteKMY6ZzWsOfp1B9DAyK6wq2Lp+TqbJqh
+pyL/lPhKASzGVegUqAOczdo0rvNDCVIPu0gCk5PgjcpieA==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P1subCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P1subCACRL.pem
new file mode 100644
index 0000000000..3730e7c738
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P1subCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB0TCBugIBATANBgkqhkiG9w0BAQsFADBXMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEnMCUGA1UEAxMeaW5oaWJpdFBvbGlj
+eU1hcHBpbmcxIFAxIHN1YkNBFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBa
+oC8wLTAfBgNVHSMEGDAWgBTzzQc/gzDTxwJi2ubKbAGlsbaAyzAKBgNVHRQEAwIB
+ATANBgkqhkiG9w0BAQsFAAOCAQEAAuGpcOqakKHpoO5Y+E7QAQnB1fmAm4smN7eu
+RNXIdrZaVd24C1BbFzYAnjdewBVYT4adCdnslaNe4tqpq3Chh/YtmUe152/GTiXF
+MVbo5FRZhjSvK8VTVEzvSZ21b3oiqIv5d4P47XmhVfo0GtTv7Rg+x+ay8dGUgni1
+D153LEBh9beouesqqxn/8uFfxYpqmxFrS8vLdL9kxpeaFX32bM0eSOhA3lg4oCfm
+j28x6yL57beJMHjFZMN5vAXTZHZKeJS1QXak2Dt21G3VKPyq3v7iY0GDgLqQGsIp
+vPsv+nuvwdTjcQPwsMIQjZBrq2woAYvlF5hx8ofqoLNW6/oV1g==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P1subsubCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P1subsubCACRL.pem
new file mode 100644
index 0000000000..6bb1b2a960
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping1P1subsubCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB1DCBvQIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEqMCgGA1UEAxMhaW5oaWJpdFBvbGlj
+eU1hcHBpbmcxIFAxIHN1YnN1YkNBFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMw
+MDBaoC8wLTAfBgNVHSMEGDAWgBQ+RXSii9LxVoxGAWZ4cCTGIsEDnjAKBgNVHRQE
+AwIBATANBgkqhkiG9w0BAQsFAAOCAQEAdMziQBhDzdFRF40rOtd55OD5MPOXWPRb
+5i6KUQcwxrHZ6xZibEhM/eHGtHW89pL4Jjzrwbp+SXz/OzJ6yU9Cf3PQsP3a7l87
+J/EY+KL++6g5V58wlaXZYOvO8v5WTSFGP6NUvg8Nq2SChq3KqVvKxp/MrFSckP74
+gd2jepabJyTeXajSMManT+wxxTKG8WKMQtiQdXclZmEgaVYgxKVgIJudF46yLEh6
+gVwhKAR8xdIBr/mztrcM+aQKvdxtz3aHuKNwm+lo0tSjxB7UojZvIMdd7fuc0V1E
+PEVJDd2+Eej5s071zlgMeaahFbVeBNgaQy5rURdHxtyMZukFdCW5aQ==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping5CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping5CACRL.pem
new file mode 100644
index 0000000000..68d33d924f
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping5CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIByzCBtAIBATANBgkqhkiG9w0BAQsFADBRMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEhMB8GA1UEAxMYaW5oaWJpdFBvbGlj
+eU1hcHBpbmc1IENBFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoC8wLTAf
+BgNVHSMEGDAWgBTbgAe5YizFw/3zQ+JmUSW72/QczTAKBgNVHRQEAwIBATANBgkq
+hkiG9w0BAQsFAAOCAQEANZI64pJVPbGyUy9hrPD2bO0EkxlY3aJHxDko6PaPdQ86
+dFjmX8tTCD0vmm8Hox4bI8fZHbjMDqhWxLU8NtjNJLSZX5IY7SJaaacDGaRd6laP
+05hB5MTLcEKBxH5FIetoK93e8mf+rMVRG4kCmn/UX4notzBcX0x0qKoWd2v9v2QH
+Gx7Gr6Ouae8wubYiu7aR9fCYRIcllEZVFRQ9f0bB5o4NANAUM4uq7ZrrqSRauqN/
+iNxCEeKSVnItuZnAZXpazNmXwSCdWPiRSl/77tThqoBhGKsgOvNbwJaTKJIuJ8HX
+5HgiQiSaz6Y5GySbA6rFemmW6X6o49/CiJr8cI+fKA==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping5subCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping5subCACRL.pem
new file mode 100644
index 0000000000..7925d0d1f2
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping5subCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzjCBtwIBATANBgkqhkiG9w0BAQsFADBUMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEkMCIGA1UEAxMbaW5oaWJpdFBvbGlj
+eU1hcHBpbmc1IHN1YkNBFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoC8w
+LTAfBgNVHSMEGDAWgBTY7G2+t2/KE2PKJ8ycW6JpNrbyaDAKBgNVHRQEAwIBATAN
+BgkqhkiG9w0BAQsFAAOCAQEAOYCNoa/mt1m/IQNy9kCVeCItblOzMyiCcng/IMCd
+RQ9q7kAa/nPj/zINqGAM4GUY4yB5wHm5zVKPL/AxC4adae2Xg5o2XqJ9rRI9bSgJ
+s48iHWbFp8mU2H5Wbn/hVKSWWCi6XzP1N9QwsFJa/5nsgRDzp73VHarqIPUBahtA
+mYLPo0bIg77oHPsXYmEI+aufY88+IMtVr4iFIW3ifEQu/XbmfwNjQLopIHBn3E0+
+gyD5XDJeF5f5C3FG9vQ/3DSgrdN2DLzWHr3/dWNIkRWhVxqimffMjYUkuxi4bKQ0
++30q3zclNs0lOr240CPBkg6Y39n0Zo7ihxBoS5INvbTi4g==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping5subsubCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping5subsubCACRL.pem
new file mode 100644
index 0000000000..2fb83ef408
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping5subsubCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB0TCBugIBATANBgkqhkiG9w0BAQsFADBXMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEnMCUGA1UEAxMeaW5oaWJpdFBvbGlj
+eU1hcHBpbmc1IHN1YnN1YkNBFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBa
+oC8wLTAfBgNVHSMEGDAWgBQ1p9ThS3ROVahxtEJ/Mv4EGskBuDAKBgNVHRQEAwIB
+ATANBgkqhkiG9w0BAQsFAAOCAQEAbayhlH01G0sqNxiiUyC8qPsdhUF3mHVEhoqz
+2SOwTTDzqCTLyqftFnZPAJ9fbG/FN3Denqr2ouh1Rl2mPEG3KmBA/w6gRrTzxmS0
+pC8UsBWdRvRebGZ29WJEjgslUz/r9BbSlwabF1dsAssvmv9xPxFBql4uNrLOEfap
+M9Ldo4y1eiBWd5xNTYp2zu+oBOAgywJggc7xepoUhwcPCTSrcAqmsQNLBoMYcf84
+nzm8rJ89cTqyPvpLxKjjgLdquVevhCcIG9HSCmAbb1z8SKhWaaBjRSoLmAo7845M
+VoDabAd0zNq9DEwb9WHB0zZldJ+u4LJtAAEpdl1nc2KqMADUnA==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping5subsubsubCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping5subsubsubCACRL.pem
new file mode 100644
index 0000000000..ade3f19453
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/inhibitPolicyMapping5subsubsubCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB1DCBvQIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEqMCgGA1UEAxMhaW5oaWJpdFBvbGlj
+eU1hcHBpbmc1IHN1YnN1YnN1YkNBFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMw
+MDBaoC8wLTAfBgNVHSMEGDAWgBSuY8vX4sNx4/TObvw19JvSTT7cFzAKBgNVHRQE
+AwIBATANBgkqhkiG9w0BAQsFAAOCAQEAj0qjzBDkME3FgINy8gUWHlUGBpgreUMF
+1IqXG918JUeFy1vfkDdhwmg9ln2GjMquqb6J26L5mgH0EN4qUsfRZtcLHTEnMXt+
+MSKI8xOWJrid//uFlitbPPNdppvovBNSAZroq+uZLd+jDxKfiPOVlrIkbbTQvv44
+YAGrkkdsmrxSxWwrtXdLIURmW/D9J5uRkRqpMVvikD5aMLGQEangg5MO7ZLsGUBL
++mdA7YDq+RMG5F0TVoKOOlhOZhAxcgs+RMCZdJKWxJd6/gu5opHeEuOy5KShVzUW
+ABXNyqZXT4tjAjYW0Z26urTv8FeBoRoJC2Kyozm7+IR4m/H4/GaJMQ==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/keyUsageCriticalcRLSignFalseCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/keyUsageCriticalcRLSignFalseCACRL.pem
new file mode 100644
index 0000000000..4993db248d
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/keyUsageCriticalcRLSignFalseCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB1TCBvgIBATANBgkqhkiG9w0BAQsFADBbMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTErMCkGA1UEAxMia2V5VXNhZ2UgQ3Jp
+dGljYWwgY1JMU2lnbiBGYWxzZSBDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgz
+MDAwWqAvMC0wHwYDVR0jBBgwFoAUwspp9bSvEy30nPIRVcsqMLPSWkkwCgYDVR0U
+BAMCAQEwDQYJKoZIhvcNAQELBQADggEBAJk/UxyWvcm6kbidRgW52BKoSxXcHpfW
+896BFKl4iGUzmYA8GanMvM9EkEoeqjrHdTABcPE1Mv0lREGRYZv9H+gD6iAnKctc
+8G74C8eYkvcdocWAixuvDMyZ+D+TxSCOo04ppe+HraHgEQRy2sgobIYdqEY6XcyS
+X0areuyMQPjqbTdOMFsTrvtSew034Q0zSoKsPZhxfMQ6zcx7JKqna8HzCO9LCZag
+r5+47Bk470ve2Xy5FrPk6sWJQal0/YHOAKKnnXoXitqst2A3cYiWgRAqpDMz2yMH
+zdtJKbBsIieZGgQiedwXDs7aKWzN5o5sh0ALyj17bbHyMrs7gvyiGvA=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/keyUsageCriticalkeyCertSignFalseCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/keyUsageCriticalkeyCertSignFalseCACRL.pem
new file mode 100644
index 0000000000..8a9a50b563
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/keyUsageCriticalkeyCertSignFalseCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB2TCBwgIBATANBgkqhkiG9w0BAQsFADBfMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEvMC0GA1UEAxMma2V5VXNhZ2UgQ3Jp
+dGljYWwga2V5Q2VydFNpZ24gRmFsc2UgQ0EXDTEwMDEwMTA4MzAwMFoXDTMwMTIz
+MTA4MzAwMFqgLzAtMB8GA1UdIwQYMBaAFDRVC2f8HLHcwnIKFPBj6dSb8GP5MAoG
+A1UdFAQDAgEBMA0GCSqGSIb3DQEBCwUAA4IBAQB3bfisM1UBugxKYYdxZkYgpRvs
+rh8UEjPVD8z0t29+yeyiPm4bFmTZI64VNvQlcl/Jj0YdcqkWGEKdH7RS79lSQhBs
+piAcYQcdS9WzaZ1tFNG/Fvxo+MkksrQ+Z95rb0vvB+7YuTIVWqbHcJamCgZ4h+Pl
+XTUQgHedNzpPKisiLF9y32JbDJ/nnrec9wEpMn7z2Yhb2vDWhdtQoYMTk4LrMOSk
+74Cqfpuy6JEaymDfdmrIIx4JZOfmo9mQcgeN2WoV/4YYaGGL3T3Sk8FqUaTTdM9Z
+iRiqzBSTOfl4VF4e3S1ZTDv5JH0U/HrJexLhgdi3xEpE4EQIZvXVsZX6I8rn
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/keyUsageNotCriticalCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/keyUsageNotCriticalCACRL.pem
new file mode 100644
index 0000000000..844a745e39
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/keyUsageNotCriticalCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIByzCBtAIBATANBgkqhkiG9w0BAQsFADBRMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEhMB8GA1UEAxMYa2V5VXNhZ2UgTm90
+IENyaXRpY2FsIENBFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoC8wLTAf
+BgNVHSMEGDAWgBTBkBFK2bQrxXB+zow7Yljlu5crczAKBgNVHRQEAwIBATANBgkq
+hkiG9w0BAQsFAAOCAQEAgK5IxkJ3u7pRpg/BKAlwCJPgj4SrjTrLeu875hsUvEfv
+mMzLN50lGQpwuuH2oaQ15Da+PGpzng6Ao5MhMt3vTqU+Yp5VQEnBIsGED0lTJDHj
+pDyQpS2d4nhdYyPrHQHJWwLoGaTBPglYqc/vASXq862RiNKywdVX4QFj9IXXUrwI
+wQ7d5uKirZUEkInjJCdVH8ryJfo9fLRD4kb3OkbO62e/HHSJO2DstQadNweLoLCM
+hhJlw5KkDXIBfQvq5pPrI76dHY9VatsnqKRkt1CUE4MVk0fOIqci2Nz77LdTsFre
+Pfe0WNoqSJpoGv4SfIr7v8Uw83bmO3Yy/enh3p9J9g==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/keyUsageNotCriticalcRLSignFalseCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/keyUsageNotCriticalcRLSignFalseCACRL.pem
new file mode 100644
index 0000000000..e0fd7bfd8f
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/keyUsageNotCriticalcRLSignFalseCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB2TCBwgIBATANBgkqhkiG9w0BAQsFADBfMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEvMC0GA1UEAxMma2V5VXNhZ2UgTm90
+IENyaXRpY2FsIGNSTFNpZ24gRmFsc2UgQ0EXDTEwMDEwMTA4MzAwMFoXDTMwMTIz
+MTA4MzAwMFqgLzAtMB8GA1UdIwQYMBaAFPl+UqB5ZgQIRAhleRAO3ZDmQ/HYMAoG
+A1UdFAQDAgEBMA0GCSqGSIb3DQEBCwUAA4IBAQCa3FLqxtdS2NeSwWMvuticdJwe
+M+xS0ZRf30G+WsPtmoRnb753WkhlJZZcglilAExrCN9BIMSEpO/UgyXpjDj7GUri
+F9QHfTdIT8QGKcZMbx/nq29ge/fdjOIkhXnBktQy5BfB8lGkYwNs20NuFpL3FaUx
+IvruMRR2AyivlndK+xcz6s2j2v1WYXlvZlFNAAHVmXR8+67zbU7t0WIN7VlkTyTa
+0mxanuASRP5FmlT+Czr6N6OERlBTp1wnvlq9BHeTGDXQp1oXu8B8sTsQHTMbuGWH
+FqGDZpZJL1BsCMuXkBk40b6b57/C5CvIy7SfX9xnvKmJs81C6910qBITMcZI
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/keyUsageNotCriticalkeyCertSignFalseCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/keyUsageNotCriticalkeyCertSignFalseCACRL.pem
new file mode 100644
index 0000000000..d7877a9b68
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/keyUsageNotCriticalkeyCertSignFalseCACRL.pem
@@ -0,0 +1,13 @@
+-----BEGIN X509 CRL-----
+MIIB3TCBxgIBATANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEzMDEGA1UEAxMqa2V5VXNhZ2UgTm90
+IENyaXRpY2FsIGtleUNlcnRTaWduIEZhbHNlIENBFw0xMDAxMDEwODMwMDBaFw0z
+MDEyMzEwODMwMDBaoC8wLTAfBgNVHSMEGDAWgBSyJdIoMNBVaG5MtcJI88qbFfJA
+RTAKBgNVHRQEAwIBATANBgkqhkiG9w0BAQsFAAOCAQEAtIeKFZV9BB4OBq63soXU
+rgYDlsozbj5cYoU86vXpmHddbTowwaGtFlqbfg9deTqT6r9IpdIClfZtJVT3s3Lm
+PFb/areGyQblwYuOD6Mldtdty0FH5A9uMMMCEk1iZD0Z8WApxo1bomtY/EI+ZHAF
+N9+xTE7DZtHIOSZ0nyz64fHMPDYQPDGtkK2QQ6nFNX+ljnPOCRBfwwAsndlumWRP
+SlthF8gU3A8008ytHdpkNEsUhf81ntUy4o2pftmjQOnMJT0C97CXykxZBc8f49A9
+QKsI6ql/dt1XO9hNmVp7qamXA7+yhBwfWAKnhXRQn5D64/ZqVxE9lYL7PvJrr1tM
++w==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN1CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN1CACRL.pem
new file mode 100644
index 0000000000..c999bf8b23
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN1CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIByTCBsgIBATANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEfMB0GA1UEAxMWbmFtZUNvbnN0cmFp
+bnRzIEROMSBDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAvMC0wHwYD
+VR0jBBgwFoAUQXhCRs1OqILn4Tnf96kWwAr874YwCgYDVR0UBAMCAQEwDQYJKoZI
+hvcNAQELBQADggEBAFtcX7FztYXgApU6J1ska8lB9xinzLv+LkatWBtqZuRZ8yYU
+LLgGDlzgHX8d51lkdXrlTe3iW6aNmKTFznTRqxPGLNA8VikBmBhNLYGgk0u3HTQD
+hZzWtyLOa4FB26lrREAgvEC7P5TB0Xd1p72E4IwKf1ZV7KOiTpw7EmHLsSWYGcDr
+96mwtkUK6g//vxJnIa+k7C9jjQboCmOyH0HSluB0KQYqislhXHO3BSBxiXVhHec5
+3ToVLhmo/v+3fgl8wkEO2RH9MRcx29+JiRrqLr5xYZy3sKKBX/7e5jT0PQsKFOqI
+CKt6oFNRwz2qzEcbHFMyoDR2+5R8zA8OHCDYf54=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN1subCA1CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN1subCA1CRL.pem
new file mode 100644
index 0000000000..3884626320
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN1subCA1CRL.pem
@@ -0,0 +1,13 @@
+-----BEGIN X509 CRL-----
+MIIB6TCB0gIBATANBgkqhkiG9w0BAQsFADBvMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEaMBgGA1UECxMRcGVybWl0dGVkU3Vi
+dHJlZTExIzAhBgNVBAMTGm5hbWVDb25zdHJhaW50cyBETjEgc3ViQ0ExFw0xMDAx
+MDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoC8wLTAfBgNVHSMEGDAWgBThOA4UGBRD
+XM7nS2LHGsGS9maC6jAKBgNVHRQEAwIBATANBgkqhkiG9w0BAQsFAAOCAQEAL1Mn
+Ok+7QkFamOzoQfdBznGodtPDmg30Cgk3VHY7mAwg0VzRhhTaUHjMrmZzpyKuNNU5
+of9K/maIKludVfLuV9NPmt4pTZWW8l02umkRg/vbAIfPGWpUhev5X3V6f+Bn5bbg
+UQvEiuFQvJzutxukSCkNzijr698Qa5qEu1HzILhO1gQxPhufrfjHqQ5qxAnJiVkm
+uOFSP/OBfuuDg7HS8kCAkzfHrtweRwrrtGf6AYzVZO/+pc7OMOyUW+kh0oXHY60n
+snh7NPi/PNGb4RANJBcQhNKHMVY23eCcwylCnfp7FfuNLSAj55aRvxvG3Pn+WQ+t
+UqzAs79/UBMKcj1IWg==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN1subCA2CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN1subCA2CRL.pem
new file mode 100644
index 0000000000..a39dd31a35
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN1subCA2CRL.pem
@@ -0,0 +1,13 @@
+-----BEGIN X509 CRL-----
+MIIB6TCB0gIBATANBgkqhkiG9w0BAQsFADBvMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEaMBgGA1UECxMRcGVybWl0dGVkU3Vi
+dHJlZTExIzAhBgNVBAMTGm5hbWVDb25zdHJhaW50cyBETjEgc3ViQ0EyFw0xMDAx
+MDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoC8wLTAfBgNVHSMEGDAWgBSiL1iDW0yV
+l7fu9oe0lw7gf+CXFTAKBgNVHRQEAwIBATANBgkqhkiG9w0BAQsFAAOCAQEAyDcs
+pkncHaUX9Ebs68OGd6Vbz7PAjZ/cnQXN6ZzCf1HVx8vtldilw0xP7L6LA1z4/sKe
+5AglNKS18TrC9jvMcs5MPI8g9jNPpmzn4tVGJiISlft8SqKPL9dvgUCODtIj+Vqv
+x5ELHuMRwAsj7vXY6FrgTwM4eTwEbRhYCxM1r05VPj8t/fl5XoNR/4vaCmDYR9uf
+JscXoSlBsXJkPrkxHnrreTiSNtP1iAiX6CXOBctSfPzhrZknzWq76UYq4LnQrqNo
+gyZ1pc46+f7RqxgGOgn/Nb6AqBy+N2vpYXabMKmNpIBmpOGq/qonbtPF/zJbj+fc
+Bafk7fSWIrCNZg0pFw==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN1subCA3CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN1subCA3CRL.pem
new file mode 100644
index 0000000000..7dc7ee7fd4
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN1subCA3CRL.pem
@@ -0,0 +1,13 @@
+-----BEGIN X509 CRL-----
+MIIB6TCB0gIBATANBgkqhkiG9w0BAQsFADBvMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEaMBgGA1UECxMRcGVybWl0dGVkU3Vi
+dHJlZTExIzAhBgNVBAMTGm5hbWVDb25zdHJhaW50cyBETjEgc3ViQ0EzFw0xMDAx
+MDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoC8wLTAfBgNVHSMEGDAWgBQnSeQE2UX6
+bJiUbPztDcMkUm1VRDAKBgNVHRQEAwIBATANBgkqhkiG9w0BAQsFAAOCAQEAuEeu
+G7nwSvVr9BxS9bMPB12xdegiBpg5U2K0vTD1JSSOR+RQ2LvwpJlkNy2oFt8+sbAi
+oTCOgifKXzi0tszHRH8vYcKy+DJ/RE8mX214KIg5Lj3DEpOlzPE19/z+eUl41Pbw
+sgnQTE+ccm2h4GlUefprR8PSZdOIcqxbDbapLHC9vz1Dy1YdM5iySa7YJ7Xk4uDe
+NtysCgwKtANPKF/qtbYQgcZxGPYArrWprgK2xyMBeux7WTQp+9xaSOU2gUmAKwzj
+bt0iV6KEkoU08FmUwzXTxX1bBsjLyIeRFPm58XbJ0MxgGdJPmMn7m2W4PPeMJpGD
+vH1qhNYwy4NsWosCfQ==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN2CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN2CACRL.pem
new file mode 100644
index 0000000000..d32449cf89
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN2CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIByTCBsgIBATANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEfMB0GA1UEAxMWbmFtZUNvbnN0cmFp
+bnRzIEROMiBDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAvMC0wHwYD
+VR0jBBgwFoAUo1fZW10Rs2D2AGuJUSuCwwlzqHswCgYDVR0UBAMCAQEwDQYJKoZI
+hvcNAQELBQADggEBAAky6btWTahA//H8vhr8u8hbW8h/OWD8skXuVJHLv0LdS2cI
+zzk3f1u8vwWaohmjsIdNllFU2hd3GH62mJdoXJflLxxVDm47FWdzmmlyUsxFXojL
+HI+tjwBFmSzzzd/t7GeF5mKc11PrUz9oqoSJEZVCcYQX2px2xJIzmqOkc4VWGrGo
+rIvTE8SETRWTYcE/IDOxc1lSs4KyH/MGIwMeN6Mu3p3d/H8ygXKEzf7gYR0riFW7
+ps5wlQRxDC7ICktp4f2bN8l7pw5TwjCfNmzqDbW9IlDFaRr1VUV6hpPwORT9qWVQ
+7ZbDXVLZwaWxGmp8vYh7weNKgrmfibuz/DcHqPg=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN3CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN3CACRL.pem
new file mode 100644
index 0000000000..a72350793c
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN3CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIByTCBsgIBATANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEfMB0GA1UEAxMWbmFtZUNvbnN0cmFp
+bnRzIEROMyBDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAvMC0wHwYD
+VR0jBBgwFoAUBtxbvscSN1mkikB0fAmdRTxKodswCgYDVR0UBAMCAQEwDQYJKoZI
+hvcNAQELBQADggEBAItPJiJOtxXyscdSk4LVnHx2Ge6LLKaoPE6qXi5JRs2t4LjU
+DJAh0bKPehBDlbvqpV6/e8pqaJP3T1DH28vZTr2gGY/Ar4BcVSzrKO0jH7j2PJU1
+Kzq68kP2/tr90XnUOuz5589ORJ9aryewWxJ5g1w5GqD4dC8NV5aDWPWAdnxVw0Dn
+DVvJl11dzlFqaZSwuDIj0IjzssosDmCrPDUjLDLn37f35XRIX7/GB3ghSrUJLsId
+TrU+ROvpQ4iO9zAVMDfQOePSnUeNpO4Sr/as3lHaFptwj0tY1PIeLcyfv8ZNZYN5
+7Q8+aKRQMPg2ZHGeF0d9ADvGLZTZ2vMCK/hHfL4=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN3subCA1CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN3subCA1CRL.pem
new file mode 100644
index 0000000000..c179e730e0
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN3subCA1CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzTCBtgIBATANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEjMCEGA1UEAxMabmFtZUNvbnN0cmFp
+bnRzIEROMyBzdWJDQTEXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqgLzAt
+MB8GA1UdIwQYMBaAFIC8xy73jhp/8Th79DXr3elYxjxQMAoGA1UdFAQDAgEBMA0G
+CSqGSIb3DQEBCwUAA4IBAQDKBu+BE4WjUUs1+SbDPdTUvtI61Eo5D0f55tSFFzqY
+3mjQN51xcisMQIFvf9dPdD7/MOUjS2GeSG7CgPObXBVkhjsNzNhgUdk7obAAuQNo
+7pj0c+Kp36GKHgSzMmOvzXOpe0OcS0iEJTqOss/+GD+a0kPUQBTQptEFJwPyDdKZ
+yIpuXbmhEtaXJVEq/fIkQLtHDv6VqsOCPDyyca/NP1J2Ed4zEHcP7w4wTcxhCkq1
+duWazm3Bnc3Qu4lIOHUP1VGum+Q4cLzFzNlWCOIaWqCVwQvywAADhy4E/mxHtGAF
+8s55z3PAJfeRKySqkJJtPI5qRgllB+n9b/HxD7DskHy/
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN3subCA2CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN3subCA2CRL.pem
new file mode 100644
index 0000000000..4f416b3ab6
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN3subCA2CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzTCBtgIBATANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEjMCEGA1UEAxMabmFtZUNvbnN0cmFp
+bnRzIEROMyBzdWJDQTIXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqgLzAt
+MB8GA1UdIwQYMBaAFMwE7WooHX7eZOoAiCrsdRG/pS5nMAoGA1UdFAQDAgEBMA0G
+CSqGSIb3DQEBCwUAA4IBAQBSQba9PCeM3gDcJ5/15bCZXzS1J88gi1mSM00AHLmm
+cvaM3zC1dupZ3+nUGrGuJeSy9gJvKmRvCGQJVVScbWaJSBCLsE2OTLQZosIbktpA
+SMDnJNCgEQMqL3S8I0U71qD4gw/f8DoxBloqVyzuwIynWZl+V9agP5UCWweDpo3n
+zqfqm4zYF2gZYgVz53l9/zYpxr8e0d6o/Y2sqk6ykbzR1e+Yw8Jr5AKs8awilABf
+Lu5pl0DO/pFtT1cX7MEtd1aoxZqQxssOS0JlosEF66VMeOKgUw4uvovkbjP9zfUr
+GfwYbvUJZ4XSDy6p68jsQKRpG7/v6V6Xy4LcZ+4I+ATD
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN4CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN4CACRL.pem
new file mode 100644
index 0000000000..bd4472556c
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN4CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIByTCBsgIBATANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEfMB0GA1UEAxMWbmFtZUNvbnN0cmFp
+bnRzIERONCBDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAvMC0wHwYD
+VR0jBBgwFoAUbEk2rS5YiRI2UUE7VFImJADTynUwCgYDVR0UBAMCAQEwDQYJKoZI
+hvcNAQELBQADggEBAH6NXW4G6VFh6lalxV0HfwwV4W70J+q058P1U/nVsOOg7s46
+v+bhzKwJrIovS+fGE+WmDCMbeeIzvmMnkF7ZSGmZarmGDzNGsxghmiNHW9eP2Wk2
+7QjyePG/cAff8ILOqzCHw1WZMtIgyVM3tQY492xqKPRTBac5P5DN6COtBGzKsk7O
+mtOvhcqtwMt5ejXil9ibRhAKHcgoNtzOoZoaQOvTajOP0vdFYnHHkF+bFDd+lxUE
+IHgX9IOmk1xGFgdEcSpQL+6mvV0aKk9iavdbVBQCeWzul24GRr21EVO2emR3oceI
+vBeEL509yRgDMZoosPcUPzU3MCre4KHexkxNGKg=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN5CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN5CACRL.pem
new file mode 100644
index 0000000000..bdb12dbf59
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDN5CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIByTCBsgIBATANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEfMB0GA1UEAxMWbmFtZUNvbnN0cmFp
+bnRzIERONSBDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAvMC0wHwYD
+VR0jBBgwFoAUup8JypA5nE53Wuv7EJWs06dKXScwCgYDVR0UBAMCAQEwDQYJKoZI
+hvcNAQELBQADggEBAITmZi9ly086wq/MHAGjaUYsma31grAeyveTU+oJ7olEb42/
+ALSN0DXoO4UjV1bj/wiIPtErg0EjHWqVW4M9ID8ZdfDuXBLNBQ2NP14gJLjVTk2H
+6iHx4QK9QiB1gVdfKbj5+lTCt+7YWZtOWovr5SIlPtbNqszR1gpTLaLyIkT1FRg0
+txRaU4qTZmOIYCuWGEWeh0F9xHAZ4d30j1KcBSdHzOL28ibTjgDsYQF1680ChYu6
+TMUWY6q/ufziFDezkXkrLrtNWAwYZvS4sRynpbrhKUL+CldFK/u96ZZwL6T9Nkkn
+aY1gGgepUvLKlQt20+jmOu/L8Va7xcXK+AtuQQI=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDNS1CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDNS1CACRL.pem
new file mode 100644
index 0000000000..33e2aa1407
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDNS1CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIByjCBswIBATANBgkqhkiG9w0BAQsFADBQMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEgMB4GA1UEAxMXbmFtZUNvbnN0cmFp
+bnRzIEROUzEgQ0EXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqgLzAtMB8G
+A1UdIwQYMBaAFLGqF/Djz8zSp4mmgwfd/27aB+NJMAoGA1UdFAQDAgEBMA0GCSqG
+SIb3DQEBCwUAA4IBAQA16Gsjfh0eCk00xbqXxGjwPJCTmNcQ5BQRATn1KHZNDm0l
+HSuZNQELk9z/M1jw8rEArioWWkLQEKdVQ8WtjFYYYcj7VTo8aho763/UhY1WBQQF
+ISHqASE4ygCUcwSKus12Ksk+NXvvARlv5EG/UqoSAMx+6t0VLuPteV5JtXaAgABC
+xXScnAJvH0BZJWDXh8x9TCocXxmH9SsZhgXM4WEZxRch1Z3bxLd3NrxztPXe8h7H
+9Lvp/TOEvTdjtbBn0kwomw1DCVeJd9DBNXFO5YvXyDBU3usNmHNMk0wri1roJzUg
+UrnYLYox1O/52yeQdQiSAkQ3grctmcBcJW8WaIWu
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDNS2CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDNS2CACRL.pem
new file mode 100644
index 0000000000..02b8226a6d
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsDNS2CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIByjCBswIBATANBgkqhkiG9w0BAQsFADBQMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEgMB4GA1UEAxMXbmFtZUNvbnN0cmFp
+bnRzIEROUzIgQ0EXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqgLzAtMB8G
+A1UdIwQYMBaAFEZInEIJjl1TcNgWHuDByRgVNQoGMAoGA1UdFAQDAgEBMA0GCSqG
+SIb3DQEBCwUAA4IBAQAmhkWLOOzNQKAS8uW774Ig/r2A1dpM2sBujFbCeg9blw2k
+/qRHoInFtwM22vgIBInC6EZW8qPqzPeJpjIluu02T25EjxRFGiameUbHQ02XAejf
+thhUnDw6lWF+N/sIKYXCkN6TuiKC9m4LPvlmI1JC1RqGWmZIsl59ae4zV1G0iyMy
+ol7WhsPhzsQj8pRACFdznwq0ehd3L8UO43BHl8+rXVzS6f++filZ2WZHPFCR5Nq8
+l9KaNhNCE7VeBQv7dElPeknvANPEGomeXFIIPwCx7Ra2mc3mjG5qYwmX1JYjPxe4
+siLRqgKc8s5vwYGwwPqtoInJckVUxfkZ8YAu5vTI
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsRFC822CA1CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsRFC822CA1CRL.pem
new file mode 100644
index 0000000000..4b594be896
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsRFC822CA1CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzTCBtgIBATANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEjMCEGA1UEAxMabmFtZUNvbnN0cmFp
+bnRzIFJGQzgyMiBDQTEXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqgLzAt
+MB8GA1UdIwQYMBaAFMhqjrEPS6qliLinj5Hb6jNK6NXiMAoGA1UdFAQDAgEBMA0G
+CSqGSIb3DQEBCwUAA4IBAQAEHhqk9qr1vH2Svec33ko0nUKpbgipddl8h6FtsAXi
+ewGnaaUK55/3Eu4FsbORjB+jSKWvYyaXnMPecX8zseOKgDWEiPZY6i+0/16Dz/NI
+2aOEVA3hxBmSToyka2FOki/KzcWfeKpebdihmZ/pyKk2qo5ygfASyV+/3fyroafe
+0FwfIRz0EHXamVhpTBVK/nsmtk2KxccIP0QjPkCu95nAAzeXJVTbzOUAbz9ZDpnM
+puACGthyjzpNfQmx1LHF1juFUdywoQSm/c/FOoPnU2KH2Ae/x0Z+tKQ3O36c72EV
+IU8WWZP82htw8qMDi5U5gymAIdQJjsyKbg53DpbkEwom
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsRFC822CA2CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsRFC822CA2CRL.pem
new file mode 100644
index 0000000000..6aa93849c0
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsRFC822CA2CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzTCBtgIBATANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEjMCEGA1UEAxMabmFtZUNvbnN0cmFp
+bnRzIFJGQzgyMiBDQTIXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqgLzAt
+MB8GA1UdIwQYMBaAFFGAzfpJckg87Q5OC87OH0BlEnCgMAoGA1UdFAQDAgEBMA0G
+CSqGSIb3DQEBCwUAA4IBAQAw8GlFDmo7lahPoMQ4ha8PN7CTyiVN52wVziP3qO0H
+uFi2H7EZV3VuYHNfJlzeeRtXGjpxBDiYkJJIg/n4ibxdyNtRnCjWTDb0BKbnQuUb
+QxoDRWuzc6G2pJ29H3Dp6DHQ7TLZwCfPfayn3AfOJBtYQpLk6c7ejrgXWv0T1ZSv
+H871UQpCF57JNU3zco9nXYN+I2IVnfgG08JXxGJsw3PMg1xa4v3awSYQ00/8v66G
+lBekAv9no926ub3Hp2DwYwcfE7iLaOdLtnBFPjdFLuZTPIGGJeeIve6NaEAwPqWO
+ZNUKSZipydOKeYsvEVEFUxVApV4TZbcSREvjGXQlYuH9
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsRFC822CA3CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsRFC822CA3CRL.pem
new file mode 100644
index 0000000000..b2cec3d3fa
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsRFC822CA3CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzTCBtgIBATANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEjMCEGA1UEAxMabmFtZUNvbnN0cmFp
+bnRzIFJGQzgyMiBDQTMXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqgLzAt
+MB8GA1UdIwQYMBaAFJq6OU3aIXWv6kHDPGxR2KhFqX+jMAoGA1UdFAQDAgEBMA0G
+CSqGSIb3DQEBCwUAA4IBAQAAhq4g3DB1Yb6DUVC11zrj0kzA3Lbth5HDupuy0okk
+5Do0LQZeiwCI37JhQceiRGxtD5riXbo3LyL2g+XqV1OCTXAbJrRAe+5sHmwrH8pO
+PZobXV32KSzzqzPbUNn4QmQDxfQLZgGAz/aPtMDuBIm22oI5iP93csW6p0lHcu34
+Z78RF06bdhO5nd8PbU8BQ+weHoWq8h8iykRzkvxL2d+vk0rS9AbEu0Hs/tqnw/pD
+1l+cuy9gmD5MFpfoMDZ9seQAKJOt5VkKW4rphhX9b3rm2cxceIqlvqQgJip+RM/I
+v3o2PYMSOePzWfRA63LYY8B5sY79W0v/miCl08vsjte9
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsURI1CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsURI1CACRL.pem
new file mode 100644
index 0000000000..67688e4aa4
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsURI1CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIByjCBswIBATANBgkqhkiG9w0BAQsFADBQMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEgMB4GA1UEAxMXbmFtZUNvbnN0cmFp
+bnRzIFVSSTEgQ0EXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqgLzAtMB8G
+A1UdIwQYMBaAFPoorUEW3ipoF8gPHCM/JgPeAhQCMAoGA1UdFAQDAgEBMA0GCSqG
+SIb3DQEBCwUAA4IBAQAr3EikSVaRZA2v0/ARpi/8rC3nZprCYF4pOzM5aC96Hooz
+oEfd6+gFBJWGGPyyQuztWCg4AYXJqqotuSL0rGteXeA7S09i58Vi0rMZEYiaw1HV
+EYvt4LDShzMpeTXstjWCfMlhWnBVII+6ga0LwGD1SWtci91T6zgYlXczH33esi9i
+ras/1f4p1SQDAyo1gHulaaBRJvqQrjE/MaL8q3Ts0kQMM57aI6UeqpydIttGUcl3
+pwNujq4V8yChxN9nB1wQauRsi9xCaqTJwLDqxouZIxdUeFWEQvRAIur8NHdhZrE0
+gvLGaebETdYzvDYEkFdVMsYNWPEmd2fZ+F8dJKYB
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsURI2CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsURI2CACRL.pem
new file mode 100644
index 0000000000..fa5a247617
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/nameConstraintsURI2CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIByjCBswIBATANBgkqhkiG9w0BAQsFADBQMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEgMB4GA1UEAxMXbmFtZUNvbnN0cmFp
+bnRzIFVSSTIgQ0EXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqgLzAtMB8G
+A1UdIwQYMBaAFE3riXHf8AQBsvp2OlixumDdjNPDMAoGA1UdFAQDAgEBMA0GCSqG
+SIb3DQEBCwUAA4IBAQBk9OEGWwvZ0lgWzqgJL4OZ9j0+fjAMdi78QuVFSmvPPOi3
+kLfoOrPjMNmwi42SIz4BEyDt0iVxlq+eYqrIN5q/NqFdjl1w0UvNivcuPMjYtkdg
+4XPJXcfGCfnKbZ1voHnuDlmj6+lpUsXRA0YjgRhmGz4T26ReJO1FQy6+DDqO27+V
+CZ3JM83sNDNlcMeZZk9f46HtFq/kwvqFpTHmqWvvti1hLal0aRetSyckf01vmHQa
+14FbJwEqs6hrwxhLN6Fwd/b6lN3+vLbgucxKkFvRL0JUbPuY2VtFlJk8WOllxXMc
+MYhV7lqBnaFyCO+gWQaEIE5dDbKQTNVpmVRqbT+8
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlyContainsAttributeCertsCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlyContainsAttributeCertsCACRL.pem
new file mode 100644
index 0000000000..0c5aa4a18c
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlyContainsAttributeCertsCACRL.pem
@@ -0,0 +1,13 @@
+-----BEGIN X509 CRL-----
+MIIB4TCBygIBATANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEmMCQGA1UEAxMdb25seUNvbnRhaW5z
+QXR0cmlidXRlQ2VydHMgQ0EXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqg
+QDA+MB8GA1UdIwQYMBaAFE0H/vYtvLUZGlBN35kEem0zcJBOMA8GA1UdHAEB/wQF
+MAOFAf8wCgYDVR0UBAMCAQEwDQYJKoZIhvcNAQELBQADggEBAILLUDuBlm16hFFX
+7mKimuJxRJIqqqi7YTYNnUkkt1ZjNwD+Zb+YdPhJrJJMboHIGRErVjSDGwHJs0HF
+HveDuGTcBDgqyJeG0C55xjRlSkPABS4jtWVVROYX/GkccJOjCGEs8A0vMVWUrsP9
+Otao6UOKDtn4wNkaItZ1Mv8Bbk1han+DsqJIdjCc3T8RV6xZcyQ9o0uO7THeyATG
+mPT6keQhjiAbT7NtvSL7pdd+F3U+68etzFFxjwqFr7/wSJxVWzF4vtrwW6tqPcCF
+SXNG3adV0JgEG4luWVHRC2GODHTh8DeygWMtEkKtkRouQMFoZGv7MvgoqlewMTfB
+1YnOC+M=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlyContainsCACertsCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlyContainsCACertsCACRL.pem
new file mode 100644
index 0000000000..23ab0ba052
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlyContainsCACertsCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB2jCBwwIBATANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEfMB0GA1UEAxMWb25seUNvbnRhaW5z
+Q0FDZXJ0cyBDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqBAMD4wHwYD
+VR0jBBgwFoAUJTjDrsotdXpbTdTAA5KIEyLHbFQwDwYDVR0cAQH/BAUwA4IB/zAK
+BgNVHRQEAwIBATANBgkqhkiG9w0BAQsFAAOCAQEAMHmB5cF8VCL97/Gfo/Dpi3SC
+hi1rnJSgDEUQFwICI2Jlyewhfxs6F/EC7F0YYnPPfiA8ajXpGp5ccAvVUIoQUBgX
+iUdjp/RBmalZoyzPw8ZkGQMyy6ehymfyMnH/wKrivmAnxtPm8SGuWVJouu0T5+7n
+8G/vJg4q42RHYQQ7ripuh6wiI+Lf9wNHAzmmGsT6vG0Yrpg0hAcQzhof9xOK88h1
+xyJPReiXKjJx8Uvp/jIRjarGdjh19va1ysYLfMypqeF3C3Lb3J9vuxLS31FdX93s
+wLY919ormQApL+COmVhzilgTKI6ZfgxFhlF3nRNMQDdGc/r3tdezNoMznqBbBA==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlyContainsUserCertsCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlyContainsUserCertsCACRL.pem
new file mode 100644
index 0000000000..e99752a506
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlyContainsUserCertsCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB3DCBxQIBATANBgkqhkiG9w0BAQsFADBRMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEhMB8GA1UEAxMYb25seUNvbnRhaW5z
+VXNlckNlcnRzIENBFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoEAwPjAf
+BgNVHSMEGDAWgBSdvACp3AHN/h2WiH21nk+Z3iTSBTAPBgNVHRwBAf8EBTADgQH/
+MAoGA1UdFAQDAgEBMA0GCSqGSIb3DQEBCwUAA4IBAQCHCFuxTPvpn0fp83f2Az3x
+GKcDG6BSg4w2lISlNPpcuzAOfsNrNNvWBc8jiwdsgKpMr2rFH7HdpvG9k+A5EqT4
+B978vmdJe6d+HJ0a6RINKrDeQ3BWUeZVyzXzKJvJNEtP6+l67BA/PV1O7t93prcA
+sUdgfm074/h81yKVQJKfsE+H9yCXo4XxlvN9/37Du9lNWtlU13tvD1Hc7FjO3pB2
++YJQwmKhlXrt+7K96k9DdPJMXGzJmpICBFxHz8KkC3f0vmYau2h8FzDZV3P0trhO
+azIpQl9N2nqKsYQ57hLeTBRQ3B9tlKm8MH3lzfYUf8Iktufhg/HGuFg35gfeZWUd
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA1compromiseCRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA1compromiseCRL.pem
new file mode 100644
index 0000000000..8aeb421af8
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA1compromiseCRL.pem
@@ -0,0 +1,13 @@
+-----BEGIN X509 CRL-----
+MIIB/DCB5QIBATANBgkqhkiG9w0BAQsFADBMMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEcMBoGA1UEAxMTb25seVNvbWVSZWFz
+b25zIENBMRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWjAiMCACAQEXDTEw
+MDEwMTA4MzAwMFowDDAKBgNVHRUEAwoBAaBBMD8wHwYDVR0jBBgwFoAUUGjRCUEn
+h+cKTrd4VvsXju4EB3EwEAYDVR0cAQH/BAYwBIMCBWAwCgYDVR0UBAMCAQEwDQYJ
+KoZIhvcNAQELBQADggEBAGGC6QC55Xv0YiF5ILhvWpoLo4gexHND0T8vTNw6fKSa
+g9Re5ty4c1tDwJkRQ3RRY36O82BLImIyx+NltDfnu21/0zLv9XbZxHUraT+5Ch2v
+smfGOTG/zm7a0Ht0QtM6q/br1RJPbxG0c7RUyV4hooP9WDV2UIz/9ba6XfbIf6Ts
+SaDhRmu6P2hbGTuAvKwsMR+DgDRvCQ8OUdc639W2hiVXaf5+kHyQz25BDTDEOptA
+cwgpFmaZiGKgltA63nn4Fl797/VmQbQYg8pmRPsEPeF5kw6n5lbXEo7wLXG4dc4N
+GiqeRO8oi8zU8rI/ddx+zr9jUeJZQldzM9VBsOq2c8c=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA1otherreasonsCRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA1otherreasonsCRL.pem
new file mode 100644
index 0000000000..49f7456ffa
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA1otherreasonsCRL.pem
@@ -0,0 +1,13 @@
+-----BEGIN X509 CRL-----
+MIIB/TCB5gIBATANBgkqhkiG9w0BAQsFADBMMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEcMBoGA1UEAxMTb25seVNvbWVSZWFz
+b25zIENBMRcNMTAwMTAxMDgzMDAxWhcNMzAxMjMxMDgzMDAwWjAiMCACAQIXDTEw
+MDEwMTA4MzAwMFowDDAKBgNVHRUEAwoBBqBCMEAwHwYDVR0jBBgwFoAUUGjRCUEn
+h+cKTrd4VvsXju4EB3EwEQYDVR0cAQH/BAcwBYMDB5+AMAoGA1UdFAQDAgEBMA0G
+CSqGSIb3DQEBCwUAA4IBAQASB9/TxIVbi32C3VcEK5Q9oKUrzWbOmzDBEI3G1S0k
+Y451pdZaFfBVzikVlcBVTw5gikTy4TUK6sEoysiEvRlpTzYuBxqKQgXwacRlVNUG
+mzZqYmHQycTyrlZfv4PyVPrz6E9ToTvz9/DymSkswVyBm/GKZ3Rq31G8niu4xHT2
+EBz0BEW3/GN9sUC/Y4dGPcTNJc3OkcrL7t1YKfz9H+dFdXqpTW9wdt6DkyEI/Ync
+3pxo6Qnj8Wwk8U2aiDvKqQh6z/b8Mlt1CullIhKM3SqGzTqGnv7SntdZwTv/1oeY
+dbpJ6VGFTMqXxUkgDnR4ba+Tn9iMkAUakQvbjnN5/mgW
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA2CRL1.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA2CRL1.pem
new file mode 100644
index 0000000000..2d585f4780
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA2CRL1.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB2DCBwQIBATANBgkqhkiG9w0BAQsFADBMMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEcMBoGA1UEAxMTb25seVNvbWVSZWFz
+b25zIENBMhcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqBBMD8wHwYDVR0j
+BBgwFoAUYGPf0iOkKdZBpKzKhnmYpmUBSK4wEAYDVR0cAQH/BAYwBIMCAxgwCgYD
+VR0UBAMCAQEwDQYJKoZIhvcNAQELBQADggEBAE7Yv0ls2R1n277KQK1TR+2NXC1y
+pY4ZorshYnrshNO+Uy23PtVCJzy0390E1CsDzIZdmz+/rXEDsQOSwCYDWrCSo6hK
+BCyTlWBfqZcNTQJnRgYV95e3yHaqY0mEgY6l+az1gDR7hC5UBwFPnFGNnY0s9JSD
+bu4LOdl+bT8QmTw02+hfMA4Q/I+ytJOkWkLs+5pLg6vyQreprf8MjJDdGxG0oKk5
+Q+vPpYQQmsyBosaz7mNSuZ799BAqRAl0ATMmT5FGldFo7whlDhyYwCnT6djdR3nd
+nsBhSdbf3LXqnKk6i79U1H+Yzx0XagnJA7wGGmHf5oIRRVDaMmQOzaf/sl0=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA2CRL2.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA2CRL2.pem
new file mode 100644
index 0000000000..657f0999fa
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA2CRL2.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB2DCBwQIBATANBgkqhkiG9w0BAQsFADBMMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEcMBoGA1UEAxMTb25seVNvbWVSZWFz
+b25zIENBMhcNMTAwMTAxMDgzMDAxWhcNMzAxMjMxMDgzMDAwWqBBMD8wHwYDVR0j
+BBgwFoAUYGPf0iOkKdZBpKzKhnmYpmUBSK4wEAYDVR0cAQH/BAYwBIMCAQYwCgYD
+VR0UBAMCAQEwDQYJKoZIhvcNAQELBQADggEBAI78t4QP3CIEpYKHa9TIyjr1Z+lq
+HE7UgiKd4HbsKK5gPDAme9A/DK/klDZoufxmSUnjJ+KO5yE5YiQITW9k2CvZL17g
+Wo8miQcf7HFp9dEEnwd6yHE10ZmqqIJrujTaa9P76KhaovCCoWlJUAyCOSF9DDyj
+5fJyJYUKxXo4FwkcViwsJgp4NK3m+YB3BYFRy/p4PQKPFYYrDMI1yx8B/lOp16UH
+rhYzMC5sohfnCpryHxNTgBu1Cy9XzITBvUniXOtMO+hY/axGojkm/IOQSlzYAahL
+AOc1qr6BEK/tkWxUJanBWTpPh5d5Rojto/uu4fOG4XbQLS4PllRZlCKQTyY=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA3compromiseCRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA3compromiseCRL.pem
new file mode 100644
index 0000000000..acac31a59e
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA3compromiseCRL.pem
@@ -0,0 +1,15 @@
+-----BEGIN X509 CRL-----
+MIICPTCCASUCAQEwDQYJKoZIhvcNAQELBQAwTDELMAkGA1UEBhMCVVMxHzAdBgNV
+BAoTFlRlc3QgQ2VydGlmaWNhdGVzIDIwMTExHDAaBgNVBAsTE29ubHlTb21lUmVh
+c29ucyBDQTMXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqggaQwgaEwHwYD
+VR0jBBgwFoAULSS3l4cs7tocvt6XhBuvoBUWvmswcgYDVR0cAQH/BGgwZqBgoF6k
+XDBaMQswCQYDVQQGEwJVUzEfMB0GA1UEChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAx
+MTEcMBoGA1UECxMTb25seVNvbWVSZWFzb25zIENBMzEMMAoGA1UEAxMDQ1JMgwIF
+YDAKBgNVHRQEAwIBATANBgkqhkiG9w0BAQsFAAOCAQEAdQRa9rY2kA/f5hPXwMzB
+IiCNKdlFB5gAcrElHOAFq8MP3BQ6LtE0dH+RoAudtqh92aydcFza5EsMVAQq99AM
+jBjlm535dj9hxo79uqC2ZReofJBNgLL5H8cktqZPCsnyeGgDWDxHGtSE7PThveN3
+4VD9Kstk04qFpJ/8TK3BPca6zEtTb0k8LkpRojumPy+KGNs936HEkGwRBQaFkn4v
+i0gosO557Q4wXMI4AQfuY5jGCavXjUkXoR1BlS0CrQqMFC69J8hOrpK7tOdDPefa
+NpCf+3pMgASPMhuc3W9/bQIQTQL/dFwdfQZCmJUrxu3e04URw13J+rDXaZKgYXb9
+cg==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA3otherreasonsCRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA3otherreasonsCRL.pem
new file mode 100644
index 0000000000..3d20df2931
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA3otherreasonsCRL.pem
@@ -0,0 +1,15 @@
+-----BEGIN X509 CRL-----
+MIICPjCCASYCAQEwDQYJKoZIhvcNAQELBQAwTDELMAkGA1UEBhMCVVMxHzAdBgNV
+BAoTFlRlc3QgQ2VydGlmaWNhdGVzIDIwMTExHDAaBgNVBAsTE29ubHlTb21lUmVh
+c29ucyBDQTMXDTEwMDEwMTA4MzAwMVoXDTMwMTIzMTA4MzAwMFqggaUwgaIwHwYD
+VR0jBBgwFoAULSS3l4cs7tocvt6XhBuvoBUWvmswcwYDVR0cAQH/BGkwZ6BgoF6k
+XDBaMQswCQYDVQQGEwJVUzEfMB0GA1UEChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAx
+MTEcMBoGA1UECxMTb25seVNvbWVSZWFzb25zIENBMzEMMAoGA1UEAxMDQ1JMgwMH
+n4AwCgYDVR0UBAMCAQEwDQYJKoZIhvcNAQELBQADggEBAE32bsFUkG2yqjakiO6C
+h4PUu/ZdW+ec4ZPUt/0Aw5pN/yGw2DJp2nBjHbLEn8qoxZbVX7CM4Kl44520B2Mm
+rn/e/dmOMzfKLV5SxreIg2gzl0Y/mg4JqmGza4sTA8nDExWiRyqQbf7wIgK6pQEU
+sEjvc2RsJrzvIt6QryEMYAJaAe9FaMP++SnKSKisBKzcirBgTz0nrPrNkUcI2o6P
+GHW3ZwPfyDsUhx1z2sbtT3y/svye0Ksgh+2wZc3tU5zsvRAKN6fokw4ADhlporgF
+3WZLQJcywJElK3w7mPc8YL9JKieuAiul/E1dbpnm8dA9Sj5oDyooynxUav/o4HCl
+WDw=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA4compromiseCRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA4compromiseCRL.pem
new file mode 100644
index 0000000000..3b60898d4d
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA4compromiseCRL.pem
@@ -0,0 +1,15 @@
+-----BEGIN X509 CRL-----
+MIICYjCCAUoCAQEwDQYJKoZIhvcNAQELBQAwTDELMAkGA1UEBhMCVVMxHzAdBgNV
+BAoTFlRlc3QgQ2VydGlmaWNhdGVzIDIwMTExHDAaBgNVBAsTE29ubHlTb21lUmVh
+c29ucyBDQTQXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFowIjAgAgECFw0x
+MDAxMDEwODMwMDBaMAwwCgYDVR0VBAMKAQGggaUwgaIwHwYDVR0jBBgwFoAUvmbc
+HgwGO/bTiDSRUyaBDWgXbskwcwYDVR0cAQH/BGkwZ6BhoF+kXTBbMQswCQYDVQQG
+EwJVUzEfMB0GA1UEChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEcMBoGA1UECxMT
+b25seVNvbWVSZWFzb25zIENBNDENMAsGA1UEAxMEQ1JMMYMCBWAwCgYDVR0UBAMC
+AQEwDQYJKoZIhvcNAQELBQADggEBAAJIN0tHbsczxcPvHunvZEwHCJR0fVLav9lF
+XrsjWM5Qsaj0eOddNDav/I/ELvHUL2JCVu0UKLtwlNZlAIPgOKi3wEhf6qSV2WY8
+NW+zQ8Zdk+zuIsE/to9477C7VJfd95fqPhxFRzrfo3R1TCwEskmOVhvwIcsuYOfM
+fNl1ObbutpSkauLcUTJaHkdo0/QO6vSMEEVbmVbqXUOVq/Bbv4QFypTl9tEGCAeS
+SXhy9KG1XxdDJRL8nExHIqzvaBxRg0IJAHGi1ERrL3mlUyq/0AkHnT2kqrNaVzxL
+aDF48Wb41H/JPZjU73gRqAm4HHQcEIR/ZMgCQy2ZqMFxubBzw6U=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA4otherreasonsCRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA4otherreasonsCRL.pem
new file mode 100644
index 0000000000..189002c25d
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/onlySomeReasonsCA4otherreasonsCRL.pem
@@ -0,0 +1,15 @@
+-----BEGIN X509 CRL-----
+MIICYzCCAUsCAQEwDQYJKoZIhvcNAQELBQAwTDELMAkGA1UEBhMCVVMxHzAdBgNV
+BAoTFlRlc3QgQ2VydGlmaWNhdGVzIDIwMTExHDAaBgNVBAsTE29ubHlTb21lUmVh
+c29ucyBDQTQXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFowIjAgAgEDFw0x
+MDAxMDEwODMwMDBaMAwwCgYDVR0VBAMKAQOggaYwgaMwHwYDVR0jBBgwFoAUvmbc
+HgwGO/bTiDSRUyaBDWgXbskwdAYDVR0cAQH/BGowaKBhoF+kXTBbMQswCQYDVQQG
+EwJVUzEfMB0GA1UEChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEcMBoGA1UECxMT
+b25seVNvbWVSZWFzb25zIENBNDENMAsGA1UEAxMEQ1JMMoMDB5+AMAoGA1UdFAQD
+AgEBMA0GCSqGSIb3DQEBCwUAA4IBAQA6VO6zbrPramIZ5tc+d2wb1qV2eX230xjC
+Z+k9zK/PWUvG47ZOYUDccUWhVUgH99nRvoqdhVZrF69HIqdJx8a1+kvi45meJsHN
+faOVtyb2cXnYduYiSrcVZtimnSItAc9LIKt5NvRKVbsD/ZX4Nf+fnCaQEmd1Vx89
+dWq+5Pt3iqORg89D6HzU1GFVE/ES60t7rUbYkxKdfnZhsauX6Mm7ZBIDZK6I14LD
+6qm0UicAFZzpn15jKZWD6h3s3ZGgpFBIR1CkQH5pyTLQK/jPma1mq6ktz3hHjAfR
++BFDWpDxlfjcvBm8TPB8kmPYF9zl7fj8VkpDW/g2jwvDYNwyuYq9
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint0CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint0CACRL.pem
new file mode 100644
index 0000000000..c1142fd5f2
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint0CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIByDCBsQIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEeMBwGA1UEAxMVcGF0aExlbkNvbnN0
+cmFpbnQwIENBFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoC8wLTAfBgNV
+HSMEGDAWgBSbK7JKPJDFblABySK9Y84J8Yw9+jAKBgNVHRQEAwIBATANBgkqhkiG
+9w0BAQsFAAOCAQEACbNqHOyNhLoyqsp302Qhh2DQ5xn50BIJt8FHPQoxzjgcSxkV
+vSWc3F7o93x2Gy3t90APobAPMq7lgkvI9rUyIdg3jn+mkAyaGOaZNoocBVIGwEmI
+ITL2DEhUSGag4wZgXgxAqkcvasDMihLpVudYujuqQ3sU4FLxr1jwXtdtwmXrYHSx
+W3CFNk07BfXdrjETCFJVP2fmElf1s3xOJJaw82NqWBAU7OGk/CTI0XQwxPHAqnao
+Pywh9giLL8cjIqi77qOQk3qSmPvygMXfsMQv1LkdL1UpSNta0D4NurcyLXUojN9p
+qwk5NGs5KwY5CNr3lncwUfuSkuySGB+KmoSzQA==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint0subCA2CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint0subCA2CRL.pem
new file mode 100644
index 0000000000..34b51bd784
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint0subCA2CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzDCBtQIBATANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEiMCAGA1UEAxMZcGF0aExlbkNvbnN0
+cmFpbnQwIHN1YkNBMhcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAvMC0w
+HwYDVR0jBBgwFoAUxgkqG/u46T5oYHrHl86zWFF7dt4wCgYDVR0UBAMCAQEwDQYJ
+KoZIhvcNAQELBQADggEBAJqExyZTBoPDB2CCe0jcRtIcGgoQJSMase7HfvYA2gVB
+zQ+2yRT8qyeoK/ybY8kBRGQ8pSfv7R4ARlwK2vvAfx70U512ssjSDWpmAXK3EuDU
+JVvVfrmHO66z6LhZ1BUx3ngzk1tnEZnvfCWqMGkRFh3dXT142l/0uWGdEBpr/lyy
+zhhJZ+AvGuhEWpeuAI5GL4Gw7p/YBaMoioEvVVMJ16Jp9k7dwaFF7hSPLf31GCtn
+Rm/6rENr/P+vdFLRET/FG84eGMBsLtlW4y6q2boQImMqZZ6uC5hIfK1Ke4vLfEZS
+/6Qs392dyBadvH2ifTb/L95kG7zGC7fHAx2e+tECzCo=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint0subCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint0subCACRL.pem
new file mode 100644
index 0000000000..1c2c371782
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint0subCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIByzCBtAIBATANBgkqhkiG9w0BAQsFADBRMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEhMB8GA1UEAxMYcGF0aExlbkNvbnN0
+cmFpbnQwIHN1YkNBFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoC8wLTAf
+BgNVHSMEGDAWgBQUYmcQfdI3xXIG0N5/tRYdyqNzXjAKBgNVHRQEAwIBATANBgkq
+hkiG9w0BAQsFAAOCAQEAFpwGZEbWR35NljL/Cqg+hxRkUXPsz9aZL5+OrEpCBF/F
+AvtTISr5emDzeNbc+DWdsPAIYIOZ/1kx31aA+0e9Hc5Bac7O246yIwM/kyODPfM+
+36CTCsUCHdIlEm2tDNOhn7gHV9y+tJkT49rRp952zeTwloKyMADiR5amnqhcoOXp
++uY55zW2wQLkADXqukppj4bP13g/R9fIZvhkTFLD1FGArjGt9HH1Hfe3n3MjI0TV
+AaD5TOm4Jogz8RsrFDz3EFMUxCb06jcGz+B3Oe5etjJ0aSpbG8d5ETgGAW3ucXbP
+eVlTs9xMJlm4s34hxYOI3Xnu2ksQ3YiHccWpFcNo8Q==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint1CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint1CACRL.pem
new file mode 100644
index 0000000000..c0dedb88c7
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint1CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIByDCBsQIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEeMBwGA1UEAxMVcGF0aExlbkNvbnN0
+cmFpbnQxIENBFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoC8wLTAfBgNV
+HSMEGDAWgBTz5HFg/xcU3o0mhTN+HPzBR2f6wTAKBgNVHRQEAwIBATANBgkqhkiG
+9w0BAQsFAAOCAQEAYUHA3NQZQRmqjqAh2cWof7Fkl+YK2qY4pF/Yo6L2+ASqcQaE
+6+YCwPVUcjJsNzrF76KKHib7UbodnAH9cBBig1d5a00OFN9n4B81Ha7C0UxKtphU
+gm7wVEBlsHY8KAcV9y+VX11UX9qJ2GEAN1pa/Kio6w42wMcW/oDrAO7UKZtzJv3M
+peqQexGUQYQMbyIh2TTz4TOk2uZovikXa2+1FiUqFPNZfHkZ4eRnQBUQBxFJT1pj
+m0QtotM8+yChkTGrP52ilV/GI3kaLuyIbZVl7adUHiIxUkrEmmkOl7OHhsKwrrTU
+9RkZtL1XF075smmMW8iNRRVEDA3HqJxv2GN0iQ==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint1subCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint1subCACRL.pem
new file mode 100644
index 0000000000..fd43b9187b
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint1subCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIByzCBtAIBATANBgkqhkiG9w0BAQsFADBRMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEhMB8GA1UEAxMYcGF0aExlbkNvbnN0
+cmFpbnQxIHN1YkNBFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoC8wLTAf
+BgNVHSMEGDAWgBTlmZa1x31VQq2Bjscl9hjNrJ2QeTAKBgNVHRQEAwIBATANBgkq
+hkiG9w0BAQsFAAOCAQEAE0X1RyeBmz4sK6l9ognWRz3YK1XFln2WRcvR6Rnj5+hD
+paYtOhh2FRMNL11CqqpiG2IC1JPGKA36hx7UcF6LyhcqtDS0YEI9kXz/C5Hk60bc
+wKuIyVOZYgXOnNvsewa2LvGhi8ZUCI4L6DGdV7+OcJ/7PX3Jth+01Np7T15jo/gv
+cCCkFx3fmd9ysx2xcO2Cyd5vtqiEOK7DIoNZ6WguHlYdZb9/kDoRoWf5Qq7rmKXQ
+agJhrU6jWsCfQqY6e1oYlafSRPemgJj4kD1vtTW1D8OZc+iUFy0Fd3EZ6HT8xOAP
+9e0WFDsqL0+K31KZk5tFm3KZOrjJIxvcmLu+a1mELw==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6CACRL.pem
new file mode 100644
index 0000000000..a4bb7e3ab2
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIByDCBsQIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEeMBwGA1UEAxMVcGF0aExlbkNvbnN0
+cmFpbnQ2IENBFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMwMDBaoC8wLTAfBgNV
+HSMEGDAWgBSvvIWu/kyu4Y2XI4jIpbFgC7pO2DAKBgNVHRQEAwIBATANBgkqhkiG
+9w0BAQsFAAOCAQEAmHcSluSxj/t6JAD/aFB0G2KneIGVwM+c+dhxzVgL8/onCq0v
+KLB3BafsI5LQYRb5peAT1mCROTnVIHW0n6bE0RCQIxGty7Zh/kcjRtdL9cv5JX91
+ovjJVm7snc3XR5wUe4+8pRO3HeWurcXj/NvUOmaZg+hEnv8zgICjxndiqtPlQPjq
+/BIIDOT7FSuYwFIB5bcPBvyEjRSR7hi2UDzR9bxjiHBULC8nCbNhk5Qff0815fLK
+TQozMgMeB3D9psl8cDfO2owL77bsQx0um2QjJWW/ByMnYndkzGRt/9SkxRGHKtmV
+2rp5wMZKEQcVOm8v6KmfkdWtMBf5GCXLvjf0RQ==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subCA0CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subCA0CRL.pem
new file mode 100644
index 0000000000..a06b0839cf
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subCA0CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzDCBtQIBATANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEiMCAGA1UEAxMZcGF0aExlbkNvbnN0
+cmFpbnQ2IHN1YkNBMBcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAvMC0w
+HwYDVR0jBBgwFoAUz3Z2g3OQJMeNo21nfOtSwNTU7UgwCgYDVR0UBAMCAQEwDQYJ
+KoZIhvcNAQELBQADggEBAFyoC4W//fvuVDNbyQCjkcD+eWvMUc48a7gacH/9yFzM
+auBjPEdjd4HWqUjEH7AH75ZgRXnf1n1pL9wh9mIJmVV4hLHfnDcryOMH71gfDrft
+d72DZcCBNZv7jXSMuIjCDn4TtlF8DgldJHQ5uA1f/a+qt1nOV7OCgHStr8PsP45+
+Cf/UGN/hqLWdlvaMB7PF7Qbfm639AE4UWs5NyKQC9PaDpFw12fAUJSO6PRXnSEMT
+9xx74LAC4aZIO5CtnUE/MPIvGgJFdUneXVkGDmsg/jsXbCVhKH7fUWun9IPvehE/
+OW6kYzC+6v943J3NelQUzcWzzF0CH8DwMGEY/GcmIwI=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subCA1CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subCA1CRL.pem
new file mode 100644
index 0000000000..5aff3ab9e6
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subCA1CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzDCBtQIBATANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEiMCAGA1UEAxMZcGF0aExlbkNvbnN0
+cmFpbnQ2IHN1YkNBMRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAvMC0w
+HwYDVR0jBBgwFoAUPJqVnpNeVmLpWziQbJo6bpLb9wswCgYDVR0UBAMCAQEwDQYJ
+KoZIhvcNAQELBQADggEBAJEL4fmSZTA+fF23RGynu2YEOWQ+YFNJzfYPg8EdimTL
+8AAXERJlbKKh+51nygXhYhUEonLIVmJyK83n7rIbEaOlrfXu2M4CtSi0zPZyTNL6
+hntIw1oK90JumjJhqxc0T9viI+cCoKz5b1Y0VZ5UNrno5fHmhw784TwN8bKxTig1
+DC4mjrk38QAAEV/5xQdS0i4nXP7Tz1PO81ueqMz8kgdp+QHjFKxDOoadq1gt+7Ly
+GRuY2SlF7pKZ6e4SdGF3rJ/sSzmO0wMLkMU4074RRg0BOo7J8ow/WuMVmwi+alQJ
+l5xRRlX1d4F30oa5AuJWrOSDw87HKTfRwPvCF/U6hPY=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subCA4CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subCA4CRL.pem
new file mode 100644
index 0000000000..1cc5a4506e
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subCA4CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzDCBtQIBATANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEiMCAGA1UEAxMZcGF0aExlbkNvbnN0
+cmFpbnQ2IHN1YkNBNBcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAvMC0w
+HwYDVR0jBBgwFoAUSYXbS/sRY9mZAii0C3qeExdaFXcwCgYDVR0UBAMCAQEwDQYJ
+KoZIhvcNAQELBQADggEBALcHlK8kwUx4MZCo/sdlhk02Cf/n4mMvGAzXzjTDFoO1
++Nvo1HL5xmZ9KKCTSYmfBHc/qhMAmH31I6UJAVlOdtUcq2VCRRej8OlOGLImThkt
+oClLD6mmtW1YuB6bJtsuFj+GIPvLZfkpOgKg0fDmcQRVL5DO5ajMN/BH/xJtHuiV
+n5DjNZPhJls11DOd57TzFhGVq17PhOrMvL+8nCMs4Zl7DtNKw3EJuTDGTGAB+OYx
+5FJBmick+Mnkf2ElfidE3yBiOlg0Oj/fXjb5cqCa4uR+sAqYOl9BBjM6RfVbOrhJ
+7FuBGqYEmCr0D/FT8EusGdWFDBqfDsWtXVV7LHxcm6c=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subsubCA00CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subsubCA00CRL.pem
new file mode 100644
index 0000000000..6b19bdf4f3
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subsubCA00CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB0DCBuQIBATANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEmMCQGA1UEAxMdcGF0aExlbkNvbnN0
+cmFpbnQ2IHN1YnN1YkNBMDAXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqg
+LzAtMB8GA1UdIwQYMBaAFLq54oj31FkliuMp30+gBjjdcXSCMAoGA1UdFAQDAgEB
+MA0GCSqGSIb3DQEBCwUAA4IBAQC9tjk91ybiFjv2eYZsjGMKc+y1kd1xc1xIXSdD
+dM5JR+GglRm79uK4gDZ3gTLIQpDVgYPXV+ereJ9Kg9DOl79O3h/nxtS45azUxvdb
+uk/DW7PpSZSOK4d6hW/VgZG2Giv+ZucWNnUGjsXCs4/Hhi+IZvAI/Fhtcbi5cwHQ
+RG1hqJYGsqzQ1V4iBshQnZeyjp0KFz95dIifHNsL1YJJy7ODiCE6RLGaXs064DII
+g3XyZdz7hZOFbGTR7GwkYtSyIHLm4iD/xJeCU6cA6FNd+Xb5Fs4SSteCUd0lurH1
+JQLnUF/Xjt2IowuQFnfQ7z2jq+8BRrIgkvCQp5lzteSqPE1i
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subsubCA11CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subsubCA11CRL.pem
new file mode 100644
index 0000000000..f85921377f
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subsubCA11CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB0DCBuQIBATANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEmMCQGA1UEAxMdcGF0aExlbkNvbnN0
+cmFpbnQ2IHN1YnN1YkNBMTEXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqg
+LzAtMB8GA1UdIwQYMBaAFNOmRV4CnWcWfZSAD3O5hMZbtTG+MAoGA1UdFAQDAgEB
+MA0GCSqGSIb3DQEBCwUAA4IBAQChBEJUKVtETDiFUgxBvxOrmaOjI5NxDTsqyM7m
+HrkP330mh+ij8w4DJ/kOhHxC0c4EBgD7m4oUbkClmqY0LVRNaUlFHdNvftGJMg8k
+Z6Vveak9+Z3q5J7QlE8hdLCGsnQXL3gWoOjH28j3I72fW5tabTdyq7qPjNKkt0xh
+6Sv9jLxHbAWimSvj6xQ3JxO4UweFvDl72eQb+tFhrJpouhlUv13eF6eaQoVKf4to
+KRjRXWEErBEkb1fEXzUISEvQH8gbzVi8raKG/CWbUfFCkBWiqd3Ahr+w0xtmVV9W
+wk0SlM+XlKRQZ4chc+93RMQQBCC6LwN2rBmyaLUPAtzUOTA2
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subsubCA41CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subsubCA41CRL.pem
new file mode 100644
index 0000000000..744befe8d2
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subsubCA41CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB0DCBuQIBATANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEmMCQGA1UEAxMdcGF0aExlbkNvbnN0
+cmFpbnQ2IHN1YnN1YkNBNDEXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqg
+LzAtMB8GA1UdIwQYMBaAFERapgfP9vPIx0bvZKH1W8E/grxXMAoGA1UdFAQDAgEB
+MA0GCSqGSIb3DQEBCwUAA4IBAQBC2N5Gdl473M+niHqbKh49ObjDXcF0Vbam4NyC
+e5V+1D6PZLlZQDNh0ORk/MnIOYWxchUhXpUnpNfcqReFdP/kIhwlc/Nm3xveO86n
+zWuRP3NrN0N8SRz9YmLkoZvDNL5gagKCwLzeGTTi6lMKqhZnmcDH3ko7k3TOlCO7
+I7f6jEp6ECAHUbDE7UyJC93lYu98YpaM5SV4L8i58/GBpCwGsGirSxws7Xhrgr4L
+Q5UUt5v3GDNW5YiRBEuG1kMlBC4T4gX/TNsdu/8G4RT2hO+SIDOtMNfA4D4TIiY0
+OzDtVVto9DYarCyKlQKHzb6RrFL8sYZJc213B/1O4qRNeJCj
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subsubsubCA11XCRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subsubsubCA11XCRL.pem
new file mode 100644
index 0000000000..20392a29a6
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subsubsubCA11XCRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB1DCBvQIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEqMCgGA1UEAxMhcGF0aExlbkNvbnN0
+cmFpbnQ2IHN1YnN1YnN1YkNBMTFYFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMw
+MDBaoC8wLTAfBgNVHSMEGDAWgBSD2ri1xp3Iiwh8iz/tGnIl4q8b6jAKBgNVHRQE
+AwIBATANBgkqhkiG9w0BAQsFAAOCAQEAmKydWhVC5ytcp4DjzRPCIZ1myP9MGW97
+diaTIZaFdYYz52k2GD6uHBEL1rALDG6e2DiU+YbmfVJHE5RbehxwtimoWsHOtGLO
+NPTMBPwGoGHIUyR2Ex40oozOrprl5tY3y8uticLLyQQ4meUTrquM7aAEaHHYGwU/
+FziX56TGzO9Tm6ci+jlTrOwHy/uj/AVkkQS9RHk1ytgrG54WSwh/diP9qJrNGvBe
+a8Ditg8ijMjGU9J7NeDJn33G0U8/R08ZOfo0kNqD6mG8Np5meREfiCt5UGfwBOV1
+EVMpK/Liv20yc7PcJT2lKGl1eXZmiZ7TLGV0KJWUWRNy1o4cv6a1ng==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subsubsubCA41XCRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subsubsubCA41XCRL.pem
new file mode 100644
index 0000000000..8674072d00
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/pathLenConstraint6subsubsubCA41XCRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB1DCBvQIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEqMCgGA1UEAxMhcGF0aExlbkNvbnN0
+cmFpbnQ2IHN1YnN1YnN1YkNBNDFYFw0xMDAxMDEwODMwMDBaFw0zMDEyMzEwODMw
+MDBaoC8wLTAfBgNVHSMEGDAWgBSh7aLzNVSln7xj5kdqUyRsSgxyLDAKBgNVHRQE
+AwIBATANBgkqhkiG9w0BAQsFAAOCAQEAB9m9d1A5cqTJSbdKDkv4KfjAJDsKOqyf
+l1QLXj28Mq43YlLbcoaivW0yL+44zumb02ZKr4v1qd7tP5QLPvv+Ew1pQwC3I8cp
+Hq33iO6VX/ZLVT+vD8wguU/Lwq+oZGFDHMatgq2CGtZ2lJbZ8/I11wR/otTBa9Ne
+krQ+n79avPaAagJoyz+1HKSerOyuyFQ9GP/v64sS3YKy5LJZ/VXC9PlpzU523ENu
+ncwldAgVmNTgxa+kPmdIzUkWLHuuggVltFtRbVsiKyJINgNcmooZhDIHCk6LsXYY
+fBMmxX4xFLGzi1p4sobgJgBkY8YBDiB2xEslOFkwKIgpRfX01T4IZQ==
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/pre2000CRLnextUpdateCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/pre2000CRLnextUpdateCACRL.pem
new file mode 100644
index 0000000000..57afdac2b5
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/pre2000CRLnextUpdateCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzDCBtQIBATANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEiMCAGA1UEAxMZcHJlMjAwMCBDUkwg
+bmV4dFVwZGF0ZSBDQRcNOTgwMTAxMTIwMTAwWhcNOTkwMTAxMTIwMTAwWqAvMC0w
+HwYDVR0jBBgwFoAUHqhHnGGAaCixQpopjOYoAymSA8wwCgYDVR0UBAMCAQEwDQYJ
+KoZIhvcNAQELBQADggEBAF6aXbwxymxr0Q8xGFXYqmr5vzuVUREiNHYZMX6N6pqI
+noDmGZN1FgX3FSkcKlsiVYWPRp8VygdNPt2sctjy5OV3J8kAKXzoll7/cHVPWj3b
+uGP8B0Y3sk7oCupwlI/lPwu4Yf5hHcUofyGV4yeOCNn0BHGtOzcfStxbO/K2sG10
+ny8KKkH/+horhqSur2p6z02jq1hcHsQLt293tPfaG6skObtvWgrajbE8rPKYLHiS
+mkh+9Lxtzv/+WOR7YeBgjfg7Eu+gLC+2rrA4C/UiQT27baIzEJkaz3qarL8p4qWR
+BctCVbNVbcrgSA7pT3kavp4Te5NHLg1vRfmkHka1ESk=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy0CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy0CACRL.pem
new file mode 100644
index 0000000000..faecb30bdc
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy0CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzDCBtQIBATANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEiMCAGA1UEAxMZcmVxdWlyZUV4cGxp
+Y2l0UG9saWN5MCBDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAvMC0w
+HwYDVR0jBBgwFoAUuezfulIiuLi+aveiEtUnINZnBDUwCgYDVR0UBAMCAQEwDQYJ
+KoZIhvcNAQELBQADggEBAErZavnEyTgHh/ez0LB7FgIfWGuiJB+NDDOQBT31adQW
+nPq1ylOQnG5ALE9askbusXrsw8VHIffm8bBd6JRdFXD9p7S2SzFE5skbRHVs71qr
+ytTzQhoQgYMaWRIYBx5Yg9J0+HSp7rip8FPRoPA34LRoPFmtvGyESnFQCZQMj6Ar
+DrRhaj9MFsicWAObMlIWNOsISnNkDd1s4XeRTMbZ6NgvyZ9Oo6K4S9YsPJypmaWD
+rAtkwSqyyH9yT/Ip7jNFdYfin5oE2i+dN4FCWzQXyr+z0l6dWdw/sjiDWRHVQTkA
+G/F4Ro+qR6bVtq9wt/H1qbauMxOqI+OILjfZARtV/mY=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy0subCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy0subCACRL.pem
new file mode 100644
index 0000000000..6aa182da50
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy0subCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzzCBuAIBATANBgkqhkiG9w0BAQsFADBVMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTElMCMGA1UEAxMccmVxdWlyZUV4cGxp
+Y2l0UG9saWN5MCBzdWJDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAv
+MC0wHwYDVR0jBBgwFoAUvmJ4/Tu9bpwLM/I7MqpBCPPliVowCgYDVR0UBAMCAQEw
+DQYJKoZIhvcNAQELBQADggEBABmiY4GL9Z4TINu3A3r2ReqPCf6NBrK838gjCy5y
+yomt33rwH0sDWcdU1YtKMk1iAWpBBon3nBrfylsFDAacz9oqvHBnCSYnO/b3WWLv
+rv80IaJoV6IeZC1CF7vXFcUWt0VnUgVxNzhLWOn0GEu/R/W3HIPUUvpg/0+RVG6c
+WSPwCUAidFY88P195evwDEXaKykQw6LzAlnWMvrL0lviPl4Px/GDUOBp+aZaDz+t
+ktuljb5StVBqdQ4XzemwS12ZkAGw//synft8xDg7c1Pq7csftQ1SFuEvkRaobXYp
+mSWUqhhm5pkRQBxPySvpDiYCOiQbsiTyAAnYkydIeAkX1Ps=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy0subsubCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy0subsubCACRL.pem
new file mode 100644
index 0000000000..58a10374de
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy0subsubCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB0jCBuwIBATANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEoMCYGA1UEAxMfcmVxdWlyZUV4cGxp
+Y2l0UG9saWN5MCBzdWJzdWJDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAw
+WqAvMC0wHwYDVR0jBBgwFoAU69iXen96IzUZ5M+XJCcizGenVkkwCgYDVR0UBAMC
+AQEwDQYJKoZIhvcNAQELBQADggEBADaIskgZjnU/+X04sIHx4MxEDo7nCtfaRe6U
+sgYqAEr8u9JCuba3tJgEud2meu8XRkQjagttBmG52vxS4rMiu6Xq79DPWLrdKc3x
++1Tx/wF0iACCp7B0aNfFnrF+Cg/XCQqeVlthn8EP51HmFl+Fu/0szwhHS3N4Nh67
+C7QGGL61vSUqK3V9tRSn7ubAJBJp+BFbG0uLvOlEUbs4iil1f+VlWlXr7WFfKw0F
+k9prVeYBcnyV7X4uLEpQZGk26Qo1X63H+aMUhSehqg9v+M5A8/pq5MKCRwD6S3Ej
+h8DoK5dmqjOrjfBGsS8Z1az1WsVDlC7EO/BFgTXM349j406Rpe4=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy0subsubsubCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy0subsubsubCACRL.pem
new file mode 100644
index 0000000000..34265b943c
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy0subsubsubCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB1TCBvgIBATANBgkqhkiG9w0BAQsFADBbMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTErMCkGA1UEAxMicmVxdWlyZUV4cGxp
+Y2l0UG9saWN5MCBzdWJzdWJzdWJDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgz
+MDAwWqAvMC0wHwYDVR0jBBgwFoAUtdsE1sggCC9aQcd4o0SJ2s4ua7owCgYDVR0U
+BAMCAQEwDQYJKoZIhvcNAQELBQADggEBAChXnVu5rzda6+f2NZ1nWf5qyFfBR3qb
+IwWmBIAATlpil8e/RfSjzkNP2SrKhGi7KDseMn7F6MsHlGp8McNb7ryQcd0+PSUV
+m9hELQcBosZrU/XTdctfTx2/k5mfixlK+UYqz3k7rFfG7RhdkhUexaCQFSCgBgxQ
+RhHlXyP8xpSytC0T6w8gIXxUQjK5jEBwr8uVYhadcCsQnx4I35MXmNUb52BohF3s
+p3pOdgGiCn5CmgcqBa1ybBK5qtKKHav8H6dBzNLeuG9giZC/ALpFhzB0fgkGXXFr
+52zZxy2Z8dN7OWAMTski7B2c363+TwXI7Y/Vuq3qIYLxdcFWix3zefY=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy10CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy10CACRL.pem
new file mode 100644
index 0000000000..efb8976e4e
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy10CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzTCBtgIBATANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEjMCEGA1UEAxMacmVxdWlyZUV4cGxp
+Y2l0UG9saWN5MTAgQ0EXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqgLzAt
+MB8GA1UdIwQYMBaAFBnzTATRX9WAR/P4NCwRgeSYz2ufMAoGA1UdFAQDAgEBMA0G
+CSqGSIb3DQEBCwUAA4IBAQALMOPr5blCX12/wmoUiyjhE3KtwudCyjTFeRfWdh1y
+i74p1lKaCtLS2Ccqelr0fuD98PSUvKa37UrWDtj9fXTCgbe0dB2upF/hfkaCEq9b
+vO5HAuBB/hBwR/F1IsQ7qHwDkQA8WhXRfYsrneWfygUtQUzrji/nz0yF5l+GnWWX
+iMID56whZjh/ch6Uvb9qYJO2p4R1KMFJ7G+xKJQm+TsTx6iYIDP2Q8uedSstLasu
++d68KWDFkf8pAXDDgpp4ldUflWbW7Wa7tSHodxE9D9cee4Db7jmXyV7BqQUxYUwF
+9qj1mjdivXtpeTsNKhX0ASsm4jHKmSjKOYvkEALiALq/
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy10subCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy10subCACRL.pem
new file mode 100644
index 0000000000..125c24847c
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy10subCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB0DCBuQIBATANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEmMCQGA1UEAxMdcmVxdWlyZUV4cGxp
+Y2l0UG9saWN5MTAgc3ViQ0EXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFqg
+LzAtMB8GA1UdIwQYMBaAFG4YpmEkD2jbLgYRliY3r8l4KVYGMAoGA1UdFAQDAgEB
+MA0GCSqGSIb3DQEBCwUAA4IBAQCZ/4QYxzZaC5BIcXVOv0Pa0KrQdGUx6Ae7knJP
+df/x+IrPcwEHZeD8dQUYnWT7EOvcJBRS3HaI8xD0+n3IFR1+ayaQuV2UCQSu2WbA
+FXx+HRApe5lWOVZsG9vg7V2ccF+8u4qIaLxxTlfOGL3m1FyK8/YXhDfNeOwRukNG
+JxHdfhaqHFtofV3Spa2HcUwKbNAEtu4SAcW55ZV0q/W1tbOBeYwBMNoNMKEVPf8B
+FhJh0ID0xyoFdFIDsj0uNkvNRazAjnUGtz0m7/PZE22qvPH2Bt9gII5UEIbWY4Nv
++Kz6TiXfjZZkl5vR4DHy6qOfQxVDbEuehfRxsBLngKLXzW3r
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy10subsubCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy10subsubCACRL.pem
new file mode 100644
index 0000000000..7754862b2e
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy10subsubCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB0zCBvAIBATANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEpMCcGA1UEAxMgcmVxdWlyZUV4cGxp
+Y2l0UG9saWN5MTAgc3Vic3ViQ0EXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAw
+MFqgLzAtMB8GA1UdIwQYMBaAFFhQTw7y/nIkpNB3P6CWLHe1JOghMAoGA1UdFAQD
+AgEBMA0GCSqGSIb3DQEBCwUAA4IBAQBc9QUsQJu8eEkhD/bB2k137z1Tw2E+SOGM
+InCgU/5FjqgVS8frk2POJXSyTdZonYpJvj3fEuXLp/eViZ0+V3oe31vnFtzeQ9qv
+//rOvJd0b3yOtLFAB58oF5yms/4Zj2ekeWU38HUrQ8lVrT3p0nj7V49ENlaiXwVD
+vhsaTShUxHnVPb5W4nX/uvl6PUWXZLwzWvr3foaAbf0rgV3eWhpjspPlE0ajF0Tk
+ButtK76M4AJocWeWr1AupATbtGU+vvi+I5D7YrBGn7qxF9BvzMiq65H4YHnNfiiF
+iVtgU+GXZxft7+hmVYgX5eQKcDhSQdKKB05U8r2Q5ZRFq8o+b/Vr
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy10subsubsubCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy10subsubsubCACRL.pem
new file mode 100644
index 0000000000..caac766953
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy10subsubsubCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB1jCBvwIBATANBgkqhkiG9w0BAQsFADBcMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEsMCoGA1UEAxMjcmVxdWlyZUV4cGxp
+Y2l0UG9saWN5MTAgc3Vic3Vic3ViQ0EXDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4
+MzAwMFqgLzAtMB8GA1UdIwQYMBaAFJaMcfwVqDvO2cT4w9BfaXF86ABLMAoGA1Ud
+FAQDAgEBMA0GCSqGSIb3DQEBCwUAA4IBAQBzlq+27lis3jgVun42HmkOAJ9zzdIt
+iyptjiWBCLV5lLA3gbiuroQbr6cKYWhP/qQ91g7MgSzvq/cVwCudSeqIOCJZUwRu
+Kpu6AKkK77GfWA2/GC4ZtIhsHIyA0P0MTa2ygmtxIn0ufluNzgEognWxF4Kdd0F6
+g1sJL547W8byiNlD6KtZ8Oe9PQOr1tevTWvWgSRj2bitAfcwrEBSsyG1eu/Yyeun
+opopG2H28TuBcitgZA7mjicFqzibabUUA+hqZ/X5cL+JiR+84VWc3o5fPFwpdAWr
+09gYI6qG+5O4q7tIyb8d8dIVO+FcKV+mkbZDpFu+3VWRFY4GkBjq98uJ
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy2CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy2CACRL.pem
new file mode 100644
index 0000000000..acf0e69c78
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy2CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzDCBtQIBATANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEiMCAGA1UEAxMZcmVxdWlyZUV4cGxp
+Y2l0UG9saWN5MiBDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAvMC0w
+HwYDVR0jBBgwFoAUNqnZ+6o4L6D3TDvZhZ2aFaMtqccwCgYDVR0UBAMCAQEwDQYJ
+KoZIhvcNAQELBQADggEBAD8YETFOSpFWhTbHdjwH+oNciH7CRTbs6UkICQVsnIN4
+xt8m4Pvho9VeU9KNeIvmcaKaJk8HrxbhKlluWFUS/IMk+U6SQ3QSdnxLtJdvC0JT
+iARR9dKR5YX/G0JHJaAO3ULSu8Gaj093TFfQPs2ALcfg5G6BbQmxJ6qCwp/IZ61T
+x71148Lqbb0k2JVZgnnPkhe1k/7no2rjmvu4Zp0BuFkQIwceN908LGSZmuVf09R9
+6FUkYhY5s6tM0rHLLS0JGgCuYyl6RTeD/OemNh4QfA6z6N+WmvAUwzbRWtm/gDOx
+hQq+8Qcc+HErYcZfSg9cgJqRGb1J8KGGd+92uK1wHmo=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy2subCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy2subCACRL.pem
new file mode 100644
index 0000000000..426415e452
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy2subCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzzCBuAIBATANBgkqhkiG9w0BAQsFADBVMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTElMCMGA1UEAxMccmVxdWlyZUV4cGxp
+Y2l0UG9saWN5MiBzdWJDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAv
+MC0wHwYDVR0jBBgwFoAUIHf+TDCN4rNRHY+w9xx/HYOYDkcwCgYDVR0UBAMCAQEw
+DQYJKoZIhvcNAQELBQADggEBAHnk7z+QEkfo+N/q7+bAHDhYCm1ax7Vg1PSs/3WE
+OvoTOp65ghyIX7UdKdmUTpefa89C2PRORNB06xIYzQSeCkCoq7bpTW0hzMfPweY3
+MwlEqnllWldcWgczSOxsomOjJ6os81onh9ZyICGbIZLPL+HZtfPpXKdyw7riGAm3
+h3V0pHznhgcm4XEpe6iHovoFbdmWs73G0vSjLnTyDmSBVjAiEVnZLut10BGyjCRq
+ZQjLcXfXtF1aFymk1p/eN5QLMaNZ59uoGNgsjRQmod7H1Lezp0r53yA1bg9P7yXU
+RsY/pvoiI9j5t3svgZWKC5wuTmJ7nMTwlqaZDS2nWAw3/TE=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy4CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy4CACRL.pem
new file mode 100644
index 0000000000..c96cbf6314
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy4CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzDCBtQIBATANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEiMCAGA1UEAxMZcmVxdWlyZUV4cGxp
+Y2l0UG9saWN5NCBDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAvMC0w
+HwYDVR0jBBgwFoAUzdHczNQxYwcsXTaxD42edb5LXmMwCgYDVR0UBAMCAQEwDQYJ
+KoZIhvcNAQELBQADggEBACOdVMcZUqu3gJlw13ZK7/NcOtSAuvEOVHfjChSXRFkp
+gVhiUJqPQYg0fs6eORxMRc/EyKUTNeKQE/08Q0pN69TSShhHJgrbI0qL+z+1l+OA
+615L/Z658Nv7uKLt0nk/RkguMQw2xIlUEKvC1S/MQAcJAiBKPnSA7fCb93ph053o
+ZOVorML758OWTjvXGykpiJMbxgdS1MQpSRrU3FGST+auQhI4Qet5QpMlA9nfHwgB
+l4lUkF73iHwV8LNHI8t/Pnd5LkKd6XWiDrQRAzhrh/UhmcspUJyFlLIxthO2Az6n
+/FIQMAHm0mvyrgmmZSsw8HCseOgTNCnQEEnWLodqabI=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy4subCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy4subCACRL.pem
new file mode 100644
index 0000000000..332b2ec9e5
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy4subCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzzCBuAIBATANBgkqhkiG9w0BAQsFADBVMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTElMCMGA1UEAxMccmVxdWlyZUV4cGxp
+Y2l0UG9saWN5NCBzdWJDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAv
+MC0wHwYDVR0jBBgwFoAUfe8OlBe79qeX5tgiSENIrLPuuo0wCgYDVR0UBAMCAQEw
+DQYJKoZIhvcNAQELBQADggEBALIg2yo0C0OaDGoUWWB1PeKkFzO29Zrz7os0w6Ta
+c4W0ufJ/V7W6GTWtNjN2zoVhWe1DJzAivJejwI89ES8kpKJvQ0FIqSmeKk6v7qM6
+gZuhVsvemsw7mb2LVd7t6ismBYCbYTBnoHc/dW+zgHLXNsjHA7aIq3zEzeiJPxgy
+qf4a48BXm8WKQVFLAJv28l/B3nanW2+rYMnEMUBlI7ytGE/gcZ5WB3x8i/NxQAa1
+mBBrHVFyNLJX1pxCmg1myP9dXj1ljlSwRHVgxfYhVcfl5H72cJg/zTQNELpqjlqO
+kM8wXuKpxsFsJpGBOfl3zjeCeFmjOyucmB/CZT3L9h+H9sY=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy4subsubCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy4subsubCACRL.pem
new file mode 100644
index 0000000000..ab40c50e73
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy4subsubCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB0jCBuwIBATANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEoMCYGA1UEAxMfcmVxdWlyZUV4cGxp
+Y2l0UG9saWN5NCBzdWJzdWJDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAw
+WqAvMC0wHwYDVR0jBBgwFoAUqerm056wCZev5/4eLhAyoRBnTIYwCgYDVR0UBAMC
+AQEwDQYJKoZIhvcNAQELBQADggEBAD08KCdOiCGTM5PYyFE+HRlYaBd1VnGIFiAb
+fCdTAlEmK+/NxqlrBGqz1zx6O09X4u/XsmvwI5Pi9ujsyxN/aHR16/JBWfUEPKDg
+2a7XOoAyKWO623Z78xWD4DbfQo32vsyDpe2ydCnYiX7qPf3muC7KNROeHMt1QwK0
+/T89l2NJmPBE5+sSCMMZ+8tY1GQgVTeNczO8zzoYcG5XZrKs503sfLvISvcCpre+
+l/LeByAhkJpr+/wlR8+eTrUMpZIhnB8x9uk9hi0YBBbdKmAR8Sqc4U/2yUPFp6ue
+FyF/txO3HXmTNYLFSYo0+G8uEkQCOFQn7BHJOybYH6ertxgKhdQ=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy4subsubsubCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy4subsubsubCACRL.pem
new file mode 100644
index 0000000000..986abff429
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy4subsubsubCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB1TCBvgIBATANBgkqhkiG9w0BAQsFADBbMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTErMCkGA1UEAxMicmVxdWlyZUV4cGxp
+Y2l0UG9saWN5NCBzdWJzdWJzdWJDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgz
+MDAwWqAvMC0wHwYDVR0jBBgwFoAUFLvRJvSegTyLDhLP2XsVsizcoyEwCgYDVR0U
+BAMCAQEwDQYJKoZIhvcNAQELBQADggEBAC0JNUPn/JJeMGuu1cv0PUV36H5zZk3z
+KXq6TT6CRatXHsIRl7bwvsJ2wnkkT4QUM0xeVl8Q50Thm/P81vxVb48w3ahA/mm8
+QtxJwkPK9VPV+jkfAW5vcTVzJZlr9EWhuYgfqC0KdUUiE2omtydtinQhGdI0ooey
+U5XP6voQwf8BKCYOgXxQNJtRE1+W96SifSUQr07fN7gXUp2MgZYwp8QPjFZrX5dH
+FqgmhSv6rdjO9knE/guw21FzA0F5rM6HjNuxre3qont7vlzpI9sx7VzrR4J87meb
+DhRujiMvn1Ge6qwNPGgSnd8P/LsA8kltmewk93W94u74GqfwQCtFtxk=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy5CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy5CACRL.pem
new file mode 100644
index 0000000000..6b45ed261f
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy5CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzDCBtQIBATANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEiMCAGA1UEAxMZcmVxdWlyZUV4cGxp
+Y2l0UG9saWN5NSBDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAvMC0w
+HwYDVR0jBBgwFoAUu5GDq66u3lzY4PKQPFz6ny7hOWgwCgYDVR0UBAMCAQEwDQYJ
+KoZIhvcNAQELBQADggEBAMz51cm+tJdOQUKRaISFOoTqH2PSV3W1i/VLNoo60huI
+wSIOg0YNxG2wXxFH5UdH+SdRacD3qHlAKKyTsWgvhqZgdgbgieS4Nc1CpGnyxeXk
+FCdGt4OJ6mEToXFqJayWwR25ckoJp8k7gpseERoqgDCTPvKjp+1yrznlX8VWTKya
+dgVr+LgSLzCHY8HYekoKcQRbFWbnMBw5K7VE06CLJJIx9kHgDOU+Zqxjy+cilIIb
+HxMmsrxCwKW+ARA/LBiLpn26m9SC/fHstIopRML+1zkbXCoad2VwB9GyvLwzAoqn
+MwJuDzT0G/MZCB4n/s5J/urXFkYBVCQpivlfX9tNUU0=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy5subCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy5subCACRL.pem
new file mode 100644
index 0000000000..29a2c67261
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy5subCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzzCBuAIBATANBgkqhkiG9w0BAQsFADBVMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTElMCMGA1UEAxMccmVxdWlyZUV4cGxp
+Y2l0UG9saWN5NSBzdWJDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAv
+MC0wHwYDVR0jBBgwFoAUN9O/3txQx6/IiuiSsMRIYfA6BAEwCgYDVR0UBAMCAQEw
+DQYJKoZIhvcNAQELBQADggEBANAIgl9rVP+LLEYRL1+oori60bQTlB1+1LBFItkp
+7BfodwaAGRmWO4GV6phJzxjpi1aKVGuCg7vlwzS+/ns0mlAaghPxpelwd/KACsv1
+AnrbnVR7AW9z6/ipRID0K1V+8EJmjUdD05BjXoyDKP5Jg2v1joSB306Lv7EDGqBh
+babIXd9ZVrMJBFhW8Zp9A/c/P72LrfRkDBi5rhxI8lJeDUPTfQVUGn0nh2MHx2LQ
+vDd++QtcVY+4tPwkiNJiVNBu5dec8DBuGwNcxcZ2FnpExVglJuFf9AXlXPlXs1Ri
+6+WLqQ6sFjS8R0NhYyILqm/JtXO9mKzXAwa53nCXPytwtPk=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy5subsubCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy5subsubCACRL.pem
new file mode 100644
index 0000000000..9370cde1bf
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy5subsubCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB0jCBuwIBATANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEoMCYGA1UEAxMfcmVxdWlyZUV4cGxp
+Y2l0UG9saWN5NSBzdWJzdWJDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAw
+WqAvMC0wHwYDVR0jBBgwFoAU+IIvef+0fggC21uvMp3kNWG1bBswCgYDVR0UBAMC
+AQEwDQYJKoZIhvcNAQELBQADggEBABWp0q1/e5b14+ebJrBOiLc2iTt8KlT0ycPq
+EjyoPsQAO6krSC8L+PdSOSv4if2Udf9Xrgrk5zvDIBkVrv7+QlR0A/5kBRukZimS
+L0Q5lCJjpBmvgZRu/c5bYm32iIfJtwwEgXN4fNh3QESi+KGB+IopD9+/TxV8nAWn
+bTqJ3YPGM/tlmkpLHQD7lt7PAHe/ofrkJc8L6ircKUzmZ4vce3HQtQ79rlbyOLxW
+bN7O9mfUymz4SN/gsnll4HpJKrSBTeINssUcCUwpZ6p1IJ0/tmZHpF39HZo1W0ts
+ZB6DWqnOL5lWsw3x/QiKVgvfPjKA1mvqsXVhy/xvNFGT3kyNcC8=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy5subsubsubCACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy5subsubsubCACRL.pem
new file mode 100644
index 0000000000..db6c01924b
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy5subsubsubCACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB1TCBvgIBATANBgkqhkiG9w0BAQsFADBbMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTErMCkGA1UEAxMicmVxdWlyZUV4cGxp
+Y2l0UG9saWN5NSBzdWJzdWJzdWJDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgz
+MDAwWqAvMC0wHwYDVR0jBBgwFoAU+mK6vX5eX98fuge+H3k3gtz8EygwCgYDVR0U
+BAMCAQEwDQYJKoZIhvcNAQELBQADggEBAGQii0uxuUm9ok8RNEseRwlN5+lK2R2A
+VZUJ+vZ/O+4ye3x1RIcZ38oWF8zrGZqp6Afos6JbZLSUAGRrbmYowxXCT3vV3yA5
+SBdIoXsByE2Kh6dyeNbB/jDFRNP5rbKcwJJGqXrfnRbHXOOizHPMmWTBscj9lit6
+HIzQhlURn1bHP2GcQ17uBGSYpSVhVV247dlt4+HgReog9NC8D26xPVdnaodtBYvp
+oknWHAcjehSi5kjt4/DJ0Fym3yHGbwpkKWT0A7RXK6cCRWfvJDnGu5vrIKigQo7q
+z4ZIKE1aO2tXJ98dc8M6Z6u1MZDnn3n/9JUAhZPtZ9Gb4eEUU+qgrRk=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy7CACRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy7CACRL.pem
new file mode 100644
index 0000000000..99d47f5020
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy7CACRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBzDCBtQIBATANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEiMCAGA1UEAxMZcmVxdWlyZUV4cGxp
+Y2l0UG9saWN5NyBDQRcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAwWqAvMC0w
+HwYDVR0jBBgwFoAUbDGXATUg3ts15QppWFmIZMwhzkowCgYDVR0UBAMCAQEwDQYJ
+KoZIhvcNAQELBQADggEBAHC+EDnf6+cnW0GTLMwWoISAn/jJ++FGGwmSv7O8st49
+YmlngcgSQdE1CmcLFM8Lsv390rQwtm57E89aLHSpSbVXvAS/ZvyS5yRgoxGJLw5r
+ulwKqAmjzrXPB/0A7mjLwXVxLBZTAqJgnIFW+qE679S4SKLWOsc66HRFsdQmFbwe
+BiF1/V5PbM83sNyN+boyBm1w5YrasEIWLajc+s+gF1dbQTKuDziD52azMegWvfIO
+xqixHCdK+CpIFObodAnW2gPHWTicXYH+ZwagtqQbI2EM7SdnbvQQe68frsfqK1k/
+SGXl0LfQl3/GmYynOg46FDf53/oRxz0bwsEa8XBpXpY=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy7subCARE2CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy7subCARE2CRL.pem
new file mode 100644
index 0000000000..dd8aaf35a7
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy7subCARE2CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB0jCBuwIBATANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEoMCYGA1UEAxMfcmVxdWlyZUV4cGxp
+Y2l0UG9saWN5NyBzdWJDQVJFMhcNMTAwMTAxMDgzMDAwWhcNMzAxMjMxMDgzMDAw
+WqAvMC0wHwYDVR0jBBgwFoAU51wljn6qTHeDe8PqadbHojThNFkwCgYDVR0UBAMC
+AQEwDQYJKoZIhvcNAQELBQADggEBACgCaW8g9ZHgkL+vcByM70Ao9B8BhlunjYHK
+905EiAQQ3OqjJzEE5YRp0uhrbChY1xoHKAjE45VIhK1aADKyV5Wt+ugBAoFLAPcN
+9FQwvTEBjUwZPCQaV54hyt/PrDBh8GJxnTpLnEb/+gl/hu2P1tDD0Zqb4BPoOxur
+abZ0PpzSCPHJdQq75RX/KZCEkaOsa4wHslFHXJXlLLh5vRqvrM23NDsY9lsNb9+3
+3mSVngQWhqVJNdFsMJisyzq88Iv3cSmgzD4oowE05khNWWhpbgxtdMYGWVqN2qEg
+EDI3oExT5CeehzLWuI7dnhKZVJl7y68n1s7KHKJtMb9vnGsiNZ4=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy7subsubCARE2RE4CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy7subsubCARE2RE4CRL.pem
new file mode 100644
index 0000000000..cce599a5fb
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy7subsubCARE2RE4CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB2DCBwQIBATANBgkqhkiG9w0BAQsFADBeMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEuMCwGA1UEAxMlcmVxdWlyZUV4cGxp
+Y2l0UG9saWN5NyBzdWJzdWJDQVJFMlJFNBcNMTAwMTAxMDgzMDAwWhcNMzAxMjMx
+MDgzMDAwWqAvMC0wHwYDVR0jBBgwFoAUbv+NCItm/pule/tkM2XqA5VIlJgwCgYD
+VR0UBAMCAQEwDQYJKoZIhvcNAQELBQADggEBADsVgmLjUlCjkqyM30ho6gvaBfoZ
+3IEMbL01Z1YWCVL/M7dkcp2H98jCurGWlEQCqlx8gXZRrrO8u7rtpHKu0oUuCcrC
+6bxljOwBRgdv0TnNB3k+FrXcaBT7/SJtGhLwjh0smLC69eI42quLSEXXHhlpmYiJ
+1cOQwPCtd+KHbeDMoKi6j7HbFD3OR7jH+OsbnwMpWdlyhDeZlXXh5vbLXtN/j6VH
+9TWdi/Tt6z049i5YcCL2l5Kq9Mp/Y2DRpLQAycHpYL+/U8yOyUq3A3MYO/fdWo1k
+H0nSPreisWgBkSD/u11jR/hPbEH9SXv2nflBaRg/9kSoAbuDknlvrLGxwbQ=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy7subsubsubCARE2RE4CRL.pem b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy7subsubsubCARE2RE4CRL.pem
new file mode 100644
index 0000000000..bd1656505c
--- /dev/null
+++ b/lib/public_key/test/pkits_SUITE_data/pkits/crls/requireExplicitPolicy7subsubsubCARE2RE4CRL.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB2zCBxAIBATANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJVUzEfMB0GA1UE
+ChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTExMC8GA1UEAxMocmVxdWlyZUV4cGxp
+Y2l0UG9saWN5NyBzdWJzdWJzdWJDQVJFMlJFNBcNMTAwMTAxMDgzMDAwWhcNMzAx
+MjMxMDgzMDAwWqAvMC0wHwYDVR0jBBgwFoAUeyxRYTEVrawsa6m+OzsYGpKqf0Qw
+CgYDVR0UBAMCAQEwDQYJKoZIhvcNAQELBQADggEBAKC0+mcSVMrZw/Yabdg8xvnX
+VJrufKnwa2sdt5WXbKX73DCh2OvTm5gJg61AkjghRN4W1VfHpQqc6lsrWHlFK+6r
+GbsL/og+JwfDgiHr+xLf9hmxlS2Uu+TK1HYUVGw/VNLoLPqre1tq4ag4W7re2Z3g
+BBZ8OyS0aUcMYpI1rp9/+PWOYo/9cEDFK2zlsIazYl0Nk8Jz8xWVzFP4gf5RXb5i
+ejUZI578baWPUfUUnEQMSqiKJmHNxPyY6REVUEFkMDu5dOlCu0GfsLBw61am3hGQ
+XvILnAB1SRdyO5uNlJLkRh9EB5aUDRUC5HydfiaSTzb0gkzdKgCRjUUsUjovcPg=
+-----END X509 CRL-----
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index f2f30dad6e..ea48479f0b 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -20,85 +20,19 @@
%%
-module(public_key_SUITE).
+-include_lib("common_test/include/ct.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
%% Note: This directive should only be used in test suites.
-compile(export_all).
-%%-include_lib("common_test/include/ct.hrl").
--include_lib("test_server/include/test_server.hrl").
-
--include_lib("public_key/include/public_key.hrl").
-
-define(TIMEOUT, 120000). % 2 min
-%% Test server callback functions
-%%--------------------------------------------------------------------
-%% Function: init_per_suite(Config) -> Config
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Initialization before the whole suite
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
-%%--------------------------------------------------------------------
-init_per_suite(Config) ->
- try crypto:start() of
- ok ->
- Config
- catch _:_ ->
- {skip, "Crypto did not start"}
- end.
-%%--------------------------------------------------------------------
-%% Function: end_per_suite(Config) -> _
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after the whole suite
-%%--------------------------------------------------------------------
-end_per_suite(_Config) ->
- application:stop(crypto).
%%--------------------------------------------------------------------
-%% Function: init_per_testcase(TestCase, Config) -> Config
-%% Case - atom()
-%% Name of the test case that is about to be run.
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%%
-%% Description: Initialization before each test case
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
-%% Description: Initialization before each test case
+%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
-init_per_testcase(_TestCase, Config0) ->
- Config = lists:keydelete(watchdog, 1, Config0),
- Dog = test_server:timetrap(?TIMEOUT),
- [{watchdog, Dog} | Config].
-
-%%--------------------------------------------------------------------
-%% Function: end_per_testcase(TestCase, Config) -> _
-%% Case - atom()
-%% Name of the test case that is about to be run.
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after each test case
-%%--------------------------------------------------------------------
-end_per_testcase(_TestCase, Config) ->
- Dog = ?config(watchdog, Config),
- case Dog of
- undefined ->
- ok;
- _ ->
- test_server:timetrap_cancel(Dog)
- end.
-%%--------------------------------------------------------------------
-%% Function: all(Clause) -> TestCases
-%% Clause - atom() - suite | doc
-%% TestCases - [Case]
-%% Case - atom()
-%% Name of a test case.
-%% Description: Returns a list of all test cases in this test suite
-%%--------------------------------------------------------------------
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
@@ -111,7 +45,7 @@ all() ->
groups() ->
[{pem_decode_encode, [], [dsa_pem, rsa_pem, encrypted_pem,
- dh_pem, cert_pem]},
+ dh_pem, cert_pem, pkcs10_pem]},
{ssh_public_key_decode_encode, [],
[ssh_rsa_public_key, ssh_dsa_public_key, ssh_rfc4716_rsa_comment,
ssh_rfc4716_dsa_comment, ssh_rfc4716_rsa_subject, ssh_known_hosts,
@@ -119,30 +53,46 @@ groups() ->
ssh_openssh_public_key_long_header]},
{sign_verify, [], [rsa_sign_verify, dsa_sign_verify]}
].
+%%-------------------------------------------------------------------
+init_per_suite(Config) ->
+ try crypto:start() of
+ ok ->
+ Config
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ application:stop(crypto).
+%%-------------------------------------------------------------------
init_per_group(_GroupName, Config) ->
Config.
end_per_group(_GroupName, Config) ->
Config.
+%%-------------------------------------------------------------------
+init_per_testcase(_TestCase, Config0) ->
+ Config = lists:keydelete(watchdog, 1, Config0),
+ Dog = ct:timetrap(?TIMEOUT),
+ [{watchdog, Dog} | Config].
-%% Test cases starts here.
+end_per_testcase(_TestCase, _Config) ->
+ ok.
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------
-app(doc) ->
- "Test that the public_key app file is ok";
-app(suite) ->
- [];
+app() ->
+ [{doc, "Test that the public_key app file is ok"}].
app(Config) when is_list(Config) ->
- ok = test_server:app_test(public_key).
+ ok = ?t:app_test(public_key).
%%--------------------------------------------------------------------
-dsa_pem(doc) ->
- [""];
-dsa_pem(suite) ->
- [];
+dsa_pem() ->
+ [{doc, "DSA PEM-file decode/encode"}].
dsa_pem(Config) when is_list(Config) ->
Datadir = ?config(data_dir, Config),
@@ -164,10 +114,8 @@ dsa_pem(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-rsa_pem(doc) ->
- [""];
-rsa_pem(suite) ->
- [];
+rsa_pem() ->
+ [{doc, "RSA PEM-file decode/encode"}].
rsa_pem(Config) when is_list(Config) ->
Datadir = ?config(data_dir, Config),
[{'RSAPrivateKey', DerRSAKey, not_encrypted} = Entry0 ] =
@@ -201,10 +149,8 @@ rsa_pem(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-encrypted_pem(doc) ->
- [""];
-encrypted_pem(suite) ->
- [];
+encrypted_pem() ->
+ [{doc, "Encrypted PEM-file decode/encode"}].
encrypted_pem(Config) when is_list(Config) ->
Datadir = ?config(data_dir, Config),
@@ -234,10 +180,8 @@ encrypted_pem(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-dh_pem(doc) ->
- [""];
-dh_pem(suite) ->
- [];
+dh_pem() ->
+ [{doc, "DH parametrs PEM-file decode/encode"}].
dh_pem(Config) when is_list(Config) ->
Datadir = ?config(data_dir, Config),
[{'DHParameter', DerDH, not_encrypted} = Entry] =
@@ -249,12 +193,41 @@ dh_pem(Config) when is_list(Config) ->
DHParameter = public_key:pem_entry_decode(Entry),
Entry = public_key:pem_entry_encode('DHParameter', DHParameter).
-
+
%%--------------------------------------------------------------------
-cert_pem(doc) ->
- [""];
-cert_pem(suite) ->
- [];
+
+pkcs10_pem() ->
+ [{doc, "PKCS-10 PEM-file decode/encode"}].
+pkcs10_pem(Config) when is_list(Config) ->
+ Datadir = ?config(data_dir, Config),
+ [{'CertificationRequest', DerPKCS10, not_encrypted} = Entry] =
+ erl_make_certs:pem_to_der(filename:join(Datadir, "req.pem")),
+
+ erl_make_certs:der_to_pem(filename:join(Datadir, "new_req.pem"), [Entry]),
+
+ PKCS10 = public_key:der_decode('CertificationRequest', DerPKCS10),
+ PKCS10 = public_key:pem_entry_decode(Entry),
+
+ Entry = public_key:pem_entry_encode('CertificationRequest', PKCS10).
+
+%%--------------------------------------------------------------------
+pkcs7_pem() ->
+ [{doc, "PKCS-7 PEM-file decode/encode"}].
+pkcs7_pem(Config) when is_list(Config) ->
+ Datadir = ?config(data_dir, Config),
+ [{'ContentInfo', DerPKCS7, not_encrypted} = Entry] =
+ erl_make_certs:pem_to_der(filename:join(Datadir, "pkcs7_cert.pem")),
+
+ erl_make_certs:der_to_pem(filename:join(Datadir, "new_pkcs7_cert.pem"), [Entry]),
+
+ PKCS7 = public_key:der_decode('ContentInfo', DerPKCS7),
+ PKCS7 = public_key:pem_entry_decode(Entry),
+
+ Entry = public_key:pem_entry_encode('ContentInfo', PKCS7).
+
+%%--------------------------------------------------------------------
+cert_pem() ->
+ [{doc, "Certificate PEM-file decode/encode"}].
cert_pem(Config) when is_list(Config) ->
Datadir = ?config(data_dir, Config),
@@ -280,10 +253,8 @@ cert_pem(Config) when is_list(Config) ->
[Entry0] = erl_make_certs:pem_to_der(filename:join(Datadir, "wdsa.pem")).
%%--------------------------------------------------------------------
-ssh_rsa_public_key(doc) ->
- "";
-ssh_rsa_public_key(suite) ->
- [];
+ssh_rsa_public_key() ->
+ [{doc, "ssh rsa public key decode/encode"}].
ssh_rsa_public_key(Config) when is_list(Config) ->
Datadir = ?config(data_dir, Config),
@@ -308,10 +279,8 @@ ssh_rsa_public_key(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-ssh_dsa_public_key(doc) ->
- "";
-ssh_dsa_public_key(suite) ->
- [];
+ssh_dsa_public_key() ->
+ [{doc, "ssh dsa public key decode/encode"}].
ssh_dsa_public_key(Config) when is_list(Config) ->
Datadir = ?config(data_dir, Config),
@@ -335,10 +304,8 @@ ssh_dsa_public_key(Config) when is_list(Config) ->
public_key:ssh_decode(EncodedOpenSsh, public_key).
%%--------------------------------------------------------------------
-ssh_rfc4716_rsa_comment(doc) ->
- "Test comment header and rsa key";
-ssh_rfc4716_rsa_comment(suite) ->
- [];
+ssh_rfc4716_rsa_comment() ->
+ [{doc, "Test comment header and rsa key"}].
ssh_rfc4716_rsa_comment(Config) when is_list(Config) ->
Datadir = ?config(data_dir, Config),
@@ -353,10 +320,8 @@ ssh_rfc4716_rsa_comment(Config) when is_list(Config) ->
RSARawSsh2 = public_key:ssh_encode([{PubKey, Attributes}], rfc4716_public_key).
%%--------------------------------------------------------------------
-ssh_rfc4716_dsa_comment(doc) ->
- "Test comment header and dsa key";
-ssh_rfc4716_dsa_comment(suite) ->
- [];
+ssh_rfc4716_dsa_comment() ->
+ [{doc, "Test comment header and dsa key"}].
ssh_rfc4716_dsa_comment(Config) when is_list(Config) ->
Datadir = ?config(data_dir, Config),
@@ -375,10 +340,8 @@ ssh_rfc4716_dsa_comment(Config) when is_list(Config) ->
public_key:ssh_decode(Encoded, public_key).
%%--------------------------------------------------------------------
-ssh_rfc4716_rsa_subject(doc) ->
- "Test another header value than comment";
-ssh_rfc4716_rsa_subject(suite) ->
- [];
+ssh_rfc4716_rsa_subject() ->
+ [{doc, "Test another header value than comment"}].
ssh_rfc4716_rsa_subject(Config) when is_list(Config) ->
Datadir = ?config(data_dir, Config),
@@ -397,10 +360,8 @@ ssh_rfc4716_rsa_subject(Config) when is_list(Config) ->
public_key:ssh_decode(Encoded, public_key).
%%--------------------------------------------------------------------
-ssh_known_hosts(doc) ->
- "";
-ssh_known_hosts(suite) ->
- [];
+ssh_known_hosts() ->
+ [{doc, "ssh known hosts file encode/decode"}].
ssh_known_hosts(Config) when is_list(Config) ->
Datadir = ?config(data_dir, Config),
@@ -428,10 +389,8 @@ ssh_known_hosts(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-ssh1_known_hosts(doc) ->
- "";
-ssh1_known_hosts(suite) ->
- [];
+ssh1_known_hosts() ->
+ [{doc, "ssh (ver 1) known hosts file encode/decode"}].
ssh1_known_hosts(Config) when is_list(Config) ->
Datadir = ?config(data_dir, Config),
@@ -450,10 +409,8 @@ ssh1_known_hosts(Config) when is_list(Config) ->
Decoded = public_key:ssh_decode(Encoded, known_hosts).
%%--------------------------------------------------------------------
-ssh_auth_keys(doc) ->
- "";
-ssh_auth_keys(suite) ->
- [];
+ssh_auth_keys() ->
+ [{doc, "ssh authorized keys file encode/decode"}].
ssh_auth_keys(Config) when is_list(Config) ->
Datadir = ?config(data_dir, Config),
@@ -478,10 +435,8 @@ ssh_auth_keys(Config) when is_list(Config) ->
Decoded = public_key:ssh_decode(Encoded, auth_keys).
%%--------------------------------------------------------------------
-ssh1_auth_keys(doc) ->
- "";
-ssh1_auth_keys(suite) ->
- [];
+ssh1_auth_keys() ->
+ [{doc, "ssh (ver 1) authorized keys file encode/decode"}].
ssh1_auth_keys(Config) when is_list(Config) ->
Datadir = ?config(data_dir, Config),
@@ -508,10 +463,8 @@ ssh1_auth_keys(Config) when is_list(Config) ->
Decoded = public_key:ssh_decode(Encoded, auth_keys).
%%--------------------------------------------------------------------
-ssh_openssh_public_key_with_comment(doc) ->
- "Test that emty lines and lines starting with # are ignored";
-ssh_openssh_public_key_with_comment(suite) ->
- [];
+ssh_openssh_public_key_with_comment() ->
+ [{doc, "Test that emty lines and lines starting with # are ignored"}].
ssh_openssh_public_key_with_comment(Config) when is_list(Config) ->
Datadir = ?config(data_dir, Config),
@@ -519,10 +472,8 @@ ssh_openssh_public_key_with_comment(Config) when is_list(Config) ->
[{{_, #'Dss-Parms'{}}, _}] = public_key:ssh_decode(DSARawOpenSsh, openssh_public_key).
%%--------------------------------------------------------------------
-ssh_openssh_public_key_long_header(doc) ->
- "Test that long headers are handled";
-ssh_openssh_public_key_long_header(suite) ->
- [];
+ssh_openssh_public_key_long_header() ->
+ [{doc, "Test that long headers are handled"}].
ssh_openssh_public_key_long_header(Config) when is_list(Config) ->
Datadir = ?config(data_dir, Config),
@@ -533,10 +484,8 @@ ssh_openssh_public_key_long_header(Config) when is_list(Config) ->
Decoded = public_key:ssh_decode(Encoded, rfc4716_public_key).
%%--------------------------------------------------------------------
-encrypt_decrypt(doc) ->
- [""];
-encrypt_decrypt(suite) ->
- [];
+encrypt_decrypt() ->
+ [{doc, "Test public_key:encrypt_private and public_key:decrypt_public"}].
encrypt_decrypt(Config) when is_list(Config) ->
{PrivateKey, _DerKey} = erl_make_certs:gen_rsa(64),
#'RSAPrivateKey'{modulus=Mod, publicExponent=Exp} = PrivateKey,
@@ -553,10 +502,8 @@ encrypt_decrypt(Config) when is_list(Config) ->
ok.
%%--------------------------------------------------------------------
-rsa_sign_verify(doc) ->
- ["Checks that we can sign and verify rsa signatures."];
-rsa_sign_verify(suite) ->
- [];
+rsa_sign_verify() ->
+ [{doc, "Checks that we can sign and verify rsa signatures."}].
rsa_sign_verify(Config) when is_list(Config) ->
Ca = {_, CaKey} = erl_make_certs:make_cert([]),
{Cert1, _} = erl_make_certs:make_cert([{key, dsa}, {issuer, Ca}]),
@@ -576,10 +523,8 @@ rsa_sign_verify(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-dsa_sign_verify(doc) ->
- ["Checks that we can sign and verify dsa signatures."];
-dsa_sign_verify(suite) ->
- [];
+dsa_sign_verify() ->
+ [{doc, "Checks that we can sign and verify dsa signatures."}].
dsa_sign_verify(Config) when is_list(Config) ->
Ca = erl_make_certs:make_cert([]),
CertInfo = {_,CertKey1} = erl_make_certs:make_cert([{key, dsa}, {issuer, Ca}]),
@@ -615,10 +560,8 @@ dsa_sign_verify(Config) when is_list(Config) ->
{DSAPublicKey, DSAParams}).
%%--------------------------------------------------------------------
-pkix(doc) ->
- "Misc pkix tests not covered elsewhere";
-pkix(suite) ->
- [];
+pkix() ->
+ [{doc, "Misc pkix tests not covered elsewhere"}].
pkix(Config) when is_list(Config) ->
Datadir = ?config(data_dir, Config),
Certs0 = erl_make_certs:pem_to_der(filename:join(Datadir, "cacerts.pem")),
@@ -656,17 +599,15 @@ pkix(Config) when is_list(Config) ->
[[{'AttributeTypeAndValue', {2,5,4,3},{printableString,"ERLANGCA"}}],
[{'AttributeTypeAndValue', {2,5,4,3},{printableString," erlang ca "}}]]},
VerifyStr = {rdnSequence,
- [[{'AttributeTypeAndValue', {2,5,4,3},{printableString,"erlang ca"}}],
- [{'AttributeTypeAndValue', {2,5,4,3},{printableString,"erlangca"}}]]},
+ [[{'AttributeTypeAndValue', {2,5,4,3},{printableString,"erlangca"}}],
+ [{'AttributeTypeAndValue', {2,5,4,3},{printableString,"erlang ca"}}]]},
VerifyStr = public_key:pkix_normalize_name(TestStr),
ok.
%%--------------------------------------------------------------------
-pkix_countryname(doc) ->
- "Test workaround for certs that code x509countryname as utf8";
-pkix_countryname(suite) ->
- [];
+pkix_countryname() ->
+ [{doc, "Test workaround for certs that code x509countryname as utf8"}].
pkix_countryname(Config) when is_list(Config) ->
Cert = incorrect_pkix_cert(),
OTPCert = public_key:pkix_decode_cert(Cert, otp),
@@ -676,24 +617,9 @@ pkix_countryname(Config) when is_list(Config) ->
check_countryname(Issuer),
check_countryname(Subj).
-check_countryname({rdnSequence,DirName}) ->
- do_check_countryname(DirName).
-do_check_countryname([]) ->
- ok;
-do_check_countryname([#'AttributeTypeAndValue'{type = ?'id-at-countryName',
- value = "US"}|_]) ->
- ok;
-do_check_countryname([#'AttributeTypeAndValue'{type = ?'id-at-countryName',
- value = Value}|_]) ->
- test_server:fail({incorrect_cuntry_name, Value});
-do_check_countryname([_| Rest]) ->
- do_check_countryname(Rest).
-
%%--------------------------------------------------------------------
-pkix_path_validation(doc) ->
- "Misc pkix tests not covered elsewhere";
-pkix_path_validation(suite) ->
- [];
+pkix_path_validation() ->
+ [{doc, "Test PKIX path validation"}].
pkix_path_validation(Config) when is_list(Config) ->
CaK = {Trusted,_} =
erl_make_certs:make_cert([{key, dsa},
@@ -724,7 +650,8 @@ pkix_path_validation(Config) when is_list(Config) ->
CertK3 = {Cert3,_} = erl_make_certs:make_cert([{issuer, CertK1},
{extensions, [{basic_constraints, false}]}]),
- {Cert4,_} = erl_make_certs:make_cert([{issuer, CertK3}]),
+ {Cert4,_} = erl_make_certs:make_cert([{issuer, CertK3}, {extensions, [{key_usage, undefined}]}]),
+
{error, {bad_cert,missing_basic_constraint}} =
public_key:pkix_path_validation(Trusted, [Cert1, Cert3,Cert4], []),
@@ -761,6 +688,21 @@ pkix_path_validation(Config) when is_list(Config) ->
public_key:pkix_path_validation(unknown_ca, [Cert1], [{verify_fun,
VerifyFunAndState1}]),
ok.
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
+check_countryname({rdnSequence,DirName}) ->
+ do_check_countryname(DirName).
+do_check_countryname([]) ->
+ ok;
+do_check_countryname([#'AttributeTypeAndValue'{type = ?'id-at-countryName',
+ value = "US"}|_]) ->
+ ok;
+do_check_countryname([#'AttributeTypeAndValue'{type = ?'id-at-countryName',
+ value = Value}|_]) ->
+ ct:fail({incorrect_cuntry_name, Value});
+do_check_countryname([_| Rest]) ->
+ do_check_countryname(Rest).
check_entry_type(#'DSAPrivateKey'{}, 'DSAPrivateKey') ->
true;
diff --git a/lib/public_key/test/public_key_SUITE_data/pkcs7_cert.pem b/lib/public_key/test/public_key_SUITE_data/pkcs7_cert.pem
new file mode 100644
index 0000000000..9b450a22c5
--- /dev/null
+++ b/lib/public_key/test/public_key_SUITE_data/pkcs7_cert.pem
@@ -0,0 +1,23 @@
+-----BEGIN PKCS7-----
+MIID6QYJKoZIhvcNAQcCoIID2jCCA9YCAQExADALBgkqhkiG9w0BBwGgggO8MIID
+uDCCAyGgAwIBAgIBAjANBgkqhkiG9w0BAQUFADCBgzEOMAwGA1UEAxMFb3RwQ0Ex
+EzARBgNVBAsTCkVybGFuZyBPVFAxFDASBgNVBAoTC0VyaWNzc29uIEFCMQswCQYD
+VQQGEwJTRTESMBAGA1UEBxMJU3RvY2tob2xtMSUwIwYJKoZIhvcNAQkBFhZwZXRl
+ckBlcml4LmVyaWNzc29uLnNlMB4XDTA4MDEwOTA4MjkzMFoXDTE3MTExNzA4Mjkz
+MFowgYQxDzANBgNVBAMTBnNlcnZlcjETMBEGA1UECxMKRXJsYW5nIE9UUDEUMBIG
+A1UEChMLRXJpY3Nzb24gQUIxCzAJBgNVBAYTAlNFMRIwEAYDVQQHEwlTdG9ja2hv
+bG0xJTAjBgkqhkiG9w0BCQEWFnBldGVyQGVyaXguZXJpY3Nzb24uc2UwgZ8wDQYJ
+KoZIhvcNAQEBBQADgY0AMIGJAoGBAKR20HPrkDGdiavHUyWwFEQwta2dmtF2eQZZ
+i9Xk68UJYbuU7CikHs2srkrwzj0OPIqbp/xOBNzJ7Kch0o4yO6vcEAiSCJ6AB4uS
+M742hrYW4qXgc18K6PqTwSuKr94sn3qQuo4hF/ymCxLrnSicrNpzGOz9A0Lf2+Vk
+6hV0BtdHAgMBAAGjggE3MIIBMzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DAdBgNV
+HQ4EFgQUi19l/qhEwHP/CUeaEjWy4GhOBRIwgbMGA1UdIwSBqzCBqIAUBquANDqk
+uHayvZ0uKOVtkd59AZuhgYykgYkwgYYxETAPBgNVBAMTCGVybGFuZ0NBMRMwEQYD
+VQQLEwpFcmxhbmcgT1RQMRQwEgYDVQQKEwtFcmljc3NvbiBBQjESMBAGA1UEBxMJ
+U3RvY2tob2xtMQswCQYDVQQGEwJTRTElMCMGCSqGSIb3DQEJARYWcGV0ZXJAZXJp
+eC5lcmljc3Nvbi5zZYIBATAhBgNVHREEGjAYgRZwZXRlckBlcml4LmVyaWNzc29u
+LnNlMCEGA1UdEgQaMBiBFnBldGVyQGVyaXguZXJpY3Nzb24uc2UwDQYJKoZIhvcN
+AQEFBQADgYEAzHGutrGMSeC3Di7Z8d65SM7jZLrkkusmL+D2oPVIOGrfZbVuyfDK
+U/nImm99z+lhC/N3JEEpB6PgAYSskfVdBL3LoxbUTaCn/+G3A/G8NfRVIYyANTBe
+NW6ueNpjnauLzcwpyXpu3vp1VBg8wBePtGTBIbRHRgtwwHRXAddE/WuhADEA
+-----END PKCS7-----
diff --git a/lib/public_key/vsn.mk b/lib/public_key/vsn.mk
index c8165fa247..b8af89d040 100644
--- a/lib/public_key/vsn.mk
+++ b/lib/public_key/vsn.mk
@@ -1 +1 @@
-PUBLIC_KEY_VSN = 0.16
+PUBLIC_KEY_VSN = 0.17
diff --git a/lib/reltool/doc/src/reltool.xml b/lib/reltool/doc/src/reltool.xml
index fbe29753be..8437b7a623 100644
--- a/lib/reltool/doc/src/reltool.xml
+++ b/lib/reltool/doc/src/reltool.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2009</year>
- <year>2012</year>
+ <year>2013</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -274,7 +274,8 @@
</taglist>
<p>Example:</p>
- <p><code>erl -sasl releases_dir \"mytarget/releases\" -boot mytarget/releases/1.0/myrel -boot_var RELTOOL_EXT_LIB mytarget/lib</code></p>
+ <p><code>erl -sasl releases_dir \"mytarget/releases\" -boot mytarget/releases/1.0/myrel\
+ -boot_var RELTOOL_EXT_LIB mytarget/lib</code></p>
</item>
<tag><c>incl_sys_filters</c></tag>
diff --git a/lib/reltool/src/Makefile b/lib/reltool/src/Makefile
index a7e34053f1..74918f1d67 100644
--- a/lib/reltool/src/Makefile
+++ b/lib/reltool/src/Makefile
@@ -79,10 +79,10 @@ docs:
# ----------------------------------------------------
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
# ----------------------------------------------------
# Dependencies
diff --git a/lib/reltool/src/reltool_sys_win.erl b/lib/reltool/src/reltool_sys_win.erl
index 0c0b295db1..8e182d02ed 100644
--- a/lib/reltool/src/reltool_sys_win.erl
+++ b/lib/reltool/src/reltool_sys_win.erl
@@ -49,7 +49,6 @@
rel_book,
lib_tree,
status_bar,
- popup_menu,
source,
whitelist,
blacklist,
@@ -136,6 +135,7 @@ init(Options) ->
do_init(Options)
catch
error:Reason ->
+ io:format("~p: ~p~n",[Reason, erlang:get_stacktrace()]),
exit({Reason, erlang:get_stacktrace()})
end.
@@ -403,8 +403,6 @@ create_menubar(Frame) ->
wxEvtHandler:connect(Frame,
command_menu_selected,
[{userData, main_window}]),
- wxEvtHandler:connect(File, menu_close),
- wxEvtHandler:connect(Help, menu_close),
MenuBar.
create_app_page(#state{book = Book} = S) ->
@@ -780,15 +778,12 @@ root_popup(S, Root, Tree, Item) ->
wxMenu:appendSeparator(PopupMenu),
wxMenu:append(PopupMenu, 1, "Edit"),
Choices = [edit],
- wxEvtHandler:connect(PopupMenu, command_menu_selected),
- wxEvtHandler:connect(PopupMenu, menu_close),
+ Popup = #root_popup{dir = Root, choices = Choices,
+ tree = Tree, item = Item},
+ wxEvtHandler:connect(PopupMenu, command_menu_selected, [{userData, {popup, Popup}}]),
wxWindow:popupMenu(S#state.frame, PopupMenu),
- Popup = #root_popup{dir = Root,
- choices = Choices,
- tree = Tree,
- item = Item},
- S#state{popup_menu = Popup}.
+ S.
lib_popup(S, Lib, Tree, Item) ->
PopupMenu = wxMenu:new(),
@@ -804,12 +799,10 @@ lib_popup(S, Lib, Tree, Item) ->
wxMenu:append(PopupMenu, 3, "Delete"),
[add, edit, delete]
end,
- wxEvtHandler:connect(PopupMenu, command_menu_selected),
- wxEvtHandler:connect(PopupMenu, menu_close),
- wxWindow:popupMenu(S#state.frame, PopupMenu),
-
Popup = #lib_popup{dir = Lib, choices = Choices, tree = Tree, item = Item},
- S#state{popup_menu = Popup}.
+ wxEvtHandler:connect(PopupMenu, command_menu_selected, [{userData, {popup, Popup}}]),
+ wxWindow:popupMenu(S#state.frame, PopupMenu),
+ S.
escript_popup(S, File, Tree, Item) ->
PopupMenu = wxMenu:new(),
@@ -825,15 +818,11 @@ escript_popup(S, File, Tree, Item) ->
wxMenu:append(PopupMenu, 3, "Delete"),
[add, edit, delete]
end,
- wxEvtHandler:connect(PopupMenu, command_menu_selected),
- wxEvtHandler:connect(PopupMenu, menu_close),
+ Popup = #escript_popup{file = File, choices = Choices,
+ tree = Tree, item = Item},
+ wxEvtHandler:connect(PopupMenu, command_menu_selected, [{userData, {popup, Popup}}]),
wxWindow:popupMenu(S#state.frame, PopupMenu),
-
- Popup = #escript_popup{file = File,
- choices = Choices,
- tree = Tree,
- item = Item},
- S#state{popup_menu = Popup}.
+ S.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -903,11 +892,13 @@ handle_event(S, #wx{id = Id, obj= ObjRef, userData = UserData, event = Event} =
wxMessageDialog:showModal(MD),
wxMessageDialog:destroy(MD),
S;
- #wxMenu{type = menu_close} ->
- S#state{popup_menu = undefined};
- #wxCommand{type = command_menu_selected = Type, cmdString = Str}
- when S#state.popup_menu =/= undefined ->
- handle_popup_event(S, Type, Id, ObjRef, UserData, Str);
+ #wxCommand{type = command_menu_selected = Type, cmdString = Str} ->
+ case UserData of
+ {popup, Popup} ->
+ handle_popup_event(S, Type, Id, ObjRef, Popup, Str);
+ true ->
+ S
+ end;
#wxMouse{type = enter_window} ->
%% The following is commented out because it raises the
%% main system window on top of popup windows.
@@ -1028,11 +1019,9 @@ warning_popup_position(#state{frame=MF,warning_list=WL},{WFW,WFH}) ->
{X,Y}.
handle_popup_event(S, _Type, 0, _ObjRef, _UserData, _Str) ->
- S#state{popup_menu = undefined};
-handle_popup_event(#state{popup_menu = #root_popup{dir = OldDir,
- choices = Choices},
- sys = Sys} = S,
- _Type, Pos, _ObjRef, _UserData, _Str) ->
+ S;
+handle_popup_event(#state{sys = Sys} = S, _Type, Pos, _ObjRef,
+ #root_popup{dir = OldDir, choices = Choices}, _Str) ->
case lists:nth(Pos, Choices) of
edit ->
Style = ?wxFD_OPEN bor ?wxFD_FILE_MUST_EXIST,
@@ -1042,18 +1031,16 @@ handle_popup_event(#state{popup_menu = #root_popup{dir = OldDir,
Style) of
{ok, NewDir} when NewDir =:= OldDir ->
%% Same dir.Ignore.
- S#state{popup_menu = undefined};
+ S;
{ok, NewDir} ->
Sys2 = Sys#sys{root_dir = NewDir},
- do_set_sys(S#state{popup_menu = undefined, sys = Sys2});
+ do_set_sys(S#state{sys = Sys2});
cancel ->
- S#state{popup_menu = undefined}
+ S
end
end;
-handle_popup_event(#state{popup_menu = #lib_popup{dir = OldDir,
- choices = Choices},
- sys = Sys} = S,
- _Type, Pos, _ObjRef, _UserData, _Str) ->
+handle_popup_event(#state{sys = Sys} = S, _Type, Pos, _ObjRef,
+ #lib_popup{dir = OldDir, choices = Choices}, _Str) ->
case lists:nth(Pos, Choices) of
add ->
{ok, Cwd} = file:get_cwd(),
@@ -1063,15 +1050,14 @@ handle_popup_event(#state{popup_menu = #lib_popup{dir = OldDir,
case lists:member(NewDir, Sys#sys.lib_dirs) of
true ->
%% Ignore duplicate. Keep old.
- S#state{popup_menu = undefined};
+ S;
false ->
LibDirs = Sys#sys.lib_dirs ++ [NewDir],
Sys2 = Sys#sys{lib_dirs = LibDirs},
- do_set_sys(S#state{popup_menu = undefined,
- sys = Sys2})
+ do_set_sys(S#state{sys = Sys2})
end;
cancel ->
- S#state{popup_menu = undefined}
+ S
end;
edit ->
Style = ?wxFD_OPEN bor ?wxFD_FILE_MUST_EXIST,
@@ -1083,28 +1069,25 @@ handle_popup_event(#state{popup_menu = #lib_popup{dir = OldDir,
case lists:member(NewDir, Sys#sys.lib_dirs) of
true ->
%% Ignore duplicate. Keep old.
- S#state{popup_menu = undefined};
+ S;
false ->
Pred = fun(E) -> E =/= OldDir end,
{Before, [_| After]} =
lists:splitwith(Pred, Sys#sys.lib_dirs),
LibDirs2 = Before ++ [NewDir | After],
Sys2 = Sys#sys{lib_dirs = LibDirs2},
- do_set_sys(S#state{popup_menu = undefined,
- sys = Sys2})
+ do_set_sys(S#state{sys = Sys2})
end;
cancel ->
- S#state{popup_menu = undefined}
+ S
end;
delete ->
LibDirs = Sys#sys.lib_dirs -- [OldDir],
Sys2 = Sys#sys{lib_dirs = LibDirs},
- do_set_sys(S#state{popup_menu = undefined, sys = Sys2})
+ do_set_sys(S#state{sys = Sys2})
end;
-handle_popup_event(#state{popup_menu = #escript_popup{file = OldFile,
- choices = Choices},
- sys = Sys} = S,
- _Type, Pos, _ObjRef, _UserData, _Str) ->
+handle_popup_event(#state{sys = Sys} = S, _Type, Pos, _ObjRef,
+ #escript_popup{file = OldFile, choices = Choices}, _Str) ->
case lists:nth(Pos, Choices) of
add ->
OldFile2 =
@@ -1124,14 +1107,14 @@ handle_popup_event(#state{popup_menu = #escript_popup{file = OldFile,
case lists:member(NewFile, Sys#sys.escripts) of
true ->
%% Ignore duplicate. Keep old.
- S#state{popup_menu = undefined};
+ S;
false ->
Escripts = Sys#sys.escripts ++ [NewFile],
Sys2 = Sys#sys{escripts = Escripts},
- do_set_sys(S#state{popup_menu = undefined, sys = Sys2})
+ do_set_sys(S#state{sys = Sys2})
end;
cancel ->
- S#state{popup_menu = undefined}
+ S
end;
edit ->
Style = ?wxFD_OPEN bor ?wxFD_FILE_MUST_EXIST,
@@ -1143,23 +1126,22 @@ handle_popup_event(#state{popup_menu = #escript_popup{file = OldFile,
case lists:member(NewFile, Sys#sys.escripts) of
true ->
%% Ignore duplicate. Keep old.
- S#state{popup_menu = undefined};
+ S;
false ->
Pred = fun(E) -> E =/= OldFile end,
{Before, [_| After]} =
lists:splitwith(Pred, Sys#sys.escripts),
Escripts2 = Before ++ [NewFile | After],
Sys2 = Sys#sys{escripts = Escripts2},
- do_set_sys(S#state{popup_menu = undefined,
- sys = Sys2})
+ do_set_sys(S#state{sys = Sys2})
end;
cancel ->
- S#state{popup_menu = undefined}
+ S
end;
delete ->
Escripts = Sys#sys.escripts -- [OldFile],
Sys2 = Sys#sys{escripts = Escripts},
- do_set_sys(S#state{popup_menu = undefined, sys = Sys2})
+ do_set_sys(S#state{sys = Sys2})
end.
handle_system_event(#state{sys = Sys} = S,
diff --git a/lib/reltool/src/reltool_target.erl b/lib/reltool/src/reltool_target.erl
index 6cb7ba0163..1f4ce7226a 100644
--- a/lib/reltool/src/reltool_target.erl
+++ b/lib/reltool/src/reltool_target.erl
@@ -482,33 +482,12 @@ do_gen_script(#rel{name = RelName, vsn = RelVsn},
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-load_app_mods(#app{mods = Mods} = App, Mand, PathFlag, Variables) ->
+load_app_mods(#app{mods = Mods0} = App, Mand, PathFlag, Variables) ->
Path = cr_path(App, PathFlag, Variables),
- PartNames =
- lists:sort([{packages:split(M),M} ||
- #mod{name = M, is_included=true} <- Mods,
- not lists:member(M, Mand)]),
- SplitMods =
- lists:foldl(
- fun({Parts,M}, [{Last, Acc}|Rest]) ->
- [_|Tail] = lists:reverse(Parts),
- case lists:reverse(Tail) of
- Subs when Subs == Last ->
- [{Last,[M|Acc]}|Rest];
- Subs ->
- [{Subs, [M]}|[{Last,Acc}|Rest]]
- end
- end,
- [{[],
- []}],
- PartNames),
- lists:foldl(
- fun({Subs,Ms}, Cmds) ->
- [{path, [filename:join([Path | Subs])]},
- {primLoad, lists:sort(Ms)} | Cmds]
- end,
- [],
- SplitMods).
+ Mods = [M || #mod{name = M, is_included=true} <- Mods0,
+ not lists:member(M, Mand)],
+ [{path, [filename:join([Path])]},
+ {primLoad, lists:sort(Mods)}].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% sort_used_and_incl_apps(Apps, OrderedApps) -> Apps
diff --git a/lib/runtime_tools/c_src/Makefile.in b/lib/runtime_tools/c_src/Makefile.in
index 586f649924..d315a90e18 100644
--- a/lib/runtime_tools/c_src/Makefile.in
+++ b/lib/runtime_tools/c_src/Makefile.in
@@ -111,11 +111,11 @@ debug opt valgrind: $(SOLIBS) $(OBJDIR) $(LIBDIR) $(NIF_LIB)
ifdef DTRACE_ENABLED
DTRACE_USER_HEADER=$(OBJDIR)/dtrace_user.h
$(OBJDIR)/dtrace_user.h: ./dtrace_user.d
- dtrace -h -C $(INCLUDES) \
+ $(dtrace_verbose)dtrace -h -C $(INCLUDES) \
-s ./dtrace_user.d \
-o ./dtrace_user.tmp
- sed -e '/^#define[ ]*ERLANG_[A-Z0-9_]*(.*)/y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' ./dtrace_user.tmp > $@
- rm ./dtrace_user.tmp
+ $(V_at)sed -e '/^#define[ ]*ERLANG_[A-Z0-9_]*(.*)/y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' ./dtrace_user.tmp > $@
+ $(V_at)rm ./dtrace_user.tmp
else
DTRACE_USER_HEADER=
endif
@@ -124,7 +124,7 @@ DTRACE_OBJS =
ifdef DTRACE_ENABLED_2STEP
DTRACE_OBJS += $(OBJDIR)/dtrace_user.o
$(OBJDIR)/dtrace_user.o: $(before_DTrace_OBJS) $(OBJDIR)/dtrace_user.h
- dtrace -G -C \
+ $(dtrace_verbose)dtrace -G -C \
-s ./dtrace_user.d \
-o $@ $(before_DTrace_OBJS)
endif
@@ -138,26 +138,26 @@ $(LIBDIR):
-@mkdir -p $(LIBDIR)
$(OBJDIR)/dyntrace$(TYPEMARKER).o: dyntrace.c $(DTRACE_USER_HEADER)
- $(INSTALL_DIR) $(OBJDIR)
- $(CC) -c -o $@ $(ALL_CFLAGS) $<
+ $(V_at)$(INSTALL_DIR) $(OBJDIR)
+ $(V_CC) -c -o $@ $(ALL_CFLAGS) $<
$(NIF_LIB): $(DYNTRACE_OBJS)
- $(INSTALL_DIR) $(LIBDIR)
- $(LD) $(LDFLAGS) -o $@ $^ $(LDLIBS)
+ $(V_at)$(INSTALL_DIR) $(LIBDIR)
+ $(V_LD) $(LDFLAGS) -o $@ $^ $(LDLIBS)
$(OBJDIR)/%.o: %.c
- $(CC) -c -o $@ $(ALL_CFLAGS) $<
+ $(V_CC) -c -o $@ $(ALL_CFLAGS) $<
$(LIBDIR)/trace_ip_drv.so: $(TRACE_IP_DRV_OBJS)
- $(LD) $(LDFLAGS) -o $@ $^ -lc $(LIBS)
+ $(V_LD) $(LDFLAGS) -o $@ $^ -lc $(LIBS)
$(LIBDIR)/trace_file_drv.so: $(TRACE_FILE_DRV_OBJS)
- $(LD) $(LDFLAGS) -o $@ $^ -lc $(LIBS)
+ $(V_LD) $(LDFLAGS) -o $@ $^ -lc $(LIBS)
$(LIBDIR)/trace_ip_drv.dll: $(TRACE_IP_DRV_OBJS)
- $(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
+ $(V_LD) $(LDFLAGS) -o $@ $^ $(LIBS)
$(LIBDIR)/trace_file_drv.dll: $(TRACE_FILE_DRV_OBJS)
- $(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
+ $(V_LD) $(LDFLAGS) -o $@ $^ $(LIBS)
clean:
rm -f $(SOLIBS) $(TRACE_IP_DRV_OBJS) $(TRACE_FILE_DRV_OBJS)
diff --git a/lib/runtime_tools/doc/src/dbg.xml b/lib/runtime_tools/doc/src/dbg.xml
index c7c5cd4ff0..d8c82b2459 100644
--- a/lib/runtime_tools/doc/src/dbg.xml
+++ b/lib/runtime_tools/doc/src/dbg.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2011</year>
+ <year>1996</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -101,7 +101,8 @@
allowed:</p>
<pre>
4> <input>dbg:fun2ms(fun([M,N]) when N > X, is_atomm(M) -> return_trace() end).</input>
-Error: fun containing local erlang function calls ('is_atomm' called in guard) cannot be translated into match_spec
+Error: fun containing local erlang function calls ('is_atomm' called in guard)\
+ cannot be translated into match_spec
{error,transform_error}
5> <input>dbg:fun2ms(fun([M,N]) when N > X, is_atom(M) -> return_trace() end).</input>
[{['$1','$2'],[{'>','$2',{const,3}},{is_atom,'$1'}],[{return_trace}]}]</pre>
diff --git a/lib/runtime_tools/src/Makefile b/lib/runtime_tools/src/Makefile
index d6750f3a88..53b9ce34e4 100644
--- a/lib/runtime_tools/src/Makefile
+++ b/lib/runtime_tools/src/Makefile
@@ -35,6 +35,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/runtime_tools-$(VSN)
# ----------------------------------------------------
MODULES= \
+ appmon_info \
erts_alloc_config \
runtime_tools \
runtime_tools_sup \
@@ -80,10 +81,10 @@ clean:
rm -f errs core *~
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
docs:
diff --git a/lib/appmon/src/appmon_info.erl b/lib/runtime_tools/src/appmon_info.erl
index 332140f69d..332140f69d 100644
--- a/lib/appmon/src/appmon_info.erl
+++ b/lib/runtime_tools/src/appmon_info.erl
diff --git a/lib/runtime_tools/src/dyntrace.erl b/lib/runtime_tools/src/dyntrace.erl
index b4579fd5ce..f7dbef6929 100644
--- a/lib/runtime_tools/src/dyntrace.erl
+++ b/lib/runtime_tools/src/dyntrace.erl
@@ -105,7 +105,7 @@ available() ->
user_trace_s1(_Message) ->
erlang:nif_error(nif_not_loaded).
--spec user_trace_i4s4(iolist(),
+-spec user_trace_i4s4(binary() | undefined,
integer_maybe(), integer_maybe(),
integer_maybe(), integer_maybe(),
iolist_maybe(), iolist_maybe(),
@@ -115,7 +115,7 @@ user_trace_s1(_Message) ->
user_trace_i4s4(_, _, _, _, _, _, _, _, _) ->
erlang:nif_error(nif_not_loaded).
--spec user_trace_n(n_probe_label(), iolist(),
+-spec user_trace_n(n_probe_label(), binary() | undefined,
integer_maybe(), integer_maybe(),
integer_maybe(), integer_maybe(),
iolist_maybe(), iolist_maybe(),
diff --git a/lib/runtime_tools/src/observer_backend.erl b/lib/runtime_tools/src/observer_backend.erl
index 01e99f3f5e..9498412505 100644
--- a/lib/runtime_tools/src/observer_backend.erl
+++ b/lib/runtime_tools/src/observer_backend.erl
@@ -83,7 +83,7 @@ get_table2(Parent, Table, Type) ->
ets -> ets:info(Table, size);
mnesia -> mnesia:table_info(Table, size)
end,
- case Size > 0 of
+ case Size =/= undefined andalso Size > 0 of
false ->
Parent ! {self(), '$end_of_table'},
normal;
diff --git a/lib/runtime_tools/src/runtime_tools.app.src b/lib/runtime_tools/src/runtime_tools.app.src
index 60be9ed7c9..602048dc21 100644
--- a/lib/runtime_tools/src/runtime_tools.app.src
+++ b/lib/runtime_tools/src/runtime_tools.app.src
@@ -19,7 +19,7 @@
{application, runtime_tools,
[{description, "RUNTIME_TOOLS"},
{vsn, "%VSN%"},
- {modules, [dbg,observer_backend,percept_profile,
+ {modules, [appmon_info, dbg,observer_backend,percept_profile,
runtime_tools,runtime_tools_sup,erts_alloc_config,
ttb_autostart,dyntrace]},
{registered, [runtime_tools_sup]},
diff --git a/lib/runtime_tools/src/runtime_tools_sup.erl b/lib/runtime_tools/src/runtime_tools_sup.erl
index c8dab250dd..264e172a3c 100644
--- a/lib/runtime_tools/src/runtime_tools_sup.erl
+++ b/lib/runtime_tools/src/runtime_tools_sup.erl
@@ -1,3 +1,4 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
@@ -18,7 +19,7 @@
%%
%% ------------------------------------------------------------------------------
%% File : runtime_tools_sup.erl
-%% Author : Lennart �hman <[email protected]>
+%% Author : Lennart Öhman <[email protected]>
-module(runtime_tools_sup).
-behaviour(supervisor).
diff --git a/lib/runtime_tools/test/dbg_SUITE.erl b/lib/runtime_tools/test/dbg_SUITE.erl
index 4071b159a1..dfae52ed1d 100644
--- a/lib/runtime_tools/test/dbg_SUITE.erl
+++ b/lib/runtime_tools/test/dbg_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -514,7 +514,7 @@ file_port_schedfix1(Config) when is_list(Config) ->
%% Cleanup
%%
?line ToBeDeleted = filelib:wildcard(FName++"*"++".wraplog"),
- ?line lists:map({file, delete}, ToBeDeleted),
+ ?line lists:map(fun file:delete/1, ToBeDeleted),
% io:format("ToBeDeleted=~p", [ToBeDeleted]),
%%
%% Present the result
diff --git a/lib/sasl/src/Makefile b/lib/sasl/src/Makefile
index de0c45e6ae..c1ad8ca0bb 100644
--- a/lib/sasl/src/Makefile
+++ b/lib/sasl/src/Makefile
@@ -80,10 +80,10 @@ docs:
# ----------------------------------------------------
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
# ----------------------------------------------------
# Release Target
diff --git a/lib/sasl/src/overload.erl b/lib/sasl/src/overload.erl
index 5a4782efff..97f7bebe00 100644
--- a/lib/sasl/src/overload.erl
+++ b/lib/sasl/src/overload.erl
@@ -1,7 +1,8 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -25,7 +26,7 @@
format_status/2]).
%%%-----------------------------------------------------------------
-%%% This is a rewrite of overload from BS.3, by Peter H�gfeldt.
+%%% This is a rewrite of overload from BS.3, by Peter Högfeldt.
%%%
%%% DESCRIPTION
%%%
diff --git a/lib/sasl/src/release_handler.erl b/lib/sasl/src/release_handler.erl
index 5efd932c92..1ff3eb96eb 100644
--- a/lib/sasl/src/release_handler.erl
+++ b/lib/sasl/src/release_handler.erl
@@ -494,10 +494,10 @@ find_script(App, Dir, OldVsn, UpOrDown) ->
up -> UpFromScripts;
down -> DownToScripts
end,
- case lists:keysearch(OldVsn, 1, Scripts) of
- {value, {_OldVsn, Script}} ->
- {NewVsn, Script};
- false ->
+ case systools_relup:appup_search_for_version(OldVsn,Scripts) of
+ {ok,Script} ->
+ {NewVsn,Script};
+ error ->
throw({version_not_in_appup, OldVsn})
end;
{error, enoent} ->
diff --git a/lib/sasl/src/systools_make.erl b/lib/sasl/src/systools_make.erl
index e8b28998c1..9b2e2c809b 100644
--- a/lib/sasl/src/systools_make.erl
+++ b/lib/sasl/src/systools_make.erl
@@ -1067,11 +1067,10 @@ check_mod(Mod,App,Dir,Ext,IncPath) ->
end.
mod_to_filename(Dir, Mod, Ext) ->
- Parts = packages:split(Mod),
- filename:join([Dir | Parts]) ++ Ext.
+ filename:join(Dir, atom_to_list(Mod) ++ Ext).
check_module(Mod, Dir, ObjModTime, IncPath) ->
- {SrcDirs,_IncDirs}= smart_guess(Mod, Dir,IncPath),
+ {SrcDirs,_IncDirs}= smart_guess(Dir,IncPath),
case locate_src(Mod,SrcDirs) of
{ok,_FDir,_File,LastModTime} ->
if
@@ -1085,7 +1084,7 @@ check_module(Mod, Dir, ObjModTime, IncPath) ->
end.
locate_src(Mod,[Dir|Dirs]) ->
- File = filename:join(Dir, mod_to_fname(Mod) ++ ".erl"),
+ File = mod_to_filename(Dir, Mod, ".erl"),
case file:read_file_info(File) of
{ok,FileInfo} ->
LastModTime = FileInfo#file_info.mtime,
@@ -1096,9 +1095,6 @@ locate_src(Mod,[Dir|Dirs]) ->
locate_src(_,[]) ->
false.
-mod_to_fname(Mod) ->
- hd(lists:reverse(packages:split(Mod))).
-
%%______________________________________________________________________
%% smart_guess(Mod, Dir,IncludePath) -> {[Dirs],[IncDirs]}
@@ -1106,17 +1102,12 @@ mod_to_fname(Mod) ->
%% src-dir should be one of .../src or .../src/e_src
%% If dir does not contain .../ebin set dir to the same directory.
-smart_guess(Mod, Dir,IncPath) ->
+smart_guess(Dir,IncPath) ->
case reverse(filename:split(Dir)) of
["ebin"|D] ->
- Subdirs = case packages:split(Mod) of
- [_] -> [];
- [_|_] = Parts ->
- lists:reverse(tl(lists:reverse(Parts)))
- end,
D1 = reverse(D),
- Dirs = [filename:join(D1 ++ ["src" | Subdirs]),
- filename:join(D1 ++ ["src", "e_src" | Subdirs])],
+ Dirs = [filename:join(D1 ++ ["src"]),
+ filename:join(D1 ++ ["src", "e_src"])],
{Dirs,Dirs ++ IncPath};
_ ->
{[Dir],[Dir] ++ IncPath}
@@ -1423,23 +1414,8 @@ load_appl_mods([], _, _, _) ->
[{progress, modules_loaded}].
load_commands(Mods, Path) ->
- SplitMods = lists:foldl(
- fun({Parts,M}, [{Last, Acc}|Rest]) ->
- [_|Tail] = lists:reverse(Parts),
- case lists:reverse(Tail) of
- Subs when Subs == Last ->
- [{Last,[M|Acc]}|Rest];
- Subs ->
- [{Subs, [M]}|[{Last,Acc}|Rest]]
- end
- end, [{[],[]}],
- lists:sort([{packages:split(M),M} || M <- Mods])),
- lists:foldl(
- fun({Subs,Ms}, Cmds) ->
- [{path, [filename:join([Path | Subs])]},
- {primLoad,lists:sort(Ms)} | Cmds]
- end, [], SplitMods).
-
+ [{path, [filename:join([Path])]},
+ {primLoad,lists:sort(Mods)}].
%%______________________________________________________________________
%% Pack an application to an application term.
@@ -1485,7 +1461,8 @@ mandatory_modules() ->
preloaded() ->
%% Sorted
- [erl_prim_loader,erlang,init,otp_ring0,prim_file,prim_inet, prim_zip,zlib].
+ [erl_prim_loader,erlang,erts_internal,init,otp_ring0,prim_file,prim_inet,
+ prim_zip,zlib].
%%______________________________________________________________________
%% Kernel processes; processes that are specially treated by the init
diff --git a/lib/sasl/src/systools_relup.erl b/lib/sasl/src/systools_relup.erl
index 7fb623bb85..7048184426 100644
--- a/lib/sasl/src/systools_relup.erl
+++ b/lib/sasl/src/systools_relup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -114,7 +114,8 @@
-define(R15_SASL_VSN,"2.2").
-%% For test purposes only - used by kernel, stdlib and sasl tests
+%% Used by release_handler:find_script/4.
+%% Also used by kernel, stdlib and sasl tests
-export([appup_search_for_version/2]).
%%-----------------------------------------------------------------
diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl
index 87a755031c..94cffc988d 100644
--- a/lib/sasl/test/release_handler_SUITE.erl
+++ b/lib/sasl/test/release_handler_SUITE.erl
@@ -63,7 +63,8 @@ cases() ->
instructions, eval_appup, eval_appup_with_restart,
supervisor_which_children_timeout,
release_handler_which_releases, install_release_syntax_check,
- upgrade_supervisor, upgrade_supervisor_fail, otp_9864].
+ upgrade_supervisor, upgrade_supervisor_fail, otp_9864,
+ otp_10463_upgrade_script_regexp].
groups() ->
[{release,[],
@@ -1660,6 +1661,15 @@ upgrade_gg(cleanup,Config) ->
ok = stop_nodes(NodeNames).
+%%%-----------------------------------------------------------------
+%%% OTP-10463, Bug - release_handler could not handle regexp in appup
+%%% files.
+otp_10463_upgrade_script_regexp(_Config) ->
+ %% Assuming that kernel always has a regexp in it's appup
+ KernelVsn = vsn(kernel,current),
+ {ok,KernelVsn,_} =
+ release_handler:upgrade_script(kernel,code:lib_dir(kernel)),
+ ok.
%%%=================================================================
diff --git a/lib/snmp/doc/src/Makefile b/lib/snmp/doc/src/Makefile
index 8820565124..6e55498669 100644
--- a/lib/snmp/doc/src/Makefile
+++ b/lib/snmp/doc/src/Makefile
@@ -118,7 +118,7 @@ clean clean_docs: clean_html clean_man clean_pdf
rm -f errs core *~
$(INDEX_TARGET): $(INDEX_SRC) ../../vsn.mk # Create top make file
- sed -e 's;%VSN%;$(VSN);' $< > $@ # inserting version number
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@ # inserting version number
man: man1 man3 man6 man7
diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml
index 442837d57d..5b94dcb051 100644
--- a/lib/snmp/doc/src/notes.xml
+++ b/lib/snmp/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1996</year><year>2012</year>
+ <year>1996</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -34,6 +34,86 @@
<section>
+ <title>SNMP Development Toolkit 4.23</title>
+<!--
+ <p>Version 4.23 supports code replacement in runtime from/to
+ version 4.22.1,
+ 4.22, 4.21.7 4.21.6 4.21.5, 4.21.4, 4.21.3, 4.21.2, 4.21.1 and 4.21. </p>
+-->
+
+ <section>
+ <title>Improvements and new features</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>[manager] Polish return values of snmpm_user_default according
+ to snmpm_user doc.</p>
+ <p>Luca Favatella</p>
+ <p>Own Id: OTP-10671</p>
+ </item>
+
+ <item>
+ <p>[agent] Remove runtime warning in snmpa_agent because of
+ tuple fun usage. </p>
+ <p>Luca Favatella</p>
+ <p>Own Id: OTP-10672</p>
+ </item>
+
+ <item>
+ <p>[manager] SNMP manager performance optimization. </p>
+ <p>Ivan Dubovik</p>
+ <p>Own Id: OTP-10673</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Fixed Bugs and Malfunctions</title>
+ <p>-</p>
+
+ <!--
+ <list type="bulleted">
+ <item>
+ <p>[agent] Simultaneous
+ <seealso marker="snmpa#backup">snmpa:backup/1,2</seealso>
+ calls can interfere.
+ The master agent did not check if a backup was already in
+ progress when a backup request was accepted. </p>
+ <p>Own Id: OTP-9884</p>
+ <p>Aux Id: Seq 11995</p>
+ </item>
+
+ </list>
+ -->
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>[manager] The old Addr-and-Port based API functions, previously
+ long deprecated and marked for deletion in R16B, has now been
+ removed. </p>
+ <p>Own Id: OTP-10027</p>
+ </item>
+
+ </list>
+ </section>
+
+ </section> <!-- 4.23 -->
+
+
+ <section>
<title>SNMP Development Toolkit 4.22.1</title>
<p>Version 4.22.1 supports code replacement in runtime from/to
version 4.22, 4.21.7 4.21.6 4.21.5, 4.21.4, 4.21.3, 4.21.2, 4.21.1 and
diff --git a/lib/snmp/doc/src/snmpm.xml b/lib/snmp/doc/src/snmpm.xml
index 8ab3be8e18..07fdd208ff 100644
--- a/lib/snmp/doc/src/snmpm.xml
+++ b/lib/snmp/doc/src/snmpm.xml
@@ -279,7 +279,6 @@ sec_level = noAuthNoPriv | authNoPriv | authPriv
<fsummary>Register this agent</fsummary>
<type>
<v>UserId = term()</v>
- <v>Addr = ip_address()</v>
<v>TargetName = target_name()</v>
<v>Config = [agent_config()]</v>
<v>agent_config() = {Item, Val}</v>
@@ -367,7 +366,7 @@ sec_level = noAuthNoPriv | authNoPriv | authPriv
<p>Update agent config. The function <c>update_agent_info/3</c>
should be used when several values needs to be updated atomically. </p>
<p>See function
- <seealso marker="#register_agent">register_agent</seealso>)
+ <seealso marker="#register_agent">register_agent</seealso>
for more info about what kind of items are allowed. </p>
<marker id="which_agents"></marker>
diff --git a/lib/snmp/mibs/Makefile.in b/lib/snmp/mibs/Makefile.in
index 5c1f855fad..e7ca540cc6 100644
--- a/lib/snmp/mibs/Makefile.in
+++ b/lib/snmp/mibs/Makefile.in
@@ -141,11 +141,11 @@ OTP_MIBDIR = $(shell if test -d ../../otp_mibs; then echo otp_mibs; \
debug opt: $(TARGET_FILES)
$(ERL_TOP)/lib/snmp/bin/snmp-v2tov1: $(ERL_TOP)/lib/snmp/bin/snmp-v2tov1.src
- $(PERL) -p -e 's?%PERL%?$(PERL)? ' < $< > $@
- chmod 755 $@
+ $(gen_verbose)$(PERL) -p -e 's?%PERL%?$(PERL)? ' < $< > $@
+ $(V_at)chmod 755 $@
$(SNMP_BIN_TARGET_DIR)/OTP-REG.bin: $(ERL_TOP)/lib/$(OTP_MIBDIR)/mibs/OTP-REG.mib
- $(ERLC) -pa $(SNMP_TOOLKIT)/ebin -I $(SNMP_TOOLKIT)/priv/mibs $(SNMP_FLAGS) -o $(SNMP_BIN_TARGET_DIR) $<
+ $(snmp_verbose)$(ERLC) -pa $(SNMP_TOOLKIT)/ebin -I $(SNMP_TOOLKIT)/priv/mibs $(SNMP_FLAGS) -o $(SNMP_BIN_TARGET_DIR) $<
# To support parallel make, we'll need explicit dependencies
# to ensure that an imported MIB has been compiled when it's needed.
@@ -214,7 +214,7 @@ info:
@echo "RELSYSDIR = "$(RELSYSDIR)""
v1/%.mib.v1: %.mib $(ERL_TOP)/lib/snmp/bin/snmp-v2tov1
- $(ERL_TOP)/lib/snmp/bin/snmp-v2tov1 -o $@ $<
+ $(gen_verbose)$(ERL_TOP)/lib/snmp/bin/snmp-v2tov1 -o $@ $<
# ----------------------------------------------------
diff --git a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
index 436f15eb9c..ad9540e886 100644
--- a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
+++ b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
@@ -496,7 +496,7 @@ verify_vacmSecurityToGroupTable_col(_, Val) ->
%%
%%-----------------------------------------------------------------
vacmAccessTable(print) ->
- %% M�ste jag g�ra om alla entrien till {RowIdx, Row}?
+ %% Do I need to turn all entries into {RowIdx, Row}?
TableInfo = get_table(vacmAccessTable),
PrintRow =
fun(Prefix, Row) ->
diff --git a/lib/snmp/src/agent/snmpa_agent.erl b/lib/snmp/src/agent/snmpa_agent.erl
index 9d30e332f1..57846db13b 100644
--- a/lib/snmp/src/agent/snmpa_agent.erl
+++ b/lib/snmp/src/agent/snmpa_agent.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -1134,7 +1134,7 @@ handle_call({get, Vars, Context}, _From, S) ->
"~n Vars: ~p"
"~n Context: ~p", [Vars, Context]),
put_pdu_data({undefined, undefined, undefined, undefined, Context}),
- case catch mapfoldl({?MODULE, tr_var}, [], 1, Vars) of
+ case catch mapfoldl(fun ?MODULE:tr_var/2, [], 1, Vars) of
{error, Reason} -> {reply, {error, Reason}, S};
{_, Varbinds} ->
?vdebug("Varbinds: ~p",[Varbinds]),
@@ -1155,7 +1155,7 @@ handle_call({get_next, Vars, Context}, _From, S) ->
"~n Vars: ~p"
"~n Context: ~p",[Vars, Context]),
put_pdu_data({undefined, undefined, undefined, undefined, Context}),
- case catch mapfoldl({?MODULE, tr_var}, [], 1, Vars) of
+ case catch mapfoldl(fun ?MODULE:tr_var/2, [], 1, Vars) of
{error, Reason} -> {reply, {error, Reason}, S};
{_, Varbinds} ->
?vdebug("Varbinds: ~p",[Varbinds]),
diff --git a/lib/snmp/src/app/Makefile b/lib/snmp/src/app/Makefile
index f7c311b663..716add8b9e 100644
--- a/lib/snmp/src/app/Makefile
+++ b/lib/snmp/src/app/Makefile
@@ -116,10 +116,10 @@ info:
# ----------------------------------------------------
$(APP_TARGET): $(APP_SRC) ../../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
# ----------------------------------------------------
# Release Target
diff --git a/lib/snmp/src/app/snmp.appup.src b/lib/snmp/src/app/snmp.appup.src
index 593ddd82bd..a6abf8439a 100644
--- a/lib/snmp/src/app/snmp.appup.src
+++ b/lib/snmp/src/app/snmp.appup.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -22,582 +22,12 @@
%% ----- U p g r a d e -------------------------------------------------------
[
- {"4.22",
- [
- {load_module, snmpm, soft_purge, soft_purge, []},
- {load_module, snmp_pdus, soft_purge, soft_purge, []},
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
- {load_module, snmp_user_based_sm_mib, soft_purge, soft_purge, []}
- ]
- },
- {"4.21.7",
- [
- {load_module, snmp_pdus, soft_purge, soft_purge, []},
-
- {load_module, snmp_config, soft_purge, soft_purge, []},
- {load_module, snmp_conf, soft_purge, soft_purge, []},
- {load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_framework_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_notification_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_standard_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_target_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_user_based_sm_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, [snmp_conf]},
-
- {load_module, snmp, soft_purge, soft_purge, [snmp_log]},
- {load_module, snmpa, soft_purge, soft_purge, [snmp]},
- {load_module, snmpm, soft_purge, soft_purge, [snmp]},
- {load_module, snmp_log, soft_purge, soft_purge, []},
- {load_module, snmp_verbosity, soft_purge, soft_purge, []},
- {load_module, snmpm_mpd, soft_purge, soft_purge, []},
-
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []},
-
- {add_module, snmpm_net_if_mt}
- ]
- },
- {"4.21.6",
- [
- {load_module, snmp_pdus, soft_purge, soft_purge, []},
-
- {load_module, snmp_config, soft_purge, soft_purge, []},
- {load_module, snmp_conf, soft_purge, soft_purge, []},
- {load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_framework_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_notification_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_standard_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_target_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_user_based_sm_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, [snmp_conf]},
-
- {load_module, snmp, soft_purge, soft_purge, [snmp_log]},
- {load_module, snmpa, soft_purge, soft_purge, [snmp]},
- {load_module, snmpm, soft_purge, soft_purge, [snmp]},
- {load_module, snmp_log, soft_purge, soft_purge, []},
- {load_module, snmp_verbosity, soft_purge, soft_purge, []},
- {load_module, snmpm_mpd, soft_purge, soft_purge, []},
-
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []},
-
- {add_module, snmpm_net_if_mt}
- ]
- },
- {"4.21.5",
- [
- {load_module, snmp_pdus, soft_purge, soft_purge, []},
-
- {load_module, snmp_config, soft_purge, soft_purge, []},
- {load_module, snmp_conf, soft_purge, soft_purge, []},
- {load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_framework_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_notification_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_standard_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_user_based_sm_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, [snmp_conf]},
-
- {load_module, snmp, soft_purge, soft_purge, [snmp_log]},
- {load_module, snmpm, soft_purge, soft_purge, [snmp]},
- {load_module, snmp_log, soft_purge, soft_purge, []},
- {load_module, snmp_verbosity, soft_purge, soft_purge, []},
- {load_module, snmpm_mpd, soft_purge, soft_purge, []},
-
- {load_module, snmpa, soft_purge, soft_purge, [snmp]},
- {load_module, snmp_target_mib, soft_purge, soft_purge,
- [snmp_conf, snmpa_mib_lib]},
- {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
- {load_module, snmpa_trap, soft_purge, soft_purge, []},
- {load_module, snmpa_vacm, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []},
-
- {add_module, snmpm_net_if_mt}
- ]
- },
- {"4.21.4",
- [
- {load_module, snmp_pdus, soft_purge, soft_purge, []},
-
- {load_module, snmp_config, soft_purge, soft_purge, []},
- {load_module, snmp_conf, soft_purge, soft_purge, []},
- {load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_framework_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_notification_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_standard_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_user_based_sm_mib, soft_purge, soft_purge, [snmp_conf]},
-
- {load_module, snmp, soft_purge, soft_purge, [snmp_log]},
- {load_module, snmpm, soft_purge, soft_purge, [snmp]},
- {load_module, snmp_log, soft_purge, soft_purge, []},
- {load_module, snmp_verbosity, soft_purge, soft_purge, []},
- {load_module, snmpm_mpd, soft_purge, soft_purge, []},
-
- {load_module, snmpa, soft_purge, soft_purge, [snmp]},
- {load_module, snmp_target_mib, soft_purge, soft_purge,
- [snmp_conf, snmpa_mib_lib]},
- {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
- {load_module, snmpa_trap, soft_purge, soft_purge, []},
- {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
-
- {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge,
- [snmp_conf]},
- {load_module, snmpa_vacm, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []},
-
- {add_module, snmpm_net_if_mt}
- ]
- },
- {"4.21.3",
- [
- {load_module, snmp_pdus, soft_purge, soft_purge, []},
-
- {load_module, snmp_config, soft_purge, soft_purge, []},
- {load_module, snmp_conf, soft_purge, soft_purge, []},
- {load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_framework_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_notification_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_standard_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_user_based_sm_mib, soft_purge, soft_purge, [snmp_conf]},
-
- {load_module, snmp, soft_purge, soft_purge, [snmp_log]},
- {load_module, snmpm, soft_purge, soft_purge, [snmp]},
- {load_module, snmp_log, soft_purge, soft_purge, []},
- {load_module, snmp_verbosity, soft_purge, soft_purge, []},
- {load_module, snmpm_mpd, soft_purge, soft_purge, []},
-
- {load_module, snmpa, soft_purge, soft_purge, [snmp]},
- {load_module, snmp_target_mib, soft_purge, soft_purge,
- [snmp_conf, snmpa_mib_lib]},
- {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
- {load_module, snmpa_trap, soft_purge, soft_purge, []},
- {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
-
- {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge,
- [snmp_conf]},
- {load_module, snmpa_vacm, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []},
-
- {add_module, snmpm_net_if_mt}
- ]
- },
- {"4.21.2",
- [
- {load_module, snmp_pdus, soft_purge, soft_purge, []},
-
- {load_module, snmp_config, soft_purge, soft_purge, []},
- {load_module, snmp_conf, soft_purge, soft_purge, []},
- {load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_framework_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_notification_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_standard_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_user_based_sm_mib, soft_purge, soft_purge, [snmp_conf]},
-
- {load_module, snmp, soft_purge, soft_purge, [snmp_log]},
- {load_module, snmpm, soft_purge, soft_purge, [snmp]},
- {load_module, snmp_log, soft_purge, soft_purge, []},
- {load_module, snmp_verbosity, soft_purge, soft_purge, []},
- {load_module, snmpm_mpd, soft_purge, soft_purge, []},
-
- {load_module, snmpa, soft_purge, soft_purge, [snmp]},
- {load_module, snmp_target_mib, soft_purge, soft_purge,
- [snmp_conf, snmpa_mib_lib]},
- {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
- {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
-
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge,
- [snmp_conf]},
- {load_module, snmpa_vacm, soft_purge, soft_purge, []},
- {load_module, snmpa_mpd, soft_purge, soft_purge, []},
- {load_module, snmpa_set_lib, soft_purge, soft_purge, []},
- {load_module, snmpa_trap, soft_purge, soft_purge, []},
- {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []},
-
- {add_module, snmpm_net_if_mt}
- ]
- },
- {"4.21.1",
- [
- {load_module, snmp_pdus, soft_purge, soft_purge, []},
-
- {load_module, snmp_config, soft_purge, soft_purge, []},
- {load_module, snmp_conf, soft_purge, soft_purge, []},
- {load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_framework_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_notification_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_standard_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_user_based_sm_mib, soft_purge, soft_purge, [snmp_conf]},
-
- {load_module, snmp, soft_purge, soft_purge, [snmp_log]},
- {load_module, snmpm, soft_purge, soft_purge, [snmp]},
- {load_module, snmp_log, soft_purge, soft_purge, []},
- {load_module, snmp_verbosity, soft_purge, soft_purge, []},
- {load_module, snmpm_mpd, soft_purge, soft_purge, []},
-
- {load_module, snmpa, soft_purge, soft_purge, [snmp]},
- {load_module, snmp_target_mib, soft_purge, soft_purge,
- [snmp_conf, snmpa_mib_lib]},
- {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
- {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
-
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge,
- [snmp_conf]},
- {load_module, snmpa_vacm, soft_purge, soft_purge, []},
- {load_module, snmpa_mpd, soft_purge, soft_purge, []},
- {load_module, snmpa_set_lib, soft_purge, soft_purge, []},
- {load_module, snmpa_trap, soft_purge, soft_purge, []},
- {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []},
- {update, snmp_note_store, soft, soft_purge, soft_purge, []},
-
- {add_module, snmpm_net_if_mt}
- ]
- },
- {"4.21",
- [
- {load_module, snmp_pdus, soft_purge, soft_purge, []},
-
- {load_module, snmp_config, soft_purge, soft_purge, []},
- {load_module, snmp_conf, soft_purge, soft_purge, []},
- {load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_framework_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_notification_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_standard_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_user_based_sm_mib, soft_purge, soft_purge, [snmp_conf]},
-
- {load_module, snmp, soft_purge, soft_purge, [snmp_log]},
- {load_module, snmpm, soft_purge, soft_purge, [snmp]},
- {load_module, snmp_log, soft_purge, soft_purge, []},
- {load_module, snmp_verbosity, soft_purge, soft_purge, []},
- {load_module, snmpm_mpd, soft_purge, soft_purge, []},
-
- {load_module, snmpa, soft_purge, soft_purge, [snmp]},
- {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
- {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
-
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge,
- [snmp_conf]},
- {load_module, snmpa_vacm, soft_purge, soft_purge, []},
- {load_module, snmpa_mpd, soft_purge, soft_purge, []},
- {load_module, snmpa_set_lib, soft_purge, soft_purge, []},
- {load_module, snmpa_trap, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge,
- [snmp_conf, snmpa_mib_lib]},
- {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []},
- {update, snmp_note_store, soft, soft_purge, soft_purge, []},
-
- {add_module, snmpm_net_if_mt}
- ]
- }
],
%% ------D o w n g r a d e ---------------------------------------------------
[
- {"4.22",
- [
- {load_module, snmpm, soft_purge, soft_purge, []},
- {load_module, snmp_pdus, soft_purge, soft_purge, []},
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
- {load_module, snmp_user_based_sm_mib, soft_purge, soft_purge, []}
- ]
- },
- {"4.21.7",
- [
- {load_module, snmp_pdus, soft_purge, soft_purge, []},
-
- {load_module, snmp_pdus, soft_purge, soft_purge, []},
- {load_module, snmp_config, soft_purge, soft_purge, []},
- {load_module, snmp_conf, soft_purge, soft_purge, []},
- {load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_framework_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_notification_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_standard_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_target_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_user_based_sm_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, [snmp_conf]},
-
- {load_module, snmp, soft_purge, soft_purge, [snmp_log]},
- {load_module, snmpa, soft_purge, soft_purge, [snmp]},
- {load_module, snmpm, soft_purge, soft_purge, [snmp]},
- {load_module, snmp_log, soft_purge, soft_purge, []},
- {load_module, snmp_verbosity, soft_purge, soft_purge, []},
- {load_module, snmpm_mpd, soft_purge, soft_purge, []},
-
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []},
-
- {remove, {snmpm_net_if_mt, soft_purge, soft_purge}}
- ]
- },
- {"4.21.6",
- [
- {load_module, snmp_pdus, soft_purge, soft_purge, []},
-
- {load_module, snmp_config, soft_purge, soft_purge, []},
- {load_module, snmp_conf, soft_purge, soft_purge, []},
- {load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_framework_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_notification_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_standard_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_target_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_user_based_sm_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, [snmp_conf]},
-
- {load_module, snmp, soft_purge, soft_purge, [snmp_log]},
- {load_module, snmpa, soft_purge, soft_purge, [snmp]},
- {load_module, snmpm, soft_purge, soft_purge, [snmp]},
- {load_module, snmp_log, soft_purge, soft_purge, []},
- {load_module, snmp_verbosity, soft_purge, soft_purge, []},
- {load_module, snmpm_mpd, soft_purge, soft_purge, []},
-
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []},
-
- {remove, {snmpm_net_if_mt, soft_purge, soft_purge}}
- ]
- },
- {"4.21.5",
- [
- {load_module, snmp_pdus, soft_purge, soft_purge, []},
-
- {load_module, snmp_config, soft_purge, soft_purge, []},
- {load_module, snmp_conf, soft_purge, soft_purge, []},
- {load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_framework_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_notification_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_standard_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_user_based_sm_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, [snmp_conf]},
-
- {load_module, snmp, soft_purge, soft_purge, [snmp_log]},
- {load_module, snmpm, soft_purge, soft_purge, [snmp]},
- {load_module, snmp_log, soft_purge, soft_purge, []},
- {load_module, snmp_verbosity, soft_purge, soft_purge, []},
- {load_module, snmpm_mpd, soft_purge, soft_purge, []},
-
- {load_module, snmpa, soft_purge, soft_purge, [snmp]},
- {load_module, snmp_target_mib, soft_purge, soft_purge,
- [snmp_conf, snmpa_mib_lib]},
- {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
- {load_module, snmpa_trap, soft_purge, soft_purge, []},
- {load_module, snmpa_vacm, soft_purge, soft_purge, []},
- {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []},
-
- {remove, {snmpm_net_if_mt, soft_purge, soft_purge}}
- ]
- },
- {"4.21.4",
- [
- {load_module, snmp_pdus, soft_purge, soft_purge, []},
-
- {load_module, snmp_config, soft_purge, soft_purge, []},
- {load_module, snmp_conf, soft_purge, soft_purge, []},
- {load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_framework_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_notification_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_standard_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_user_based_sm_mib, soft_purge, soft_purge, [snmp_conf]},
-
- {load_module, snmp, soft_purge, soft_purge, [snmp_log]},
- {load_module, snmpm, soft_purge, soft_purge, [snmp]},
- {load_module, snmp_log, soft_purge, soft_purge, []},
- {load_module, snmp_verbosity, soft_purge, soft_purge, []},
- {load_module, snmpm_mpd, soft_purge, soft_purge, []},
-
- {load_module, snmpa, soft_purge, soft_purge, [snmp]},
- {load_module, snmp_target_mib, soft_purge, soft_purge,
- [snmp_conf, snmpa_mib_lib]},
- {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
- {load_module, snmpa_trap, soft_purge, soft_purge, []},
- {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
-
- {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge,
- [snmp_conf]},
- {load_module, snmpa_vacm, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []},
-
- {remove, {snmpm_net_if_mt, soft_purge, soft_purge}}
- ]
- },
- {"4.21.3",
- [
- {load_module, snmp_pdus, soft_purge, soft_purge, []},
-
- {load_module, snmp_config, soft_purge, soft_purge, []},
- {load_module, snmp_conf, soft_purge, soft_purge, []},
- {load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_framework_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_notification_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_standard_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_user_based_sm_mib, soft_purge, soft_purge, [snmp_conf]},
-
- {load_module, snmp, soft_purge, soft_purge, [snmp_log]},
- {load_module, snmpm, soft_purge, soft_purge, [snmp]},
- {load_module, snmp_log, soft_purge, soft_purge, []},
- {load_module, snmp_verbosity, soft_purge, soft_purge, []},
- {load_module, snmpm_mpd, soft_purge, soft_purge, []},
-
- {load_module, snmpa, soft_purge, soft_purge, [snmp]},
- {load_module, snmp_target_mib, soft_purge, soft_purge,
- [snmp_conf, snmpa_mib_lib]},
- {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
- {load_module, snmpa_trap, soft_purge, soft_purge, []},
- {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
-
- {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge,
- [snmp_conf]},
- {load_module, snmpa_vacm, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []},
-
- {remove, {snmpm_net_if_mt, soft_purge, soft_purge}}
- ]
- },
- {"4.21.2",
- [
- {load_module, snmp_pdus, soft_purge, soft_purge, []},
-
- {load_module, snmp_config, soft_purge, soft_purge, []},
- {load_module, snmp_conf, soft_purge, soft_purge, []},
- {load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_framework_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_notification_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_standard_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_user_based_sm_mib, soft_purge, soft_purge, [snmp_conf]},
-
- {load_module, snmp, soft_purge, soft_purge, [snmp_log]},
- {load_module, snmpm, soft_purge, soft_purge, [snmp]},
- {load_module, snmp_log, soft_purge, soft_purge, []},
- {load_module, snmp_verbosity, soft_purge, soft_purge, []},
- {load_module, snmpm_mpd, soft_purge, soft_purge, []},
-
- {load_module, snmpa, soft_purge, soft_purge, [snmp]},
- {load_module, snmp_target_mib, soft_purge, soft_purge,
- [snmp_conf, snmpa_mib_lib]},
- {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
- {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
-
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge,
- [snmp_conf]},
- {load_module, snmpa_vacm, soft_purge, soft_purge, []},
- {load_module, snmpa_mpd, soft_purge, soft_purge, []},
- {load_module, snmpa_set_lib, soft_purge, soft_purge, []},
- {load_module, snmpa_trap, soft_purge, soft_purge, []},
- {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []},
-
- {remove, {snmpm_net_if_mt, soft_purge, soft_purge}}
- ]
- },
- {"4.21.1",
- [
- {load_module, snmp_pdus, soft_purge, soft_purge, []},
-
- {load_module, snmp_config, soft_purge, soft_purge, []},
- {load_module, snmp_conf, soft_purge, soft_purge, []},
- {load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_framework_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_notification_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_standard_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_user_based_sm_mib, soft_purge, soft_purge, [snmp_conf]},
-
- {load_module, snmp, soft_purge, soft_purge, [snmp_log]},
- {load_module, snmpm, soft_purge, soft_purge, [snmp]},
- {load_module, snmp_log, soft_purge, soft_purge, []},
- {load_module, snmp_verbosity, soft_purge, soft_purge, []},
- {load_module, snmpm_mpd, soft_purge, soft_purge, []},
-
- {load_module, snmpa, soft_purge, soft_purge, [snmp]},
- {load_module, snmp_target_mib, soft_purge, soft_purge,
- [snmp_conf, snmpa_mib_lib]},
- {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
- {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
-
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge,
- [snmp_conf]},
- {load_module, snmpa_vacm, soft_purge, soft_purge, []},
- {load_module, snmpa_mpd, soft_purge, soft_purge, []},
- {load_module, snmpa_set_lib, soft_purge, soft_purge, []},
- {load_module, snmpa_trap, soft_purge, soft_purge, []},
- {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []},
- {update, snmp_note_store, soft, soft_purge, soft_purge, []},
-
- {remove, {snmpm_net_if_mt, soft_purge, soft_purge}}
- ]
- },
- {"4.21",
- [
- {load_module, snmp_pdus, soft_purge, soft_purge, []},
-
- {load_module, snmp_config, soft_purge, soft_purge, []},
- {load_module, snmp_conf, soft_purge, soft_purge, []},
- {load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_framework_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_notification_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_standard_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmp_user_based_sm_mib, soft_purge, soft_purge, [snmp_conf]},
-
- {load_module, snmp, soft_purge, soft_purge, [snmp_log]},
- {load_module, snmpm, soft_purge, soft_purge, [snmp]},
- {load_module, snmp_log, soft_purge, soft_purge, []},
- {load_module, snmp_verbosity, soft_purge, soft_purge, []},
- {load_module, snmpm_mpd, soft_purge, soft_purge, []},
-
- {load_module, snmpa, soft_purge, soft_purge, [snmp]},
- {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
- {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
-
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge,
- [snmp_conf]},
- {load_module, snmpa_vacm, soft_purge, soft_purge, []},
- {load_module, snmpa_mpd, soft_purge, soft_purge, []},
- {load_module, snmpa_set_lib, soft_purge, soft_purge, []},
- {load_module, snmpa_trap, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge,
- [snmp_conf, snmpa_mib_lib]},
- {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_mib, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []},
- {update, snmp_note_store, soft, soft_purge, soft_purge, []},
-
- {remove, {snmpm_net_if_mt, soft_purge, soft_purge}}
- ]
- }
]
+
}.
diff --git a/lib/snmp/src/compile/depend.mk b/lib/snmp/src/compile/depend.mk
index 3ee8dc4bec..e6ba1ac810 100644
--- a/lib/snmp/src/compile/depend.mk
+++ b/lib/snmp/src/compile/depend.mk
@@ -45,5 +45,5 @@ $(EBIN)/snmpc_mib_gram.$(EMULATOR): \
snmpc_mib_gram.erl
$(BIN)/snmpc: snmpc.src ../../vsn.mk
- $(PERL) -p -e 's?%VSN%?$(VSN)? ' < $< > $@
- chmod 755 $@
+ $(vsn_verbose)$(PERL) -p -e 's?%VSN%?$(VSN)? ' < $< > $@
+ $(V_at)chmod 755 $@
diff --git a/lib/snmp/src/manager/snmpm.erl b/lib/snmp/src/manager/snmpm.erl
index f590892c66..6ac0115dad 100644
--- a/lib/snmp/src/manager/snmpm.erl
+++ b/lib/snmp/src/manager/snmpm.erl
@@ -107,63 +107,9 @@
async_get_bulk/5, async_get_bulk/6, async_get_bulk/7, async_get_bulk/8
]).
-%% Backward compatibility exports (API version "1")
--deprecated({agent_info, 3}).
--deprecated({update_agent_info, 5}).
--deprecated({g, 3}).
--deprecated({g, 4}).
--deprecated({g, 5}).
--deprecated({g, 6}).
--deprecated({g, 7}).
--deprecated({ag, 3}).
--deprecated({ag, 4}).
--deprecated({ag, 5}).
--deprecated({ag, 6}).
--deprecated({ag, 7}).
--deprecated({gn, 3}).
--deprecated({gn, 4}).
--deprecated({gn, 5}).
--deprecated({gn, 6}).
--deprecated({gn, 7}).
--deprecated({agn, 3}).
--deprecated({agn, 4}).
--deprecated({agn, 5}).
--deprecated({agn, 6}).
--deprecated({agn, 7}).
--deprecated({gb, 5}).
--deprecated({gb, 6}).
--deprecated({gb, 7}).
--deprecated({gb, 8}).
--deprecated({gb, 9}).
--deprecated({agb, 5}).
--deprecated({agb, 6}).
--deprecated({agb, 7}).
--deprecated({agb, 8}).
--deprecated({agb, 9}).
--deprecated({s, 3}).
--deprecated({s, 4}).
--deprecated({s, 5}).
--deprecated({s, 6}).
--deprecated({s, 7}).
--deprecated({as, 3}).
--deprecated({as, 4}).
--deprecated({as, 5}).
--deprecated({as, 6}).
--deprecated({as, 7}).
--export([
- agent_info/3, update_agent_info/5,
- g/3, g/4, g/5, g/6, g/7,
- ag/3, ag/4, ag/5, ag/6, ag/7,
- gn/3, gn/4, gn/5, gn/6, gn/7,
- agn/3, agn/4, agn/5, agn/6, agn/7,
- gb/5, gb/6, gb/7, gb/8, gb/9,
- agb/5, agb/6, agb/7, agb/8, agb/9,
- s/3, s/4, s/5, s/6, s/7,
- as/3, as/4, as/5, as/6, as/7
- ]).
-
%% Application internal export
-export([start_link/3, snmpm_start_verify/2, snmpm_start_verify/3]).
+-export([target_name/1, target_name/2]).
-include_lib("snmp/src/misc/snmp_debug.hrl").
@@ -439,32 +385,16 @@ unregister_agent(UserId, Addr, Port) ->
Error
end.
+
agent_info(TargetName, Item) ->
snmpm_config:agent_info(TargetName, Item).
-%% Backward compatibility
-agent_info(Addr, Port, Item) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- agent_info(TargetName, Item);
- Error ->
- Error
- end.
-
update_agent_info(UserId, TargetName, Info) when is_list(Info) ->
snmpm_config:update_agent_info(UserId, TargetName, Info).
update_agent_info(UserId, TargetName, Item, Val) ->
update_agent_info(UserId, TargetName, [{Item, Val}]).
-%% Backward compatibility functions
-update_agent_info(UserId, Addr, Port, Item, Val) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- update_agent_info(UserId, TargetName, Item, Val);
- Error ->
- Error
- end.
which_agents() ->
snmpm_config:which_agents().
@@ -552,55 +482,6 @@ sync_get(UserId, TargetName, Context, Oids, Timeout, ExtraInfo) ->
%% </BACKWARD-COMPAT>
-%% <DEPRECATED>
-g(UserId, Addr, Oids) ->
- g(UserId, Addr, ?DEFAULT_AGENT_PORT, Oids).
-
-g(UserId, Addr, CtxName, Oids) when is_list(CtxName) andalso is_list(Oids) ->
- g(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, Oids);
-
-g(UserId, Addr, Port, Oids) when is_integer(Port) andalso is_list(Oids) ->
- g(UserId, Addr, Port, ?DEFAULT_CONTEXT, Oids);
-
-g(UserId, Addr, Oids, Timeout)
- when is_list(Oids) andalso is_integer(Timeout) ->
- g(UserId, Addr, ?DEFAULT_AGENT_PORT, Oids, Timeout).
-
-g(UserId, Addr, Port, CtxName, Oids)
- when is_integer(Port) andalso is_list(CtxName) andalso is_list(Oids) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- sync_get(UserId, TargetName, CtxName, Oids);
- Error ->
- Error
- end;
-
-g(UserId, Addr, Port, Oids, Timeout)
- when is_integer(Port) andalso is_list(Oids) andalso is_integer(Timeout) ->
- g(UserId, Addr, Port, ?DEFAULT_CONTEXT, Oids, Timeout);
-
-g(UserId, Addr, CtxName, Oids, Timeout)
- when is_list(CtxName) andalso is_list(Oids) andalso is_integer(Timeout) ->
- g(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, Oids, Timeout).
-
-g(UserId, Addr, Port, CtxName, Oids, Timeout) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- sync_get(UserId, TargetName, CtxName, Oids, Timeout);
- Error ->
- Error
- end.
-
-g(UserId, Addr, Port, CtxName, Oids, Timeout, ExtraInfo) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- sync_get(UserId, TargetName, CtxName, Oids, Timeout, ExtraInfo);
- Error ->
- Error
- end.
-%% </DEPRECATED>
-
-
%% --- asynchroneous get-request ---
%%
@@ -637,55 +518,6 @@ async_get(UserId, TargetName, Context, Oids, Expire, ExtraInfo) ->
%% </BACKWARD-COMPAT>
-%% <DEPRECATED>
-ag(UserId, Addr, Oids) ->
- ag(UserId, Addr, ?DEFAULT_AGENT_PORT, Oids).
-
-ag(UserId, Addr, Port, Oids) when is_integer(Port) andalso is_list(Oids) ->
- ag(UserId, Addr, Port, ?DEFAULT_CONTEXT, Oids);
-
-ag(UserId, Addr, CtxName, Oids) when is_list(CtxName) andalso is_list(Oids) ->
- ag(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, Oids);
-
-ag(UserId, Addr, Oids, Expire) when is_list(Oids) andalso is_integer(Expire) ->
- ag(UserId, Addr, ?DEFAULT_AGENT_PORT, ?DEFAULT_CONTEXT, Oids, Expire).
-
-ag(UserId, Addr, Port, CtxName, Oids)
- when is_integer(Port) andalso is_list(CtxName) andalso is_list(Oids) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- async_get(UserId, TargetName, CtxName, Oids);
- Error ->
- Error
- end;
-
-ag(UserId, Addr, Port, Oids, Expire)
- when is_integer(Port) andalso is_list(Oids) andalso is_integer(Expire) ->
- ag(UserId, Addr, Port, ?DEFAULT_CONTEXT, Oids, Expire);
-
-ag(UserId, Addr, CtxName, Oids, Expire)
- when is_list(CtxName) andalso is_list(Oids) andalso is_integer(Expire) ->
- ag(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, Oids, Expire).
-
-ag(UserId, Addr, Port, CtxName, Oids, Expire) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- async_get(UserId, TargetName, CtxName, Oids, Expire);
- Error ->
- Error
- end.
-
-ag(UserId, Addr, Port, CtxName, Oids, Expire, ExtraInfo) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- async_get(UserId, TargetName, CtxName, Oids, Expire, ExtraInfo);
- Error ->
- Error
- end.
-%% </DEPRECATED>
-
-
-
%% --- synchroneous get_next-request ---
%%
@@ -719,55 +551,6 @@ sync_get_next(UserId, TargetName, Context, Oids, Timeout, ExtraInfo) ->
%% </BACKWARD-COMPAT>
-%% <DEPRECATED>
-gn(UserId, Addr, Oids) ->
- gn(UserId, Addr, ?DEFAULT_AGENT_PORT, Oids).
-
-gn(UserId, Addr, CtxName, Oids) when is_list(CtxName) andalso is_list(Oids) ->
- gn(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, Oids);
-
-gn(UserId, Addr, Port, Oids) when is_integer(Port) andalso is_list(Oids) ->
- gn(UserId, Addr, Port, ?DEFAULT_CONTEXT, Oids);
-
-gn(UserId, Addr, Oids, Timeout)
- when is_list(Oids) andalso is_integer(Timeout) ->
- gn(UserId, Addr, ?DEFAULT_AGENT_PORT, Oids, Timeout).
-
-gn(UserId, Addr, Port, CtxName, Oids)
- when is_integer(Port) andalso is_list(CtxName) andalso is_list(Oids) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- sync_get_next(UserId, TargetName, CtxName, Oids);
- Error ->
- Error
- end;
-
-gn(UserId, Addr, Port, Oids, Timeout)
- when is_integer(Port) andalso is_list(Oids) andalso is_integer(Timeout) ->
- gn(UserId, Addr, Port, ?DEFAULT_CONTEXT, Oids, Timeout);
-gn(UserId, Addr, CtxName, Oids, Timeout)
- when is_list(CtxName) andalso is_list(Oids) andalso is_integer(Timeout) ->
- gn(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, Oids, Timeout).
-
-gn(UserId, Addr, Port, CtxName, Oids, Timeout) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- sync_get_next(UserId, TargetName, CtxName, Oids, Timeout);
- Error ->
- Error
- end.
-
-gn(UserId, Addr, Port, CtxName, Oids, Timeout, ExtraInfo) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- sync_get_next(UserId, TargetName, CtxName, Oids, Timeout, ExtraInfo);
- Error ->
- Error
- end.
-%% </DEPRECATED>
-
-
-
%% --- asynchroneous get_next-request ---
%%
@@ -801,56 +584,6 @@ async_get_next(UserId, TargetName, Context, Oids, Expire, ExtraInfo) ->
%% </BACKWARD-COMPAT>
-%% <DEPRECATED>
-agn(UserId, Addr, Oids) ->
- agn(UserId, Addr, ?DEFAULT_AGENT_PORT, Oids).
-
-agn(UserId, Addr, CtxName, Oids) when is_list(CtxName) andalso is_list(Oids) ->
- agn(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, Oids);
-
-agn(UserId, Addr, Port, Oids) when is_integer(Port) andalso is_list(Oids) ->
- agn(UserId, Addr, Port, ?DEFAULT_CONTEXT, Oids);
-
-agn(UserId, Addr, Oids, Expire)
- when is_list(Oids) andalso is_integer(Expire) ->
- agn(UserId, Addr, ?DEFAULT_AGENT_PORT, Oids, Expire).
-
-agn(UserId, Addr, Port, CtxName, Oids)
- when is_integer(Port) andalso is_list(CtxName) andalso is_list(Oids) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- async_get_next(UserId, TargetName, CtxName, Oids);
- Error ->
- Error
- end;
-
-agn(UserId, Addr, Port, Oids, Expire)
- when is_integer(Port) andalso is_list(Oids) andalso is_integer(Expire) ->
- agn(UserId, Addr, Port, ?DEFAULT_CONTEXT, Oids, Expire);
-agn(UserId, Addr, CtxName, Oids, Expire)
- when is_list(CtxName) andalso is_list(CtxName) andalso is_integer(Expire) ->
- agn(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, Oids, Expire).
-
-agn(UserId, Addr, Port, CtxName, Oids, Expire) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- async_get_next(UserId, TargetName, CtxName, Oids, Expire);
- Error ->
- Error
- end.
-
-agn(UserId, Addr, Port, CtxName, Oids, Expire, ExtraInfo) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- async_get_next(UserId, TargetName, CtxName, Oids, Expire,
- ExtraInfo);
- Error ->
- Error
- end.
-%% </DEPRECATED>
-
-
-
%% --- synchroneous set-request ---
%%
@@ -884,64 +617,6 @@ sync_set(UserId, TargetName, Context, VarsAndVals, Timeout, ExtraInfo) ->
%% </BACKWARD-COMPAT>
-%% <DEPRECATED>
-s(UserId, Addr, VarsAndVals) ->
- s(UserId, Addr, ?DEFAULT_AGENT_PORT, VarsAndVals).
-
-s(UserId, Addr, Port, VarsAndVals)
- when is_integer(Port) andalso is_list(VarsAndVals) ->
- s(UserId, Addr, Port, ?DEFAULT_CONTEXT, VarsAndVals);
-
-s(UserId, Addr, CtxName, VarsAndVals)
- when is_list(CtxName) andalso is_list(VarsAndVals) ->
- s(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, VarsAndVals);
-
-s(UserId, Addr, VarsAndVals, Timeout)
- when is_list(VarsAndVals) andalso is_integer(Timeout) ->
- s(UserId, Addr, ?DEFAULT_AGENT_PORT, VarsAndVals, Timeout).
-
-s(UserId, Addr, Port, CtxName, VarsAndVals)
- when is_integer(Port) andalso
- is_list(CtxName) andalso
- is_list(VarsAndVals) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- sync_set(UserId, TargetName, CtxName, VarsAndVals);
- Error ->
- Error
- end;
-
-s(UserId, Addr, Port, VarsAndVals, Timeout)
- when is_integer(Port) andalso
- is_list(VarsAndVals) andalso
- is_integer(Timeout) ->
- s(UserId, Addr, Port, ?DEFAULT_CONTEXT, VarsAndVals, Timeout);
-
-s(UserId, Addr, CtxName, VarsAndVals, Timeout)
- when is_list(CtxName) andalso
- is_list(VarsAndVals) andalso
- is_integer(Timeout) ->
- s(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, VarsAndVals, Timeout).
-
-s(UserId, Addr, Port, CtxName, VarsAndVals, Timeout) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- sync_set(UserId, TargetName, CtxName, VarsAndVals, Timeout);
- Error ->
- Error
- end.
-
-s(UserId, Addr, Port, CtxName, VarsAndVals, Timeout, ExtraInfo) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- sync_set(UserId, TargetName, CtxName, VarsAndVals, Timeout, ExtraInfo);
- Error ->
- Error
- end.
-%% </DEPRECATED>
-
-
-
%% --- asynchroneous set-request ---
%%
@@ -975,63 +650,6 @@ async_set(UserId, TargetName, Context, VarsAndVals, Expire, ExtraInfo) ->
%% </BACKWARD-COMPAT>
-%% <DEPRECATED>
-as(UserId, Addr, VarsAndVals) ->
- as(UserId, Addr, ?DEFAULT_AGENT_PORT, VarsAndVals).
-
-as(UserId, Addr, Port, VarsAndVals)
- when is_integer(Port) andalso is_list(VarsAndVals) ->
- as(UserId, Addr, Port, ?DEFAULT_CONTEXT, VarsAndVals);
-
-as(UserId, Addr, CtxName, VarsAndVals)
- when is_list(CtxName) andalso is_list(VarsAndVals) ->
- as(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, VarsAndVals);
-
-as(UserId, Addr, VarsAndVals, Expire)
- when is_list(VarsAndVals) andalso is_integer(Expire) ->
- as(UserId, Addr, ?DEFAULT_AGENT_PORT, VarsAndVals, Expire).
-
-as(UserId, Addr, Port, CtxName, VarsAndVals)
- when is_integer(Port) andalso
- is_list(CtxName) andalso
- is_list(VarsAndVals) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- async_set(UserId, TargetName, CtxName, VarsAndVals);
- Error ->
- Error
- end;
-
-as(UserId, Addr, Port, VarsAndVals, Expire)
- when is_integer(Port) andalso
- is_list(VarsAndVals) andalso
- is_integer(Expire) ->
- as(UserId, Addr, Port, ?DEFAULT_CONTEXT, VarsAndVals, Expire);
-
-as(UserId, Addr, CtxName, VarsAndVals, Expire)
- when is_list(CtxName) andalso
- is_list(VarsAndVals) andalso
- is_integer(Expire) ->
- as(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, VarsAndVals, Expire).
-
-as(UserId, Addr, Port, CtxName, VarsAndVals, Expire) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- async_set(UserId, TargetName, CtxName, VarsAndVals, Expire);
- Error ->
- Error
- end.
-
-as(UserId, Addr, Port, CtxName, VarsAndVals, Expire, ExtraInfo) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- async_set(UserId, TargetName, CtxName, VarsAndVals, Expire, ExtraInfo);
- Error ->
- Error
- end.
-%% </DEPRECATED>
-
-
%% --- synchroneous get-bulk ---
%%
@@ -1091,162 +709,6 @@ sync_get_bulk(UserId, TargetName, NonRep, MaxRep, Context, Oids, Timeout,
%% </BACKWARD-COMPAT>
-%% <DEPRECATED>
-gb(UserId, Addr, NonRep, MaxRep, Oids) ->
- %% p("gb -> entry with"
- %% "~n UserId: ~p"
- %% "~n Addr: ~p"
- %% "~n NonRep: ~p"
- %% "~n MaxRep: ~p"
- %% "~n Oids: ~p",
- %% [UserId, Addr, NonRep, MaxRep, Oids]),
- gb(UserId, Addr, ?DEFAULT_AGENT_PORT, NonRep, MaxRep, Oids).
-
-gb(UserId, Addr, Port, NonRep, MaxRep, Oids)
- when is_integer(Port) andalso
- is_integer(NonRep) andalso
- is_integer(MaxRep) andalso
- is_list(Oids) ->
- %% p("gb -> entry with"
- %% "~n UserId: ~p"
- %% "~n Addr: ~p"
- %% "~n Port: ~p"
- %% "~n NonRep: ~p"
- %% "~n MaxRep: ~p"
- %% "~n Oids: ~p",
- %% [UserId, Addr, Port, NonRep, MaxRep, Oids]),
- gb(UserId, Addr, Port, NonRep, MaxRep, ?DEFAULT_CONTEXT, Oids);
-
-gb(UserId, Addr, NonRep, MaxRep, CtxName, Oids)
- when is_integer(NonRep) andalso
- is_integer(MaxRep) andalso
- is_list(CtxName) andalso
- is_list(Oids) ->
- %% p("gb -> entry with"
- %% "~n UserId: ~p"
- %% "~n Addr: ~p"
- %% "~n NonRep: ~p"
- %% "~n MaxRep: ~p"
- %% "~n CtxName: ~p"
- %% "~n Oids: ~p",
- %% [UserId, Addr, NonRep, MaxRep, CtxName, Oids]),
- gb(UserId, Addr, ?DEFAULT_AGENT_PORT, NonRep, MaxRep, CtxName, Oids);
-
-gb(UserId, Addr, NonRep, MaxRep, Oids, Timeout)
- when is_integer(NonRep) andalso
- is_integer(MaxRep) andalso
- is_list(Oids) andalso
- is_integer(Timeout) ->
- %% p("gb -> entry with"
- %% "~n UserId: ~p"
- %% "~n Addr: ~p"
- %% "~n NonRep: ~p"
- %% "~n MaxRep: ~p"
- %% "~n Oids: ~p"
- %% "~n Timeout: ~p",
- %% [UserId, Addr, NonRep, MaxRep, Oids, Timeout]),
- gb(UserId, Addr, ?DEFAULT_AGENT_PORT, NonRep, MaxRep, Oids, Timeout).
-
-gb(UserId, Addr, Port, NonRep, MaxRep, CtxName, Oids)
- when is_integer(Port) andalso
- is_integer(NonRep) andalso
- is_integer(MaxRep) andalso
- is_list(CtxName) andalso
- is_list(Oids) ->
- %% p("gb -> entry with"
- %% "~n UserId: ~p"
- %% "~n Addr: ~p"
- %% "~n Port: ~p"
- %% "~n NonRep: ~p"
- %% "~n MaxRep: ~p"
- %% "~n CtxName: ~p"
- %% "~n Oids: ~p",
- %% [UserId, Addr, Port, NonRep, MaxRep, CtxName, Oids]),
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- %% p("gb -> TargetName: ~p", [TargetName]),
- sync_get_bulk(UserId, TargetName, NonRep, MaxRep, CtxName, Oids);
- Error ->
- Error
- end;
-
-gb(UserId, Addr, Port, NonRep, MaxRep, Oids, Timeout)
- when is_integer(Port) andalso
- is_integer(NonRep) andalso
- is_integer(MaxRep) andalso
- is_list(Oids) andalso
- is_integer(Timeout) ->
- %% p("gb -> entry with"
- %% "~n UserId: ~p"
- %% "~n Addr: ~p"
- %% "~n Port: ~p"
- %% "~n NonRep: ~p"
- %% "~n MaxRep: ~p"
- %% "~n Oids: ~p"
- %% "~n Timeout: ~p",
- %% [UserId, Addr, Port, NonRep, MaxRep, Oids, Timeout]),
- gb(UserId, Addr, Port, NonRep, MaxRep, ?DEFAULT_CONTEXT, Oids, Timeout);
-
-gb(UserId, Addr, NonRep, MaxRep, CtxName, Oids, Timeout)
- when is_integer(NonRep) andalso
- is_integer(MaxRep) andalso
- is_list(CtxName) andalso
- is_list(Oids) andalso
- is_integer(Timeout) ->
- %% p("gb -> entry with"
- %% "~n UserId: ~p"
- %% "~n Addr: ~p"
- %% "~n NonRep: ~p"
- %% "~n MaxRep: ~p"
- %% "~n CtxName: ~p"
- %% "~n Oids: ~p"
- %% "~n Timeout: ~p",
- %% [UserId, Addr, NonRep, MaxRep, CtxName, Oids, Timeout]),
- gb(UserId, Addr, ?DEFAULT_AGENT_PORT, NonRep, MaxRep, CtxName, Oids,
- Timeout).
-
-gb(UserId, Addr, Port, NonRep, MaxRep, CtxName, Oids, Timeout) ->
- %% p("gb -> entry with"
- %% "~n UserId: ~p"
- %% "~n Addr: ~p"
- %% "~n Port: ~p"
- %% "~n NonRep: ~p"
- %% "~n MaxRep: ~p"
- %% "~n CtxName: ~p"
- %% "~n Oids: ~p"
- %% "~n Timeout: ~p",
- %% [UserId, Addr, Port, NonRep, MaxRep, CtxName, Oids, Timeout]),
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- sync_get_bulk(UserId, TargetName,
- NonRep, MaxRep, CtxName, Oids, Timeout);
- Error ->
- Error
- end.
-
-gb(UserId, Addr, Port, NonRep, MaxRep, CtxName, Oids, Timeout, ExtraInfo) ->
- %% p("gb -> entry with"
- %% "~n UserId: ~p"
- %% "~n Addr: ~p"
- %% "~n Port: ~p"
- %% "~n NonRep: ~p"
- %% "~n MaxRep: ~p"
- %% "~n CtxName: ~p"
- %% "~n Oids: ~p"
- %% "~n Timeout: ~p"
- %% "~n ExtraInfo: ~p",
- %% [UserId, Addr, Port, NonRep, MaxRep, CtxName, Oids, Timeout, ExtraInfo]),
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- sync_get_bulk(UserId, TargetName,
- NonRep, MaxRep, CtxName, Oids, Timeout, ExtraInfo);
- Error ->
- Error
- end.
-%% </DEPRECATED>
-
-
-
%% --- asynchroneous get-bulk ---
%%
@@ -1291,81 +753,6 @@ async_get_bulk(UserId, TargetName, NonRep, MaxRep, Context, Oids, Expire,
%% </BACKWARD-COMPAT>
-%% <DEPRECATED>
-agb(UserId, Addr, NonRep, MaxRep, Oids) ->
- agb(UserId, Addr, ?DEFAULT_AGENT_PORT, NonRep, MaxRep, Oids).
-
-agb(UserId, Addr, Port, NonRep, MaxRep, Oids)
- when is_integer(Port) andalso
- is_integer(NonRep) andalso
- is_integer(MaxRep) andalso
- is_list(Oids) ->
- agb(UserId, Addr, Port, NonRep, MaxRep, ?DEFAULT_CONTEXT, Oids);
-
-agb(UserId, Addr, NonRep, MaxRep, CtxName, Oids)
- when is_integer(NonRep) andalso
- is_integer(MaxRep) andalso
- is_list(CtxName) andalso
- is_list(Oids) ->
- agb(UserId, Addr, ?DEFAULT_AGENT_PORT, NonRep, MaxRep, CtxName, Oids);
-
-agb(UserId, Addr, NonRep, MaxRep, Oids, Expire)
- when is_integer(NonRep) andalso
- is_integer(MaxRep) andalso
- is_list(Oids) andalso
- is_integer(Expire) ->
- agb(UserId, Addr, ?DEFAULT_AGENT_PORT, NonRep, MaxRep, Oids, Expire).
-
-agb(UserId, Addr, Port, NonRep, MaxRep, CtxName, Oids)
- when is_integer(Port) andalso
- is_integer(NonRep) andalso
- is_integer(MaxRep),
- is_list(CtxName) andalso
- is_list(Oids) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- async_get_bulk(UserId, TargetName,
- NonRep, MaxRep, CtxName, Oids);
- Error ->
- Error
- end;
-
-agb(UserId, Addr, Port, NonRep, MaxRep, Oids, Expire)
- when is_integer(Port) andalso
- is_integer(NonRep) andalso
- is_integer(MaxRep) andalso
- is_list(Oids) andalso
- is_integer(Expire) ->
- agb(UserId, Addr, Port, NonRep, MaxRep, ?DEFAULT_CONTEXT, Oids, Expire);
-
-agb(UserId, Addr, NonRep, MaxRep, CtxName, Oids, Expire)
- when is_integer(NonRep) andalso
- is_integer(MaxRep) andalso
- is_list(CtxName) andalso
- is_list(Oids) andalso
- is_integer(Expire) ->
- agb(UserId, Addr, ?DEFAULT_AGENT_PORT, NonRep, MaxRep, CtxName, Oids).
-
-agb(UserId, Addr, Port, NonRep, MaxRep, CtxName, Oids, Expire) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- async_get_bulk(UserId, TargetName,
- NonRep, MaxRep, CtxName, Oids, Expire);
- Error ->
- Error
- end.
-
-agb(UserId, Addr, Port, NonRep, MaxRep, CtxName, Oids, Expire, ExtraInfo) ->
- case target_name(Addr, Port) of
- {ok, TargetName} ->
- async_get_bulk(UserId, TargetName,
- NonRep, MaxRep, CtxName, Oids, Expire,
- ExtraInfo);
- Error ->
- Error
- end.
-%% </DEPRECATED>
-
cancel_async_request(UserId, ReqId) ->
snmpm_server:cancel_async_request(UserId, ReqId).
@@ -1457,7 +844,7 @@ sys_up_time() ->
format_reason(Reason) ->
format_reason("", Reason).
-format_reason(Prefix, Reason) when is_integer(Prefix) and (Prefix >= 0) ->
+format_reason(Prefix, Reason) when is_integer(Prefix) andalso (Prefix >= 0) ->
format_reason(lists:duplicate(Prefix, $ ), Reason);
format_reason(Prefix, Reason) when is_list(Prefix) ->
case (catch do_format_reason(Prefix, Reason)) of
@@ -1691,6 +1078,9 @@ format_vb_value(Prefix, _Type, Val) ->
%% --- Internal utility functions ---
%%
+target_name(Addr) ->
+ target_name(Addr, ?DEFAULT_AGENT_PORT).
+
target_name(Addr, Port) ->
snmpm_config:agent_info(Addr, Port, target_name).
diff --git a/lib/snmp/src/manager/snmpm_conf.erl b/lib/snmp/src/manager/snmpm_conf.erl
index e50508c489..03dbd028f7 100644
--- a/lib/snmp/src/manager/snmpm_conf.erl
+++ b/lib/snmp/src/manager/snmpm_conf.erl
@@ -1,7 +1,8 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -365,7 +366,7 @@ do_write_usm_conf(Fd,
do_write_usm_conf(Fd,
{EngineID, UserName, SecName,
AuthP, AuthKey, PrivP, PrivKey}) ->
- io:format(Fd, "{\"~s\", \"~s\", \"~s\", �~w, ~w, ~w, ~w}.~n",
+ io:format(Fd, "{\"~s\", \"~s\", \"~s\", í~w, ~w, ~w, ~w}.~n",
[EngineID, UserName, SecName, AuthP, AuthKey, PrivP, PrivKey]);
do_write_usm_conf(_Fd, Crap) ->
error({bad_usm_conf, Crap}).
diff --git a/lib/snmp/src/manager/snmpm_mpd.erl b/lib/snmp/src/manager/snmpm_mpd.erl
index d7148bb4a4..953c94ab54 100644
--- a/lib/snmp/src/manager/snmpm_mpd.erl
+++ b/lib/snmp/src/manager/snmpm_mpd.erl
@@ -591,8 +591,8 @@ sec_engine_id(TargetName) ->
%% BMK BMK BMK
-%% Denna verkar v�ldigt lik generate_v1_v2c_response_msg!
-%% Gemensam? Borde det finnas olikheter?
+%% This one looks very similar to lik generate_v1_v2c_response_msg!
+%% Common/shared? Should there be differences?
%%
generate_v1_v2c_msg(Vsn, Pdu, Community, Log) ->
?vdebug("generate_v1_v2c_msg -> encode pdu", []),
diff --git a/lib/snmp/src/manager/snmpm_server.erl b/lib/snmp/src/manager/snmpm_server.erl
index 484954addb..61d22362cc 100644
--- a/lib/snmp/src/manager/snmpm_server.erl
+++ b/lib/snmp/src/manager/snmpm_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -3163,17 +3163,16 @@ request_id() ->
%%----------------------------------------------------------------------
agent_data(TargetName, SendOpts) ->
- case snmpm_config:agent_info(TargetName, all) of
- {ok, Info} ->
- Version = agent_data_item(version, Info),
+ case snmpm_config:agent_info(TargetName, version) of
+ {ok, Version} ->
MsgData =
case Version of
v3 ->
- DefSecModel = agent_data_item(sec_model, Info),
- DefSecName = agent_data_item(sec_name, Info),
- DefSecLevel = agent_data_item(sec_level, Info),
+ DefSecModel = agent_data_item(sec_model, TargetName),
+ DefSecName = agent_data_item(sec_name, TargetName),
+ DefSecLevel = agent_data_item(sec_level, TargetName),
- EngineId = agent_data_item(engine_id, Info),
+ EngineId = agent_data_item(engine_id, TargetName),
CtxName = agent_data_item(context,
SendOpts,
?DEFAULT_CONTEXT),
@@ -3191,8 +3190,8 @@ agent_data(TargetName, SendOpts) ->
{SecModel, SecName, mk_sec_level_flag(SecLevel),
EngineId, CtxName, TargetName};
_ ->
- DefComm = agent_data_item(community, Info),
- DefSecModel = agent_data_item(sec_model, Info),
+ DefComm = agent_data_item(community, TargetName),
+ DefSecModel = agent_data_item(sec_model, TargetName),
Comm = agent_data_item(community,
SendOpts,
@@ -3203,21 +3202,21 @@ agent_data(TargetName, SendOpts) ->
{Comm, SecModel}
end,
- Domain = agent_data_item(tdomain, Info),
- Addr = agent_data_item(address, Info),
- Port = agent_data_item(port, Info),
- RegType = agent_data_item(reg_type, Info),
+ Domain = agent_data_item(tdomain, TargetName),
+ Addr = agent_data_item(address, TargetName),
+ Port = agent_data_item(port, TargetName),
+ RegType = agent_data_item(reg_type, TargetName),
{ok, RegType, Domain, Addr, Port, version(Version), MsgData};
Error ->
Error
end.
-agent_data_item(Item, Info) ->
- case lists:keysearch(Item, 1, Info) of
- {value, {_, Val}} ->
+agent_data_item(Item, TargetName) ->
+ case snmpm_config:agent_info(TargetName, Item) of
+ {ok, Val} ->
Val;
- false ->
- throw({error, {not_found, Item, Info}})
+ {error, not_found} ->
+ throw({error, {not_found, Item, TargetName}})
end.
agent_data_item(Item, Info, Default) ->
diff --git a/lib/snmp/src/manager/snmpm_user_default.erl b/lib/snmp/src/manager/snmpm_user_default.erl
index d90fc3f258..015198cb76 100644
--- a/lib/snmp/src/manager/snmpm_user_default.erl
+++ b/lib/snmp/src/manager/snmpm_user_default.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -62,7 +62,7 @@ handle_trap(TargetName, SnmpTrap, UserData) ->
"~n SnmpTrap: ~p"
"~n UserData: ~p",
[TargetName, SnmpTrap, UserData]),
- ok.
+ ignore.
handle_inform(TargetName, SnmpInform, UserData) ->
@@ -80,7 +80,7 @@ handle_report(TargetName, SnmpReport, UserData) ->
"~n SnmpReport: ~p"
"~n UserData: ~p",
[TargetName, SnmpReport, UserData]),
- ok.
+ ignore.
info(F, A) ->
diff --git a/lib/snmp/test/snmp_agent_test.erl b/lib/snmp/test/snmp_agent_test.erl
index bfe14bc080..09e1eb25a9 100644
--- a/lib/snmp/test/snmp_agent_test.erl
+++ b/lib/snmp/test/snmp_agent_test.erl
@@ -1,3 +1,4 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
@@ -5752,14 +5753,14 @@ otp_4394_config(AgentConfDir, MgrDir, Ip0) ->
?line write_community_conf(AgentConfDir, [C1, C2]),
?line update_vacm(Vsn, AgentConfDir),
Ta1 = {"shelob v1",
- [134,138,177,177], 5000, 1500, 3, %% Anv�nd Ip och modda
+ [134,138,177,177], 5000, 1500, 3, %% Use Ip and modify
"pc1",
"target_v1", "",
%% [255,255,255,255,0,0],
[],
2048},
Ta2 = {"bifur v1",
- [134,138,177,75], 5000, 1500, 3, %% Anv�nd Ip
+ [134,138,177,75], 5000, 1500, 3, %% Use Ip
"pc2",
"target_v1", "",
%% [255,255,255,255,0,0],
diff --git a/lib/snmp/test/snmp_log_test.erl b/lib/snmp/test/snmp_log_test.erl
index aeac4d1f71..e9345b44cc 100644
--- a/lib/snmp/test/snmp_log_test.erl
+++ b/lib/snmp/test/snmp_log_test.erl
@@ -375,9 +375,9 @@ log_to_io1(Config) when is_list(Config) ->
%%======================================================================
-%% Starta en logger-process som med ett visst intervall loggar
-%% meddelanden. Starta en reader-process som vid ett viss tillf�lle
-%% l�ser fr�n loggen.
+%% Start a logger-process that logs messages with a certain interval.
+%% Start a reader-process that reads messages from the log at a certain
+%% point of time.
log_to_io2(suite) -> [];
log_to_io2(doc) -> "Log to io from a different process than which "
@@ -578,9 +578,9 @@ log_to_txt(Name, SeqNoGen, Config) when is_list(Config) ->
%%======================================================================
-%% Starta en logger-process som med ett visst intervall loggar
-%% meddelanden. Starta en reader-process som vid ett viss tillf�lle
-%% l�ser fr�n loggen.
+%% Start a logger-process that logs messages with a certain interval.
+%% Start a reader-process that reads messages from the log at a certain
+%% point of time.
%%
%% Test: ts:run(snmp, snmp_log_test, log_to_txt2, [batch]).
diff --git a/lib/snmp/test/snmp_manager_test.erl b/lib/snmp/test/snmp_manager_test.erl
index c374a2f0a6..dedbae5ce4 100644
--- a/lib/snmp/test/snmp_manager_test.erl
+++ b/lib/snmp/test/snmp_manager_test.erl
@@ -174,7 +174,26 @@ end_per_suite(Config) when is_list(Config) ->
init_per_testcase(Case, Config) when is_list(Config) ->
io:format(user, "~n~n*** INIT ~w:~w ***~n~n", [?MODULE,Case]),
- init_per_testcase2(Case, Config).
+ %% This version of the API, based on Addr and Port, has been deprecated
+ DeprecatedApiCases =
+ [
+ simple_sync_get1,
+ simple_async_get1,
+ simple_sync_get_next1,
+ simple_async_get_next1,
+ simple_sync_set1,
+ simple_async_set1,
+ simple_sync_get_bulk1,
+ simple_async_get_bulk1,
+ misc_async1
+ ],
+ case lists:member(Case, DeprecatedApiCases) of
+ true ->
+ %% ?SKIP(api_no_longer_supported);
+ {skip, api_no_longer_supported};
+ false ->
+ init_per_testcase2(Case, Config)
+ end.
init_per_testcase2(Case, Config) ->
?DBG("init_per_testcase2 -> ~p", [erlang:nodes()]),
@@ -226,18 +245,6 @@ init_per_testcase2(Case, Config) ->
Conf2.
init_per_testcase3(Case, Config) ->
- ApiCases01 =
- [
- simple_sync_get1,
- simple_async_get1,
- simple_sync_get_next1,
- simple_async_get_next1,
- simple_sync_set1,
- simple_async_set1,
- simple_sync_get_bulk1,
- simple_async_get_bulk1,
- misc_async1
- ],
ApiCases02 =
[
simple_sync_get2,
@@ -273,7 +280,6 @@ init_per_testcase3(Case, Config) ->
inform_swarm,
report
] ++
- ApiCases01 ++
ApiCases02 ++
ApiCases03,
case lists:member(Case, Cases) of
@@ -319,18 +325,6 @@ end_per_testcase(Case, Config) when is_list(Config) ->
Conf2.
end_per_testcase2(Case, Config) ->
- ApiCases01 =
- [
- simple_sync_get1,
- simple_async_get1,
- simple_sync_get_next1,
- simple_async_get_next1,
- simple_sync_set1,
- simple_async_set1,
- simple_sync_get_bulk1,
- simple_async_get_bulk1,
- misc_async1
- ],
ApiCases02 =
[
simple_sync_get2,
@@ -366,7 +360,6 @@ end_per_testcase2(Case, Config) ->
inform_swarm,
report
] ++
- ApiCases01 ++
ApiCases02 ++
ApiCases03,
case lists:member(Case, Cases) of
@@ -1596,12 +1589,14 @@ register_agent3(Config) when is_list(Config) ->
simple_sync_get1(doc) -> ["Simple sync get-request - Old style (Addr & Port)"];
simple_sync_get1(suite) -> [];
simple_sync_get1(Config) when is_list(Config) ->
+ ?SKIP(api_no_longer_supported),
+
process_flag(trap_exit, true),
put(tname, ssg1),
p("starting with Config: ~p~n", [Config]),
Node = ?config(manager_node, Config),
- Addr = ?config(ip, Config),
+ Addr = ?config(manager_agent_target_name, Config),
Port = ?AGENT_PORT,
p("issue get-request without loading the mib"),
@@ -1757,6 +1752,8 @@ simple_async_get1(doc) ->
["Simple (async) get-request - Old style (Addr & Port)"];
simple_async_get1(suite) -> [];
simple_async_get1(Config) when is_list(Config) ->
+ ?SKIP(api_no_longer_supported),
+
process_flag(trap_exit, true),
put(tname, sag1),
p("starting with Config: ~p~n", [Config]),
@@ -1972,6 +1969,8 @@ simple_sync_get_next1(doc) -> ["Simple (sync) get_next-request - "
"Old style (Addr & Port)"];
simple_sync_get_next1(suite) -> [];
simple_sync_get_next1(Config) when is_list(Config) ->
+ ?SKIP(api_no_longer_supported),
+
process_flag(trap_exit, true),
put(tname, ssgn1),
p("starting with Config: ~p~n", [Config]),
@@ -2264,6 +2263,8 @@ simple_async_get_next1(doc) -> ["Simple (async) get_next-request - "
"Old style (Addr & Port)"];
simple_async_get_next1(suite) -> [];
simple_async_get_next1(Config) when is_list(Config) ->
+ ?SKIP(api_no_longer_supported),
+
process_flag(trap_exit, true),
put(tname, ssgn1),
p("starting with Config: ~p~n", [Config]),
@@ -2516,6 +2517,8 @@ simple_sync_set1(doc) -> ["Simple (sync) set-request - "
"Old style (Addr & Port)"];
simple_sync_set1(suite) -> [];
simple_sync_set1(Config) when is_list(Config) ->
+ ?SKIP(api_no_longer_supported),
+
process_flag(trap_exit, true),
put(tname, sss1),
p("starting with Config: ~p~n", [Config]),
@@ -2686,6 +2689,8 @@ simple_async_set1(doc) -> ["Simple (async) set-request - "
"Old style (Addr & Port)"];
simple_async_set1(suite) -> [];
simple_async_set1(Config) when is_list(Config) ->
+ ?SKIP(api_no_longer_supported),
+
process_flag(trap_exit, true),
put(tname, sas1),
p("starting with Config: ~p~n", [Config]),
@@ -2896,6 +2901,8 @@ simple_sync_get_bulk1(doc) -> ["Simple (sync) get_bulk-request - "
"Old style (Addr & Port)"];
simple_sync_get_bulk1(suite) -> [];
simple_sync_get_bulk1(Config) when is_list(Config) ->
+ ?SKIP(api_no_longer_supported),
+
process_flag(trap_exit, true),
put(tname, ssgb1),
p("starting with Config: ~p~n", [Config]),
@@ -3261,6 +3268,8 @@ simple_async_get_bulk1(doc) -> ["Simple (async) get_bulk-request - "
"Old style (Addr & Port)"];
simple_async_get_bulk1(suite) -> [];
simple_async_get_bulk1(Config) when is_list(Config) ->
+ ?SKIP(api_no_longer_supported),
+
process_flag(trap_exit, true),
put(tname, sagb1),
p("starting with Config: ~p~n", [Config]),
@@ -3605,6 +3614,8 @@ misc_async1(doc) -> ["Misc (async) request(s) - "
"Old style (Addr & Port)"];
misc_async1(suite) -> [];
misc_async1(Config) when is_list(Config) ->
+ ?SKIP(api_no_longer_supported),
+
process_flag(trap_exit, true),
put(tname, ms1),
p("starting with Config: ~p~n", [Config]),
@@ -5591,29 +5602,35 @@ fin_mgr_user(Conf) ->
init_mgr_user_data1(Conf) ->
Node = ?config(manager_node, Conf),
- Addr = ?config(ip, Conf),
- Port = ?AGENT_PORT,
- ?line ok = mgr_user_register_agent(Node, Addr, Port),
+ TargetName = ?config(manager_agent_target_name, Conf),
+ Addr = ?config(ip, Conf),
+ Port = ?AGENT_PORT,
+ ?line ok = mgr_user_register_agent(Node, TargetName,
+ [{address, Addr},
+ {port, Port},
+ {engine_id, "agentEngine"}]),
Agents = mgr_user_which_own_agents(Node),
?DBG("Own agents: ~p", [Agents]),
- ?line {ok, DefAgentConf} = mgr_user_agent_info(Node, Addr, Port, all),
+ ?line {ok, DefAgentConf} = mgr_user_agent_info(Node, TargetName, all),
?DBG("Default agent config: ~n~p", [DefAgentConf]),
- ?line ok = mgr_user_update_agent_info(Node, Addr, Port,
+ ?line ok = mgr_user_update_agent_info(Node, TargetName,
community, "all-rights"),
- ?line ok = mgr_user_update_agent_info(Node, Addr, Port,
+ ?line ok = mgr_user_update_agent_info(Node, TargetName,
sec_name, "all-rights"),
- ?line ok = mgr_user_update_agent_info(Node, Addr, Port,
+ ?line ok = mgr_user_update_agent_info(Node, TargetName,
engine_id, "agentEngine"),
- ?line ok = mgr_user_update_agent_info(Node, Addr, Port,
+ ?line ok = mgr_user_update_agent_info(Node, TargetName,
max_message_size, 1024),
- ?line {ok, AgentConf} = mgr_user_agent_info(Node, Addr, Port, all),
+ ?line {ok, AgentConf} = mgr_user_agent_info(Node, TargetName, all),
?DBG("Updated agent config: ~n~p", [AgentConf]),
Conf.
init_mgr_user_data2(Conf) ->
+ ?DBG("init_mgr_user_data2 -> entry with"
+ "~n Conf: ~p", [Conf]),
Node = ?config(manager_node, Conf),
TargetName = ?config(manager_agent_target_name, Conf),
Addr = ?config(ip, Conf),
@@ -5641,9 +5658,8 @@ init_mgr_user_data2(Conf) ->
fin_mgr_user_data1(Conf) ->
Node = ?config(manager_node, Conf),
- Addr = ?config(ip, Conf),
- Port = ?AGENT_PORT,
- mgr_user_unregister_agent(Node, Addr, Port),
+ TargetName = ?config(manager_agent_target_name, Conf),
+ mgr_user_unregister_agent(Node, TargetName),
mgr_user_which_own_agents(Node),
Conf.
@@ -5670,33 +5686,41 @@ mgr_user_stop(Node) ->
%% mgr_user_register_agent(Node, Addr, ?AGENT_PORT, []).
mgr_user_register_agent(Node, TargetName, Conf)
when is_list(TargetName) andalso is_list(Conf) ->
- rcall(Node, snmp_manager_user, register_agent, [TargetName, Conf]);
-mgr_user_register_agent(Node, Addr, Port) ->
- mgr_user_register_agent(Node, Addr, Port, []).
-mgr_user_register_agent(Node, Addr, Port, Conf) ->
- rcall(Node, snmp_manager_user, register_agent, [Addr, Port, Conf]).
+ rcall(Node, snmp_manager_user, register_agent, [TargetName, Conf]).
+%% <REMOVED-IN-R16B>
+%% mgr_user_register_agent(Node, Addr, Port) ->
+%% mgr_user_register_agent(Node, Addr, Port, []).
+%% mgr_user_register_agent(Node, Addr, Port, Conf) ->
+%% rcall(Node, snmp_manager_user, register_agent, [Addr, Port, Conf]).
+%% </REMOVED-IN-R16B>
%% mgr_user_unregister_agent(Node) ->
%% mgr_user_unregister_agent(Node, ?LOCALHOST(), ?AGENT_PORT).
-mgr_user_unregister_agent(Node, Addr_or_TargetName) ->
- rcall(Node, snmp_manager_user, unregister_agent, [Addr_or_TargetName]).
-mgr_user_unregister_agent(Node, Addr, Port) ->
- rcall(Node, snmp_manager_user, unregister_agent, [Addr, Port]).
-
-mgr_user_agent_info(Node, Addr_or_TargetName, Item) when is_atom(Item) ->
- rcall(Node, snmp_manager_user, agent_info, [Addr_or_TargetName, Item]).
-mgr_user_agent_info(Node, Addr, Port, Item) when is_atom(Item) ->
- rcall(Node, snmp_manager_user, agent_info, [Addr, Port, Item]).
+mgr_user_unregister_agent(Node, TargetName) when is_list(TargetName) ->
+ rcall(Node, snmp_manager_user, unregister_agent, [TargetName]).
+%% <REMOVED-IN-R16B>
+%% mgr_user_unregister_agent(Node, Addr, Port) ->
+%% rcall(Node, snmp_manager_user, unregister_agent, [Addr, Port]).
+%% </REMOVED-IN-R16B>
+
+mgr_user_agent_info(Node, TargetName, Item)
+ when is_list(TargetName) andalso is_atom(Item) ->
+ rcall(Node, snmp_manager_user, agent_info, [TargetName, Item]).
+%% <REMOVED-IN-R16B>
+%% mgr_user_agent_info(Node, Addr, Port, Item) when is_atom(Item) ->
+%% rcall(Node, snmp_manager_user, agent_info, [Addr, Port, Item]).
+%% </REMOVED-IN-R16B>
%% mgr_user_update_agent_info(Node, Item, Val) when atom(Item) ->
%% mgr_user_update_agent_info(Node, ?LOCALHOST(), ?AGENT_PORT, Item, Val).
-mgr_user_update_agent_info(Node, Addr_or_TargetName, Item, Val)
- when is_atom(Item) ->
- rcall(Node, snmp_manager_user, update_agent_info,
- [Addr_or_TargetName, Item, Val]).
-mgr_user_update_agent_info(Node, Addr, Port, Item, Val) when is_atom(Item) ->
- rcall(Node, snmp_manager_user, update_agent_info,
- [Addr, Port, Item, Val]).
+mgr_user_update_agent_info(Node, TargetName, Item, Val)
+ when is_list(TargetName) andalso is_atom(Item) ->
+ rcall(Node, snmp_manager_user, update_agent_info, [TargetName, Item, Val]).
+%% <REMOVED-IN-R16B>
+%% mgr_user_update_agent_info(Node, Addr, Port, Item, Val) when is_atom(Item) ->
+%% rcall(Node, snmp_manager_user, update_agent_info,
+%% [Addr, Port, Item, Val]).
+%% </REMOVED-IN-R16B>
%% mgr_user_which_all_agents(Node) ->
%% rcall(Node, snmp_manager_user, which_all_agents, []).
@@ -5709,89 +5733,112 @@ mgr_user_load_mib(Node, Mib) ->
%% mgr_user_sync_get(Node, Oids) ->
%% mgr_user_sync_get(Node, ?LOCALHOST(), ?AGENT_PORT, Oids).
-mgr_user_sync_get(Node, Addr_or_TargetName, Oids) ->
- rcall(Node, snmp_manager_user, sync_get, [Addr_or_TargetName, Oids]).
+mgr_user_sync_get(Node, TargetName, Oids) when is_list(TargetName) ->
+ rcall(Node, snmp_manager_user, sync_get, [TargetName, Oids]).
+%% <REMOVED-IN-R16B>
mgr_user_sync_get(Node, Addr, Port, Oids) ->
rcall(Node, snmp_manager_user, sync_get, [Addr, Port, Oids]).
+%% </REMOVED-IN-R16B>
-mgr_user_sync_get2(Node, TargetName, Oids, SendOpts) ->
+mgr_user_sync_get2(Node, TargetName, Oids, SendOpts) when is_list(TargetName) ->
rcall(Node, snmp_manager_user, sync_get2, [TargetName, Oids, SendOpts]).
%% mgr_user_async_get(Node, Oids) ->
%% mgr_user_async_get(Node, ?LOCALHOST(), ?AGENT_PORT, Oids).
-mgr_user_async_get(Node, Addr_or_TargetName, Oids) ->
- rcall(Node, snmp_manager_user, async_get, [Addr_or_TargetName, Oids]).
+mgr_user_async_get(Node, TargetName, Oids) when is_list(TargetName) ->
+ rcall(Node, snmp_manager_user, async_get, [TargetName, Oids]).
+%% <REMOVED-IN-R16B>
mgr_user_async_get(Node, Addr, Port, Oids) ->
rcall(Node, snmp_manager_user, async_get, [Addr, Port, Oids]).
+%% </REMOVED-IN-R16B>
-mgr_user_async_get2(Node, TargetName, Oids, SendOpts) ->
+mgr_user_async_get2(Node, TargetName, Oids, SendOpts)
+ when is_list(TargetName) ->
rcall(Node, snmp_manager_user, async_get2, [TargetName, Oids, SendOpts]).
%% mgr_user_sync_get_next(Node, Oids) ->
%% mgr_user_sync_get_next(Node, ?LOCALHOST(), ?AGENT_PORT, Oids).
-mgr_user_sync_get_next(Node, Addr_or_TargetName, Oids) ->
- rcall(Node, snmp_manager_user, sync_get_next, [Addr_or_TargetName, Oids]).
+mgr_user_sync_get_next(Node, TargetName, Oids) when is_list(TargetName) ->
+ rcall(Node, snmp_manager_user, sync_get_next, [TargetName, Oids]).
+%% <REMOVED-IN-R16B>
mgr_user_sync_get_next(Node, Addr, Port, Oids) ->
rcall(Node, snmp_manager_user, sync_get_next, [Addr, Port, Oids]).
+%% </REMOVED-IN-R16B>
-mgr_user_sync_get_next2(Node, TargetName, Oids, SendOpts) ->
+mgr_user_sync_get_next2(Node, TargetName, Oids, SendOpts)
+ when is_list(TargetName) ->
rcall(Node, snmp_manager_user, sync_get_next2, [TargetName, Oids, SendOpts]).
%% mgr_user_async_get_next(Node, Oids) ->
%% mgr_user_async_get_next(Node, ?LOCALHOST(), ?AGENT_PORT, Oids).
-mgr_user_async_get_next(Node, Addr_or_TargetName, Oids) ->
- rcall(Node, snmp_manager_user, async_get_next, [Addr_or_TargetName, Oids]).
+mgr_user_async_get_next(Node, TargetName, Oids) when is_list(TargetName) ->
+ rcall(Node, snmp_manager_user, async_get_next, [TargetName, Oids]).
+%% <REMOVED-IN-R16B>
mgr_user_async_get_next(Node, Addr, Port, Oids) ->
rcall(Node, snmp_manager_user, async_get_next, [Addr, Port, Oids]).
+%% </REMOVED-IN-R16B>
-mgr_user_async_get_next2(Node, TargetName, Oids, SendOpts) ->
+mgr_user_async_get_next2(Node, TargetName, Oids, SendOpts)
+ when is_list(TargetName) ->
rcall(Node, snmp_manager_user, async_get_next2, [TargetName, Oids, SendOpts]).
%% mgr_user_sync_set(Node, VAV) ->
%% mgr_user_sync_set(Node, ?LOCALHOST(), ?AGENT_PORT, VAV).
-mgr_user_sync_set(Node, Addr_or_TargetName, VAV) ->
- rcall(Node, snmp_manager_user, sync_set, [Addr_or_TargetName, VAV]).
+mgr_user_sync_set(Node, TargetName, VAV) when is_list(TargetName) ->
+ rcall(Node, snmp_manager_user, sync_set, [TargetName, VAV]).
+%% <REMOVED-IN-R16B>
mgr_user_sync_set(Node, Addr, Port, VAV) ->
rcall(Node, snmp_manager_user, sync_set, [Addr, Port, VAV]).
+%% </REMOVED-IN-R16B>
-mgr_user_sync_set2(Node, TargetName, VAV, SendOpts) ->
+mgr_user_sync_set2(Node, TargetName, VAV, SendOpts) when is_list(TargetName) ->
rcall(Node, snmp_manager_user, sync_set2, [TargetName, VAV, SendOpts]).
%% mgr_user_async_set(Node, VAV) ->
%% mgr_user_async_set(Node, ?LOCALHOST(), ?AGENT_PORT, VAV).
-mgr_user_async_set(Node, Addr_or_TargetName, VAV) ->
- rcall(Node, snmp_manager_user, async_set, [Addr_or_TargetName, VAV]).
+mgr_user_async_set(Node, TargetName, VAV) when is_list(TargetName) ->
+ rcall(Node, snmp_manager_user, async_set, [TargetName, VAV]).
+%% <REMOVED-IN-R16B>
mgr_user_async_set(Node, Addr, Port, VAV) ->
rcall(Node, snmp_manager_user, async_set, [Addr, Port, VAV]).
+%% </REMOVED-IN-R16B>
-mgr_user_async_set2(Node, TargetName, VAV, SendOpts) ->
+mgr_user_async_set2(Node, TargetName, VAV, SendOpts) when is_list(TargetName) ->
rcall(Node, snmp_manager_user, async_set2, [TargetName, VAV, SendOpts]).
%% mgr_user_sync_get_bulk(Node, NonRep, MaxRep, Oids) ->
%% mgr_user_sync_get_bulk(Node, ?LOCALHOST(), ?AGENT_PORT,
%% NonRep, MaxRep, Oids).
-mgr_user_sync_get_bulk(Node, Addr_or_TargetName, NonRep, MaxRep, Oids) ->
+mgr_user_sync_get_bulk(Node, TargetName, NonRep, MaxRep, Oids)
+ when is_list(TargetName) ->
rcall(Node, snmp_manager_user, sync_get_bulk,
- [Addr_or_TargetName, NonRep, MaxRep, Oids]).
+ [TargetName, NonRep, MaxRep, Oids]).
+%% <REMOVED-IN-R16B>
mgr_user_sync_get_bulk(Node, Addr, Port, NonRep, MaxRep, Oids) ->
rcall(Node, snmp_manager_user, sync_get_bulk,
[Addr, Port, NonRep, MaxRep, Oids]).
+%% </REMOVED-IN-R16B>
-mgr_user_sync_get_bulk2(Node, TargetName, NonRep, MaxRep, Oids, SendOpts) ->
+mgr_user_sync_get_bulk2(Node, TargetName, NonRep, MaxRep, Oids, SendOpts)
+ when is_list(TargetName) ->
rcall(Node, snmp_manager_user, sync_get_bulk2,
[TargetName, NonRep, MaxRep, Oids, SendOpts]).
%% mgr_user_async_get_bulk(Node, NonRep, MaxRep, Oids) ->
%% mgr_user_async_get_bulk(Node, ?LOCALHOST(), ?AGENT_PORT,
%% NonRep, MaxRep, Oids).
-mgr_user_async_get_bulk(Node, Addr_or_TargetName, NonRep, MaxRep, Oids) ->
+mgr_user_async_get_bulk(Node, TargetName, NonRep, MaxRep, Oids)
+ when is_list(TargetName) ->
rcall(Node, snmp_manager_user, async_get_bulk,
- [Addr_or_TargetName, NonRep, MaxRep, Oids]).
+ [TargetName, NonRep, MaxRep, Oids]).
+%% <REMOVED-IN-R16B>
mgr_user_async_get_bulk(Node, Addr, Port, NonRep, MaxRep, Oids) ->
rcall(Node, snmp_manager_user, async_get_bulk,
[Addr, Port, NonRep, MaxRep, Oids]).
+%% </REMOVED-IN-R16B>
-mgr_user_async_get_bulk2(Node, TargetName, NonRep, MaxRep, Oids, SendOpts) ->
+mgr_user_async_get_bulk2(Node, TargetName, NonRep, MaxRep, Oids, SendOpts)
+ when is_list(TargetName) ->
rcall(Node, snmp_manager_user, async_get_bulk2,
[TargetName, NonRep, MaxRep, Oids, SendOpts]).
diff --git a/lib/snmp/test/snmp_manager_user.erl b/lib/snmp/test/snmp_manager_user.erl
index 1b62b04960..4e789bbaec 100644
--- a/lib/snmp/test/snmp_manager_user.erl
+++ b/lib/snmp/test/snmp_manager_user.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -44,20 +44,20 @@
info/0,
system_info/0,
simulate_crash/1,
- register_agent/2, register_agent/3,
- unregister_agent/1, unregister_agent/2,
- agent_info/2, agent_info/3,
- update_agent_info/3, update_agent_info/4,
+ register_agent/2,
+ unregister_agent/1,
+ agent_info/2,
+ update_agent_info/3,
which_all_agents/0, which_own_agents/0,
load_mib/1, unload_mib/1,
- sync_get/1, sync_get/2, sync_get/3, sync_get2/3,
- async_get/1, async_get/2, async_get/3, async_get2/3,
- sync_get_next/1, sync_get_next/2, sync_get_next/3, sync_get_next2/3,
- async_get_next/1, async_get_next/2, async_get_next/3, async_get_next2/3,
- sync_set/1, sync_set/2, sync_set/3, sync_set2/3,
- async_set/1, async_set/2, async_set/3, async_set2/3,
- sync_get_bulk/3, sync_get_bulk/4, sync_get_bulk/5, sync_get_bulk2/5,
- async_get_bulk/3, async_get_bulk/4, async_get_bulk/5, async_get_bulk2/5,
+ sync_get/1, sync_get/2, sync_get2/3,
+ async_get/1, async_get/2, async_get2/3,
+ sync_get_next/1, sync_get_next/2, sync_get_next2/3,
+ async_get_next/1, async_get_next/2, async_get_next2/3,
+ sync_set/1, sync_set/2, sync_set2/3,
+ async_set/1, async_set/2, async_set2/3,
+ sync_get_bulk/3, sync_get_bulk/4, sync_get_bulk2/5,
+ async_get_bulk/3, async_get_bulk/4, async_get_bulk2/5,
name_to_oid/1, oid_to_name/1,
purify_oid/1
]).
@@ -73,15 +73,11 @@
-export([
handle_error/3,
- handle_agent/4,
+ handle_agent/5,
handle_pdu/4,
handle_trap/3,
handle_inform/3,
- handle_report/3,
- handle_pdu/5, % For backwards compatibillity
- handle_trap/4, % For backwards compatibillity
- handle_inform/4, % For backwards compatibillity
- handle_report/4 % For backwards compatibillity
+ handle_report/3
]).
@@ -126,27 +122,16 @@ simulate_crash(Reason) ->
register_agent(TargetName, Config)
when is_list(TargetName) andalso is_list(Config) ->
- call({register_agent, TargetName, Config});
-register_agent(Addr, Port) ->
- register_agent(Addr, Port, []).
-
-register_agent(Addr, Port, Conf) ->
- call({register_agent, Addr, Port, Conf}).
+ call({register_agent, TargetName, Config}).
unregister_agent(TargetName) ->
call({unregister_agent, TargetName}).
-unregister_agent(Addr, Port) ->
- call({unregister_agent, Addr, Port}).
agent_info(TargetName, Item) ->
call({agent_info, TargetName, Item}).
-agent_info(Addr, Port, Item) ->
- call({agent_info, Addr, Port, Item}).
update_agent_info(TargetName, Item, Val) ->
call({update_agent_info, TargetName, Item, Val}).
-update_agent_info(Addr, Port, Item, Val) ->
- call({update_agent_info, Addr, Port, Item, Val}).
which_all_agents() ->
call(which_all_agents).
@@ -165,11 +150,8 @@ unload_mib(Mib) ->
sync_get(Oids) ->
call({sync_get, Oids}).
-sync_get(Addr_or_TargetName, Oids) ->
- call({sync_get, Addr_or_TargetName, Oids}).
-
-sync_get(Addr, Port, Oids) ->
- call({sync_get, Addr, Port, Oids}).
+sync_get(TargetName, Oids) ->
+ call({sync_get, TargetName, Oids}).
sync_get2(TargetName, Oids, SendOpts) ->
call({sync_get2, TargetName, Oids, SendOpts}).
@@ -180,11 +162,8 @@ sync_get2(TargetName, Oids, SendOpts) ->
async_get(Oids) ->
call({async_get, Oids}).
-async_get(Addr_or_TargetName, Oids) ->
- call({async_get, Addr_or_TargetName, Oids}).
-
-async_get(Addr, Port, Oids) ->
- call({async_get, Addr, Port, Oids}).
+async_get(TargetName, Oids) ->
+ call({async_get, TargetName, Oids}).
async_get2(TargetName, Oids, SendOpts) ->
call({async_get2, TargetName, Oids, SendOpts}).
@@ -194,11 +173,8 @@ async_get2(TargetName, Oids, SendOpts) ->
sync_get_next(Oids) ->
call({sync_get_next, Oids}).
-sync_get_next(Addr_or_TargetName, Oids) ->
- call({sync_get_next, Addr_or_TargetName, Oids}).
-
-sync_get_next(Addr, Port, Oids) ->
- call({sync_get_next, Addr, Port, Oids}).
+sync_get_next(TargetName, Oids) ->
+ call({sync_get_next, TargetName, Oids}).
sync_get_next2(TargetName, Oids, SendOpts) ->
call({sync_get_next2, TargetName, Oids, SendOpts}).
@@ -208,11 +184,8 @@ sync_get_next2(TargetName, Oids, SendOpts) ->
async_get_next(Oids) ->
call({async_get_next, Oids}).
-async_get_next(Addr_or_TargetName, Oids) ->
- call({async_get_next, Addr_or_TargetName, Oids}).
-
-async_get_next(Addr, Port, Oids) ->
- call({async_get_next, Addr, Port, Oids}).
+async_get_next(TargetName, Oids) ->
+ call({async_get_next, TargetName, Oids}).
async_get_next2(TargetName, Oids, SendOpts) ->
call({async_get_next2, TargetName, Oids, SendOpts}).
@@ -222,11 +195,8 @@ async_get_next2(TargetName, Oids, SendOpts) ->
sync_set(VAV) ->
call({sync_set, VAV}).
-sync_set(Addr_or_TargetName, VAV) ->
- call({sync_set, Addr_or_TargetName, VAV}).
-
-sync_set(Addr, Port, VAV) ->
- call({sync_set, Addr, Port, VAV}).
+sync_set(TargetName, VAV) ->
+ call({sync_set, TargetName, VAV}).
sync_set2(TargetName, VAV, SendOpts) ->
call({sync_set2, TargetName, VAV, SendOpts}).
@@ -236,11 +206,8 @@ sync_set2(TargetName, VAV, SendOpts) ->
async_set(VAV) ->
call({async_set, VAV}).
-async_set(Addr_or_TargetName, VAV) ->
- call({async_set, Addr_or_TargetName, VAV}).
-
-async_set(Addr, Port, VAV) ->
- call({async_set, Addr, Port, VAV}).
+async_set(TargetName, VAV) ->
+ call({async_set, TargetName, VAV}).
async_set2(TargetName, VAV, SendOpts) ->
call({async_set2, TargetName, VAV, SendOpts}).
@@ -250,11 +217,8 @@ async_set2(TargetName, VAV, SendOpts) ->
sync_get_bulk(NonRep, MaxRep, Oids) ->
call({sync_get_bulk, NonRep, MaxRep, Oids}).
-sync_get_bulk(Addr_or_TargetName, NonRep, MaxRep, Oids) ->
- call({sync_get_bulk, Addr_or_TargetName, NonRep, MaxRep, Oids}).
-
-sync_get_bulk(Addr, Port, NonRep, MaxRep, Oids) ->
- call({sync_get_bulk, Addr, Port, NonRep, MaxRep, Oids}).
+sync_get_bulk(TargetName, NonRep, MaxRep, Oids) ->
+ call({sync_get_bulk, TargetName, NonRep, MaxRep, Oids}).
sync_get_bulk2(TargetName, NonRep, MaxRep, Oids, SendOpts) ->
call({sync_get_bulk2, TargetName, NonRep, MaxRep, Oids, SendOpts}).
@@ -264,11 +228,8 @@ sync_get_bulk2(TargetName, NonRep, MaxRep, Oids, SendOpts) ->
async_get_bulk(NonRep, MaxRep, Oids) ->
call({async_get_bulk, NonRep, MaxRep, Oids}).
-async_get_bulk(Addr_or_TargetName, NonRep, MaxRep, Oids) ->
- call({async_get_bulk, Addr_or_TargetName, NonRep, MaxRep, Oids}).
-
-async_get_bulk(Addr, Port, NonRep, MaxRep, Oids) ->
- call({async_get_bulk, Addr, Port, NonRep, MaxRep, Oids}).
+async_get_bulk(TargetName, NonRep, MaxRep, Oids) ->
+ call({async_get_bulk, TargetName, NonRep, MaxRep, Oids}).
async_get_bulk2(TargetName, NonRep, MaxRep, Oids, SendOpts) ->
call({async_get_bulk2, TargetName, NonRep, MaxRep, Oids, SendOpts}).
@@ -340,24 +301,12 @@ loop(#state{parent = Parent, id = Id} = S) ->
reply(From, Res, Ref),
loop(S);
- {{register_agent, Addr, Port, Conf}, From, Ref} ->
- d("loop -> received register_agent request"),
- Res = snmpm:register_agent(Id, Addr, Port, Conf),
- reply(From, Res, Ref),
- loop(S);
-
{{unregister_agent, TargetName}, From, Ref} ->
d("loop -> received unregister_agent request"),
Res = snmpm:unregister_agent(Id, TargetName),
reply(From, Res, Ref),
loop(S);
- {{unregister_agent, Addr, Port}, From, Ref} ->
- d("loop -> received unregister_agent request"),
- Res = snmpm:unregister_agent(Id, Addr, Port),
- reply(From, Res, Ref),
- loop(S);
-
{{agent_info, TargetName, Item}, From, Ref} ->
d("loop -> received agent_info request with"
"~n TargetName: ~p"
@@ -368,15 +317,6 @@ loop(#state{parent = Parent, id = Id} = S) ->
reply(From, Res, Ref),
loop(S);
- {{agent_info, Addr, Port, Item}, From, Ref} ->
- d("loop -> received agent_info request with"
- "~n Addr: ~p"
- "~n Port: ~p"
- "~n Item: ~p", [Addr, Port, Item]),
- Res = snmpm:agent_info(Addr, Port, Item),
- reply(From, Res, Ref),
- loop(S);
-
{{update_agent_info, TargetName, Item, Val}, From, Ref} ->
d("loop -> received update_agent_info request with"
"~n TargetName: ~p"
@@ -386,16 +326,6 @@ loop(#state{parent = Parent, id = Id} = S) ->
reply(From, Res, Ref),
loop(S);
- {{update_agent_info, Addr, Port, Item, Val}, From, Ref} ->
- d("loop -> received update_agent_info request with"
- "~n Addr: ~p"
- "~n Port: ~p"
- "~n Item: ~p"
- "~n Val: ~p", [Addr, Port, Item, Val]),
- Res = snmpm:update_agent_info(Id, Addr, Port, Item, Val),
- reply(From, Res, Ref),
- loop(S);
-
{which_all_agents, From, Ref} ->
d("loop -> received which_all_agents request"),
Res = snmpm:which_agents(),
@@ -452,23 +382,6 @@ loop(#state{parent = Parent, id = Id} = S) ->
reply(From, Res, Ref),
loop(S);
- {{sync_get, Addr, Oids}, From, Ref} ->
- d("loop -> received sync_get request with"
- "~n Addr: ~p"
- "~n Oids: ~p", [Addr, Oids]),
- Res = snmpm:g(Id, Addr, Oids),
- reply(From, Res, Ref),
- loop(S);
-
- {{sync_get, Addr, Port, Oids}, From, Ref} ->
- d("loop -> received sync_get request with"
- "~n Addr: ~p"
- "~n Port: ~p"
- "~n Oids: ~p", [Addr, Port, Oids]),
- Res = snmpm:g(Id, Addr, Port, Oids),
- reply(From, Res, Ref),
- loop(S);
-
%%
%% -- (async) get-request --
@@ -500,18 +413,6 @@ loop(#state{parent = Parent, id = Id} = S) ->
reply(From, Res, Ref),
loop(S);
- {{async_get, Addr, Oids}, From, Ref} ->
- d("loop -> received async_get request"),
- Res = snmpm:ag(Id, Addr, Oids),
- reply(From, Res, Ref),
- loop(S);
-
- {{async_get, Addr, Port, Oids}, From, Ref} ->
- d("loop -> received async_get request"),
- Res = snmpm:ag(Id, Addr, Port, Oids),
- reply(From, Res, Ref),
- loop(S);
-
%%
%% -- (sync) get_next-request --
@@ -543,18 +444,6 @@ loop(#state{parent = Parent, id = Id} = S) ->
reply(From, Res, Ref),
loop(S);
- {{sync_get_next, Addr, Oids}, From, Ref} ->
- d("loop -> received sync_get_next request"),
- Res = snmpm:gn(Id, Addr, Oids),
- reply(From, Res, Ref),
- loop(S);
-
- {{sync_get_next, Addr, Port, Oids}, From, Ref} ->
- d("loop -> received sync_get_next request"),
- Res = snmpm:gn(Id, Addr, Port, Oids),
- reply(From, Res, Ref),
- loop(S);
-
%%
%% -- (async) get_next-request --
@@ -586,18 +475,6 @@ loop(#state{parent = Parent, id = Id} = S) ->
reply(From, Res, Ref),
loop(S);
- {{async_get_next, Addr, Oids}, From, Ref} ->
- d("loop -> received async_get_next request"),
- Res = snmpm:agn(Id, Addr, Oids),
- reply(From, Res, Ref),
- loop(S);
-
- {{async_get_next, Addr, Port, Oids}, From, Ref} ->
- d("loop -> received async_get_next request"),
- Res = snmpm:agn(Id, Addr, Port, Oids),
- reply(From, Res, Ref),
- loop(S);
-
%%
%% -- (sync) set-request --
@@ -626,18 +503,6 @@ loop(#state{parent = Parent, id = Id} = S) ->
reply(From, Res, Ref),
loop(S);
- {{sync_set, Addr, VAV}, From, Ref} ->
- d("loop -> received sync_set request"),
- Res = snmpm:s(Id, Addr, VAV),
- reply(From, Res, Ref),
- loop(S);
-
- {{sync_set, Addr, Port, VAV}, From, Ref} ->
- d("loop -> received sync_set request"),
- Res = snmpm:s(Id, Addr, Port, VAV),
- reply(From, Res, Ref),
- loop(S);
-
%%
%% -- (async) set-request --
@@ -666,18 +531,6 @@ loop(#state{parent = Parent, id = Id} = S) ->
reply(From, Res, Ref),
loop(S);
- {{async_set, Addr, VAV}, From, Ref} ->
- d("loop -> received async_set request"),
- Res = snmpm:as(Id, Addr, VAV),
- reply(From, Res, Ref),
- loop(S);
-
- {{async_set, Addr, Port, VAV}, From, Ref} ->
- d("loop -> received async_set request"),
- Res = snmpm:as(Id, Addr, Port, VAV),
- reply(From, Res, Ref),
- loop(S);
-
%%
%% -- (sync) get-bulk-request --
@@ -718,27 +571,6 @@ loop(#state{parent = Parent, id = Id} = S) ->
reply(From, Res, Ref),
loop(S);
- {{sync_get_bulk, Addr, NonRep, MaxRep, Oids}, From, Ref} ->
- d("loop -> received sync_get_bulk request with"
- "~n Addr: ~p"
- "~n NonRep: ~w"
- "~n MaxRep: ~w"
- "~n Oids: ~p", [Addr, NonRep, MaxRep, Oids]),
- Res = snmpm:gb(Id, Addr, NonRep, MaxRep, Oids),
- reply(From, Res, Ref),
- loop(S);
-
- {{sync_get_bulk, Addr, Port, NonRep, MaxRep, Oids}, From, Ref} ->
- d("loop -> received sync_get_bulk request with"
- "~n Addr: ~p"
- "~n Port: ~w"
- "~n NonRep: ~w"
- "~n MaxRep: ~w"
- "~n Oids: ~p", [Addr, Port, NonRep, MaxRep, Oids]),
- Res = snmpm:gb(Id, Addr, Port, NonRep, MaxRep, Oids),
- reply(From, Res, Ref),
- loop(S);
-
%%
%% -- (async) get-bulk-request --
@@ -779,27 +611,6 @@ loop(#state{parent = Parent, id = Id} = S) ->
reply(From, Res, Ref),
loop(S);
- {{async_get_bulk, Addr, NonRep, MaxRep, Oids}, From, Ref} ->
- d("loop -> received async_get_bulk request with"
- "~n Addr: ~p"
- "~n NonRep: ~w"
- "~n MaxRep: ~w"
- "~n Oids: ~p", [Addr, NonRep, MaxRep, Oids]),
- Res = snmpm:agb(Id, Addr, NonRep, MaxRep, Oids),
- reply(From, Res, Ref),
- loop(S);
-
- {{async_get_bulk, Addr, Port, NonRep, MaxRep, Oids}, From, Ref} ->
- d("loop -> received async_get_bulk request with"
- "~n Addr: ~p"
- "~n Port: ~w"
- "~n NonRep: ~w"
- "~n MaxRep: ~w"
- "~n Oids: ~p", [Addr, Port, NonRep, MaxRep, Oids]),
- Res = snmpm:agb(Id, Addr, Port, NonRep, MaxRep, Oids),
- reply(From, Res, Ref),
- loop(S);
-
%%
%% -- logical name translation --
@@ -846,12 +657,6 @@ loop(#state{parent = Parent, id = Id} = S) ->
Parent ! {async_event, ReqId, {pdu, SnmpResponse}},
loop(S);
- %% For backwards compatibillity
- {handle_pdu, _Pid, _Addr, _Port, ReqId, SnmpResponse} ->
- d("loop -> received pdu callback from manager for ~w", [ReqId]),
- Parent ! {async_event, ReqId, {pdu, SnmpResponse}},
- loop(S);
-
{handle_trap, _Pid, TargetName, SnmpTrap} ->
d("loop -> received trap callback from manager for "
"~n ~p",
@@ -860,15 +665,6 @@ loop(#state{parent = Parent, id = Id} = S) ->
Parent ! {async_event, TargetName, {trap, SnmpTrap}},
loop(S);
- %% For backwards compatibillity
- {handle_trap, _Pid, Addr, Port, SnmpTrap} ->
- d("loop -> received trap callback from manager for "
- "~n ~p:~w",
- "~n ~p",
- [Addr, Port, SnmpTrap]),
- Parent ! {async_event, {Addr, Port}, {trap, SnmpTrap}},
- loop(S);
-
{handle_inform, Pid, TargetName, SnmpInform} ->
d("loop -> received inform callback from manager for "
"~n ~p",
@@ -877,15 +673,6 @@ loop(#state{parent = Parent, id = Id} = S) ->
Parent ! {async_event, TargetName, {inform, Pid, SnmpInform}},
loop(S);
- %% For backwards compatibillity
- {handle_inform, Pid, Addr, Port, SnmpInform} ->
- d("loop -> received inform callback from manager for "
- "~n ~p:~w",
- "~n ~p",
- [Addr, Port, SnmpInform]),
- Parent ! {async_event, {Addr, Port}, {inform, Pid, SnmpInform}},
- loop(S);
-
{handle_report, _Pid, TargetName, SnmpReport} ->
d("loop -> received report callback from manager for "
"~n ~p",
@@ -894,15 +681,6 @@ loop(#state{parent = Parent, id = Id} = S) ->
Parent ! {async_event, TargetName, {report, SnmpReport}},
loop(S);
- %% For backwards compatibillity
- {handle_report, _Pid, Addr, Port, SnmpReport} ->
- d("loop -> received report callback from manager for "
- "~n ~p:~w",
- "~n ~p",
- [Addr, Port, SnmpReport]),
- Parent ! {async_event, {Addr, Port}, {report, SnmpReport}},
- loop(S);
-
{'EXIT', Parent, Reason} ->
d("received exit signal from parent: ~n~p", [Reason]),
info("received exit signal from parent: ~n~p", [Reason]),
@@ -981,8 +759,8 @@ handle_error(ReqId, Reason, UserPid) ->
ignore.
-handle_agent(Addr, Port, SnmpInfo, UserPid) ->
- UserPid ! {handle_agent, self(), Addr, Port, SnmpInfo},
+handle_agent(Addr, Port, SnmpInfo, UserPid, UserData) ->
+ UserPid ! {handle_agent, self(), Addr, Port, SnmpInfo, UserData},
ignore.
@@ -990,22 +768,10 @@ handle_pdu(TargetName, ReqId, SnmpResponse, UserPid) ->
UserPid ! {handle_pdu, self(), TargetName, ReqId, SnmpResponse},
ignore.
-%% For backwards compatibillity
-handle_pdu(Addr, Port, ReqId, SnmpResponse, UserPid) ->
- UserPid ! {handle_pdu, self(), Addr, Port, ReqId, SnmpResponse},
- ignore.
-
-
handle_trap(TargetName, SnmpTrap, UserPid) ->
UserPid ! {handle_trap, self(), TargetName, SnmpTrap},
ok.
-%% For backwards compatibillity
-handle_trap(Addr, Port, SnmpTrap, UserPid) ->
- UserPid ! {handle_trap, self(), Addr, Port, SnmpTrap},
- ok.
-
-
handle_inform(TargetName, SnmpInform, UserPid) ->
UserPid ! {handle_inform, self(), TargetName, SnmpInform},
receive
@@ -1015,26 +781,10 @@ handle_inform(TargetName, SnmpInform, UserPid) ->
ok
end.
-%% For backwards compatibillity
-handle_inform(Addr, Port, SnmpInform, UserPid) ->
- UserPid ! {handle_inform, self(), Addr, Port, SnmpInform},
- receive
- {handle_inform_no_response, {Addr, Port}} ->
- no_reply;
- {handle_inform_response, {Addr, Port}} ->
- ok
- end.
-
-
handle_report(TargetName, SnmpReport, UserPid) ->
UserPid ! {handle_report, self(), TargetName, SnmpReport},
ok.
-%% For backwards compatibillity
-handle_report(Addr, Port, SnmpReport, UserPid) ->
- UserPid ! {handle_report, self(), Addr, Port, SnmpReport},
- ok.
-
%%----------------------------------------------------------------------
%% Debug
diff --git a/lib/snmp/test/snmp_manager_user_old.erl b/lib/snmp/test/snmp_manager_user_old.erl
index 6280cef51f..9f951bf64d 100644
--- a/lib/snmp/test/snmp_manager_user_old.erl
+++ b/lib/snmp/test/snmp_manager_user_old.erl
@@ -107,10 +107,20 @@ unregister_agent(Addr, Port) ->
snmpm:unregister_agent(?USER_ID, Addr, Port).
agent_info(Addr, Port, Item) ->
- snmpm:agent_info(?USER_ID, Addr, Port, Item).
+ case snmpm:target_name(Addr, Port) of
+ {ok, TargetName} ->
+ snmpm:agent_info(TargetName, Item);
+ Error ->
+ Error
+ end.
update_agent_info(Addr, Port, Item, Val) ->
- snmpm:update_agent_info(?USER_ID, Addr, Port, Item, Val).
+ case snmpm:target_name(Addr, Port) of
+ {ok, TargetName} ->
+ snmpm:update_agent_info(?USER_ID, TargetName, Item, Val);
+ Error ->
+ Error
+ end.
which_agents() ->
snmpm:which_agents().
@@ -128,73 +138,153 @@ unload_mib(Mib) ->
%% --
sync_get(Addr, Oids) ->
- snmpm:g(?USER_ID, Addr, Oids).
+ case snmpm:target_name(Addr) of
+ {ok, TargetName} ->
+ snmpm:sync_get2(?USER_ID, TargetName, Oids);
+ Error ->
+ Error
+ end.
sync_get(Addr, Port, Oids) ->
- snmpm:g(?USER_ID, Addr, Port, Oids).
+ case snmpm:target_name(Addr, Port) of
+ {ok, TargetName} ->
+ snmpm:sync_get2(?USER_ID, TargetName, Oids);
+ Error ->
+ Error
+ end.
%% --
async_get(Addr, Oids) ->
- snmpm:ag(?USER_ID, Addr, Oids).
+ case snmpm:target_name(Addr) of
+ {ok, TargetName} ->
+ snmpm:async_get2(?USER_ID, TargetName, Oids);
+ Error ->
+ Error
+ end.
async_get(Addr, Port, Oids) ->
- snmpm:ag(?USER_ID, Addr, Port, Oids).
+ case snmpm:target_name(Addr, Port) of
+ {ok, TargetName} ->
+ snmpm:async_get2(?USER_ID, TargetName, Oids);
+ Error ->
+ Error
+ end.
%% --
sync_get_next(Addr, Oids) ->
- snmpm:gn(?USER_ID, Addr, Oids).
+ case snmpm:target_name(Addr) of
+ {ok, TargetName} ->
+ snmpm:sync_get_next2(?USER_ID, TargetName, Oids);
+ Error ->
+ Error
+ end.
sync_get_next(Addr, Port, Oids) ->
- snmpm:gn(?USER_ID, Addr, Port, Oids).
+ case snmpm:target_name(Addr, Port) of
+ {ok, TargetName} ->
+ snmpm:sync_get_next2(?USER_ID, TargetName, Oids);
+ Error ->
+ Error
+ end.
%% --
async_get_next(Addr, Oids) ->
- snmpm:agn(?USER_ID, Addr, Oids).
+ case snmpm:target_name(Addr) of
+ {ok, TargetName} ->
+ snmpm:async_get_next2(?USER_ID, TargetName, Oids);
+ Error ->
+ Error
+ end.
async_get_next(Addr, Port, Oids) ->
- snmpm:agn(?USER_ID, Addr, Port, Oids).
+ case snmpm:target_name(Addr, Port) of
+ {ok, TargetName} ->
+ snmpm:async_get_next2(?USER_ID, TargetName, Oids);
+ Error ->
+ Error
+ end.
%% --
sync_set(Addr, VAV) ->
- snmpm:s(?USER_ID, Addr, VAV).
+ case snmpm:target_name(Addr) of
+ {ok, TargetName} ->
+ snmpm:sync_set2(?USER_ID, TargetName, VAV);
+ Error ->
+ Error
+ end.
sync_set(Addr, Port, VAV) ->
- snmpm:s(?USER_ID, Addr, Port, VAV).
+ case snmpm:target_name(Addr, Port) of
+ {ok, TargetName} ->
+ snmpm:sync_set2(?USER_ID, TargetName, VAV);
+ Error ->
+ Error
+ end.
%% --
async_set(Addr, VAV) ->
- snmpm:as(?USER_ID, Addr, VAV).
+ case snmpm:target_name(Addr) of
+ {ok, TargetName} ->
+ snmpm:async_set2(?USER_ID, TargetName, VAV);
+ Error ->
+ Error
+ end.
async_set(Addr, Port, VAV) ->
- snmpm:as(?USER_ID, Addr, Port, VAV).
+ case snmpm:target_name(Addr, Port) of
+ {ok, TargetName} ->
+ snmpm:async_set2(?USER_ID, TargetName, VAV);
+ Error ->
+ Error
+ end.
%% --
sync_get_bulk(Addr, NonRep, MaxRep, Oids) ->
- snmpm:gb(?USER_ID, Addr, NonRep, MaxRep, Oids).
+ case snmpm:target_name(Addr) of
+ {ok, TargetName} ->
+ snmpm:sync_get_bulk2(?USER_ID, TargetName, NonRep, MaxRep, Oids);
+ Error ->
+ Error
+ end.
sync_get_bulk(Addr, Port, NonRep, MaxRep, Oids) ->
- snmpm:gb(?USER_ID, Addr, Port, NonRep, MaxRep, Oids).
+ case snmpm:target_name(Addr, Port) of
+ {ok, TargetName} ->
+ snmpm:sync_get_bulk2(?USER_ID, TargetName, NonRep, MaxRep, Oids);
+ Error ->
+ Error
+ end.
%% --
async_get_bulk(Addr, NonRep, MaxRep, Oids) ->
- snmpm:agb(?USER_ID, Addr, NonRep, MaxRep, Oids).
+ case snmpm:target_name(Addr) of
+ {ok, TargetName} ->
+ snmpm:async_get_bulk2(?USER_ID, TargetName, NonRep, MaxRep, Oids);
+ Error ->
+ Error
+ end.
async_get_bulk(Addr, Port, NonRep, MaxRep, Oids) ->
- snmpm:agb(?USER_ID, Addr, Port, NonRep, MaxRep, Oids).
+ case snmpm:target_name(Addr, Port) of
+ {ok, TargetName} ->
+ snmpm:async_get_bulk2(?USER_ID, TargetName, NonRep, MaxRep, Oids);
+ Error ->
+ Error
+ end.
%% --
diff --git a/lib/snmp/test/snmp_manager_user_test.erl b/lib/snmp/test/snmp_manager_user_test.erl
index fefa1ad713..41d5c50b19 100644
--- a/lib/snmp/test/snmp_manager_user_test.erl
+++ b/lib/snmp/test/snmp_manager_user_test.erl
@@ -36,7 +36,7 @@
%% -compile(export_all).
-export([
-all/0,groups/0,init_per_group/2,end_per_group/2,
+ all/0,groups/0,init_per_group/2,end_per_group/2,
init_per_testcase/2, end_per_testcase/2,
diff --git a/lib/snmp/test/snmp_test_lib.erl b/lib/snmp/test/snmp_test_lib.erl
index e327456bc4..f0abae73e8 100644
--- a/lib/snmp/test/snmp_test_lib.erl
+++ b/lib/snmp/test/snmp_test_lib.erl
@@ -324,7 +324,7 @@ fail(Reason, Mod, Line) ->
skip(Reason, Module, Line) ->
String = lists:flatten(io_lib:format("Skipping ~p(~p): ~p~n",
[Module, Line, Reason])),
- exit({skipped, String}).
+ exit({skip, String}).
%% ----------------------------------------------------------------
diff --git a/lib/snmp/test/snmp_test_manager.erl b/lib/snmp/test/snmp_test_manager.erl
index 4cc6d36acc..0df2350d58 100644
--- a/lib/snmp/test/snmp_test_manager.erl
+++ b/lib/snmp/test/snmp_test_manager.erl
@@ -43,7 +43,7 @@
%% Manager callback API:
-export([
handle_error/3,
- handle_agent/4,
+ handle_agent/5,
handle_pdu/4,
handle_trap/3,
handle_inform/3,
@@ -239,7 +239,7 @@ handle_info({snmp_error, ReqId, Reason},
P ! {snmp_error, ReqId, Reason},
{noreply, State};
-handle_info({snmp_agent, Addr, Port, Info, Pid},
+handle_info({snmp_agent, Addr, Port, Info, Pid, _UserData},
#state{parent = P} = State) ->
error_msg("detected new agent: "
"~n Addr: ~w"
@@ -326,8 +326,8 @@ handle_error(ReqId, Reason, Pid) ->
ignore.
-handle_agent(Addr, Port, SnmpInfo, Pid) ->
- Pid ! {snmp_agent, Addr, Port, SnmpInfo, self()},
+handle_agent(Addr, Port, SnmpInfo, Pid, UserData) ->
+ Pid ! {snmp_agent, Addr, Port, SnmpInfo, self(), UserData},
receive
{snmp_agent_reply, Reply, Pid} ->
Reply
diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk
index b90dbe4eef..8145e415f3 100644
--- a/lib/snmp/vsn.mk
+++ b/lib/snmp/vsn.mk
@@ -18,6 +18,6 @@
# %CopyrightEnd%
APPLICATION = snmp
-SNMP_VSN = 4.22.1
+SNMP_VSN = 4.23
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(SNMP_VSN)$(PRE_VSN)"
diff --git a/lib/ssh/doc/html/SSH_protocols.png b/lib/ssh/doc/html/SSH_protocols.png
new file mode 100644
index 0000000000..145c96c4cd
--- /dev/null
+++ b/lib/ssh/doc/html/SSH_protocols.png
Binary files differ
diff --git a/lib/ssh/doc/man6/.gitignore b/lib/ssh/doc/man6/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/ssh/doc/man6/.gitignore
diff --git a/lib/ssh/doc/src/Makefile b/lib/ssh/doc/src/Makefile
index da99c4ea0f..0e79d9979f 100644
--- a/lib/ssh/doc/src/Makefile
+++ b/lib/ssh/doc/src/Makefile
@@ -37,21 +37,30 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
# Target Specs
# ----------------------------------------------------
XML_APPLICATION_FILES = ref_man.xml
-XML_REF3_FILES = \
- ssh.xml \
+XML_REF3_FILES = ssh.xml \
ssh_channel.xml \
- ssh_connection.xml\
+ ssh_connection.xml \
+ ssh_client_key_api.xml \
+ ssh_server_key_api.xml \
ssh_sftp.xml \
ssh_sftpd.xml \
-XML_PART_FILES = part_notes.xml
-XML_CHAPTER_FILES = notes.xml
+XML_REF6_FILES = ssh_app.xml
+
+XML_PART_FILES = part_notes.xml \
+ usersguide.xml
+XML_CHAPTER_FILES = notes.xml \
+ introduction.xml \
+ ssh_protocol.xml \
+ using_ssh.xml
BOOK_FILES = book.xml
-XML_FILES = $(BOOK_FILES) $(XML_APPLICATION_FILES) $(XML_REF3_FILES) \
+XML_FILES = $(BOOK_FILES) $(XML_APPLICATION_FILES) $(XML_REF3_FILES) $(XML_REF6_FILES)\
$(XML_PART_FILES) $(XML_CHAPTER_FILES)
+IMAGE_FILES = SSH_protocols.png
+
# ----------------------------------------------------
HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \
@@ -62,10 +71,12 @@ EXTRA_FILES = \
$(DEFAULT_GIF_FILES) \
$(DEFAULT_HTML_FILES) \
$(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html) \
+ $(XML_REF6_FILES:%.xml=$(HTMLDIR)/%.html) \
$(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html)
MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
+MAN6_FILES = $(XML_REF6_FILES:%_app.xml=$(MAN6DIR)/%.6)
HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
@@ -80,16 +91,19 @@ DVIPS_FLAGS +=
# ----------------------------------------------------
# Targets
# ----------------------------------------------------
-$(HTMLDIR)/%.gif: %.gif
+$(HTMLDIR)/%.png: %.png
$(INSTALL_DATA) $< $@
docs: pdf html man
$(TOP_PDF_FILE): $(XML_FILES)
+images: $(IMAGE_FILES:%=$(HTMLDIR)/%)
+
pdf: $(TOP_PDF_FILE)
-html: $(HTML_REF_MAN_FILE)
+html: images $(HTML_REF_MAN_FILE)
+
clean clean_docs:
rm -rf $(HTMLDIR)/*
@@ -97,7 +111,7 @@ clean clean_docs:
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
-man: $(MAN3_FILES)
+man: $(MAN3_FILES) $(MAN6_FILES)
debug opt:
@@ -117,5 +131,8 @@ release_docs_spec: docs
$(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
$(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
$(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man6"
+ $(INSTALL_DATA) $(MAN6_FILES) "$(RELEASE_PATH)/man/man6"
+
release_spec:
diff --git a/lib/ssh/doc/src/SSH_protocols.png b/lib/ssh/doc/src/SSH_protocols.png
new file mode 100644
index 0000000000..145c96c4cd
--- /dev/null
+++ b/lib/ssh/doc/src/SSH_protocols.png
Binary files differ
diff --git a/lib/ssh/doc/src/book.xml b/lib/ssh/doc/src/book.xml
index fcec1d6f70..3c2375f96d 100644
--- a/lib/ssh/doc/src/book.xml
+++ b/lib/ssh/doc/src/book.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE book SYSTEM "book.dtd">
<book xmlns:xi="http://www.w3.org/2001/XInclude">
<header titlestyle="normal">
<copyright>
- <year>2005</year><year>2010</year>
+ <year>2005</year><year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -34,6 +34,9 @@
<preamble>
<contents level="2"></contents>
</preamble>
+ <parts lift="yes">
+ <xi:include href="usersguide.xml"/>
+ </parts>
<applications>
<xi:include href="ref_man.xml"/>
</applications>
diff --git a/lib/ssh/doc/src/fascicules.xml b/lib/ssh/doc/src/fascicules.xml
index 43090b4aed..069d9002e0 100644
--- a/lib/ssh/doc/src/fascicules.xml
+++ b/lib/ssh/doc/src/fascicules.xml
@@ -1,7 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE fascicules SYSTEM "fascicules.dtd">
<fascicules>
+ <fascicule file="usersguide" href="usersguide_frame.html" entry="no">
+ User's Guide
+ </fascicule>
<fascicule file="ref_man" href="ref_man_frame.html" entry="yes">
Reference Manual
</fascicule>
diff --git a/lib/ssh/doc/src/introduction.xml b/lib/ssh/doc/src/introduction.xml
new file mode 100644
index 0000000000..aac8de0f76
--- /dev/null
+++ b/lib/ssh/doc/src/introduction.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="iso-8859-1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2012</year>
+ <holder>Ericsson AB, All Rights Reserved</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ The Initial Developer of the Original Code is Ericsson AB.
+ </legalnotice>
+
+ <title>Introduction</title>
+ <prepared>OTP team</prepared>
+ <file>introduction.xml</file>
+ </header>
+
+ <section>
+ <title>Purpose</title>
+
+ <p>Secure Shell (SSH) is a protocol for secure remote login and
+ other secure network services over an insecure network. SSH
+ provides a single, full-duplex, byte-oriented connection between
+ client and server. The protocol also provides privacy, integrity,
+ server authentication and man-in-the-middle protection.</p>
+
+ <p>The Erlang SSH application is an implementation of the SSH
+ protocol in Erlang which offers API functions to write customized
+ SSH clients and servers as well as making the Erlang shell
+ available via SSH. Also included in the SSH application are an
+ SFTP (SSH File Transfer Protocol) client <seealso
+ marker="ssh_sftp">ssh_sftp</seealso> and server <seealso
+ marker="ssh_sftp">ssh_sftpd</seealso>.</p>
+ </section>
+
+ <section>
+ <title>Prerequisites</title>
+ <p>It is assumed that the reader is familiar with the concepts of <seealso marker="doc/design_principals:users_guide">OTP</seealso>
+ and has a basic understanding of <url href="http://en.wikipedia.org/wiki/Public-key_cryptography">public keys</url>.</p>
+ </section>
+
+</chapter>
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index 36010da07a..e58d4e2c36 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE chapter SYSTEM "chapter.dtd">
<chapter>
@@ -29,6 +29,50 @@
<file>notes.xml</file>
</header>
+<section><title>Ssh 2.1.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ SSH quiet mode</p>
+ <p>
+ A new option to ssh:connect/3,4, quiet_mode. If true, the
+ client will not print out anything on authorization.</p>
+ <p>
+ Own Id: OTP-10429 Aux Id: kunagi-273 [184] </p>
+ </item>
+ <item>
+ <p>
+ Restrict which key algorithms to use</p>
+ <p>
+ A new option to ssh:connect/3,4 is introduced,
+ public_key_algs, where you can restrict which key
+ algorithms to use and in which order to try them.</p>
+ <p>
+ Own Id: OTP-10498 Aux Id: kunagi-289 [200] </p>
+ </item>
+ <item>
+ <p>
+ Confidentiality of client password</p>
+ <p>
+ Unsets clients password after authentication.</p>
+ <p>
+ Own Id: OTP-10511 Aux Id: kunagi-292 [203] </p>
+ </item>
+ <item>
+ <p>
+ Fixed user interaction for SSH</p>
+ <p>
+ It's now available to accept hosts and input password</p>
+ <p>
+ Own Id: OTP-10513 Aux Id: kunagi-293 [204] </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Ssh 2.1.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -736,7 +780,7 @@
<list>
<item>
<p>
- Ssh timeouts will now behave as expected e.i. defaults to
+ Ssh timeouts will now behave as expected i.e. defaults to
infinity only the user of the ssh application can know of
a reasonable timeout value for their application.</p>
<p>
@@ -789,7 +833,7 @@
caused the ssh daemon to close the connections to all
currently logged in users if one user logged out. Another
problem related to the supervision tree caused the closing
- down of clients to leak processes e.i. all processes was
+ down of clients to leak processes i.e. all processes was
not shutdown correctly.</p>
<p>
Own Id: OTP-7676</p>
@@ -881,7 +925,7 @@
slightly changes the options to the API function
ssh:daemon/[1,2,3] deprecating all no longer documented
options. Note that the new API enforces the "logical way"
- of using the old API e.i. making the subsystem process
+ of using the old API i.e. making the subsystem process
part of the ssh applications supervisor tree, so missuses
of the old API are not compatible with the new API.</p>
<p>
diff --git a/lib/ssh/doc/src/ref_man.xml b/lib/ssh/doc/src/ref_man.xml
index 9ab56b28ec..88203b5034 100644
--- a/lib/ssh/doc/src/ref_man.xml
+++ b/lib/ssh/doc/src/ref_man.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE application SYSTEM "application.dtd">
<application xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>2004</year><year>2010</year>
+ <year>2004</year><year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -22,19 +22,22 @@
</legalnotice>
<title>SSH Reference Manual</title>
- <prepared>Jakob Cederlund</prepared>
- <docno></docno>
+ <prepared>OTP</prepared>
<date>2007-10-06</date>
<rev>%VSN%</rev>
- <file>application.sgml</file>
+ <file>ref_man.xml</file>
</header>
<description>
<p>The SSH application is an erlang implementation of the
- secure shell protocol.</p>
+ secure shell protocol (SSH) as defined by RFC 4250 - 4254</p>
+
</description>
+ <xi:include href="ssh_app.xml"/>
<xi:include href="ssh.xml"/>
<xi:include href="ssh_channel.xml"/>
<xi:include href="ssh_connection.xml"/>
+ <xi:include href="ssh_client_key_api.xml"/>
+ <xi:include href="ssh_server_key_api.xml"/>
<xi:include href="ssh_sftp.xml"/>
<xi:include href="ssh_sftpd.xml"/>
</application>
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index 0133250979..7f7d887d5e 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -22,13 +22,7 @@
</legalnotice>
<title>ssh</title>
- <prepared>Ingela Anderton Andin</prepared>
- <responsible>H&aring;kan Mattsson</responsible>
- <docno></docno>
- <approved>H&aring;kan Mattsson</approved>
- <checked></checked>
<date>2007-10-06</date>
- <rev>PA1</rev>
</header>
<module>ssh</module>
<modulesummary>Main API of the SSH application</modulesummary>
@@ -40,80 +34,85 @@
<title>SSH</title>
<list type="bulleted">
- <item>ssh requires the crypto and public_key applications.</item>
- <item>Supported SSH-version is 2.0 </item>
- <item>Currently supports only a minimum of mac and encryption algorithms i.e.
- hmac-sha1, and aes128-cb and 3des-cbc.</item>
+ <item>SSH requires the crypto and public_key applications.</item>
+ <item>Supported SSH version is 2.0 </item>
+ <item>Supported MAC algorithms: hmac-sha1</item>
+ <item>Supported encryption algorithms: aes128-cb and 3des-cbc</item>
</list>
</section>
<section>
- <title>COMMON DATA TYPES </title>
+ <title>DATA TYPES </title>
<p>Type definitions that are used more than once in
- this module:</p>
+ this module and/or abstractions to indicate the intended use of the data
+ type:</p>
<p><c>boolean() = true | false </c></p>
- <p><c>string() = list of ASCII characters</c></p>
+ <p><c>string() = [byte()]</c></p>
<p><c>ssh_daemon_ref() - opaque to the user
returned by ssh:daemon/[1,2,3]</c></p>
<p><c>ssh_connection_ref() - opaque to the user
returned by ssh:connect/3</c></p>
<p><c>ip_address() - {N1,N2,N3,N4} % IPv4 |
{K1,K2,K3,K4,K5,K6,K7,K8} % IPv6</c></p>
- <p><c>subsystem_spec() = {subsystem_name(), {channel_callback(), channel_init_args()}} </c></p>
+ <p><c>subsystem_spec() = {subsystem_name(),
+ {channel_callback(), channel_init_args()}} </c></p>
<p><c>subsystem_name() = string() </c></p>
<p><c>channel_callback() = atom() - Name of the erlang module
implementing the subsystem using the ssh_channel behavior see</c>
<seealso marker="ssh_channel">ssh_channel(3)</seealso></p>
<p><c>channel_init_args() = list()</c></p>
</section>
-
+
<funcs>
<func>
<name>close(ConnectionRef) -> ok </name>
- <fsummary>Closes a ssh connection</fsummary>
+ <fsummary>Closes an SSH connection</fsummary>
<type>
<v>ConnectionRef = ssh_connection_ref()</v>
</type>
- <desc><p>Closes a ssh connection.</p>
+ <desc><p>Closes an SSH connection.</p>
</desc>
</func>
<func>
<name>connect(Host, Port, Options) -> </name>
- <name>connect(Host, Port, Options, Timeout) -> {ok, ssh_connection_ref()}
- | {error, Reason}</name>
+ <name>connect(Host, Port, Options, Timeout) -> {ok,
+ ssh_connection_ref()} | {error, Reason}</name>
<fsummary>Connect to an ssh server.</fsummary>
<type>
<v>Host = string()</v>
<v>Port = integer()</v>
- <d>The default is <c><![CDATA[22]]></c>, the registered port for SSH.</d>
+ <d>The default is <c><![CDATA[22]]></c>, the assigned well known port
+ number for SSH.</d>
<v>Options = [{Option, Value}]</v>
<v>Timeout = infinity | integer(milliseconds)</v>
</type>
<desc>
- <p>Connects to an SSH server. No channel is started this is done
+ <p>Connects to an SSH server. No channel is started. This is done
by calling ssh_connect:session_channel/2.</p>
<p>Options are:</p>
<taglist>
<tag><c><![CDATA[{user_dir, string()}]]></c></tag>
<item>
- <p>Sets the user directory e.i. the directory containing
+ <p>Sets the user directory i.e. the directory containing
ssh configuration files for the user such as
- <c><![CDATA[known_hosts]]></c>, <c><![CDATA[id_rsa, id_dsa]]></c> and
- <c><![CDATA[authorized_key]]></c>. Defaults to the directory normally
- referred to as <c><![CDATA[~/.ssh]]></c> </p>
+ <c><![CDATA[known_hosts]]></c>, <c><![CDATA[id_rsa,
+ id_dsa]]></c> and
+ <c><![CDATA[authorized_key]]></c>. Defaults to the
+ directory normally referred to as
+ <c><![CDATA[~/.ssh]]></c> </p>
</item>
<tag><c><![CDATA[{dsa_pass_phrase, string()}]]></c></tag>
<item>
- <p>If the user dsa key is protected by a pass phrase it can be
+ <p>If the user dsa key is protected by a passphrase it can be
supplied with this option.
</p>
</item>
<tag><c><![CDATA[{rsa_pass_phrase, string()}]]></c></tag>
<item>
- <p>If the user rsa key is protected by a pass phrase it can be
+ <p>If the user rsa key is protected by a passphrase it can be
supplied with this option.
</p>
</item>
@@ -135,20 +134,26 @@
password. Do note that it may not always be desirable to use
those options from a security point of view.</p>
</item>
- <tag><c><![CDATA[{public_key_alg, ssh_rsa | ssh_dsa}]]></c></tag>
+ <tag><c><![CDATA[{public_key_alg, 'ssh-rsa' | 'ssh-dss'}]]></c></tag>
<item>
<p>Sets the preferred public key algorithm to use for user
- authentication. If the the preferred algorithm fails of
+ authentication. If the the preferred algorithm fails for
some reason, the other algorithm is tried. The default is
to try <c><![CDATA[ssh_rsa]]></c> first.</p>
</item>
+ <tag><c><![CDATA[{pref_public_key_algs, list()}]]></c></tag>
+ <item>
+ <p>List of public key algorithms to try to use, 'ssh-rsa' and 'ssh-dss' available.
+ Will override <c><![CDATA[{public_key_alg, 'ssh-rsa' | 'ssh-dss'}]]></c></p>
+ </item>
<tag><c><![CDATA[{connect_timeout, timeout()}]]></c></tag>
<item>
- <p>Sets a timeout on the transport layer connection. Defaults to infinity.</p>
+ <p>Sets a timeout on the transport layer
+ connection. Defaults to <c>infinity</c>.</p>
</item>
- <tag><c><![CDATA[{user, String}]]></c></tag>
+ <tag><c><![CDATA[{user, string()}]]></c></tag>
<item>
- <p>Provide a user name. If this option is not given, ssh
+ <p>Provides a user name. If this option is not given, ssh
reads from the environment (<c><![CDATA[LOGNAME]]></c> or
<c><![CDATA[USER]]></c> on unix,
<c><![CDATA[USERNAME]]></c> on Windows).</p>
@@ -160,37 +165,39 @@
password if the password authentication method is
attempted.</p>
</item>
- <tag><c><![CDATA[{user_auth, Fun/3}]]></c></tag>
- <item>
- <p>Provide a fun for password authentication. The fun
- will be called as <c><![CDATA[fun(User, Password, Opts)]]></c> and
- should return <c><![CDATA[true]]></c> or <c><![CDATA[false]]></c>.</p>
+ <tag><c><![CDATA[{key_cb, atom()}]]></c></tag>
+ <item>
+ <p>Module implementing the behaviour <seealso marker="ssh_client_key_api">ssh_client_key_api</seealso>.
+ Can be used to customize the handling of public keys.
+ </p>
</item>
- <tag><c><![CDATA[{key_cb, atom() = KeyCallbackModule}]]></c></tag>
+ <tag><c><![CDATA[{quiet_mode, atom() = boolean()}]]></c></tag>
<item>
- <p>Provide a special call-back module for key handling.
- The call-back module should be modeled after the
- <c><![CDATA[ssh_file]]></c> module. The functions that must
- be exported are:
- <c><![CDATA[private_host_rsa_key/2]]></c>,
- <c><![CDATA[private_host_dsa_key/2]]></c>,
- <c><![CDATA[lookup_host_key/3]]></c> and
- <c><![CDATA[add_host_key/3]]></c>. This is considered
- somewhat experimental and will be better documented later on.</p>
+ <p>If true, the client will not print out anything on authorization.</p>
</item>
<tag><c><![CDATA[{fd, file_descriptor()}]]></c></tag>
<item>
- <p>Allow an existing file-descriptor to be used
+ <p>Allow an existing file descriptor to be used
(simply passed on to the transport protocol).</p></item>
- <tag><c><![CDATA[{ip_v6_disabled, boolean()}]]></c></tag>
+ <tag><c><![CDATA[{ipv6_disabled, boolean()}]]></c></tag>
<item>
- <p>Determines if SSH shall use IPv6 or not.</p></item>
+ <p>Determines if SSH shall use IPv6 or not.</p>
+ </item>
+ <tag><c><![CDATA[{rekey_limit, integer()}]]></c></tag>
+ <item>
+ <p>Provide, in bytes, when rekeying should be initiated,
+ defaults to one time each GB and one time per hour.</p>
+ </item>
+ <tag><c><![CDATA[{idle_time, integer()}]]></c></tag>
+ <item>
+ <p>Sets a timeout on connection when no channels are active, default is infinity</p></item>
</taglist>
</desc>
</func>
<func>
- <name>connection_info(ConnectionRef, [Option]) ->[{Option, Value}] </name>
+ <name>connection_info(ConnectionRef, [Option]) ->[{Option,
+ Value}] </name>
<fsummary> Retrieves information about a connection. </fsummary>
<type>
<v>Option = client_version | server_version | peer</v>
@@ -205,7 +212,8 @@
<func>
<name>daemon(Port) -> </name>
<name>daemon(Port, Options) -> </name>
- <name>daemon(HostAddress, Port, Options) -> ssh_daemon_ref()</name>
+ <name>daemon(HostAddress, Port, Options) -> {ok,
+ ssh_daemon_ref()} | {error, atom()}</name>
<fsummary>Starts a server listening for SSH connections
on the given port.</fsummary>
<type>
@@ -216,30 +224,32 @@
<v>Value = term()</v>
</type>
<desc>
- <p>Starts a server listening for SSH connections on the given port.</p>
-
- <p>Options are:</p>
+ <p>Starts a server listening for SSH connections on the given
+ port.</p>
+ <p>Options are:</p>
<taglist>
<tag><c><![CDATA[{subsystems, [subsystem_spec()]]]></c></tag>
<item>
- Provides specifications for handling of subsystems. The
- "sftp" subsystem-spec can be retrieved by calling
- ssh_sftpd:subsystem_spec/1. If the subsystems option in not present
- the value of <c>[ssh_sftpd:subsystem_spec([])]</c> will be used.
- It is of course possible to set the option to the empty list
- if you do not want the daemon to run any subsystems at all.
+ Provides specifications for handling of subsystems. The
+ "sftp" subsystem spec can be retrieved by calling
+ ssh_sftpd:subsystem_spec/1. If the subsystems option in
+ not present the value of
+ <c>[ssh_sftpd:subsystem_spec([])]</c> will be used. It is
+ of course possible to set the option to the empty list if
+ you do not want the daemon to run any subsystems at all.
</item>
- <tag><c><![CDATA[{shell, {Module, Function, Args} | fun(string() = User) - > pid() |
- fun(string() = User, ip_address() = PeerAddr) -> pid()}]]></c></tag>
+ <tag><c><![CDATA[{shell, {Module, Function, Args} |
+ fun(string() = User) - > pid() | fun(string() = User,
+ ip_address() = PeerAddr) -> pid()}]]></c></tag>
<item>
- Defines the read-eval-print loop used when a shell is requested
- by the client. Example use the
- erlang shell: <c><![CDATA[{shell, start, []}]]></c> which is
- the default behavior.
+ Defines the read-eval-print loop used when a shell is
+ requested by the client. Default is to use the erlang shell:
+ <c><![CDATA[{shell, start, []}]]></c>
</item>
- <tag><c><![CDATA[{ssh_cli,{channel_callback(), channel_init_args()}}]]></c></tag>
+ <tag><c><![CDATA[{ssh_cli,{channel_callback(),
+ channel_init_args()}}]]></c></tag>
<item>
- Provide your own cli implementation, e.i. a channel callback
+ Provides your own cli implementation, i.e. a channel callback
module that implements a shell and command execution. Note
that you may customize the shell read-eval-print loop using the
option <c>shell</c> which is much less work than implementing
@@ -247,27 +257,30 @@
</item>
<tag><c><![CDATA[{user_dir, String}]]></c></tag>
<item>
- <p>Sets the user directory e.i. the directory containing
+ <p>Sets the user directory i.e. the directory containing
ssh configuration files for the user such as
- <c><![CDATA[known_hosts]]></c>, <c><![CDATA[id_rsa, id_dsa]]></c> and
- <c><![CDATA[authorized_key]]></c>. Defaults to the directory normally
- referred to as <c><![CDATA[~/.ssh]]></c> </p>
+ <c><![CDATA[known_hosts]]></c>, <c><![CDATA[id_rsa,
+ id_dsa]]></c> and
+ <c><![CDATA[authorized_key]]></c>. Defaults to the
+ directory normally referred to as
+ <c><![CDATA[~/.ssh]]></c> </p>
</item>
<tag><c><![CDATA[{system_dir, string()}]]></c></tag>
<item>
- <p>Sets the system directory, containing the host files
- that identifies the host for ssh. The default is
- <c><![CDATA[/etc/ssh]]></c>, note that SSH normally
- requires the host files there to be readable only by
- root.</p>
+ <p>Sets the system directory, containing the host key files
+ that identifies the host keys for ssh. The default is
+ <c><![CDATA[/etc/ssh]]></c>, note that for security reasons
+ this directory is normally only accessible by the root user.</p>
</item>
<tag><c><![CDATA[{auth_methods, string()}]]></c></tag>
<item>
- <p>Comma separated string that determines which authentication methodes that the server
- should support and in what order they will be tried. Defaults to
+ <p>Comma separated string that determines which
+ authentication methodes that the server should support and
+ in what order they will be tried. Defaults to
<c><![CDATA["publickey,keyboard-interactive,password"]]></c></p>
</item>
- <tag><c><![CDATA[{user_passwords, [{string() = User, string() = Password}]}]]></c></tag>
+ <tag><c><![CDATA[{user_passwords, [{string() = User,
+ string() = Password}]}]]></c></tag>
<item>
<p>Provide passwords for password authentication.They will
be used when someone tries to connect to the server and
@@ -281,13 +294,19 @@
user. From a security perspective this option makes
the server very vulnerable.</p>
</item>
- <tag><c><![CDATA[{pwdfun, fun/2}]]></c></tag>
+ <tag><c><![CDATA[{pwdfun, fun(User::string(), password::string() -> boolean()}]]></c></tag>
<item>
<p>Provide a function for password validation. This is called
with user and password as strings, and should return
<c><![CDATA[true]]></c> if the password is valid and
<c><![CDATA[false]]></c> otherwise.</p>
</item>
+ <tag><c><![CDATA[{key_cb, atom()}]]></c></tag>
+ <item>
+ <p>Module implementing the behaviour <seealso marker="ssh_server_key_api">ssh_server_key_api</seealso>.
+ Can be used to customize the handling of public keys.
+ </p>
+ </item>
<tag><c><![CDATA[{fd, file_descriptor()}]]></c></tag>
<item>
<p>Allow an existing file-descriptor to be used
@@ -296,6 +315,18 @@
<item>
<p>Determines if SSH shall use IPv6 or not (only used when
HostAddress is set to any).</p></item>
+ <tag><c><![CDATA[{failfun, fun()}]]></c></tag>
+ <item>
+ <p>Provide a fun() to implement your own logging when a user fails to authenticate.</p>
+ </item>
+ <tag><c><![CDATA[{connectfun, fun()}]]></c></tag>
+ <item>
+ <p>Provide a fun() to implement your own logging when a user authenticates to the server.</p>
+ </item>
+ <tag><c><![CDATA[{disconnectfun, fun()}]]></c></tag>
+ <item>
+ <p>Provide a fun() to implement your own logging when a user disconnects from the server.</p>
+ </item>
</taglist>
</desc>
</func>
@@ -311,9 +342,9 @@
<v> Options - see ssh:connect/3</v>
</type>
<desc>
- <p>Starts an interactive shell to an SSH server on the
+ <p>Starts an interactive shell via an SSH server on the
given <c>Host</c>. The function waits for user input,
- and will not return until the remote shell is ended (e.g. on
+ and will not return until the remote shell is ended (i.e.
exit from the shell).
</p>
</desc>
@@ -322,25 +353,24 @@
<func>
<name>start() -> </name>
<name>start(Type) -> ok | {error, Reason}</name>
- <fsummary>Starts the Ssh application. </fsummary>
+ <fsummary>Starts the SSH application. </fsummary>
<type>
<v>Type = permanent | transient | temporary</v>
<v>Reason = term() </v>
</type>
<desc>
- <p>Starts the Ssh application. Default type
- is temporary. See also
- <seealso marker="kernel:application">application(3)</seealso>
- Requires that the crypto application has been started.
+ <p>Utility function that starts crypto, public_key and the SSH
+ application. Defult type is temporary.
+ See also <seealso marker="kernel:application">application(3)</seealso>
</p>
</desc>
</func>
<func>
<name>stop() -> ok </name>
- <fsummary>Stops the Ssh application.</fsummary>
+ <fsummary>Stops the SSH application.</fsummary>
<desc>
- <p>Stops the Ssh application. See also
+ <p>Stops the SSH application. See also
<seealso marker="kernel:application">application(3)</seealso></p>
</desc>
</func>
diff --git a/lib/ssh/doc/src/ssh_app.xml b/lib/ssh/doc/src/ssh_app.xml
new file mode 100644
index 0000000000..c01f44936a
--- /dev/null
+++ b/lib/ssh/doc/src/ssh_app.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="iso-8859-1" ?>
+<!DOCTYPE appref SYSTEM "appref.dtd">
+
+<appref>
+ <header>
+ <copyright>
+ <year>2012</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>SSH</title>
+ <file>ssh_app.xml</file>
+ </header>
+ <app>SSH</app>
+ <appsummary>The ssh application implements the SSH (Secure Shell) protocol and
+ provides an SFTP (SSH File Transfer Protocol) client and server. </appsummary>
+
+ <section>
+ <title>DEPENDENCIES</title>
+ <p>The ssh application uses the Erlang applications public_key and
+ crypto to handle public keys and encryption, hence these
+ applications needs to be loaded for the ssh application to work. In
+ an embedded environment that means they need to be started with
+ application:start/[1,2] before the ssh application is started.
+ </p>
+ </section>
+
+ <section>
+ <title>CONFIGURATION</title>
+
+ <p>The ssh application does not currently have an application
+ specific configuration file as described in application(3),
+ however it will by default use the following configuration files
+ from openssh: known_hosts, authorized_keys, authorized_keys2,
+ id_dsa and id_rsa, ssh_host_dsa_key and ssh_host_rsa_key. By
+ default Erlang SSH will look for id_dsa, id_rsa, known_hosts
+ and authorized_keys in ~/.ssh, and the host key files in /etc/ssh
+ . These locations may be changed by the options user_dir and
+ system_dir. Public key handling may also be customized by
+ providing a callback module implementing the behaviors
+ <seealso marker="ssh_client_key_api">ssh_client_key_api</seealso> and
+ <seealso marker="ssh_server_key_api">ssh_server_key_api</seealso>.
+ </p>
+
+ <section>
+ <title>PUBLIC KEYS</title>
+ <p>
+ id_dsa and id_rsa are the users private key files, note that
+ the public key is part of the private key so the ssh
+ application will not use the id_&lt;*>.pub files. These are
+ for the users convenience when he/she needs to convey their
+ public key.
+ </p>
+ </section>
+
+ <section>
+ <title>KNOW HOSTS</title>
+ <p>The known_hosts file contains a list of approved servers and
+ their public keys. Once a server is listed, it can be verified
+ without user interaction.
+ </p>
+ </section>
+
+ <section>
+ <title>AUTHORIZED KEYS</title>
+ <p>The authorized key file keeps track of the user's authorized
+ public keys. The most common use of this file is to let users
+ log in without entering their password which is supported by the
+ Erlang SSH daemon.
+ </p>
+ </section>
+
+ <section>
+ <title>HOST KEYS</title>
+ <p>Currently rsa and dsa host keys are supported and are
+ expected to be found in files named ssh_host_rsa_key and
+ ssh_host_dsa_key.
+ </p>
+ </section>
+ </section>
+
+ <section>
+ <title>SEE ALSO</title>
+ <p>application(3)</p>
+ </section>
+
+</appref>
diff --git a/lib/ssh/doc/src/ssh_channel.xml b/lib/ssh/doc/src/ssh_channel.xml
index c2b7aa94a5..f0083ae8d1 100644
--- a/lib/ssh/doc/src/ssh_channel.xml
+++ b/lib/ssh/doc/src/ssh_channel.xml
@@ -1,11 +1,11 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
<year>2009</year>
- <year>2009</year>
+ <year>2012</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -22,31 +22,35 @@
The Initial Developer of the Original Code is Ericsson AB.
</legalnotice>
-
<title>ssh_channel</title>
- <prepared>Ingela Anderton Andin</prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date></date>
- <rev></rev>
</header>
<module>ssh_channel</module>
- <modulesummary>Generic Ssh Channel Behavior
+ <modulesummary>-behaviour(ssh_channel).
</modulesummary>
<description>
- <p>Ssh services are implemented as channels that are multiplexed
- over an ssh connection and communicates via the ssh connection
- protocol. This module provides a callback API that takes care of
- generic channel aspects such as flow control and close messages
- and lets the callback functions take care of the service specific
- parts.
+ <p>SSH services (clients and servers) are implemented as channels
+ that are multiplexed over an SSH connection and communicates via
+ the <url href="http://www.ietf.org/rfc/rfc4254.txt"> SSH
+ Connection Protocol </url>. This module provides a callback API
+ that takes care of generic channel aspects such as flow control
+ and close messages and lets the callback functions take care of
+ the service (application) specific parts. This behavior also ensures
+ that the channel process honors the principal of an OTP-process so
+ that it can be part of a supervisor tree. This is a requirement of
+ channel processes implementing a subsystem that will be added to
+ the SSH applications supervisor tree.
</p>
+
+ <note> When implementing a SSH subsystem use the
+ <c>-behaviour(ssh_subsystem).</c> instead of <c>-behaviour(ssh_channel).</c>
+ as the only relevant callback functions for subsystems are
+ init/1, handle_ssh_msg/2, handle_msg/2 and terminate/2, so the ssh_subsystem
+ behaviour is limited version of the ssh_channel behaviour.
+ </note>
</description>
<section>
- <title>COMMON DATA TYPES </title>
+ <title>DATA TYPES </title>
<p>Type definitions that are used more than once in this module
and/or abstractions to indicate the intended use of the data
@@ -56,10 +60,10 @@
<p><c>string() = list of ASCII characters</c></p>
<p><c>timeout() = infinity | integer() - in milliseconds.</c></p>
<p><c>ssh_connection_ref() - opaque to the user returned by
- ssh:connect/3 or sent to a ssh channel process</c></p>
+ ssh:connect/3 or sent to an SSH channel process</c></p>
<p><c>ssh_channel_id() = integer() </c></p>
<p><c>ssh_data_type_code() = 1 ("stderr") | 0 ("normal") are
- currently valid values see RFC 4254 section 5.2.</c></p>
+ currently valid values see <url href="http://www.ietf.org/rfc/rfc4254.txt">RFC 4254 </url> section 5.2.</c></p>
</section>
<funcs>
@@ -74,13 +78,15 @@
<v>Timeout = timeout() </v>
<v>Reply = term() </v>
<v>Reason = closed | timeout </v>
+
</type>
<desc>
<p>Makes a synchronous call to the channel process by sending
a message and waiting until a reply arrives or a timeout
- occurs. The channel will call
- <c>CallbackModule:handle_call/3</c> to handle the message.
- If the channel process does not exist <c>{error, closed}</c> is returned.
+ occurs. The channel will call <seealso mark =
+ "#Module:handle_call-3">Module:handle_call/3</seealso>
+ to handle the message. If the channel process does not exist
+ <c>{error, closed}</c> is returned.
</p>
</desc>
</func>
@@ -98,26 +104,27 @@
<p>Sends an asynchronous message to the channel process and
returns ok immediately, ignoring if the destination node or
channel process does not exist. The channel will call
- <c>CallbackModule:handle_cast/2</c> to handle the message.
+ <seealso mark = "#Module:handle_cast-3">Module:handle_cast/2</seealso>
+ to handle the message.
</p>
</desc>
</func>
<func>
<name>enter_loop(State) -> _ </name>
- <fsummary> Makes an existing process into a ssh_channel process. </fsummary>
+ <fsummary> Makes an existing process an ssh_channel process. </fsummary>
<type>
- <v> State = term() - as returned by ssh_channel:init/1</v>
+ <v> State = term() - as returned by <seealso mark = "#init-1">ssh_channel:init/1</seealso></v>
</type>
<desc>
- <p> Makes an existing process into a <c>ssh_channel</c>
+ <p> Makes an existing process an <c>ssh_channel</c>
process. Does not return, instead the calling process will
- enter the <c>ssh_channel</c> process receive loop and become a
+ enter 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 proc_lib, see <seealso
marker="stdlib:proc_lib">proc_lib(3)</seealso>. The
user is responsible for any initialization of the process
- and needs to call ssh_channel:init/1.
+ and needs to call <seealso mark = "#init-1">ssh_channel:init/1</seealso>
</p>
</desc>
</func>
@@ -126,7 +133,10 @@
<name>init(Options) -> {ok, State} | {ok, State, Timeout} | {stop, Reason} </name>
<fsummary> Initiates a ssh_channel process.</fsummary>
<type>
- <v> Options = [{Option, Value}]</v>
+ <v>Options = [{Option, Value}]</v>
+ <v>State = term()</v>
+ <v>Timeout = timeout() </v>
+ <v>Reason = term() </v>
</type>
<desc>
<p>
@@ -134,24 +144,27 @@
</p>
<taglist>
<tag><c><![CDATA[{channel_cb, atom()}]]></c></tag>
- <item>The module that implements the channel behavior.</item>
+ <item>The module that implements the channel behaviour.</item>
<tag><c><![CDATA[{init_args(), list()}]]></c></tag>
- <item> The list of arguments to the callback modules
+ <item> The list of arguments to the callback module's
init function.</item>
<tag><c><![CDATA[{cm, connection_ref()}]]></c></tag>
- <item> Reference to the ssh connection.</item>
+ <item> Reference to the ssh connection as returned by <seealso
+ marker="ssh#connect-3">ssh:connect/3</seealso></item>
<tag><c><![CDATA[{channel_id, channel_id()}]]></c></tag>
<item> Id of the ssh channel.</item>
</taglist>
- <note><p>This function is normally not called by the user, it is
- only needed if for some reason the channel process needs
- to be started with help of <c>proc_lib</c> instead calling
- <c>ssh_channel:start/4</c> or <c>ssh_channel:start_link/4</c> </p>
+ <note><p>This function is normally not called by the
+ user. The user only needs to call if for some reason the
+ channel process needs to be started with help of
+ <c>proc_lib</c> instead of calling
+ <c>ssh_channel:start/4</c> or
+ <c>ssh_channel:start_link/4</c> </p>
</note>
</desc>
</func>
@@ -167,12 +180,12 @@
<p>This function can be used by a channel to explicitly send a
reply to a client that called <c>call/[2,3]</c> when the reply
cannot be defined in the return value of
- <c>CallbackModule:handle_call/3</c>.</p>
+ <seealso marker ="#Module:handle_call-3">Module:handle_call/3</seealso>.</p>
<p><c>Client</c> must be the <c>From</c> argument provided to
the callback function <c>handle_call/3</c>.
<c>Reply</c> is an arbitrary term,
- which will be given back to the client as the return value of
- <c>ssh_channel:call/[2,3].</c></p>
+ which will be given back to the client as the return value of
+ <seealso marker="#call-2">ssh_channel:call/[2,3].</seealso>></p>
</desc>
</func>
@@ -180,11 +193,12 @@
<name>start(SshConnection, ChannelId, ChannelCb, CbInitArgs) -> </name>
<name>start_link(SshConnection, ChannelId, ChannelCb, CbInitArgs) ->
{ok, ChannelRef} | {error, Reason}</name>
- <fsummary> Starts a processes that handles a ssh channel. </fsummary>
+ <fsummary> Starts a processes that handles a SSH channel. </fsummary>
<type>
<v>SshConnection = ssh_connection_ref()</v>
<v>ChannelId = ssh_channel_id() </v>
- <d> As returned by ssh_connection:session_channel/[2,4]</d>
+ <d> As returned by cannot be defined in the return value of
+ <seealso marker ="ssh_connection#session_channel/2">ssh_connection:session_channel/[2,4]</seealso></d>
<v>ChannelCb = atom()</v>
<d> The name of the module implementing the service specific parts
of the channel.</d>
@@ -193,10 +207,10 @@
<v>ChannelRef = pid()</v>
</type>
<desc>
- <p>Starts a processes that handles a ssh channel. Will be
- called internally by the ssh daemon or explicitly by the ssh
- client implementations. A channel process traps exit signals
- by default.
+ <p>Starts a processes that handles an SSH channel. It will be
+ called internally by the SSH daemon or explicitly by the SSH
+ client implementations. The behavior will set the
+ <c>trap_exit</c> flag to true.
</p>
</desc>
</func>
@@ -204,72 +218,61 @@
</funcs>
<section>
- <title>CALLBACK FUNCTIONS</title>
-
- <p>The functions init/1, terminate/2, handle_ssh_msg/2 and
- handle_msg/2 are the functions that are required to provide the
- implementation for a server side channel, such as a ssh subsystem
- channel that can be plugged into the erlang ssh daemon see
- <seealso marker="ssh">ssh:daemon/[2, 3]</seealso>. The
- handle_call/3, handle_cast/2 code_change/3 and enter_loop/1
- functions are only relevant when implementing a client side
- channel.</p>
- </section>
-
- <section>
<marker id="cb_timeouts"></marker>
<title> CALLBACK TIMEOUTS</title>
- <p> If an integer timeout value is provided in a return value of
- one of the callback functions, a timeout will occur unless a
- message is received within <c>Timeout</c> milliseconds. A timeout
- is represented by the atom <c>timeout</c> which should be handled
- by the <seealso marker="#handle_msg">handle_msg/2</seealso>
- callback function. The atom infinity can be used to wait
- indefinitely, this is the default value. </p>
+
+ <p>The timeout values that may be returned by the callback functions
+ has the same semantics as in a <seealso marker="stdlib#gen_server">gen_server</seealso>
+ If the timeout occurs <seealso marker="#handle_msg">handle_msg/2</seealso>
+ will be called as <c>handle_msg(timeout, State). </c></p>
</section>
<funcs>
<func>
- <name>CallbackModule:code_change(OldVsn, State, Extra) -> {ok,
+ <name>Module:code_change(OldVsn, State, Extra) -> {ok,
NewState}</name>
<fsummary> Converts process state when code is changed.</fsummary>
<type>
- <v> Converts process state when code is changed.</v>
+ <v>OldVsn = term()</v>
+ <d>In the case of an upgrade, <c>OldVsn</c> is <c>Vsn</c>, and
+ in the case of a downgrade, <c>OldVsn</c> is
+ <c>{down,Vsn}</c>. <c>Vsn</c> is defined by the <c>vsn</c>
+ attribute(s) of the old version of the callback module
+ <c>Module</c>. If no such attribute is defined, the version is
+ the checksum of the BEAM file.</d>
+ <v>State = term()</v>
+ <d>The internal state of the channel.</d>
+ <v>Extra = term()</v>
+ <d>Passed as-is from the <c>{advanced,Extra}</c>
+ part of the update instruction.</d>
</type>
<desc>
- <p>This function is called by a client side channel when it
- should update its internal state during a release
- upgrade/downgrade, i.e. when the instruction
- <c>{update,Module,Change,...}</c> where
- <c>Change={advanced,Extra}</c> is given in the <c>appup</c>
- file. See <seealso
- marker="doc/design_principles:release_handling#instr">OTP
- Design Principles</seealso> for more information. Any new
- connection will benefit from a server side upgrade but
- already started connections on the server side will not be
- affected.
- </p>
+ <p> Converts process state when code is changed.</p>
+
+ <p>This function is called by a client side channel when it
+ should update its internal state during a release
+ upgrade/downgrade, i.e. when the instruction
+ <c>{update,Module,Change,...}</c> where
+ <c>Change={advanced,Extra}</c> is given in the <c>appup</c>
+ file. See <seealso marker="doc/design_principles:release_handling#instr">OTP
+ Design Principles</seealso> for more information.
+ </p>
- <note><p>If there are long lived ssh connections and more
- than one upgrade in a short time this may cause the old
- connections to fail as only two versions of the code may
- be loaded simultaneously.</p></note>
+ <note><p>Soft upgrade according to the OTP release concept
+ is not straight forward for the server side, as subsystem
+ channel processes are spawned by the SSH application and
+ hence added to its supervisor tree. It could be possible to
+ upgrade the subsystem channels, when upgrading the user
+ application, if the callback functions can handle two
+ versions of the state, but this function can not be used in
+ the normal way.</p>
+ </note>
- <p>In the case of an upgrade, <c>OldVsn</c> is <c>Vsn</c>, and
- in the case of a downgrade, <c>OldVsn</c> is
- <c>{down,Vsn}</c>. <c>Vsn</c> is defined by the <c>vsn</c>
- attribute(s) of the old version of the callback module
- <c>Module</c>. If no such attribute is defined, the version
- is the checksum of the BEAM file.</p>
- <p><c>State</c> is the internal state of the channel.</p>
- <p><c>Extra</c> is passed as-is from the <c>{advanced,Extra}</c>
- part of the update instruction.</p>
- <p>The function should return the updated internal state.</p>
</desc>
</func>
<func>
- <name>CallbackModule:init(Args) -> {ok, State} | {ok, State, Timeout} |
+ <name>Module:init(Args) -> {ok, State} | {ok, State, timeout()} |
{stop, Reason}</name>
<fsummary> Makes necessary initializations and returns the
initial channel state if the initializations succeed.</fsummary>
@@ -277,7 +280,6 @@
<v> Args = term() </v>
<d> Last argument to ssh_channel:start_link/4.</d>
<v> State = term() </v>
- <v>Timeout = timeout() </v>
<v> Reason = term() </v>
</type>
<desc>
@@ -290,7 +292,7 @@
</func>
<func>
- <name>CallbackModule:handle_call(Msg, From, State) -> Result</name>
+ <name>Module:handle_call(Msg, From, State) -> Result</name>
<fsummary> Handles messages sent by calling
<c>ssh_channel:call/[2,3]</c></fsummary>
<type>
@@ -298,17 +300,16 @@
<v>From = opaque to the user should be used as argument to
ssh_channel:reply/2</v>
<v>State = term()</v>
- <v>Result = {reply, Reply, NewState} | {reply, Reply, NewState, Timeout}
- | {noreply, NewState} | {noreply , NewState, Timeout}
+ <v>Result = {reply, Reply, NewState} | {reply, Reply, NewState, timeout()}
+ | {noreply, NewState} | {noreply , NewState, timeout()}
| {stop, Reason, Reply, NewState} | {stop, Reason, NewState} </v>
<v>Reply = term() - will be the return value of ssh_channel:call/[2,3]</v>
- <v>Timeout = timeout() </v>
- <v>NewState = term() - a possible updated version of State</v>
+ <v>NewState = term()</v>
<v>Reason = term()</v>
</type>
<desc>
<p>Handles messages sent by calling
- <c>ssh_channel:call/[2,3]</c>
+ <seealso marker="#call-2">ssh_channel:call/[2,3]</seealso>
</p>
<p>For more detailed information on timeouts see the section
<seealso marker="#cb_timeouts">CALLBACK TIMEOUTS</seealso>. </p>
@@ -316,16 +317,15 @@
</func>
<func>
- <name>CallbackModule:handle_cast(Msg, State) -> Result</name>
+ <name>Module:handle_cast(Msg, State) -> Result</name>
<fsummary> Handles messages sent by calling
<c>ssh_channel:cact/2</c></fsummary>
<type>
<v>Msg = term()</v>
<v>State = term()</v>
- <v>Result = {noreply, NewState} | {noreply, NewState, Timeout}
+ <v>Result = {noreply, NewState} | {noreply, NewState, timeout()}
| {stop, Reason, NewState}</v>
- <v>NewState = term() - a possible updated version of State</v>
- <v>Timeout = timeout() </v>
+ <v>NewState = term() </v>
<v>Reason = term()</v>
</type>
<desc>
@@ -339,7 +339,7 @@
</func>
<func>
- <name>CallbackModule:handle_msg(Msg, State) -> {ok, State} |
+ <name>Module:handle_msg(Msg, State) -> {ok, State} |
{stop, ChannelId, State}</name>
<fsummary> Handle other messages than ssh connection protocol,
@@ -359,136 +359,37 @@
<taglist>
<tag><c><![CDATA[{ssh_channel_up, ssh_channel_id(),
ssh_connection_ref()}]]></c></tag>
- <item>This is the first messages that will be received
- by the channel, it is sent just before
- the ssh_channel:init/1 function returns successfully.
- This is especially useful if the server wants
- to send a message to the client without first receiving
- a message from the client. If the message is not useful
- for your particular problem just ignore it by immediately
- returning {ok, State}.
+ <item>This is the first messages that will be received by
+ the channel, it is sent just before the <seealso
+ marker="#init-2">ssh_channel:init/1</seealso> function
+ returns successfully. This is especially useful if the
+ server wants to send a message to the client without first
+ receiving a message from it. If the message is not
+ useful for your particular scenario just ignore it by
+ immediately returning {ok, State}.
</item>
</taglist>
</desc>
</func>
<func>
- <name>CallbackModule:handle_ssh_msg(Msg, State) -> {ok, State} | {stop,
+ <name>Module:handle_ssh_msg(Msg, State) -> {ok, State} | {stop,
ssh_channel_id(), State}</name>
<fsummary> Handles ssh connection protocol messages. </fsummary>
<type>
- <v>Msg = {ssh_cm, ssh_connection_ref(), SshMsg}</v>
- <v> SshMsg = tuple() - see message list below</v>
+ <v>Msg = <seealso marker="ssh_connection"> ssh_connection:event() </seealso> </v>
<v>State = term()</v>
</type>
<desc>
<p> Handles ssh connection protocol messages that may need
service specific attention.
</p>
-
- <p> All channels should handle the following messages. For
- channels implementing subsystems the handle_ssh_msg-callback
- will not be called for any other messages. </p>
-
- <taglist>
- <tag><c><![CDATA[{ssh_cm, ssh_connection_ref(), {data, ssh_channel_id(),
- ssh_data_type_code(), binary() = Data}}]]></c></tag>
- <item> Data has arrived on the channel. When the callback
- for this message returns the channel behavior will adjust
- the ssh flow control window.</item>
-
- <tag><c><![CDATA[{ssh_cm, ssh_connection_ref(), {eof,
- ssh_channel_id()}}]]></c></tag>
- <item>Indicteas that the other side will not send any more
- data.</item>
-
- <tag><c><![CDATA[{ssh_cm, ssh_connection_ref(), {signal,
- ssh_channel_id(), ssh_signal()}} ]]></c></tag>
- <item>A signal can be delivered to the remote
- process/service using the following message. Some systems
- may not implement signals, in which case they should ignore
- this message.</item>
-
- <tag><c><![CDATA[{ssh_cm, ssh_connection_ref(),
- {exit_signal, ssh_channel_id(), string() = exit_signal,
- string() = ErrorMsg, string() =
- LanguageString}}]]></c></tag>
- <item>A remote execution may terminate violently due to a
- signal then this message may be received. For details on valid string
- values see RFC 4254 section 6.10</item>
-
- <tag><c><![CDATA[{ssh_cm, ssh_connection_ref(), {exit_status,
- ssh_channel_id(), integer() = ExitStatus}}]]></c></tag>
- <item> When the command running at the other end terminates,
- the following message can be sent to return the exit status
- of the command. A zero 'exit_status' usually means that the
- command terminated successfully.</item>
- </taglist>
-
- <p> Channels implementing a shell and command execution on the server side
- should also handle the following messages. </p>
-
- <taglist>
- <tag><c><![CDATA[{ssh_cm, ssh_connection_ref(), {env, ssh_channel_id(),
- boolean() = WantReply, string() = Var, string() = Value}}]]></c></tag>
- <item> Environment variables may be passed to the
- shell/command to be started later. Note that before the
- callback returns it should call the function
- ssh_connection:reply_request/4 with the boolean value of <c>
- WantReply</c> as the second argument.
- </item>
-
- <tag><c><![CDATA[{ssh_cm, ConnectionRef, {exec, ssh_channel_id(),
- boolean() = WantReply, string() = Cmd}}]]></c></tag>
- <item> This message will request that the server start the
- execution of the given command. Note that before the
- callback returns it should call the function
- ssh_connection:reply_request/4 with the boolean value of <c>
- WantReply</c> as the second argument.</item>
-
- <tag><c><![CDATA[{ssh_cm, ssh_connection_ref(), {pty, ssh_channel_id(),
- boolean() = WantReply, {string() = Terminal, integer() = CharWidth,
- integer() = RowHeight, integer() = PixelWidth, integer() = PixelHight,
- [{atom() | integer() = Opcode,
- integer() = Value}] = TerminalModes}}}]]></c></tag>
- <item>A pseudo-terminal has been requested for the
- session. Terminal is the value of the TERM environment
- variable value (e.g., vt100). Zero dimension parameters must
- be ignored. The character/row dimensions override the pixel
- dimensions (when nonzero). Pixel dimensions refer to the
- drawable area of the window. The <c>Opcode</c> in the
- <c>TerminalModes</c> list is the mnemonic name, represented
- as an lowercase erlang atom, defined in RFC 4254 section 8,
- or the opcode if the mnemonic name is not listed in the
- RFC. Example <c>OP code: 53, mnemonic name ECHO erlang atom:
- echo</c>. Note that before the callback returns it should
- call the function ssh_connection:reply_request/4 with the
- boolean value of <c> WantReply</c> as the second
- argument.</item>
-
- <tag><c><![CDATA[{ssh_cm, ConnectionRef, {shell, boolean() =
- WantReply}}]]></c></tag>
- <item> This message will request that the user's default
- shell be started at the other end. Note that before the
- callback returns it should call the function
- ssh_connection:reply_request/4 with the value of <c>
- WantReply</c> as the second argument.
- </item>
-
- <tag><c><![CDATA[ {ssh_cm, ssh_connection_ref(), {window_change,
- ssh_channel_id(), integer() = CharWidth, integer() = RowHeight,
- integer() = PixWidth, integer() = PixHeight}}]]></c></tag>
- <item> When the window (terminal) size changes on the client
- side, it MAY send a message to the other side to inform it
- of the new dimensions.</item>
- </taglist>
<p> The following message is completely taken care of by the
ssh channel behavior</p>
<taglist>
- <tag><c><![CDATA[{ssh_cm, ssh_connection_ref(), {closed,
- ssh_channel_id()}}]]></c></tag>
+ <tag><c><![CDATA[{closed, ssh_channel_id()}]]></c></tag>
<item> The channel behavior will send a close message to the
other side if such a message has not already been sent and
then terminate the channel with reason normal.</item>
@@ -497,7 +398,7 @@
</func>
<func>
- <name>CallbackModule:terminate(Reason, State) -> _</name>
+ <name>Module:terminate(Reason, State) -> _</name>
<fsummary> </fsummary>
<type>
<v>Reason = term()</v>
@@ -505,12 +406,12 @@
</type>
<desc>
<p>This function is called by a channel process when it is
- about to terminate. Before this function is called ssh_connection:close/2
- will be called if it has not been called earlier.
- This function should be the opposite of <c>CallbackModule:init/1</c>
- and do any necessary cleaning up. When it returns, the
- channel process terminates with reason <c>Reason</c>. The return value is
- ignored.
+ about to terminate. Before this function is called <seealso
+ marker="ssh_connection#close-2"> ssh_connection:close/2
+ </seealso> will be called if it has not been called earlier.
+ This function should do any necessary cleaning
+ up. When it returns, the channel process terminates with
+ reason <c>Reason</c>. The return value is ignored.
</p>
</desc>
</func>
diff --git a/lib/ssh/doc/src/ssh_client_key_api.xml b/lib/ssh/doc/src/ssh_client_key_api.xml
new file mode 100644
index 0000000000..abc1070e78
--- /dev/null
+++ b/lib/ssh/doc/src/ssh_client_key_api.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="iso-8859-1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2012</year>
+ <holder>Ericsson AB, All Rights Reserved</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ The Initial Developer of the Original Code is Ericsson AB.
+ </legalnotice>
+ <title>ssh_client_key_api</title>
+ </header>
+ <module>ssh_client_key_api</module>
+ <modulesummary>
+ -behaviour(ssh_client_key_api).
+ </modulesummary>
+ <description>
+ <p> Behavior describing the API for an SSH client's public key handling.
+ By implementing the callbacks defined.
+ in this behavior it is possible to customize the SSH client's public key
+ handling. By default the SSH application implements this behavior
+ with help of the standard openssh files, see <seealso marker="SSH_app"> ssh(6)</seealso>. </p>
+ </description>
+
+ <section>
+ <title>DATA TYPES </title>
+
+ <p>Type definitions that are used more than once in this module
+ and/or abstractions to indicate the intended use of the data
+ type:</p>
+
+ <p> boolean() = true | false</p>
+ <p> string() = [byte()] </p>
+ <p> public_key() = #'RSAPublicKey'{}| {integer(), #'Dss-Parms'{}}| term()</p>
+ <p> private_key() = #'RSAPublicKey'{}| {integer(), #'Dss-Parms'{}}| term()</p>
+ <p> public_key_algorithm() = 'ssh-rsa'| 'ssh-dss' | atom()</p>
+
+ </section>
+
+ <funcs>
+ <func>
+ <name>Module:add_host_key(HostNames, Key, ConnectOptions) -> ok | {error, Reason}</name>
+ <fsummary>Adds a host key to the set of trusted host keys</fsummary>
+ <type>
+ <v>HostNames = string()</v>
+ <d>Description of the host that owns the <c>PublicKey</c></d>
+
+ <v>Key = public_key() </v>
+ <d> Normally an RSA or DSA public key but handling of other public keys can be added</d>
+
+ <v>ConnectOptions = proplists:proplist() </v>
+ <d>Options provided to <seealso marker="ssh#daemon">ssh:connect/[3,4]</seealso></d>
+ <v>Reason = term() </v>
+ </type>
+ <desc>
+ <p> Adds a host key to the set of trusted host keys</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:is_host_key(Key, Host, Algorithm, ConnectOptions) -> Result</name>
+ <fsummary>Checks if a host key is trusted</fsummary>
+ <type>
+ <v>Key = public_key() </v>
+ <d> Normally an RSA or DSA public key but handling of other public keys can be added</d>
+
+ <v>Host = string()</v>
+ <d>Description of the host</d>
+
+ <v>Algorithm = public_key_algorithm()</v>
+ <d> Host key algorithm. Should support 'ssh-rsa'| 'ssh-dss' but additional algorithms
+ can be handled.</d>
+
+ <v> ConnectOptions = proplists:proplist() </v>
+ <d>Options provided to <seealso marker="ssh#daemon">ssh:connect/[3,4]</seealso></d>
+
+ <v> Result = boolean()</v>
+ </type>
+ <desc>
+ <p>Checks if a host key is trusted</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:user_key(Algorithm, ConnectOptions) ->
+ {ok, PrivateKey} | {error, Reason}</name>
+ <fsummary>Fetches the users "public key" matching the <c>Algorithm</c>.</fsummary>
+ <type>
+ <v>Algorithm = public_key_algorithm()</v>
+ <d> Host key algorithm. Should support 'ssh-rsa'| 'ssh-dss' but additional algorithms
+ can be handled.</d>
+
+ <v> ConnectOptions = proplists:proplist() </v>
+ <d>Options provided to <seealso marker="ssh#daemon">ssh:connect/[3,4]</seealso></d>
+
+ <v> PrivateKey = private_key()</v>
+ <d> The private key of the user matching the <c>Algorithm</c></d>
+
+ <v>Reason = term() </v>
+ </type>
+
+ <desc>
+ <p>Fetches the users "public key" matching the <c>Algorithm</c>.
+ <note>The private key contains the public key</note>
+ </p>
+ </desc>
+ </func>
+
+ </funcs>
+
+</erlref>
diff --git a/lib/ssh/doc/src/ssh_connection.xml b/lib/ssh/doc/src/ssh_connection.xml
index 9942306b93..c66622307f 100644
--- a/lib/ssh/doc/src/ssh_connection.xml
+++ b/lib/ssh/doc/src/ssh_connection.xml
@@ -1,11 +1,11 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
<year>2008</year>
- <year>2011</year>
+ <year>2012</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -24,69 +24,178 @@
</legalnotice>
<title>ssh_connection</title>
- <prepared>Ingela Anderton Andin</prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
<date></date>
- <rev></rev>
</header>
<module>ssh_connection</module>
- <modulesummary>This module provides an API to the ssh connection protocol.
+ <modulesummary>This module provides API functions to send <url href="http://www.ietf.org/rfc/rfc4254.txt"> SSH Connection Protocol </url>
+ events to the other side of an SSH channel.
</modulesummary>
+
<description>
- <p>This module provides an API to the ssh connection protocol.
- Not all features of the connection protocol are officially supported yet.
- Only the ones supported are documented here.</p>
+ <p>The SSH Connection Protocol is used by clients and servers
+ (i.e. SSH channels) to communicate over the SSH connection. The
+ API functions in this module sends SSH Connection Protocol events
+ that are received as messages by the remote channel.
+ In the case that the receiving channel is an Erlang process the
+ message will be on the following format
+ <c><![CDATA[{ssh_cm, ssh_connection_ref(), ssh_event_msg()}]]></c>. If the <seealso
+ marker="ssh_channel">ssh_channel</seealso> behavior is used to
+ implement the channel process these will be handled by
+ <seealso
+ marker="ssh_channel#CallbackModule:handled_ssh_msg-2">handle_ssh_msg/2 </seealso>.</p>
</description>
- <section>
- <title>COMMON DATA TYPES </title>
+ <section>
+ <title>DATA TYPES </title>
+
<p>Type definitions that are used more than once in this module and/or
abstractions to indicate the intended use of the data type:</p>
-
+
<p><c>boolean() = true | false </c></p>
<p><c>string() = list of ASCII characters</c></p>
<p><c>timeout() = infinity | integer() - in milliseconds.</c></p>
<p><c>ssh_connection_ref() - opaque to the user returned by
- ssh:connect/3 or sent to a ssh channel processes</c></p>
+ ssh:connect/3 or sent to an SSH channel processes</c></p>
<p><c>ssh_channel_id() = integer() </c></p>
<p><c>ssh_data_type_code() = 1 ("stderr") | 0 ("normal") are
- currently valid values see RFC 4254 section 5.2.</c></p>
+ currently valid values see</c> <url href="http://www.ietf.org/rfc/rfc4254.txt">RFC 4254 </url> section 5.2.</p>
<p><c>ssh_request_status() = success | failure</c></p>
- </section>
+ <p><c>event() = {ssh_cm, ssh_connection_ref(), ssh_event_msg()} </c></p>
+ <p><c>ssh_event_msg() = data_events() | status_events() | terminal_events() </c></p>
+
+ <taglist>
+ <tag><b>data_events()</b></tag>
+ <item>
+ <taglist>
+ <tag><c><![CDATA[{data, ssh_channel_id(), ssh_data_type_code(), binary() = Data}]]></c></tag>
+ <item> Data has arrived on the channel. This event is sent as
+ result of calling <seealso marker="#send-3"> ssh_connection:send/[3,4,5] </seealso></item>
+
+ <tag><c><![CDATA[{eof, ssh_channel_id()}]]></c></tag>
+ <item>Indicates that the other side will not send any more
+ data. This event is sent as result of calling <seealso
+ marker="#send_eof-2"> ssh_connection:send_eof/2</seealso>
+ </item>
+ </taglist>
+ </item>
+
+ <tag><b>status_events()</b></tag>
+ <item>
+
+ <taglist>
+ <tag><c><![CDATA[{signal, ssh_channel_id(), ssh_signal()}]]></c></tag>
+ <item>A signal can be delivered to the remote process/service
+ using the following message. Some systems will not support
+ signals, in which case they should ignore this message. There is
+ currently no funtion to generate this event as the signals
+ refered to are on OS-level and not something generated by an
+ Erlang program.</item>
+
+ <tag><c><![CDATA[{exit_signal, ssh_channel_id(), string() = ExitSignal, string() = ErrorMsg,
+ string() = LanguageString}]]></c></tag>
+
+ <item>A remote execution may terminate violently due to a signal
+ then this message may be received. For details on valid string
+ values see <url href="http://www.ietf.org/rfc/rfc4254.txt">RFC 4254</url> section 6.10. Special case of the signals
+ mentioned above.</item>
+
+ <tag><c><![CDATA[{exit_status, ssh_channel_id(), integer() = ExitStatus}]]></c></tag>
+ <item> When the command running at the other end terminates, the
+ following message can be sent to return the exit status of the
+ command. A zero 'exit_status' usually means that the command
+ terminated successfully. This event is sent as result of calling
+ <seealso marker="#exit_status">
+ ssh_connection:exit_status/3</seealso></item>
+
+ <tag><c><![CDATA[{closed, ssh_channel_id()}]]></c></tag>
+ <item> This event is sent as result of calling
+ <seealso marker="#close">ssh_connection:close/2</seealso> Both the handling of this
+ event and sending of it will be taken care of by the
+ <seealso marker="ssh_channel">ssh_channel</seealso> behavior.</item>
+
+ </taglist>
+ </item>
- <section>
- <title>MESSAGES SENT TO CHANNEL PROCESSES</title>
+ <tag><b>terminal_events()</b></tag>
+
+ <item>
+ <p> Channels implementing a shell and command execution on the
+ server side should handle the following messages that may be sent by client channel processes. </p>
+
+ <p><note>Events that includes a <c> WantReply</c> expects the event handling
+ process to call <seealso marker="#reply_request">ssh_connection:reply_request/4</seealso>
+ with the boolean value of <c> WantReply</c> as the second
+ argument. </note> </p>
+
+ <taglist>
+ <tag><c><![CDATA[{env, ssh_channel_id(), boolean() = WantReply,
+ string() = Var, string() = Value}]]></c></tag>
+ <item> Environment variables may be passed to the shell/command
+ to be started later. This event is sent as result of calling <seealso
+ marker="#setenv"> ssh_connection:setenv/5</seealso>
+ </item>
+
+ <tag><c><![CDATA[{pty, ssh_channel_id(),
+ boolean() = WantReply, {string() = Terminal, integer() = CharWidth,
+ integer() = RowHeight, integer() = PixelWidth, integer() = PixelHight,
+ [{atom() | integer() = Opcode,
+ integer() = Value}] = TerminalModes}}]]></c></tag>
+ <item>A pseudo-terminal has been requested for the
+ session. Terminal is the value of the TERM environment
+ variable value (e.g., vt100). Zero dimension parameters must
+ be ignored. The character/row dimensions override the pixel
+ dimensions (when nonzero). Pixel dimensions refer to the
+ drawable area of the window. The <c>Opcode</c> in the
+ <c>TerminalModes</c> list is the mnemonic name, represented
+ as an lowercase erlang atom, defined in
+ <url href="http://www.ietf.org/rfc/rfc4254.txt">RFC 4254 </url> section 8,
+ or the opcode if the mnemonic name is not listed in the
+ RFC. Example <c>OP code: 53, mnemonic name ECHO erlang atom:
+ echo</c>. There is currently no API function to generate this
+ event.</item>
+
+ <tag><c><![CDATA[{shell, boolean() = WantReply}]]></c></tag>
+ <item> This message will request that the user's default shell
+ be started at the other end. This event is sent as result of calling <seealso
+ marker="#shell"> ssh_connection:shell/2</seealso>
+ </item>
+
+ <tag><c><![CDATA[{window_change, ssh_channel_id(), integer() = CharWidth,
+ integer() = RowHeight, integer() = PixWidth, integer() = PixHeight}]]></c></tag>
+ <item> When the window (terminal) size changes on the client
+ side, it MAY send a message to the server side to inform it of
+ the new dimensions. There is currently no API function to generate this
+ event.</item>
- <p>As a result of the ssh connection protocol messages on the form
- <c><![CDATA[{ssh_cm, ssh_connection_ref(), term()}]]></c>
- will be sent to a channel process. The term will contain
- information regarding the ssh connection protocol event,
- for details see the ssh channel behavior callback <seealso
- marker="ssh_channel">handle_ssh_msg/2 </seealso> </p>
- </section>
-
- <funcs>
+ <tag><c><![CDATA[{exec, ssh_channel_id(),
+ boolean() = WantReply, string() = Cmd}]]></c></tag>
+ <item> This message will request that the server starts
+ execution of the given command. This event is sent as result of calling <seealso
+ marker="#exec">ssh_connection:exec/4 </seealso>
+ </item>
+ </taglist>
+ </item>
+ </taglist>
+ </section>
+
+ <funcs>
<func>
<name>adjust_window(ConnectionRef, ChannelId, NumOfBytes) -> ok</name>
- <fsummary>Adjusts the ssh flowcontrol window. </fsummary>
+ <fsummary>Adjusts the SSH flowcontrol window. </fsummary>
<type>
<v> ConnectionRef = ssh_connection_ref() </v>
<v> ChannelId = ssh_channel_id() </v>
<v> NumOfBytes = integer()</v>
</type>
<desc>
- <p>Adjusts the ssh flowcontrol window. </p>
+ <p>Adjusts the SSH flowcontrol window. This shall be done by both client and server side channel processes.</p>
- <note><p>This will be taken care of by the ssh_channel
- behavior when the callback <seealso marker="ssh_channel">
- handle_ssh_msg/2 </seealso> has returned after processing a
- {ssh_cm, ssh_connection_ref(), {data, ssh_channel_id(),
- ssh_data_type_code(), binary()}}
- message, and should normally not be called explicitly.</p></note>
+ <note><p>Channels implemented with the <seealso marker="ssh_channel"> ssh_channel
+ behavior</seealso> will normaly not need to call this function as flow control
+ will be handled by the behavior. The behavior will adjust the window every time
+ the callback <seealso marker="ssh_channel#handled_ssh_msg-2">
+ handle_ssh_msg/2 </seealso> has returned after processing channel data</p> </note>
</desc>
</func>
@@ -98,20 +207,19 @@
<v> ChannelId = ssh_channel_id()</v>
</type>
<desc>
- <p>Sends a close message on the channel <c>ChannelId</c>
+ <p>A server or client channel process can choose to close their session by sending a close event.
</p>
- <note><p>This function will be called by the ssh channel
+ <note><p>This function will be called by the ssh_channel
behavior when the channel is terminated see <seealso
- marker="ssh_channel"> ssh_channel(3) </seealso> and should
- normally not be called explicitly.</p></note>
+ marker="ssh_channel"> ssh_channel(3) </seealso> so channels implemented with the
+ behavior should not call this function explicitly.</p></note>
</desc>
</func>
<func>
<name>exec(ConnectionRef, ChannelId, Command, TimeOut) -> ssh_request_status() </name>
- <fsummary>Will request that the server start the
- execution of the given command. </fsummary>
+ <fsummary>Request that the server start the execution of the given command. </fsummary>
<type>
<v> ConnectionRef = ssh_connection_ref() </v>
<v> ChannelId = ssh_channel_id()</v>
@@ -119,44 +227,39 @@
<v>Timeout = timeout() </v>
</type>
<desc>
- <p>Will request that the server start the execution of the
- given command, the result will be received as:</p>
+ <p>Should be called by a client channel process to request that the server starts execution of the
+ given command, the result will be several messages according to the following pattern. Note
+ that the last message will be a channel close message, as the exec request is a one time
+ execution that closes the channel when it is done.</p>
<taglist>
- <tag><c> N X {ssh_cm,
- ssh_connection_ref(), {data, ssh_channel_id(), ssh_data_type_code(),
- binary() = Data}} </c></tag>
+ <tag><c> N x {ssh_cm, ssh_connection_ref(),
+ {data, ssh_channel_id(), ssh_data_type_code(), binary() = Data}} </c></tag>
<item>The result of executing the command may be only one line
or thousands of lines depending on the command.</item>
- <tag><c> 1 X {ssh_cm, ssh_connection_ref(), {eof, ssh_channel_id()}}</c></tag>
+ <tag><c>0 or 1 x {ssh_cm, ssh_connection_ref(), {eof, ssh_channel_id()}}</c></tag>
<item>Indicates that no more data will be sent.</item>
- <tag><c>0 or 1 X {ssh_cm,
+ <tag><c>0 or 1 x {ssh_cm,
ssh_connection_ref(), {exit_signal,
ssh_channel_id(), string() = ExitSignal, string() = ErrorMsg, string() = LanguageString}}</c></tag>
<item>Not all systems send signals. For details on valid string
values see RFC 4254 section 6.10 </item>
- <tag><c>0 or 1 X {ssh_cm, ssh_connection_ref(), {exit_status,
+ <tag><c>0 or 1 x {ssh_cm, ssh_connection_ref(), {exit_status,
ssh_channel_id(), integer() = ExitStatus}}</c></tag>
<item>It is recommended by the <c>ssh connection protocol</c> that this
message shall be sent, but that may not always be the case.</item>
- <tag><c> 1 X {ssh_cm, ssh_connection_ref(),
+ <tag><c> 1 x {ssh_cm, ssh_connection_ref(),
{closed, ssh_channel_id()}}</c></tag>
<item>Indicates that the ssh channel started for the
execution of the command has now been shutdown.</item>
</taglist>
-
- <p> These message should be handled by the
- client. The <seealso marker="ssh_channel">ssh channel
- behavior</seealso> can be used when writing a client.
- </p>
</desc>
</func>
-
<func>
<name>exit_status(ConnectionRef, ChannelId, Status) -> ok</name>
<fsummary>Sends the exit status of a command to the client.</fsummary>
@@ -166,12 +269,12 @@
<v> Status = integer()</v>
</type>
<desc>
- <p>Sends the exit status of a command to the client.</p>
+ <p>Should be called by a server channel process to sends the exit status of a command to the client.</p>
</desc>
- </func>
+ </func>
<func>
- <name>reply_request(ConnectionRef, WantReply, Status, CannelId) -> ok</name>
+ <name>reply_request(ConnectionRef, WantReply, Status, ChannelId) -> ok</name>
<fsummary>Send status replies to requests that want such replies. </fsummary>
<type>
<v> ConnectionRef = ssh_connection_ref() </v>
@@ -183,10 +286,9 @@
<p>Sends status replies to requests where the requester has
stated that they want a status report e.i .<c> WantReply = true</c>,
if <c> WantReply</c> is false calling this function will be a
- "noop". Should be called after handling an ssh connection
+ "noop". Should be called while handling an ssh connection
protocol message containing a <c>WantReply</c> boolean
- value. See the ssh_channel behavior callback <seealso
- marker="ssh_channel"> handle_ssh_msg/2 </seealso>
+ value.
</p>
</desc>
</func>
@@ -196,7 +298,7 @@
<name>send(ConnectionRef, ChannelId, Data, Timeout) -></name>
<name>send(ConnectionRef, ChannelId, Type, Data) -></name>
<name>send(ConnectionRef, ChannelId, Type, Data, TimeOut) ->
- ok | {error, timeout}</name>
+ ok | {error, timeout} | {error, closed}</name>
<fsummary>Sends channel data </fsummary>
<type>
<v> ConnectionRef = ssh_connection_ref() </v>
@@ -206,13 +308,13 @@
<v> Timeout = timeout()</v>
</type>
<desc>
- <p>Sends channel data.
+ <p>Should be called by client- and server channel processes to send data to each other.
</p>
</desc>
</func>
<func>
- <name>send_eof(ConnectionRef, ChannelId) -> ok </name>
+ <name>send_eof(ConnectionRef, ChannelId) -> ok | {error, closed}</name>
<fsummary>Sends eof on the channel <c>ChannelId</c>. </fsummary>
<type>
<v> ConnectionRef = ssh_connection_ref() </v>
@@ -228,9 +330,7 @@
<name>session_channel(ConnectionRef, Timeout) -> </name>
<name>session_channel(ConnectionRef, InitialWindowSize,
MaxPacketSize, Timeout) -> {ok, ssh_channel_id()} | {error, Reason}</name>
- <fsummary>Opens a channel for a ssh session. A session is a
- remote execution of a program. The program may be a shell, an
- application, a system command, or some built-in subsystem. </fsummary>
+ <fsummary>Opens a channel for a ssh session. </fsummary>
<type>
<v> ConnectionRef = ssh_connection_ref()</v>
<v> InitialWindowSize = integer() </v>
@@ -239,9 +339,8 @@
<v> Reason = term() </v>
</type>
<desc>
- <p>Opens a channel for a ssh session. A session is a
- remote execution of a program. The program may be a shell, an
- application, a system command, or some built-in subsystem.
+ <p>Opens a channel for an SSH session. The channel id returned from this function
+ is the id used as input to the other funtions in this module.
</p>
</desc>
</func>
@@ -258,8 +357,8 @@
<v> Timeout = timeout()</v>
</type>
<desc>
- <p> Environment variables may be passed to the shell/command to be
- started later.
+ <p> Environment variables may be passed before starting the
+ shell/command. Should be called by a client channel processes.
</p>
</desc>
</func>
@@ -267,17 +366,16 @@
<func>
<name>shell(ConnectionRef, ChannelId) -> ssh_request_status()
</name>
- <fsummary> Will request that the user's default shell (typically
- defined in /etc/passwd in UNIX systems) be started at the other
+ <fsummary> Requests that the user's default shell (typically
+ defined in /etc/passwd in UNIX systems) shall be executed at the server
end. </fsummary>
<type>
<v> ConnectionRef = ssh_connection_ref() </v>
<v> ChannelId = ssh_channel_id()</v>
</type>
<desc>
- <p> Will request that the user's default shell (typically
- defined in /etc/passwd in UNIX systems) be started at the
- other end.
+ <p> Should be called by a client channel process to request that the user's default shell (typically
+ defined in /etc/passwd in UNIX systems) shall be executed at the server end.
</p>
</desc>
</func>
@@ -292,7 +390,7 @@
<v> Timeout = timeout()</v>
</type>
<desc>
- <p> Sends a request to execute a predefined subsystem.
+ <p> Should be called by a client channel process for requesting to execute a predefined subsystem on the server.
</p>
</desc>
</func>
diff --git a/lib/ssh/doc/src/ssh_protocol.xml b/lib/ssh/doc/src/ssh_protocol.xml
new file mode 100644
index 0000000000..28f42f5707
--- /dev/null
+++ b/lib/ssh/doc/src/ssh_protocol.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="iso-8859-1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+<!-- %EricssonCopyright% -->
+<chapter>
+ <header>
+ <copyright>
+ <year>2013</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The program may be used and/or copied only with the written permission from
+ Ericsson AB, or in accordance with the terms and conditions stipulated in
+ the agreement/contract under which the program has been supplied.
+ </legalnotice>
+ <title>Secure Shell (SSH)</title>
+ <prepared>OTP</prepared>
+ <date></date>
+ <rev>%VSN%</rev>
+ <file>ssh_protocol.xml</file>
+ </header>
+
+ <section>
+ <title>SSH Protocol Overview</title>
+
+ <p> Conceptually the SSH protocol can be partitioned into four
+ layers:</p>
+
+ <image file="SSH_protocols.png">
+ <icaption>SSH Protocol Architecture</icaption>
+ </image>
+
+ <section>
+ <title>Transport Protocol</title>
+
+ <p> The SSH Transport Protocol is a secure, low level transport.
+ It provides strong encryption, cryptographic host
+ authentication and integrity protection. Currently, only a
+ minimum of MAC- (message authentication code, a short piece of
+ information used to authenticate a message) and encryption
+ algorithms are supported see <seealso marker="ssh">ssh(3)</seealso>
+ </p>
+ </section>
+
+ <section>
+ <title>Authentication Protocol</title>
+
+ <p>The SSH authentication protocol is a general-purpose user
+ authentication protocol run over the SSH transport
+ protocol. Erlang SSH supports user authentication using public
+ key technology (RSA and DSA, X509-certificates are currently not
+ supported). It is also possible to use a so called keyboard
+ interactive authentication. This method is suitable for
+ interactive authentication methods that do not need any special
+ software support on the client side. Instead, all authentication
+ data should be entered via the keyboard. It is also possible
+ to use a pure password based authentication scheme, note that in
+ this case the the plain text password will be encrypted before sent
+ over the network. There are several configuration options for
+ authentication handling available in
+ <seealso marker="ssh#connect-3">ssh:connect/[3,4]</seealso>
+ and <seealso marker="ssh#daemon-2">ssh:daemon/[2,3]</seealso>
+ It is also possible to customize the public key handling
+ by implementing the behaviours <seealso
+ marker="ssh_client_key_api">ssh_client_key_api</seealso> and
+ <seealso
+ marker="ssh_server_key_api">ssh_server_key_api</seealso>
+ </p>
+ </section>
+
+ <section>
+ <title>Connection Protocol</title>
+
+ <p>The SSH Connection Protocol provides application-support
+ services over the transport pipe, such as channel multiplexing,
+ flow control, remote program execution, signal propagation,
+ connection forwarding, etc. Functions for handling the SSH
+ Connection Protocol can be found in the module <seealso
+ marker="ssh_connection">ssh_connection</seealso>.
+ </p>
+ </section>
+
+ <section>
+ <title>Channels</title>
+
+ <p>All terminal sessions, forwarded connections etc., are
+ channels. Multiple channels are multiplexed into a single
+ connection, and all channels are flow-controlled. Typically an
+ SSH client will open a channel, send data/commands, receive
+ data/"control information" and when it is done close the
+ channel. The <seealso
+ marker="ssh_channel">ssh_channel</seealso> behaviour makes it easy to
+ write your own SSH client/server processes that use flow
+ control. It handles generic parts of SSH channel management and
+ lets you focus on the application logic.
+ </p>
+
+ <p>Channels comes in three flavors</p>
+
+ <list type="bulleted">
+ <item><em>Subsystem</em> - named services that can be run as
+ part of an SSH server such as SFTP <seealso
+ marker="ssh_sftpd">ssh_sftpd</seealso>, that is built in to the
+ SSH daemon (server) by default but may be disabled. The Erlang SSH
+ daemon may be configured to run any Erlang
+ implemented SSH subsystem.
+ </item>
+ <item><em>Shell</em> - interactive shell. By default the
+ Erlang daemon will run the Erlang shell. It is
+ possible to customize the shell by providing your own
+ read-eval-print loop. It is also possible, but much more work,
+ to provide your own CLI (Command Line Interface) implementation.
+ </item>
+ <item><em>Exec</em> - one-time remote execution of commands. See <seealso
+ marker="ssh_connection#exec-4">ssh_connection:exec/4</seealso></item>
+ </list>
+ </section>
+
+ <p>Channels are flow controlled. No data may be sent to a channel
+ peer until a message is received to indicate that window space is
+ available. The 'initial window size' specifies how many bytes of
+ channel data that can be sent to the channel peer without adjusting the
+ window.
+ </p>
+
+ <p>
+ For more detailed information about the SSH protocol, see the
+ following RFCs:
+ </p>
+
+ <list type="bulleted">
+ <item><url href="http://www.ietf.org/rfc/rfc4250.txt">RFC 4250</url> -
+ Protocol Assigned Numbers.</item>
+ <item><url href="http://www.ietf.org/rfc/rfc4251.txt">RFC 4251</url> -
+ Protocol Architecture.</item>
+ <item><url href="http://www.ietf.org/rfc/rfc4252.txt">RFC 4252</url> -
+ Authentication Protocol.</item>
+ <item><url href="http://www.ietf.org/rfc/rfc4253.txt">RFC 4253</url> -
+ 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> -
+ Public Key File Format.</item>
+ </list>
+ </section>
+</chapter>
diff --git a/lib/ssh/doc/src/ssh_server_key_api.xml b/lib/ssh/doc/src/ssh_server_key_api.xml
new file mode 100644
index 0000000000..78ff105387
--- /dev/null
+++ b/lib/ssh/doc/src/ssh_server_key_api.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="iso-8859-1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2012</year>
+ <holder>Ericsson AB, All Rights Reserved</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ The Initial Developer of the Original Code is Ericsson AB.
+ </legalnotice>
+ <title>ssh_server_key_api</title>
+ </header>
+ <module>ssh_server_key_api</module>
+ <modulesummary>
+ -behaviour(ssh_server_key_api).
+ </modulesummary>
+ <description>
+ <p> Behaviour describing the API for an SSH server's public key handling.By implementing the callbacks defined
+ in this behavior it is possible to customize the SSH server's public key
+ handling. By default the SSH application implements this behavior
+ with help of the standard openssh files, see <seealso marker="SSH_app"> ssh(6)</seealso>.</p>
+ </description>
+
+ <section>
+ <title>DATA TYPES </title>
+
+ <p>Type definitions that are used more than once in this module
+ and/or abstractions to indicate the intended use of the data
+ type:</p>
+
+ <p> boolean() = true | false</p>
+ <p> string() = [byte()]</p>
+ <p> public_key() = #'RSAPublicKey'{}| {integer(), #'Dss-Parms'{}}| term()</p>
+ <p> private_key() = #'RSAPublicKey'{}| {integer(), #'Dss-Parms'{}}| term()</p>
+ <p> public_key_algorithm() = 'ssh-rsa'| 'ssh-dss' | atom()</p>
+ </section>
+
+ <funcs>
+ <func>
+ <name>Module:host_key(Algorithm, DaemonOptions) ->
+ {ok, Key} | {error, Reason}</name>
+ <fsummary>Fetches the hosts private key </fsummary>
+ <type>
+ <v>Algorithm = public_key_algorithm()</v>
+ <d> Host key algorithm. Should support 'ssh-rsa'| 'ssh-dss' but additional algorithms
+ can be handled.</d>
+ <v> DaemonOptions = proplists:proplist() </v>
+ <d>Options provided to <seealso marker="ssh#daemon">ssh:daemon/[2,3]</seealso></d>
+ <v> Key = private_key()</v>
+ <d> The private key of the host matching the <c>Algorithm</c></d>
+ <v>Reason = term() </v>
+ </type>
+ <desc>
+ <p>Fetches the hosts private key</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:is_auth_key(Key, User, DaemonOptions) -> Result</name>
+ <fsummary> Checks if the user key is authorized</fsummary>
+ <type>
+ <v> Key = public_key() </v>
+ <d> Normally an RSA or DSA public key but handling of other public keys can be added</d>
+ <v> User = string()</v>
+ <d> The user owning the public key</d>
+ <v> DaemonOptions = proplists:proplist() </v>
+ <d> Options provided to <seealso marker="ssh#daemon">ssh:daemon/[2,3]</seealso></d>
+ <v> Result = boolean()</v>
+ </type>
+ <desc>
+ <p> Checks if the user key is authorized </p>
+ </desc>
+ </func>
+
+ </funcs>
+
+</erlref>
diff --git a/lib/ssh/doc/src/ssh_sftp.xml b/lib/ssh/doc/src/ssh_sftp.xml
index c1f75461b1..0d61e57edb 100644
--- a/lib/ssh/doc/src/ssh_sftp.xml
+++ b/lib/ssh/doc/src/ssh_sftp.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>2005</year><year>2010</year>
+ <year>2005</year><year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -22,25 +22,20 @@
</legalnotice>
<title>ssh_sftp</title>
- <prepared>Jakob Cederlund</prepared>
- <responsible></responsible>
- <docno>1</docno>
- <approved></approved>
- <checked></checked>
+ <prepared>OTP</prepared>
<date>2005-09-22</date>
- <rev>PA1</rev>
<file>ssh_sftp.sgml</file>
</header>
<module>ssh_sftp</module>
<modulesummary>SFTP client.</modulesummary>
<description>
<p>This module implements an SFTP (SSH FTP) client. SFTP is a
- secure, encrypted file transfer service available for
- SSH.</p>
+ secure, encrypted file transfer service available for
+ SSH.</p>
</description>
<section>
- <title>COMMON DATA TYPES </title>
+ <title>DATA TYPES </title>
<p>Type definitions that are used more than once in this module
and/or abstractions to indicate the intended use of the data type:
</p>
@@ -51,8 +46,8 @@
<section>
<title>TIMEOUTS </title>
- <p>If the request functions for the sftp channel return {error, timeout}
- it does not mean that the request did not reach the server and was
+ <p>If the request functions for the SFTP channel return {error, timeout}
+ it does not guarantee that the request did not reach the server and was
not performed, it only means that we did not receive an answer from the
server within the time that was expected.</p>
</section>
@@ -64,7 +59,7 @@
<name>start_channel(Host, Options) -></name>
<name>start_channel(Host, Port, Options) -> {ok, Pid} | {ok, Pid, ConnectionRef} |
{error, Reason}</name>
- <fsummary>Starts a sftp client</fsummary>
+ <fsummary>Starts a SFTP client</fsummary>
<type>
<v>Host = string()</v>
<v>ConnectionRef = ssh_connection_ref()</v>
@@ -73,11 +68,11 @@
<v>Reason = term()</v>
</type>
<desc>
- <p>If not provided, setups a ssh connection in this case a
- connection reference will be returned too. A ssh channel
- process is started to handle the communication with the SFTP
- server, the returned pid for this process should be used as
- input to all other API functions in this module.</p>
+ <p>If no connection reference is provided, a connection is set
+ up and the new connection is returned. An SSH channel process
+ is started to handle the communication with the SFTP server.
+ The returned pid for this process should be used as input to
+ all other API functions in this module.</p>
<p>Options are:</p>
<taglist>
@@ -95,13 +90,13 @@
<func>
<name>stop_channel(ChannelPid) -> ok</name>
- <fsummary>Stops the sftp client channel.</fsummary>
+ <fsummary>Stops the SFTP client channel.</fsummary>
<type>
<v>ChannelPid = pid()</v>
</type>
<desc>
- <p>Stops a sftp channel. If the ssh connection should be closed
- call <seealso marker="ssh">ssh:close/1</seealso>.</p>
+ <p>Stops an SFTP channel. Does not close the SSH connetion.
+ Use <seealso marker="ssh">ssh:close/1</seealso> to close it.</p>
</desc>
</func>
@@ -133,8 +128,9 @@
<v>Reason = term()</v>
</type>
<desc>
- <p>Writes a file to the server, like <c><![CDATA[file:write_file/2]]></c>.
- The file is created if it's not there.</p>
+ <p>Writes a file to the server, like
+ <c><![CDATA[file:write_file/2]]></c>. The file is created if
+ it does not exist or is owerwritten if it does.</p>
</desc>
</func>
<func>
@@ -169,7 +165,7 @@
</type>
<desc>
<p>Opens a file on the server, and returns a handle that
- is used for reading or writing.</p>
+ can be used for reading or writing.</p>
</desc>
</func>
<func>
@@ -184,7 +180,7 @@
</type>
<desc>
<p>Opens a handle to a directory on the server, the handle
- is used for reading directory contents.</p>
+ can be used for reading directory contents.</p>
</desc>
</func>
<func>
@@ -218,7 +214,7 @@
</type>
<desc>
<p>Reads <c><![CDATA[Len]]></c> bytes from the file referenced by
- <c><![CDATA[Handle]]></c>. Returns <c><![CDATA[{ok, Data}]]></c>, or <c><![CDATA[eof]]></c>, or
+ <c><![CDATA[Handle]]></c>. Returns <c><![CDATA[{ok, Data}]]></c>, <c><![CDATA[eof]]></c>, or
<c><![CDATA[{error, Reason}]]></c>. If the file is opened with <c><![CDATA[binary]]></c>,
<c><![CDATA[Data]]></c> is a binary, otherwise it is a string.</p>
<p>If the file is read past eof, only the remaining bytes
@@ -267,9 +263,9 @@
<v>Reason = term()</v>
</type>
<desc>
- <p>Write <c><![CDATA[data]]></c> to the file referenced by <c><![CDATA[Handle]]></c>.
+ <p>Writes<c><![CDATA[data]]></c> to the file referenced by <c><![CDATA[Handle]]></c>.
The file should be opened with <c><![CDATA[write]]></c> or <c><![CDATA[append]]></c>
- flag. Returns <c><![CDATA[ok]]></c> if successful and <c><![CDATA[{error, Reason}]]></c>
+ flag. Returns <c><![CDATA[ok]]></c> if successful or S<c><![CDATA[{error, Reason}]]></c>
otherwise.</p>
<p>Typical error reasons are:</p>
<taglist>
@@ -317,14 +313,14 @@
<v>ChannelPid = pid()</v>
<v>Handle = term()</v>
<v>Location = Offset | {bof, Offset} | {cur, Offset} | {eof, Offset} | bof | cur | eof</v>
- <v>Offset = int()</v>
+ <v>Offset = integer()</v>
<v>Timeout = timeout()</v>
<v>NewPosition = integer()</v>
<v>Reason = term()</v>
</type>
<desc>
<p>Sets the file position of the file referenced by <c><![CDATA[Handle]]></c>.
- Returns <c><![CDATA[{ok, NewPosition]]></c> (as an absolute offset) if
+ Returns <c><![CDATA[{ok, NewPosition}]]></c> (as an absolute offset) if
successful, otherwise <c><![CDATA[{error, Reason}]]></c>. <c><![CDATA[Location]]></c> is
one of the following:</p>
<taglist>
@@ -413,7 +409,7 @@
<v>Reason = term()</v>
</type>
<desc>
- <p>Read the link target from the symbolic link specified
+ <p>Reads the link target from the symbolic link specified
by <c><![CDATA[name]]></c>, like <c><![CDATA[file:read_link/1]]></c>.</p>
</desc>
</func>
@@ -490,8 +486,9 @@
<v>Reason = term()</v>
</type>
<desc>
- <p>Deletes a directory specified by <c><![CDATA[Name]]></c>. The directory
- should be empty.</p>
+ <p>Deletes a directory specified by <c><![CDATA[Name]]></c>.
+ Note that the directory must be empty before it can be successfully deleted
+ </p>
</desc>
</func>
diff --git a/lib/ssh/doc/src/ssh_sftpd.xml b/lib/ssh/doc/src/ssh_sftpd.xml
index b3d64e72b4..3666bc7692 100644
--- a/lib/ssh/doc/src/ssh_sftpd.xml
+++ b/lib/ssh/doc/src/ssh_sftpd.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>2005</year><year>2010</year>
+ <year>2005</year><year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -22,23 +22,17 @@
</legalnotice>
<title>ssh_sftpd</title>
- <prepared>Ingela Anderton Andin</prepared>
- <responsible></responsible>
- <docno>1</docno>
- <approved></approved>
- <checked></checked>
<date>2005-09-22</date>
- <rev>PA1</rev>
<file>ssh_sftpd.sgml</file>
</header>
<module>ssh_sftpd</module>
- <modulesummary>Specifies a channel process to handle a sftp subsystem.</modulesummary>
+ <modulesummary>Specifies the channel process to handle an sftp subsystem.</modulesummary>
<description>
<p>Specifies a channel process to handle a sftp subsystem.</p>
</description>
<section>
- <title>COMMON DATA TYPES </title>
+ <title>DATA TYPES </title>
<p><c>subsystem_spec() = {subsystem_name(), {channel_callback(), channel_init_args()}} </c></p>
<p><c>subsystem_name() = "sftp"</c></p>
<p><c>channel_callback() = atom()</c> - Name of the erlang module implementing the
@@ -65,27 +59,32 @@
</item>
<tag><c><![CDATA[{file_handler, CallbackModule}]]></c></tag>
<item>
- <p>Determines which module to call for communicating with
- the file server. Default value is <c>ssh_sftpd_file</c> that uses the
- file and filelib API:s to access the standard OTP file
- server. This option may be used to plug in the use of
- other file servers.</p>
- </item>
- <tag><c><![CDATA[{max_files, Integer}]]></c></tag>
- <item>
- <p>The default value is <c>0</c>, which means that there is no upper limit.
- If supplied, the number of filenames returned to the sftp client per <c>READDIR</c>
- request, is limited to at most the given value.</p>
- </item>
+ <p>Determines which module to call for accessing
+ the file server. The default value is <c>ssh_sftpd_file</c> that uses the
+ <seealso marker="kernel#file">file</seealso> and <seealso marker="kernel#filelib">filelib</seealso> API:s to access the standard OTP file
+ server. This option may be used to plug in
+ other file servers.</p>
+ </item>
+ <tag><c><![CDATA[{max_files, Integer}]]></c></tag>
+ <item>
+ <p>The default value is <c>0</c>, which means that there is no upper limit.
+ If supplied, the number of filenames returned to the sftp client per <c>READDIR</c>
+ request is limited to at most the given value.</p>
+ </item>
<tag><c><![CDATA[{root, String}]]></c></tag>
<item>
<p>Sets the sftp root directory. The user will then not be
- able to see any files above this root. If for instance
- the root is set to <c>/tmp</c> the user will see this
- directory as <c>/</c> and if the user does cd <c>/etc</c>
- the user will end up in <c>/tmp/etc</c>.
+ able to see any files above this root. If for instance
+ the root is set to <c>/tmp</c> the user will see this
+ directory as <c>/</c> and if the user does cd <c>/etc</c>
+ the user will end up in <c>/tmp/etc</c>.
</p>
</item>
+ <tag><c><![CDATA[{sftpd_vsn, integer()}]]></c></tag>
+ <item>
+ <p>Sets the sftp version to use, defaults to 5. Version 6 is under
+ development and limited.</p>
+ </item>
</taglist>
</desc>
</func>
diff --git a/lib/ssh/doc/src/user_guide.gif b/lib/ssh/doc/src/user_guide.gif
deleted file mode 100644
index e6275a803d..0000000000
--- a/lib/ssh/doc/src/user_guide.gif
+++ /dev/null
Binary files differ
diff --git a/lib/ssh/doc/src/usersguide.xml b/lib/ssh/doc/src/usersguide.xml
new file mode 100644
index 0000000000..c818003090
--- /dev/null
+++ b/lib/ssh/doc/src/usersguide.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="iso-8859-1" ?>
+<!DOCTYPE part SYSTEM "part.dtd">
+
+<part xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header>
+ <copyright>
+ <year>2012</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>SSH User's Guide</title>
+ <prepared>OTP Team</prepared>
+ <date>2012-10-11</date>
+ <file>usersguide.xml</file>
+ </header>
+ <description>
+ <p>The <em>SSH</em> application implements the SSH (Secure Shell) protocol and
+ provides an SFTP (Secret File Transfer Protocol) client and server.
+ </p>
+ </description>
+ <xi:include href="introduction.xml"/>
+ <xi:include href="ssh_protocol.xml"/>
+ <xi:include href="using_ssh.xml"/>
+</part>
diff --git a/lib/ssh/doc/src/using_ssh.xml b/lib/ssh/doc/src/using_ssh.xml
new file mode 100644
index 0000000000..87b811d591
--- /dev/null
+++ b/lib/ssh/doc/src/using_ssh.xml
@@ -0,0 +1,298 @@
+<?xml version="1.0" encoding="iso-8859-1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2012</year>
+ <year>2013</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Getting started</title>
+ <file>using_ssh.xml</file>
+ </header>
+
+ <section>
+ <title> General information</title>
+ <p>The examples in the following sections use the utility function
+ <seealso marker="ssh#start"> ssh:start/0 </seealso> that starts
+ all needed applications (crypto, public_key and ssh). All examples
+ are run in an Erlang shell, or in a bash shell using openssh to
+ illustrate how the erlang ssh application can be used. The
+ exampels are run as the user otptest on a local network where the
+ user is authorized to login in over ssh to the host "tarlop". If
+ nothing else is stated it is persumed that the otptest user has an
+ entry in tarlop's authorized_keys file (may log in via ssh without
+ entering a password). Also tarlop is a known host in the user
+ otptest's known_hosts file so that host verification can be done
+ without user interaction.
+ </p>
+ </section>
+
+ <section>
+ <title>Using the Erlang SSH Terminal Client</title>
+
+ <p>The user otptest, that has bash as default shell, uses the
+ ssh:shell/1 client to connect to the openssh daemon running on a
+ host called tarlop. Note that currently this client is very simple
+ and you should not be expected to be as fancy as the openssh
+ client.</p>
+
+ <code type="erl" >
+ 1> ssh:start().
+ ok
+ 2> {ok, S} = ssh:shell("tarlop").
+ >pwd
+ /home/otptest
+ >exit
+ logout
+ 3>
+ </code>
+ </section>
+
+ <section>
+ <title>Running an Erlang SSH Daemon </title>
+
+ <p> The option system_dir must be a directory containing a host
+ key file and it defaults to /etc/ssh. For details see section
+ Configuration Files in <seealso
+ marker="ssh_app">ssh(6)</seealso>.
+ </p>
+
+ <note><p>Normally the /etc/ssh directory is only readable by root. </p>
+ </note>
+
+ <p> The option user_dir defaults to the users ~/.ssh directory</p>
+
+ <p>In the following example we generate new keys and host keys as
+ to be able to run the example without having root privilages</p>
+
+ <code>
+ $bash> ssh-keygen -t rsa -f /tmp/ssh_daemon/ssh_host_rsa_key
+ [...]
+ $bash> ssh-keygen -t rsa -f /tmp/otptest_user/.ssh/id_rsa
+ [...]
+ </code>
+
+ <p>Create the file /tmp/otptest_user/.ssh/authrized_keys and add the content
+ of /tmp/otptest_user/.ssh/id_rsa.pub Now we can do</p>
+
+ <code type="erl">
+ 1> ssh:start().
+ ok
+ 2> {ok, Sshd} = ssh:daemon(8989, [{system_dir, "/tmp/ssh_daemon"},
+ {user_dir, "/tmp/otptest_user/.ssh"}]).
+ {ok,&lt;0.54.0>}
+ 3>
+ </code>
+
+ <p>Use the openssh client from a shell to connect to the Erlang ssh daemon.</p>
+
+ <code>
+ $bash> ssh tarlop -p 8989 -i /tmp/otptest_user/.ssh/id_rsa\
+ -o UserKnownHostsFile=/tmp/otptest_user/.ssh/known_hosts
+ The authenticity of host 'tarlop' can't be established.
+ RSA key fingerprint is 14:81:80:50:b1:1f:57:dd:93:a8:2d:2f:dd:90:ae:a8.
+ Are you sure you want to continue connecting (yes/no)? yes
+ Warning: Permanently added 'tarlop' (RSA) to the list of known hosts.
+ Eshell V5.10 (abort with ^G)
+ 1>
+ </code>
+
+ <p>There are two ways of shutting down an SSH daemon</p>
+
+ <p>1: Stops the listener, but leaves existing connections started by the listener up and running.</p>
+
+ <code type="erl">
+ 3> ssh:stop_listener(Sshd).
+ ok
+ 4>
+ </code>
+
+ <p>2: Stops the listener and all connections started by the listener.</p>
+
+ <code type="erl">
+ 3> ssh:stop_daemon(Sshd)
+ ok
+ 4>
+ </code>
+
+ </section>
+
+ <section>
+ <title>One Time Execution</title>
+
+ <p>In the following example the Erlang shell is the client process
+ that receives the channel replies. <note> If you run this example
+ in your environment you may get fewer or more messages back as
+ this depends on the OS and shell on the machine running the ssh
+ daemon. See also <seealso marker="ssh_connection#exec-4">ssh_connection:exec/4</seealso>
+ </note>
+ </p>
+
+ <code type="erl" >
+ 1> ssh:start().
+ ok
+ 2> {ok, ConnectionRef} = ssh:connect("tarlop", 22, []).
+ {ok,&lt;0.57.0>}
+ 3>{ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity).
+ {ok,0}
+ 4> success = ssh_connection:exec(ConnectionRef, ChannelId, "pwd", infinity).
+ 5> flush().
+ Shell got {ssh_cm,&lt;0.57.0>,{data,0,0,&lt;&lt;"/home/otptest\n">>}}
+ Shell got {ssh_cm,&lt;0.57.0>,{eof,0}}
+ Shell got {ssh_cm,&lt;0.57.0>,{exit_status,0,0}}
+ Shell got {ssh_cm,&lt;0.57.0>,{closed,0}}
+ ok
+ 6>
+ </code>
+
+ <p>Note only the channel is closed the connection is still up and can handle other channels</p>
+
+ <code type="erl" >
+ 6> {ok, NewChannelId} = ssh_connection:session_channel(ConnectionRef, infinity).
+ {ok,1}
+ ...
+ </code>
+ </section>
+
+ <section>
+ <title>SFTP (SSH File Transport Protocol) server</title>
+
+ <code type="erl" >
+ 1> ssh:start().
+ ok
+ 2> ssh:daemon(8989, [{system_dir, "/tmp/ssh_daemon"},
+ {user_dir, "/tmp/otptest_user/.ssh"},
+ {subsystems, [ssh_sftpd:subsystem_spec([{cwd, "/tmp/sftp/example"}])]}]).
+ {ok,&lt;0.54.0>}
+ 3>
+ </code>
+
+ <p> Run the openssh sftp client</p>
+
+ <code type="erl">
+ $bash> sftp -oPort=8989 -o IdentityFile=/tmp/otptest_user/.ssh/id_rsa\
+ -o UserKnownHostsFile=/tmp/otptest_user/.ssh/known_hosts tarlop
+ Connecting to tarlop...
+ sftp> pwd
+ Remote working directory: /tmp/sftp/example
+ sftp>
+ </code>
+ </section>
+
+ <section>
+ <title>SFTP (SSH File Transport Protocol) client</title>
+
+ <code type="erl" >
+ 1> ssh:start().
+ ok
+ 2> {ok, ChannelPid, Connection} = ssh_sftp:start_channel("tarlop", []).
+ {ok,&lt;0.57.0>,&lt;0.51.0>}
+ 3> ssh_sftp:read_file(ChannelPid, "/home/otptest/test.txt").
+ {ok,&lt;&lt;"This is a test file\n">>}
+ </code>
+ </section>
+
+ <section>
+ <title>Creating a subsystem</title>
+
+ <p>A very small SSH subsystem that echos N bytes could be implemented like this.
+ See also <seealso marker="ssh_channel"> ssh_channel(3)</seealso> </p>
+
+ <code type="erl" >
+-module(ssh_echo_server).
+-behaviour(ssh_subsystem).
+-record(state, {
+ n,
+ id,
+ cm
+ }).
+-export([init/1, handle_msg/2, handle_ssh_msg/2, terminate/2]).
+
+init([N]) ->
+ {ok, #state{n = N}}.
+
+handle_msg({ssh_channel_up, ChannelId, ConnectionManager}, State) ->
+ {ok, State#state{id = ChannelId,
+ cm = ConnectionManager}}.
+
+handle_ssh_msg({ssh_cm, CM, {data, ChannelId, 0, Data}}, #state{n = N} = State) ->
+ M = N - size(Data),
+ case M > 0 of
+ true ->
+ ssh_connection:send(CM, ChannelId, Data),
+ {ok, State#state{n = M}};
+ false ->
+ &lt;&lt;SendData:N/binary, _/binary>> = Data,
+ ssh_connection:send(CM, ChannelId, SendData),
+ ssh_connection:send_eof(CM, ChannelId),
+ {stop, ChannelId, State}
+ end;
+handle_ssh_msg({ssh_cm, _ConnectionManager,
+ {data, _ChannelId, 1, Data}}, State) ->
+ error_logger:format(standard_error, " ~p~n", [binary_to_list(Data)]),
+ {ok, State};
+
+handle_ssh_msg({ssh_cm, _ConnectionManager, {eof, _ChannelId}}, State) ->
+ {ok, State};
+
+handle_ssh_msg({ssh_cm, _, {signal, _, _}}, State) ->
+ %% Ignore signals according to RFC 4254 section 6.9.
+ {ok, State};
+
+handle_ssh_msg({ssh_cm, _, {exit_signal, ChannelId, _, _Error, _}},
+ State) ->
+ {stop, ChannelId, State};
+
+handle_ssh_msg({ssh_cm, _, {exit_status, ChannelId, _Status}}, State) ->
+ {stop, ChannelId, State}.
+
+terminate(_Reason, _State) ->
+ ok.
+ </code>
+
+ <p>And run like this on the host tarlop with the keys generated in section 3.3</p>
+
+ <code type="erl" >
+ 1> ssh:start().
+ ok
+ 2> ssh:daemon(8989, [{system_dir, "/tmp/ssh_daemon"},
+ {user_dir, "/tmp/otptest_user/.ssh"}
+ {subsystems, [{"echo_n", {ssh_echo_server, [10]}}]}]).
+ {ok,&lt;0.54.0>}
+ 3>
+ </code>
+
+ <code type="erl" >
+ 1> ssh:start().
+ ok
+ 2>{ok, ConnectionRef} = ssh:connect("tarlop", 8989, [{user_dir, "/tmp/otptest_user/.ssh"}]).
+ {ok,&lt;0.57.0>}
+ 3>{ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity).
+ 4> success = ssh_connection:subsystem(ConnectionRef, ChannelId, "echo_n", infinity).
+ 5> ok = ssh_connection:send(ConnectionRef, ChannelId, "0123456789", infinity).
+ 6> flush().
+ {ssh_msg, &lt;0.57.0>, {data, 0, 1, "0123456789"}}
+ {ssh_msg, &lt;0.57.0>, {eof, 0}}
+ {ssh_msg, &lt;0.57.0>, {closed, 0}}
+ 7> {error, closed} = ssh_connection:send(ConnectionRef, ChannelId, "10", infinity).
+ </code>
+
+</section>
+
+</chapter>
diff --git a/lib/ssh/src/Makefile b/lib/ssh/src/Makefile
index b8eecd3fa2..27e43a88ed 100644
--- a/lib/ssh/src/Makefile
+++ b/lib/ssh/src/Makefile
@@ -41,7 +41,9 @@ RELSYSDIR = $(RELEASE_PATH)/lib/ssh-$(VSN)
BEHAVIOUR_MODULES= \
ssh_sftpd_file_api \
ssh_channel \
- ssh_key_api
+ ssh_subsystem \
+ ssh_client_key_api \
+ ssh_server_key_api
MODULES= \
ssh \
@@ -118,10 +120,10 @@ clean:
rm -f errs core *~
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
docs:
diff --git a/lib/ssh/src/ssh.app.src b/lib/ssh/src/ssh.app.src
index 316c09eb06..a0ba7cf7d9 100644
--- a/lib/ssh/src/ssh.app.src
+++ b/lib/ssh/src/ssh.app.src
@@ -10,6 +10,7 @@
ssh_auth,
ssh_bits,
ssh_cli,
+ ssh_client_key_api,
ssh_channel,
ssh_channel_sup,
ssh_connection,
@@ -21,13 +22,14 @@
sshd_sup,
ssh_file,
ssh_io,
- ssh_key_api,
ssh_math,
ssh_no_io,
+ ssh_server_key_api,
ssh_sftp,
ssh_sftpd,
ssh_sftpd_file,
ssh_sftpd_file_api,
+ ssh_subsystem,
ssh_subsystem_sup,
ssh_sup,
ssh_system_sup,
@@ -35,7 +37,7 @@
ssh_userreg,
ssh_xfer]},
{registered, []},
- {applications, [kernel, stdlib, crypto]},
+ {applications, [kernel, stdlib, crypto, public_key]},
{env, []},
{mod, {ssh_app, []}}]}.
diff --git a/lib/ssh/src/ssh.appup.src b/lib/ssh/src/ssh.appup.src
index d08dbafc32..826a11f1f4 100644
--- a/lib/ssh/src/ssh.appup.src
+++ b/lib/ssh/src/ssh.appup.src
@@ -19,24 +19,14 @@
{"%VSN%",
[
- {<<"2.1">>, [{load_module, ssh_sftpd_file_api, soft_purge, soft_purge, []},
- {load_module, ssh_connection, soft_purge, soft_purge, []},
- {load_module, ssh_connection_manager, soft_purge, soft_purge, []},
- {load_module, ssh_auth, soft_purge, soft_purge, []},
- {load_module, ssh_channel, soft_purge, soft_purge, []},
- {load_module, ssh_file, soft_purge, soft_purge, []}]},
- {load_module, ssh, soft_purge, soft_purge, []}]},
+ {<<"2.1.1">>, [{restart_application, ssh}]},
+ {<<"2.1">>, [{restart_application, ssh}]},
{<<"2.0\\.*">>, [{restart_application, ssh}]},
{<<"1\\.*">>, [{restart_application, ssh}]}
],
[
- {<<"2.1">>,[{load_module, ssh_sftpd_file_api, soft_purge, soft_purge, []},
- {load_module, ssh_connection, soft_purge, soft_purge, []},
- {load_module, ssh_connection_manager, soft_purge, soft_purge, []},
- {load_module, ssh_auth, soft_purge, soft_purge, []},
- {load_module, ssh_channel, soft_purge, soft_purge, []},
- {load_module, ssh_file, soft_purge, soft_purge, []}]},
- {load_module, ssh, soft_purge, soft_purge, []}]},
+ {<<"2.1.1">>, [{restart_application, ssh}]},
+ {<<"2.1">>,[{restart_application, ssh}]},
{<<"2.0\\.*">>, [{restart_application, ssh}]},
{<<"1\\.*">>, [{restart_application, ssh}]}
]
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 3395f73884..b5a0aa2e05 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -41,19 +41,23 @@
%%
%% Type = permanent | transient | temporary
%%
-%% Description: Starts the inets application. Default type
+%% Description: Starts the ssh application. Default type
%% is temporary. see application(3)
%%--------------------------------------------------------------------
start() ->
+ application:start(crypto),
+ application:start(public_key),
application:start(ssh).
start(Type) ->
+ application:start(crypto, Type),
+ application:start(public_key, Type),
application:start(ssh, Type).
%%--------------------------------------------------------------------
%% Function: stop() -> ok
%%
-%% Description: Stops the inets application.
+%% Description: Stops the ssh application.
%%--------------------------------------------------------------------
stop() ->
application:stop(ssh).
@@ -76,10 +80,10 @@ connect(Host, Port, Options, Timeout) ->
{error, _Reason} = Error ->
Error;
{SocketOptions, SshOptions} ->
- DisableIpv6 = proplists:get_value(ip_v6_disabled, SshOptions, false),
+ DisableIpv6 = proplists:get_value(ipv6_disabled, SshOptions, false),
Inet = inetopt(DisableIpv6),
do_connect(Host, Port, [Inet | SocketOptions],
- [{host, Host} | SshOptions], Timeout, DisableIpv6)
+ [{user_pid, self()}, {host, Host} | fix_idle_time(SshOptions)], Timeout, DisableIpv6)
end.
do_connect(Host, Port, SocketOptions, SshOptions, Timeout, DisableIpv6) ->
@@ -91,30 +95,39 @@ do_connect(Host, Port, SocketOptions, SshOptions, Timeout, DisableIpv6) ->
{ok, ConnectionSup} ->
{ok, Manager} =
ssh_connection_sup:connection_manager(ConnectionSup),
- receive
- {Manager, is_connected} ->
- {ok, Manager};
- %% When the connection fails
- %% ssh_connection_sup:connection_manager
- %% might return undefined as the connection manager
- %% could allready have terminated, so we will not
- %% match the Manager in this case
- {_, not_connected, {error, econnrefused}} when DisableIpv6 == false ->
- do_connect(Host, Port, proplists:delete(inet6, SocketOptions),
- SshOptions, Timeout, true);
- {_, not_connected, {error, Reason}} ->
- {error, Reason};
- {_, not_connected, Other} ->
- {error, Other}
- after Timeout ->
- ssh_connection_manager:stop(Manager),
- {error, timeout}
- end
+ msg_loop(Manager, DisableIpv6, Host, Port, SocketOptions, SshOptions, Timeout)
catch
exit:{noproc, _} ->
{error, ssh_not_started}
end.
-
+msg_loop(Manager, DisableIpv6, Host, Port, SocketOptions, SshOptions, Timeout) ->
+ receive
+ {Manager, is_connected} ->
+ {ok, Manager};
+ %% When the connection fails
+ %% ssh_connection_sup:connection_manager
+ %% might return undefined as the connection manager
+ %% could allready have terminated, so we will not
+ %% match the Manager in this case
+ {_, not_connected, {error, econnrefused}} when DisableIpv6 == false ->
+ do_connect(Host, Port, proplists:delete(inet6, SocketOptions),
+ SshOptions, Timeout, true);
+ {_, not_connected, {error, Reason}} ->
+ {error, Reason};
+ {_, not_connected, Other} ->
+ {error, Other};
+ {From, user_password} ->
+ Pass = io:get_password(),
+ From ! Pass,
+ msg_loop(Manager, DisableIpv6, Host, Port, SocketOptions, SshOptions, Timeout);
+ {From, question} ->
+ Answer = io:get_line(""),
+ From ! Answer,
+ msg_loop(Manager, DisableIpv6, Host, Port, SocketOptions, SshOptions, Timeout)
+ after Timeout ->
+ ssh_connection_manager:stop(Manager),
+ {error, timeout}
+ end.
%%--------------------------------------------------------------------
%% Function: close(ConnectionRef) -> ok
%%
@@ -160,7 +173,7 @@ daemon(HostAddr, Port, Options0) ->
_ ->
Options0
end,
- DisableIpv6 = proplists:get_value(ip_v6_disabled, Options0, false),
+ DisableIpv6 = proplists:get_value(ipv6_disabled, Options0, false),
{Host, Inet, Options} = case HostAddr of
any ->
{ok, Host0} = inet:gethostname(),
@@ -237,6 +250,13 @@ shell(Host, Port, Options) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
+fix_idle_time(SshOptions) ->
+ case proplists:get_value(idle_time, SshOptions) of
+ undefined ->
+ [{idle_time, infinity}|SshOptions];
+ _ ->
+ SshOptions
+ end.
start_daemon(Host, Port, Options, Inet) ->
case handle_options(Options) of
{error, _Reason} = Error ->
@@ -248,7 +268,7 @@ start_daemon(Host, Port, Options, Inet) ->
do_start_daemon(Host, Port, Options, SocketOptions) ->
case ssh_system_sup:system_supervisor(Host, Port) of
undefined ->
- %% TODO: It would proably make more sense to call the
+ %% It would proably make more sense to call the
%% address option host but that is a too big change at the
%% monent. The name is a legacy name!
try sshd_sup:start_child([{address, Host},
@@ -258,7 +278,9 @@ do_start_daemon(Host, Port, Options, SocketOptions) ->
{ok, SysSup} ->
{ok, SysSup};
{error, {already_started, _}} ->
- {error, eaddrinuse}
+ {error, eaddrinuse};
+ {error, R} ->
+ {error, R}
catch
exit:{noproc, _} ->
{error, ssh_not_started}
@@ -309,8 +331,6 @@ handle_option([{user_passwords, _} = Opt | Rest], SocketOptions, SshOptions) ->
handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
handle_option([{pwdfun, _} = Opt | Rest], SocketOptions, SshOptions) ->
handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{user_auth, _} = Opt | Rest],SocketOptions, SshOptions ) ->
- handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
handle_option([{key_cb, _} = Opt | Rest], SocketOptions, SshOptions) ->
handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
handle_option([{role, _} = Opt | Rest], SocketOptions, SshOptions) ->
@@ -328,7 +348,10 @@ handle_option([{disconnectfun, _} = Opt | Rest], SocketOptions, SshOptions) ->
handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
handle_option([{failfun, _} = Opt | Rest], SocketOptions, SshOptions) ->
handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
-handle_option([{ip_v6_disabled, _} = Opt | Rest], SocketOptions, SshOptions) ->
+%%Backwards compatibility should not be underscore between ip and v6 in API
+handle_option([{ip_v6_disabled, Value} | Rest], SocketOptions, SshOptions) ->
+ handle_option(Rest, SocketOptions, [handle_ssh_option({ipv6_disabled, Value}) | SshOptions]);
+handle_option([{ipv6_disabled, _} = Opt | Rest], SocketOptions, SshOptions) ->
handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
handle_option([{transport, _} = Opt | Rest], SocketOptions, SshOptions) ->
handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
@@ -342,6 +365,14 @@ handle_option([{exec, _} = Opt | Rest], SocketOptions, SshOptions) ->
handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
handle_option([{auth_methods, _} = Opt | Rest], SocketOptions, SshOptions) ->
handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
+handle_option([{pref_public_key_algs, _} = Opt | Rest], SocketOptions, SshOptions) ->
+ handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
+handle_option([{quiet_mode, _} = Opt|Rest], SocketOptions, SshOptions) ->
+ handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
+handle_option([{idle_time, _} = Opt | Rest], SocketOptions, SshOptions) ->
+ handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
+handle_option([{rekey_limit, _} = Opt|Rest], SocketOptions, SshOptions) ->
+ handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
handle_option([Opt | Rest], SocketOptions, SshOptions) ->
handle_option(Rest, [handle_inet_option(Opt) | SocketOptions], SshOptions).
@@ -355,8 +386,19 @@ handle_ssh_option({silently_accept_hosts, Value} = Opt) when Value == true; Valu
Opt;
handle_ssh_option({user_interaction, Value} = Opt) when Value == true; Value == false ->
Opt;
-handle_ssh_option({public_key_alg, Value} = Opt) when Value == ssh_rsa; Value == ssh_dsa ->
+handle_ssh_option({public_key_alg, ssh_dsa}) ->
+ {public_key_alg, 'ssh-dss'};
+handle_ssh_option({public_key_alg, ssh_rsa}) ->
+ {public_key_alg, 'ssh-rsa'};
+handle_ssh_option({public_key_alg, Value} = Opt) when Value == 'ssh-rsa'; Value == 'ssh-dss' ->
Opt;
+handle_ssh_option({pref_public_key_algs, Value} = Opt) when is_list(Value), length(Value) >= 1 ->
+ case handle_pref_algs(Value, []) of
+ true ->
+ Opt;
+ _ ->
+ throw({error, {eoptions, Opt}})
+ end;
handle_ssh_option({connect_timeout, Value} = Opt) when is_integer(Value); Value == infinity ->
Opt;
handle_ssh_option({user, Value} = Opt) when is_list(Value) ->
@@ -371,8 +413,6 @@ handle_ssh_option({user_passwords, Value} = Opt) when is_list(Value)->
Opt;
handle_ssh_option({pwdfun, Value} = Opt) when is_function(Value) ->
Opt;
-handle_ssh_option({user_auth, Value} = Opt) when is_function(Value) ->
- Opt;
handle_ssh_option({key_cb, Value} = Opt) when is_atom(Value) ->
Opt;
handle_ssh_option({compression, Value} = Opt) when is_atom(Value) ->
@@ -391,7 +431,8 @@ handle_ssh_option({disconnectfun , Value} = Opt) when is_function(Value) ->
Opt;
handle_ssh_option({failfun, Value} = Opt) when is_function(Value) ->
Opt;
-handle_ssh_option({ip_v6_disabled, Value} = Opt) when Value == true;
+
+handle_ssh_option({ipv6_disabled, Value} = Opt) when Value == true;
Value == false ->
Opt;
handle_ssh_option({transport, {Protocol, Cb, ClosTag}} = Opt) when is_atom(Protocol),
@@ -407,6 +448,13 @@ handle_ssh_option({shell, {Module, Function, _}} = Opt) when is_atom(Module),
Opt;
handle_ssh_option({shell, Value} = Opt) when is_function(Value) ->
Opt;
+handle_ssh_option({quiet_mode, Value} = Opt) when Value == true;
+ Value == false ->
+ 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) ->
+ Opt;
handle_ssh_option(Opt) ->
throw({error, {eoptions, Opt}}).
@@ -415,7 +463,7 @@ handle_inet_option({active, _} = Opt) ->
"and activ is handled internaly user is not allowd"
"to specify this option"}});
handle_inet_option({inet, _} = Opt) ->
- throw({error, {{eoptions, Opt},"Is set internaly use ip_v6_disabled to"
+ throw({error, {{eoptions, Opt},"Is set internaly use ipv6_disabled to"
" enforce iv4 in the server, client will fallback to ipv4 if"
" it can not use ipv6"}});
handle_inet_option({reuseaddr, _} = Opt) ->
@@ -424,12 +472,27 @@ handle_inet_option({reuseaddr, _} = Opt) ->
%% Option verified by inet
handle_inet_option(Opt) ->
Opt.
-
+%% Check preferred algs
+handle_pref_algs([], Acc) ->
+ {true, lists:reverse(Acc)};
+handle_pref_algs([H|T], Acc) ->
+ case H of
+ ssh_dsa ->
+ handle_pref_algs(T, ['ssh-dss'| Acc]);
+ ssh_rsa ->
+ handle_pref_algs(T, ['ssh-rsa'| Acc]);
+ 'ssh-dss' ->
+ handle_pref_algs(T, ['ssh-dss'| Acc]);
+ 'ssh-rsa' ->
+ handle_pref_algs(T, ['ssh-rsa'| Acc]);
+ _ ->
+ false
+ end.
%% Has IPv6 been disabled?
inetopt(true) ->
inet;
inetopt(false) ->
- case gen_tcp:listen(0, [inet6, {ip, loopback}]) of
+ case gen_tcp:listen(0, [inet6]) of
{ok, Dummyport} ->
gen_tcp:close(Dummyport),
inet6;
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index aa452a8e09..cb0c7751f0 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -48,17 +48,18 @@ publickey_msg([Alg, #ssh{user = User,
case KeyCb:user_key(Alg, Opts) of
{ok, Key} ->
+ StrAlgo = algorithm_string(Alg),
PubKeyBlob = encode_public_key(Key),
SigData = build_sig_data(SessionId,
- User, Service, PubKeyBlob, Alg),
+ User, Service, PubKeyBlob, StrAlgo),
Sig = ssh_transport:sign(SigData, Hash, Key),
- SigBlob = list_to_binary([?string(Alg), ?binary(Sig)]),
+ SigBlob = list_to_binary([?string(StrAlgo), ?binary(Sig)]),
ssh_transport:ssh_packet(
#ssh_msg_userauth_request{user = User,
service = Service,
method = "publickey",
data = [?TRUE,
- ?string(Alg),
+ ?string(StrAlgo),
?binary(PubKeyBlob),
?binary(SigBlob)]},
Ssh);
@@ -71,7 +72,7 @@ password_msg([#ssh{opts = Opts, io_cb = IoCb,
ssh_bits:install_messages(userauth_passwd_messages()),
Password = case proplists:get_value(password, Opts) of
undefined ->
- user_interaction(IoCb);
+ user_interaction(IoCb, Ssh);
PW ->
PW
end,
@@ -89,10 +90,10 @@ password_msg([#ssh{opts = Opts, io_cb = IoCb,
Ssh)
end.
-user_interaction(ssh_no_io) ->
+user_interaction(ssh_no_io, _) ->
not_ok;
-user_interaction(IoCb) ->
- IoCb:read_password("ssh password: ").
+user_interaction(IoCb, Ssh) ->
+ IoCb:read_password("ssh password: ", Ssh).
%% See RFC 4256 for info on keyboard-interactive
@@ -118,15 +119,36 @@ init_userauth_request_msg(#ssh{opts = Opts} = Ssh) ->
service = "ssh-connection",
method = "none",
data = <<>>},
- FirstAlg = algorithm(proplists:get_value(public_key_alg, Opts,
- ?PREFERRED_PK_ALG)),
- SecondAlg = other_alg(FirstAlg),
- AllowUserInt = proplists:get_value(user_interaction, Opts, true),
- Prefs = method_preference(FirstAlg, SecondAlg, AllowUserInt),
- ssh_transport:ssh_packet(Msg, Ssh#ssh{user = User,
- userauth_preference = Prefs,
- userauth_methods = none,
- service = "ssh-connection"});
+ case proplists:get_value(pref_public_key_algs, Opts, false) of
+ false ->
+ FirstAlg = proplists:get_value(public_key_alg, Opts, ?PREFERRED_PK_ALG),
+ SecondAlg = other_alg(FirstAlg),
+ AllowUserInt = proplists:get_value(user_interaction, Opts, true),
+ Prefs = method_preference(FirstAlg, SecondAlg, AllowUserInt),
+ ssh_transport:ssh_packet(Msg, Ssh#ssh{user = User,
+ userauth_preference = Prefs,
+ userauth_methods = none,
+ service = "ssh-connection"});
+ Algs ->
+ FirstAlg = lists:nth(1, Algs),
+ case length(Algs) =:= 2 of
+ true ->
+ SecondAlg = other_alg(FirstAlg),
+ AllowUserInt = proplists:get_value(user_interaction, Opts, true),
+ Prefs = method_preference(FirstAlg, SecondAlg, AllowUserInt),
+ ssh_transport:ssh_packet(Msg, Ssh#ssh{user = User,
+ userauth_preference = Prefs,
+ userauth_methods = none,
+ service = "ssh-connection"});
+ _ ->
+ AllowUserInt = proplists:get_value(user_interaction, Opts, true),
+ Prefs = method_preference(FirstAlg, AllowUserInt),
+ ssh_transport:ssh_packet(Msg, Ssh#ssh{user = User,
+ userauth_preference = Prefs,
+ userauth_methods = none,
+ service = "ssh-connection"})
+ end
+ end;
{error, no_user} ->
ErrStr = "Could not determine the users name",
throw(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_ILLEGAL_USER_NAME,
@@ -287,6 +309,15 @@ method_preference(Alg1, Alg2, false) ->
{"publickey", ?MODULE, publickey_msg,[Alg2]},
{"password", ?MODULE, password_msg, []}
].
+method_preference(Alg1, true) ->
+ [{"publickey", ?MODULE, publickey_msg, [Alg1]},
+ {"password", ?MODULE, password_msg, []},
+ {"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []}
+ ];
+method_preference(Alg1, false) ->
+ [{"publickey", ?MODULE, publickey_msg, [Alg1]},
+ {"password", ?MODULE, password_msg, []}
+ ].
user_name(Opts) ->
Env = case os:type() of
@@ -327,7 +358,7 @@ 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),
- case KeyCb:is_auth_key(Key, User, Alg, Opts) of
+ case KeyCb:is_auth_key(Key, User, Opts) of
true ->
PlainText = build_sig_data(SessionId, User,
Service, KeyBlob, Alg),
@@ -350,9 +381,9 @@ build_sig_data(SessionId, User, Service, KeyBlob, Alg) ->
?binary(KeyBlob)],
list_to_binary(Sig).
-algorithm(ssh_rsa) ->
+algorithm_string('ssh-rsa') ->
"ssh-rsa";
-algorithm(ssh_dsa) ->
+algorithm_string('ssh-dss') ->
"ssh-dss".
decode_keyboard_interactive_prompts(NumPrompts, Data) ->
@@ -370,11 +401,11 @@ keyboard_interact_get_responses(IoCb, Opts, Name, Instr, PromptInfos) ->
%% Special case/fallback for just one prompt
%% (assumed to be the password prompt)
case proplists:get_value(password, Opts) of
- undefined -> keyboard_interact(IoCb, Name, Instr, PromptInfos);
+ undefined -> keyboard_interact(IoCb, Name, Instr, PromptInfos, Opts);
PW -> [PW]
end;
undefined ->
- keyboard_interact(IoCb, Name, Instr, PromptInfos);
+ keyboard_interact(IoCb, Name, Instr, PromptInfos, Opts);
KbdInteractFun ->
Prompts = lists:map(fun({Prompt, _Echo}) -> Prompt end,
PromptInfos),
@@ -388,15 +419,15 @@ keyboard_interact_get_responses(IoCb, Opts, Name, Instr, PromptInfos) ->
end
end.
-keyboard_interact(IoCb, Name, Instr, Prompts) ->
+keyboard_interact(IoCb, Name, Instr, Prompts, Opts) ->
if Name /= "" -> IoCb:format("~s", [Name]);
true -> ok
end,
if Instr /= "" -> IoCb:format("~s", [Instr]);
true -> ok
end,
- lists:map(fun({Prompt, true}) -> IoCb:read_line(Prompt);
- ({Prompt, false}) -> IoCb:read_password(Prompt)
+ lists:map(fun({Prompt, true}) -> IoCb:read_line(Prompt, Opts);
+ ({Prompt, false}) -> IoCb:read_password(Prompt, Opts)
end,
Prompts).
@@ -426,10 +457,10 @@ userauth_pk_messages() ->
binary]} % key blob
].
-other_alg("ssh-rsa") ->
- "ssh-dss";
-other_alg("ssh-dss") ->
- "ssh-rsa".
+other_alg('ssh-rsa') ->
+ 'ssh-dss';
+other_alg('ssh-dss') ->
+ 'ssh-rsa'.
decode_public_key_v2(K_S, "ssh-rsa") ->
case ssh_bits:decode(K_S,[string,mpint,mpint]) of
["ssh-rsa", E, N] ->
diff --git a/lib/ssh/src/ssh_auth.hrl b/lib/ssh/src/ssh_auth.hrl
index e74ee10041..6cd8e6bf14 100644
--- a/lib/ssh/src/ssh_auth.hrl
+++ b/lib/ssh/src/ssh_auth.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -23,7 +23,7 @@
-define(SUPPORTED_AUTH_METHODS, "publickey,keyboard-interactive,password").
--define(PREFERRED_PK_ALG, ssh_rsa).
+-define(PREFERRED_PK_ALG, 'ssh-rsa').
-define(SSH_MSG_USERAUTH_REQUEST, 50).
-define(SSH_MSG_USERAUTH_FAILURE, 51).
diff --git a/lib/ssh/src/ssh_channel.erl b/lib/ssh/src/ssh_channel.erl
index 1938858420..4e8f8538c2 100644
--- a/lib/ssh/src/ssh_channel.erl
+++ b/lib/ssh/src/ssh_channel.erl
@@ -23,14 +23,35 @@
-include("ssh_connect.hrl").
-%%% Optional callbacks handle_call/3, handle_cast/2, handle_msg/2,
-%%% code_change/3
-%% Should be further specified later
--callback init(Options::list()) ->
- {ok, State::term()} | {ok, State::term(), Timeout::timeout()} |
- {stop, Reason ::term()}.
-
--callback terminate(term(), term()) -> term().
+-callback init(Args :: term()) ->
+ {ok, State :: term()} | {ok, State :: term(), timeout() | hibernate} |
+ {stop, Reason :: term()} | ignore.
+-callback handle_call(Request :: term(), From :: {pid(), Tag :: term()},
+ State :: term()) ->
+ {reply, Reply :: term(), NewState :: term()} |
+ {reply, Reply :: term(), NewState :: term(), timeout() | hibernate} |
+ {noreply, NewState :: term()} |
+ {noreply, NewState :: term(), timeout() | hibernate} |
+ {stop, Reason :: term(), Reply :: term(), NewState :: term()} |
+ {stop, Reason :: term(), NewState :: term()}.
+-callback handle_cast(Request :: term(), State :: term()) ->
+ {noreply, NewState :: term()} |
+ {noreply, NewState :: term(), timeout() | hibernate} |
+ {stop, Reason :: term(), NewState :: term()}.
+
+-callback terminate(Reason :: (normal | shutdown | {shutdown, term()} |
+ term()),
+ State :: term()) ->
+ term().
+-callback code_change(OldVsn :: (term() | {down, term()}), State :: term(),
+ Extra :: term()) ->
+ {ok, NewState :: term()} | {error, Reason :: term()}.
+
+-callback handle_msg(Msg ::term(), State :: term()) ->
+ {noreply, NewState :: term()} |
+ {noreply, NewState :: term(), timeout() | hibernate} |
+ {stop, Reason :: term(), NewState :: term()}.
+
-callback handle_ssh_msg({ssh_cm, ConnectionRef::term(), SshMsg::term()},
State::term()) -> {ok, State::term()} |
diff --git a/lib/ssh/src/ssh_cli.erl b/lib/ssh/src/ssh_cli.erl
index 781e01b9d1..c8c610f8ef 100644
--- a/lib/ssh/src/ssh_cli.erl
+++ b/lib/ssh/src/ssh_cli.erl
@@ -81,7 +81,8 @@ handle_ssh_msg({ssh_cm, ConnectionManager,
height = not_zero(Height, 24),
pixel_width = PixWidth,
pixel_height = PixHeight,
- modes = Modes}},
+ modes = Modes},
+ buf = empty_buf()},
set_echo(State),
ssh_connection:reply_request(ConnectionManager, WantReply,
success, ChannelId),
diff --git a/lib/ssh/src/ssh_client_key.erl b/lib/ssh/src/ssh_client_key.erl
new file mode 100644
index 0000000000..2c48884dc2
--- /dev/null
+++ b/lib/ssh/src/ssh_client_key.erl
@@ -0,0 +1,34 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2011-2012. All Rights Reserved.
+%%
+%% The 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(ssh_client_key).
+
+-include_lib("public_key/include/public_key.hrl").
+-include("ssh.hrl").
+
+-callback is_host_key(Key :: public_key(), Host :: string(),
+ Algorithm :: 'ssh-rsa'| 'ssh-dsa'| atom(), Options :: proplists:proplist()) ->
+ boolean().
+
+-callback user_key(Algorithm :: 'ssh-rsa'| 'ssh-dsa'| atom(), Options :: list()) ->
+ {ok, PrivateKey :: term()} | {error, string()}.
+
+
+-callback add_host_key(Host :: string(), PublicKey :: term(), Options :: list()) ->
+ ok | {error, Error::term()}.
diff --git a/lib/ssh/src/ssh_client_key_api.erl b/lib/ssh/src/ssh_client_key_api.erl
new file mode 100644
index 0000000000..eed0b85f47
--- /dev/null
+++ b/lib/ssh/src/ssh_client_key_api.erl
@@ -0,0 +1,35 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2011-2012. All Rights Reserved.
+%%
+%% The 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(ssh_client_key_api).
+
+-include_lib("public_key/include/public_key.hrl").
+-include("ssh.hrl").
+
+-callback is_host_key(PublicKey :: #'RSAPublicKey'{}| {integer(), #'Dss-Parms'{}}| term() , Host :: string(),
+ Algorithm :: 'ssh-rsa'| 'ssh-dss'| atom(), ConnectOptions :: proplists:proplist()) ->
+ boolean().
+
+-callback user_key(Algorithm :: 'ssh-rsa'| 'ssh-dss'| atom(), ConnectOptions :: proplists:proplists()) ->
+ {ok, PrivateKey :: #'RSAPrivateKey'{}| #'DSAPrivateKey'{} | term()} | {error, string()}.
+
+
+-callback add_host_key(Host :: string(), PublicKey :: #'RSAPublicKey'{}| {integer(), #'Dss-Parms'{}}| term(),
+ Options :: list()) ->
+ ok | {error, Error::term()}.
diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl
index e3b8ebfb79..9424cdd423 100644
--- a/lib/ssh/src/ssh_connection.erl
+++ b/lib/ssh/src/ssh_connection.erl
@@ -177,7 +177,7 @@ close(ConnectionManager, ChannelId) ->
%% Description: Send status replies to requests that want such replies.
%%--------------------------------------------------------------------
reply_request(ConnectionManager, true, Status, ChannelId) ->
- ConnectionManager ! {ssh_cm, self(), {Status, ChannelId}},
+ ssh_connection_manager:reply_request(ConnectionManager, Status, ChannelId),
ok;
reply_request(_,false, _, _) ->
ok.
@@ -318,21 +318,22 @@ channel_data(ChannelId, DataType, Data,
From) ->
case ssh_channel:cache_lookup(Cache, ChannelId) of
- #channel{remote_id = Id} = Channel0 ->
- {SendList, Channel} = update_send_window(Channel0, DataType,
+ #channel{remote_id = Id, sent_close = false} = Channel0 ->
+ {SendList, Channel} = update_send_window(Channel0#channel{flow_control = From}, DataType,
Data, Connection),
Replies =
lists:map(fun({SendDataType, SendData}) ->
- {connection_reply, ConnectionPid,
- channel_data_msg(Id,
- SendDataType,
- SendData)}
+ {connection_reply, ConnectionPid,
+ channel_data_msg(Id,
+ SendDataType,
+ SendData)}
end, SendList),
FlowCtrlMsgs = flow_control(Replies,
- Channel#channel{flow_control = From},
+ Channel,
Cache),
{{replies, Replies ++ FlowCtrlMsgs}, Connection};
- undefined ->
+ _ ->
+ gen_server:reply(From, {error, closed}),
{noreply, Connection}
end.
@@ -386,20 +387,30 @@ handle_msg(#ssh_msg_channel_close{recipient_channel = ChannelId},
ConnectionPid, _) ->
case ssh_channel:cache_lookup(Cache, ChannelId) of
- #channel{sent_close = Closed, remote_id = RemoteId} = Channel ->
+ #channel{sent_close = Closed, remote_id = RemoteId, flow_control = FlowControl} = Channel ->
ssh_channel:cache_delete(Cache, ChannelId),
{CloseMsg, Connection} =
reply_msg(Channel, Connection0, {closed, ChannelId}),
+
+ ConnReplyMsgs =
case Closed of
- true ->
- {{replies, [CloseMsg]}, Connection};
+ true -> [];
false ->
RemoteCloseMsg = channel_close_msg(RemoteId),
- {{replies,
- [{connection_reply,
- ConnectionPid, RemoteCloseMsg},
- CloseMsg]}, Connection}
- end;
+ [{connection_reply, ConnectionPid, RemoteCloseMsg}]
+ end,
+
+ %% if there was a send() in progress, make it fail
+ SendReplyMsgs =
+ case FlowControl of
+ undefined -> [];
+ From ->
+ [{flow_control, From, {error, closed}}]
+ end,
+
+ Replies = ConnReplyMsgs ++ [CloseMsg] ++ SendReplyMsgs,
+ {{replies, Replies}, Connection};
+
undefined ->
{{replies, []}, Connection0}
end;
@@ -1126,13 +1137,13 @@ flow_control(Channel, Cache) ->
flow_control([], Channel, Cache) ->
ssh_channel:cache_update(Cache, Channel),
[];
-flow_control([_|_], #channel{flow_control = From} = Channel, Cache) ->
- case From of
- undefined ->
- [];
- _ ->
- [{flow_control, Cache, Channel, From, ok}]
- end.
+
+flow_control([_|_], #channel{flow_control = From,
+ send_buf = []} = Channel, Cache) when From =/= undefined ->
+ [{flow_control, Cache, Channel, From, ok}];
+flow_control(_,_,_) ->
+ [].
+
encode_pty_opts(Opts) ->
Bin = list_to_binary(encode_pty_opts2(Opts)),
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 5b3d1b8a1b..9378686242 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -35,7 +35,8 @@
-export([start_link/4, send/2, renegotiate/1, send_event/2,
connection_info/3,
- peer_address/1]).
+ peer_address/1,
+ renegotiate_data/1]).
%% gen_fsm callbacks
-export([hello/2, kexinit/2, key_exchange/2, new_keys/2,
@@ -85,6 +86,8 @@ send(ConnectionHandler, Data) ->
renegotiate(ConnectionHandler) ->
send_all_state_event(ConnectionHandler, renegotiate).
+renegotiate_data(ConnectionHandler) ->
+ send_all_state_event(ConnectionHandler, data_size).
connection_info(ConnectionHandler, From, Options) ->
send_all_state_event(ConnectionHandler, {info, From, Options}).
@@ -419,11 +422,15 @@ userauth(#ssh_msg_userauth_failure{authentications = Methodes},
#state{ssh_params = #ssh{role = client,
userauth_methods = none} = Ssh0} = State) ->
AuthMethods = string:tokens(Methodes, ","),
- {Msg, Ssh} = ssh_auth:userauth_request_msg(
- Ssh0#ssh{userauth_methods = AuthMethods}),
- send_msg(Msg, State),
- {next_state, userauth, next_packet(State#state{ssh_params = Ssh})};
-
+ Ssh1 = Ssh0#ssh{userauth_methods = AuthMethods},
+ case ssh_auth:userauth_request_msg(Ssh1) of
+ {disconnect, DisconnectMsg, {Msg, Ssh}} ->
+ send_msg(Msg, State),
+ handle_disconnect(DisconnectMsg, State#state{ssh_params = Ssh});
+ {Msg, Ssh} ->
+ send_msg(Msg, State),
+ {next_state, userauth, next_packet(State#state{ssh_params = Ssh})}
+ end;
%% The prefered authentication method failed try next method
userauth(#ssh_msg_userauth_failure{},
#state{ssh_params = #ssh{role = client} = Ssh0} = State) ->
@@ -500,7 +507,22 @@ handle_event(renegotiate, StateName, State) ->
handle_event({info, From, Options}, StateName, #state{ssh_params = Ssh} = State) ->
spawn(?MODULE, ssh_info_handler, [Options, Ssh, From]),
{next_state, StateName, State};
-
+handle_event(data_size, connected, #state{ssh_params = Ssh0} = State) ->
+ Sent = inet:getstat(State#state.socket, [send_oct]),
+ MaxSent = proplists:get_value(rekey_limit, State#state.opts, 1024000000),
+ case Sent >= MaxSent of
+ true ->
+ {KeyInitMsg, SshPacket, Ssh} = ssh_transport:key_exchange_init_msg(Ssh0),
+ send_msg(SshPacket, State),
+ {next_state, connected,
+ next_packet(State#state{ssh_params = Ssh,
+ key_exchange_init_msg = KeyInitMsg,
+ renegotiate = true})};
+ _ ->
+ {next_state, connected, next_packet(State)}
+ end;
+handle_event(data_size, StateName, State) ->
+ {next_state, StateName, State};
handle_event({unknown, Data}, StateName, State) ->
Msg = #ssh_msg_unimplemented{sequence = Data},
send_msg(Msg, State),
@@ -718,8 +740,18 @@ init_ssh(server = Role, Vsn, Version, Options, Socket) ->
available_host_keys = supported_host_keys(Role, KeyCb, Options)
}.
-supported_host_keys(client, _, _) ->
- ["ssh-rsa", "ssh-dss"];
+supported_host_keys(client, _, Options) ->
+ try
+ case extract_algs(proplists:get_value(pref_public_key_algs, Options, false), []) of
+ false ->
+ ["ssh-rsa", "ssh-dss"];
+ Algs ->
+ Algs
+ end
+ catch
+ exit:Reason ->
+ {stop, {shutdown, Reason}}
+ end;
supported_host_keys(server, KeyCb, Options) ->
lists:foldl(fun(Type, Acc) ->
case available_host_key(KeyCb, Type, Options) of
@@ -731,7 +763,19 @@ supported_host_keys(server, KeyCb, Options) ->
end, [],
%% Prefered alg last so no need to reverse
["ssh-dss", "ssh-rsa"]).
-
+extract_algs(false, _) ->
+ false;
+extract_algs([],[]) ->
+ false;
+extract_algs([], NewList) ->
+ lists:reverse(NewList);
+extract_algs([H|T], NewList) ->
+ case H of
+ 'ssh-dss' ->
+ extract_algs(T, ["ssh-dss"|NewList]);
+ 'ssh-rsa' ->
+ extract_algs(T, ["ssh-rsa"|NewList])
+ end.
available_host_key(KeyCb, "ssh-dss"= Alg, Opts) ->
case KeyCb:host_key('ssh-dss', Opts) of
{ok, _} ->
diff --git a/lib/ssh/src/ssh_connection_manager.erl b/lib/ssh/src/ssh_connection_manager.erl
index e53cd4f4f7..94a9ed505f 100644
--- a/lib/ssh/src/ssh_connection_manager.erl
+++ b/lib/ssh/src/ssh_connection_manager.erl
@@ -40,7 +40,7 @@
close/2, stop/1, send/5,
send_eof/2]).
--export([open_channel/6, request/6, request/7, global_request/4, event/2,
+-export([open_channel/6, reply_request/3, request/6, request/7, global_request/4, event/2,
cast/2]).
%% Internal application API and spawn
@@ -62,6 +62,7 @@
latest_channel_id = 0,
opts,
channel_args,
+ idle_timer_ref, % timerref
connected
}).
@@ -95,6 +96,9 @@ request(ConnectionManager, ChannelId, Type, true, Data, Timeout) ->
request(ConnectionManager, ChannelId, Type, false, Data, _) ->
cast(ConnectionManager, {request, ChannelId, Type, Data}).
+reply_request(ConnectionManager, Status, ChannelId) ->
+ cast(ConnectionManager, {reply_request, Status, ChannelId}).
+
global_request(ConnectionManager, Type, true = Reply, Data) ->
case call(ConnectionManager,
{global_request, self(), Type, Reply, Data}) of
@@ -121,7 +125,8 @@ info(ConnectionManager, ChannelProcess) ->
%% or amount of data sent counter!
renegotiate(ConnectionManager) ->
cast(ConnectionManager, renegotiate).
-
+renegotiate_data(ConnectionManager) ->
+ cast(ConnectionManager, renegotiate_data).
connection_info(ConnectionManager, Options) ->
call(ConnectionManager, {connection_info, Options}).
@@ -163,7 +168,7 @@ send(ConnectionManager, ChannelId, Type, Data, Timeout) ->
call(ConnectionManager, {data, ChannelId, Type, Data}, Timeout).
send_eof(ConnectionManager, ChannelId) ->
- cast(ConnectionManager, {eof, ChannelId}).
+ call(ConnectionManager, {eof, ChannelId}).
%%====================================================================
%% gen_server callbacks
@@ -200,6 +205,8 @@ init([client, Opts]) ->
ChannelPid = proplists:get_value(channel_pid, Opts),
self() !
{start_connection, client, [Parent, Address, Port, SocketOpts, Options]},
+ TimerRef = get_idle_time(Options),
+
{ok, #state{role = client,
client = ChannelPid,
connection_state = #connection{channel_cache = Cache,
@@ -208,6 +215,7 @@ init([client, Opts]) ->
connection_supervisor = Parent,
requests = []},
opts = Opts,
+ idle_timer_ref = TimerRef,
connected = false}}.
%%--------------------------------------------------------------------
@@ -227,6 +235,13 @@ handle_call({request, ChannelPid, ChannelId, Type, Data}, From, State0) ->
%% channel is sent later when reply arrives from the connection
%% handler.
lists:foreach(fun send_msg/1, Replies),
+ SshOpts = proplists:get_value(ssh_opts, State0#state.opts),
+ case proplists:get_value(idle_time, SshOpts) of
+ infinity ->
+ ok;
+ _IdleTime ->
+ erlang:send_after(5000, self(), {check_cache, [], []})
+ end,
{noreply, State};
handle_call({request, ChannelId, Type, Data}, From, State0) ->
@@ -295,6 +310,18 @@ handle_call({data, ChannelId, Type, Data}, From,
channel_data(ChannelId, Type, Data, Connection0, ConnectionPid, From,
State);
+handle_call({eof, ChannelId}, _From,
+ #state{connection = Pid, connection_state =
+ #connection{channel_cache = Cache}} = State) ->
+ case ssh_channel:cache_lookup(Cache, ChannelId) of
+ #channel{remote_id = Id, sent_close = false} ->
+ send_msg({connection_reply, Pid,
+ ssh_connection:channel_eof_msg(Id)}),
+ {reply, ok, State};
+ _ ->
+ {reply, {error,closed}, State}
+ end;
+
handle_call({connection_info, Options}, From,
#state{connection = Connection} = State) ->
ssh_connection_handler:connection_info(Connection, From, Options),
@@ -343,7 +370,7 @@ handle_call({open, ChannelPid, Type, InitialWindowSize, MaxPacketSize, Data},
recv_packet_size = MaxPacketSize},
ssh_channel:cache_update(Cache, Channel),
State = add_request(true, ChannelId, From, State1),
- {noreply, State};
+ {noreply, remove_timer_ref(State)};
handle_call({send_window, ChannelId}, _From,
#state{connection_state =
@@ -388,6 +415,13 @@ handle_call({close, ChannelId}, _,
send_msg({connection_reply, Pid,
ssh_connection:channel_close_msg(Id)}),
ssh_channel:cache_update(Cache, Channel#channel{sent_close = true}),
+ SshOpts = proplists:get_value(ssh_opts, State#state.opts),
+ case proplists:get_value(idle_time, SshOpts) of
+ infinity ->
+ ok;
+ _IdleTime ->
+ erlang:send_after(5000, self(), {check_cache, [], []})
+ end,
{reply, ok, State};
undefined ->
{reply, ok, State}
@@ -431,6 +465,16 @@ handle_cast({request, ChannelId, Type, Data}, State0) ->
lists:foreach(fun send_msg/1, Replies),
{noreply, State};
+handle_cast({reply_request, Status, ChannelId}, #state{connection_state =
+ #connection{channel_cache = Cache}} = State0) ->
+ State = case ssh_channel:cache_lookup(Cache, ChannelId) of
+ #channel{remote_id = RemoteId} ->
+ cm_message({Status, RemoteId}, State0);
+ undefined ->
+ State0
+ end,
+ {noreply, State};
+
handle_cast({global_request, _, _, _, _} = Request, State0) ->
State = handle_global_request(Request, State0),
{noreply, State};
@@ -438,7 +482,9 @@ handle_cast({global_request, _, _, _, _} = Request, State0) ->
handle_cast(renegotiate, #state{connection = Pid} = State) ->
ssh_connection_handler:renegotiate(Pid),
{noreply, State};
-
+handle_cast(renegotiate_data, #state{connection = Pid} = State) ->
+ ssh_connection_handler:renegotiate_data(Pid),
+ {noreply, State};
handle_cast({adjust_window, ChannelId, Bytes},
#state{connection = Pid, connection_state =
#connection{channel_cache = Cache}} = State) ->
@@ -453,18 +499,6 @@ handle_cast({adjust_window, ChannelId, Bytes},
end,
{noreply, State};
-handle_cast({eof, ChannelId},
- #state{connection = Pid, connection_state =
- #connection{channel_cache = Cache}} = State) ->
- case ssh_channel:cache_lookup(Cache, ChannelId) of
- #channel{remote_id = Id} ->
- send_msg({connection_reply, Pid,
- ssh_connection:channel_eof_msg(Id)}),
- {noreply, State};
- undefined ->
- {noreply, State}
- end;
-
handle_cast({success, ChannelId}, #state{connection = Pid} = State) ->
Msg = ssh_connection:channel_success_msg(ChannelId),
send_msg({connection_reply, Pid, Msg}),
@@ -489,6 +523,8 @@ handle_info({start_connection, server,
Exec = proplists:get_value(exec, Options),
CliSpec = proplists:get_value(ssh_cli, Options, {ssh_cli, [Shell]}),
ssh_connection_handler:send_event(Connection, socket_control),
+ erlang:send_after(3600000, self(), rekey),
+ erlang:send_after(60000, self(), rekey_data),
{noreply, State#state{connection = Connection,
connection_state =
CState#connection{address = Address,
@@ -505,12 +541,17 @@ handle_info({start_connection, client,
case (catch ssh_transport:connect(Parent, Address,
Port, SocketOpts, Options)) of
{ok, Connection} ->
+ erlang:send_after(60000, self(), rekey_data),
+ erlang:send_after(3600000, self(), rekey),
{noreply, State#state{connection = Connection}};
Reason ->
Pid ! {self(), not_connected, Reason},
{stop, {shutdown, normal}, State}
end;
-
+handle_info({check_cache, _ , _},
+ #state{connection_state =
+ #connection{channel_cache = Cache}} = State) ->
+ {noreply, check_cache(State, Cache)};
handle_info({ssh_cm, _Sender, Msg}, State0) ->
%% Backwards compatibility!
State = cm_message(Msg, State0),
@@ -523,7 +564,7 @@ handle_info({same_user, _}, State) ->
handle_info(ssh_connected, #state{role = client, client = Pid}
= State) ->
Pid ! {self(), is_connected},
- {noreply, State#state{connected = true}};
+ {noreply, State#state{connected = true, opts = handle_password(State#state.opts)}};
handle_info(ssh_connected, #state{role = server} = State) ->
{noreply, State#state{connected = true}};
@@ -534,8 +575,56 @@ handle_info({'DOWN', _Ref, process, ChannelPid, _Reason}, State) ->
%%% So that terminate will be run when supervisor is shutdown
handle_info({'EXIT', _Sup, Reason}, State) ->
- {stop, Reason, State}.
-
+ {stop, Reason, State};
+handle_info(rekey, State) ->
+ renegotiate(self()),
+ erlang:send_after(3600000, self(), rekey),
+ {noreply, State};
+handle_info(rekey_data, State) ->
+ renegotiate_data(self()),
+ erlang:send_after(60000, self(), rekey_data),
+ {noreply, State}.
+handle_password(Opts) ->
+ handle_rsa_password(handle_dsa_password(handle_normal_password(Opts))).
+handle_normal_password(Opts) ->
+ case proplists:get_value(ssh_opts, Opts, false) of
+ false ->
+ Opts;
+ SshOpts ->
+ case proplists:get_value(password, SshOpts, false) of
+ false ->
+ Opts;
+ _Password ->
+ NewOpts = [{password, undefined}|lists:keydelete(password, 1, SshOpts)],
+ [{ssh_opts, NewOpts}|lists:keydelete(ssh_opts, 1, Opts)]
+ end
+ end.
+handle_dsa_password(Opts) ->
+ case proplists:get_value(ssh_opts, Opts, false) of
+ false ->
+ Opts;
+ SshOpts ->
+ case proplists:get_value(dsa_pass_phrase, SshOpts, false) of
+ false ->
+ Opts;
+ _Password ->
+ NewOpts = [{dsa_pass_phrase, undefined}|lists:keydelete(dsa_pass_phrase, 1, SshOpts)],
+ [{ssh_opts, NewOpts}|lists:keydelete(ssh_opts, 1, Opts)]
+ end
+ end.
+handle_rsa_password(Opts) ->
+ case proplists:get_value(ssh_opts, Opts, false) of
+ false ->
+ Opts;
+ SshOpts ->
+ case proplists:get_value(rsa_pass_phrase, SshOpts, false) of
+ false ->
+ Opts;
+ _Password ->
+ NewOpts = [{rsa_pass_phrase, undefined}|lists:keydelete(rsa_pass_phrase, 1, SshOpts)],
+ [{ssh_opts, NewOpts}|lists:keydelete(ssh_opts, 1, Opts)]
+ end
+ end.
%%--------------------------------------------------------------------
%% Function: terminate(Reason, State) -> void()
%% Description: This function is called by a gen_server when it is about to
@@ -567,6 +656,45 @@ code_change(_OldVsn, State, _Extra) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
+get_idle_time(SshOptions) ->
+ case proplists:get_value(idle_time, SshOptions) of
+ infinity ->
+ infinity;
+ _IdleTime -> %% We dont want to set the timeout on first connect
+ undefined
+ end.
+check_cache(State, Cache) ->
+ %% Check the number of entries in Cache
+ case proplists:get_value(size, ets:info(Cache)) of
+ 0 ->
+ Opts = proplists:get_value(ssh_opts, State#state.opts),
+ case proplists:get_value(idle_time, Opts) of
+ infinity ->
+ State;
+ undefined ->
+ State;
+ Time ->
+ case State#state.idle_timer_ref of
+ undefined ->
+ TimerRef = erlang:send_after(Time, self(), {'EXIT', [], "Timeout"}),
+ State#state{idle_timer_ref=TimerRef};
+ _ ->
+ State
+ end
+ end;
+ _ ->
+ State
+ end.
+remove_timer_ref(State) ->
+ case State#state.idle_timer_ref of
+ infinity -> %% If the timer is not activated
+ State;
+ undefined -> %% If we already has cancelled the timer
+ State;
+ TimerRef -> %% Timer is active
+ erlang:cancel_timer(TimerRef),
+ State#state{idle_timer_ref = undefined}
+ end.
channel_data(Id, Type, Data, Connection0, ConnectionPid, From, State) ->
case ssh_connection:channel_data(Id, Type, Data, Connection0,
ConnectionPid, From) of
@@ -614,6 +742,8 @@ do_send_msg({connection_reply, Pid, Data}) ->
ssh_connection_handler:send(Pid, Msg);
do_send_msg({flow_control, Cache, Channel, From, Msg}) ->
ssh_channel:cache_update(Cache, Channel#channel{flow_control = undefined}),
+ gen_server:reply(From, Msg);
+do_send_msg({flow_control, From, Msg}) ->
gen_server:reply(From, Msg).
handle_request(ChannelPid, ChannelId, Type, Data, WantReply, From,
@@ -662,7 +792,7 @@ handle_channel_down(ChannelPid, #state{connection_state =
(_,Acc) ->
Acc
end, [], Cache),
- {{replies, []}, State}.
+ {{replies, []}, check_cache(State, Cache)}.
update_sys(Cache, Channel, Type, ChannelPid) ->
ssh_channel:cache_update(Cache,
diff --git a/lib/ssh/src/ssh_file.erl b/lib/ssh/src/ssh_file.erl
index a6b82a7a13..f115a32710 100644
--- a/lib/ssh/src/ssh_file.erl
+++ b/lib/ssh/src/ssh_file.erl
@@ -23,7 +23,8 @@
-module(ssh_file).
--behaviour(ssh_key_api).
+-behaviour(ssh_server_key_api).
+-behaviour(ssh_client_key_api).
-include_lib("public_key/include/public_key.hrl").
-include_lib("kernel/include/file.hrl").
@@ -34,7 +35,7 @@
user_key/2,
is_host_key/4,
add_host_key/3,
- is_auth_key/4]).
+ is_auth_key/3]).
-define(PERM_700, 8#700).
@@ -53,8 +54,8 @@ host_key(Algorithm, Opts) ->
decode(File, Password).
-is_auth_key(Key, User, Alg, Opts) ->
- case lookup_user_key(Key, User, Alg, Opts) of
+is_auth_key(Key, User,Opts) ->
+ case lookup_user_key(Key, User, Opts) of
{ok, Key} ->
true;
_ ->
@@ -138,13 +139,13 @@ add_host_key(Host, Key, Opts) ->
Error
end.
-lookup_user_key(Key, User, Alg, Opts) ->
+lookup_user_key(Key, User, Opts) ->
SshDir = ssh_dir({remoteuser,User}, Opts),
- case lookup_user_key_f(Key, User, SshDir, Alg, "authorized_keys", Opts) of
+ case lookup_user_key_f(Key, User, SshDir, "authorized_keys", Opts) of
{ok, Key} ->
{ok, Key};
_ ->
- lookup_user_key_f(Key, User, SshDir, Alg, "authorized_keys2", Opts)
+ lookup_user_key_f(Key, User, SshDir, "authorized_keys2", Opts)
end.
@@ -213,9 +214,9 @@ do_lookup_host_key(Host, Alg, Opts) ->
Error -> Error
end.
-identity_key_filename("ssh-dss") ->
+identity_key_filename('ssh-dss') ->
"id_dsa";
-identity_key_filename("ssh-rsa") ->
+identity_key_filename('ssh-rsa') ->
"id_rsa".
identity_pass_phrase("ssh-dss") ->
@@ -261,9 +262,9 @@ host_name(Atom) when is_atom(Atom) ->
host_name(List) ->
List.
-key_match(#'RSAPublicKey'{}, "ssh-rsa") ->
+key_match(#'RSAPublicKey'{}, 'ssh-rsa') ->
true;
-key_match({_, #'Dss-Parms'{}}, "ssh-dss") ->
+key_match({_, #'Dss-Parms'{}}, 'ssh-dss') ->
true;
key_match(_, _) ->
false.
@@ -272,11 +273,11 @@ add_key_fd(Fd, Host,Key) ->
SshBin = public_key:ssh_encode([{Key, [{hostnames, [Host]}]}], known_hosts),
file:write(Fd, SshBin).
-lookup_user_key_f(_, _User, [], _Alg, _F, _Opts) ->
+lookup_user_key_f(_, _User, [], _F, _Opts) ->
{error, nouserdir};
-lookup_user_key_f(_, _User, nouserdir, _Alg, _F, _Opts) ->
+lookup_user_key_f(_, _User, nouserdir, _F, _Opts) ->
{error, nouserdir};
-lookup_user_key_f(Key, _User, Dir, _Alg, F, _Opts) ->
+lookup_user_key_f(Key, _User, Dir, F, _Opts) ->
FileName = filename:join(Dir, F),
case file:open(FileName, [read, binary]) of
{ok, Fd} ->
diff --git a/lib/ssh/src/ssh_io.erl b/lib/ssh/src/ssh_io.erl
index 1dbd097423..01fc713569 100644
--- a/lib/ssh/src/ssh_io.erl
+++ b/lib/ssh/src/ssh_io.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -23,37 +23,52 @@
-module(ssh_io).
--export([yes_no/1, read_password/1, read_line/1, format/2]).
+-export([yes_no/2, read_password/2, read_line/2, format/2]).
-import(lists, [reverse/1]).
+-include("ssh.hrl").
+read_line(Prompt, Ssh) ->
+ format("~s", [listify(Prompt)]),
+ proplists:get_value(user_pid, Ssh) ! {self(), question},
+ receive
+ Answer ->
+ Answer
+ end.
-read_line(Prompt) when is_list(Prompt) ->
- io:get_line(list_to_atom(Prompt));
-read_line(Prompt) when is_atom(Prompt) ->
- io:get_line(Prompt).
-
-read_ln(Prompt) ->
- trim(read_line(Prompt)).
-
-yes_no(Prompt) ->
+yes_no(Prompt, Ssh) ->
io:format("~s [y/n]?", [Prompt]),
- case read_ln('') of
- "y" -> yes;
- "n" -> no;
- "Y" -> yes;
- "N" -> no;
- _ ->
- io:format("please answer y or n\n"),
- yes_no(Prompt)
+ proplists:get_value(user_pid, Ssh#ssh.opts) ! {self(), question},
+ receive
+ 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"),
+ yes_no(Prompt, Ssh)
+ end
end.
-read_password(Prompt) ->
+read_password(Prompt, Ssh) ->
format("~s", [listify(Prompt)]),
- case io:get_password() of
- "" ->
- read_password(Prompt);
- Pass -> Pass
+ 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,
+ receive
+ Answer ->
+ case Answer of
+ "" ->
+ read_password(Prompt, Ssh);
+ Pass -> Pass
+ end
end.
listify(A) when is_atom(A) ->
diff --git a/lib/ssh/src/ssh_key_api.erl b/lib/ssh/src/ssh_key_api.erl
deleted file mode 100644
index 8085c12e21..0000000000
--- a/lib/ssh/src/ssh_key_api.erl
+++ /dev/null
@@ -1,45 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2011-2012. All Rights Reserved.
-%%
-%% The 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(ssh_key_api).
-
--include_lib("public_key/include/public_key.hrl").
--include("ssh.hrl").
-
--type ssh_algorithm() :: string().
--type file_error() :: file:posix() | badarg | system_limit | terminated.
-
--callback host_key(Algorithm :: ssh_algorithm(), Options :: list()) ->
- {ok, [{public_key(), Attributes::list()}]} | public_key()
- | {error, string()}.
-
--callback user_key(Algorithm :: ssh_algorithm(), Options :: list()) ->
- {ok, [{public_key(), Attributes::list()}]} | public_key()
- | {error, string()}.
-
--callback is_host_key(Key :: public_key(), PeerName :: string(),
- Algorithm :: ssh_algorithm(), Options :: list()) ->
- boolean().
-
--callback add_host_key(Host :: string(), Key :: public_key(), Options :: list()) ->
- ok | {error, file_error()}.
-
--callback is_auth_key(Key :: public_key(), User :: string(),
- Algorithm :: ssh_algorithm(), Options :: list()) ->
- boolean().
diff --git a/lib/stdlib/test/erl_eval_helper.erl b/lib/ssh/src/ssh_server_key.erl
index 6863b40108..8140114990 100644
--- a/lib/stdlib/test/erl_eval_helper.erl
+++ b/lib/ssh/src/ssh_server_key.erl
@@ -1,28 +1,33 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2005-2010. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2011-2012. All Rights Reserved.
+%%
%% The 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(erl_eval_helper, [Base]).
-
--export([add/1]).
+-module(ssh_server_key).
-add(Arg) ->
- Base+Arg.
+-include_lib("public_key/include/public_key.hrl").
+-include("ssh.hrl").
+-type ssh_algorithm() :: string().
+-callback host_key(Algorithm :: ssh_algorithm(), Options :: list()) ->
+ {ok, [{public_key(), Attributes::list()}]} | public_key()
+ | {error, string()}.
+-callback is_auth_key(Key :: public_key(), User :: string(),
+ Algorithm :: ssh_algorithm(), Options :: list()) ->
+ boolean().
diff --git a/lib/test_server/test/test_server_line_SUITE_data/parse_transform_test.erl b/lib/ssh/src/ssh_server_key_api.erl
index 8f3477d3ac..4fd660ecb5 100644
--- a/lib/test_server/test/test_server_line_SUITE_data/parse_transform_test.erl
+++ b/lib/ssh/src/ssh_server_key_api.erl
@@ -1,59 +1,30 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2011-2012. All Rights Reserved.
+%%
%% The 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(parse_transform_test).
-
--include("test_server_line.hrl").
--no_lines([{excluded,0}]).
-
--export([excluded/0, func/0]).
-
-
-excluded() ->
- line1,
- line2,
- ok.
+-module(ssh_server_key_api).
-func() ->
- hello,
- func1(),
- case func2() of
- ok ->
- helloagain,
- case func3() of
- ok ->
- ok;
- error ->
- error
- end;
- error ->
- error
- end,
- excluded(),
- func4().
+-include_lib("public_key/include/public_key.hrl").
+-include("ssh.hrl").
-func1() ->
- ok.
-func2() ->
- ok.
-func3() ->
- error.
-func4() ->
- ok.
+-callback host_key(Algorithm :: 'ssh-rsa'| 'ssh-dss'| atom(), DaemonOptions :: proplists:proplist()) ->
+ {ok, PrivateKey :: #'RSAPrivateKey'{}| #'DSAPrivateKey'{} | term()} | {error, string()}.
+-callback is_auth_key(PublicKey :: #'RSAPublicKey'{}| {integer(), #'Dss-Parms'{}}| term(),
+ User :: string(), DaemonOptions :: proplists:proplist()) ->
+ boolean().
diff --git a/lib/ssh/src/ssh_sftpd.erl b/lib/ssh/src/ssh_sftpd.erl
index ec7b76b0b3..c7e8373840 100644
--- a/lib/ssh/src/ssh_sftpd.erl
+++ b/lib/ssh/src/ssh_sftpd.erl
@@ -24,7 +24,7 @@
-module(ssh_sftpd).
%%-behaviour(gen_server).
--behaviour(ssh_channel).
+-behaviour(ssh_subsystem).
-include_lib("kernel/include/file.hrl").
@@ -36,7 +36,7 @@
-export([subsystem_spec/1,
listen/1, listen/2, listen/3, stop/1]).
--export([init/1, handle_ssh_msg/2, handle_msg/2, terminate/2, code_change/3]).
+-export([init/1, handle_ssh_msg/2, handle_msg/2, terminate/2]).
-record(state, {
xf, % [{channel,ssh_xfer states}...]
@@ -119,23 +119,13 @@ init(Options) ->
{Root0, State0}
end,
MaxLength = proplists:get_value(max_files, Options, 0),
-
- Vsn = proplists:get_value(vsn, Options, 5),
-
+ Vsn = proplists:get_value(sftpd_vsn, Options, 5),
{ok, State#state{cwd = CWD, root = Root, max_files = MaxLength,
handles = [], pending = <<>>,
xf = #ssh_xfer{vsn = Vsn, ext = []}}}.
%%--------------------------------------------------------------------
-%% Function: code_change(OldVsn, State, Extra) -> {ok, NewState}
-%% Description:
-%%--------------------------------------------------------------------
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-
-%%--------------------------------------------------------------------
%% Function: handle_ssh_msg(Args) -> {ok, State} | {stop, ChannelId, State}
%%
%% Description: Handles channel messages
@@ -369,17 +359,21 @@ handle_op(?SSH_FXP_FSETSTAT, ReqId, <<?UINT32(HLen), BinHandle:HLen/binary,
State0
end;
handle_op(?SSH_FXP_REMOVE, ReqId, <<?UINT32(PLen), BPath:PLen/binary>>,
- State0 = #state{file_handler = FileMod, file_state = FS0}) ->
+ State0 = #state{file_handler = FileMod, file_state = FS0, xf = #ssh_xfer{vsn = Vsn}}) ->
Path = relate_file_name(BPath, State0),
- %% case FileMod:is_dir(Path) of %% This version 6 we still have ver 5
- %% true ->
- %% ssh_xfer:xf_send_status(State#state.xf, ReqId,
- %% ?SSH_FX_FILE_IS_A_DIRECTORY);
- %% false ->
- {Status, FS1} = FileMod:delete(Path, FS0),
- State1 = State0#state{file_state = FS1},
- send_status(Status, ReqId, State1);
- %%end;
+ {IsDir, _FS1} = FileMod:is_dir(Path, FS0),
+ 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");
+ true ->
+ ssh_xfer:xf_send_status(State0#state.xf, ReqId,
+ ?SSH_FX_FAILURE, "File is a directory");
+ false ->
+ {Status, FS1} = FileMod:delete(Path, FS0),
+ State1 = State0#state{file_state = FS1},
+ send_status(Status, ReqId, State1)
+ end;
handle_op(?SSH_FXP_RMDIR, ReqId, <<?UINT32(PLen), BPath:PLen/binary>>,
State0 = #state{file_handler = FileMod, file_state = FS0}) ->
Path = relate_file_name(BPath, State0),
@@ -637,31 +631,34 @@ 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} = State0,
+ #state{file_handler = FileMod, file_state = FS0, root = Root, xf = #ssh_xfer{vsn = Vsn}} = State0,
XF = State0#state.xf,
F = [binary | Flags],
- %% case FileMod:is_dir(Path) of %% This is version 6 we still have 5
- %% true ->
- %% ssh_xfer:xf_send_status(State#state.xf, ReqId,
- %% ?SSH_FX_FILE_IS_A_DIRECTORY);
- %% false ->
-
- AbsPath = case Root of
- "" ->
- Path;
- _ ->
- relate_file_name(Path, State0)
- end,
-
- {Res, FS1} = FileMod:open(AbsPath, F, FS0),
- State1 = State0#state{file_state = FS1},
- case Res of
- {ok, IoDevice} ->
- add_handle(State1, XF, ReqId, file, {Path,IoDevice});
- {error, Error} ->
- ssh_xfer:xf_send_status(State1#state.xf, ReqId,
- ssh_xfer:encode_erlang_status(Error)),
- State1
+ {IsDir, _FS1} = FileMod:is_dir(Path, 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");
+ true ->
+ ssh_xfer:xf_send_status(State0#state.xf, ReqId,
+ ?SSH_FX_FAILURE, "File is a directory");
+ false ->
+ AbsPath = case Root of
+ "" ->
+ Path;
+ _ ->
+ relate_file_name(Path, State0)
+ end,
+ {Res, FS1} = FileMod:open(AbsPath, F, FS0),
+ State1 = State0#state{file_state = FS1},
+ case Res of
+ {ok, IoDevice} ->
+ add_handle(State1, XF, ReqId, file, {Path,IoDevice});
+ {error, Error} ->
+ ssh_xfer:xf_send_status(State1#state.xf, ReqId,
+ ssh_xfer:encode_erlang_status(Error)),
+ State1
+ end
end.
%% resolve all symlinks in a path
diff --git a/lib/ssh/src/ssh_subsystem.erl b/lib/ssh/src/ssh_subsystem.erl
new file mode 100644
index 0000000000..5a9fa32668
--- /dev/null
+++ b/lib/ssh/src/ssh_subsystem.erl
@@ -0,0 +1,47 @@
+-module(ssh_subsystem).
+
+%% API to special server side channel that can be pluged into the erlang ssh daemeon
+-callback init(Args :: term()) ->
+ {ok, State :: term()} | {ok, State :: term(), timeout() | hibernate} |
+ {stop, Reason :: term()} | ignore.
+
+-callback terminate(Reason :: (normal | shutdown | {shutdown, term()} |
+ term()),
+ State :: term()) ->
+ term().
+
+-callback handle_msg(Msg ::term(), State :: term()) ->
+ {noreply, NewState :: term()} |
+ {noreply, NewState :: term(), timeout() | hibernate} |
+ {stop, Reason :: term(), NewState :: term()}.
+
+-callback handle_ssh_msg({ssh_cm, ConnectionRef::term(), SshMsg::term()},
+ State::term()) -> {ok, State::term()} |
+ {stop, ChannelId::integer(),
+ State::term()}.
+
+%%% API
+-export([start/4, start/5, start_link/4, start_link/5, enter_loop/1]).
+
+%% gen_server callbacks
+-export([init/1, terminate/2]).
+
+start(ConnectionManager, ChannelId, CallBack, CbInitArgs) ->
+ ssh_channel:start(ConnectionManager, ChannelId, CallBack, CbInitArgs, undefined).
+
+start(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec) ->
+ ssh_channel:start(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec).
+
+start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs) ->
+ ssh_channel:start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, undefined).
+
+start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec) ->
+ ssh_channel:start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec).
+
+enter_loop(State) ->
+ ssh_channel:enter_loop(State).
+
+init(Args) ->
+ ssh_channel:init(Args).
+terminate(Reason, State) ->
+ ssh_channel:terminate(Reason, State).
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 1f912c9bdf..1abb69921d 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -133,7 +133,7 @@ kex_dh_gex_messages() ->
].
yes_no(Ssh, Prompt) ->
- (Ssh#ssh.io_cb):yes_no(Prompt).
+ (Ssh#ssh.io_cb):yes_no(Prompt, Ssh).
connect(ConnectionSup, Address, Port, SocketOpts, Opts) ->
Timeout = proplists:get_value(connect_timeout, Opts, infinity),
@@ -449,7 +449,7 @@ verify_host_key_rsa(SSH, K_S, H, H_SIG) ->
false ->
{error, bad_signature};
true ->
- known_host_key(SSH, Public, "ssh-rsa")
+ known_host_key(SSH, Public, 'ssh-rsa')
end;
_ ->
{error, bad_format}
@@ -464,7 +464,7 @@ verify_host_key_dss(SSH, K_S, H, H_SIG) ->
false ->
{error, bad_signature};
true ->
- known_host_key(SSH, Public, "ssh-dss")
+ known_host_key(SSH, Public, 'ssh-dss')
end;
_ ->
{error, bad_host_key_format}
diff --git a/lib/ssh/src/ssh_xfer.erl b/lib/ssh/src/ssh_xfer.erl
index d5b6dd03d1..4dfd9ed8b0 100644
--- a/lib/ssh/src/ssh_xfer.erl
+++ b/lib/ssh/src/ssh_xfer.erl
@@ -383,6 +383,8 @@ decode_status(Status) ->
?SSH_FX_UNKNOWN_PRINCIPLE -> unknown_principle;
?SSH_FX_LOCK_CONFlICT -> lock_conflict;
?SSH_FX_NOT_A_DIRECTORY -> not_a_directory;
+ ?SSH_FX_FILE_IS_A_DIRECTORY -> file_is_a_directory;
+ ?SSH_FX_CANNOT_DELETE -> cannot_delete;
_ -> {error,Status}
end.
@@ -392,6 +394,9 @@ encode_erlang_status(Status) ->
eof -> ?SSH_FX_EOF;
enoent -> ?SSH_FX_NO_SUCH_FILE;
eacces -> ?SSH_FX_PERMISSION_DENIED;
+ eisdir -> ?SSH_FX_FILE_IS_A_DIRECTORY;
+ eperm -> ?SSH_FX_CANNOT_DELETE;
+ eexist -> ?SSH_FX_FILE_ALREADY_EXISTS;
_ -> ?SSH_FX_FAILURE
end.
diff --git a/lib/ssh/src/ssh_xfer.hrl b/lib/ssh/src/ssh_xfer.hrl
index c13950eb6e..0d85cf2094 100644
--- a/lib/ssh/src/ssh_xfer.hrl
+++ b/lib/ssh/src/ssh_xfer.hrl
@@ -58,7 +58,6 @@
%%% # SSH_FX_xxx
%%% Description: Response packet types for file transfer protocol.
%%%----------------------------------------------------------------------
-
-define(SSH_FX_OK, 0).
-define(SSH_FX_EOF, 1).
-define(SSH_FX_NO_SUCH_FILE, 2).
@@ -79,7 +78,18 @@
-define(SSH_FX_LOCK_CONFlICT, 17).
-define(SSH_FX_DIR_NOT_EMPTY, 18).
-define(SSH_FX_NOT_A_DIRECTORY, 19).
+-define(SSH_FX_INVALID_FILENAME, 20).
+-define(SSH_FX_LINK_LOOP, 21).
+-define(SSH_FX_CANNOT_DELETE, 22).
+-define(SSH_FX_INVALID_PARAMETER, 23).
-define(SSH_FX_FILE_IS_A_DIRECTORY, 24).
+-define(SSH_FX_BYTE_RANGE_LOCK_CONFLICT,25).
+-define(SSH_FX_BYTE_RANGE_LOCK_REFUSED, 26).
+-define(SSH_FX_DELETE_PENDING, 27).
+-define(SSH_FX_FILE_CORRUPT, 28).
+-define(SSH_FX_OWNER_INVALID, 29).
+-define(SSH_FX_GROUP_INVALID, 30).
+-define(SSH_FX_NO_MATCHING_BYTE_RANGE_LOCK,31).
%%%----------------------------------------------------------------------
%%% # SSH_FILEXFER_xxx
diff --git a/lib/ssh/test/Makefile b/lib/ssh/test/Makefile
index 25072688ad..f5db31baee 100644
--- a/lib/ssh/test/Makefile
+++ b/lib/ssh/test/Makefile
@@ -36,7 +36,9 @@ MODULES= \
ssh_to_openssh_SUITE \
ssh_sftp_SUITE \
ssh_sftpd_SUITE \
- ssh_sftpd_erlclient_SUITE
+ ssh_sftpd_erlclient_SUITE \
+ ssh_connection_SUITE \
+ ssh_echo_server
HRL_FILES_NEEDED_IN_TEST= \
$(ERL_TOP)/lib/ssh/src/ssh.hrl \
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index c224e5b800..efcb11f88f 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -22,7 +22,6 @@
-module(ssh_basic_SUITE).
-include_lib("common_test/include/ct.hrl").
--include("test_server_line.hrl").
%% Note: This directive should only be used in test suites.
-compile(export_all).
@@ -30,78 +29,12 @@
-define(NEWLINE, <<"\r\n">>).
%%--------------------------------------------------------------------
-%% Function: init_per_suite(Config) -> Config
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Initialization before the whole suite
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
+%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
-init_per_suite(Config) ->
- case catch crypto:start() of
- ok ->
- Config;
- _Else ->
- {skip, "Crypto could not be started!"}
- end.
-%%--------------------------------------------------------------------
-%% Function: end_per_suite(Config) -> _
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after the whole suite
-%%--------------------------------------------------------------------
-end_per_suite(_Config) ->
- ssh:stop(),
- crypto:stop(),
- ok.
-
-%%--------------------------------------------------------------------
-%% Function: init_per_testcase(TestCase, Config) -> Config
-%% Case - atom()
-%% Name of the test case that is about to be run.
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%%
-%% Description: Initialization before each test case
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
-%% Description: Initialization before each test case
-%%--------------------------------------------------------------------
-init_per_testcase(_TestCase, Config) ->
- ssh:start(),
- Config.
+suite() ->
+ [{ct_hooks,[ts_install_cth]}].
-%%--------------------------------------------------------------------
-%% Function: end_per_testcase(TestCase, Config) -> _
-%% Case - atom()
-%% Name of the test case that is about to be run.
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after each test case
-%%--------------------------------------------------------------------
-
-end_per_testcase(TestCase, Config) when TestCase == server_password_option;
- TestCase == server_userpassword_option ->
- UserDir = filename:join(?config(priv_dir, Config), nopubkey),
- ssh_test_lib:del_dirs(UserDir),
- end_per_testcase(Config);
-end_per_testcase(_TestCase, Config) ->
- end_per_testcase(Config).
-end_per_testcase(_Config) ->
- ssh:stop(),
- ok.
-
-%%--------------------------------------------------------------------
-%% Function: all(Clause) -> TestCases
-%% Clause - atom() - suite | doc
-%% TestCases - [Case]
-%% Case - atom()
-%% Name of a test case.
-%% Description: Returns a list of all test cases in this test suite
-%%--------------------------------------------------------------------
all() ->
[app_test,
{group, dsa_key},
@@ -115,13 +48,24 @@ all() ->
close].
groups() ->
- [{dsa_key, [], [send, exec, exec_compressed, shell, known_hosts]},
- {rsa_key, [], [send, exec, exec_compressed, shell, known_hosts]},
+ [{dsa_key, [], [send, exec, exec_compressed, shell, known_hosts, idle_time, rekey]},
+ {rsa_key, [], [send, exec, exec_compressed, shell, known_hosts, idle_time, rekey]},
{dsa_pass_key, [], [pass_phrase]},
{rsa_pass_key, [], [pass_phrase]},
{internal_error, [], [internal_error]}
].
-
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ case catch crypto:start() of
+ ok ->
+ Config;
+ _Else ->
+ {skip, "Crypto could not be started!"}
+ end.
+end_per_suite(_Config) ->
+ ssh:stop(),
+ crypto:stop().
+%%--------------------------------------------------------------------
init_per_group(dsa_key, Config) ->
DataDir = ?config(data_dir, Config),
PrivDir = ?config(priv_dir, Config),
@@ -174,11 +118,25 @@ end_per_group(internal_error, Config) ->
end_per_group(_, Config) ->
Config.
+%%--------------------------------------------------------------------
+init_per_testcase(_TestCase, Config) ->
+ ssh:start(),
+ Config.
-%% Test cases starts here.
+end_per_testcase(TestCase, Config) when TestCase == server_password_option;
+ TestCase == server_userpassword_option ->
+ UserDir = filename:join(?config(priv_dir, Config), nopubkey),
+ ssh_test_lib:del_dirs(UserDir),
+ end_per_testcase(Config);
+end_per_testcase(_TestCase, Config) ->
+ end_per_testcase(Config).
+end_per_testcase(_Config) ->
+ ssh:stop(),
+ ok.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------
-app_test(suite) ->
- [];
app_test(doc) ->
["Application consistency test."];
app_test(Config) when is_list(Config) ->
@@ -189,8 +147,6 @@ misc_ssh_options(doc) ->
["Test that we can set some misc options not tested elsewhere, "
"some options not yet present are not decided if we should support or "
"if they need thier own test case."];
-misc_ssh_options(suite) ->
- [];
misc_ssh_options(Config) when is_list(Config) ->
SystemDir = filename:join(?config(priv_dir, Config), system),
UserDir = ?config(priv_dir, Config),
@@ -209,10 +165,6 @@ misc_ssh_options(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
exec(doc) ->
["Test api function ssh_connection:exec"];
-
-exec(suite) ->
- [];
-
exec(Config) when is_list(Config) ->
process_flag(trap_exit, true),
SystemDir = filename:join(?config(priv_dir, Config), system),
@@ -233,7 +185,7 @@ exec(Config) when is_list(Config) ->
expected ->
ok;
Other0 ->
- test_server:fail(Other0)
+ ct:fail(Other0)
end,
ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId0),
@@ -247,7 +199,7 @@ exec(Config) when is_list(Config) ->
expected ->
ok;
Other1 ->
- test_server:fail(Other1)
+ ct:fail(Other1)
end,
ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId1),
ssh:stop_daemon(Pid).
@@ -255,10 +207,6 @@ exec(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
exec_compressed(doc) ->
["Test that compression option works"];
-
-exec_compressed(suite) ->
- [];
-
exec_compressed(Config) when is_list(Config) ->
process_flag(trap_exit, true),
SystemDir = filename:join(?config(priv_dir, Config), system),
@@ -280,19 +228,58 @@ exec_compressed(Config) when is_list(Config) ->
expected ->
ok;
Other ->
- test_server:fail(Other)
+ ct:fail(Other)
end,
ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId),
ssh:stop_daemon(Pid).
%%--------------------------------------------------------------------
+idle_time(doc) ->
+ ["Idle timeout test"];
+idle_time(Config) ->
+ SystemDir = filename:join(?config(priv_dir, Config), system),
+ UserDir = ?config(priv_dir, Config),
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ {user_dir, UserDir},
+ {failfun, fun ssh_test_lib:failfun/2}]),
+ ConnectionRef =
+ ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ {user_dir, UserDir},
+ {user_interaction, false},
+ {idle_time, 2000}]),
+ {ok, Id} = ssh_connection:session_channel(ConnectionRef, 1000),
+ ssh_connection:close(ConnectionRef, Id),
+ receive
+ after 10000 ->
+ {error,channel_closed} = ssh_connection:session_channel(ConnectionRef, 1000)
+ end,
+ ssh:stop_daemon(Pid).
+%%--------------------------------------------------------------------
+rekey(doc) ->
+ ["Idle timeout test"];
+rekey(Config) ->
+ SystemDir = filename:join(?config(priv_dir, Config), system),
+ UserDir = ?config(priv_dir, Config),
+
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ {user_dir, UserDir},
+ {failfun, fun ssh_test_lib:failfun/2},
+ {rekey_limit, 0}]),
+ ConnectionRef =
+ ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ {user_dir, UserDir},
+ {user_interaction, false},
+ {rekey_limit, 0}]),
+ receive
+ after 15000 ->
+ %%By this time rekeying would have been done
+ ssh:close(ConnectionRef),
+ ssh:stop_daemon(Pid)
+ end.
+%%--------------------------------------------------------------------
shell(doc) ->
["Test that ssh:shell/2 works"];
-
-shell(suite) ->
- [];
-
shell(Config) when is_list(Config) ->
process_flag(trap_exit, true),
SystemDir = filename:join(?config(priv_dir, Config), system),
@@ -300,76 +287,22 @@ shell(Config) when is_list(Config) ->
{_Pid, _Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},{user_dir, UserDir},
{failfun, fun ssh_test_lib:failfun/2}]),
- test_server:sleep(500),
+ ct:sleep(500),
IO = ssh_test_lib:start_io_server(),
Shell = ssh_test_lib:start_shell(Port, IO, UserDir),
receive
{'EXIT', _, _} ->
- test_server:fail(no_ssh_connection);
+ ct:fail(no_ssh_connection);
ErlShellStart ->
- test_server:format("Erlang shell start: ~p~n", [ErlShellStart]),
+ ct:pal("Erlang shell start: ~p~n", [ErlShellStart]),
do_shell(IO, Shell)
end.
-do_shell(IO, Shell) ->
- receive
- ErlPrompt0 ->
- test_server:format("Erlang prompt: ~p~n", [ErlPrompt0])
- end,
- IO ! {input, self(), "1+1.\r\n"},
- receive
- Echo0 ->
- test_server:format("Echo: ~p ~n", [Echo0])
- end,
- receive
- ?NEWLINE ->
- ok
- end,
- receive
- Result0 = <<"2">> ->
- test_server:format("Result: ~p~n", [Result0])
- end,
- receive
- ?NEWLINE ->
- ok
- end,
- receive
- ErlPrompt1 ->
- test_server:format("Erlang prompt: ~p~n", [ErlPrompt1])
- end,
- exit(Shell, kill),
- %% Does not seem to work in the testserver!
- %% IO ! {input, self(), "q().\r\n"},
- %% receive
- %% ?NEWLINE ->
- %% ok
- %% end,
- %% receive
- %% Echo1 ->
- %% test_server:format("Echo: ~p ~n", [Echo1])
- %% end,
- %% receive
- %% ?NEWLINE ->
- %% ok
- %% end,
- %% receive
- %% Result1 ->
- %% test_server:format("Result: ~p~n", [Result1])
- %% end,
- receive
- {'EXIT', Shell, killed} ->
- ok
- end.
-
%%--------------------------------------------------------------------
daemon_already_started(doc) ->
["Test that get correct error message if you try to start a daemon",
"on an adress that already runs a daemon see also seq10667" ];
-
-daemon_already_started(suite) ->
- [];
-
daemon_already_started(Config) when is_list(Config) ->
SystemDir = ?config(data_dir, Config),
UserDir = ?config(priv_dir, Config),
@@ -386,8 +319,6 @@ daemon_already_started(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
server_password_option(doc) ->
["validate to server that uses the 'password' option"];
-server_password_option(suite) ->
- [];
server_password_option(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth
@@ -413,7 +344,7 @@ server_password_option(Config) when is_list(Config) ->
{user_interaction, false},
{user_dir, UserDir}]),
- test_server:format("Test of wrong password: Error msg: ~p ~n", [Reason]),
+ ct:pal("Test of wrong password: Error msg: ~p ~n", [Reason]),
ssh:close(ConnectionRef),
ssh:stop_daemon(Pid).
@@ -422,8 +353,6 @@ server_password_option(Config) when is_list(Config) ->
server_userpassword_option(doc) ->
["validate to server that uses the 'password' option"];
-server_userpassword_option(suite) ->
- [];
server_userpassword_option(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth
@@ -460,8 +389,6 @@ server_userpassword_option(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
known_hosts(doc) ->
["check that known_hosts is updated correctly"];
-known_hosts(suite) ->
- [];
known_hosts(Config) when is_list(Config) ->
SystemDir = ?config(data_dir, Config),
PrivDir = ?config(priv_dir, Config),
@@ -489,10 +416,6 @@ known_hosts(Config) when is_list(Config) ->
pass_phrase(doc) ->
["Test that we can use keyes protected by pass phrases"];
-
-pass_phrase(suite) ->
- [];
-
pass_phrase(Config) when is_list(Config) ->
process_flag(trap_exit, true),
SystemDir = filename:join(?config(priv_dir, Config), system),
@@ -514,10 +437,6 @@ pass_phrase(Config) when is_list(Config) ->
internal_error(doc) ->
["Test that client does not hang if disconnects due to internal error"];
-
-internal_error(suite) ->
- [];
-
internal_error(Config) when is_list(Config) ->
process_flag(trap_exit, true),
SystemDir = filename:join(?config(priv_dir, Config), system),
@@ -535,10 +454,6 @@ internal_error(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
send(doc) ->
["Test ssh_connection:send/3"];
-
-send(suite) ->
- [];
-
send(Config) when is_list(Config) ->
process_flag(trap_exit, true),
SystemDir = filename:join(?config(priv_dir, Config), system),
@@ -560,10 +475,6 @@ send(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
close(doc) ->
["Simulate that we try to close an already closed connection"];
-
-close(suite) ->
- [];
-
close(Config) when is_list(Config) ->
SystemDir = ?config(data_dir, Config),
PrivDir = ?config(priv_dir, Config),
@@ -583,10 +494,8 @@ close(Config) when is_list(Config) ->
exit(CM, {shutdown, normal}),
ok = ssh:close(CM).
-
-
%%--------------------------------------------------------------------
-%% Internal functions
+%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
basic_test(Config) ->
@@ -597,3 +506,53 @@ basic_test(Config) ->
{ok, CM} = ssh:connect(Host, Port, ClientOpts),
ok = ssh:close(CM),
ssh:stop_daemon(Pid).
+
+do_shell(IO, Shell) ->
+ receive
+ ErlPrompt0 ->
+ ct:pal("Erlang prompt: ~p~n", [ErlPrompt0])
+ end,
+ IO ! {input, self(), "1+1.\r\n"},
+ receive
+ Echo0 ->
+ ct:pal("Echo: ~p ~n", [Echo0])
+ end,
+ receive
+ ?NEWLINE ->
+ ok
+ end,
+ receive
+ Result0 = <<"2">> ->
+ ct:pal("Result: ~p~n", [Result0])
+ end,
+ receive
+ ?NEWLINE ->
+ ok
+ end,
+ receive
+ ErlPrompt1 ->
+ ct:pal("Erlang prompt: ~p~n", [ErlPrompt1])
+ end,
+ exit(Shell, kill).
+ %%Does not seem to work in the testserver!
+ %% IO ! {input, self(), "q().\r\n"},
+ %% receive
+ %% ?NEWLINE ->
+ %% ok
+ %% end,
+ %% receive
+ %% Echo1 ->
+ %% ct:pal("Echo: ~p ~n", [Echo1])
+ %% end,
+ %% receive
+ %% ?NEWLINE ->
+ %% ok
+ %% end,
+ %% receive
+ %% Result1 ->
+ %% ct:pal("Result: ~p~n", [Result1])
+ %% end,
+ %% receive
+ %% {'EXIT', Shell, killed} ->
+ %% ok
+ %% end.
diff --git a/lib/ssh/test/ssh_connection_SUITE.erl b/lib/ssh/test/ssh_connection_SUITE.erl
new file mode 100644
index 0000000000..acaf3d6eeb
--- /dev/null
+++ b/lib/ssh/test/ssh_connection_SUITE.erl
@@ -0,0 +1,313 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
+%%
+%% The 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(ssh_connection_SUITE).
+
+-include_lib("common_test/include/ct.hrl").
+
+-compile(export_all).
+
+-define(SSH_DEFAULT_PORT, 22).
+-define(EXEC_TIMEOUT, 10000).
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+suite() ->
+ [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [
+ {group, openssh_payload},
+ interrupted_send
+ ].
+groups() ->
+ [{openssh_payload, [], [simple_exec,
+ small_cat,
+ big_cat,
+ send_after_exit
+ ]}].
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ case catch crypto:start() of
+ ok ->
+ Config;
+ _Else ->
+ {skip, "Crypto could not be started!"}
+ end.
+
+end_per_suite(_Config) ->
+ crypto:stop().
+
+%%--------------------------------------------------------------------
+init_per_group(openssh_payload, _Config) ->
+ case gen_tcp:connect("localhost", 22, []) of
+ {error,econnrefused} ->
+ {skip,"No openssh deamon"};
+ {ok, Socket} ->
+ gen_tcp:close(Socket)
+ end;
+init_per_group(_, Config) ->
+ Config.
+
+end_per_group(_, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+init_per_testcase(_TestCase, Config) ->
+ ssh:start(),
+ Config.
+
+end_per_testcase(_Config) ->
+ ssh:stop().
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+simple_exec(doc) ->
+ ["Simple openssh connectivity test for ssh_connection:exec"];
+
+simple_exec(Config) when is_list(Config) ->
+ ConnectionRef = ssh_test_lib:connect(?SSH_DEFAULT_PORT, [{silently_accept_hosts, true},
+ {user_interaction, false}]),
+ {ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity),
+ success = ssh_connection:exec(ConnectionRef, ChannelId0,
+ "echo testing", infinity),
+
+ %% receive response to input
+ receive
+ {ssh_cm, ConnectionRef, {data, ChannelId0, 0, <<"testing\n">>}} ->
+ ok
+ end,
+
+ %% receive close messages
+ receive
+ {ssh_cm, ConnectionRef, {eof, ChannelId0}} ->
+ ok
+ end,
+ receive
+ {ssh_cm, ConnectionRef, {exit_status, ChannelId0, 0}} ->
+ ok
+ end,
+ receive
+ {ssh_cm, ConnectionRef,{closed, ChannelId0}} ->
+ ok
+ end.
+
+%%--------------------------------------------------------------------
+small_cat(doc) ->
+ ["Use 'cat' to echo small data block back to us."];
+
+small_cat(Config) when is_list(Config) ->
+ ConnectionRef = ssh_test_lib:connect(?SSH_DEFAULT_PORT, [{silently_accept_hosts, true},
+ {user_interaction, false}]),
+ {ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity),
+ success = ssh_connection:exec(ConnectionRef, ChannelId0,
+ "cat", infinity),
+
+ Data = <<"I like spaghetti squash">>,
+ ok = ssh_connection:send(ConnectionRef, ChannelId0, Data),
+ ok = ssh_connection:send_eof(ConnectionRef, ChannelId0),
+
+ %% receive response to input
+ receive
+ {ssh_cm, ConnectionRef, {data, ChannelId0, 0, Data}} ->
+ ok
+ end,
+
+ %% receive close messages
+ receive
+ {ssh_cm, ConnectionRef, {eof, ChannelId0}} ->
+ ok
+ end,
+ receive
+ {ssh_cm, ConnectionRef, {exit_status, ChannelId0, 0}} ->
+ ok
+ end,
+ receive
+ {ssh_cm, ConnectionRef,{closed, ChannelId0}} ->
+ ok
+ end.
+
+%%--------------------------------------------------------------------
+big_cat(doc) ->
+ ["Use 'cat' to echo large data block back to us."];
+
+big_cat(Config) when is_list(Config) ->
+ ConnectionRef = ssh_test_lib:connect(?SSH_DEFAULT_PORT, [{silently_accept_hosts, true},
+ {user_interaction, false}]),
+ {ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity),
+ success = ssh_connection:exec(ConnectionRef, ChannelId0,
+ "cat", infinity),
+
+ %% build 10MB binary
+ Data = << <<X:32>> || X <- lists:seq(1,2500000)>>,
+
+ %% pre-adjust receive window so the other end doesn't block
+ ssh_connection:adjust_window(ConnectionRef, ChannelId0, size(Data)),
+
+ ct:pal("sending ~p byte binary~n",[size(Data)]),
+ ok = ssh_connection:send(ConnectionRef, ChannelId0, Data, 10000),
+ ok = ssh_connection:send_eof(ConnectionRef, ChannelId0),
+
+ %% collect echoed data until eof
+ case big_cat_rx(ConnectionRef, ChannelId0) of
+ {ok, Data} ->
+ ok;
+ {ok, Other} ->
+ case size(Data) =:= size(Other) of
+ true ->
+ ct:pal("received and sent data are same"
+ "size but do not match~n",[]);
+ false ->
+ ct:pal("sent ~p but only received ~p~n",
+ [size(Data), size(Other)])
+ end,
+ ct:fail(receive_data_mismatch);
+ Else ->
+ ct:fail(Else)
+ end,
+
+ %% receive close messages (eof already consumed)
+ receive
+ {ssh_cm, ConnectionRef, {exit_status, ChannelId0, 0}} ->
+ ok
+ end,
+ receive
+ {ssh_cm, ConnectionRef,{closed, ChannelId0}} ->
+ ok
+ end.
+
+%%--------------------------------------------------------------------
+send_after_exit(doc) ->
+ ["Send channel data after the channel has been closed."];
+
+send_after_exit(Config) when is_list(Config) ->
+ ConnectionRef = ssh_test_lib:connect(?SSH_DEFAULT_PORT, [{silently_accept_hosts, true},
+ {user_interaction, false}]),
+ {ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity),
+
+ %% Shell command "false" will exit immediately
+ success = ssh_connection:exec(ConnectionRef, ChannelId0,
+ "false", infinity),
+
+ timer:sleep(2000), %% Allow incoming eof/close/exit_status ssh messages to be processed
+
+ Data = <<"I like spaghetti squash">>,
+ case ssh_connection:send(ConnectionRef, ChannelId0, Data, 2000) of
+ {error, closed} -> ok;
+ ok ->
+ ct:fail({expected,{error,closed}});
+ {error, timeout} ->
+ ct:fail({expected,{error,closed}});
+ Else ->
+ ct:fail(Else)
+ end,
+
+ %% receive close messages
+ receive
+ {ssh_cm, ConnectionRef, {eof, ChannelId0}} ->
+ ok
+ end,
+ receive
+ {ssh_cm, ConnectionRef, {exit_status, ChannelId0, _}} ->
+ ok
+ end,
+ receive
+ {ssh_cm, ConnectionRef,{closed, ChannelId0}} ->
+ ok
+ end.
+%%--------------------------------------------------------------------
+interrupted_send(doc) ->
+ ["Use a subsystem that echos n char and then sends eof to cause a channel exit partway through a large send."];
+
+interrupted_send(Config) when is_list(Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth
+ file:make_dir(UserDir),
+ SysDir = ?config(data_dir, Config),
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
+ {user_dir, UserDir},
+ {password, "morot"},
+ {subsystems, [{"echo_n", {ssh_echo_server, [4000000]}}]}]),
+
+ ConnectionRef = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ {user, "foo"},
+ {password, "morot"},
+ {user_interaction, false},
+ {user_dir, UserDir}]),
+
+ {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity),
+
+ success = ssh_connection:subsystem(ConnectionRef, ChannelId, "echo_n", infinity),
+
+ %% build 10MB binary
+ Data = << <<X:32>> || X <- lists:seq(1,2500000)>>,
+
+ %% expect remote end to send us 4MB back
+ <<ExpectedData:4000000/binary, _/binary>> = Data,
+
+ %% pre-adjust receive window so the other end doesn't block
+ ssh_connection:adjust_window(ConnectionRef, ChannelId, size(ExpectedData) + 1),
+
+ case ssh_connection:send(ConnectionRef, ChannelId, Data, 10000) of
+ {error, closed} ->
+ ok;
+ Msg ->
+ ct:fail({expected,{error,closed}, got, Msg})
+ end,
+ receive_data(ExpectedData, ConnectionRef, ChannelId),
+ ssh:close(ConnectionRef),
+ ssh:stop_daemon(Pid).
+
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
+big_cat_rx(ConnectionRef, ChannelId) ->
+ big_cat_rx(ConnectionRef, ChannelId, []).
+
+big_cat_rx(ConnectionRef, ChannelId, Acc) ->
+ receive
+ {ssh_cm, ConnectionRef, {data, ChannelId, 0, Data}} ->
+ %% ssh_connection:adjust_window(ConnectionRef, ChannelId, size(Data)),
+ %% window was pre-adjusted, don't adjust again here
+ big_cat_rx(ConnectionRef, ChannelId, [Data | Acc]);
+ {ssh_cm, ConnectionRef, {eof, ChannelId}} ->
+ {ok, iolist_to_binary(lists:reverse(Acc))}
+ after ?EXEC_TIMEOUT ->
+ timeout
+ end.
+
+receive_data(ExpectedData, ConnectionRef, ChannelId) ->
+ ExpectedData = collect_data(ConnectionRef, ChannelId).
+
+collect_data(ConnectionRef, ChannelId) ->
+ collect_data(ConnectionRef, ChannelId, []).
+
+collect_data(ConnectionRef, ChannelId, Acc) ->
+ receive
+ {ssh_cm, ConnectionRef, {data, ChannelId, 0, Data}} ->
+ collect_data(ConnectionRef, ChannelId, [Data | Acc]);
+ {ssh_cm, ConnectionRef, {eof, ChannelId}} ->
+ iolist_to_binary(lists:reverse(Acc))
+ after 5000 ->
+ timeout
+ end.
diff --git a/lib/ssh/test/ssh_connection_SUITE_data/ssh_host_rsa_key b/lib/ssh/test/ssh_connection_SUITE_data/ssh_host_rsa_key
new file mode 100644
index 0000000000..6ae7ee023d
--- /dev/null
+++ b/lib/ssh/test/ssh_connection_SUITE_data/ssh_host_rsa_key
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8semM4q843337
+zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RWRWzjaxSB
+6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4QIDAQAB
+AoGANmvJzJO5hkLuvyDZHKfAnGTtpifcR1wtSa9DjdKUyn8vhKF0mIimnbnYQEmW
+NUUb3gXCZLi9PvkpRSVRrASDOZwcjoU/Kvww163vBUVb2cOZfFhyn6o2Sk88Tt++
+udH3hdjpf9i7jTtUkUe+QYPsia+wgvvrmn4QrahLAH86+kECQQDx5gFeXTME3cnW
+WMpFz3PPumduzjqgqMMWEccX4FtQkMX/gyGa5UC7OHFyh0N/gSWvPbRHa8A6YgIt
+n8DO+fh5AkEAzbqX4DOn8NY6xJIi42q7l/2jIA0RkB6P7YugW5NblhqBZ0XDnpA5
+sMt+rz+K07u9XZtxgh1xi7mNfwY6lEAMqQJBAJBEauCKmRj35Z6OyeQku59SPsnY
++SJEREVvSNw2lH9SOKQQ4wPsYlTGbvKtNVZgAcen91L5MmYfeckYE/fdIZECQQCt
+64zxsTnM1I8iFxj/gP/OYlJBikrKt8udWmjaghzvLMEw+T2DExJyb9ZNeT53+UMB
+m6O+B/4xzU/djvp+0hbhAkAemIt+rA5kTmYlFndhpvzkSSM8a2EXsO4XIPgGWCTT
+tQKS/tTly0ADMjN/TVy11+9d6zcqadNVuHXHGtR4W0GR
+-----END RSA PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_echo_server.erl b/lib/ssh/test/ssh_echo_server.erl
new file mode 100644
index 0000000000..007b00c373
--- /dev/null
+++ b/lib/ssh/test/ssh_echo_server.erl
@@ -0,0 +1,71 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+%%% Description: Example ssh server
+-module(ssh_echo_server).
+-behaviour(ssh_subsytem).
+-record(state, {
+ n,
+ id,
+ cm
+ }).
+-export([init/1, handle_msg/2, handle_ssh_msg/2, terminate/2]).
+
+init([N]) ->
+ {ok, #state{n = N}}.
+
+handle_msg({ssh_channel_up, ChannelId, ConnectionManager}, State) ->
+ {ok, State#state{id = ChannelId,
+ cm = ConnectionManager}}.
+
+handle_ssh_msg({ssh_cm, CM, {data, ChannelId, 0, Data}}, #state{n = N} = State) ->
+ M = N - size(Data),
+ case M > 0 of
+ true ->
+ ssh_connection:send(CM, ChannelId, Data),
+ {ok, State#state{n = M}};
+ false ->
+ <<SendData:N/binary, _/binary>> = Data,
+ ssh_connection:send(CM, ChannelId, SendData),
+ ssh_connection:send_eof(CM, ChannelId),
+ {stop, ChannelId, State}
+ end;
+handle_ssh_msg({ssh_cm, _ConnectionManager,
+ {data, _ChannelId, 1, Data}}, State) ->
+ error_logger:format(standard_error, " ~p~n", [binary_to_list(Data)]),
+ {ok, State};
+
+handle_ssh_msg({ssh_cm, _ConnectionManager, {eof, _ChannelId}}, State) ->
+ {ok, State};
+
+handle_ssh_msg({ssh_cm, _, {signal, _, _}}, State) ->
+ %% Ignore signals according to RFC 4254 section 6.9.
+ {ok, State};
+
+handle_ssh_msg({ssh_cm, _, {exit_signal, ChannelId, _, _Error, _}},
+ State) ->
+ {stop, ChannelId, State};
+
+handle_ssh_msg({ssh_cm, _, {exit_status, ChannelId, _Status}}, State) ->
+ {stop, ChannelId, State}.
+
+terminate(_Reason, _State) ->
+ ok.
diff --git a/lib/ssh/test/ssh_sftp_SUITE.erl b/lib/ssh/test/ssh_sftp_SUITE.erl
index d40b1d544d..232161d029 100644
--- a/lib/ssh/test/ssh_sftp_SUITE.erl
+++ b/lib/ssh/test/ssh_sftp_SUITE.erl
@@ -24,7 +24,6 @@
-compile(export_all).
-include_lib("common_test/include/ct.hrl").
-
-include_lib("kernel/include/file.hrl").
% Default timetrap timeout
@@ -33,16 +32,18 @@
-define(USER, "Alladin").
-define(PASSWD, "Sesame").
-%% Test server callback functions
%%--------------------------------------------------------------------
-%% Function: init_per_suite(Config) -> Config
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Initiation before the whole suite
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
+%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
+
+suite() ->
+ [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [{group, erlang_server},
+ {group, openssh_server}].
+
+
init_per_suite(Config) ->
case (catch crypto:start()) of
ok ->
@@ -52,35 +53,58 @@ init_per_suite(Config) ->
{skip,"Could not start crypto!"}
end.
-%%--------------------------------------------------------------------
-%% Function: end_per_suite(Config) -> _
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after the whole suite
-%%--------------------------------------------------------------------
end_per_suite(Config) ->
ssh:stop(),
crypto:stop(),
Config.
%%--------------------------------------------------------------------
-%% Function: init_per_testcase(TestCase, Config) -> Config
-%% Case - atom()
-%% Name of the test case that is about to be run.
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%%
-%% Description: Initiation before each test case
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
-%% Description: Initiation before each test case
+groups() ->
+ [{erlang_server, [], [open_close_file, open_close_dir, read_file, read_dir,
+ write_file, rename_file, mk_rm_dir, remove_file, links,
+ retrieve_attributes, set_attributes, async_read,
+ async_write, position, pos_read, pos_write]},
+ {openssh_server, [], [open_close_file, open_close_dir, read_file, read_dir,
+ write_file, rename_file, mk_rm_dir, remove_file, links,
+ retrieve_attributes, set_attributes, async_read,
+ async_write, position, pos_read, pos_write]}].
+
+init_per_group(erlang_server, Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ SysDir = ?config(data_dir, Config),
+ Sftpd =
+ ssh_test_lib:daemon([{system_dir, SysDir},
+ {user_dir, PrivDir},
+ {user_passwords,
+ [{?USER, ?PASSWD}]},
+ {failfun,
+ fun ssh_test_lib:failfun/2}]),
+ [{group, erlang_server}, {sftpd, Sftpd} | Config];
+
+init_per_group(openssh_server, Config) ->
+ Host = ssh_test_lib:hostname(),
+ case (catch ssh_sftp:start_channel(Host,
+ [{user_interaction, false},
+ {silently_accept_hosts, true}])) of
+ {ok, _ChannelPid, Connection} ->
+ ssh:close(Connection),
+ [{group, openssh_server} | Config];
+ _ ->
+ {skip, "No openssh server"}
+ end.
+
+end_per_group(erlang_server, Config) ->
+ Config;
+end_per_group(_, Config) ->
+ Config.
+
%%--------------------------------------------------------------------
+
init_per_testcase(Case, Config) ->
prep(Config),
TmpConfig0 = lists:keydelete(watchdog, 1, Config),
TmpConfig = lists:keydelete(sftp, 1, TmpConfig0),
- Dog = test_server:timetrap(?default_timeout),
+ Dog = ct:timetrap(?default_timeout),
case ?config(group, Config) of
erlang_server ->
@@ -105,14 +129,6 @@ init_per_testcase(Case, Config) ->
[{sftp, Sftp}, {watchdog, Dog} | TmpConfig]
end.
-%%--------------------------------------------------------------------
-%% Function: end_per_testcase(TestCase, Config) -> _
-%% Case - atom()
-%% Name of the test case that is about to be run.
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after each test case
-%%--------------------------------------------------------------------
end_per_testcase(rename_file, Config) ->
PrivDir = ?config(priv_dir, Config),
NewFileName = filename:join(PrivDir, "test.txt"),
@@ -124,69 +140,13 @@ end_per_testcase(_, Config) ->
end_per_testcase(Config) ->
{Sftp, Connection} = ?config(sftp, Config),
ssh_sftp:stop_channel(Sftp),
- ssh:close(Connection),
- Dog = ?config(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
+ ssh:close(Connection).
%%--------------------------------------------------------------------
-%% Function: all(Clause) -> TestCases
-%% Clause - atom() - suite | doc
-%% TestCases - [Case]
-%% Case - atom()
-%% Name of a test case.
-%% Description: Returns a list of all test cases in this test suite
-%%--------------------------------------------------------------------
-all() ->
- [{group, erlang_server},
- {group, openssh_server}].
-
-groups() ->
- [{erlang_server, [], [open_close_file, open_close_dir, read_file, read_dir,
- write_file, rename_file, mk_rm_dir, remove_file, links,
- retrieve_attributes, set_attributes, async_read,
- async_write, position, pos_read, pos_write]},
- {openssh_server, [], [open_close_file, open_close_dir, read_file, read_dir,
- write_file, rename_file, mk_rm_dir, remove_file, links,
- retrieve_attributes, set_attributes, async_read,
- async_write, position, pos_read, pos_write]}].
-
-init_per_group(erlang_server, Config) ->
- PrivDir = ?config(priv_dir, Config),
- SysDir = ?config(data_dir, Config),
- Sftpd =
- ssh_test_lib:daemon([{system_dir, SysDir},
- {user_dir, PrivDir},
- {user_passwords,
- [{?USER, ?PASSWD}]},
- {failfun,
- fun ssh_test_lib:failfun/2}]),
- [{group, erlang_server}, {sftpd, Sftpd} | Config];
-
-init_per_group(openssh_server, Config) ->
- Host = ssh_test_lib:hostname(),
- case (catch ssh_sftp:start_channel(Host,
- [{user_interaction, false},
- {silently_accept_hosts, true}])) of
- {ok, _ChannelPid, Connection} ->
- ssh:close(Connection),
- [{group, openssh_server} | Config];
- _ ->
- {skip, "No openssh server"}
- end.
-
-end_per_group(erlang_server, Config) ->
- Config;
-end_per_group(_, Config) ->
- Config.
-
-
-%% Test cases starts here.
+%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------
open_close_file(doc) ->
["Test API functions open/3 and close/2"];
-open_close_file(suite) ->
- [];
open_close_file(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
FileName = filename:join(PrivDir, "sftp.txt"),
@@ -198,21 +158,15 @@ open_close_file(Config) when is_list(Config) ->
ok = open_close_file(Sftp, FileName, [write, creat]),
ok = open_close_file(Sftp, FileName, [write, trunc]),
ok = open_close_file(Sftp, FileName, [append]),
- ok = open_close_file(Sftp, FileName, [read, binary]),
-
- ok.
+ ok = open_close_file(Sftp, FileName, [read, binary]).
open_close_file(Server, File, Mode) ->
{ok, Handle} = ssh_sftp:open(Server, File, Mode),
- ok = ssh_sftp:close(Server, Handle),
- ok.
-
+ ok = ssh_sftp:close(Server, Handle).
%%--------------------------------------------------------------------
open_close_dir(doc) ->
["Test API functions opendir/2 and close/2"];
-open_close_dir(suite) ->
- [];
open_close_dir(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
{Sftp, _} = ?config(sftp, Config),
@@ -220,138 +174,92 @@ open_close_dir(Config) when is_list(Config) ->
{ok, Handle} = ssh_sftp:opendir(Sftp, PrivDir),
ok = ssh_sftp:close(Sftp, Handle),
- {error, _} = ssh_sftp:opendir(Sftp, FileName),
+ {error, _} = ssh_sftp:opendir(Sftp, FileName).
- ok.
%%--------------------------------------------------------------------
read_file(doc) ->
["Test API funtion read_file/2"];
-read_file(suite) ->
- [];
read_file(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
FileName = filename:join(PrivDir, "sftp.txt"),
-
{Sftp, _} = ?config(sftp, Config),
-
{ok, Data} = ssh_sftp:read_file(Sftp, FileName),
+ {ok, Data} = file:read_file(FileName).
- {ok, Data} = file:read_file(FileName),
-
- ok.
%%--------------------------------------------------------------------
read_dir(doc) ->
["Test API function list_dir/2"];
-read_dir(suite) ->
- [];
read_dir(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
{Sftp, _} = ?config(sftp, Config),
{ok, Files} = ssh_sftp:list_dir(Sftp, PrivDir),
- test_server:format("sftp list dir: ~p~n", [Files]),
- ok.
+ ct:pal("sftp list dir: ~p~n", [Files]).
%%--------------------------------------------------------------------
write_file(doc) ->
["Test API function write_file/2"];
-write_file(suite) ->
- [];
write_file(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
FileName = filename:join(PrivDir, "sftp.txt"),
-
{Sftp, _} = ?config(sftp, Config),
Data = list_to_binary("Hej hopp!"),
-
ssh_sftp:write_file(Sftp, FileName, [Data]),
-
- {ok, Data} = file:read_file(FileName),
-
- ok.
+ {ok, Data} = file:read_file(FileName).
%%--------------------------------------------------------------------
remove_file(doc) ->
["Test API function delete/2"];
-remove_file(suite) ->
- [];
remove_file(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
FileName = filename:join(PrivDir, "sftp.txt"),
-
{Sftp, _} = ?config(sftp, Config),
{ok, Files} = ssh_sftp:list_dir(Sftp, PrivDir),
-
true = lists:member(filename:basename(FileName), Files),
-
ok = ssh_sftp:delete(Sftp, FileName),
-
{ok, NewFiles} = ssh_sftp:list_dir(Sftp, PrivDir),
-
false = lists:member(filename:basename(FileName), NewFiles),
-
- {error, _} = ssh_sftp:delete(Sftp, FileName),
-
- ok.
-
+ {error, _} = ssh_sftp:delete(Sftp, FileName).
%%--------------------------------------------------------------------
rename_file(doc) ->
["Test API function rename_file/2"];
-rename_file(suite) ->
- [];
rename_file(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
FileName = filename:join(PrivDir, "sftp.txt"),
NewFileName = filename:join(PrivDir, "test.txt"),
{Sftp, _} = ?config(sftp, Config),
-
{ok, Files} = ssh_sftp:list_dir(Sftp, PrivDir),
-
- test_server:format("FileName: ~p, Files: ~p~n", [FileName, Files]),
-
+ ct:pal("FileName: ~p, Files: ~p~n", [FileName, Files]),
true = lists:member(filename:basename(FileName), Files),
false = lists:member(filename:basename(NewFileName), Files),
-
ok = ssh_sftp:rename(Sftp, FileName, NewFileName),
-
{ok, NewFiles} = ssh_sftp:list_dir(Sftp, PrivDir),
-
- test_server:format("FileName: ~p, Files: ~p~n", [FileName, NewFiles]),
+ ct:pal("FileName: ~p, Files: ~p~n", [FileName, NewFiles]),
false = lists:member(filename:basename(FileName), NewFiles),
- true = lists:member(filename:basename(NewFileName), NewFiles),
-
- ok.
+ true = lists:member(filename:basename(NewFileName), NewFiles).
%%--------------------------------------------------------------------
mk_rm_dir(doc) ->
["Test API functions make_dir/2, del_dir/2"];
-mk_rm_dir(suite) ->
- [];
mk_rm_dir(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
{Sftp, _} = ?config(sftp, Config),
+
DirName = filename:join(PrivDir, "test"),
-
ok = ssh_sftp:make_dir(Sftp, DirName),
ok = ssh_sftp:del_dir(Sftp, DirName),
-
NewDirName = filename:join(PrivDir, "foo/bar"),
-
{error, _} = ssh_sftp:make_dir(Sftp, NewDirName),
- {error, _} = ssh_sftp:del_dir(Sftp, PrivDir),
-
- ok.
+ {error, _} = ssh_sftp:del_dir(Sftp, PrivDir).
%%--------------------------------------------------------------------
links(doc) ->
["Tests API function make_symlink/3"];
-links(suite) ->
- [];
links(Config) when is_list(Config) ->
- case test_server:os_type() of
+ case os:type() of
{win32, _} ->
{skip, "Links are not fully supported by windows"};
_ ->
@@ -361,74 +269,60 @@ links(Config) when is_list(Config) ->
LinkFileName = filename:join(PrivDir, "link_test.txt"),
ok = ssh_sftp:make_symlink(Sftp, LinkFileName, FileName),
- {ok, FileName} = ssh_sftp:read_link(Sftp, LinkFileName),
- ok
+ {ok, FileName} = ssh_sftp:read_link(Sftp, LinkFileName)
end.
%%--------------------------------------------------------------------
retrieve_attributes(doc) ->
["Test API function read_file_info/3"];
-retrieve_attributes(suite) ->
- [];
retrieve_attributes(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
FileName = filename:join(PrivDir, "sftp.txt"),
- {Sftp, _} = ?config(sftp, Config),
+ {Sftp, _} = ?config(sftp, Config),
{ok, FileInfo} = ssh_sftp:read_file_info(Sftp, FileName),
-
{ok, NewFileInfo} = file:read_file_info(FileName),
%% TODO comparison. There are some differences now is that ok?
- test_server:format("SFTP: ~p FILE: ~p~n", [FileInfo, NewFileInfo]),
- ok.
+ ct:pal("SFTP: ~p FILE: ~p~n", [FileInfo, NewFileInfo]).
%%--------------------------------------------------------------------
set_attributes(doc) ->
["Test API function write_file_info/3"];
-set_attributes(suite) ->
- [];
set_attributes(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
FileName = filename:join(PrivDir, "test.txt"),
- {Sftp, _} = ?config(sftp, Config),
+ {Sftp, _} = ?config(sftp, Config),
{ok,Fd} = file:open(FileName, write),
io:put_chars(Fd,"foo"),
-
ok = ssh_sftp:write_file_info(Sftp, FileName, #file_info{mode=8#400}),
{error, eacces} = file:write_file(FileName, "hello again"),
ssh_sftp:write_file_info(Sftp, FileName, #file_info{mode=8#600}),
- ok = file:write_file(FileName, "hello again"),
-
- ok.
+ ok = file:write_file(FileName, "hello again").
%%--------------------------------------------------------------------
async_read(doc) ->
["Test API aread/3"];
-async_read(suite) ->
- [];
async_read(Config) when is_list(Config) ->
{Sftp, _} = ?config(sftp, Config),
PrivDir = ?config(priv_dir, Config),
+
FileName = filename:join(PrivDir, "sftp.txt"),
{ok, Handle} = ssh_sftp:open(Sftp, FileName, [read]),
{async, Ref} = ssh_sftp:aread(Sftp, Handle, 20),
receive
{async_reply, Ref, {ok, Data}} ->
- test_server:format("Data: ~p~n", [Data]),
+ ct:pal("Data: ~p~n", [Data]),
ok;
Msg ->
- test_server:fail(Msg)
- end,
- ok.
+ ct:fail(Msg)
+ end.
%%--------------------------------------------------------------------
async_write(doc) ->
["Test API awrite/3"];
-async_write(suite) ->
- [];
async_write(Config) when is_list(Config) ->
{Sftp, _} = ?config(sftp, Config),
PrivDir = ?config(priv_dir, Config),
@@ -441,16 +335,13 @@ async_write(Config) when is_list(Config) ->
{async_reply, Ref, ok} ->
{ok, Data} = file:read_file(FileName);
Msg ->
- test_server:fail(Msg)
- end,
- ok.
+ ct:fail(Msg)
+ end.
%%--------------------------------------------------------------------
position(doc) ->
["Test API functions position/3"];
-position(suite) ->
- [];
position(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
FileName = filename:join(PrivDir, "test.txt"),
@@ -458,7 +349,6 @@ position(Config) when is_list(Config) ->
Data = list_to_binary("1234567890"),
ssh_sftp:write_file(Sftp, FileName, [Data]),
-
{ok, Handle} = ssh_sftp:open(Sftp, FileName, [read]),
{ok, 3} = ssh_sftp:position(Sftp, Handle, {bof, 3}),
@@ -477,15 +367,11 @@ position(Config) when is_list(Config) ->
{ok, "1"} = ssh_sftp:read(Sftp, Handle, 1),
{ok, 1} = ssh_sftp:position(Sftp, Handle, cur),
- {ok, "2"} = ssh_sftp:read(Sftp, Handle, 1),
-
- ok.
+ {ok, "2"} = ssh_sftp:read(Sftp, Handle, 1).
%%--------------------------------------------------------------------
pos_read(doc) ->
["Test API functions pread/3 and apread/3"];
-pos_read(suite) ->
- [];
pos_read(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
FileName = filename:join(PrivDir, "test.txt"),
@@ -494,7 +380,6 @@ pos_read(Config) when is_list(Config) ->
ssh_sftp:write_file(Sftp, FileName, [Data]),
{ok, Handle} = ssh_sftp:open(Sftp, FileName, [read]),
-
{async, Ref} = ssh_sftp:apread(Sftp, Handle, {bof, 5}, 4),
NewData = "opp!",
@@ -503,21 +388,17 @@ pos_read(Config) when is_list(Config) ->
{async_reply, Ref, {ok, NewData}} ->
ok;
Msg ->
- test_server:fail(Msg)
+ ct:fail(Msg)
end,
NewData1 = "hopp",
- {ok, NewData1} = ssh_sftp:pread(Sftp, Handle, {bof, 4}, 4),
+ {ok, NewData1} = ssh_sftp:pread(Sftp, Handle, {bof, 4}, 4).
- ok.
%%--------------------------------------------------------------------
pos_write(doc) ->
["Test API functions pwrite/4 and apwrite/4"];
-pos_write(suite) ->
- [];
pos_write(Config) when is_list(Config) ->
-
PrivDir = ?config(priv_dir, Config),
FileName = filename:join(PrivDir, "test.txt"),
{Sftp, _} = ?config(sftp, Config),
@@ -533,17 +414,16 @@ pos_write(Config) when is_list(Config) ->
{async_reply, Ref, ok} ->
ok;
Msg ->
- test_server:fail(Msg)
+ ct:fail(Msg)
end,
ok = ssh_sftp:pwrite(Sftp, Handle, eof, list_to_binary("!")),
NewData1 = list_to_binary("Bye, see you tomorrow!"),
- {ok, NewData1} = ssh_sftp:read_file(Sftp, FileName),
+ {ok, NewData1} = ssh_sftp:read_file(Sftp, FileName).
- ok.
-
-%% Internal functions
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
prep(Config) ->
PrivDir = ?config(priv_dir, Config),
diff --git a/lib/ssh/test/ssh_sftpd_SUITE.erl b/lib/ssh/test/ssh_sftpd_SUITE.erl
index 695a7caa7d..5aa46872ee 100644
--- a/lib/ssh/test/ssh_sftpd_SUITE.erl
+++ b/lib/ssh/test/ssh_sftpd_SUITE.erl
@@ -24,12 +24,10 @@
-compile(export_all).
-include_lib("common_test/include/ct.hrl").
--include("test_server_line.hrl").
+-include_lib("kernel/include/file.hrl").
-include("ssh_xfer.hrl").
-include("ssh.hrl").
--include_lib("kernel/include/file.hrl").
-
-define(USER, "Alladin").
-define(PASSWD, "Sesame").
-define(XFER_PACKET_SIZE, 32768).
@@ -41,16 +39,33 @@
-define(is_set(F, Bits),
((F) band (Bits)) == (F)).
-%% Test server callback functions
%%--------------------------------------------------------------------
-%% Function: init_per_suite(Config) -> Config
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Initiation before the whole suite
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+all() ->
+ [open_close_file,
+ open_close_dir,
+ read_file,
+ read_dir,
+ write_file,
+ rename_file,
+ mk_rm_dir,
+ remove_file,
+ real_path,
+ retrieve_attributes,
+ set_attributes,
+ links,
+ ver3_rename,
+ relpath,
+ sshd_read_file,
+ ver6_basic].
+
+groups() ->
+ [].
+
%%--------------------------------------------------------------------
+
init_per_suite(Config) ->
case (catch crypto:start()) of
ok ->
@@ -66,34 +81,24 @@ init_per_suite(Config) ->
{skip,"Could not start crypto!"}
end.
-%%--------------------------------------------------------------------
-%% Function: end_per_suite(Config) -> _
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after the whole suite
-%%--------------------------------------------------------------------
end_per_suite(Config) ->
SysDir = ?config(priv_dir, Config),
ssh_test_lib:clean_dsa(SysDir),
UserDir = filename:join(?config(priv_dir, Config), nopubkey),
file:del_dir(UserDir),
ssh:stop(),
- crypto:stop(),
- ok.
+ crypto:stop().
%%--------------------------------------------------------------------
-%% Function: init_per_testcase(TestCase, Config) -> Config
-%% Case - atom()
-%% Name of the test case that is about to be run.
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%%
-%% Description: Initiation before each test case
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
-%% Description: Initiation before each test case
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
%%--------------------------------------------------------------------
+
init_per_testcase(TestCase, Config) ->
ssh:start(),
prep(Config),
@@ -102,12 +107,18 @@ init_per_testcase(TestCase, Config) ->
SystemDir = filename:join(?config(priv_dir, Config), system),
Port = ssh_test_lib:inet_port(node()),
-
- {ok, Sftpd} =
- ssh_sftpd:listen(Port, [{system_dir, SystemDir},
- {user_dir, PrivDir},
- {user_passwords,[{?USER, ?PASSWD}]},
- {pwdfun, fun(_,_) -> true end}]),
+ Options = [{system_dir, SystemDir},
+ {user_dir, PrivDir},
+ {user_passwords,[{?USER, ?PASSWD}]},
+ {pwdfun, fun(_,_) -> true end}],
+ {ok, Sftpd} = case TestCase of
+ ver6_basic ->
+ SubSystems = [ssh_sftpd:subsystem_spec([{sftpd_vsn, 6}])],
+ ssh:daemon(Port, [{subsystems, SubSystems}|Options]);
+ _ ->
+ SubSystems = [ssh_sftpd:subsystem_spec([])],
+ ssh:daemon(Port, [{subsystems, SubSystems}|Options])
+ end,
Cm = ssh_test_lib:connect(Port,
[{user_dir, ClientUserDir},
@@ -138,56 +149,22 @@ init_per_testcase(TestCase, Config) ->
{ok, <<?SSH_FXP_VERSION, ?UINT32(Version), _Ext/binary>>, _}
= reply(Cm, Channel),
- test_server:format("Client: ~p Server ~p~n", [ProtocolVer, Version]),
+ ct:pal("Client: ~p Server ~p~n", [ProtocolVer, Version]),
[{sftp, {Cm, Channel}}, {sftpd, Sftpd }| Config].
-%%--------------------------------------------------------------------
-%% Function: end_per_testcase(TestCase, Config) -> _
-%% Case - atom()
-%% Name of the test case that is about to be run.
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after each test case
-%%--------------------------------------------------------------------
end_per_testcase(_TestCase, Config) ->
ssh_sftpd:stop(?config(sftpd, Config)),
{Cm, Channel} = ?config(sftp, Config),
ssh_connection:close(Cm, Channel),
ssh:close(Cm),
- ssh:stop(),
- ok.
+ ssh:stop().
%%--------------------------------------------------------------------
-%% Function: all(Clause) -> TestCases
-%% Clause - atom() - suite | doc
-%% TestCases - [Case]
-%% Case - atom()
-%% Name of a test case.
-%% Description: Returns a list of all test cases in this test suite
-%%--------------------------------------------------------------------
-all() ->
- [open_close_file, open_close_dir, read_file, read_dir,
- write_file, rename_file, mk_rm_dir, remove_file,
- real_path, retrieve_attributes, set_attributes, links,
- ver3_rename_OTP_6352, seq10670, sshd_read_file].
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%% Test cases starts here.
+%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------
open_close_file(doc) ->
["Test SSH_FXP_OPEN and SSH_FXP_CLOSE commands"];
-open_close_file(suite) ->
- [];
open_close_file(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
FileName = filename:join(PrivDir, "test.txt"),
@@ -214,15 +191,11 @@ open_close_file(Config) when is_list(Config) ->
?UINT32(?SSH_FX_FAILURE), _/binary>>, _} =
open_file(PrivDir, Cm, Channel, NewReqId1,
?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES,
- ?SSH_FXF_OPEN_EXISTING),
-
- ok.
+ ?SSH_FXF_OPEN_EXISTING).
%%--------------------------------------------------------------------
open_close_dir(doc) ->
["Test SSH_FXP_OPENDIR and SSH_FXP_CLOSE commands"];
-open_close_dir(suite) ->
- [];
open_close_dir(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
{Cm, Channel} = ?config(sftp, Config),
@@ -250,8 +223,6 @@ open_close_dir(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
read_file(doc) ->
["Test SSH_FXP_READ command"];
-read_file(suite) ->
- [];
read_file(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
FileName = filename:join(PrivDir, "test.txt"),
@@ -270,28 +241,22 @@ read_file(Config) when is_list(Config) ->
Data/binary>>, _} =
read_file(Handle, 100, 0, Cm, Channel, NewReqId),
- {ok, Data} = file:read_file(FileName),
+ {ok, Data} = file:read_file(FileName).
- ok.
%%--------------------------------------------------------------------
read_dir(doc) ->
["Test SSH_FXP_READDIR command"];
-read_dir(suite) ->
- [];
read_dir(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
{Cm, Channel} = ?config(sftp, Config),
ReqId = 0,
{ok, <<?SSH_FXP_HANDLE, ?UINT32(ReqId), Handle/binary>>, _} =
open_dir(PrivDir, Cm, Channel, ReqId),
- ok = read_dir(Handle, Cm, Channel, ReqId),
- ok.
+ ok = read_dir(Handle, Cm, Channel, ReqId).
%%--------------------------------------------------------------------
write_file(doc) ->
["Test SSH_FXP_WRITE command"];
-write_file(suite) ->
- [];
write_file(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
FileName = filename:join(PrivDir, "test.txt"),
@@ -311,15 +276,11 @@ write_file(Config) when is_list(Config) ->
_/binary>>, _}
= write_file(Handle, Data, 0, Cm, Channel, NewReqId),
- {ok, Data} = file:read_file(FileName),
-
- ok.
+ {ok, Data} = file:read_file(FileName).
%%--------------------------------------------------------------------
remove_file(doc) ->
["Test SSH_FXP_REMOVE command"];
-remove_file(suite) ->
- [];
remove_file(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
FileName = filename:join(PrivDir, "test.txt"),
@@ -336,15 +297,11 @@ remove_file(Config) when is_list(Config) ->
{ok, <<?SSH_FXP_STATUS, ?UINT32(NewReqId),
?UINT32(?SSH_FX_FAILURE), _/binary>>, _} =
- remove(PrivDir, Cm, Channel, NewReqId),
-
- ok.
+ remove(PrivDir, Cm, Channel, NewReqId).
%%--------------------------------------------------------------------
rename_file(doc) ->
["Test SSH_FXP_RENAME command"];
-rename_file(suite) ->
- [];
rename_file(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
FileName = filename:join(PrivDir, "test.txt"),
@@ -377,15 +334,11 @@ rename_file(Config) when is_list(Config) ->
{ok, <<?SSH_FXP_STATUS, ?UINT32(NewReqId2),
?UINT32(?SSH_FX_OP_UNSUPPORTED), _/binary>>, _} =
rename(FileName, NewFileName, Cm, Channel, NewReqId2, 6,
- ?SSH_FXP_RENAME_ATOMIC),
-
- ok.
+ ?SSH_FXP_RENAME_ATOMIC).
%%--------------------------------------------------------------------
mk_rm_dir(doc) ->
["Test SSH_FXP_MKDIR and SSH_FXP_RMDIR command"];
-mk_rm_dir(suite) ->
- [];
mk_rm_dir(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
{Cm, Channel} = ?config(sftp, Config),
@@ -395,7 +348,7 @@ mk_rm_dir(Config) when is_list(Config) ->
_/binary>>, _} = mkdir(DirName, Cm, Channel, ReqId),
NewReqId = 1,
- {ok, <<?SSH_FXP_STATUS, ?UINT32(NewReqId), ?UINT32(?SSH_FX_FAILURE),
+ {ok, <<?SSH_FXP_STATUS, ?UINT32(NewReqId), ?UINT32(?SSH_FX_FILE_ALREADY_EXISTS),
_/binary>>, _} = mkdir(DirName, Cm, Channel, NewReqId),
NewReqId1 = 2,
@@ -404,16 +357,13 @@ mk_rm_dir(Config) when is_list(Config) ->
NewReqId2 = 3,
{ok, <<?SSH_FXP_STATUS, ?UINT32(NewReqId2), ?UINT32(?SSH_FX_NO_SUCH_FILE),
- _/binary>>, _} = rmdir(DirName, Cm, Channel, NewReqId2),
+ _/binary>>, _} = rmdir(DirName, Cm, Channel, NewReqId2).
- ok.
%%--------------------------------------------------------------------
real_path(doc) ->
["Test SSH_FXP_REALPATH command"];
-real_path(suite) ->
- [];
real_path(Config) when is_list(Config) ->
- case test_server:os_type() of
+ case os:type() of
{win32, _} ->
{skip, "Not a relevant test on windows"};
_ ->
@@ -432,20 +382,16 @@ real_path(Config) when is_list(Config) ->
RealPath = filename:absname(binary_to_list(Path)),
AbsPrivDir = filename:absname(PrivDir),
- test_server:format("Path: ~p PrivDir: ~p~n", [RealPath, AbsPrivDir]),
-
- true = RealPath == AbsPrivDir,
+ ct:pal("Path: ~p PrivDir: ~p~n", [RealPath, AbsPrivDir]),
- ok
+ true = RealPath == AbsPrivDir
end.
%%--------------------------------------------------------------------
links(doc) ->
[];
-links(suite) ->
- [];
links(Config) when is_list(Config) ->
- case test_server:os_type() of
+ case os:type() of
{win32, _} ->
{skip, "Links are not fully supported by windows"};
_ ->
@@ -467,15 +413,12 @@ links(Config) when is_list(Config) ->
true = binary_to_list(Path) == FileName,
- test_server:format("Path: ~p~n", [binary_to_list(Path)]),
- ok
+ ct:pal("Path: ~p~n", [binary_to_list(Path)])
end.
%%--------------------------------------------------------------------
retrieve_attributes(doc) ->
["Test SSH_FXP_STAT, SSH_FXP_LSTAT AND SSH_FXP_FSTAT commands"];
-retrieve_attributes(suite) ->
- [];
retrieve_attributes(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
FileName = filename:join(PrivDir, "test.txt"),
@@ -536,16 +479,13 @@ retrieve_attributes(Config) when is_list(Config) ->
Owner = list_to_integer(binary_to_list(BinOwner)),
Group = list_to_integer(binary_to_list(BinGroup))
- end, AttrValues),
+ end, AttrValues).
- ok.
%%--------------------------------------------------------------------
set_attributes(doc) ->
["Test SSH_FXP_SETSTAT AND SSH_FXP_FSETSTAT commands"];
-set_attributes(suite) ->
- [];
set_attributes(Config) when is_list(Config) ->
- case test_server:os_type() of
+ case os:type() of
{win32, _} ->
{skip, "Known error bug in erts file:read_file_info"};
_ ->
@@ -574,10 +514,10 @@ set_attributes(Config) when is_list(Config) ->
%% Can not test that NewPermissions = Permissions as
%% on Unix platforms, other bits than those listed in the
%% API may be set.
- test_server:format("Org: ~p New: ~p~n", [OrigPermissions, NewPermissions]),
+ ct:pal("Org: ~p New: ~p~n", [OrigPermissions, NewPermissions]),
true = OrigPermissions =/= NewPermissions,
- test_server:format("Try to open the file"),
+ ct:pal("Try to open the file"),
NewReqId = 2,
{ok, <<?SSH_FXP_HANDLE, ?UINT32(NewReqId), Handle/binary>>, _} =
open_file(FileName, Cm, Channel, NewReqId,
@@ -589,25 +529,20 @@ set_attributes(Config) when is_list(Config) ->
NewReqId1 = 3,
- test_server:format("Set original permissions on the now open file"),
+ ct:pal("Set original permissions on the now open file"),
{ok, <<?SSH_FXP_STATUS, ?UINT32(NewReqId1),
?UINT32(?SSH_FX_OK), _/binary>>, _} =
set_attributes_open_file(Handle, NewAtters, Cm, Channel, NewReqId1),
{ok, NewFileInfo1} = file:read_file_info(FileName),
- OrigPermissions = NewFileInfo1#file_info.mode,
- ok
+ OrigPermissions = NewFileInfo1#file_info.mode
end.
%%--------------------------------------------------------------------
-ver3_rename_OTP_6352(doc) ->
- ["Test that ver3 rename message is handled"];
-
-ver3_rename_OTP_6352(suite) ->
- [];
-
-ver3_rename_OTP_6352(Config) when is_list(Config) ->
+ver3_rename(doc) ->
+ ["Test that ver3 rename message is handled OTP 6352"];
+ver3_rename(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
FileName = filename:join(PrivDir, "test.txt"),
NewFileName = filename:join(PrivDir, "test1.txt"),
@@ -616,22 +551,16 @@ ver3_rename_OTP_6352(Config) when is_list(Config) ->
{ok, <<?SSH_FXP_STATUS, ?UINT32(ReqId),
?UINT32(?SSH_FX_OK), _/binary>>, _} =
- rename(FileName, NewFileName, Cm, Channel, ReqId, 3, 0),
-
- ok.
+ rename(FileName, NewFileName, Cm, Channel, ReqId, 3, 0).
%%--------------------------------------------------------------------
-seq10670(doc) ->
- ["Check that realpath works ok"];
-
-seq10670(suite) ->
- [];
-
-seq10670(Config) when is_list(Config) ->
+relpath(doc) ->
+ ["Check that realpath works ok seq10670"];
+relpath(Config) when is_list(Config) ->
ReqId = 0,
{Cm, Channel} = ?config(sftp, Config),
- case test_server:os_type() of
+ case os:type() of
{win32, _} ->
{skip, "Not a relevant test on windows"};
_ ->
@@ -644,11 +573,45 @@ seq10670(Config) when is_list(Config) ->
{ok, <<?SSH_FXP_NAME, ?UINT32(ReqId), ?UINT32(_), ?UINT32(Len),
Path:Len/binary, _/binary>>, _}
= real_path("/usr/bin/../..", Cm, Channel, ReqId),
-
Root = Path
end.
-%% Internal functions
+%%--------------------------------------------------------------------
+sshd_read_file(doc) ->
+ ["Test SSH_FXP_READ command, using sshd-server"];
+sshd_read_file(Config) when is_list(Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ FileName = filename:join(PrivDir, "test.txt"),
+
+ ReqId = 0,
+ {Cm, Channel} = ?config(sftp, Config),
+
+ {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),
+
+ NewReqId = 1,
+
+ {ok, <<?SSH_FXP_DATA, ?UINT32(NewReqId), ?UINT32(_Length),
+ Data/binary>>, _} =
+ read_file(Handle, 100, 0, Cm, Channel, NewReqId),
+
+ {ok, Data} = file:read_file(FileName).
+ver6_basic(doc) ->
+ ["Test SFTP Version 6"];
+ver6_basic(Config) when is_list(Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ %FileName = filename:join(PrivDir, "test.txt"),
+ {Cm, Channel} = ?config(sftp, Config),
+ ReqId = 0,
+ {ok, <<?SSH_FXP_STATUS, ?UINT32(ReqId), % Ver 6 we have 5
+ ?UINT32(?SSH_FX_FILE_IS_A_DIRECTORY), _/binary>>, _} =
+ open_file(PrivDir, Cm, Channel, ReqId,
+ ?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES,
+ ?SSH_FXF_OPEN_EXISTING).
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
prep(Config) ->
PrivDir = ?config(priv_dir, Config),
@@ -684,7 +647,7 @@ reply(Cm, Channel, RBuf) ->
{ssh_cm, Cm, {closed, Channel}} ->
closed;
{ssh_cm, Cm, Msg} ->
- test_server:fail(Msg)
+ ct:fail(Msg)
end.
@@ -778,7 +741,7 @@ read_dir(Handle, Cm, Channel, ReqId) ->
case reply(Cm, Channel) of
{ok, <<?SSH_FXP_NAME, ?UINT32(ReqId), ?UINT32(Count),
?UINT32(Len), Listing:Len/binary, _/binary>>, _} ->
- test_server:format("Count: ~p Listing: ~p~n",
+ ct:pal("Count: ~p Listing: ~p~n",
[Count, binary_to_list(Listing)]),
read_dir(Handle, Cm, Channel, ReqId);
{ok, <<?SSH_FXP_STATUS, ?UINT32(ReqId),
@@ -921,32 +884,5 @@ encode_file_type(Type) ->
undefined -> ?SSH_FILEXFER_TYPE_UNKNOWN
end.
-%%--------------------------------------------------------------------
-sshd_read_file(doc) ->
- ["Test SSH_FXP_READ command, using sshd-server"];
-sshd_read_file(suite) ->
- [];
-sshd_read_file(Config) when is_list(Config) ->
- PrivDir = ?config(priv_dir, Config),
- FileName = filename:join(PrivDir, "test.txt"),
-
- ReqId = 0,
- {Cm, Channel} = ?config(sftp, Config),
-
- {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),
-
- NewReqId = 1,
-
- {ok, <<?SSH_FXP_DATA, ?UINT32(NewReqId), ?UINT32(_Length),
- Data/binary>>, _} =
- read_file(Handle, 100, 0, Cm, Channel, NewReqId),
-
- {ok, Data} = file:read_file(FileName),
-
- ok.
-
not_default_permissions() ->
8#600. %% User read-write-only
diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl b/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl
index 4c469ed5f7..8f722941d4 100644
--- a/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl
+++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl
@@ -24,24 +24,32 @@
-compile(export_all).
-include_lib("common_test/include/ct.hrl").
--include("test_server_line.hrl").
-
-include_lib("kernel/include/file.hrl").
-define(USER, "Alladin").
-define(PASSWD, "Sesame").
-define(SSH_MAX_PACKET_SIZE, 32768).
-%% Test server callback functions
%%--------------------------------------------------------------------
-%% Function: init_per_suite(Config) -> Config
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Initiation before the whole suite
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+suite() ->
+ [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [close_file,
+ quit,
+ file_cb,
+ root_dir,
+ list_dir_limited,
+ ver6_basic].
+
+groups() ->
+ [].
+
%%--------------------------------------------------------------------
+
init_per_suite(Config) ->
catch ssh:stop(),
case catch crypto:start() of
@@ -60,12 +68,6 @@ init_per_suite(Config) ->
{skip,"Could not start ssh!"}
end.
-%%--------------------------------------------------------------------
-%% Function: end_per_suite(Config) -> _
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after the whole suite
-%%--------------------------------------------------------------------
end_per_suite(Config) ->
UserDir = filename:join(?config(priv_dir, Config), nopubkey),
file:del_dir(UserDir),
@@ -75,18 +77,14 @@ end_per_suite(Config) ->
ok.
%%--------------------------------------------------------------------
-%% Function: init_per_testcase(TestCase, Config) -> Config
-%% Case - atom()
-%% Name of the test case that is about to be run.
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%%
-%% Description: Initiation before each test case
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
-%% Description: Initiation before each test case
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
%%--------------------------------------------------------------------
+
init_per_testcase(TestCase, Config) ->
ssh:start(),
PrivDir = ?config(priv_dir, Config),
@@ -115,7 +113,12 @@ init_per_testcase(TestCase, Config) ->
[{system_dir, SystemDir},
{user_dir, PrivDir},
{subsystems, [Spec]}];
-
+ "ver6_basic" ->
+ Spec =
+ ssh_sftpd:subsystem_spec([{sftpd_vsn, 6}]),
+ [{system_dir, SystemDir},
+ {user_dir, PrivDir},
+ {subsystems, [Spec]}];
_ ->
[{user_dir, PrivDir},
{system_dir, SystemDir}]
@@ -132,53 +135,21 @@ init_per_testcase(TestCase, Config) ->
NewConfig = lists:keydelete(sftpd, 1, TmpConfig),
[{port, Port}, {sftp, {ChannelPid, Connection}}, {sftpd, Sftpd} | NewConfig].
-%%--------------------------------------------------------------------
-%% Function: end_per_testcase(TestCase, Config) -> _
-%% Case - atom()
-%% Name of the test case that is about to be run.
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after each test case
-%%--------------------------------------------------------------------
end_per_testcase(_TestCase, Config) ->
catch ssh_sftpd:stop(?config(sftpd, Config)),
{Sftp, Connection} = ?config(sftp, Config),
catch ssh_sftp:stop_channel(Sftp),
catch ssh:close(Connection),
- ssh:stop(),
- ok.
+ ssh:stop().
%%--------------------------------------------------------------------
-%% Function: all(Clause) -> TestCases
-%% Clause - atom() - suite | doc
-%% TestCases - [Case]
-%% Case - atom()
-%% Name of a test case.
-%% Description: Returns a list of all test cases in this test suite
+%% Test cases starts here. -------------------------------------------
%%--------------------------------------------------------------------
-all() ->
- [close_file_OTP_6350, quit_OTP_6349, file_cb_OTP_6356,
- root_dir, list_dir_limited].
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-%% Test cases starts here.
-%%--------------------------------------------------------------------
-close_file_OTP_6350(doc) ->
+close_file(doc) ->
["Test that sftpd closes its fildescriptors after compleating the "
- "transfer"];
-
-close_file_OTP_6350(suite) ->
- [];
+ "transfer OTP-6350"];
-close_file_OTP_6350(Config) when is_list(Config) ->
+close_file(Config) when is_list(Config) ->
DataDir = ?config(data_dir, Config),
FileName = filename:join(DataDir, "test.txt"),
@@ -186,28 +157,20 @@ close_file_OTP_6350(Config) when is_list(Config) ->
NumOfPorts = length(erlang:ports()),
- test_server:format("Number of open ports: ~p~n", [NumOfPorts]),
+ ct:pal("Number of open ports: ~p~n", [NumOfPorts]),
{ok, <<_/binary>>} = ssh_sftp:read_file(Sftp, FileName),
- NumOfPorts = length(erlang:ports()),
-
- test_server:format("Number of open ports: ~p~n",
- [length(erlang:ports())]),
-
- ok.
+ NumOfPorts = length(erlang:ports()).
%%--------------------------------------------------------------------
-quit_OTP_6349(doc) ->
+quit(doc) ->
[" When the sftp client ends the session the "
"server will now behave correctly and not leave the "
- "client hanging."];
-
-quit_OTP_6349(suite) ->
- [];
+ "client hanging. OTP-6349"];
-quit_OTP_6349(Config) when is_list(Config) ->
+quit(Config) when is_list(Config) ->
DataDir = ?config(data_dir, Config),
FileName = filename:join(DataDir, "test.txt"),
UserDir = ?config(priv_dir, Config),
@@ -230,19 +193,15 @@ quit_OTP_6349(Config) when is_list(Config) ->
{ok, <<_/binary>>} = ssh_sftp:read_file(NewSftp, FileName),
- ok = ssh_sftp:stop_channel(NewSftp),
- ok.
+ ok = ssh_sftp:stop_channel(NewSftp).
%%--------------------------------------------------------------------
-file_cb_OTP_6356(doc) ->
+file_cb(doc) ->
["Test that it is possible to change the callback module for"
- " the sftpds filehandling."];
-
-file_cb_OTP_6356(suite) ->
- [];
+ " the sftpds filehandling. OTP-6356"];
-file_cb_OTP_6356(Config) when is_list(Config) ->
+file_cb(Config) when is_list(Config) ->
DataDir = ?config(data_dir, Config),
PrivDir = ?config(priv_dir, Config),
FileName = filename:join(DataDir, "test.txt"),
@@ -279,17 +238,15 @@ file_cb_OTP_6356(Config) when is_list(Config) ->
NewDir = filename:join(PrivDir, "testdir"),
ok = ssh_sftp:make_dir(Sftp, NewDir),
alt_file_handler_check(alt_make_dir),
-
+
ok = ssh_sftp:del_dir(Sftp, NewDir),
alt_file_handler_check(alt_read_link_info),
alt_file_handler_check(alt_write_file_info),
- alt_file_handler_check(alt_del_dir),
- ok.
+ alt_file_handler_check(alt_del_dir).
+%%--------------------------------------------------------------------
root_dir(doc) ->
[""];
-root_dir(suite) ->
- [];
root_dir(Config) when is_list(Config) ->
{Sftp, _} = ?config(sftp, Config),
FileName = "test.txt",
@@ -298,26 +255,36 @@ root_dir(Config) when is_list(Config) ->
{ok, Bin} = ssh_sftp:read_file(Sftp, FileName),
{ok, Listing} =
ssh_sftp:list_dir(Sftp, "."),
- test_server:format("Listing: ~p~n", [Listing]),
- ok.
+ ct:pal("Listing: ~p~n", [Listing]).
+%%--------------------------------------------------------------------
list_dir_limited(doc) ->
[""];
-list_dir_limited(suite) ->
- [];
list_dir_limited(Config) when is_list(Config) ->
{Sftp, _} = ?config(sftp, Config),
{ok, Listing} =
ssh_sftp:list_dir(Sftp, "."),
- test_server:format("Listing: ~p~n", [Listing]),
- ok.
+ ct:pal("Listing: ~p~n", [Listing]).
+ver6_basic(doc) ->
+ ["Test some version 6 features"];
+ver6_basic(Config) when is_list(Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ NewDir = filename:join(PrivDir, "testdir2"),
+ {Sftp, _} = ?config(sftp, Config),
+ ok = ssh_sftp:make_dir(Sftp, NewDir),
+ %%Test file_is_a_directory
+ {error, file_is_a_directory} = ssh_sftp:delete(Sftp, NewDir).
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
+
alt_file_handler_check(Msg) ->
receive
Msg ->
ok;
Other ->
- test_server:fail({Msg, Other})
+ ct:fail({Msg, Other})
after 10000 ->
- test_server:fail("Not alt file handler")
+ ct:fail("Not alt file handler")
end.
diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_sftpd_file_alt.erl b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_sftpd_file_alt.erl
index 9e119c4929..9f8a7c496c 100644
--- a/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_sftpd_file_alt.erl
+++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_sftpd_file_alt.erl
@@ -48,7 +48,7 @@ get_cwd(State) ->
{file:get_cwd(), State}.
is_dir(AbsPath, State) ->
- sftpd_file_alt_tester ! alt_is_dir,
+ %sftpd_file_alt_tester ! alt_is_dir,
{filelib:is_dir(AbsPath), State}.
list_dir(AbsPath, State) ->
diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl
index 609663c87a..6ed3dfa68c 100644
--- a/lib/ssh/test/ssh_test_lib.erl
+++ b/lib/ssh/test/ssh_test_lib.erl
@@ -25,8 +25,7 @@
-compile(export_all).
-include_lib("public_key/include/public_key.hrl").
--include("test_server.hrl").
--include("test_server_line.hrl").
+-include_lib("common_test/include/ct.hrl").
-define(TIMEOUT, 50000).
@@ -129,16 +128,16 @@ reply(TestCase, Result) ->
TestCase ! Result.
receive_exec_result(Msg) ->
- test_server:format("Expect data! ~p", [Msg]),
+ ct:pal("Expect data! ~p", [Msg]),
receive
{ssh_cm,_,{data,_,1, Data}} ->
- test_server:format("StdErr: ~p~n", [Data]),
+ ct:pal("StdErr: ~p~n", [Data]),
receive_exec_result(Msg);
Msg ->
- test_server:format("1: Collected data ~p", [Msg]),
+ ct:pal("1: Collected data ~p", [Msg]),
expected;
Other ->
- test_server:format("Other ~p", [Other]),
+ ct:pal("Other ~p", [Other]),
{unexpected_msg, Other}
end.
@@ -150,19 +149,19 @@ receive_exec_end(ConnectionRef, ChannelId) ->
case receive_exec_result(ExitStatus) of
{unexpected_msg, Eof} -> %% Open ssh seems to not allways send these messages
%% in the same order!
- test_server:format("2: Collected data ~p", [Eof]),
+ ct:pal("2: Collected data ~p", [Eof]),
case receive_exec_result(ExitStatus) of
expected ->
expected = receive_exec_result(Closed);
{unexpected_msg, Closed} ->
- test_server:format("3: Collected data ~p", [Closed])
+ ct:pal("3: Collected data ~p", [Closed])
end;
expected ->
- test_server:format("4: Collected data ~p", [ExitStatus]),
+ ct:pal("4: Collected data ~p", [ExitStatus]),
expected = receive_exec_result(Eof),
expected = receive_exec_result(Closed);
Other ->
- test_server:fail({unexpected_msg, Other})
+ ct:fail({unexpected_msg, Other})
end.
receive_exec_result(Data, ConnectionRef, ChannelId) ->
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index c337617ee4..99dc76e12d 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -21,7 +21,6 @@
-module(ssh_to_openssh_SUITE).
-include_lib("common_test/include/ct.hrl").
--include("test_server_line.hrl").
%% Note: This directive should only be used in test suites.
-compile(export_all).
@@ -29,76 +28,10 @@
-define(TIMEOUT, 50000).
-define(SSH_DEFAULT_PORT, 22).
-%% Test server callback functions
%%--------------------------------------------------------------------
-%% Function: init_per_suite(Config) -> Config
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Initialization before the whole suite
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
-%%--------------------------------------------------------------------
-init_per_suite(Config) ->
- case catch crypto:start() of
- ok ->
- case gen_tcp:connect("localhost", 22, []) of
- {error,econnrefused} ->
- {skip,"No openssh deamon"};
- _ ->
- Config
- end;
- _Else ->
- {skip,"Could not start crypto!"}
- end.
-
-%%--------------------------------------------------------------------
-%% Function: end_per_suite(Config) -> _
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after the whole suite
-%%--------------------------------------------------------------------
-end_per_suite(_Config) ->
- crypto:stop(),
- ok.
-
-%%--------------------------------------------------------------------
-%% Function: init_per_testcase(TestCase, Config) -> Config
-%% Case - atom()
-%% Name of the test case that is about to be run.
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%%
-%% Description: Initialization before each test case
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
-%% Description: Initialization before each test case
-%%--------------------------------------------------------------------
-init_per_testcase(_TestCase, Config) ->
- ssh:start(),
- Config.
-
-%%--------------------------------------------------------------------
-%% Function: end_per_testcase(TestCase, Config) -> _
-%% Case - atom()
-%% Name of the test case that is about to be run.
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after each test case
+%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
-end_per_testcase(_TestCase, _Config) ->
- ssh:stop(),
- ok.
-%%--------------------------------------------------------------------
-%% Function: all(Clause) -> TestCases
-%% Clause - atom() - suite | doc
-%% TestCases - [Case]
-%% Case - atom()
-%% Name of a test case.
-%% Description: Returns a list of all test cases in this test suite
-%%--------------------------------------------------------------------
all() ->
case os:find_executable("ssh") of
false ->
@@ -122,6 +55,23 @@ groups() ->
erlang_server_openssh_client_pulic_key_dsa]}
].
+init_per_suite(Config) ->
+ case catch crypto:start() of
+ ok ->
+ case gen_tcp:connect("localhost", 22, []) of
+ {error,econnrefused} ->
+ {skip,"No openssh deamon"};
+ _ ->
+ Config
+ end;
+ _Else ->
+ {skip,"Could not start crypto!"}
+ end.
+
+end_per_suite(_Config) ->
+ crypto:stop(),
+ ok.
+
init_per_group(erlang_server, Config) ->
DataDir = ?config(data_dir, Config),
UserDir = ?config(priv_dir, Config),
@@ -137,14 +87,21 @@ end_per_group(erlang_server, Config) ->
end_per_group(_, Config) ->
Config.
-%% TEST cases starts here.
+init_per_testcase(_TestCase, Config) ->
+ ssh:start(),
+ Config.
+
+end_per_testcase(_TestCase, _Config) ->
+ ssh:stop(),
+ ok.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------
+
erlang_shell_client_openssh_server(doc) ->
["Test that ssh:shell/2 works"];
-erlang_shell_client_openssh_server(suite) ->
- [];
-
erlang_shell_client_openssh_server(Config) when is_list(Config) ->
process_flag(trap_exit, true),
IO = ssh_test_lib:start_io_server(),
@@ -159,22 +116,19 @@ erlang_shell_client_openssh_server(Config) when is_list(Config) ->
ok
end;
Other0 ->
- test_server:fail({unexpected_msg, Other0})
+ ct:fail({unexpected_msg, Other0})
end,
receive
{'EXIT', Shell, normal} ->
ok;
Other1 ->
- test_server:fail({unexpected_msg, Other1})
+ ct:fail({unexpected_msg, Other1})
end.
%--------------------------------------------------------------------
erlang_client_openssh_server_exec(doc) ->
["Test api function ssh_connection:exec"];
-erlang_client_openssh_server_exec(suite) ->
- [];
-
erlang_client_openssh_server_exec(Config) when is_list(Config) ->
ConnectionRef = ssh_test_lib:connect(?SSH_DEFAULT_PORT, [{silently_accept_hosts, true},
{user_interaction, false}]),
@@ -187,11 +141,11 @@ erlang_client_openssh_server_exec(Config) when is_list(Config) ->
ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId0);
{unexpected_msg,{ssh_cm, ConnectionRef, {exit_status, ChannelId0, 0}}
= ExitStatus0} ->
- test_server:format("0: Collected data ~p", [ExitStatus0]),
+ ct:pal("0: Collected data ~p", [ExitStatus0]),
ssh_test_lib:receive_exec_result(Data0,
ConnectionRef, ChannelId0);
Other0 ->
- test_server:fail(Other0)
+ ct:fail(Other0)
end,
{ok, ChannelId1} = ssh_connection:session_channel(ConnectionRef, infinity),
@@ -203,20 +157,17 @@ erlang_client_openssh_server_exec(Config) when is_list(Config) ->
ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId1);
{unexpected_msg,{ssh_cm, ConnectionRef, {exit_status, ChannelId1, 0}}
= ExitStatus1} ->
- test_server:format("0: Collected data ~p", [ExitStatus1]),
+ ct:pal("0: Collected data ~p", [ExitStatus1]),
ssh_test_lib:receive_exec_result(Data1,
ConnectionRef, ChannelId1);
Other1 ->
- test_server:fail(Other1)
+ ct:fail(Other1)
end.
%%--------------------------------------------------------------------
erlang_client_openssh_server_exec_compressed(doc) ->
["Test that compression option works"];
-erlang_client_openssh_server_exec_compressed(suite) ->
- [];
-
erlang_client_openssh_server_exec_compressed(Config) when is_list(Config) ->
ConnectionRef = ssh_test_lib:connect(?SSH_DEFAULT_PORT, [{silently_accept_hosts, true},
{user_interaction, false},
@@ -230,19 +181,16 @@ erlang_client_openssh_server_exec_compressed(Config) when is_list(Config) ->
ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId);
{unexpected_msg,{ssh_cm, ConnectionRef,
{exit_status, ChannelId, 0}} = ExitStatus} ->
- test_server:format("0: Collected data ~p", [ExitStatus]),
+ ct:pal("0: Collected data ~p", [ExitStatus]),
ssh_test_lib:receive_exec_result(Data, ConnectionRef, ChannelId);
Other ->
- test_server:fail(Other)
+ ct:fail(Other)
end.
%%--------------------------------------------------------------------
erlang_server_openssh_client_exec(doc) ->
["Test that exec command works."];
-erlang_server_openssh_client_exec(suite) ->
- [];
-
erlang_server_openssh_client_exec(Config) when is_list(Config) ->
SystemDir = ?config(data_dir, Config),
PrivDir = ?config(priv_dir, Config),
@@ -252,12 +200,12 @@ erlang_server_openssh_client_exec(Config) when is_list(Config) ->
{failfun, fun ssh_test_lib:failfun/2}]),
- test_server:sleep(500),
+ ct:sleep(500),
Cmd = "ssh -p " ++ integer_to_list(Port) ++
" -o UserKnownHostsFile=" ++ KnownHosts ++ " " ++ Host ++ " 1+1.",
- test_server:format("Cmd: ~p~n", [Cmd]),
+ ct:pal("Cmd: ~p~n", [Cmd]),
SshPort = open_port({spawn, Cmd}, [binary]),
@@ -265,7 +213,7 @@ erlang_server_openssh_client_exec(Config) when is_list(Config) ->
{SshPort,{data, <<"2\n">>}} ->
ok
after ?TIMEOUT ->
- test_server:fail("Did not receive answer")
+ ct:fail("Did not receive answer")
end,
ssh:stop_daemon(Pid).
@@ -274,9 +222,6 @@ erlang_server_openssh_client_exec(Config) when is_list(Config) ->
erlang_server_openssh_client_exec_compressed(doc) ->
["Test that exec command works."];
-erlang_server_openssh_client_exec_compressed(suite) ->
- [];
-
erlang_server_openssh_client_exec_compressed(Config) when is_list(Config) ->
SystemDir = ?config(data_dir, Config),
PrivDir = ?config(priv_dir, Config),
@@ -286,7 +231,7 @@ erlang_server_openssh_client_exec_compressed(Config) when is_list(Config) ->
{compression, zlib},
{failfun, fun ssh_test_lib:failfun/2}]),
- test_server:sleep(500),
+ ct:sleep(500),
Cmd = "ssh -p " ++ integer_to_list(Port) ++
" -o UserKnownHostsFile=" ++ KnownHosts ++ " -C "++ Host ++ " 1+1.",
@@ -296,7 +241,7 @@ erlang_server_openssh_client_exec_compressed(Config) when is_list(Config) ->
{SshPort,{data, <<"2\n">>}} ->
ok
after ?TIMEOUT ->
- test_server:fail("Did not receive answer")
+ ct:fail("Did not receive answer")
end,
ssh:stop_daemon(Pid).
@@ -305,9 +250,6 @@ erlang_server_openssh_client_exec_compressed(Config) when is_list(Config) ->
erlang_client_openssh_server_setenv(doc) ->
["Test api function ssh_connection:setenv"];
-erlang_client_openssh_server_setenv(suite) ->
- [];
-
erlang_client_openssh_server_setenv(Config) when is_list(Config) ->
ConnectionRef =
ssh_test_lib:connect(?SSH_DEFAULT_PORT, [{silently_accept_hosts, true},
@@ -332,15 +274,15 @@ erlang_client_openssh_server_setenv(Config) when is_list(Config) ->
{data,0,1, UnxpectedData}}} ->
%% Some os may return things as
%% ENV_TEST: Undefined variable.\n"
- test_server:format("UnxpectedData: ~p", [UnxpectedData]),
+ ct:pal("UnxpectedData: ~p", [UnxpectedData]),
ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId);
{unexpected_msg,{ssh_cm, ConnectionRef, {exit_status, ChannelId, 0}}
= ExitStatus} ->
- test_server:format("0: Collected data ~p", [ExitStatus]),
+ ct:pal("0: Collected data ~p", [ExitStatus]),
ssh_test_lib:receive_exec_result(Data,
ConnectionRef, ChannelId);
Other ->
- test_server:fail(Other)
+ ct:fail(Other)
end.
%%--------------------------------------------------------------------
@@ -350,8 +292,6 @@ erlang_client_openssh_server_setenv(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
erlang_client_openssh_server_publickey_rsa(doc) ->
["Validate using rsa publickey."];
-erlang_client_openssh_server_publickey_rsa(suite) ->
- [];
erlang_client_openssh_server_publickey_rsa(Config) when is_list(Config) ->
{ok,[[Home]]} = init:get_argument(home),
KeyFile = filename:join(Home, ".ssh/id_rsa"),
@@ -379,8 +319,6 @@ erlang_client_openssh_server_publickey_rsa(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
erlang_client_openssh_server_publickey_dsa(doc) ->
["Validate using dsa publickey."];
-erlang_client_openssh_server_publickey_dsa(suite) ->
- [];
erlang_client_openssh_server_publickey_dsa(Config) when is_list(Config) ->
{ok,[[Home]]} = init:get_argument(home),
KeyFile = filename:join(Home, ".ssh/id_dsa"),
@@ -406,10 +344,6 @@ erlang_client_openssh_server_publickey_dsa(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
erlang_server_openssh_client_pulic_key_dsa(doc) ->
["Validate using dsa publickey."];
-
-erlang_server_openssh_client_pulic_key_dsa(suite) ->
- [];
-
erlang_server_openssh_client_pulic_key_dsa(Config) when is_list(Config) ->
SystemDir = ?config(data_dir, Config),
PrivDir = ?config(priv_dir, Config),
@@ -419,7 +353,7 @@ erlang_server_openssh_client_pulic_key_dsa(Config) when is_list(Config) ->
{public_key_alg, ssh_dsa},
{failfun, fun ssh_test_lib:failfun/2}]),
- test_server:sleep(500),
+ ct:sleep(500),
Cmd = "ssh -p " ++ integer_to_list(Port) ++
" -o UserKnownHostsFile=" ++ KnownHosts ++
@@ -430,17 +364,13 @@ erlang_server_openssh_client_pulic_key_dsa(Config) when is_list(Config) ->
{SshPort,{data, <<"2\n">>}} ->
ok
after ?TIMEOUT ->
- test_server:fail("Did not receive answer")
+ ct:fail("Did not receive answer")
end,
ssh:stop_daemon(Pid).
%%--------------------------------------------------------------------
erlang_client_openssh_server_password(doc) ->
["Test client password option"];
-
-erlang_client_openssh_server_password(suite) ->
- [];
-
erlang_client_openssh_server_password(Config) when is_list(Config) ->
%% to make sure we don't public-key-auth
UserDir = ?config(data_dir, Config),
@@ -451,7 +381,7 @@ erlang_client_openssh_server_password(Config) when is_list(Config) ->
{user_interaction, false},
{user_dir, UserDir}]),
- test_server:format("Test of user foo that does not exist. "
+ ct:pal("Test of user foo that does not exist. "
"Error msg: ~p~n", [Reason0]),
User = string:strip(os:cmd("whoami"), right, $\n),
@@ -465,10 +395,10 @@ erlang_client_openssh_server_password(Config) when is_list(Config) ->
{password, "foo"},
{user_interaction, false},
{user_dir, UserDir}]),
- test_server:format("Test of wrong Pasword. "
+ ct:pal("Test of wrong Pasword. "
"Error msg: ~p~n", [Reason1]);
_ ->
- test_server:format("Whoami failed reason: ~n", [])
+ ct:pal("Whoami failed reason: ~n", [])
end.
%%--------------------------------------------------------------------
@@ -477,13 +407,13 @@ erlang_client_openssh_server_password(Config) when is_list(Config) ->
%%
%%--------------------------------------------------------------------
%%--------------------------------------------------------------------
-%%% Internal functions
+%%% Internal functions -----------------------------------------------
%%--------------------------------------------------------------------
receive_hej() ->
receive
<<"Hej\n">> = Hej->
- test_server:format("Expected result: ~p~n", [Hej]);
+ ct:pal("Expected result: ~p~n", [Hej]);
Info ->
- test_server:format("Extra info: ~p~n", [Info]),
+ ct:pal("Extra info: ~p~n", [Info]),
receive_hej()
end.
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index defa47f824..921ec2206a 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,5 +1,5 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 2.1.1
+SSH_VSN = 2.1.2
APP_VSN = "ssh-$(SSH_VSN)"
diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml
index 6c01954010..49bbd5d27d 100644
--- a/lib/ssl/doc/src/notes.xml
+++ b/lib/ssl/doc/src/notes.xml
@@ -30,7 +30,54 @@
</header>
<p>This document describes the changes made to the SSL application.</p>
- <section><title>SSL 5.1</title>
+ <section><title>SSL 5.1.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ ssl:ssl_accept/2 timeout is no longer ignored</p>
+ <p>
+ Own Id: OTP-10600</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 5.1.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ ssl:recv/3 could "loose" data when the timeout occurs. If
+ the timout in ssl:connect or ssl:ssl_accept expired the
+ ssl connection process was not terminated as it should,
+ this due to gen_fsm:send_all_state_event timout is a
+ client side time out. These timouts are now handled by
+ the gen_fsm-procss instead.</p>
+ <p>
+ Own Id: OTP-10569</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Better termination handling that avoids hanging.</p>
+ <p>
+ Own Id: OTP-10574</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 5.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index f0eac76264..e45a4c774f 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -36,8 +36,8 @@
<list type="bulleted">
<item>ssl requires the crypto and public_key applications.</item>
- <item>Supported SSL/TLS-versions are SSL-3.0 and TLS-1.0, experimental
- support for TLS-1.1 and TLS-1.2 is also available (no support for elliptic curve cipher suites yet).</item>
+ <item>Supported SSL/TLS-versions are SSL-3.0, TLS-1.0,
+ TLS-1.1 and TLS-1.2 (no support for elliptic curve cipher suites yet).</item>
<item>For security reasons sslv2 is not supported.</item>
<item>Ephemeral Diffie-Hellman cipher suites are supported
but not Diffie Hellman Certificates cipher suites.</item>
diff --git a/lib/ssl/doc/src/ssl_app.xml b/lib/ssl/doc/src/ssl_app.xml
index 2ba6f48611..178bbcaebb 100644
--- a/lib/ssl/doc/src/ssl_app.xml
+++ b/lib/ssl/doc/src/ssl_app.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE appref SYSTEM "appref.dtd">
<appref>
@@ -29,7 +29,17 @@
sockets.</appsummary>
<section>
- <title>Environment</title>
+ <title>DEPENDENCIES</title>
+ <p>The ssl application uses the Erlang applications public_key and
+ crypto to handle public keys and encryption, hence these
+ applications needs to be loaded for the ssl application to work. In
+ an embedded environment that means they need to be started with
+ application:start/[1,2] before the ssl application is started.
+ </p>
+ </section>
+
+ <section>
+ <title>ENVIRONMENT</title>
<p>The following application environment configuration parameters
are defined for the SSL application. Refer to application(3) for
more information about configuration parameters.
diff --git a/lib/ssl/doc/src/ssl_protocol.xml b/lib/ssl/doc/src/ssl_protocol.xml
index 17268a634d..f540dc999b 100644
--- a/lib/ssl/doc/src/ssl_protocol.xml
+++ b/lib/ssl/doc/src/ssl_protocol.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2003</year><year>2011</year>
+ <year>2003</year><year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -25,9 +25,8 @@
<file>ssl_protocol.xml</file>
</header>
- <p>The erlang SSL application currently supports SSL 3.0 and TLS 1.0
- RFC 2246, and will in the future also support later versions of TLS.
- SSL 2.0 is not supported.
+ <p>The erlang SSL application currently implements the protocol SSL/TLS
+ for currently supported versions see <seealso marker="ssl">ssl(3)</seealso>
</p>
<p>By default erlang SSL is run over the TCP/IP protocol even
diff --git a/lib/ssl/src/Makefile b/lib/ssl/src/Makefile
index c5c5bf593a..043645be41 100644
--- a/lib/ssl/src/Makefile
+++ b/lib/ssl/src/Makefile
@@ -108,10 +108,10 @@ clean:
rm -f errs core *~
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
docs:
@@ -130,3 +130,23 @@ release_spec: opt
release_docs_spec:
+# ----------------------------------------------------
+# Dependencies
+# ----------------------------------------------------
+$(EBIN)/inet_tls_dist.$(EMULATOR): ../../kernel/include/net_address.hrl ../../kernel/include/dist.hrl ../../kernel/include/dist_util.hrl
+$(EBIN)/ssl.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl ssl_handshake.hrl ../../public_key/include/public_key.hrl
+$(EBIN)/ssl_alert.$(EMULATOR): ssl_alert.hrl ssl_record.hrl
+$(EBIN)/ssl_certificate.$(EMULATOR): ssl_internal.hrl ssl_alert.hrl ssl_handshake.hrl ../../public_key/include/public_key.hrl
+$(EBIN)/ssl_certificate_db.$(EMULATOR): ssl_internal.hrl ../../public_key/include/public_key.hrl ../../kernel/include/file.hrl
+$(EBIN)/ssl_cipher.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_alert.hrl ../../public_key/include/public_key.hrl
+$(EBIN)/ssl_connection.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_alert.hrl ../../public_key/include/public_key.hrl
+$(EBIN)/ssl_handshake.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_alert.hrl ../../public_key/include/public_key.hrl
+$(EBIN)/ssl_manager.$(EMULATOR): ssl_internal.hrl ssl_handshake.hrl ../../kernel/include/file.hrl
+$(EBIN)/ssl_record.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_alert.hrl
+$(EBIN)/ssl_session.$(EMULATOR): ssl_internal.hrl ssl_handshake.hrl
+$(EBIN)/ssl_session_cache.$(EMULATOR): ssl_internal.hrl ssl_handshake.hrl
+$(EBIN)/ssl_session_cache_api.$(EMULATOR): ssl_internal.hrl ssl_handshake.hrl
+$(EBIN)/ssl_ssl3.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl
+$(EBIN)/ssl_tls1.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl
+
+
diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src
index 76550fa04b..9b1227fa7f 100644
--- a/lib/ssl/src/ssl.appup.src
+++ b/lib/ssl/src/ssl.appup.src
@@ -1,14 +1,25 @@
%% -*- erlang -*-
{"%VSN%",
[
- {"5.0.1", [{restart_application, ssl}]},
- {"5.0", [{restart_application, ssl}]},
+ {"5.1.1", [{restart_application, ssl}]
+ },
+ {"5.1", [
+ {load_module, ssl_connection, soft_purge, soft_purge, []}
+ ]
+ },
+ {<<"5.0\\*">>, [{restart_application, ssl}]},
{<<"4\\.*">>, [{restart_application, ssl}]},
{<<"3\\.*">>, [{restart_application, ssl}]}
],
[
- {"5.0.1", [{restart_application, ssl}]},
- {"5.0", [{restart_application, ssl}]},
+ {"5.1.1", [{restart_application, ssl}]
+ },
+ {"5.1", [
+ {load_module, ssl_connection, soft_purge, soft_purge, []}
+ ]
+ },
+ {"5.1", [{restart_application, ssl}]},
+ {<<"5.0\\*">>, [{restart_application, ssl}]},
{<<"4\\.*">>, [{restart_application, ssl}]},
{<<"3\\.*">>, [{restart_application, ssl}]}
]}.
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 9a562aa5a8..09f2819ca8 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -28,14 +28,11 @@
cipher_suites/0, cipher_suites/1, suite_definition/1,
close/1, shutdown/2,
connect/3, connect/2, connect/4, connection_info/1,
- controlling_process/2, listen/2, pid/1, peername/1, peercert/1,
+ controlling_process/2, listen/2, peername/1, peercert/1,
recv/2, recv/3, send/2, getopts/2, setopts/2, sockname/1,
versions/0, session_info/1, format_error/1,
renegotiate/1, prf/5, clear_pem_cache/0, random_bytes/1, negotiated_next_protocol/1]).
-
--deprecated({pid, 1, next_major_release}).
-
-include("ssl_internal.hrl").
-include("ssl_record.hrl").
-include("ssl_cipher.hrl").
@@ -47,7 +44,7 @@
-export_type([connect_option/0, listen_option/0, ssl_option/0, transport_option/0,
erl_cipher_suite/0, %% From ssl_cipher.hrl
tls_atom_version/0, %% From ssl_internal.hrl
- prf_random/0]).
+ prf_random/0, sslsocket/0]).
-record(config, {ssl, %% SSL parameters
inet_user, %% User set inet options
@@ -55,6 +52,8 @@
inet_ssl, %% inet options for internal ssl socket
cb %% Callback info
}).
+
+-type sslsocket() :: #sslsocket{}.
-type connect_option() :: socket_connect_option() | ssl_option() | transport_option().
-type socket_connect_option() :: gen_tcp:connect_option().
-type listen_option() :: socket_listen_option() | ssl_option() | transport_option().
@@ -165,7 +164,7 @@ listen(Port, Options0) ->
#config{cb={CbModule, _, _, _},inet_user=Options} = Config,
case CbModule:listen(Port, Options) of
{ok, ListenSocket} ->
- {ok, #sslsocket{pid = {ListenSocket, Config}, fd = new_ssl}};
+ {ok, #sslsocket{pid = {ListenSocket, Config}}};
Err = {error, _} ->
Err
end
@@ -245,18 +244,20 @@ ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket) ->
%%
%% Description: Close an ssl connection
%%--------------------------------------------------------------------
+close(#sslsocket{pid = Pid}) when is_pid(Pid) ->
+ ssl_connection:close(Pid);
close(#sslsocket{pid = {ListenSocket, #config{cb={CbMod,_, _, _}}}}) ->
- CbMod:close(ListenSocket);
-close(#sslsocket{pid = Pid}) ->
- ssl_connection:close(Pid).
+ CbMod:close(ListenSocket).
%%--------------------------------------------------------------------
-spec send(#sslsocket{}, iodata()) -> ok | {error, reason()}.
%%
%% Description: Sends data over the ssl connection
%%--------------------------------------------------------------------
-send(#sslsocket{pid = Pid}, Data) ->
- ssl_connection:send(Pid, Data).
+send(#sslsocket{pid = Pid}, Data) when is_pid(Pid) ->
+ ssl_connection:send(Pid, Data);
+send(#sslsocket{pid = {ListenSocket, #config{cb={CbModule, _, _, _}}}}, Data) ->
+ CbModule:send(ListenSocket, Data). %% {error,enotconn}
%%--------------------------------------------------------------------
-spec recv(#sslsocket{}, integer()) -> {ok, binary()| list()} | {error, reason()}.
@@ -266,8 +267,10 @@ send(#sslsocket{pid = Pid}, Data) ->
%%--------------------------------------------------------------------
recv(Socket, Length) ->
recv(Socket, Length, infinity).
-recv(#sslsocket{pid = Pid, fd = new_ssl}, Length, Timeout) ->
- ssl_connection:recv(Pid, Length, Timeout).
+recv(#sslsocket{pid = Pid}, Length, Timeout) when is_pid(Pid) ->
+ ssl_connection:recv(Pid, Length, Timeout);
+recv(#sslsocket{pid = {Listen, #config{cb={CbModule, _, _, _}}}}, _,_) when is_port(Listen)->
+ CbModule:recv(Listen, 0). %% {error,enotconn}
%%--------------------------------------------------------------------
-spec controlling_process(#sslsocket{}, pid()) -> ok | {error, reason()}.
@@ -275,8 +278,12 @@ recv(#sslsocket{pid = Pid, fd = new_ssl}, Length, Timeout) ->
%% Description: Changes process that receives the messages when active = true
%% or once.
%%--------------------------------------------------------------------
-controlling_process(#sslsocket{pid = Pid}, NewOwner) when is_pid(Pid) ->
- ssl_connection:new_user(Pid, NewOwner).
+controlling_process(#sslsocket{pid = Pid}, NewOwner) when is_pid(Pid), is_pid(NewOwner) ->
+ ssl_connection:new_user(Pid, NewOwner);
+controlling_process(#sslsocket{pid = {Listen,
+ #config{cb={CbModule, _, _, _}}}}, NewOwner) when is_port(Listen),
+ is_pid(NewOwner) ->
+ CbModule:controlling_process(Listen, NewOwner).
%%--------------------------------------------------------------------
-spec connection_info(#sslsocket{}) -> {ok, {tls_atom_version(), erl_cipher_suite()}} |
@@ -284,29 +291,35 @@ controlling_process(#sslsocket{pid = Pid}, NewOwner) when is_pid(Pid) ->
%%
%% Description: Returns ssl protocol and cipher used for the connection
%%--------------------------------------------------------------------
-connection_info(#sslsocket{pid = Pid}) ->
- ssl_connection:info(Pid).
+connection_info(#sslsocket{pid = Pid}) when is_pid(Pid) ->
+ ssl_connection:info(Pid);
+connection_info(#sslsocket{pid = {Listen, _}}) when is_port(Listen) ->
+ {error, enotconn}.
%%--------------------------------------------------------------------
-spec peername(#sslsocket{}) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, reason()}.
%%
%% Description: same as inet:peername/1.
%%--------------------------------------------------------------------
-peername(#sslsocket{pid = Pid}) ->
- ssl_connection:peername(Pid).
+peername(#sslsocket{pid = Pid, fd = Socket}) when is_pid(Pid)->
+ inet:peername(Socket);
+peername(#sslsocket{pid = {ListenSocket, _}}) ->
+ inet:peername(ListenSocket). %% Will return {error, enotconn}
%%--------------------------------------------------------------------
-spec peercert(#sslsocket{}) ->{ok, DerCert::binary()} | {error, reason()}.
%%
%% Description: Returns the peercert.
%%--------------------------------------------------------------------
-peercert(#sslsocket{pid = Pid}) ->
+peercert(#sslsocket{pid = Pid}) when is_pid(Pid) ->
case ssl_connection:peer_certificate(Pid) of
{ok, undefined} ->
{error, no_peercert};
Result ->
Result
- end.
+ end;
+peercert(#sslsocket{pid = {Listen, _}}) when is_port(Listen) ->
+ {error, enotconn}.
%%--------------------------------------------------------------------
-spec suite_definition(cipher_suite()) -> erl_cipher_suite().
@@ -323,7 +336,7 @@ suite_definition(S) ->
%% Description: Returns the next protocol that has been negotiated. If no
%% protocol has been negotiated will return {error, next_protocol_not_negotiated}
%%--------------------------------------------------------------------
-negotiated_next_protocol(#sslsocket{fd = new_ssl, pid = Pid}) ->
+negotiated_next_protocol(#sslsocket{pid = Pid}) ->
ssl_connection:negotiated_next_protocol(Pid).
-spec cipher_suites() -> [erl_cipher_suite()].
@@ -396,8 +409,9 @@ setopts(#sslsocket{}, Options) ->
%%
%% Description: Same as gen_tcp:shutdown/2
%%--------------------------------------------------------------------
-shutdown(#sslsocket{pid = {ListenSocket, #config{cb={CbMod,_, _, _}}}}, How) ->
- CbMod:shutdown(ListenSocket, How);
+shutdown(#sslsocket{pid = {Listen, #config{cb={CbMod,_, _, _}}}},
+ How) when is_port(Listen) ->
+ CbMod:shutdown(Listen, How);
shutdown(#sslsocket{pid = Pid}, How) ->
ssl_connection:shutdown(Pid, How).
@@ -406,11 +420,11 @@ shutdown(#sslsocket{pid = Pid}, How) ->
%%
%% Description: Same as inet:sockname/1
%%--------------------------------------------------------------------
-sockname(#sslsocket{pid = {ListenSocket, _}}) ->
- inet:sockname(ListenSocket);
+sockname(#sslsocket{pid = {Listen, _}}) when is_port(Listen) ->
+ inet:sockname(Listen);
-sockname(#sslsocket{pid = Pid}) ->
- ssl_connection:sockname(Pid).
+sockname(#sslsocket{pid = Pid, fd = Socket}) when is_pid(Pid) ->
+ inet:sockname(Socket).
%%---------------------------------------------------------------
-spec session_info(#sslsocket{}) -> {ok, list()} | {error, reason()}.
@@ -418,12 +432,14 @@ sockname(#sslsocket{pid = Pid}) ->
%% Description: Returns list of session info currently [{session_id, session_id(),
%% {cipher_suite, cipher_suite()}]
%%--------------------------------------------------------------------
-session_info(#sslsocket{pid = Pid, fd = new_ssl}) ->
- ssl_connection:session_info(Pid).
+session_info(#sslsocket{pid = Pid}) when is_pid(Pid) ->
+ ssl_connection:session_info(Pid);
+session_info(#sslsocket{pid = {Listen,_}}) when is_port(Listen) ->
+ {error, enotconn}.
%%---------------------------------------------------------------
-spec versions() -> [{ssl_app, string()} | {supported, [tls_atom_version()]} |
- {available, [tls_atom_version()]}].
+ {available, [tls_atom_version()]}].
%%
%% Description: Returns a list of relevant versions.
%%--------------------------------------------------------------------
@@ -439,8 +455,10 @@ versions() ->
%%
%% Description: Initiates a renegotiation.
%%--------------------------------------------------------------------
-renegotiate(#sslsocket{pid = Pid, fd = new_ssl}) ->
- ssl_connection:renegotiation(Pid).
+renegotiate(#sslsocket{pid = Pid}) when is_pid(Pid) ->
+ ssl_connection:renegotiation(Pid);
+renegotiate(#sslsocket{pid = {Listen,_}}) when is_port(Listen) ->
+ {error, enotconn}.
%%--------------------------------------------------------------------
-spec prf(#sslsocket{}, binary() | 'master_secret', binary(),
@@ -449,10 +467,11 @@ renegotiate(#sslsocket{pid = Pid, fd = new_ssl}) ->
%%
%% Description: use a ssl sessions TLS PRF to generate key material
%%--------------------------------------------------------------------
-prf(#sslsocket{pid = Pid, fd = new_ssl},
- Secret, Label, Seed, WantedLength) ->
- ssl_connection:prf(Pid, Secret, Label, Seed, WantedLength).
-
+prf(#sslsocket{pid = Pid},
+ Secret, Label, Seed, WantedLength) when is_pid(Pid) ->
+ ssl_connection:prf(Pid, Secret, Label, Seed, WantedLength);
+prf(#sslsocket{pid = {Listen,_}}, _,_,_,_) when is_port(Listen) ->
+ {error, enotconn}.
%%--------------------------------------------------------------------
-spec clear_pem_cache() -> ok.
@@ -849,10 +868,10 @@ internal_inet_values() ->
socket_options(InetValues) ->
#socket_options{
- mode = proplists:get_value(mode, InetValues),
- header = proplists:get_value(header, InetValues),
- active = proplists:get_value(active, InetValues),
- packet = proplists:get_value(packet, InetValues),
+ mode = proplists:get_value(mode, InetValues, lists),
+ header = proplists:get_value(header, InetValues, 0),
+ active = proplists:get_value(active, InetValues, active),
+ packet = proplists:get_value(packet, InetValues, 0),
packet_size = proplists:get_value(packet_size, InetValues)
}.
@@ -934,14 +953,3 @@ make_next_protocol_selector({server, AllProtocols, DefaultProtocol}) ->
PreferredProtocol -> PreferredProtocol
end
end.
-
-%% Only used to remove exit messages from old ssl
-%% First is a nonsense clause to provide some
-%% backward compatibility for orber that uses this
-%% function in a none recommended way, but will
-%% work correctly if a valid pid is returned.
-%% Deprcated to be removed in r16
-pid(#sslsocket{fd = new_ssl}) ->
- whereis(ssl_connection_sup);
-pid(#sslsocket{pid = Pid}) ->
- Pid.
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index 23f22987df..94f76e0606 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -40,8 +40,7 @@
-export([send/2, recv/3, connect/7, ssl_accept/6, handshake/2,
socket_control/3, close/1, shutdown/2,
new_user/2, get_opts/2, set_opts/2, info/1, session_info/1,
- peer_certificate/1, sockname/1, peername/1, renegotiation/1,
- negotiated_next_protocol/1, prf/5]).
+ peer_certificate/1, renegotiation/1, negotiated_next_protocol/1, prf/5]).
%% Called by ssl_connection_sup
-export([start_link/7]).
@@ -90,6 +89,7 @@
log_alert, % boolean()
renegotiation, % {boolean(), From | internal | peer}
start_or_recv_from, % "gen_fsm From"
+ timer, % start_or_recv_timer
send_queue, % queue()
terminated = false, %
allow_renegotiate = true,
@@ -120,7 +120,7 @@ send(Pid, Data) ->
sync_send_all_state_event(Pid, {application_data,
%% iolist_to_binary should really
%% be called iodata_to_binary()
- erlang:iolist_to_binary(Data)}, infinity).
+ erlang:iolist_to_binary(Data)}).
%%--------------------------------------------------------------------
-spec recv(pid(), integer(), timeout()) ->
@@ -129,7 +129,7 @@ send(Pid, Data) ->
%% Description: Receives data when active = false
%%--------------------------------------------------------------------
recv(Pid, Length, Timeout) ->
- sync_send_all_state_event(Pid, {recv, Length}, Timeout).
+ sync_send_all_state_event(Pid, {recv, Length, Timeout}).
%%--------------------------------------------------------------------
-spec connect(host(), inet:port_number(), port(), {#ssl_options{}, #socket_options{}},
pid(), tuple(), timeout()) ->
@@ -166,7 +166,7 @@ ssl_accept(Port, Socket, Opts, User, CbInfo, Timeout) ->
%% Description: Starts ssl handshake.
%%--------------------------------------------------------------------
handshake(#sslsocket{pid = Pid}, Timeout) ->
- case sync_send_all_state_event(Pid, start, Timeout) of
+ case sync_send_all_state_event(Pid, {start, Timeout}) of
connected ->
ok;
Error ->
@@ -181,7 +181,7 @@ handshake(#sslsocket{pid = Pid}, Timeout) ->
socket_control(Socket, Pid, CbModule) ->
case CbModule:controlling_process(Socket, Pid) of
ok ->
- {ok, sslsocket(Pid)};
+ {ok, sslsocket(Pid, Socket)};
{error, Reason} ->
{error, Reason}
end.
@@ -215,13 +215,7 @@ shutdown(ConnectionPid, How) ->
%%--------------------------------------------------------------------
new_user(ConnectionPid, User) ->
sync_send_all_state_event(ConnectionPid, {new_user, User}).
-%%--------------------------------------------------------------------
--spec sockname(pid()) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, reason()}.
-%%
-%% Description: Same as inet:sockname/1
-%%--------------------------------------------------------------------
-sockname(ConnectionPid) ->
- sync_send_all_state_event(ConnectionPid, sockname).
+
%%--------------------------------------------------------------------
-spec negotiated_next_protocol(pid()) -> {ok, binary()} | {error, reason()}.
%%
@@ -229,13 +223,7 @@ sockname(ConnectionPid) ->
%%--------------------------------------------------------------------
negotiated_next_protocol(ConnectionPid) ->
sync_send_all_state_event(ConnectionPid, negotiated_next_protocol).
-%%--------------------------------------------------------------------
--spec peername(pid()) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, reason()}.
-%%
-%% Description: Same as inet:peername/1
-%%--------------------------------------------------------------------
-peername(ConnectionPid) ->
- sync_send_all_state_event(ConnectionPid, peername).
+
%%--------------------------------------------------------------------
-spec get_opts(pid(), list()) -> {ok, list()} | {error, reason()}.
%%
@@ -344,15 +332,15 @@ init([Role, Host, Port, Socket, {SSLOpts0, _} = Options, User, CbInfo]) ->
#state{}) -> gen_fsm_state_return().
%%--------------------------------------------------------------------
hello(start, #state{host = Host, port = Port, role = client,
- ssl_options = SslOpts,
- session = #session{own_certificate = Cert} = Session0,
- session_cache = Cache, session_cache_cb = CacheCb,
- transport_cb = Transport, socket = Socket,
- connection_states = ConnectionStates0,
- renegotiation = {Renegotiation, _}} = State0) ->
+ ssl_options = SslOpts,
+ session = #session{own_certificate = Cert} = Session0,
+ session_cache = Cache, session_cache_cb = CacheCb,
+ transport_cb = Transport, socket = Socket,
+ connection_states = ConnectionStates0,
+ renegotiation = {Renegotiation, _}} = State0) ->
Hello = ssl_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts,
Cache, CacheCb, Renegotiation, Cert),
-
+
Version = Hello#client_hello.client_version,
Handshake0 = ssl_handshake:init_handshake_history(),
{BinMsg, ConnectionStates, Handshake} =
@@ -383,23 +371,22 @@ hello(#server_hello{cipher_suite = CipherSuite,
renegotiation = {Renegotiation, _},
ssl_options = SslOptions} = State0) ->
case ssl_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of
- #alert{} = Alert ->
- handle_own_alert(Alert, ReqVersion, hello, State0),
- {stop, normal, State0};
-
+ #alert{} = Alert ->
+ handle_own_alert(Alert, ReqVersion, hello, State0),
+ {stop, {shutdown, own_alert}, State0};
{Version, NewId, ConnectionStates, NextProtocol} ->
{KeyAlgorithm, _, _, _} =
ssl_cipher:suite_definition(CipherSuite),
PremasterSecret = make_premaster_secret(ReqVersion, KeyAlgorithm),
-
- NewNextProtocol = case NextProtocol of
- undefined ->
- State0#state.next_protocol;
- _ ->
- NextProtocol
- end,
-
+
+ NewNextProtocol = case NextProtocol of
+ undefined ->
+ State0#state.next_protocol;
+ _ ->
+ NextProtocol
+ end,
+
State = State0#state{key_algorithm = KeyAlgorithm,
hashsign_algorithm = default_hashsign(Version, KeyAlgorithm),
negotiated_version = Version,
@@ -407,13 +394,13 @@ hello(#server_hello{cipher_suite = CipherSuite,
premaster_secret = PremasterSecret,
expecting_next_protocol_negotiation = NextProtocol =/= undefined,
next_protocol = NewNextProtocol},
-
+
case ssl_session:is_new(OldId, NewId) of
true ->
handle_new_session(NewId, CipherSuite, Compression,
State#state{connection_states = ConnectionStates});
false ->
- handle_resumed_session(NewId, State#state{connection_states = ConnectionStates})
+ handle_resumed_session(NewId, State#state{connection_states = ConnectionStates})
end
end;
@@ -432,8 +419,7 @@ hello(Hello = #client_hello{client_version = ClientVersion},
negotiated_version = Version,
session = Session});
#alert{} = Alert ->
- handle_own_alert(Alert, ClientVersion, hello, State),
- {stop, normal, State}
+ handle_own_alert(Alert, ClientVersion, hello, State)
end;
hello(timeout, State) ->
@@ -464,8 +450,7 @@ abbreviated(#finished{verify_data = Data} = Finished,
next_state_connection(abbreviated,
ack_connection(State#state{connection_states = ConnectionStates}));
#alert{} = Alert ->
- handle_own_alert(Alert, Version, abbreviated, State),
- {stop, normal, State}
+ handle_own_alert(Alert, Version, abbreviated, State)
end;
abbreviated(#finished{verify_data = Data} = Finished,
@@ -485,8 +470,7 @@ abbreviated(#finished{verify_data = Data} = Finished,
connection_states =
ConnectionStates}));
#alert{} = Alert ->
- handle_own_alert(Alert, Version, abbreviated, State),
- {stop, normal, State}
+ handle_own_alert(Alert, Version, abbreviated, State)
end;
abbreviated(timeout, State) ->
@@ -510,8 +494,7 @@ certify(#certificate{asn1_certificates = []},
fail_if_no_peer_cert = true}} =
State) ->
Alert = ?ALERT_REC(?FATAL,?HANDSHAKE_FAILURE),
- handle_own_alert(Alert, Version, certify, State),
- {stop, normal, State};
+ handle_own_alert(Alert, Version, certify, State);
certify(#certificate{asn1_certificates = []},
#state{role = server,
@@ -534,8 +517,7 @@ certify(#certificate{} = Cert,
handle_peer_cert(PeerCert, PublicKeyInfo,
State#state{client_certificate_requested = false});
#alert{} = Alert ->
- handle_own_alert(Alert, Version, certify, State),
- {stop, normal, State}
+ handle_own_alert(Alert, Version, certify, State)
end;
certify(#server_key_exchange{} = KeyExchangeMsg,
@@ -547,8 +529,7 @@ certify(#server_key_exchange{} = KeyExchangeMsg,
{Record, State} = next_record(State1),
next_state(certify, certify, Record, State);
#alert{} = Alert ->
- handle_own_alert(Alert, Version, certify, State0),
- {stop, normal, State0}
+ handle_own_alert(Alert, Version, certify, State0)
end;
certify(#server_key_exchange{} = Msg,
@@ -572,8 +553,7 @@ certify(#server_hello_done{},
State = State0#state{connection_states = ConnectionStates},
client_certify_and_key_exchange(State);
#alert{} = Alert ->
- handle_own_alert(Alert, Version, certify, State0),
- {stop, normal, State0}
+ handle_own_alert(Alert, Version, certify, State0)
end;
%% Master secret is calculated from premaster_secret
@@ -591,8 +571,7 @@ certify(#server_hello_done{},
session = Session},
client_certify_and_key_exchange(State);
#alert{} = Alert ->
- handle_own_alert(Alert, Version, certify, State0),
- {stop, normal, State0}
+ handle_own_alert(Alert, Version, certify, State0)
end;
certify(#client_key_exchange{} = Msg,
@@ -608,8 +587,7 @@ certify(#client_key_exchange{exchange_keys = Keys},
certify_client_key_exchange(ssl_handshake:decode_client_key(Keys, KeyAlg, Version), State)
catch
#alert{} = Alert ->
- handle_own_alert(Alert, Version, certify, State),
- {stop, normal, State}
+ handle_own_alert(Alert, Version, certify, State)
end;
@@ -634,8 +612,7 @@ certify_client_key_exchange(#encrypted_premaster_secret{premaster_secret= EncPMS
{Record, State} = next_record(State1),
next_state(certify, cipher, Record, State);
#alert{} = Alert ->
- handle_own_alert(Alert, Version, certify, State0),
- {stop, normal, State0}
+ handle_own_alert(Alert, Version, certify, State0)
end;
certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPublicDhKey},
@@ -648,8 +625,7 @@ certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPubl
{Record, State} = next_record(State1),
next_state(certify, cipher, Record, State);
#alert{} = Alert ->
- handle_own_alert(Alert, Version, certify, State0),
- {stop, normal, State0}
+ handle_own_alert(Alert, Version, certify, State0)
end.
%%--------------------------------------------------------------------
@@ -678,8 +654,7 @@ cipher(#certificate_verify{signature = Signature, hashsign_algorithm = CertHashS
{Record, State} = next_record(State0),
next_state(cipher, cipher, Record, State);
#alert{} = Alert ->
- handle_own_alert(Alert, Version, cipher, State0),
- {stop, normal, State0}
+ handle_own_alert(Alert, Version, cipher, State0)
end;
% client must send a next protocol message if we are expecting it
@@ -705,8 +680,7 @@ cipher(#finished{verify_data = Data} = Finished,
Session = register_session(Role, Host, Port, Session0),
cipher_role(Role, Data, Session, State);
#alert{} = Alert ->
- handle_own_alert(Alert, Version, cipher, State),
- {stop, normal, State}
+ handle_own_alert(Alert, Version, cipher, State)
end;
% only allowed to send next_protocol message after change cipher spec
@@ -801,8 +775,10 @@ handle_sync_event({application_data, Data}, From, StateName,
State#state{send_queue = queue:in({From, Data}, Queue)},
get_timeout(State)};
-handle_sync_event(start, StartFrom, hello, State) ->
- hello(start, State#state{start_or_recv_from = StartFrom});
+handle_sync_event({start, Timeout}, StartFrom, hello, State) ->
+ Timer = start_or_recv_cancel_timer(Timeout, StartFrom),
+ hello(start, State#state{start_or_recv_from = StartFrom,
+ timer = Timer});
%% The two clauses below could happen if a server upgrades a socket in
%% active mode. Note that in this case we are lucky that
@@ -811,13 +787,16 @@ handle_sync_event(start, StartFrom, hello, State) ->
%% mode before telling the client that it is willing to upgrade
%% and before calling ssl:ssl_accept/2. These clauses are
%% here to make sure it is the users problem and not owers if
-%% they upgrade a active socket.
-handle_sync_event(start, _, connection, State) ->
+%% they upgrade an active socket.
+handle_sync_event({start,_}, _, connection, State) ->
{reply, connected, connection, State, get_timeout(State)};
-handle_sync_event(start, _From, error, {Error, State = #state{}}) ->
+handle_sync_event({start,_}, _From, error, {Error, State = #state{}}) ->
{stop, {shutdown, Error}, {error, Error}, State};
-handle_sync_event(start, StartFrom, StateName, State) ->
- {next_state, StateName, State#state{start_or_recv_from = StartFrom}, get_timeout(State)};
+
+handle_sync_event({start, Timeout}, StartFrom, StateName, State) ->
+ Timer = start_or_recv_cancel_timer(Timeout, StartFrom),
+ {next_state, StateName, State#state{start_or_recv_from = StartFrom,
+ timer = Timer}, get_timeout(State)};
handle_sync_event(close, _, StateName, State) ->
%% Run terminate before returning
@@ -848,13 +827,17 @@ handle_sync_event({shutdown, How0}, _, StateName,
{stop, normal, Error, State}
end;
-handle_sync_event({recv, N}, RecvFrom, connection = StateName, State0) ->
- passive_receive(State0#state{bytes_to_read = N, start_or_recv_from = RecvFrom}, StateName);
+handle_sync_event({recv, N, Timeout}, RecvFrom, connection = StateName, State0) ->
+ Timer = start_or_recv_cancel_timer(Timeout, RecvFrom),
+ passive_receive(State0#state{bytes_to_read = N,
+ start_or_recv_from = RecvFrom, timer = Timer}, StateName);
%% Doing renegotiate wait with handling request until renegotiate is
%% finished. Will be handled by next_state_is_connection/2.
-handle_sync_event({recv, N}, RecvFrom, StateName, State) ->
- {next_state, StateName, State#state{bytes_to_read = N, start_or_recv_from = RecvFrom},
+handle_sync_event({recv, N, Timeout}, RecvFrom, StateName, State) ->
+ Timer = start_or_recv_cancel_timer(Timeout, RecvFrom),
+ {next_state, StateName, State#state{bytes_to_read = N, start_or_recv_from = RecvFrom,
+ timer = Timer},
get_timeout(State)};
handle_sync_event({new_user, User}, _From, StateName,
@@ -870,19 +853,10 @@ handle_sync_event({get_opts, OptTags}, _From, StateName,
OptsReply = get_socket_opts(Socket, OptTags, SockOpts, []),
{reply, OptsReply, StateName, State, get_timeout(State)};
-handle_sync_event(sockname, _From, StateName,
- #state{socket = Socket} = State) ->
- SockNameReply = inet:sockname(Socket),
- {reply, SockNameReply, StateName, State, get_timeout(State)};
-
handle_sync_event(negotiated_next_protocol, _From, StateName, #state{next_protocol = undefined} = State) ->
{reply, {error, next_protocol_not_negotiated}, StateName, State, get_timeout(State)};
handle_sync_event(negotiated_next_protocol, _From, StateName, #state{next_protocol = NextProtocol} = State) ->
{reply, {ok, NextProtocol}, StateName, State, get_timeout(State)};
-handle_sync_event(peername, _From, StateName,
- #state{socket = Socket} = State) ->
- PeerNameReply = inet:peername(Socket),
- {reply, PeerNameReply, StateName, State, get_timeout(State)};
handle_sync_event({set_opts, Opts0}, _From, StateName,
#state{socket_options = Opts1,
@@ -985,7 +959,7 @@ handle_info({Protocol, _, Data}, StateName,
next_state(StateName, StateName, Record, State);
#alert{} = Alert ->
handle_normal_shutdown(Alert, StateName, State0),
- {stop, normal, State0}
+ {stop, {shutdown, own_alert}, State0}
end;
handle_info({CloseTag, Socket}, StateName,
@@ -1006,12 +980,12 @@ handle_info({CloseTag, Socket}, StateName,
ok
end,
handle_normal_shutdown(?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), StateName, State),
- {stop, normal, State};
+ {stop, {shutdown, transport_closed}, State};
handle_info({ErrorTag, Socket, econnaborted}, StateName,
#state{socket = Socket, start_or_recv_from = StartFrom, role = Role,
error_tag = ErrorTag} = State) when StateName =/= connection ->
- alert_user(StartFrom, ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE), Role),
+ alert_user(Socket, StartFrom, ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE), Role),
{stop, normal, State};
handle_info({ErrorTag, Socket, Reason}, StateName, #state{socket = Socket,
@@ -1027,7 +1001,21 @@ handle_info({'DOWN', MonitorRef, _, _, _}, _,
handle_info(allow_renegotiate, StateName, State) ->
{next_state, StateName, State#state{allow_renegotiate = true}, get_timeout(State)};
-
+
+handle_info({cancel_start_or_recv, StartFrom}, StateName,
+ #state{renegotiation = {false, first}} = State) when StateName =/= connection ->
+ gen_fsm:reply(StartFrom, {error, timeout}),
+ {stop, {shutdown, user_timeout}, State#state{timer = undefined}};
+
+handle_info({cancel_start_or_recv, RecvFrom}, StateName, #state{start_or_recv_from = RecvFrom} = State) ->
+ gen_fsm:reply(RecvFrom, {error, timeout}),
+ {next_state, StateName, State#state{start_or_recv_from = undefined,
+ bytes_to_read = undefined,
+ timer = undefined}, get_timeout(State)};
+
+handle_info({cancel_start_or_recv, _RecvFrom}, StateName, State) ->
+ {next_state, StateName, State#state{timer = undefined}, get_timeout(State)};
+
handle_info(Msg, StateName, State) ->
Report = io_lib:format("SSL: Got unexpected info: ~p ~n", [Msg]),
error_logger:info_report(Report),
@@ -1044,6 +1032,20 @@ terminate(_, _, #state{terminated = true}) ->
%% we want to guarantee that Transport:close has been called
%% when ssl:close/1 returns.
ok;
+
+terminate({shutdown, transport_closed}, StateName, #state{send_queue = SendQueue,
+ renegotiation = Renegotiate} = State) ->
+ handle_unrecv_data(StateName, State),
+ handle_trusted_certs_db(State),
+ notify_senders(SendQueue),
+ notify_renegotiater(Renegotiate);
+
+terminate({shutdown, own_alert}, _StateName, #state{send_queue = SendQueue,
+ renegotiation = Renegotiate} = State) ->
+ handle_trusted_certs_db(State),
+ notify_senders(SendQueue),
+ notify_renegotiater(Renegotiate);
+
terminate(Reason, connection, #state{negotiated_version = Version,
connection_states = ConnectionStates,
transport_cb = Transport,
@@ -1054,16 +1056,14 @@ terminate(Reason, connection, #state{negotiated_version = Version,
notify_renegotiater(Renegotiate),
BinAlert = terminate_alert(Reason, Version, ConnectionStates),
Transport:send(Socket, BinAlert),
- workaround_transport_delivery_problems(Socket, Transport, Reason),
- Transport:close(Socket);
+ workaround_transport_delivery_problems(Socket, Transport);
-terminate(Reason, _StateName, #state{transport_cb = Transport,
+terminate(_Reason, _StateName, #state{transport_cb = Transport,
socket = Socket, send_queue = SendQueue,
renegotiation = Renegotiate} = State) ->
handle_trusted_certs_db(State),
notify_senders(SendQueue),
notify_renegotiater(Renegotiate),
- workaround_transport_delivery_problems(Socket, Transport, Reason),
Transport:close(Socket).
%%--------------------------------------------------------------------
@@ -1238,18 +1238,13 @@ init_diffie_hellman(DbHandle,_, DHParamFile, server) ->
end.
sync_send_all_state_event(FsmPid, Event) ->
- sync_send_all_state_event(FsmPid, Event, infinity).
-
-sync_send_all_state_event(FsmPid, Event, Timeout) ->
- try gen_fsm:sync_send_all_state_event(FsmPid, Event, Timeout)
+ try gen_fsm:sync_send_all_state_event(FsmPid, Event, infinity)
catch
exit:{noproc, _} ->
{error, closed};
- exit:{timeout, _} ->
- {error, timeout};
exit:{normal, _} ->
{error, closed};
- exit:{shutdown, _} ->
+ exit:{{shutdown, _},_} ->
{error, closed}
end.
@@ -1346,8 +1341,7 @@ new_server_hello(#server_hello{cipher_suite = CipherSuite,
next_state(hello, certify, Record, State)
catch
#alert{} = Alert ->
- handle_own_alert(Alert, Version, hello, State0),
- {stop, normal, State0}
+ handle_own_alert(Alert, Version, hello, State0)
end.
resumed_server_hello(#state{session = Session,
@@ -1367,8 +1361,7 @@ resumed_server_hello(#state{session = Session,
{Record, State} = next_record(State2),
next_state(hello, abbreviated, Record, State);
#alert{} = Alert ->
- handle_own_alert(Alert, Version, hello, State0),
- {stop, normal, State0}
+ handle_own_alert(Alert, Version, hello, State0)
end.
handle_new_session(NewId, CipherSuite, Compression, #state{session = Session0} = State0) ->
@@ -1393,8 +1386,7 @@ handle_resumed_session(SessId, #state{connection_states = ConnectionStates0,
session = Session}),
next_state(hello, abbreviated, Record, State);
#alert{} = Alert ->
- handle_own_alert(Alert, Version, hello, State0),
- {stop, normal, State0}
+ handle_own_alert(Alert, Version, hello, State0)
end.
@@ -1411,8 +1403,7 @@ client_certify_and_key_exchange(#state{negotiated_version = Version} =
next_state(certify, cipher, Record, State)
catch
throw:#alert{} = Alert ->
- handle_own_alert(Alert, Version, certify, State0),
- {stop, normal, State0}
+ handle_own_alert(Alert, Version, certify, State0)
end.
do_client_certify_and_key_exchange(State0) ->
@@ -1637,78 +1628,49 @@ save_verify_data(client, #finished{verify_data = Data}, ConnectionStates, abbrev
save_verify_data(server, #finished{verify_data = Data}, ConnectionStates, abbreviated) ->
ssl_record:set_server_verify_data(current_write, Data, ConnectionStates).
-handle_server_key(#server_key_exchange{params =
- #server_dh_params{dh_p = P,
- dh_g = G,
- dh_y = ServerPublicDhKey},
- signed_params = <<>>},
- #state{key_algorithm = dh_anon} = State) ->
- dh_master_secret(P, G, ServerPublicDhKey, undefined, State);
-
-handle_server_key(
- #server_key_exchange{params =
- #server_dh_params{dh_p = P,
- dh_g = G,
- dh_y = ServerPublicDhKey},
- signed_params = Signed,
- hashsign = HashSign},
- #state{negotiated_version = Version,
- public_key_info = PubKeyInfo,
- connection_states = ConnectionStates} = State) ->
-
- PLen = size(P),
- GLen = size(G),
- YLen = size(ServerPublicDhKey),
- HashAlgo = connection_hash_algo(HashSign, State),
+handle_server_key(#server_key_exchange{exchange_keys = Keys},
+ #state{key_algorithm = KeyAlg,
+ negotiated_version = Version} = State) ->
+ Params = ssl_handshake:decode_server_key(Keys, KeyAlg, Version),
+ HashSign = connection_hashsign(Params#server_key_params.hashsign, State),
+ case HashSign of
+ {_, anon} ->
+ server_master_secret(Params#server_key_params.params, State);
+ _ ->
+ verify_server_key(Params, HashSign, State)
+ end.
- ConnectionState =
+verify_server_key(#server_key_params{params = Params,
+ params_bin = EncParams,
+ signature = Signature},
+ HashSign = {HashAlgo, _},
+ #state{negotiated_version = Version,
+ public_key_info = PubKeyInfo,
+ connection_states = ConnectionStates} = State) ->
+ ConnectionState =
ssl_record:pending_connection_state(ConnectionStates, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
Hash = ssl_handshake:server_key_exchange_hash(HashAlgo,
- <<ClientRandom/binary,
- ServerRandom/binary,
- ?UINT16(PLen), P/binary,
- ?UINT16(GLen), G/binary,
- ?UINT16(YLen),
- ServerPublicDhKey/binary>>),
-
- case verify_dh_params(Version, Signed, Hash, HashAlgo, PubKeyInfo) of
+ <<ClientRandom/binary,
+ ServerRandom/binary,
+ EncParams/binary>>),
+ case ssl_handshake:verify_signature(Version, Hash, HashSign, Signature, PubKeyInfo) of
true ->
- dh_master_secret(P, G, ServerPublicDhKey, undefined, State);
+ server_master_secret(Params, State);
false ->
?ALERT_REC(?FATAL, ?DECRYPT_ERROR)
end.
-verify_dh_params({3, Minor}, Signed, Hashes, HashAlgo, {?rsaEncryption, PubKey, _PubKeyParams})
- when Minor >= 3 ->
- public_key:verify({digest, Hashes}, HashAlgo, Signed, PubKey);
-verify_dh_params(_Version, Signed, Hashes, _HashAlgo, {?rsaEncryption, PubKey, _PubKeyParams}) ->
- case public_key:decrypt_public(Signed, PubKey,
- [{rsa_pad, rsa_pkcs1_padding}]) of
- Hashes ->
- true;
- _ ->
- false
- end;
-verify_dh_params(_Version, Signed, Hash, HashAlgo, {?'id-dsa', PublicKey, PublicKeyParams}) ->
- public_key:verify({digest, Hash}, HashAlgo, Signed, {PublicKey, PublicKeyParams}).
+server_master_secret(#server_dh_params{dh_p = P, dh_g = G, dh_y = ServerPublicDhKey},
+ State) ->
+ dh_master_secret(P, G, ServerPublicDhKey, undefined, State).
-dh_master_secret(Prime, Base, PublicDhKey, undefined, State) ->
- PMpint = mpint_binary(Prime),
- GMpint = mpint_binary(Base),
- Keys = {_, PrivateDhKey} =
- crypto:dh_generate_key([PMpint,GMpint]),
- dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State#state{diffie_hellman_keys = Keys});
-
-dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey,
- #state{session = Session,
- negotiated_version = Version, role = Role,
- connection_states = ConnectionStates0} = State) ->
- PremasterSecret =
- crypto:dh_compute_key(mpint_binary(PublicDhKey), PrivateDhKey,
- [PMpint, GMpint]),
+master_from_premaster_secret(PremasterSecret,
+ #state{session = Session,
+ negotiated_version = Version, role = Role,
+ connection_states = ConnectionStates0} = State) ->
case ssl_handshake:master_secret(Version, PremasterSecret,
ConnectionStates0, Role) of
{MasterSecret, ConnectionStates} ->
@@ -1720,6 +1682,19 @@ dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey,
Alert
end.
+dh_master_secret(Prime, Base, PublicDhKey, undefined, State) ->
+ PMpint = mpint_binary(Prime),
+ GMpint = mpint_binary(Base),
+ Keys = {_, PrivateDhKey} =
+ crypto:dh_generate_key([PMpint,GMpint]),
+ dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State#state{diffie_hellman_keys = Keys});
+
+dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State) ->
+ PremasterSecret =
+ crypto:dh_compute_key(mpint_binary(PublicDhKey), PrivateDhKey,
+ [PMpint, GMpint]),
+ master_from_premaster_secret(PremasterSecret, State).
+
cipher_role(client, Data, Session, #state{connection_states = ConnectionStates0} = State) ->
ConnectionStates = ssl_record:set_server_verify_data(current_both, Data, ConnectionStates0),
next_state_connection(cipher, ack_connection(State#state{session = Session,
@@ -1787,10 +1762,12 @@ passive_receive(State0 = #state{user_data_buffer = Buffer}, StateName) ->
end.
read_application_data(Data, #state{user_application = {_Mon, Pid},
- socket_options = SOpts,
- bytes_to_read = BytesToRead,
- start_or_recv_from = RecvFrom,
- user_data_buffer = Buffer0} = State0) ->
+ socket = Socket,
+ socket_options = SOpts,
+ bytes_to_read = BytesToRead,
+ start_or_recv_from = RecvFrom,
+ timer = Timer,
+ user_data_buffer = Buffer0} = State0) ->
Buffer1 = if
Buffer0 =:= <<>> -> Data;
Data =:= <<>> -> Buffer0;
@@ -1798,10 +1775,12 @@ read_application_data(Data, #state{user_application = {_Mon, Pid},
end,
case get_data(SOpts, BytesToRead, Buffer1) of
{ok, ClientData, Buffer} -> % Send data
- SocketOpt = deliver_app_data(SOpts, ClientData, Pid, RecvFrom),
+ SocketOpt = deliver_app_data(Socket, SOpts, ClientData, Pid, RecvFrom),
+ cancel_timer(Timer),
State = State0#state{user_data_buffer = Buffer,
start_or_recv_from = undefined,
- bytes_to_read = 0,
+ timer = undefined,
+ bytes_to_read = undefined,
socket_options = SocketOpt
},
if
@@ -1814,8 +1793,10 @@ read_application_data(Data, #state{user_application = {_Mon, Pid},
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(SOpts, Buffer1, Pid, RecvFrom),
+ deliver_packet_error(Socket, SOpts, Buffer1, Pid, RecvFrom),
{stop, normal, State0}
end.
@@ -1855,6 +1836,9 @@ is_time_to_renegotiate(_,_) ->
%% 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
@@ -1894,9 +1878,9 @@ decode_packet(Type, Buffer, PacketOpts) ->
%% 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(SOpts = #socket_options{active=Active, packet=Type},
- Data, Pid, From) ->
- send_or_reply(Active, Pid, From, format_reply(SOpts, Data)),
+deliver_app_data(Socket, SOpts = #socket_options{active=Active, packet=Type},
+ Data, Pid, From) ->
+ send_or_reply(Active, Pid, From, format_reply(Socket, SOpts, Data)),
SO = case Data of
{P, _, _, _} when ((P =:= http_request) or (P =:= http_response)),
((Type =:= http) or (Type =:= http_bin)) ->
@@ -1915,31 +1899,31 @@ deliver_app_data(SOpts = #socket_options{active=Active, packet=Type},
SO
end.
-format_reply(#socket_options{active = false, mode = Mode, packet = Packet,
+format_reply(_,#socket_options{active = false, mode = Mode, packet = Packet,
header = Header}, Data) ->
- {ok, format_reply(Mode, Packet, Header, Data)};
-format_reply(#socket_options{active = _, mode = Mode, packet = Packet,
+ {ok, do_format_reply(Mode, Packet, Header, Data)};
+format_reply(Socket, #socket_options{active = _, mode = Mode, packet = Packet,
header = Header}, Data) ->
- {ssl, sslsocket(), format_reply(Mode, Packet, Header, Data)}.
+ {ssl, sslsocket(self(), Socket), do_format_reply(Mode, Packet, Header, Data)}.
-deliver_packet_error(SO= #socket_options{active = Active}, Data, Pid, From) ->
- send_or_reply(Active, Pid, From, format_packet_error(SO, Data)).
+deliver_packet_error(Socket, SO= #socket_options{active = Active}, Data, Pid, From) ->
+ send_or_reply(Active, Pid, From, format_packet_error(Socket, SO, Data)).
-format_packet_error(#socket_options{active = false, mode = Mode}, Data) ->
- {error, {invalid_packet, format_reply(Mode, raw, 0, Data)}};
-format_packet_error(#socket_options{active = _, mode = Mode}, Data) ->
- {ssl_error, sslsocket(), {invalid_packet, format_reply(Mode, raw, 0, Data)}}.
+format_packet_error(_,#socket_options{active = false, mode = Mode}, Data) ->
+ {error, {invalid_packet, do_format_reply(Mode, raw, 0, Data)}};
+format_packet_error(Socket, #socket_options{active = _, mode = Mode}, Data) ->
+ {ssl_error, sslsocket(self(), Socket), {invalid_packet, do_format_reply(Mode, raw, 0, Data)}}.
-format_reply(binary, _, N, Data) when N > 0 -> % Header mode
+do_format_reply(binary, _, N, Data) when N > 0 -> % Header mode
header(N, Data);
-format_reply(binary, _, _, Data) ->
+do_format_reply(binary, _, _, Data) ->
Data;
-format_reply(list, Packet, _, 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;
-format_reply(list, _,_, Data) ->
+do_format_reply(list, _,_, Data) ->
binary_to_list(Data).
header(0, <<>>) ->
@@ -1983,8 +1967,7 @@ handle_tls_handshake(Handle, StateName, #state{tls_packets = [Packet | Packets]}
end.
next_state(Current,_, #alert{} = Alert, #state{negotiated_version = Version} = State) ->
- handle_own_alert(Alert, Version, Current, State),
- {stop, normal, State};
+ handle_own_alert(Alert, Version, Current, State);
next_state(_,Next, no_record, State) ->
{next_state, Next, State, get_timeout(State)};
@@ -2022,8 +2005,7 @@ next_state(Current, Next, #ssl_tls{type = ?HANDSHAKE, fragment = Data},
State = State0#state{tls_packets = Packets, tls_handshake_buffer = Buf},
handle_tls_handshake(Handle, Next, State)
catch throw:#alert{} = Alert ->
- handle_own_alert(Alert, Version, Current, State0),
- {stop, normal, State0}
+ handle_own_alert(Alert, Version, Current, State0)
end;
next_state(_, StateName, #ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, State0) ->
@@ -2162,7 +2144,6 @@ initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions}, User,
tls_record_buffer = <<>>,
tls_cipher_texts = [],
user_application = {Monitor, User},
- bytes_to_read = 0,
user_data_buffer = <<>>,
log_alert = true,
session_cache_cb = SessionCacheCb,
@@ -2171,11 +2152,8 @@ initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions}, User,
send_queue = queue:new()
}.
-sslsocket(Pid) ->
- #sslsocket{pid = Pid, fd = new_ssl}.
-
-sslsocket() ->
- sslsocket(self()).
+sslsocket(Pid, Socket) ->
+ #sslsocket{pid = Pid, fd = Socket}.
get_socket_opts(_,[], _, Acc) ->
{ok, Acc};
@@ -2271,24 +2249,24 @@ handle_alerts([Alert | Alerts], {next_state, StateName, State, _Timeout}) ->
handle_alerts(Alerts, handle_alert(Alert, StateName, State)).
handle_alert(#alert{level = ?FATAL} = Alert, StateName,
- #state{start_or_recv_from = From, host = Host, port = Port, session = Session,
- user_application = {_Mon, Pid},
+ #state{socket = Socket, start_or_recv_from = From, host = Host,
+ port = Port, session = Session, user_application = {_Mon, Pid},
log_alert = Log, role = Role, socket_options = Opts} = State) ->
invalidate_session(Role, Host, Port, Session),
log_alert(Log, StateName, Alert),
- alert_user(StateName, Opts, Pid, From, Alert, Role),
+ alert_user(Socket, StateName, Opts, Pid, From, Alert, Role),
{stop, normal, State};
handle_alert(#alert{level = ?WARNING, description = ?CLOSE_NOTIFY} = Alert,
StateName, State) ->
handle_normal_shutdown(Alert, StateName, State),
- {stop, normal, State};
+ {stop, {shutdown, peer_close}, State};
handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert, StateName,
#state{log_alert = Log, renegotiation = {true, internal}} = State) ->
log_alert(Log, StateName, Alert),
handle_normal_shutdown(Alert, StateName, State),
- {stop, normal, State};
+ {stop, {shutdown, peer_close}, State};
handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert, StateName,
#state{log_alert = Log, renegotiation = {true, From}} = State0) ->
@@ -2303,28 +2281,28 @@ handle_alert(#alert{level = ?WARNING, description = ?USER_CANCELED} = Alert, Sta
{Record, State} = next_record(State0),
next_state(StateName, StateName, Record, State).
-alert_user(connection, Opts, Pid, From, Alert, Role) ->
- alert_user(Opts#socket_options.active, Pid, From, Alert, Role);
-alert_user(_, _, _, From, Alert, Role) ->
- alert_user(From, Alert, Role).
+alert_user(Socket, connection, Opts, Pid, From, Alert, Role) ->
+ alert_user(Socket, Opts#socket_options.active, Pid, From, Alert, Role);
+alert_user(Socket,_, _, _, From, Alert, Role) ->
+ alert_user(Socket, From, Alert, Role).
-alert_user(From, Alert, Role) ->
- alert_user(false, no_pid, From, Alert, Role).
+alert_user(Socket, From, Alert, Role) ->
+ alert_user(Socket, false, no_pid, From, Alert, Role).
-alert_user(false = Active, Pid, From, Alert, Role) ->
+alert_user(_Socket, false = Active, Pid, From, Alert, Role) ->
%% 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(Active, Pid, From, Alert, Role) ->
+alert_user(Socket, Active, Pid, From, Alert, Role) ->
case ssl_alert:reason_code(Alert, Role) of
closed ->
send_or_reply(Active, Pid, From,
- {ssl_closed, sslsocket()});
+ {ssl_closed, sslsocket(self(), Socket)});
ReasonCode ->
send_or_reply(Active, Pid, From,
- {ssl_error, sslsocket(), ReasonCode})
+ {ssl_error, sslsocket(self(), Socket), ReasonCode})
end.
log_alert(true, Info, Alert) ->
@@ -2341,8 +2319,8 @@ handle_own_alert(Alert, Version, StateName,
try %% Try to tell the other side
{BinMsg, _} =
encode_alert(Alert, Version, ConnectionStates),
- linux_workaround_transport_delivery_problems(Alert, Socket),
- Transport:send(Socket, BinMsg)
+ Transport:send(Socket, BinMsg),
+ workaround_transport_delivery_problems(Socket, Transport)
catch _:_ -> %% Can crash if we are in a uninitialized state
ignore
end,
@@ -2351,20 +2329,23 @@ handle_own_alert(Alert, Version, StateName,
handle_normal_shutdown(Alert,StateName, State)
catch _:_ ->
ok
- end.
+ end,
+ {stop, {shutdown, own_alert}, State}.
-handle_normal_shutdown(Alert, _, #state{start_or_recv_from = StartFrom, role = Role, renegotiation = {false, first}}) ->
- alert_user(StartFrom, Alert, Role);
+handle_normal_shutdown(Alert, _, #state{socket = Socket,
+ start_or_recv_from = StartFrom,
+ role = Role, renegotiation = {false, first}}) ->
+ alert_user(Socket, StartFrom, Alert, Role);
-handle_normal_shutdown(Alert, StateName, #state{socket_options = Opts,
+handle_normal_shutdown(Alert, StateName, #state{socket = Socket,
+ socket_options = Opts,
user_application = {_Mon, Pid},
start_or_recv_from = RecvFrom, role = Role}) ->
- alert_user(StateName, Opts, Pid, RecvFrom, Alert, Role).
+ alert_user(Socket, StateName, Opts, Pid, RecvFrom, Alert, Role).
handle_unexpected_message(Msg, Info, #state{negotiated_version = Version} = State) ->
Alert = ?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE),
- handle_own_alert(Alert, Version, {Info, Msg}, State),
- {stop, normal, State}.
+ handle_own_alert(Alert, Version, {Info, Msg}, State).
make_premaster_secret({MajVer, MinVer}, rsa) ->
Rand = ssl:random_bytes(?NUM_OF_PREMASTERSECRET_BYTES-2),
@@ -2385,9 +2366,11 @@ ack_connection(#state{renegotiation = {true, From}} = State) ->
gen_fsm:reply(From, ok),
State#state{renegotiation = undefined};
ack_connection(#state{renegotiation = {false, first},
- start_or_recv_from = StartFrom} = State) when StartFrom =/= undefined ->
+ start_or_recv_from = StartFrom,
+ timer = Timer} = State) when StartFrom =/= undefined ->
gen_fsm:reply(StartFrom, connected),
- State#state{renegotiation = undefined, start_or_recv_from = undefined};
+ cancel_timer(Timer),
+ State#state{renegotiation = undefined, start_or_recv_from = undefined, timer = undefined};
ack_connection(State) ->
State.
@@ -2422,36 +2405,35 @@ notify_renegotiater({true, From}) when not is_atom(From) ->
notify_renegotiater(_) ->
ok.
-terminate_alert(Reason, Version, ConnectionStates) when Reason == normal; Reason == shutdown;
+terminate_alert(Reason, Version, ConnectionStates) when Reason == normal;
Reason == user_close ->
{BinAlert, _} = encode_alert(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY),
Version, ConnectionStates),
BinAlert;
+terminate_alert({shutdown, _}, Version, ConnectionStates) ->
+ {BinAlert, _} = encode_alert(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY),
+ Version, ConnectionStates),
+ BinAlert;
+
terminate_alert(_, Version, ConnectionStates) ->
{BinAlert, _} = encode_alert(?ALERT_REC(?FATAL, ?INTERNAL_ERROR),
Version, ConnectionStates),
BinAlert.
-workaround_transport_delivery_problems(_,_, user_close) ->
- ok;
-workaround_transport_delivery_problems(Socket, Transport, _) ->
+workaround_transport_delivery_problems(Socket, gen_tcp = Transport) ->
%% Standard trick to try to make sure all
- %% data sent to to tcp port is really sent
- %% before tcp port is closed so that the peer will
- %% get a correct error message.
+ %% data sent to the tcp port is really delivered to the
+ %% peer application before tcp port is closed so that the peer will
+ %% get the correct TLS alert message and not only a transport close.
inet:setopts(Socket, [{active, false}]),
Transport:shutdown(Socket, write),
- Transport:recv(Socket, 0).
-
-linux_workaround_transport_delivery_problems(#alert{level = ?FATAL}, Socket) ->
- case os:type() of
- {unix, linux} ->
- inet:setopts(Socket, [{nodelay, true}]);
- _ ->
- ok
- end;
-linux_workaround_transport_delivery_problems(_, _) ->
- ok.
+ %% Will return when other side has closed or after 30 s
+ %% e.g. we do not want to hang if something goes wrong
+ %% with the network but we want to maximise the odds that
+ %% peer application gets all data sent on the tcp connection.
+ Transport:recv(Socket, 0, 30000);
+workaround_transport_delivery_problems(Socket, Transport) ->
+ Transport:close(Socket).
get_timeout(#state{ssl_options=#ssl_options{hibernate_after = undefined}}) ->
infinity;
@@ -2487,10 +2469,10 @@ get_pending_connection_state_prf(CStates, Direction) ->
CS = ssl_record:pending_connection_state(CStates, Direction),
CS#connection_state.security_parameters#security_parameters.prf_algorithm.
-connection_hash_algo({HashAlgo, _}, _State) ->
- HashAlgo;
-connection_hash_algo(_, #state{hashsign_algorithm = {HashAlgo, _}}) ->
- HashAlgo.
+connection_hashsign(HashSign = {_, _}, _State) ->
+ HashSign;
+connection_hashsign(_, #state{hashsign_algorithm = HashSign}) ->
+ HashSign.
%% RFC 5246, Sect. 7.4.1.4.1. Signature Algorithms
%% If the client does not send the signature_algorithms extension, the
@@ -2524,3 +2506,31 @@ default_hashsign(_Version, KeyExchange)
default_hashsign(_Version, KeyExchange)
when KeyExchange == dh_anon ->
{null, anon}.
+
+start_or_recv_cancel_timer(infinity, _RecvFrom) ->
+ undefined;
+start_or_recv_cancel_timer(Timeout, RecvFrom) ->
+ erlang:send_after(Timeout, self(), {cancel_start_or_recv, RecvFrom}).
+
+cancel_timer(undefined) ->
+ ok;
+cancel_timer(Timer) ->
+ erlang:cancel_timer(Timer).
+
+handle_unrecv_data(StateName, #state{socket = Socket, transport_cb = Transport} = State) ->
+ inet:setopts(Socket, [{active, false}]),
+ case Transport:recv(Socket, 0, 0) of
+ {error, closed} ->
+ ok;
+ {ok, Data} ->
+ handle_close_alert(Data, StateName, State)
+ end.
+
+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.
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index fa1784714f..1929370991 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -32,10 +32,10 @@
-export([master_secret/4, client_hello/8, server_hello/5, hello/4,
hello_request/0, certify/7, certificate/4,
- client_certificate_verify/6, certificate_verify/6,
+ client_certificate_verify/6, certificate_verify/6, verify_signature/5,
certificate_request/3, key_exchange/3, server_key_exchange_hash/2,
finished/5, verify_connection/6, get_tls_handshake/3,
- decode_client_key/3, server_hello_done/0,
+ decode_client_key/3, decode_server_key/3, server_hello_done/0,
encode_handshake/2, init_handshake_history/0, update_handshake_history/2,
decrypt_premaster_secret/2, prf/5, next_protocol/1]).
@@ -320,25 +320,36 @@ client_certificate_verify(OwnCert, MasterSecret, Version,
%%
%% Description: Checks that the certificate_verify message is valid.
%%--------------------------------------------------------------------
-certificate_verify(Signature, {?'rsaEncryption', PublicKey, _}, Version,
- {HashAlgo, _SignAlgo}, MasterSecret, {_, Handshake}) ->
- Hashes = calc_certificate_verify(Version, HashAlgo, MasterSecret, Handshake),
- case certificate_verify_rsa(Hashes, HashAlgo, Signature, PublicKey, Version) of
+certificate_verify(Signature, PublicKeyInfo, Version,
+ HashSign = {HashAlgo, _}, MasterSecret, {_, Handshake}) ->
+ Hash = calc_certificate_verify(Version, HashAlgo, MasterSecret, Handshake),
+ case verify_signature(Version, Hash, HashSign, Signature, PublicKeyInfo) of
true ->
valid;
_ ->
- ?ALERT_REC(?FATAL, ?BAD_CERTIFICATE)
- end;
-certificate_verify(Signature, {?'id-dsa', PublicKey, PublicKeyParams}, Version,
- {HashAlgo, _SignAlgo}, MasterSecret, {_, Handshake}) ->
- Hashes = calc_certificate_verify(Version, HashAlgo, MasterSecret, Handshake),
- case public_key:verify({digest, Hashes}, sha, Signature, {PublicKey, PublicKeyParams}) of
- true ->
- valid;
- false ->
?ALERT_REC(?FATAL, ?BAD_CERTIFICATE)
end.
+%%--------------------------------------------------------------------
+-spec verify_signature(tls_version(), binary(), {term(), term()}, binary(),
+ public_key_info()) -> true | false.
+%%
+%% Description: Checks that a public_key signature is valid.
+%%--------------------------------------------------------------------
+verify_signature(_Version, _Hash, {_HashAlgo, anon}, _Signature, _) ->
+ true;
+verify_signature({3, Minor}, Hash, {HashAlgo, rsa}, Signature, {?rsaEncryption, PubKey, _PubKeyParams})
+ when Minor >= 3 ->
+ public_key:verify({digest, Hash}, HashAlgo, Signature, PubKey);
+verify_signature(_Version, Hash, _HashAlgo, Signature, {?rsaEncryption, PubKey, _PubKeyParams}) ->
+ case public_key:decrypt_public(Signature, PubKey,
+ [{rsa_pad, rsa_pkcs1_padding}]) of
+ Hash -> true;
+ _ -> false
+ end;
+verify_signature(_Version, Hash, {HashAlgo, dsa}, Signature, {?'id-dsa', PublicKey, PublicKeyParams}) ->
+ public_key:verify({digest, Hash}, HashAlgo, Signature, {PublicKey, PublicKeyParams}).
+
%%--------------------------------------------------------------------
-spec certificate_request(#connection_states{}, db_handle(), certdb_ref()) ->
@@ -382,31 +393,33 @@ key_exchange(client, _Version, {dh, <<?UINT32(Len), PublicKey:Len/binary>>}) ->
key_exchange(server, Version, {dh, {<<?UINT32(Len), PublicKey:Len/binary>>, _},
#'DHParameter'{prime = P, base = G},
- {HashAlgo, SignAlgo}, ClientRandom, ServerRandom, PrivateKey}) ->
+ HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
<<?UINT32(_), PBin/binary>> = crypto:mpint(P),
<<?UINT32(_), GBin/binary>> = crypto:mpint(G),
- PLen = byte_size(PBin),
- GLen = byte_size(GBin),
- YLen = byte_size(PublicKey),
ServerDHParams = #server_dh_params{dh_p = PBin,
dh_g = GBin, dh_y = PublicKey},
+ enc_server_key_exchange(Version, ServerDHParams, HashSign,
+ ClientRandom, ServerRandom, PrivateKey).
+enc_server_key_exchange(Version, Params, {HashAlgo, SignAlgo},
+ ClientRandom, ServerRandom, PrivateKey) ->
+ EncParams = enc_server_key(Params),
case HashAlgo of
null ->
- #server_key_exchange{params = ServerDHParams,
- signed_params = <<>>,
- hashsign = {null, anon}};
+ #server_key_params{params = Params,
+ params_bin = EncParams,
+ hashsign = {null, anon},
+ signature = <<>>};
_ ->
Hash =
server_key_exchange_hash(HashAlgo, <<ClientRandom/binary,
- ServerRandom/binary,
- ?UINT16(PLen), PBin/binary,
- ?UINT16(GLen), GBin/binary,
- ?UINT16(YLen), PublicKey/binary>>),
- Signed = digitally_signed(Version, Hash, HashAlgo, PrivateKey),
- #server_key_exchange{params = ServerDHParams,
- signed_params = Signed,
- hashsign = {HashAlgo, SignAlgo}}
+ ServerRandom/binary,
+ EncParams/binary>>),
+ Signature = digitally_signed(Version, Hash, HashAlgo, PrivateKey),
+ #server_key_params{params = Params,
+ params_bin = EncParams,
+ hashsign = {HashAlgo, SignAlgo},
+ signature = Signature}
end.
%%--------------------------------------------------------------------
@@ -523,6 +536,15 @@ decode_client_key(ClientKey, Type, Version) ->
dec_client_key(ClientKey, key_exchange_alg(Type), Version).
%%--------------------------------------------------------------------
+-spec decode_server_key(binary(), key_algo(), tls_version()) ->
+ #server_key_params{}.
+%%
+%% Description: Decode server_key data and return appropriate type
+%%--------------------------------------------------------------------
+decode_server_key(ServerKey, Type, Version) ->
+ dec_server_key(ServerKey, key_exchange_alg(Type), Version).
+
+%%--------------------------------------------------------------------
-spec init_handshake_history() -> tls_handshake_history().
%%
@@ -975,31 +997,8 @@ dec_hs(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
next_protocol_negotiation = NextProtocolNegotiation};
dec_hs(_Version, ?CERTIFICATE, <<?UINT24(ACLen), ASN1Certs:ACLen/binary>>) ->
#certificate{asn1_certificates = certs_to_list(ASN1Certs)};
-
-dec_hs(_Version, ?SERVER_KEY_EXCHANGE, <<?UINT16(PLen), P:PLen/binary,
- ?UINT16(GLen), G:GLen/binary,
- ?UINT16(YLen), Y:YLen/binary,
- ?UINT16(0)>>) -> %% May happen if key_algorithm is dh_anon
- #server_key_exchange{params = #server_dh_params{dh_p = P,dh_g = G,
- dh_y = Y},
- signed_params = <<>>, hashsign = {null, anon}};
-dec_hs({Major, Minor}, ?SERVER_KEY_EXCHANGE, <<?UINT16(PLen), P:PLen/binary,
- ?UINT16(GLen), G:GLen/binary,
- ?UINT16(YLen), Y:YLen/binary,
- ?BYTE(HashAlgo), ?BYTE(SignAlgo),
- ?UINT16(Len), Sig:Len/binary>>)
- when Major == 3, Minor >= 3 ->
- #server_key_exchange{params = #server_dh_params{dh_p = P,dh_g = G,
- dh_y = Y},
- signed_params = Sig,
- hashsign = {ssl_cipher:hash_algorithm(HashAlgo), ssl_cipher:sign_algorithm(SignAlgo)}};
-dec_hs(_Version, ?SERVER_KEY_EXCHANGE, <<?UINT16(PLen), P:PLen/binary,
- ?UINT16(GLen), G:GLen/binary,
- ?UINT16(YLen), Y:YLen/binary,
- ?UINT16(Len), Sig:Len/binary>>) ->
- #server_key_exchange{params = #server_dh_params{dh_p = P,dh_g = G,
- dh_y = Y},
- signed_params = Sig, hashsign = undefined};
+dec_hs(_Version, ?SERVER_KEY_EXCHANGE, Keys) ->
+ #server_key_exchange{exchange_keys = Keys};
dec_hs({Major, Minor}, ?CERTIFICATE_REQUEST,
<<?BYTE(CertTypesLen), CertTypes:CertTypesLen/binary,
?UINT16(HashSignsLen), HashSigns:HashSignsLen/binary,
@@ -1039,6 +1038,42 @@ dec_client_key(<<?UINT16(DH_YLen), DH_Y:DH_YLen/binary>>,
?KEY_EXCHANGE_DIFFIE_HELLMAN, _) ->
#client_diffie_hellman_public{dh_public = DH_Y}.
+dec_ske_params(Len, Keys, Version) ->
+ <<Params:Len/bytes, Signature/binary>> = Keys,
+ dec_ske_signature(Params, Signature, Version).
+
+dec_ske_signature(Params, <<?BYTE(HashAlgo), ?BYTE(SignAlgo),
+ ?UINT16(0)>>, {Major, Minor})
+ when Major == 3, Minor >= 3 ->
+ HashSign = {ssl_cipher:hash_algorithm(HashAlgo), ssl_cipher:sign_algorithm(SignAlgo)},
+ {Params, HashSign, <<>>};
+dec_ske_signature(Params, <<?BYTE(HashAlgo), ?BYTE(SignAlgo),
+ ?UINT16(Len), Signature:Len/binary>>, {Major, Minor})
+ when Major == 3, Minor >= 3 ->
+ HashSign = {ssl_cipher:hash_algorithm(HashAlgo), ssl_cipher:sign_algorithm(SignAlgo)},
+ {Params, HashSign, Signature};
+dec_ske_signature(Params, <<>>, _) ->
+ {Params, {null, anon}, <<>>};
+dec_ske_signature(Params, <<?UINT16(0)>>, _) ->
+ {Params, {null, anon}, <<>>};
+dec_ske_signature(Params, <<?UINT16(Len), Signature:Len/binary>>, _) ->
+ {Params, undefined, Signature};
+dec_ske_signature(_, _, _) ->
+ throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)).
+
+dec_server_key(<<?UINT16(PLen), P:PLen/binary,
+ ?UINT16(GLen), G:GLen/binary,
+ ?UINT16(YLen), Y:YLen/binary, _/binary>> = KeyStruct,
+ ?KEY_EXCHANGE_DIFFIE_HELLMAN, Version) ->
+ Params = #server_dh_params{dh_p = P, dh_g = G, dh_y = Y},
+ {BinMsg, HashSign, Signature} = dec_ske_params(PLen + GLen + YLen + 6, KeyStruct, Version),
+ #server_key_params{params = Params,
+ params_bin = BinMsg,
+ hashsign = HashSign,
+ signature = Signature};
+dec_server_key(_, _, _) ->
+ throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)).
+
dec_hello_extensions(<<>>) ->
[];
dec_hello_extensions(<<?UINT16(ExtLen), Extensions:ExtLen/binary>>) ->
@@ -1156,18 +1191,12 @@ enc_hs(#certificate{asn1_certificates = ASN1CertList}, _Version) ->
ASN1Certs = certs_from_list(ASN1CertList),
ACLen = erlang:iolist_size(ASN1Certs),
{?CERTIFICATE, <<?UINT24(ACLen), ASN1Certs:ACLen/binary>>};
-enc_hs(#server_key_exchange{params = #server_dh_params{
- dh_p = P, dh_g = G, dh_y = Y},
- signed_params = SignedParams, hashsign = HashSign}, Version) ->
- PLen = byte_size(P),
- GLen = byte_size(G),
- YLen = byte_size(Y),
- Signature = enc_sign(HashSign, SignedParams, Version),
- {?SERVER_KEY_EXCHANGE, <<?UINT16(PLen), P/binary,
- ?UINT16(GLen), G/binary,
- ?UINT16(YLen), Y/binary,
- Signature/binary>>
- };
+enc_hs(#server_key_exchange{exchange_keys = Keys}, _Version) ->
+ {?SERVER_KEY_EXCHANGE, Keys};
+enc_hs(#server_key_params{params_bin = Keys, hashsign = HashSign,
+ signature = Signature}, Version) ->
+ EncSign = enc_sign(HashSign, Signature, Version),
+ {?SERVER_KEY_EXCHANGE, <<Keys/binary, EncSign/binary>>};
enc_hs(#certificate_request{certificate_types = CertTypes,
hashsign_algorithms = #hash_sign_algos{hash_sign_algos = HashSignAlgos},
certificate_authorities = CertAuths},
@@ -1211,6 +1240,14 @@ enc_cke(#client_diffie_hellman_public{dh_public = DHPublic}, _) ->
Len = byte_size(DHPublic),
<<?UINT16(Len), DHPublic/binary>>.
+enc_server_key(#server_dh_params{dh_p = P, dh_g = G, dh_y = Y}) ->
+ PLen = byte_size(P),
+ GLen = byte_size(G),
+ YLen = byte_size(Y),
+ <<?UINT16(PLen), P/binary, ?UINT16(GLen), G/binary, ?UINT16(YLen), Y/binary>>.
+
+enc_sign({_, anon}, _Sign, _Version) ->
+ <<>>;
enc_sign({HashAlg, SignAlg}, Signature, _Version = {Major, Minor})
when Major == 3, Minor >= 3->
SignLen = byte_size(Signature),
@@ -1328,8 +1365,8 @@ certificate_authorities_from_db(CertDbHandle, CertDbRef) ->
digitally_signed({3, Minor}, Hash, HashAlgo, Key) when Minor >= 3 ->
public_key:sign({digest, Hash}, HashAlgo, Key);
-digitally_signed(_Version, Hash, _HashAlgo, #'DSAPrivateKey'{} = Key) ->
- public_key:sign({digest, Hash}, sha, Key);
+digitally_signed(_Version, Hash, HashAlgo, #'DSAPrivateKey'{} = Key) ->
+ public_key:sign({digest, Hash}, HashAlgo, Key);
digitally_signed(_Version, Hash, _HashAlgo, #'RSAPrivateKey'{} = Key) ->
public_key:encrypt_private(Hash, Key,
[{rsa_pad, rsa_pkcs1_padding}]).
@@ -1378,19 +1415,6 @@ apply_user_fun(Fun, OtpCert, ExtensionOrError, UserState0, SslState) ->
{unknown, {SslState, UserState}}
end.
-certificate_verify_rsa(Hashes, sha, Signature, PublicKey, {Major, Minor})
- when Major == 3, Minor >= 3 ->
- public_key:verify({digest, Hashes}, sha, Signature, PublicKey);
-certificate_verify_rsa(Hashes, HashAlgo, Signature, PublicKey, {Major, Minor})
- when Major == 3, Minor >= 3 ->
- public_key:verify({digest, Hashes}, HashAlgo, Signature, PublicKey);
-certificate_verify_rsa(Hashes, _HashAlgo, Signature, PublicKey, _Version) ->
- case public_key:decrypt_public(Signature, PublicKey,
- [{rsa_pad, rsa_pkcs1_padding}]) of
- Hashes -> true;
- _ -> false
- end.
-
-define(TLSEXT_SIGALG_RSA(MD), {MD, rsa}).
-define(TLSEXT_SIGALG_DSA(MD), {MD, dsa}).
@@ -1401,6 +1425,7 @@ default_hash_signs() ->
[?TLSEXT_SIGALG(sha512),
?TLSEXT_SIGALG(sha384),
?TLSEXT_SIGALG(sha256),
+ ?TLSEXT_SIGALG(sha224),
?TLSEXT_SIGALG(sha),
?TLSEXT_SIGALG_DSA(sha),
?TLSEXT_SIGALG_RSA(md5)]}.
diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl
index 9af6511d68..2414d5b666 100644
--- a/lib/ssl/src/ssl_handshake.hrl
+++ b/lib/ssl/src/ssl_handshake.hrl
@@ -141,9 +141,14 @@
}).
-record(server_key_exchange, {
+ exchange_keys
+ }).
+
+-record(server_key_params, {
params, %% #server_rsa_params{} | #server_dh_params{}
- signed_params, %% #signature{}
- hashsign %% term(atom(), atom())
+ params_bin,
+ hashsign, %% term(atom(), atom())
+ signature %% #signature{}
}).
%% enum { anonymous, rsa, dsa } SignatureAlgorithm;
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index a5db2dcee7..ed0dc34adf 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -69,8 +69,8 @@
-define(TRUE, 0).
-define(FALSE, 1).
--define(DEFAULT_SUPPORTED_VERSIONS, [tlsv1, sslv3]). %% Add 'tlsv1.1' in R16
-define(ALL_SUPPORTED_VERSIONS, ['tlsv1.2', 'tlsv1.1', tlsv1, sslv3]).
+-define(MIN_SUPPORTED_VERSIONS, ['tlsv1.1', tlsv1, sslv3]).
-record(ssl_options, {
versions, % 'tlsv1.2' | 'tlsv1.1' | tlsv1 | sslv3
diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl
index 0cf4f2ce33..14fba72d86 100644
--- a/lib/ssl/src/ssl_manager.erl
+++ b/lib/ssl/src/ssl_manager.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -24,8 +24,6 @@
-module(ssl_manager).
-behaviour(gen_server).
--include("ssl_internal.hrl").
-
%% Internal application API
-export([start_link/1, start_link_dist/1,
connection_init/2, cache_pem_file/2,
@@ -144,8 +142,14 @@ lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer) ->
new_session_id(Port) ->
call({new_session_id, Port}).
+%%--------------------------------------------------------------------
+-spec clean_cert_db(reference(), binary()) -> term().
+%%
+%% Description: Send clean request of cert db to ssl_manager process should
+%% be called by ssl-connection processes.
+%%--------------------------------------------------------------------
clean_cert_db(Ref, File) ->
- erlang:send_after(?CLEAN_CERT_DB, self(), {clean_cert_db, Ref, File}).
+ erlang:send_after(?CLEAN_CERT_DB, get(ssl_manager), {clean_cert_db, Ref, File}).
%%--------------------------------------------------------------------
-spec register_session(inet:port_number(), #session{}) -> ok.
@@ -322,19 +326,12 @@ handle_info(clear_pem_cache, #state{certificate_db = [_,_,PemChace]} = State) ->
handle_info({clean_cert_db, Ref, File},
#state{certificate_db = [CertDb,RefDb, PemCache]} = State) ->
- case ssl_certificate_db:ref_count(Ref, RefDb, 0) of
- 0 ->
- MD5 = crypto:md5(File),
- case ssl_certificate_db:lookup_cached_pem(PemCache, MD5) of
- [{Content, Ref}] ->
- ssl_certificate_db:insert(MD5, Content, PemCache);
- undefined ->
- ok
- end,
- ssl_certificate_db:remove(Ref, RefDb),
- ssl_certificate_db:remove_trusted_certs(Ref, CertDb);
+
+ case ssl_certificate_db:lookup(Ref, RefDb) of
+ undefined -> %% Alredy cleaned
+ ok;
_ ->
- ok
+ clean_cert_db(Ref, CertDb, RefDb, PemCache, File)
end,
{noreply, State};
@@ -466,3 +463,19 @@ new_id(Port, Tries, Cache, CacheCb) ->
_ ->
new_id(Port, Tries - 1, Cache, CacheCb)
end.
+
+clean_cert_db(Ref, CertDb, RefDb, PemCache, File) ->
+ case ssl_certificate_db:ref_count(Ref, RefDb, 0) of
+ 0 ->
+ MD5 = crypto:md5(File),
+ case ssl_certificate_db:lookup_cached_pem(PemCache, MD5) of
+ [{Content, Ref}] ->
+ ssl_certificate_db:insert(MD5, Content, PemCache);
+ _ ->
+ ok
+ end,
+ ssl_certificate_db:remove(Ref, RefDb),
+ ssl_certificate_db:remove_trusted_certs(Ref, CertDb);
+ _ ->
+ ok
+ end.
diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl
index 8e93ce4634..173b9611c6 100644
--- a/lib/ssl/src/ssl_record.erl
+++ b/lib/ssl/src/ssl_record.erl
@@ -463,10 +463,9 @@ supported_protocol_versions() ->
supported_protocol_versions([]) ->
Vsns = case sufficient_tlsv1_2_crypto_support() of
true ->
- %%?ALL_SUPPORTED_VERSIONS; %% Add TlS-1.2 as default in R16
- ?DEFAULT_SUPPORTED_VERSIONS;
+ ?ALL_SUPPORTED_VERSIONS;
false ->
- ?DEFAULT_SUPPORTED_VERSIONS
+ ?MIN_SUPPORTED_VERSIONS
end,
application:set_env(ssl, protocol_version, Vsns),
Vsns;
diff --git a/lib/ssl/src/ssl_session.erl b/lib/ssl/src/ssl_session.erl
index 2ad422fc03..a24b2d9444 100644
--- a/lib/ssl/src/ssl_session.erl
+++ b/lib/ssl/src/ssl_session.erl
@@ -72,15 +72,12 @@ valid_session(#session{time_stamp = TimeStamp}, LifeTime) ->
server_id(Port, <<>>, _SslOpts, _Cert, _, _) ->
{ssl_manager:new_session_id(Port), undefined};
-server_id(Port, SuggestedId,
- #ssl_options{reuse_sessions = ReuseEnabled,
- reuse_session = ReuseFun},
- Cert, Cache, CacheCb) ->
+server_id(Port, SuggestedId, Options, Cert, Cache, CacheCb) ->
LifeTime = case application:get_env(ssl, session_lifetime) of
{ok, Time} when is_integer(Time) -> Time;
_ -> ?'24H_in_sec'
end,
- case is_resumable(SuggestedId, Port, ReuseEnabled,ReuseFun,
+ case is_resumable(SuggestedId, Port, Options,
Cache, CacheCb, LifeTime, Cert)
of
{true, Resumed} ->
@@ -112,9 +109,9 @@ select_session(Sessions, #ssl_options{ciphers = Ciphers}, OwnCert) ->
[[Id, _]|_] -> Id
end.
-is_resumable(_, _, false, _, _, _, _, _) ->
+is_resumable(_, _, #ssl_options{reuse_sessions = false}, _, _, _, _) ->
{false, undefined};
-is_resumable(SuggestedSessionId, Port, true, ReuseFun, Cache,
+is_resumable(SuggestedSessionId, Port, #ssl_options{reuse_session = ReuseFun} = Options, Cache,
CacheCb, SecondLifeTime, OwnCert) ->
case CacheCb:lookup(Cache, {Port, SuggestedSessionId}) of
#session{cipher_suite = CipherSuite,
@@ -125,6 +122,7 @@ is_resumable(SuggestedSessionId, Port, true, ReuseFun, Cache,
case resumable(IsResumable)
andalso (OwnCert == SessionOwnCert)
andalso valid_session(Session, SecondLifeTime)
+ andalso reusable_options(Options, Session)
andalso ReuseFun(SuggestedSessionId, PeerCert,
Compression, CipherSuite)
of
@@ -139,3 +137,9 @@ resumable(new) ->
false;
resumable(IsResumable) ->
IsResumable.
+
+reusable_options(#ssl_options{fail_if_no_peer_cert = true,
+ verify = verify_peer}, Session) ->
+ (Session#session.peer_certificate =/= undefined);
+reusable_options(_,_) ->
+ true.
diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile
index d36dcb588b..847907cde8 100644
--- a/lib/ssl/test/Makefile
+++ b/lib/ssl/test/Makefile
@@ -37,15 +37,16 @@ VSN=$(GS_VSN)
MODULES = \
ssl_test_lib \
ssl_basic_SUITE \
- ssl_handshake_SUITE \
- ssl_packet_SUITE \
ssl_cipher_SUITE \
- ssl_payload_SUITE \
- ssl_to_openssl_SUITE \
- ssl_session_cache_SUITE \
+ ssl_certificate_verify_SUITE\
ssl_dist_SUITE \
+ ssl_handshake_SUITE \
ssl_npn_hello_SUITE \
ssl_npn_handshake_SUITE \
+ ssl_packet_SUITE \
+ ssl_payload_SUITE \
+ ssl_session_cache_SUITE \
+ ssl_to_openssl_SUITE \
make_certs\
erl_make_certs
diff --git a/lib/ssl/test/erl_make_certs.erl b/lib/ssl/test/erl_make_certs.erl
index 254aa6d2f9..d6bdd05d01 100644
--- a/lib/ssl/test/erl_make_certs.erl
+++ b/lib/ssl/test/erl_make_certs.erl
@@ -137,10 +137,10 @@ decode_key(PemBin, Pw) ->
encode_key(Key = #'RSAPrivateKey'{}) ->
{ok, Der} = 'OTP-PUB-KEY':encode('RSAPrivateKey', Key),
- {'RSAPrivateKey', list_to_binary(Der), not_encrypted};
+ {'RSAPrivateKey', Der, not_encrypted};
encode_key(Key = #'DSAPrivateKey'{}) ->
{ok, Der} = 'OTP-PUB-KEY':encode('DSAPrivateKey', Key),
- {'DSAPrivateKey', list_to_binary(Der), not_encrypted}.
+ {'DSAPrivateKey', Der, not_encrypted}.
make_tbs(SubjectKey, Opts) ->
Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))),
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 6cf712fa6f..a313380ece 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-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -41,127 +41,10 @@
-define(RENEGOTIATION_DISABLE_TIME, 12000).
-define(CLEAN_SESSION_DB, 60000).
-%% Test server callback functions
%%--------------------------------------------------------------------
-%% Function: init_per_suite(Config) -> Config
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Initialization before the whole suite
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
-%%--------------------------------------------------------------------
-init_per_suite(Config0) ->
- Dog = ssl_test_lib:timetrap(?LONG_TIMEOUT *2),
- catch crypto:stop(),
- try crypto:start() of
- ok ->
- application:start(public_key),
-
- %% make rsa certs using oppenssl
- Result =
- (catch make_certs:all(?config(data_dir, Config0),
- ?config(priv_dir, Config0))),
- test_server:format("Make certs ~p~n", [Result]),
-
- Config1 = ssl_test_lib:make_dsa_cert(Config0),
- Config = ssl_test_lib:cert_options(Config1),
- [{watchdog, Dog} | Config]
- catch _:_ ->
- {skip, "Crypto did not start"}
- end.
-%%--------------------------------------------------------------------
-%% Function: end_per_suite(Config) -> _
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after the whole suite
+%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
-end_per_suite(_Config) ->
- ssl:stop(),
- application:stop(crypto).
-%%--------------------------------------------------------------------
-%% Function: init_per_testcase(TestCase, Config) -> Config
-%% Case - atom()
-%% Name of the test case that is about to be run.
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%%
-%% Description: Initialization before each test case
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
-%% Description: Initialization before each test case
-%%--------------------------------------------------------------------
-init_per_testcase(no_authority_key_identifier, Config) ->
- %% Clear cach so that root cert will not
- %% be found.
- ssl:clear_pem_cache(),
- Config;
-
-init_per_testcase(protocol_versions, Config) ->
- ssl:stop(),
- application:load(ssl),
- %% For backwards compatibility sslv2 should be filtered out.
- application:set_env(ssl, protocol_version, [sslv2, sslv3, tlsv1]),
- ssl:start(),
- Config;
-
-init_per_testcase(reuse_session_expired, Config0) ->
- Config = lists:keydelete(watchdog, 1, Config0),
- ssl:stop(),
- application:load(ssl),
- application:set_env(ssl, session_lifetime, ?EXPIRE),
- application:set_env(ssl, session_delay_cleanup_time, 500),
- ssl:start(),
- Config;
-
-init_per_testcase(empty_protocol_versions, Config) ->
- ssl:stop(),
- application:load(ssl),
- application:set_env(ssl, protocol_version, []),
- ssl:start(),
- Config;
-
-%% init_per_testcase(different_ca_peer_sign, Config0) ->
-%% ssl_test_lib:make_mix_cert(Config0);
-
-init_per_testcase(_TestCase, Config0) ->
- test_server:format("TLS/SSL version ~p~n ", [ssl_record:supported_protocol_versions()]),
- Config = lists:keydelete(watchdog, 1, Config0),
- Dog = test_server:timetrap(?TIMEOUT),
- [{watchdog, Dog} | Config].
-
-%%--------------------------------------------------------------------
-%% Function: end_per_testcase(TestCase, Config) -> _
-%% Case - atom()
-%% Name of the test case that is about to be run.
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after each test case
-%%--------------------------------------------------------------------
-end_per_testcase(reuse_session_expired, Config) ->
- application:unset_env(ssl, session_lifetime),
- application:unset_env(ssl, session_delay_cleanup_time),
- end_per_testcase(default_action, Config);
-
-end_per_testcase(_TestCase, Config) ->
- Dog = ?config(watchdog, Config),
- case Dog of
- undefined ->
- ok;
- _ ->
- test_server:timetrap_cancel(Dog)
- end.
-
-%%--------------------------------------------------------------------
-%% Function: all(Clause) -> TestCases
-%% Clause - atom() - suite | doc
-%% TestCases - [Case]
-%% Case - atom()
-%% Name of a test case.
-%% Description: Returns a list of all test cases in this test suite
-%%--------------------------------------------------------------------
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
@@ -183,7 +66,6 @@ groups() ->
{'tlsv1', [], all_versions_groups() ++ rizzo_tests()},
{'sslv3', [], all_versions_groups() ++ rizzo_tests()},
{api,[], api_tests()},
- {certificate_verify, [], certificate_verify_tests()},
{session, [], session_tests()},
{renegotiate, [], renegotiate_tests()},
{ciphers, [], cipher_tests()},
@@ -192,36 +74,18 @@ groups() ->
all_versions_groups ()->
[{group, api},
- {group, certificate_verify},
{group, renegotiate},
{group, ciphers},
{group, error_handling_tests}].
-init_per_group(GroupName, Config) ->
- case ssl_test_lib:is_tls_version(GroupName) of
- true ->
- case ssl_test_lib:sufficient_crypto_support(GroupName) of
- true ->
- ssl_test_lib:init_tls_version(GroupName),
- Config;
- false ->
- {skip, "Missing crypto support"}
- end;
- _ ->
- ssl:start(),
- Config
- end.
-
-
-end_per_group(_GroupName, Config) ->
- Config.
basic_tests() ->
[app,
alerts,
send_close,
connect_twice,
- connect_dist
+ connect_dist,
+ clear_pem_cache
].
options_tests() ->
@@ -242,12 +106,14 @@ options_tests() ->
protocol_versions,
empty_protocol_versions,
ipv6,
- reuseaddr].
+ reuseaddr,
+ tcp_reuseaddr].
api_tests() ->
[connection_info,
peername,
peercert,
+ peercert_with_client_cert,
sockname,
versions,
controlling_process,
@@ -257,38 +123,10 @@ api_tests() ->
shutdown_write,
shutdown_both,
shutdown_error,
- hibernate
- ].
-
-certificate_verify_tests() ->
- [server_verify_peer_passive,
- server_verify_peer_active,
- server_verify_peer_active_once,
- server_verify_none_passive,
- server_verify_none_active,
- server_verify_none_active_once,
- server_verify_no_cacerts,
- server_require_peer_cert_ok,
- server_require_peer_cert_fail,
- server_verify_client_once_passive,
- server_verify_client_once_active,
- server_verify_client_once_active_once,
- client_verify_none_passive,
- client_verify_none_active,
- client_verify_none_active_once,
- extended_key_usage_verify_peer,
- extended_key_usage_verify_none,
- invalid_signature_client,
- invalid_signature_server,
- cert_expired,
- client_with_cert_cipher_suites_handshake,
- verify_fun_always_run_client,
- verify_fun_always_run_server,
- unknown_server_ca_fail,
- unknown_server_ca_accept_verify_none,
- unknown_server_ca_accept_verify_peer,
- unknown_server_ca_accept_backwardscompatibility,
- no_authority_key_identifier
+ hibernate,
+ listen_socket,
+ ssl_accept_timeout,
+ ssl_recv_timeout
].
session_tests() ->
@@ -330,19 +168,109 @@ rizzo_tests() ->
[rizzo,
no_rizzo_rc4].
-%% Test cases starts here.
%%--------------------------------------------------------------------
-app(doc) ->
- "Test that the ssl app file is ok";
-app(suite) ->
- [];
+init_per_suite(Config0) ->
+ Dog = ct:timetrap(?LONG_TIMEOUT *2),
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ application:start(public_key),
+
+ %% make rsa certs using oppenssl
+ Result =
+ (catch make_certs:all(?config(data_dir, Config0),
+ ?config(priv_dir, Config0))),
+ ct:print("Make certs ~p~n", [Result]),
+
+ Config1 = ssl_test_lib:make_dsa_cert(Config0),
+ Config = ssl_test_lib:cert_options(Config1),
+ [{watchdog, Dog} | Config]
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto).
+
+%%--------------------------------------------------------------------
+init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:sufficient_crypto_support(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName),
+ Config;
+ false ->
+ {skip, "Missing crypto support"}
+ end;
+ _ ->
+ ssl:start(),
+ Config
+ end.
+
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+init_per_testcase(no_authority_key_identifier, Config) ->
+ %% Clear cach so that root cert will not
+ %% be found.
+ ssl:clear_pem_cache(),
+ Config;
+
+init_per_testcase(protocol_versions, Config) ->
+ ssl:stop(),
+ application:load(ssl),
+ %% For backwards compatibility sslv2 should be filtered out.
+ application:set_env(ssl, protocol_version, [sslv2, sslv3, tlsv1]),
+ ssl:start(),
+ Config;
+
+init_per_testcase(reuse_session_expired, Config0) ->
+ Config = lists:keydelete(watchdog, 1, Config0),
+ ssl:stop(),
+ application:load(ssl),
+ application:set_env(ssl, session_lifetime, ?EXPIRE),
+ application:set_env(ssl, session_delay_cleanup_time, 500),
+ ssl:start(),
+ Config;
+
+init_per_testcase(empty_protocol_versions, Config) ->
+ ssl:stop(),
+ application:load(ssl),
+ application:set_env(ssl, protocol_version, []),
+ ssl:start(),
+ Config;
+
+%% init_per_testcase(different_ca_peer_sign, Config0) ->
+%% ssl_test_lib:make_mix_cert(Config0);
+
+init_per_testcase(_TestCase, Config0) ->
+ ct:print("TLS/SSL version ~p~n ", [ssl_record:supported_protocol_versions()]),
+ Config = lists:keydelete(watchdog, 1, Config0),
+ Dog = ct:timetrap(?TIMEOUT),
+ [{watchdog, Dog} | Config].
+
+end_per_testcase(reuse_session_expired, Config) ->
+ application:unset_env(ssl, session_lifetime),
+ application:unset_env(ssl, session_delay_cleanup_time),
+ end_per_testcase(default_action, Config);
+
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+app() ->
+ [{doc, "Test that the ssl app file is ok"}].
app(Config) when is_list(Config) ->
- ok = test_server:app_test(ssl).
+ ok = ?t:app_test(ssl).
%%--------------------------------------------------------------------
-alerts(doc) ->
- "Test ssl_alert:alert_txt/1";
-alerts(suite) ->
- [];
+alerts() ->
+ [{doc, "Test ssl_alert:alert_txt/1"}].
alerts(Config) when is_list(Config) ->
Descriptions = [?CLOSE_NOTIFY, ?UNEXPECTED_MESSAGE, ?BAD_RECORD_MAC,
?DECRYPTION_FAILED, ?RECORD_OVERFLOW, ?DECOMPRESSION_FAILURE,
@@ -359,14 +287,12 @@ alerts(Config) when is_list(Config) ->
Txt when is_list(Txt) ->
ok;
Other ->
- test_server:fail({unexpected, Other})
+ ct:fail({unexpected, Other})
end
end, Alerts).
%%--------------------------------------------------------------------
-connection_info(doc) ->
- ["Test the API function ssl:connection_info/1"];
-connection_info(suite) ->
- [];
+connection_info() ->
+ [{doc,"Test the API function ssl:connection_info/1"}].
connection_info(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -385,7 +311,7 @@ connection_info(Config) when is_list(Config) ->
[{ciphers,[{rsa,rc4_128,sha,no_export}]} |
ClientOpts]}]),
- test_server:format("Testcase ~p, Client ~p Server ~p ~n",
+ ct:print("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
Version =
@@ -398,58 +324,23 @@ connection_info(Config) when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
-connection_info_result(Socket) ->
- ssl:connection_info(Socket).
-
%%--------------------------------------------------------------------
-
-protocol_versions(doc) ->
- ["Test to set a list of protocol versions in app environment."];
-
-protocol_versions(suite) ->
- [];
+protocol_versions() ->
+ [{doc,"Test to set a list of protocol versions in app environment."}].
protocol_versions(Config) when is_list(Config) ->
basic_test(Config).
-
-empty_protocol_versions(doc) ->
- ["Test to set an empty list of protocol versions in app environment."];
-
-empty_protocol_versions(suite) ->
- [];
+%%--------------------------------------------------------------------
+empty_protocol_versions() ->
+ [{doc,"Test to set an empty list of protocol versions in app environment."}].
empty_protocol_versions(Config) when is_list(Config) ->
basic_test(Config).
-
-basic_test(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, send_recv_result_active, []}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-controlling_process(doc) ->
- ["Test API function controlling_process/2"];
-
-controlling_process(suite) ->
- [];
+controlling_process() ->
+ [{doc,"Test API function controlling_process/2"}].
controlling_process(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -473,7 +364,7 @@ controlling_process(Config) when is_list(Config) ->
ClientMsg]}},
{options, ClientOpts}]),
- test_server:format("Testcase ~p, Client ~p Server ~p ~n",
+ ct:print("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
receive
@@ -492,46 +383,15 @@ controlling_process(Config) when is_list(Config) ->
ok
end;
Unexpected ->
- test_server:fail(Unexpected)
+ ct:fail(Unexpected)
end,
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
-controlling_process_result(Socket, Pid, Msg) ->
- ok = ssl:controlling_process(Socket, Pid),
- %% Make sure other side has evaluated controlling_process
- %% before message is sent
- test_server:sleep(?SLEEP),
- ssl:send(Socket, Msg),
- no_result_msg.
-
-receive_s_rizzo_duong_beast() ->
- receive
- {ssl, _, "erver hello"} ->
- receive
- {ssl, _, "C"} ->
- receive
- {ssl, _, "lient hello"} ->
- ok
- end
- end
- end.
-receive_c_rizzo_duong_beast() ->
- receive
- {ssl, _, "lient hello"} ->
- receive
- {ssl, _, "S"} ->
- receive
- {ssl, _, "erver hello"} ->
- ok
- end
- end
- end.
%%--------------------------------------------------------------------
-controller_dies(doc) ->
- ["Test that the socket is closed after controlling process dies"];
-controller_dies(suite) -> [];
+controller_dies() ->
+ [{doc,"Test that the socket is closed after controlling process dies"}].
controller_dies(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -554,8 +414,8 @@ controller_dies(Config) when is_list(Config) ->
ClientMsg]}},
{options, ClientOpts}]),
- test_server:format("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]),
- test_server:sleep(?SLEEP), %% so that they are connected
+ ct:print("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]),
+ ct:sleep(?SLEEP), %% so that they are connected
process_flag(trap_exit, true),
@@ -572,7 +432,7 @@ controller_dies(Config) when is_list(Config) ->
%% Make sure server finishes and verification
%% and is in coonection state before
%% killing client
- test_server:sleep(?SLEEP),
+ ct:sleep(?SLEEP),
Pid ! {self(), connected, Socket},
receive die_nice -> normal end
end,
@@ -592,13 +452,13 @@ controller_dies(Config) when is_list(Config) ->
Client3 ! die_nice
end,
- test_server:format("Wating on exit ~p~n",[Client3]),
+ ct:print("Wating on exit ~p~n",[Client3]),
receive {'EXIT', Client3, normal} -> ok end,
receive %% Client3 is dead but that doesn't matter, socket should not be closed.
Unexpected ->
- test_server:format("Unexpected ~p~n",[Unexpected]),
- test_server:fail({line, ?LINE-1})
+ ct:print("Unexpected ~p~n",[Unexpected]),
+ ct:fail({line, ?LINE-1})
after 1000 ->
ok
end,
@@ -614,39 +474,17 @@ controller_dies(Config) when is_list(Config) ->
controller_dies_result, [self(),
ClientMsg]}},
{options, [{reuseaddr,true}|ClientOpts]}]),
- test_server:sleep(?SLEEP), %% so that they are connected
+ ct:sleep(?SLEEP), %% so that they are connected
exit(Server, killed),
get_close(Server, ?LINE),
process_flag(trap_exit, false),
ssl_test_lib:close(LastClient).
-controller_dies_result(_Socket, _Pid, _Msg) ->
- receive Result -> Result end.
-
-get_close(Pid, Where) ->
- receive
- {'EXIT', Pid, _Reason} ->
- receive
- {_, {ssl_closed, Socket}} ->
- test_server:format("Socket closed ~p~n",[Socket]);
- Unexpected ->
- test_server:format("Unexpected ~p~n",[Unexpected]),
- test_server:fail({line, ?LINE-1})
- after 5000 ->
- test_server:fail({timeout, {line, ?LINE, Where}})
- end;
- Unexpected ->
- test_server:format("Unexpected ~p~n",[Unexpected]),
- test_server:fail({line, ?LINE-1})
- after 5000 ->
- test_server:fail({timeout, {line, ?LINE, Where}})
- end.
-
%%--------------------------------------------------------------------
-client_closes_socket(doc) ->
- ["Test what happens when client closes socket before handshake is compleated"];
-client_closes_socket(suite) -> [];
+client_closes_socket() ->
+ [{doc,"Test what happens when client closes socket before handshake is compleated"}].
+
client_closes_socket(Config) when is_list(Config) ->
ServerOpts = ?config(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -663,7 +501,7 @@ client_closes_socket(Config) when is_list(Config) ->
[Hostname, Port, TcpOpts]),
%% Make sure that ssl_accept is called before
%% client process ends and closes socket.
- test_server:sleep(?SLEEP)
+ ct:sleep(?SLEEP)
end,
_Client = spawn_link(Connect),
@@ -671,11 +509,8 @@ client_closes_socket(Config) when is_list(Config) ->
ssl_test_lib:check_result(Server, {error,closed}).
%%--------------------------------------------------------------------
-connect_dist(doc) ->
- ["Test a simple connect as is used by distribution"];
-
-connect_dist(suite) ->
- [];
+connect_dist() ->
+ [{doc,"Test a simple connect as is used by distribution"}].
connect_dist(Config) when is_list(Config) ->
ClientOpts0 = ?config(client_kc_opts, Config),
@@ -701,22 +536,36 @@ connect_dist(Config) when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
-connect_dist_s(S) ->
- Msg = term_to_binary({erlang,term}),
- ok = ssl:send(S, Msg).
-
-connect_dist_c(S) ->
- Test = binary_to_list(term_to_binary({erlang,term})),
- {ok, Test} = ssl:recv(S, 0, 10000),
- ok.
+%%--------------------------------------------------------------------
+clear_pem_cache() ->
+ [{doc,"Test that internal reference tabel is cleaned properly even when "
+ " the PEM cache is cleared" }].
+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(5, State),
+ {Server, Client} = basic_verify_test_no_close(Config),
+ 2 = ets:info(FilRefDb, size),
+ ssl:clear_pem_cache(),
+ _ = sys:get_status(whereis(ssl_manager)),
+ {Server1, Client1} = basic_verify_test_no_close(Config),
+ 4 = ets:info(FilRefDb, size),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client),
+ ct:sleep(5000),
+ _ = sys:get_status(whereis(ssl_manager)),
+ 2 = ets:info(FilRefDb, size),
+ ssl_test_lib:close(Server1),
+ ssl_test_lib:close(Client1),
+ ct:sleep(5000),
+ _ = sys:get_status(whereis(ssl_manager)),
+ 0 = ets:info(FilRefDb, size).
%%--------------------------------------------------------------------
-peername(doc) ->
- ["Test API function peername/1"];
-
-peername(suite) ->
- [];
+peername() ->
+ [{doc,"Test API function peername/1"}].
peername(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -739,7 +588,7 @@ peername(Config) when is_list(Config) ->
ServerMsg = {ok, {ClientIp, ClientPort}},
ClientMsg = {ok, {ServerIp, Port}},
- test_server:format("Testcase ~p, Client ~p Server ~p ~n",
+ ct:print("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
@@ -747,14 +596,9 @@ peername(Config) when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
-peername_result(S) ->
- ssl:peername(S).
-
%%--------------------------------------------------------------------
-peercert(doc) ->
- [""];
-peercert(suite) ->
- [];
+peercert() ->
+ [{doc,"Test API function peercert/1"}].
peercert(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -777,7 +621,7 @@ peercert(Config) when is_list(Config) ->
ServerMsg = {error, no_peercert},
ClientMsg = {ok, BinCert},
- test_server:format("Testcase ~p, Client ~p Server ~p ~n",
+ ct:print("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
@@ -787,14 +631,45 @@ peercert(Config) when is_list(Config) ->
peercert_result(Socket) ->
ssl:peercert(Socket).
-
%%--------------------------------------------------------------------
-sockname(doc) ->
- ["Test API function sockname/1"];
-sockname(suite) ->
- [];
+peercert_with_client_cert() ->
+ [{doc,"Test API function peercert/1"}].
+peercert_with_client_cert(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_dsa_opts, Config),
+ ServerOpts = ?config(server_dsa_verify_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, peercert_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, peercert_result, []}},
+ {options, ClientOpts}]),
+
+ ServerCertFile = proplists:get_value(certfile, ServerOpts),
+ [{'Certificate', ServerBinCert, _}]= ssl_test_lib:pem_to_der(ServerCertFile),
+ ClientCertFile = proplists:get_value(certfile, ClientOpts),
+ [{'Certificate', ClientBinCert, _}]= ssl_test_lib:pem_to_der(ClientCertFile),
+
+ ServerMsg = {ok, ClientBinCert},
+ ClientMsg = {ok, ServerBinCert},
+
+ ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+sockname() ->
+ [{doc,"Test API function sockname/1"}].
sockname(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -816,7 +691,7 @@ sockname(Config) when is_list(Config) ->
ServerMsg = {ok, {ServerIp, Port}},
ClientMsg = {ok, {ClientIp, ClientPort}},
- test_server:format("Testcase ~p, Client ~p Server ~p ~n",
+ ct:print("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
@@ -828,11 +703,8 @@ sockname_result(S) ->
ssl:sockname(S).
%%--------------------------------------------------------------------
-cipher_suites(doc) ->
- ["Test API function cipher_suites/0"];
-
-cipher_suites(suite) ->
- [];
+cipher_suites() ->
+ [{doc,"Test API function cipher_suites/0"}].
cipher_suites(Config) when is_list(Config) ->
MandatoryCipherSuite = {rsa,'3des_ede_cbc',sha},
@@ -842,11 +714,8 @@ cipher_suites(Config) when is_list(Config) ->
[_|_] =ssl:cipher_suites(openssl).
%%--------------------------------------------------------------------
-socket_options(doc) ->
- ["Test API function getopts/2 and setopts/2"];
-
-socket_options(suite) ->
- [];
+socket_options() ->
+ [{doc,"Test API function getopts/2 and setopts/2"}].
socket_options(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -895,16 +764,13 @@ socket_options_result(Socket, Options, DefaultValues, NewOptions, NewValues) ->
ssl:setopts(Socket, [{nodelay, true}]),
{ok,[{nodelay, true}]} = ssl:getopts(Socket, [nodelay]),
{ok, All} = ssl:getopts(Socket, []),
- test_server:format("All opts ~p~n", [All]),
+ ct:print("All opts ~p~n", [All]),
ok.
%%--------------------------------------------------------------------
-invalid_inet_get_option(doc) ->
- ["Test handling of invalid inet options in getopts"];
-
-invalid_inet_get_option(suite) ->
- [];
+invalid_inet_get_option() ->
+ [{doc,"Test handling of invalid inet options in getopts"}].
invalid_inet_get_option(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -921,24 +787,16 @@ invalid_inet_get_option(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
- test_server:format("Testcase ~p, Client ~p Server ~p ~n",
+ ct:print("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
-
-get_invalid_inet_option(Socket) ->
- {error, {eoptions, {inet_option, foo, _}}} = ssl:getopts(Socket, [foo]),
- ok.
-
%%--------------------------------------------------------------------
-invalid_inet_get_option_not_list(doc) ->
- ["Test handling of invalid type in getopts"];
-
-invalid_inet_get_option_not_list(suite) ->
- [];
+invalid_inet_get_option_not_list() ->
+ [{doc,"Test handling of invalid type in getopts"}].
invalid_inet_get_option_not_list(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -955,7 +813,7 @@ invalid_inet_get_option_not_list(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
- test_server:format("Testcase ~p, Client ~p Server ~p ~n",
+ ct:print("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok),
@@ -969,11 +827,8 @@ get_invalid_inet_option_not_list(Socket) ->
ok.
%%--------------------------------------------------------------------
-invalid_inet_get_option_improper_list(doc) ->
- ["Test handling of invalid type in getopts"];
-
-invalid_inet_get_option_improper_list(suite) ->
- [];
+invalid_inet_get_option_improper_list() ->
+ [{doc,"Test handling of invalid type in getopts"}].
invalid_inet_get_option_improper_list(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -990,7 +845,7 @@ invalid_inet_get_option_improper_list(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
- test_server:format("Testcase ~p, Client ~p Server ~p ~n",
+ ct:print("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok),
@@ -1003,11 +858,8 @@ get_invalid_inet_option_improper_list(Socket) ->
ok.
%%--------------------------------------------------------------------
-invalid_inet_set_option(doc) ->
- ["Test handling of invalid inet options in setopts"];
-
-invalid_inet_set_option(suite) ->
- [];
+invalid_inet_set_option() ->
+ [{doc,"Test handling of invalid inet options in setopts"}].
invalid_inet_set_option(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -1024,7 +876,7 @@ invalid_inet_set_option(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
- test_server:format("Testcase ~p, Client ~p Server ~p ~n",
+ ct:print("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok),
@@ -1038,11 +890,8 @@ set_invalid_inet_option(Socket) ->
{error, {eoptions, {inet_opt, {mode, foo}}}} = ssl:setopts(Socket, [{mode, foo}]),
ok.
%%--------------------------------------------------------------------
-invalid_inet_set_option_not_list(doc) ->
- ["Test handling of invalid type in setopts"];
-
-invalid_inet_set_option_not_list(suite) ->
- [];
+invalid_inet_set_option_not_list() ->
+ [{doc,"Test handling of invalid type in setopts"}].
invalid_inet_set_option_not_list(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -1059,7 +908,7 @@ invalid_inet_set_option_not_list(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
- test_server:format("Testcase ~p, Client ~p Server ~p ~n",
+ ct:print("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok),
@@ -1073,11 +922,8 @@ set_invalid_inet_option_not_list(Socket) ->
ok.
%%--------------------------------------------------------------------
-invalid_inet_set_option_improper_list(doc) ->
- ["Test handling of invalid tye in setopts"];
-
-invalid_inet_set_option_improper_list(suite) ->
- [];
+invalid_inet_set_option_improper_list() ->
+ [{doc,"Test handling of invalid tye in setopts"}].
invalid_inet_set_option_improper_list(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -1094,7 +940,7 @@ invalid_inet_set_option_improper_list(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
- test_server:format("Testcase ~p, Client ~p Server ~p ~n",
+ ct:print("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok),
@@ -1107,11 +953,8 @@ set_invalid_inet_option_improper_list(Socket) ->
ok.
%%--------------------------------------------------------------------
-misc_ssl_options(doc) ->
- ["Test what happens when we give valid options"];
-
-misc_ssl_options(suite) ->
- [];
+misc_ssl_options() ->
+ [{doc,"Test what happens when we give valid options"}].
misc_ssl_options(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -1129,17 +972,17 @@ misc_ssl_options(Config) when is_list(Config) ->
Server =
ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
- {mfa, {?MODULE, send_recv_result_active, []}},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
{options, TestOpts ++ ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
Client =
ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
- {mfa, {?MODULE, send_recv_result_active, []}},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
{options, TestOpts ++ ClientOpts}]),
- test_server:format("Testcase ~p, Client ~p Server ~p ~n",
+ ct:print("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -1147,23 +990,16 @@ misc_ssl_options(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-versions(doc) ->
- ["Test API function versions/0"];
-
-versions(suite) ->
- [];
+versions() ->
+ [{doc,"Test API function versions/0"}].
versions(Config) when is_list(Config) ->
[_|_] = Versions = ssl:versions(),
- test_server:format("~p~n", [Versions]).
+ ct:print("~p~n", [Versions]).
%%--------------------------------------------------------------------
-send_recv(doc) ->
- [""];
-
-send_recv(suite) ->
- [];
-
+send_recv() ->
+ [{doc,""}].
send_recv(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -1171,17 +1007,17 @@ send_recv(Config) when is_list(Config) ->
Server =
ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
- {mfa, {?MODULE, send_recv_result, []}},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
{options, [{active, false} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
Client =
ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
- {mfa, {?MODULE, send_recv_result, []}},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
{options, [{active, false} | ClientOpts]}]),
- test_server:format("Testcase ~p, Client ~p Server ~p ~n",
+ ct:print("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -1190,12 +1026,8 @@ send_recv(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-send_close(doc) ->
- [""];
-
-send_close(suite) ->
- [];
-
+send_close() ->
+ [{doc,""}].
send_close(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -1203,7 +1035,7 @@ send_close(Config) when is_list(Config) ->
Server =
ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
- {mfa, {?MODULE, send_recv_result, []}},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
{options, [{active, false} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
{ok, TcpS} = rpc:call(ClientNode, gen_tcp, connect,
@@ -1211,7 +1043,7 @@ send_close(Config) when is_list(Config) ->
{ok, SslS} = rpc:call(ClientNode, ssl, connect,
[TcpS,[{active, false}|ClientOpts]]),
- test_server:format("Testcase ~p, Client ~p Server ~p ~n",
+ ct:print("Testcase ~p, Client ~p Server ~p ~n",
[self(), self(), Server]),
ok = ssl:send(SslS, "Hello world"),
{ok,<<"Hello world">>} = ssl:recv(SslS, 11),
@@ -1219,11 +1051,8 @@ send_close(Config) when is_list(Config) ->
{error, _} = ssl:send(SslS, "Hello world").
%%--------------------------------------------------------------------
-close_transport_accept(doc) ->
- ["Tests closing ssl socket when waiting on ssl:transport_accept/1"];
-
-close_transport_accept(suite) ->
- [];
+close_transport_accept() ->
+ [{doc,"Tests closing ssl socket when waiting on ssl:transport_accept/1"}].
close_transport_accept(Config) when is_list(Config) ->
ServerOpts = ?config(server_opts, Config),
@@ -1233,7 +1062,7 @@ close_transport_accept(Config) when is_list(Config) ->
Opts = [{active, false} | ServerOpts],
{ok, ListenSocket} = rpc:call(ServerNode, ssl, listen, [Port, Opts]),
spawn_link(fun() ->
- test_server:sleep(?SLEEP),
+ ct:sleep(?SLEEP),
rpc:call(ServerNode, ssl, close, [ListenSocket])
end),
case rpc:call(ServerNode, ssl, transport_accept, [ListenSocket]) of
@@ -1244,11 +1073,8 @@ close_transport_accept(Config) when is_list(Config) ->
end.
%%--------------------------------------------------------------------
-dh_params(doc) ->
- ["Test to specify DH-params file in server."];
-
-dh_params(suite) ->
- [];
+dh_params() ->
+ [{doc,"Test to specify DH-params file in server."}].
dh_params(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -1260,13 +1086,13 @@ dh_params(Config) when is_list(Config) ->
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
- {mfa, {?MODULE, send_recv_result_active, []}},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
{options, [{dhfile, DHParamFile} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
- {mfa, {?MODULE, send_recv_result_active, []}},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
{options,
[{ciphers,[{dhe_rsa,aes_256_cbc,sha,ignore}]} |
ClientOpts]}]),
@@ -1277,11 +1103,8 @@ dh_params(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-upgrade(doc) ->
- ["Test that you can upgrade an tcp connection to an ssl connection"];
-
-upgrade(suite) ->
- [];
+upgrade() ->
+ [{doc,"Test that you can upgrade an tcp connection to an ssl connection"}].
upgrade(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -1305,7 +1128,7 @@ upgrade(Config) when is_list(Config) ->
{tcp_options, TcpOpts},
{ssl_options, ClientOpts}]),
- test_server:format("Testcase ~p, Client ~p Server ~p ~n",
+ ct:print("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -1329,11 +1152,8 @@ upgrade_result(Socket) ->
end.
%%--------------------------------------------------------------------
-upgrade_with_timeout(doc) ->
- ["Test ssl_accept/3"];
-
-upgrade_with_timeout(suite) ->
- [];
+upgrade_with_timeout() ->
+ [{doc,"Test ssl_accept/3"}].
upgrade_with_timeout(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -1358,7 +1178,7 @@ upgrade_with_timeout(Config) when is_list(Config) ->
{tcp_options, TcpOpts},
{ssl_options, ClientOpts}]),
- test_server:format("Testcase ~p, Client ~p Server ~p ~n",
+ ct:print("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -1367,11 +1187,8 @@ upgrade_with_timeout(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-tcp_connect(doc) ->
- ["Test what happens when a tcp tries to connect, i,e. a bad (ssl) packet is sent first"];
-
-tcp_connect(suite) ->
- [];
+tcp_connect() ->
+ [{doc,"Test what happens when a tcp tries to connect, i,e. a bad (ssl) packet is sent first"}].
tcp_connect(Config) when is_list(Config) ->
ServerOpts = ?config(server_opts, Config),
@@ -1387,22 +1204,19 @@ tcp_connect(Config) when is_list(Config) ->
Port = ssl_test_lib:inet_port(Server),
{ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {packet, 0}]),
- test_server:format("Testcase ~p connected to Server ~p ~n", [self(), Server]),
+ ct:print("Testcase ~p connected to Server ~p ~n", [self(), Server]),
gen_tcp:send(Socket, "<SOME GARBLED NON SSL MESSAGE>"),
receive
{tcp_closed, Socket} ->
receive
{Server, {error, Error}} ->
- test_server:format("Error ~p", [Error])
+ ct:print("Error ~p", [Error])
end
end.
-
-tcp_connect_big(doc) ->
- ["Test what happens when a tcp tries to connect, i,e. a bad big (ssl) packet is sent first"];
-
-tcp_connect_big(suite) ->
- [];
+%%--------------------------------------------------------------------
+tcp_connect_big() ->
+ [{doc,"Test what happens when a tcp tries to connect, i,e. a bad big (ssl) packet is sent first"}].
tcp_connect_big(Config) when is_list(Config) ->
ServerOpts = ?config(server_opts, Config),
@@ -1418,7 +1232,7 @@ tcp_connect_big(Config) when is_list(Config) ->
Port = ssl_test_lib:inet_port(Server),
{ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {packet, 0}]),
- test_server:format("Testcase ~p connected to Server ~p ~n", [self(), Server]),
+ ct:print("Testcase ~p connected to Server ~p ~n", [self(), Server]),
Rand = crypto:rand_bytes(?MAX_CIPHER_TEXT_LENGTH+1),
gen_tcp:send(Socket, <<?BYTE(0),
@@ -1428,24 +1242,16 @@ tcp_connect_big(Config) when is_list(Config) ->
{tcp_closed, Socket} ->
receive
{Server, {error, timeout}} ->
- test_server:fail("hangs");
+ ct:fail("hangs");
{Server, {error, Error}} ->
- test_server:format("Error ~p", [Error])
+ ct:print("Error ~p", [Error])
end
end.
-dummy(_Socket) ->
- %% Should not happen as the ssl connection will not be established
- %% due to fatal handshake failiure
- exit(kill).
-
%%--------------------------------------------------------------------
ipv6() ->
- [{require, ipv6_hosts}].
-ipv6(doc) ->
- ["Test ipv6."];
-ipv6(suite) ->
- [];
+ [{require, ipv6_hosts},
+ {doc,"Test ipv6."}].
ipv6(Config) when is_list(Config) ->
{ok, Hostname0} = inet:gethostname(),
@@ -1457,18 +1263,18 @@ ipv6(Config) when is_list(Config) ->
ssl_test_lib:run_where(Config, ipv6),
Server = ssl_test_lib:start_server([{node, ServerNode},
{port, 0}, {from, self()},
- {mfa, {?MODULE, send_recv_result, []}},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
{options,
[inet6, {active, false} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client([{node, ClientNode},
{port, Port}, {host, Hostname},
{from, self()},
- {mfa, {?MODULE, send_recv_result, []}},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
{options,
[inet6, {active, false} | ClientOpts]}]),
- test_server:format("Testcase ~p, Client ~p Server ~p ~n",
+ ct:print("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -1481,12 +1287,8 @@ ipv6(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-ekeyfile(doc) ->
- ["Test what happens with an invalid key file"];
-
-ekeyfile(suite) ->
- [];
-
+ekeyfile() ->
+ [{doc,"Test what happens with an invalid key file"}].
ekeyfile(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
BadOpts = ?config(server_bad_key, Config),
@@ -1509,11 +1311,8 @@ ekeyfile(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-ecertfile(doc) ->
- ["Test what happens with an invalid cert file"];
-
-ecertfile(suite) ->
- [];
+ecertfile() ->
+ [{doc,"Test what happens with an invalid cert file"}].
ecertfile(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -1538,11 +1337,8 @@ ecertfile(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-ecacertfile(doc) ->
- ["Test what happens with an invalid cacert file"];
-
-ecacertfile(suite) ->
- [];
+ecacertfile() ->
+ [{doc,"Test what happens with an invalid cacert file"}].
ecacertfile(Config) when is_list(Config) ->
ClientOpts = [{reuseaddr, true}|?config(client_opts, Config)],
@@ -1590,12 +1386,9 @@ ecacertfile(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-eoptions(doc) ->
- ["Test what happens when we give invalid options"];
+eoptions() ->
+ [{doc,"Test what happens when we give invalid options"}].
-eoptions(suite) ->
- [];
-
eoptions(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -1652,12 +1445,8 @@ eoptions(Config) when is_list(Config) ->
ok.
%%--------------------------------------------------------------------
-shutdown(doc) ->
- [""];
-
-shutdown(suite) ->
- [];
-
+shutdown() ->
+ [{doc,"Test API function ssl:shutdown/2"}].
shutdown(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -1682,25 +1471,9 @@ shutdown(Config) when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
-shutdown_result(Socket, server) ->
- ssl:send(Socket, "Hej"),
- ssl:shutdown(Socket, write),
- {ok, "Hej hopp"} = ssl:recv(Socket, 8),
- ok;
-
-shutdown_result(Socket, client) ->
- {ok, "Hej"} = ssl:recv(Socket, 3),
- ssl:send(Socket, "Hej hopp"),
- ssl:shutdown(Socket, write),
- ok.
-
%%--------------------------------------------------------------------
-shutdown_write(doc) ->
- [""];
-
-shutdown_write(suite) ->
- [];
-
+shutdown_write() ->
+ [{doc,"Test API function ssl:shutdown/2 with option write."}].
shutdown_write(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -1717,20 +1490,10 @@ shutdown_write(Config) when is_list(Config) ->
{options, [{active, false} | ClientOpts]}]),
ssl_test_lib:check_result(Server, ok, Client, {error, closed}).
-
-shutdown_write_result(Socket, server) ->
- test_server:sleep(?SLEEP),
- ssl:shutdown(Socket, write);
-shutdown_write_result(Socket, client) ->
- ssl:recv(Socket, 0).
%%--------------------------------------------------------------------
-shutdown_both(doc) ->
- [""];
-
-shutdown_both(suite) ->
- [];
-
+shutdown_both() ->
+ [{doc,"Test API function ssl:shutdown/2 with option both."}].
shutdown_both(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -1748,19 +1511,9 @@ shutdown_both(Config) when is_list(Config) ->
ssl_test_lib:check_result(Server, ok, Client, {error, closed}).
-shutdown_both_result(Socket, server) ->
- test_server:sleep(?SLEEP),
- ssl:shutdown(Socket, read_write);
-shutdown_both_result(Socket, client) ->
- ssl:recv(Socket, 0).
-
%%--------------------------------------------------------------------
-shutdown_error(doc) ->
- [""];
-
-shutdown_error(suite) ->
- [];
-
+shutdown_error() ->
+ [{doc,"Test ssl:shutdown/2 error handling"}].
shutdown_error(Config) when is_list(Config) ->
ServerOpts = ?config(server_opts, Config),
Port = ssl_test_lib:inet_port(node()),
@@ -1770,141 +1523,60 @@ shutdown_error(Config) when is_list(Config) ->
{error, closed} = ssl:shutdown(Listen, read_write).
%%-------------------------------------------------------------------
-ciphers_rsa_signed_certs(doc) ->
- ["Test all rsa ssl cipher suites in highest support ssl/tls version"];
+ciphers_rsa_signed_certs() ->
+ [{doc,"Test all rsa ssl cipher suites in highest support ssl/tls version"}].
-ciphers_rsa_signed_certs(suite) ->
- [];
-
ciphers_rsa_signed_certs(Config) when is_list(Config) ->
Version =
ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:rsa_suites(),
- test_server:format("~p erlang cipher suites ~p~n", [Version, Ciphers]),
+ ct:print("~p erlang cipher suites ~p~n", [Version, Ciphers]),
run_suites(Ciphers, Version, Config, rsa).
-
-ciphers_rsa_signed_certs_openssl_names(doc) ->
- ["Test all rsa ssl cipher suites in highest support ssl/tls version"];
+%%-------------------------------------------------------------------
+ciphers_rsa_signed_certs_openssl_names() ->
+ [{doc,"Test all rsa ssl cipher suites in highest support ssl/tls version"}].
-ciphers_rsa_signed_certs_openssl_names(suite) ->
- [];
-
ciphers_rsa_signed_certs_openssl_names(Config) when is_list(Config) ->
Version =
ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:openssl_rsa_suites(),
- test_server:format("tls1 openssl cipher suites ~p~n", [Ciphers]),
+ ct:print("tls1 openssl cipher suites ~p~n", [Ciphers]),
run_suites(Ciphers, Version, Config, rsa).
-
-ciphers_dsa_signed_certs(doc) ->
- ["Test all dsa ssl cipher suites in highest support ssl/tls version"];
+%%-------------------------------------------------------------------
+ciphers_dsa_signed_certs() ->
+ [{doc,"Test all dsa ssl cipher suites in highest support ssl/tls version"}].
-ciphers_dsa_signed_certs(suite) ->
- [];
-
ciphers_dsa_signed_certs(Config) when is_list(Config) ->
Version =
ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:dsa_suites(),
- test_server:format("~p erlang cipher suites ~p~n", [Version, Ciphers]),
+ ct:print("~p erlang cipher suites ~p~n", [Version, Ciphers]),
run_suites(Ciphers, Version, Config, dsa).
-
-ciphers_dsa_signed_certs_openssl_names(doc) ->
- ["Test all dsa ssl cipher suites in highest support ssl/tls version"];
+%%-------------------------------------------------------------------
+ciphers_dsa_signed_certs_openssl_names() ->
+ [{doc,"Test all dsa ssl cipher suites in highest support ssl/tls version"}].
-ciphers_dsa_signed_certs_openssl_names(suite) ->
- [];
-
ciphers_dsa_signed_certs_openssl_names(Config) when is_list(Config) ->
Version =
ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:openssl_dsa_suites(),
- test_server:format("tls1 openssl cipher suites ~p~n", [Ciphers]),
+ ct:print("tls1 openssl cipher suites ~p~n", [Ciphers]),
run_suites(Ciphers, Version, Config, dsa).
-
-anonymous_cipher_suites(doc)->
- ["Test the anonymous ciphersuites"];
-anonymous_cipher_suites(suite) ->
- [];
+%%-------------------------------------------------------------------
+anonymous_cipher_suites()->
+ [{doc,"Test the anonymous ciphersuites"}].
anonymous_cipher_suites(Config) when is_list(Config) ->
Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:anonymous_suites(),
run_suites(Ciphers, Version, Config, anonymous).
-run_suites(Ciphers, Version, Config, Type) ->
- {ClientOpts, ServerOpts} =
- case Type of
- rsa ->
- {?config(client_opts, Config),
- ?config(server_opts, Config)};
- dsa ->
- {?config(client_opts, Config),
- ?config(server_dsa_opts, Config)};
- anonymous ->
- %% No certs in opts!
- {?config(client_opts, Config),
- ?config(server_anon, Config)}
- end,
-
- Result = lists:map(fun(Cipher) ->
- cipher(Cipher, Version, Config, ClientOpts, ServerOpts) end,
- Ciphers),
- case lists:flatten(Result) of
- [] ->
- ok;
- Error ->
- test_server:format("Cipher suite errors: ~p~n", [Error]),
- test_server:fail(cipher_suite_failed_see_test_case_log)
- end.
-
-erlang_cipher_suite(Suite) when is_list(Suite)->
- ssl:suite_definition(ssl_cipher:openssl_suite(Suite));
-erlang_cipher_suite(Suite) ->
- Suite.
-
-cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
- %% process_flag(trap_exit, true),
- test_server:format("Testing CipherSuite ~p~n", [CipherSuite]),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- ErlangCipherSuite = erlang_cipher_suite(CipherSuite),
-
- ConnectionInfo = {ok, {Version, ErlangCipherSuite}},
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}},
- {options, 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, cipher_result, [ConnectionInfo]}},
- {options,
- [{ciphers,[CipherSuite]} |
- ClientOpts]}]),
-
- Result = ssl_test_lib:wait_for_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client),
-
- case Result of
- ok ->
- [];
- Error ->
- [{ErlangCipherSuite, Error}]
- end.
-
%%--------------------------------------------------------------------
-default_reject_anonymous(doc)->
- ["Test that by default anonymous cipher suites are rejected "];
-default_reject_anonymous(suite) ->
- [];
+default_reject_anonymous()->
+ [{doc,"Test that by default anonymous cipher suites are rejected "}].
default_reject_anonymous(Config) when is_list(Config) ->
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
ClientOpts = ?config(client_opts, Config),
@@ -1927,12 +1599,8 @@ default_reject_anonymous(Config) when is_list(Config) ->
Client, {error, "insufficient security"}).
%%--------------------------------------------------------------------
-reuse_session(doc) ->
- ["Test reuse of sessions (short handshake)"];
-
-reuse_session(suite) ->
- [];
-
+reuse_session() ->
+ [{doc,"Test reuse of sessions (short handshake)"}].
reuse_session(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -1958,7 +1626,7 @@ reuse_session(Config) when is_list(Config) ->
Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
%% Make sure session is registered
- test_server:sleep(?SLEEP),
+ ct:sleep(?SLEEP),
Client1 =
ssl_test_lib:start_client([{node, ClientNode},
@@ -1969,9 +1637,9 @@ reuse_session(Config) when is_list(Config) ->
{Client1, SessionInfo} ->
ok;
{Client1, Other} ->
- test_server:format("Expected: ~p, Unexpected: ~p~n",
+ ct:print("Expected: ~p, Unexpected: ~p~n",
[SessionInfo, Other]),
- test_server:fail(session_not_reused)
+ ct:fail(session_not_reused)
end,
Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
@@ -1984,7 +1652,7 @@ reuse_session(Config) when is_list(Config) ->
| ClientOpts]}]),
receive
{Client2, SessionInfo} ->
- test_server:fail(
+ ct:fail(
session_reused_when_session_reuse_disabled_by_client);
{Client2, _} ->
ok
@@ -2014,7 +1682,7 @@ reuse_session(Config) when is_list(Config) ->
Server1 ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
%% Make sure session is registered
- test_server:sleep(?SLEEP),
+ ct:sleep(?SLEEP),
Client4 =
ssl_test_lib:start_client([{node, ClientNode},
@@ -2024,10 +1692,10 @@ reuse_session(Config) when is_list(Config) ->
receive
{Client4, SessionInfo1} ->
- test_server:fail(
+ ct:fail(
session_reused_when_session_reuse_disabled_by_server);
{Client4, _Other} ->
- test_server:format("OTHER: ~p ~n", [_Other]),
+ ct:print("OTHER: ~p ~n", [_Other]),
ok
end,
@@ -2039,12 +1707,8 @@ reuse_session(Config) when is_list(Config) ->
ssl_test_lib:close(Client4).
%%--------------------------------------------------------------------
-reuse_session_expired(doc) ->
- ["Test sessions is not reused when it has expired"];
-
-reuse_session_expired(suite) ->
- [];
-
+reuse_session_expired() ->
+ [{doc,"Test sessions is not reused when it has expired"}].
reuse_session_expired(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -2070,7 +1734,7 @@ reuse_session_expired(Config) when is_list(Config) ->
Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
%% Make sure session is registered
- test_server:sleep(?SLEEP),
+ ct:sleep(?SLEEP),
Client1 =
ssl_test_lib:start_client([{node, ClientNode},
@@ -2081,15 +1745,15 @@ reuse_session_expired(Config) when is_list(Config) ->
{Client1, SessionInfo} ->
ok;
{Client1, Other} ->
- test_server:format("Expected: ~p, Unexpected: ~p~n",
+ ct:print("Expected: ~p, Unexpected: ~p~n",
[SessionInfo, Other]),
- test_server:fail(session_not_reused)
+ ct:fail(session_not_reused)
end,
Server ! listen,
%% Make sure session is unregistered due to expiration
- test_server:sleep((?EXPIRE+1)),
+ ct:sleep((?EXPIRE+1)),
[{session_id, Id} |_] = SessionInfo,
make_sure_expired(Hostname, Port, Id),
@@ -2101,7 +1765,7 @@ reuse_session_expired(Config) when is_list(Config) ->
{from, self()}, {options, ClientOpts}]),
receive
{Client2, SessionInfo} ->
- test_server:fail(session_reused_when_session_expired);
+ ct:fail(session_reused_when_session_expired);
{Client2, _} ->
ok
end,
@@ -2123,17 +1787,13 @@ make_sure_expired(Host, Port, Id) ->
#session{is_resumable = false} ->
ok;
_ ->
- test_server:sleep(?SLEEP),
+ ct:sleep(?SLEEP),
make_sure_expired(Host, Port, Id)
end.
%%--------------------------------------------------------------------
-server_does_not_want_to_reuse_session(doc) ->
- ["Test reuse of sessions (short handshake)"];
-
-server_does_not_want_to_reuse_session(suite) ->
- [];
-
+server_does_not_want_to_reuse_session() ->
+ [{doc,"Test reuse of sessions (short handshake)"}].
server_does_not_want_to_reuse_session(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -2162,7 +1822,7 @@ server_does_not_want_to_reuse_session(Config) when is_list(Config) ->
Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
%% Make sure session is registered
- test_server:sleep(?SLEEP),
+ ct:sleep(?SLEEP),
ssl_test_lib:close(Client0),
Client1 =
@@ -2172,7 +1832,7 @@ server_does_not_want_to_reuse_session(Config) when is_list(Config) ->
{from, self()}, {options, ClientOpts}]),
receive
{Client1, SessionInfo} ->
- test_server:fail(session_reused_when_server_does_not_want_to);
+ ct:fail(session_reused_when_server_does_not_want_to);
{Client1, _Other} ->
ok
end,
@@ -2181,512 +1841,55 @@ server_does_not_want_to_reuse_session(Config) when is_list(Config) ->
ssl_test_lib:close(Client1).
%%--------------------------------------------------------------------
-
-server_verify_peer_passive(doc) ->
- ["Test server option verify_peer"];
-
-server_verify_peer_passive(suite) ->
- [];
-
-server_verify_peer_passive(Config) when is_list(Config) ->
- ClientOpts = ?config(client_verification_opts, Config),
- ServerOpts = ?config(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, {?MODULE, send_recv_result, []}},
- {options, [{active, false}, {verify, verify_peer}
- | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, send_recv_result, []}},
- {options, [{active, false} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-
-server_verify_peer_active(doc) ->
- ["Test server option verify_peer"];
-
-server_verify_peer_active(suite) ->
- [];
-
-server_verify_peer_active(Config) when is_list(Config) ->
- ClientOpts = ?config(client_verification_opts, Config),
- ServerOpts = ?config(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, {?MODULE, send_recv_result_active, []}},
- {options, [{active, true}, {verify, verify_peer}
- | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, send_recv_result_active, []}},
- {options, [{active, true} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-server_verify_peer_active_once(doc) ->
- ["Test server option verify_peer"];
-
-server_verify_peer_active_once(suite) ->
- [];
-
-server_verify_peer_active_once(Config) when is_list(Config) ->
- ClientOpts = ?config(client_verification_opts, Config),
- ServerOpts = ?config(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, {?MODULE, send_recv_result_active_once, []}},
- {options, [{active, once}, {verify, verify_peer}
- | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, send_recv_result_active_once, []}},
- {options, [{active, once} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-
-server_verify_none_passive(doc) ->
- ["Test server option verify_none"];
-
-server_verify_none_passive(suite) ->
- [];
-
-server_verify_none_passive(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send_recv_result, []}},
- {options, [{active, false}, {verify, verify_none}
- | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, send_recv_result, []}},
- {options, [{active, false} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-
-server_verify_none_active(doc) ->
- ["Test server option verify_none"];
-
-server_verify_none_active(suite) ->
- [];
-
-server_verify_none_active(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send_recv_result_active, []}},
- {options, [{active, true}, {verify, verify_none} |
- ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, send_recv_result_active, []}},
- {options, [{active, true} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-server_verify_none_active_once(doc) ->
- ["Test server option verify_none"];
-
-server_verify_none_active_once(suite) ->
- [];
-
-server_verify_none_active_once(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send_recv_result_active_once, []}},
- {options, [{active, once}, {verify, verify_none}
- | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, send_recv_result_active_once, []}},
- {options, [{active, once} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-
-server_verify_client_once_passive(doc) ->
- ["Test server option verify_client_once"];
-
-server_verify_client_once_passive(suite) ->
- [];
-
-server_verify_client_once_passive(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(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, {?MODULE, send_recv_result, []}},
- {options, [{active, false}, {verify, verify_peer},
- {verify_client_once, true}
- | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, send_recv_result, []}},
- {options, [{active, false} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client0, ok),
- Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
- ssl_test_lib:close(Client0),
- Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, result_ok, []}},
- {options, [{active, false} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Client1, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client1).
-
-%%--------------------------------------------------------------------
-
-server_verify_client_once_active(doc) ->
- ["Test server option verify_client_once"];
-
-server_verify_client_once_active(suite) ->
- [];
-
-server_verify_client_once_active(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(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, {?MODULE, send_recv_result_active, []}},
- {options, [{active, true}, {verify, verify_peer},
- {verify_client_once, true}
- | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, send_recv_result_active, []}},
- {options, [{active, true} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client0, ok),
- Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
- ssl_test_lib:close(Client0),
- Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, result_ok, []}},
- {options, [{active, true} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Client1, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client1).
-
-%%--------------------------------------------------------------------
-
-server_verify_client_once_active_once(doc) ->
- ["Test server option verify_client_once"];
-
-server_verify_client_once_active_once(suite) ->
- [];
-
-server_verify_client_once_active_once(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(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, {?MODULE, send_recv_result_active_once, []}},
- {options, [{active, once}, {verify, verify_peer},
- {verify_client_once, true}
- | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, send_recv_result_active_once, []}},
- {options, [{active, once} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client0, ok),
- Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
- ssl_test_lib:close(Client0),
- Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, result_ok, []}},
- {options, [{active, once} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Client1, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client1).
-
-%%--------------------------------------------------------------------
-
-server_verify_no_cacerts(doc) ->
- ["Test server must have cacerts if it wants to verify client"];
-
-server_verify_no_cacerts(suite) ->
- [];
-server_verify_no_cacerts(Config) when is_list(Config) ->
- ServerOpts = ?config(server_opts, Config),
- {_, ServerNode, _} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {options, [{verify, verify_peer}
- | ServerOpts]}]),
-
- ssl_test_lib:check_result(Server, {error, {eoptions, {cacertfile, ""}}}).
-
-%%--------------------------------------------------------------------
-
-server_require_peer_cert_ok(doc) ->
- ["Test server option fail_if_no_peer_cert when peer sends cert"];
-
-server_require_peer_cert_ok(suite) ->
- [];
-
-server_require_peer_cert_ok(Config) when is_list(Config) ->
- ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
- | ?config(server_verification_opts, Config)],
- ClientOpts = ?config(client_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, {?MODULE, send_recv_result, []}},
- {options, [{active, false} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, send_recv_result, []}},
- {options, [{active, false} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-
-server_require_peer_cert_fail(doc) ->
- ["Test server option fail_if_no_peer_cert when peer doesn't send cert"];
-
-server_require_peer_cert_fail(suite) ->
- [];
-
-server_require_peer_cert_fail(Config) when is_list(Config) ->
- ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
- | ?config(server_verification_opts, Config)],
- BadClientOpts = ?config(client_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {options, [{active, false} | ServerOpts]}]),
-
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {options, [{active, false} | BadClientOpts]}]),
-
- ssl_test_lib:check_result(Server, {error, esslaccept},
- Client, {error, esslconnect}).
-
-%%--------------------------------------------------------------------
-
-client_verify_none_passive(doc) ->
- ["Test client option verify_none"];
-
-client_verify_none_passive(suite) ->
- [];
-
-client_verify_none_passive(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send_recv_result, []}},
- {options, [{active, false}
- | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, send_recv_result, []}},
- {options, [{active, false},
- {verify, verify_none}
- | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-
-client_verify_none_active(doc) ->
- ["Test client option verify_none"];
-
-client_verify_none_active(suite) ->
- [];
-
-client_verify_none_active(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE,
- send_recv_result_active, []}},
- {options, [{active, true}
- | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- send_recv_result_active, []}},
- {options, [{active, true},
- {verify, verify_none}
- | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-client_verify_none_active_once(doc) ->
- ["Test client option verify_none"];
-
-client_verify_none_active_once(suite) ->
- [];
-
-client_verify_none_active_once(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send_recv_result_active_once, []}},
- {options, [{active, once} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- send_recv_result_active_once,
- []}},
- {options, [{active, once},
- {verify, verify_none}
- | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-client_renegotiate(doc) ->
- ["Test ssl:renegotiate/1 on client."];
-
-client_renegotiate(suite) ->
- [];
-
+client_renegotiate() ->
+ [{doc,"Test ssl:renegotiate/1 on client."}].
client_renegotiate(Config) when is_list(Config) ->
- ServerOpts = ?config(server_opts, Config),
- ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ ClientOpts = ?config(client_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
+
Data = "From erlang to erlang",
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {?MODULE, erlang_ssl_receive, [Data]}},
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
-
+
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
+ {from, self()},
+ {mfa, {?MODULE,
renegotiate, [Data]}},
{options, [{reuse_sessions, false} | ClientOpts]}]),
- ssl_test_lib:check_result(Client, ok, Server, ok),
+ ssl_test_lib:check_result(Client, ok, Server, ok),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-server_renegotiate(doc) ->
- ["Test ssl:renegotiate/1 on server."];
-
-server_renegotiate(suite) ->
- [];
-
+server_renegotiate() ->
+ [{doc,"Test ssl:renegotiate/1 on server."}].
server_renegotiate(Config) when is_list(Config) ->
- ServerOpts = ?config(server_opts, Config),
- ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ ClientOpts = ?config(client_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
+
Data = "From erlang to erlang",
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
- {mfa, {?MODULE,
+ {mfa, {?MODULE,
renegotiate, [Data]}},
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
-
+
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
- {from, self()},
+ {from, self()},
{mfa, {?MODULE, erlang_ssl_receive, [Data]}},
{options, [{reuse_sessions, false} | ClientOpts]}]),
@@ -2695,805 +1898,133 @@ server_renegotiate(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-client_renegotiate_reused_session(doc) ->
- ["Test ssl:renegotiate/1 on client when the ssl session will be reused."];
-
-client_renegotiate_reused_session(suite) ->
- [];
-
+client_renegotiate_reused_session() ->
+ [{doc,"Test ssl:renegotiate/1 on client when the ssl session will be reused."}].
client_renegotiate_reused_session(Config) when is_list(Config) ->
- ServerOpts = ?config(server_opts, Config),
- ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ ClientOpts = ?config(client_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
+
Data = "From erlang to erlang",
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {?MODULE, erlang_ssl_receive, [Data]}},
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
-
+
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
+ {from, self()},
+ {mfa, {?MODULE,
renegotiate_reuse_session, [Data]}},
{options, [{reuse_sessions, true} | ClientOpts]}]),
- ssl_test_lib:check_result(Client, ok, Server, ok),
+ ssl_test_lib:check_result(Client, ok, Server, ok),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-server_renegotiate_reused_session(doc) ->
- ["Test ssl:renegotiate/1 on server when the ssl session will be reused."];
-
-server_renegotiate_reused_session(suite) ->
- [];
-
+server_renegotiate_reused_session() ->
+ [{doc,"Test ssl:renegotiate/1 on server when the ssl session will be reused."}].
server_renegotiate_reused_session(Config) when is_list(Config) ->
- ServerOpts = ?config(server_opts, Config),
- ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ ClientOpts = ?config(client_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Data = "From erlang to erlang",
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE,
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE,
renegotiate_reuse_session, [Data]}},
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
- {from, self()},
+ {from, self()},
{mfa, {?MODULE, erlang_ssl_receive, [Data]}},
{options, [{reuse_sessions, true} | ClientOpts]}]),
-
+
ssl_test_lib:check_result(Server, ok, Client, ok),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-client_no_wrap_sequence_number(doc) ->
- ["Test that erlang client will renegotiate session when",
+client_no_wrap_sequence_number() ->
+ [{doc,"Test that erlang client will renegotiate session when",
"max sequence number celing is about to be reached. Although"
- "in the testcase we use the test option renegotiate_at"
- " to lower treashold substantially."];
-
-client_no_wrap_sequence_number(suite) ->
- [];
+ "in the testcase we use the test option renegotiate_at"
+ " to lower treashold substantially."}].
client_no_wrap_sequence_number(Config) when is_list(Config) ->
- ServerOpts = ?config(server_opts, Config),
- ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ ClientOpts = ?config(client_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
+
ErlData = "From erlang to erlang",
N = 10,
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {ssl_test_lib, no_result, []}},
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
-
+
Version = ssl_record:highest_protocol_version(ssl_record:supported_protocol_versions()),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib,
+ {from, self()},
+ {mfa, {ssl_test_lib,
trigger_renegotiate, [[ErlData, treashold(N, Version)]]}},
{options, [{reuse_sessions, false},
{renegotiate_at, N} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
+
+ ssl_test_lib:check_result(Client, ok),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
- %% First two clauses handles 1/n-1 splitting countermeasure Rizzo/Duong-Beast
-treashold(N, {3,0}) ->
- (N div 2) + 1;
-treashold(N, {3,1}) ->
- (N div 2) + 1;
-treashold(N, _) ->
- N + 1.
-
%%--------------------------------------------------------------------
-server_no_wrap_sequence_number(doc) ->
- ["Test that erlang server will renegotiate session when",
+server_no_wrap_sequence_number() ->
+ [{doc, "Test that erlang server will renegotiate session when",
"max sequence number celing is about to be reached. Although"
- "in the testcase we use the test option renegotiate_at"
- " to lower treashold substantially."];
-
-server_no_wrap_sequence_number(suite) ->
- [];
+ "in the testcase we use the test option renegotiate_at"
+ " to lower treashold substantially."}].
server_no_wrap_sequence_number(Config) when is_list(Config) ->
- ServerOpts = ?config(server_opts, Config),
- ClientOpts = ?config(client_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From erlang to erlang",
- N = 10,
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib,
- trigger_renegotiate, [[Data, N+2]]}},
- {options, [{renegotiate_at, N} | 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, no_result, []}},
- {options, [{reuse_sessions, false} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-%%--------------------------------------------------------------------
-extended_key_usage_verify_peer(doc) ->
- ["Test cert that has a critical extended_key_usage extension in verify_peer mode"];
-
-extended_key_usage_verify_peer(suite) ->
- [];
-
-extended_key_usage_verify_peer(Config) when is_list(Config) ->
- ClientOpts = ?config(client_verification_opts, Config),
- ServerOpts = ?config(server_verification_opts, Config),
- PrivDir = ?config(priv_dir, Config),
-
- KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
- [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
- Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
-
- ServerCertFile = proplists:get_value(certfile, ServerOpts),
- NewServerCertFile = filename:join(PrivDir, "server/new_cert.pem"),
- [{'Certificate', ServerDerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile),
- ServerOTPCert = public_key:pkix_decode_cert(ServerDerCert, otp),
- ServerExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-serverAuth']},
- ServerOTPTbsCert = ServerOTPCert#'OTPCertificate'.tbsCertificate,
- ServerExtensions = ServerOTPTbsCert#'OTPTBSCertificate'.extensions,
- NewServerOTPTbsCert = ServerOTPTbsCert#'OTPTBSCertificate'{extensions =
- [ServerExtKeyUsageExt |
- ServerExtensions]},
- NewServerDerCert = public_key:pkix_sign(NewServerOTPTbsCert, Key),
- ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]),
- NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)],
-
- ClientCertFile = proplists:get_value(certfile, ClientOpts),
- NewClientCertFile = filename:join(PrivDir, "client/new_cert.pem"),
- [{'Certificate', ClientDerCert, _}] = ssl_test_lib:pem_to_der(ClientCertFile),
- ClientOTPCert = public_key:pkix_decode_cert(ClientDerCert, otp),
- ClientExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-clientAuth']},
- ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate,
- ClientExtensions = ClientOTPTbsCert#'OTPTBSCertificate'.extensions,
- NewClientOTPTbsCert = ClientOTPTbsCert#'OTPTBSCertificate'{extensions =
- [ClientExtKeyUsageExt |
- ClientExtensions]},
- NewClientDerCert = public_key:pkix_sign(NewClientOTPTbsCert, Key),
- ssl_test_lib:der_to_pem(NewClientCertFile, [{'Certificate', NewClientDerCert, not_encrypted}]),
- NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)],
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send_recv_result_active, []}},
- {options, [{verify, verify_peer} | NewServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, send_recv_result_active, []}},
- {options, [{verify, verify_peer} | NewClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- 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_none(suite) ->
- [];
-
-extended_key_usage_verify_none(Config) when is_list(Config) ->
- ClientOpts = ?config(client_verification_opts, Config),
- ServerOpts = ?config(server_verification_opts, Config),
- PrivDir = ?config(priv_dir, Config),
-
- KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
- [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
- Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
-
- ServerCertFile = proplists:get_value(certfile, ServerOpts),
- NewServerCertFile = filename:join(PrivDir, "server/new_cert.pem"),
- [{'Certificate', ServerDerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile),
- ServerOTPCert = public_key:pkix_decode_cert(ServerDerCert, otp),
- ServerExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-serverAuth']},
- ServerOTPTbsCert = ServerOTPCert#'OTPCertificate'.tbsCertificate,
- ServerExtensions = ServerOTPTbsCert#'OTPTBSCertificate'.extensions,
- NewServerOTPTbsCert = ServerOTPTbsCert#'OTPTBSCertificate'{extensions =
- [ServerExtKeyUsageExt |
- ServerExtensions]},
- NewServerDerCert = public_key:pkix_sign(NewServerOTPTbsCert, Key),
- ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]),
- NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)],
-
- ClientCertFile = proplists:get_value(certfile, ClientOpts),
- NewClientCertFile = filename:join(PrivDir, "client/new_cert.pem"),
- [{'Certificate', ClientDerCert, _}] = ssl_test_lib:pem_to_der(ClientCertFile),
- ClientOTPCert = public_key:pkix_decode_cert(ClientDerCert, otp),
- ClientExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-clientAuth']},
- ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate,
- ClientExtensions = ClientOTPTbsCert#'OTPTBSCertificate'.extensions,
- NewClientOTPTbsCert = ClientOTPTbsCert#'OTPTBSCertificate'{extensions =
- [ClientExtKeyUsageExt |
- ClientExtensions]},
- NewClientDerCert = public_key:pkix_sign(NewClientOTPTbsCert, Key),
- ssl_test_lib:der_to_pem(NewClientCertFile, [{'Certificate', NewClientDerCert, not_encrypted}]),
- NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)],
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send_recv_result_active, []}},
- {options, [{verify, verify_none} | NewServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, send_recv_result_active, []}},
- {options, [{verify, verify_none} | NewClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-no_authority_key_identifier(doc) ->
- ["Test cert that does not have authorityKeyIdentifier extension"
- " but are present in trusted certs db."];
-
-no_authority_key_identifier(suite) ->
- [];
-no_authority_key_identifier(Config) when is_list(Config) ->
- ClientOpts = ?config(client_verification_opts, Config),
ServerOpts = ?config(server_opts, Config),
- PrivDir = ?config(priv_dir, Config),
-
- KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
- [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
- Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
-
- CertFile = proplists:get_value(certfile, ServerOpts),
- NewCertFile = filename:join(PrivDir, "server/new_cert.pem"),
- [{'Certificate', DerCert, _}] = ssl_test_lib:pem_to_der(CertFile),
- OTPCert = public_key:pkix_decode_cert(DerCert, otp),
- OTPTbsCert = OTPCert#'OTPCertificate'.tbsCertificate,
- Extensions = OTPTbsCert#'OTPTBSCertificate'.extensions,
- NewExtensions = delete_authority_key_extension(Extensions, []),
- NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{extensions = NewExtensions},
-
- test_server:format("Extensions ~p~n, NewExtensions: ~p~n", [Extensions, NewExtensions]),
-
- NewDerCert = public_key:pkix_sign(NewOTPTbsCert, Key),
- ssl_test_lib:der_to_pem(NewCertFile, [{'Certificate', NewDerCert, not_encrypted}]),
- NewServerOpts = [{certfile, NewCertFile} | proplists:delete(certfile, ServerOpts)],
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send_recv_result_active, []}},
- {options, NewServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, send_recv_result_active, []}},
- {options, [{verify, verify_peer} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-delete_authority_key_extension([], Acc) ->
- lists:reverse(Acc);
-delete_authority_key_extension([#'Extension'{extnID = ?'id-ce-authorityKeyIdentifier'} | Rest],
- Acc) ->
- delete_authority_key_extension(Rest, Acc);
-delete_authority_key_extension([Head | Rest], Acc) ->
- delete_authority_key_extension(Rest, [Head | Acc]).
-
-%%--------------------------------------------------------------------
-
-invalid_signature_server(doc) ->
- ["Test server with invalid signature"];
-
-invalid_signature_server(suite) ->
- [];
-
-invalid_signature_server(Config) when is_list(Config) ->
- ClientOpts = ?config(client_verification_opts, Config),
- ServerOpts = ?config(server_verification_opts, Config),
- PrivDir = ?config(priv_dir, Config),
-
- KeyFile = filename:join(PrivDir, "server/key.pem"),
- [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
- Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
-
- ServerCertFile = proplists:get_value(certfile, ServerOpts),
- NewServerCertFile = filename:join(PrivDir, "server/invalid_cert.pem"),
- [{'Certificate', ServerDerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile),
- ServerOTPCert = public_key:pkix_decode_cert(ServerDerCert, otp),
- ServerOTPTbsCert = ServerOTPCert#'OTPCertificate'.tbsCertificate,
- NewServerDerCert = public_key:pkix_sign(ServerOTPTbsCert, Key),
- ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]),
- NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)],
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {options, NewServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {options, [{verify, verify_peer} | ClientOpts]}]),
-
- tcp_delivery_workaround(Server, {error, "bad certificate"},
- Client, {error,"bad certificate"}).
-
-%%--------------------------------------------------------------------
-
-invalid_signature_client(doc) ->
- ["Test server with invalid signature"];
-
-invalid_signature_client(suite) ->
- [];
-
-invalid_signature_client(Config) when is_list(Config) ->
- ClientOpts = ?config(client_verification_opts, Config),
- ServerOpts = ?config(server_verification_opts, Config),
- PrivDir = ?config(priv_dir, Config),
-
- KeyFile = filename:join(PrivDir, "client/key.pem"),
- [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
- Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
-
- ClientCertFile = proplists:get_value(certfile, ClientOpts),
- NewClientCertFile = filename:join(PrivDir, "client/invalid_cert.pem"),
- [{'Certificate', ClientDerCert, _}] = ssl_test_lib:pem_to_der(ClientCertFile),
- ClientOTPCert = public_key:pkix_decode_cert(ClientDerCert, otp),
- ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate,
- NewClientDerCert = public_key:pkix_sign(ClientOTPTbsCert, Key),
- ssl_test_lib:der_to_pem(NewClientCertFile, [{'Certificate', NewClientDerCert, not_encrypted}]),
- 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()},
- {options, [{verify, verify_peer} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {options, NewClientOpts}]),
-
- tcp_delivery_workaround(Server, {error, "bad certificate"},
- Client, {error,"bad certificate"}).
-
-tcp_delivery_workaround(Server, ServerMsg, Client, ClientMsg) ->
- receive
- {Server, ServerMsg} ->
- client_msg(Client, ClientMsg);
- {Client, ClientMsg} ->
- server_msg(Server, ServerMsg);
- {Client, {error,closed}} ->
- server_msg(Server, ServerMsg);
- {Server, {error,closed}} ->
- client_msg(Client, ClientMsg);
- {Client, {error, esslconnect}} ->
- server_msg(Server, ServerMsg);
- {Server, {error, esslaccept}} ->
- client_msg(Client, ClientMsg)
- end.
-
-client_msg(Client, ClientMsg) ->
- receive
- {Client, ClientMsg} ->
- ok;
- {Client, {error,closed}} ->
- test_server:format("client got close"),
- ok;
- {Client, {error, esslconnect}} ->
- test_server:format("client got econnaborted"),
- ok;
- Unexpected ->
- test_server:fail(Unexpected)
- end.
-
-server_msg(Server, ServerMsg) ->
- receive
- {Server, ServerMsg} ->
- ok;
- {Server, {error,closed}} ->
- test_server:format("server got close"),
- ok;
- {Server, {error, esslaccept}} ->
- test_server:format("server got econnaborted"),
- ok;
- Unexpected ->
- test_server:fail(Unexpected)
- end.
-
-%%--------------------------------------------------------------------
-cert_expired(doc) ->
- ["Test server with invalid signature"];
-
-cert_expired(suite) ->
- [];
-
-cert_expired(Config) when is_list(Config) ->
- ClientOpts = ?config(client_verification_opts, Config),
- ServerOpts = ?config(server_verification_opts, Config),
- PrivDir = ?config(priv_dir, Config),
-
- KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
- [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
- Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
-
- ServerCertFile = proplists:get_value(certfile, ServerOpts),
- NewServerCertFile = filename:join(PrivDir, "server/expired_cert.pem"),
- [{'Certificate', DerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile),
- OTPCert = public_key:pkix_decode_cert(DerCert, otp),
- OTPTbsCert = OTPCert#'OTPCertificate'.tbsCertificate,
-
- {Year, Month, Day} = date(),
- {Hours, Min, Sec} = time(),
- NotBeforeStr = lists:flatten(io_lib:format("~p~s~s~s~s~sZ",[Year-2,
- two_digits_str(Month),
- two_digits_str(Day),
- two_digits_str(Hours),
- two_digits_str(Min),
- two_digits_str(Sec)])),
- NotAfterStr = lists:flatten(io_lib:format("~p~s~s~s~s~sZ",[Year-1,
- two_digits_str(Month),
- two_digits_str(Day),
- two_digits_str(Hours),
- two_digits_str(Min),
- two_digits_str(Sec)])),
- NewValidity = {'Validity', {generalTime, NotBeforeStr}, {generalTime, NotAfterStr}},
-
- test_server:format("Validity: ~p ~n NewValidity: ~p ~n",
- [OTPTbsCert#'OTPTBSCertificate'.validity, NewValidity]),
-
- NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{validity = NewValidity},
- NewServerDerCert = public_key:pkix_sign(NewOTPTbsCert, Key),
- ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]),
- NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)],
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {options, NewServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {options, [{verify, verify_peer} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, {error, "certificate expired"},
- Client, {error, "certificate expired"}).
-
-two_digits_str(N) when N < 10 ->
- lists:flatten(io_lib:format("0~p", [N]));
-two_digits_str(N) ->
- lists:flatten(io_lib:format("~p", [N])).
-
-%%--------------------------------------------------------------------
-
-client_with_cert_cipher_suites_handshake(doc) ->
- ["Test that client with a certificate without keyEncipherment usage "
- " extension can connect to a server with restricted cipher suites "];
-
-client_with_cert_cipher_suites_handshake(suite) ->
- [];
-
-client_with_cert_cipher_suites_handshake(Config) when is_list(Config) ->
- ClientOpts = ?config(client_verification_opts_digital_signature_only, Config),
- ServerOpts = ?config(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, {?MODULE,
- send_recv_result_active, []}},
- {options, [{active, true},
- {ciphers, ssl_test_lib:rsa_non_signed_suites()}
- | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- send_recv_result_active, []}},
- {options, [{active, true}
- | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-verify_fun_always_run_client(doc) ->
- ["Verify that user verify_fun is always run (for valid and valid_peer not only unknown_extension)"];
-verify_fun_always_run_client(suite) ->
- [];
-verify_fun_always_run_client(Config) when is_list(Config) ->
- ClientOpts = ?config(client_verification_opts, Config),
- ServerOpts = ?config(server_verification_opts, Config),
- {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,
- no_result, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- %% If user verify fun is called correctly we fail the connection.
- %% otherwise we can not tell this case apart form where we miss
- %% to call users verify fun
- FunAndState = {fun(_,{extension, _}, UserState) ->
- {unknown, UserState};
- (_, valid, [ChainLen]) ->
- {valid, [ChainLen + 1]};
- (_, valid_peer, [2]) ->
- {fail, "verify_fun_was_always_run"};
- (_, valid_peer, UserState) ->
- {valid, UserState}
- end, [0]},
-
- Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib,
- no_result, []}},
- {options,
- [{verify, verify_peer},
- {verify_fun, FunAndState}
- | ClientOpts]}]),
- %% Server error may be esslaccept or closed depending on timing
- %% this is not a bug it is a circumstance of how tcp works!
- receive
- {Server, ServerError} ->
- test_server:format("Server Error ~p~n", [ServerError])
- end,
-
- ssl_test_lib:check_result(Client, {error, esslconnect}).
-
-%%--------------------------------------------------------------------
-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(suite) ->
- [];
-verify_fun_always_run_server(Config) when is_list(Config) ->
- ClientOpts = ?config(client_verification_opts, Config),
- ServerOpts = ?config(server_verification_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- %% If user verify fun is called correctly we fail the connection.
- %% otherwise we can not tell this case apart form where we miss
- %% to call users verify fun
- FunAndState = {fun(_,{extension, _}, UserState) ->
- {unknown, UserState};
- (_, valid, [ChainLen]) ->
- {valid, [ChainLen + 1]};
- (_, valid_peer, [2]) ->
- {fail, "verify_fun_was_always_run"};
- (_, valid_peer, UserState) ->
- {valid, UserState}
- end, [0]},
-
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib,
- no_result, []}},
- {options,
- [{verify, verify_peer},
- {verify_fun, FunAndState} |
- ServerOpts]}]),
- 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,
- no_result, []}},
- {options,
- [{verify, verify_peer}
- | ClientOpts]}]),
-
- %% Client error may be esslconnect or closed depending on timing
- %% this is not a bug it is a circumstance of how tcp works!
- receive
- {Client, ClientError} ->
- test_server:format("Client Error ~p~n", [ClientError])
- end,
-
- ssl_test_lib:check_result(Server, {error, esslaccept}).
-
-%%--------------------------------------------------------------------
-unknown_server_ca_fail(doc) ->
- ["Test that the client fails if the ca is unknown in verify_peer mode"];
-unknown_server_ca_fail(suite) ->
- [];
-unknown_server_ca_fail(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib,
- no_result, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- FunAndState = {fun(_,{bad_cert, unknown_ca} = Reason, _) ->
- {fail, Reason};
- (_,{extension, _}, UserState) ->
- {unknown, UserState};
- (_, valid, UserState) ->
- {valid, [test_to_update_user_state | UserState]};
- (_, valid_peer, UserState) ->
- {valid, UserState}
- end, []},
-
- Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib,
- no_result, []}},
- {options,
- [{verify, verify_peer},
- {verify_fun, FunAndState}
- | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, {error,"unknown ca"},
- Client, {error, "unknown ca"}).
+ ClientOpts = ?config(client_opts, 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(suite) ->
- [];
-unknown_server_ca_accept_verify_none(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE,
- send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- send_recv_result_active, []}},
- {options,
- [{verify, verify_none}| ClientOpts]}]),
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-%%--------------------------------------------------------------------
-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(suite) ->
- [];
-unknown_server_ca_accept_verify_peer(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE,
- send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- FunAndState = {fun(_,{bad_cert, unknown_ca}, UserState) ->
- {valid, UserState};
- (_,{bad_cert, _} = Reason, _) ->
- {fail, Reason};
- (_,{extension, _}, UserState) ->
- {unknown, UserState};
- (_, valid, UserState) ->
- {valid, UserState};
- (_, valid_peer, UserState) ->
- {valid, UserState}
- end, []},
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- send_recv_result_active, []}},
- {options,
- [{verify, verify_peer},
- {verify_fun, FunAndState}| ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
+ Data = "From erlang to erlang",
+ N = 10,
-%%--------------------------------------------------------------------
-unknown_server_ca_accept_backwardscompatibility(doc) ->
- ["Test that old style verify_funs will work"];
-unknown_server_ca_accept_backwardscompatibility(suite) ->
- [];
-unknown_server_ca_accept_backwardscompatibility(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
- {mfa, {?MODULE,
- send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- AcceptBadCa = fun({bad_cert,unknown_ca}, Acc) -> Acc;
- (Other, Acc) -> [Other | Acc]
- end,
- VerifyFun =
- fun(ErrorList) ->
- case lists:foldl(AcceptBadCa, [], ErrorList) of
- [] -> true;
- [_|_] -> false
- end
- end,
+ {mfa, {ssl_test_lib,
+ trigger_renegotiate, [[Data, N+2]]}},
+ {options, [{renegotiate_at, N} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
- {mfa, {?MODULE,
- send_recv_result_active, []}},
- {options,
- [{verify, verify_peer},
- {verify_fun, VerifyFun}| ClientOpts]}]),
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, [{reuse_sessions, false} | ClientOpts]}]),
- ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:check_result(Server, ok),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-der_input(doc) ->
- ["Test to input certs and key as der"];
-
-der_input(suite) ->
- [];
+der_input() ->
+ [{doc,"Test to input certs and key as der"}].
der_input(Config) when is_list(Config) ->
DataDir = ?config(data_dir, Config),
@@ -3514,19 +2045,19 @@ der_input(Config) when is_list(Config) ->
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
- {mfa, {?MODULE, send_recv_result, []}},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
{options, [{active, false} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
- {mfa, {?MODULE, send_recv_result, []}},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
{options, [{active, false} | ClientOpts]}]),
ssl_test_lib:check_result(Server, ok, Client, ok),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
-
+%%--------------------------------------------------------------------
der_input_opts(Opts) ->
Certfile = proplists:get_value(certfile, Opts),
CaCertsfile = proplists:get_value(cacertfile, Opts),
@@ -3543,12 +2074,9 @@ der_input_opts(Opts) ->
{Cert, {Asn1Type, Key}, CaCerts, DHParams}.
%%--------------------------------------------------------------------
-%% different_ca_peer_sign(doc) ->
+%% different_ca_peer_sign() ->
%% ["Check that a CA can have a different signature algorithm than the peer cert."];
-%% different_ca_peer_sign(suite) ->
-%% [];
-
%% different_ca_peer_sign(Config) when is_list(Config) ->
%% ClientOpts = ?config(client_mix_opts, Config),
%% ServerOpts = ?config(server_mix_verify_opts, Config),
@@ -3556,7 +2084,7 @@ der_input_opts(Opts) ->
%% {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
%% Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
%% {from, self()},
-%% {mfa, {?MODULE, send_recv_result_active_once, []}},
+%% {mfa, {ssl_test_lib, send_recv_result_active_once, []}},
%% {options, [{active, once},
%% {verify, verify_peer} | ServerOpts]}]),
%% Port = ssl_test_lib:inet_port(Server),
@@ -3564,7 +2092,7 @@ der_input_opts(Opts) ->
%% Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
%% {host, Hostname},
%% {from, self()},
-%% {mfa, {?MODULE,
+%% {mfa, {ssl_test_lib,
%% send_recv_result_active_once,
%% []}},
%% {options, [{active, once},
@@ -3577,12 +2105,8 @@ der_input_opts(Opts) ->
%%--------------------------------------------------------------------
-no_reuses_session_server_restart_new_cert(doc) ->
- ["Check that a session is not reused if the server is restarted with a new cert."];
-
-no_reuses_session_server_restart_new_cert(suite) ->
- [];
-
+no_reuses_session_server_restart_new_cert() ->
+ [{doc,"Check that a session is not reused if the server is restarted with a new cert."}].
no_reuses_session_server_restart_new_cert(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -3608,10 +2132,15 @@ no_reuses_session_server_restart_new_cert(Config) when is_list(Config) ->
end,
%% Make sure session is registered
- test_server:sleep(?SLEEP),
+ ct:sleep(?SLEEP),
+ Monitor = erlang:monitor(process, Server),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client0),
-
+ receive
+ {'DOWN', Monitor, _, _, _} ->
+ ok
+ end,
+
Server1 =
ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
{from, self()},
@@ -3625,7 +2154,7 @@ no_reuses_session_server_restart_new_cert(Config) when is_list(Config) ->
{from, self()}, {options, ClientOpts}]),
receive
{Client1, SessionInfo} ->
- test_server:fail(session_reused_when_server_has_new_cert);
+ ct:fail(session_reused_when_server_has_new_cert);
{Client1, _Other} ->
ok
end,
@@ -3633,12 +2162,9 @@ no_reuses_session_server_restart_new_cert(Config) when is_list(Config) ->
ssl_test_lib:close(Client1).
%%--------------------------------------------------------------------
-no_reuses_session_server_restart_new_cert_file(doc) ->
- ["Check that a session is not reused if a server is restarted with a new "
- "cert contained in a file with the same name as the old cert."];
-
-no_reuses_session_server_restart_new_cert_file(suite) ->
- [];
+no_reuses_session_server_restart_new_cert_file() ->
+ [{doc,"Check that a session is not reused if a server is restarted with a new "
+ "cert contained in a file with the same name as the old cert."}].
no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -3668,7 +2194,7 @@ no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) ->
%% Make sure session is registered and we get
%% new file time stamp when calling new_config!
- test_server:sleep(?SLEEP* 2),
+ ct:sleep(?SLEEP* 2),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client0),
@@ -3688,7 +2214,7 @@ no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) ->
{from, self()}, {options, ClientOpts}]),
receive
{Client1, SessionInfo} ->
- test_server:fail(session_reused_when_server_has_new_cert);
+ ct:fail(session_reused_when_server_has_new_cert);
{Client1, _Other} ->
ok
end,
@@ -3696,11 +2222,8 @@ no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) ->
ssl_test_lib:close(Client1).
%%--------------------------------------------------------------------
-reuseaddr(doc) ->
- [""];
-
-reuseaddr(suite) ->
- [];
+reuseaddr() ->
+ [{doc,"Test reuseaddr option"}].
reuseaddr(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -3718,20 +2241,19 @@ reuseaddr(Config) when is_list(Config) ->
{from, self()},
{mfa, {ssl_test_lib, no_result, []}},
{options, [{active, false} | ClientOpts]}]),
- test_server:sleep(?SLEEP),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client),
-
+
Server1 =
ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
{from, self()},
- {mfa, {?MODULE, send_recv_result, []}},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
{options, [{active, false} | ServerOpts]}]),
Client1 =
ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
- {mfa, {?MODULE, send_recv_result, []}},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
{options, [{active, false} | ClientOpts]}]),
ssl_test_lib:check_result(Server1, ok, Client1, ok),
@@ -3739,14 +2261,51 @@ reuseaddr(Config) when is_list(Config) ->
ssl_test_lib:close(Client1).
%%--------------------------------------------------------------------
+tcp_reuseaddr() ->
+ [{doc, "Reference test case."}].
+tcp_reuseaddr(Config) when is_list(Config) ->
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {transport, gen_tcp},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, [{active, false}, {reuseaddr, true}]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client =
+ ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {transport, gen_tcp},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, [{active, false}]}]),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client),
+
+ Server1 =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
+ {from, self()},
+ {transport, gen_tcp},
+ {mfa, {?MODULE, tcp_send_recv_result, []}},
+ {options, [{active, false}, {reuseaddr, true}]}]),
+ Client1 =
+ ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {transport, gen_tcp},
+ {mfa, {?MODULE, tcp_send_recv_result, []}},
+ {options, [{active, false}]}]),
-hibernate(doc) ->
- ["Check that an SSL connection that is started with option "
- "{hibernate_after, 1000} indeed hibernates after 1000ms of "
- "inactivity"];
+ ssl_test_lib:check_result(Server1, ok, Client1, ok),
+ ssl_test_lib:close(Server1),
+ ssl_test_lib:close(Client1).
-hibernate(suite) ->
- [];
+%%--------------------------------------------------------------------
+
+hibernate() ->
+ [{doc,"Check that an SSL connection that is started with option "
+ "{hibernate_after, 1000} indeed hibernates after 1000ms of "
+ "inactivity"}].
hibernate(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -3756,14 +2315,14 @@ hibernate(Config) ->
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
- {mfa, {?MODULE, send_recv_result_active, []}},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
{Client, #sslsocket{pid=Pid}} = ssl_test_lib:start_client([return_socket,
{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
- {mfa, {?MODULE, send_recv_result_active, []}},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
{options, [{hibernate_after, 1000}|ClientOpts]}]),
{current_function, _} =
process_info(Pid, current_function),
@@ -3777,11 +2336,87 @@ hibernate(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
+listen_socket() ->
+ [{doc,"Check error handling and inet compliance when calling API functions with listen sockets."}].
+
+listen_socket(Config) ->
+ ServerOpts = ?config(server_opts, Config),
+ {ok, ListenSocket} = ssl:listen(0, ServerOpts),
+
+ %% This can be a valid thing to do as
+ %% options are inherited by the accept socket
+ ok = ssl:controlling_process(ListenSocket, self()),
+
+ {ok, _} = ssl:sockname(ListenSocket),
+
+ {error, enotconn} = ssl:send(ListenSocket, <<"data">>),
+ {error, enotconn} = ssl:recv(ListenSocket, 0),
+ {error, enotconn} = ssl:connection_info(ListenSocket),
+ {error, enotconn} = ssl:peername(ListenSocket),
+ {error, enotconn} = ssl:peercert(ListenSocket),
+ {error, enotconn} = ssl:session_info(ListenSocket),
+ {error, enotconn} = ssl:renegotiate(ListenSocket),
+ {error, enotconn} = ssl:prf(ListenSocket, 'master_secret', <<"Label">>, client_random, 256),
+ {error, enotconn} = ssl:shutdown(ListenSocket, read_write),
+
+ ok = ssl:close(ListenSocket).
+%%--------------------------------------------------------------------
+ssl_accept_timeout() ->
+ [{doc,"Test ssl:ssl_accept timeout"}].
-connect_twice(doc) ->
- [""];
-connect_twice(suite) ->
- [];
+ssl_accept_timeout(Config) ->
+ process_flag(trap_exit, true),
+ ServerOpts = ?config(server_opts, Config),
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {timeout, 5000},
+ {mfa, {ssl_test_lib,
+ no_result_msg, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ {ok, CSocket} = gen_tcp:connect(Hostname, Port, [binary, {active, true}]),
+
+ receive
+ {tcp_closed, CSocket} ->
+ ssl_test_lib:check_result(Server, {error, timeout}),
+ receive
+ {'EXIT', Server, _} ->
+ [] = supervisor:which_children(ssl_connection_sup)
+ end
+ end.
+
+%%--------------------------------------------------------------------
+ssl_recv_timeout() ->
+ [{doc,"Test ssl:ssl_accept timeout"}].
+
+ssl_recv_timeout(Config) ->
+ ServerOpts = ?config(server_opts, Config),
+ ClientOpts = ?config(client_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, send_recv_result_timeout_server, []}},
+ {options, [{active, false} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ send_recv_result_timeout_client, []}},
+ {options, [{active, false} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Client, ok, Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+connect_twice() ->
+ [{doc,""}].
connect_twice(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -3791,7 +2426,7 @@ connect_twice(Config) when is_list(Config) ->
Server =
ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
- {mfa, {?MODULE, send_recv_result, []}},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
{options, [{keepalive, true},{active, false}
| ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
@@ -3799,7 +2434,7 @@ connect_twice(Config) when is_list(Config) ->
ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
- {mfa, {?MODULE, send_recv_result, []}},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
{options, [{keepalive, true},{active, false}
| ClientOpts]}]),
Server ! listen,
@@ -3809,11 +2444,11 @@ connect_twice(Config) when is_list(Config) ->
{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
- {mfa, {?MODULE, send_recv_result, []}},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
{options, [{keepalive, true},{active, false}
| ClientOpts]}]),
- test_server:format("Testcase ~p, Client ~p Server ~p ~n",
+ ct:print("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -3824,13 +2459,9 @@ connect_twice(Config) when is_list(Config) ->
ssl_test_lib:close(Client1).
%%--------------------------------------------------------------------
-renegotiate_dos_mitigate_active(doc) ->
- ["Mitigate DOS computational attack by not allowing client to renegotiate many times in a row",
- "immediately after each other"];
-
-renegotiate_dos_mitigate_active(suite) ->
- [];
-
+renegotiate_dos_mitigate_active() ->
+ [{doc, "Mitigate DOS computational attack by not allowing client to renegotiate many times in a row",
+ "immediately after each other"}].
renegotiate_dos_mitigate_active(Config) when is_list(Config) ->
ServerOpts = ?config(server_opts, Config),
ClientOpts = ?config(client_opts, Config),
@@ -3840,7 +2471,7 @@ renegotiate_dos_mitigate_active(Config) when is_list(Config) ->
Server =
ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
- {mfa, {?MODULE, send_recv_result_active, []}},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
{options, [ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
@@ -3856,13 +2487,9 @@ renegotiate_dos_mitigate_active(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-renegotiate_dos_mitigate_passive(doc) ->
- ["Mitigate DOS computational attack by not allowing client to renegotiate many times in a row",
- "immediately after each other"];
-
-renegotiate_dos_mitigate_passive(suite) ->
- [];
-
+renegotiate_dos_mitigate_passive() ->
+ [{doc, "Mitigate DOS computational attack by not allowing client to renegotiate many times in a row",
+ "immediately after each other"}].
renegotiate_dos_mitigate_passive(Config) when is_list(Config) ->
ServerOpts = ?config(server_opts, Config),
ClientOpts = ?config(client_opts, Config),
@@ -3872,7 +2499,7 @@ renegotiate_dos_mitigate_passive(Config) when is_list(Config) ->
Server =
ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
- {mfa, {?MODULE, send_recv_result, []}},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
{options, [{active, false} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
@@ -3888,8 +2515,8 @@ renegotiate_dos_mitigate_passive(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-tcp_error_propagation_in_active_mode(doc) ->
- ["Test that process recives {ssl_error, Socket, closed} when tcp error ocurres"];
+tcp_error_propagation_in_active_mode() ->
+ [{doc,"Test that process recives {ssl_error, Socket, closed} when tcp error ocurres"}].
tcp_error_propagation_in_active_mode(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -3918,11 +2545,9 @@ tcp_error_propagation_in_active_mode(Config) when is_list(Config) ->
ssl_test_lib:check_result(Client, {ssl_closed, SslSocket}).
-
%%--------------------------------------------------------------------
-
-recv_error_handling(doc) ->
- ["Special case of call error handling"];
+recv_error_handling() ->
+ [{doc,"Special case of call error handling"}].
recv_error_handling(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -3942,11 +2567,11 @@ recv_error_handling(Config) when is_list(Config) ->
ssl:close(SslSocket),
ssl_test_lib:check_result(Server, ok).
-
%%--------------------------------------------------------------------
-rizzo(doc) -> ["Test that there is a 1/n-1-split for non RC4 in 'TLS < 1.1' as it is
- vunrable to Rizzo/Dungon attack"];
+rizzo() ->
+ [{doc, "Test that there is a 1/n-1-split for non RC4 in 'TLS < 1.1' as it is
+ vunrable to Rizzo/Dungon attack"}].
rizzo(Config) when is_list(Config) ->
Ciphers = [X || X ={_,Y,_} <- ssl:cipher_suites(), Y =/= rc4_128],
@@ -3955,8 +2580,8 @@ rizzo(Config) when is_list(Config) ->
run_send_recv_rizzo(Ciphers, Config, Version,
{?MODULE, send_recv_result_active_rizzo, []}).
%%--------------------------------------------------------------------
-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() ->
+ [{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],
@@ -3966,58 +2591,141 @@ no_rizzo_rc4(Config) when is_list(Config) ->
{?MODULE, send_recv_result_active_no_rizzo, []}).
%%--------------------------------------------------------------------
-run_send_recv_rizzo(Ciphers, Config, Version, Mfa) ->
- Result = lists:map(fun(Cipher) ->
- rizzo_test(Cipher, Config, Version, Mfa) end,
- Ciphers),
- case lists:flatten(Result) of
- [] ->
- ok;
- Error ->
- test_server:format("Cipher suite errors: ~p~n", [Error]),
- test_server:fail(cipher_suite_failed_see_test_case_log)
- end.
+new_server_wants_peer_cert() ->
+ [{doc, "Test that server configured to do client certification does"
+ " not reuse session without a client certificate."}].
+new_server_wants_peer_cert(Config) when is_list(Config) ->
+ ServerOpts = ?config(server_opts, Config),
+ VServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
+ | ?config(server_verification_opts, Config)],
+ ClientOpts = ?config(client_verification_opts, Config),
-rizzo_test(Cipher, Config, Version, Mfa) ->
- {ClientOpts, ServerOpts} = client_server_opts(Cipher, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, Mfa},
- {options, [{active, true}, {ciphers, [Cipher]},
- {versions, [Version]}
- | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, Mfa},
- {options, [{active, true} | ClientOpts]}]),
-
- Result = ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, peercert_result, []}},
+ {options, [ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client =
+ ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ClientOpts}]),
+
+ Monitor = erlang:monitor(process, Server),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client),
- case Result of
- ok ->
- [];
- Error ->
- [{Cipher, Error}]
- end.
+ receive
+ {'DOWN', Monitor, _, _, _} ->
+ ok
+ end,
+
+ Server1 = ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
+ {from, self()},
+ {mfa, {?MODULE, peercert_result, []}},
+ {options, VServerOpts}]),
+ Client1 =
+ ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, [ClientOpts]}]),
-client_server_opts({KeyAlgo,_,_}, Config) when KeyAlgo == rsa orelse KeyAlgo == dhe_rsa ->
- {?config(client_opts, Config),
- ?config(server_opts, Config)};
-client_server_opts({KeyAlgo,_,_}, Config) when KeyAlgo == dss orelse KeyAlgo == dhe_dss ->
- {?config(client_dsa_opts, Config),
- ?config(server_dsa_opts, Config)}.
+ CertFile = proplists:get_value(certfile, ClientOpts),
+ [{'Certificate', BinCert, _}]= ssl_test_lib:pem_to_der(CertFile),
+
+ ServerMsg = {error, no_peercert},
+ Sever1Msg = {ok, BinCert},
+
+ ssl_test_lib:check_result(Server, ServerMsg, Server1, Sever1Msg),
+
+ ssl_test_lib:close(Server1),
+ ssl_test_lib:close(Client),
+ ssl_test_lib:close(Client1).
+
+%%--------------------------------------------------------------------
+session_cache_process_list() ->
+ [{doc,"Test reuse of sessions (short handshake)"}].
+session_cache_process_list(Config) when is_list(Config) ->
+ session_cache_process(list,Config).
+%%--------------------------------------------------------------------
+session_cache_process_mnesia() ->
+ [{doc,"Test reuse of sessions (short handshake)"}].
+session_cache_process_mnesia(Config) when is_list(Config) ->
+ session_cache_process(mnesia,Config).
%%--------------------------------------------------------------------
-%%% Internal functions
+%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
send_recv_result(Socket) ->
ssl:send(Socket, "Hello world"),
{ok,"Hello world"} = ssl:recv(Socket, 11),
ok.
+tcp_send_recv_result(Socket) ->
+ gen_tcp:send(Socket, "Hello world"),
+ {ok,"Hello world"} = gen_tcp:recv(Socket, 11),
+ ok.
+
+basic_verify_test_no_close(Config) ->
+ ClientOpts = ?config(client_verification_opts, Config),
+ ServerOpts = ?config(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, 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, ClientOpts}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ {Server, Client}.
+
+basic_test(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+send_recv_result_timeout_client(Socket) ->
+ {error, timeout} = ssl:recv(Socket, 11, 500),
+ ssl:send(Socket, "Hello world"),
+ receive
+ Msg ->
+ io:format("Msg ~p~n",[Msg])
+ after 500 ->
+ ok
+ end,
+ {ok, "Hello world"} = ssl:recv(Socket, 11, 500),
+ ok.
+send_recv_result_timeout_server(Socket) ->
+ ssl:send(Socket, "Hello"),
+ {ok, "Hello world"} = ssl:recv(Socket, 11),
+ ssl:send(Socket, " world"),
+ ok.
recv_close(Socket) ->
{error, closed} = ssl:recv(Socket, 11),
@@ -4028,17 +2736,6 @@ recv_close(Socket) ->
ok
end.
-send_recv_result_active(Socket) ->
- ssl:send(Socket, "Hello world"),
- receive
- {ssl, Socket, "H"} ->
- receive
- {ssl, Socket, "ello world"} ->
- ok
- end;
- {ssl, Socket, "Hello world"} ->
- ok
- end.
send_recv_result_active_rizzo(Socket) ->
ssl:send(Socket, "Hello world"),
@@ -4057,26 +2754,13 @@ send_recv_result_active_no_rizzo(Socket) ->
ok
end.
-send_recv_result_active_once(Socket) ->
- ssl:send(Socket, "Hello world"),
- receive
- {ssl, Socket, "H"} ->
- ssl:setopts(Socket, [{active, once}]),
- receive
- {ssl, Socket, "ello world"} ->
- ok
- end;
- {ssl, Socket, "Hello world"} ->
- ok
- end.
-
result_ok(_Socket) ->
ok.
renegotiate(Socket, Data) ->
- test_server:format("Renegotiating ~n", []),
+ ct:print("Renegotiating ~n", []),
Result = ssl:renegotiate(Socket),
- test_server:format("Result ~p~n", [Result]),
+ ct:print("Result ~p~n", [Result]),
ssl:send(Socket, Data),
case Result of
ok ->
@@ -4087,7 +2771,7 @@ renegotiate(Socket, Data) ->
renegotiate_reuse_session(Socket, Data) ->
%% Make sure session is registered
- test_server:sleep(?SLEEP),
+ ct:sleep(?SLEEP),
renegotiate(Socket, Data).
renegotiate_immediately(Socket) ->
@@ -4103,9 +2787,9 @@ renegotiate_immediately(Socket) ->
end,
ok = ssl:renegotiate(Socket),
{error, renegotiation_rejected} = ssl:renegotiate(Socket),
- test_server:sleep(?RENEGOTIATION_DISABLE_TIME +1),
+ ct:sleep(?RENEGOTIATION_DISABLE_TIME +1),
ok = ssl:renegotiate(Socket),
- test_server:format("Renegotiated again"),
+ ct:print("Renegotiated again"),
ssl:send(Socket, "Hello world"),
ok.
@@ -4124,27 +2808,11 @@ new_config(PrivDir, ServerOpts0) ->
ServerOpts = proplists:delete(keyfile, ServerOpts2),
{ok, PEM} = file:read_file(NewCaCertFile),
- test_server:format("CA file content: ~p~n", [public_key:pem_decode(PEM)]),
+ ct:print("CA file content: ~p~n", [public_key:pem_decode(PEM)]),
[{cacertfile, NewCaCertFile}, {certfile, NewCertFile},
{keyfile, NewKeyFile} | ServerOpts].
-session_cache_process_list(doc) ->
- ["Test reuse of sessions (short handshake)"];
-
-session_cache_process_list(suite) ->
- [];
-session_cache_process_list(Config) when is_list(Config) ->
- session_cache_process(list,Config).
-
-session_cache_process_mnesia(doc) ->
- ["Test reuse of sessions (short handshake)"];
-
-session_cache_process_mnesia(suite) ->
- [];
-session_cache_process_mnesia(Config) when is_list(Config) ->
- session_cache_process(mnesia,Config).
-
session_cache_process(_Type,Config) when is_list(Config) ->
reuse_session(Config).
@@ -4286,9 +2954,9 @@ erlang_ssl_receive(Socket, Data) ->
io:format("Received ~p~n",[Byte]),
erlang_ssl_receive(Socket, tl(Data));
Other ->
- test_server:fail({unexpected_message, Other})
+ ct:fail({unexpected_message, Other})
after ?SLEEP * 3 ->
- test_server:fail({did_not_get, Data})
+ ct:fail({did_not_get, Data})
end.
receive_msg(_) ->
@@ -4296,3 +2964,222 @@ receive_msg(_) ->
Msg ->
Msg
end.
+
+controlling_process_result(Socket, Pid, Msg) ->
+ ok = ssl:controlling_process(Socket, Pid),
+ %% Make sure other side has evaluated controlling_process
+ %% before message is sent
+ ct:sleep(?SLEEP),
+ ssl:send(Socket, Msg),
+ no_result_msg.
+
+receive_s_rizzo_duong_beast() ->
+ receive
+ {ssl, _, "erver hello"} ->
+ receive
+ {ssl, _, "C"} ->
+ receive
+ {ssl, _, "lient hello"} ->
+ ok
+ end
+ end
+ end.
+receive_c_rizzo_duong_beast() ->
+ receive
+ {ssl, _, "lient hello"} ->
+ receive
+ {ssl, _, "S"} ->
+ receive
+ {ssl, _, "erver hello"} ->
+ ok
+ end
+ end
+ end.
+
+controller_dies_result(_Socket, _Pid, _Msg) ->
+ receive Result -> Result end.
+
+get_close(Pid, Where) ->
+ receive
+ {'EXIT', Pid, _Reason} ->
+ receive
+ {_, {ssl_closed, Socket}} ->
+ ct:print("Socket closed ~p~n",[Socket]);
+ Unexpected ->
+ ct:print("Unexpected ~p~n",[Unexpected]),
+ ct:fail({line, ?LINE-1})
+ after 5000 ->
+ ct:fail({timeout, {line, ?LINE, Where}})
+ end;
+ Unexpected ->
+ ct:print("Unexpected ~p~n",[Unexpected]),
+ ct:fail({line, ?LINE-1})
+ after 5000 ->
+ ct:fail({timeout, {line, ?LINE, Where}})
+ end.
+
+run_send_recv_rizzo(Ciphers, Config, Version, Mfa) ->
+ Result = lists:map(fun(Cipher) ->
+ rizzo_test(Cipher, Config, Version, Mfa) end,
+ Ciphers),
+ case lists:flatten(Result) of
+ [] ->
+ ok;
+ Error ->
+ ct:print("Cipher suite errors: ~p~n", [Error]),
+ ct:fail(cipher_suite_failed_see_test_case_log)
+ end.
+
+rizzo_test(Cipher, Config, Version, Mfa) ->
+ {ClientOpts, ServerOpts} = client_server_opts(Cipher, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, Mfa},
+ {options, [{active, true}, {ciphers, [Cipher]},
+ {versions, [Version]}
+ | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, Mfa},
+ {options, [{active, true} | ClientOpts]}]),
+
+ Result = ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client),
+ case Result of
+ ok ->
+ [];
+ Error ->
+ [{Cipher, Error}]
+ end.
+
+client_server_opts({KeyAlgo,_,_}, Config) when KeyAlgo == rsa orelse KeyAlgo == dhe_rsa ->
+ {?config(client_opts, Config),
+ ?config(server_opts, Config)};
+client_server_opts({KeyAlgo,_,_}, Config) when KeyAlgo == dss orelse KeyAlgo == dhe_dss ->
+ {?config(client_dsa_opts, Config),
+ ?config(server_dsa_opts, Config)}.
+
+run_suites(Ciphers, Version, Config, Type) ->
+ {ClientOpts, ServerOpts} =
+ case Type of
+ rsa ->
+ {?config(client_opts, Config),
+ ?config(server_opts, Config)};
+ dsa ->
+ {?config(client_opts, Config),
+ ?config(server_dsa_opts, Config)};
+ anonymous ->
+ %% No certs in opts!
+ {?config(client_opts, Config),
+ ?config(server_anon, Config)}
+ end,
+
+ Result = lists:map(fun(Cipher) ->
+ cipher(Cipher, Version, Config, ClientOpts, ServerOpts) end,
+ Ciphers),
+ case lists:flatten(Result) of
+ [] ->
+ ok;
+ Error ->
+ ct:print("Cipher suite errors: ~p~n", [Error]),
+ ct:fail(cipher_suite_failed_see_test_case_log)
+ end.
+
+erlang_cipher_suite(Suite) when is_list(Suite)->
+ ssl:suite_definition(ssl_cipher:openssl_suite(Suite));
+erlang_cipher_suite(Suite) ->
+ Suite.
+
+cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
+ %% process_flag(trap_exit, true),
+ ct:print("Testing CipherSuite ~p~n", [CipherSuite]),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ ErlangCipherSuite = erlang_cipher_suite(CipherSuite),
+
+ ConnectionInfo = {ok, {Version, ErlangCipherSuite}},
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}},
+ {options, 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, cipher_result, [ConnectionInfo]}},
+ {options,
+ [{ciphers,[CipherSuite]} |
+ ClientOpts]}]),
+
+ Result = ssl_test_lib:wait_for_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client),
+
+ case Result of
+ ok ->
+ [];
+ Error ->
+ [{ErlangCipherSuite, Error}]
+ end.
+
+connection_info_result(Socket) ->
+ ssl:connection_info(Socket).
+
+connect_dist_s(S) ->
+ Msg = term_to_binary({erlang,term}),
+ ok = ssl:send(S, Msg).
+
+connect_dist_c(S) ->
+ Test = binary_to_list(term_to_binary({erlang,term})),
+ {ok, Test} = ssl:recv(S, 0, 10000),
+ ok.
+
+ %% First two clauses handles 1/n-1 splitting countermeasure Rizzo/Duong-Beast
+treashold(N, {3,0}) ->
+ (N div 2) + 1;
+treashold(N, {3,1}) ->
+ (N div 2) + 1;
+treashold(N, _) ->
+ N + 1.
+
+get_invalid_inet_option(Socket) ->
+ {error, {eoptions, {inet_option, foo, _}}} = ssl:getopts(Socket, [foo]),
+ ok.
+
+shutdown_result(Socket, server) ->
+ ssl:send(Socket, "Hej"),
+ ssl:shutdown(Socket, write),
+ {ok, "Hej hopp"} = ssl:recv(Socket, 8),
+ ok;
+
+shutdown_result(Socket, client) ->
+ {ok, "Hej"} = ssl:recv(Socket, 3),
+ ssl:send(Socket, "Hej hopp"),
+ ssl:shutdown(Socket, write),
+ ok.
+
+shutdown_write_result(Socket, server) ->
+ ct:sleep(?SLEEP),
+ ssl:shutdown(Socket, write);
+shutdown_write_result(Socket, client) ->
+ ssl:recv(Socket, 0).
+
+dummy(_Socket) ->
+ %% Should not happen as the ssl connection will not be established
+ %% due to fatal handshake failiure
+ exit(kill).
+
+shutdown_both_result(Socket, server) ->
+ ct:sleep(?SLEEP),
+ ssl:shutdown(Socket, read_write);
+shutdown_both_result(Socket, client) ->
+ ssl:recv(Socket, 0).
+
+peername_result(S) ->
+ ssl:peername(S).
diff --git a/lib/ssl/test/ssl_certificate_verify_SUITE.erl b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
new file mode 100644
index 0000000000..9677d98c1b
--- /dev/null
+++ b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
@@ -0,0 +1,982 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012-2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.2
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+-module(ssl_certificate_verify_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+-include("ssl_internal.hrl").
+-include("ssl_alert.hrl").
+-include("ssl_internal.hrl").
+-include("ssl_record.hrl").
+-include("ssl_handshake.hrl").
+
+-define(LONG_TIMEOUT, 600000).
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [{group, active},
+ {group, passive},
+ {group, active_once},
+ {group, error_handling}].
+
+
+groups() ->
+ [{active, [], tests()},
+ {active_once, [], tests()},
+ {passive, [], tests()},
+ {error_handling, [],error_handling_tests()}].
+
+tests() ->
+ [server_verify_peer,
+ server_verify_none,
+ server_require_peer_cert_ok,
+ server_require_peer_cert_fail,
+ verify_fun_always_run_client,
+ verify_fun_always_run_server,
+ cert_expired,
+ invalid_signature_client,
+ invalid_signature_server,
+ extended_key_usage_verify_peer,
+ extended_key_usage_verify_none].
+
+error_handling_tests()->
+ [client_with_cert_cipher_suites_handshake,
+ server_verify_no_cacerts,
+ unknown_server_ca_fail,
+ unknown_server_ca_accept_verify_none,
+ unknown_server_ca_accept_verify_peer,
+ unknown_server_ca_accept_backwardscompatibility,
+ no_authority_key_identifier].
+
+init_per_suite(Config0) ->
+ Dog = ct:timetrap(?LONG_TIMEOUT *2),
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ application:start(public_key),
+ application:start(ssl),
+ %% make rsa certs using oppenssl
+ Result =
+ (catch make_certs:all(?config(data_dir, Config0),
+ ?config(priv_dir, Config0))),
+ ct:print("Make certs ~p~n", [Result]),
+
+ Config1 = ssl_test_lib:make_dsa_cert(Config0),
+ Config = ssl_test_lib:cert_options(Config1),
+ [{watchdog, Dog} | Config]
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto).
+
+init_per_group(active, Config) ->
+ [{active, true}, {receive_function, send_recv_result_active} | Config];
+init_per_group(active_once, Config) ->
+ [{active, once}, {receive_function, send_recv_result_active_once} | Config];
+init_per_group(passive, Config) ->
+ [{active, false}, {receive_function, send_recv_result} | Config];
+init_per_group(_, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+server_verify_peer() ->
+ [{doc,"Test server option verify_peer"}].
+server_verify_peer(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_verification_opts, Config),
+ ServerOpts = ?config(server_verification_opts, Config),
+ Active = ?config(active, Config),
+ ReceiveFunction = ?config(receive_function, 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, ReceiveFunction, []}},
+ {options, [{active, Active}, {verify, verify_peer}
+ | 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, ReceiveFunction, []}},
+ {options, [{active, Active} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+server_verify_none() ->
+ [{doc,"Test server option verify_none"}].
+
+server_verify_none(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ Active = ?config(active, Config),
+ ReceiveFunction = ?config(receive_function, 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, ReceiveFunction, []}},
+ {options, [{active, Active}, {verify, verify_none}
+ | 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, ReceiveFunction, []}},
+ {options, [{active, Active} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+
+server_verify_client_once() ->
+ [{doc,"Test server option verify_client_once"}].
+
+server_verify_client_once(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_verification_opts, Config),
+ Active = ?config(active, Config),
+ ReceiveFunction = ?config(receive_function, 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, ReceiveFunction, []}},
+ {options, [{active, Active}, {verify, verify_peer},
+ {verify_client_once, true}
+ | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, ReceiveFunction, []}},
+ {options, [{active, Active} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client0, ok),
+ Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
+ ssl_test_lib:close(Client0),
+ Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, result_ok, []}},
+ {options, [{active, Active} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Client1, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client1).
+
+%%--------------------------------------------------------------------
+
+server_require_peer_cert_ok() ->
+ [{doc,"Test server option fail_if_no_peer_cert when peer sends cert"}].
+
+server_require_peer_cert_ok(Config) when is_list(Config) ->
+ ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
+ | ?config(server_verification_opts, Config)],
+ ClientOpts = ?config(client_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, []}},
+ {options, [{active, false} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
+ {options, [{active, false} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+
+server_require_peer_cert_fail() ->
+ [{doc,"Test server option fail_if_no_peer_cert when peer doesn't send cert"}].
+
+server_require_peer_cert_fail(Config) when is_list(Config) ->
+ ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
+ | ?config(server_verification_opts, Config)],
+ BadClientOpts = ?config(client_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, [{active, false} | ServerOpts]}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {options, [{active, false} | BadClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, {error, esslaccept},
+ Client, {error, esslconnect}).
+
+
+%%--------------------------------------------------------------------
+verify_fun_always_run_client() ->
+ [{doc,"Verify that user verify_fun is always run (for valid and valid_peer not only unknown_extension)"}].
+
+verify_fun_always_run_client(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_verification_opts, Config),
+ ServerOpts = ?config(server_verification_opts, Config),
+ {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,
+ no_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ %% If user verify fun is called correctly we fail the connection.
+ %% otherwise we can not tell this case apart form where we miss
+ %% to call users verify fun
+ FunAndState = {fun(_,{extension, _}, UserState) ->
+ {unknown, UserState};
+ (_, valid, [ChainLen]) ->
+ {valid, [ChainLen + 1]};
+ (_, valid_peer, [2]) ->
+ {fail, "verify_fun_was_always_run"};
+ (_, valid_peer, UserState) ->
+ {valid, UserState}
+ end, [0]},
+
+ Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ no_result, []}},
+ {options,
+ [{verify, verify_peer},
+ {verify_fun, FunAndState}
+ | ClientOpts]}]),
+ %% Server error may be esslaccept or closed depending on timing
+ %% this is not a bug it is a circumstance of how tcp works!
+ receive
+ {Server, ServerError} ->
+ ct:print("Server Error ~p~n", [ServerError])
+ end,
+
+ ssl_test_lib:check_result(Client, {error, esslconnect}).
+
+%%--------------------------------------------------------------------
+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 = ?config(client_verification_opts, Config),
+ ServerOpts = ?config(server_verification_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ %% If user verify fun is called correctly we fail the connection.
+ %% otherwise we can not tell this case apart form where we miss
+ %% to call users verify fun
+ FunAndState = {fun(_,{extension, _}, UserState) ->
+ {unknown, UserState};
+ (_, valid, [ChainLen]) ->
+ {valid, [ChainLen + 1]};
+ (_, valid_peer, [2]) ->
+ {fail, "verify_fun_was_always_run"};
+ (_, valid_peer, UserState) ->
+ {valid, UserState}
+ end, [0]},
+
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ no_result, []}},
+ {options,
+ [{verify, verify_peer},
+ {verify_fun, FunAndState} |
+ ServerOpts]}]),
+ 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,
+ no_result, []}},
+ {options,
+ [{verify, verify_peer}
+ | ClientOpts]}]),
+
+ %% Client error may be esslconnect or closed depending on timing
+ %% this is not a bug it is a circumstance of how tcp works!
+ receive
+ {Client, ClientError} ->
+ ct:print("Client Error ~p~n", [ClientError])
+ end,
+
+ ssl_test_lib:check_result(Server, {error, esslaccept}).
+
+%%--------------------------------------------------------------------
+
+client_verify_none_passive() ->
+ [{doc,"Test client option verify_none"}].
+
+client_verify_none_passive(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
+ {options, [{active, false}
+ | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
+ {options, [{active, false},
+ {verify, verify_none}
+ | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+cert_expired() ->
+ [{doc,"Test server with invalid signature"}].
+
+cert_expired(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_verification_opts, Config),
+ ServerOpts = ?config(server_verification_opts, Config),
+ PrivDir = ?config(priv_dir, Config),
+
+ KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
+ [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
+ Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
+
+ ServerCertFile = proplists:get_value(certfile, ServerOpts),
+ NewServerCertFile = filename:join(PrivDir, "server/expired_cert.pem"),
+ [{'Certificate', DerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile),
+ OTPCert = public_key:pkix_decode_cert(DerCert, otp),
+ OTPTbsCert = OTPCert#'OTPCertificate'.tbsCertificate,
+
+ {Year, Month, Day} = date(),
+ {Hours, Min, Sec} = time(),
+ NotBeforeStr = lists:flatten(io_lib:format("~p~s~s~s~s~sZ",[Year-2,
+ two_digits_str(Month),
+ two_digits_str(Day),
+ two_digits_str(Hours),
+ two_digits_str(Min),
+ two_digits_str(Sec)])),
+ NotAfterStr = lists:flatten(io_lib:format("~p~s~s~s~s~sZ",[Year-1,
+ two_digits_str(Month),
+ two_digits_str(Day),
+ two_digits_str(Hours),
+ two_digits_str(Min),
+ two_digits_str(Sec)])),
+ NewValidity = {'Validity', {generalTime, NotBeforeStr}, {generalTime, NotAfterStr}},
+
+ ct:print("Validity: ~p ~n NewValidity: ~p ~n",
+ [OTPTbsCert#'OTPTBSCertificate'.validity, NewValidity]),
+
+ NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{validity = NewValidity},
+ NewServerDerCert = public_key:pkix_sign(NewOTPTbsCert, Key),
+ ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]),
+ NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)],
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, NewServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {options, [{verify, verify_peer} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, {error, "certificate expired"},
+ Client, {error, "certificate expired"}).
+
+two_digits_str(N) when N < 10 ->
+ lists:flatten(io_lib:format("0~p", [N]));
+two_digits_str(N) ->
+ lists:flatten(io_lib:format("~p", [N])).
+
+%%--------------------------------------------------------------------
+
+client_verify_none_active() ->
+ [{doc,"Test client option verify_none"}].
+
+client_verify_none_active(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ send_recv_result_active, []}},
+ {options, [{active, true}
+ | 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, [{active, true},
+ {verify, verify_none}
+ | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+client_verify_none_active_once() ->
+ [{doc,"Test client option verify_none"}].
+
+client_verify_none_active_once(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, [{active, once} | 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_once,
+ []}},
+ {options, [{active, once},
+ {verify, verify_none}
+ | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+extended_key_usage_verify_peer() ->
+ [{doc,"Test cert that has a critical extended_key_usage extension in verify_peer mode"}].
+
+extended_key_usage_verify_peer(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_verification_opts, Config),
+ ServerOpts = ?config(server_verification_opts, Config),
+ PrivDir = ?config(priv_dir, Config),
+ Active = ?config(active, Config),
+ ReceiveFunction = ?config(receive_function, Config),
+
+ KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
+ [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
+ Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
+
+ ServerCertFile = proplists:get_value(certfile, ServerOpts),
+ NewServerCertFile = filename:join(PrivDir, "server/new_cert.pem"),
+ [{'Certificate', ServerDerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile),
+ ServerOTPCert = public_key:pkix_decode_cert(ServerDerCert, otp),
+ ServerExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-serverAuth']},
+ ServerOTPTbsCert = ServerOTPCert#'OTPCertificate'.tbsCertificate,
+ ServerExtensions = ServerOTPTbsCert#'OTPTBSCertificate'.extensions,
+ NewServerOTPTbsCert = ServerOTPTbsCert#'OTPTBSCertificate'{extensions =
+ [ServerExtKeyUsageExt |
+ ServerExtensions]},
+ NewServerDerCert = public_key:pkix_sign(NewServerOTPTbsCert, Key),
+ ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]),
+ NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)],
+
+ ClientCertFile = proplists:get_value(certfile, ClientOpts),
+ NewClientCertFile = filename:join(PrivDir, "client/new_cert.pem"),
+ [{'Certificate', ClientDerCert, _}] = ssl_test_lib:pem_to_der(ClientCertFile),
+ ClientOTPCert = public_key:pkix_decode_cert(ClientDerCert, otp),
+ ClientExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-clientAuth']},
+ ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate,
+ ClientExtensions = ClientOTPTbsCert#'OTPTBSCertificate'.extensions,
+ NewClientOTPTbsCert = ClientOTPTbsCert#'OTPTBSCertificate'{extensions =
+ [ClientExtKeyUsageExt |
+ ClientExtensions]},
+ NewClientDerCert = public_key:pkix_sign(NewClientOTPTbsCert, Key),
+ ssl_test_lib:der_to_pem(NewClientCertFile, [{'Certificate', NewClientDerCert, not_encrypted}]),
+ NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)],
+
+ {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, ReceiveFunction, []}},
+ {options, [{verify, verify_peer}, {active, Active} | NewServerOpts]}]),
+ 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, ReceiveFunction, []}},
+ {options, [{verify, verify_peer}, {active, Active} |
+ NewClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ 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_none(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_verification_opts, Config),
+ ServerOpts = ?config(server_verification_opts, Config),
+ PrivDir = ?config(priv_dir, Config),
+ Active = ?config(active, Config),
+ ReceiveFunction = ?config(receive_function, Config),
+
+ KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
+ [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
+ Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
+
+ ServerCertFile = proplists:get_value(certfile, ServerOpts),
+ NewServerCertFile = filename:join(PrivDir, "server/new_cert.pem"),
+ [{'Certificate', ServerDerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile),
+ ServerOTPCert = public_key:pkix_decode_cert(ServerDerCert, otp),
+ ServerExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-serverAuth']},
+ ServerOTPTbsCert = ServerOTPCert#'OTPCertificate'.tbsCertificate,
+ ServerExtensions = ServerOTPTbsCert#'OTPTBSCertificate'.extensions,
+ NewServerOTPTbsCert = ServerOTPTbsCert#'OTPTBSCertificate'{extensions =
+ [ServerExtKeyUsageExt |
+ ServerExtensions]},
+ NewServerDerCert = public_key:pkix_sign(NewServerOTPTbsCert, Key),
+ ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]),
+ NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)],
+
+ ClientCertFile = proplists:get_value(certfile, ClientOpts),
+ NewClientCertFile = filename:join(PrivDir, "client/new_cert.pem"),
+ [{'Certificate', ClientDerCert, _}] = ssl_test_lib:pem_to_der(ClientCertFile),
+ ClientOTPCert = public_key:pkix_decode_cert(ClientDerCert, otp),
+ ClientExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-clientAuth']},
+ ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate,
+ ClientExtensions = ClientOTPTbsCert#'OTPTBSCertificate'.extensions,
+ NewClientOTPTbsCert = ClientOTPTbsCert#'OTPTBSCertificate'{extensions =
+ [ClientExtKeyUsageExt |
+ ClientExtensions]},
+ NewClientDerCert = public_key:pkix_sign(NewClientOTPTbsCert, Key),
+ ssl_test_lib:der_to_pem(NewClientCertFile, [{'Certificate', NewClientDerCert, not_encrypted}]),
+ NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)],
+
+ {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, ReceiveFunction, []}},
+ {options, [{verify, verify_none}, {active, Active} | NewServerOpts]}]),
+ 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, ReceiveFunction, []}},
+ {options, [{verify, verify_none}, {active, Active} | NewClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+no_authority_key_identifier() ->
+ [{doc, "Test cert that does not have authorityKeyIdentifier extension"
+ " but are present in trusted certs db."}].
+
+no_authority_key_identifier(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_verification_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ PrivDir = ?config(priv_dir, Config),
+
+ KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
+ [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
+ Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
+
+ CertFile = proplists:get_value(certfile, ServerOpts),
+ NewCertFile = filename:join(PrivDir, "server/new_cert.pem"),
+ [{'Certificate', DerCert, _}] = ssl_test_lib:pem_to_der(CertFile),
+ OTPCert = public_key:pkix_decode_cert(DerCert, otp),
+ OTPTbsCert = OTPCert#'OTPCertificate'.tbsCertificate,
+ Extensions = OTPTbsCert#'OTPTBSCertificate'.extensions,
+ NewExtensions = delete_authority_key_extension(Extensions, []),
+ NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{extensions = NewExtensions},
+
+ ct:print("Extensions ~p~n, NewExtensions: ~p~n", [Extensions, NewExtensions]),
+
+ NewDerCert = public_key:pkix_sign(NewOTPTbsCert, Key),
+ ssl_test_lib:der_to_pem(NewCertFile, [{'Certificate', NewDerCert, not_encrypted}]),
+ NewServerOpts = [{certfile, NewCertFile} | proplists:delete(certfile, ServerOpts)],
+
+ {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, NewServerOpts}]),
+ 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, [{verify, verify_peer} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+delete_authority_key_extension([], Acc) ->
+ lists:reverse(Acc);
+delete_authority_key_extension([#'Extension'{extnID = ?'id-ce-authorityKeyIdentifier'} | Rest],
+ Acc) ->
+ delete_authority_key_extension(Rest, Acc);
+delete_authority_key_extension([Head | Rest], Acc) ->
+ delete_authority_key_extension(Rest, [Head | Acc]).
+
+%%--------------------------------------------------------------------
+
+invalid_signature_server() ->
+ [{doc,"Test server with invalid signature"}].
+
+invalid_signature_server(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_verification_opts, Config),
+ ServerOpts = ?config(server_verification_opts, Config),
+ PrivDir = ?config(priv_dir, Config),
+
+ KeyFile = filename:join(PrivDir, "server/key.pem"),
+ [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
+ Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
+
+ ServerCertFile = proplists:get_value(certfile, ServerOpts),
+ NewServerCertFile = filename:join(PrivDir, "server/invalid_cert.pem"),
+ [{'Certificate', ServerDerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile),
+ ServerOTPCert = public_key:pkix_decode_cert(ServerDerCert, otp),
+ ServerOTPTbsCert = ServerOTPCert#'OTPCertificate'.tbsCertificate,
+ NewServerDerCert = public_key:pkix_sign(ServerOTPTbsCert, Key),
+ ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]),
+ NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)],
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, NewServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {options, [{verify, verify_peer} | ClientOpts]}]),
+
+ tcp_delivery_workaround(Server, {error, "bad certificate"},
+ Client, {error,"bad certificate"}).
+
+%%--------------------------------------------------------------------
+
+invalid_signature_client() ->
+ [{doc,"Test server with invalid signature"}].
+
+invalid_signature_client(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_verification_opts, Config),
+ ServerOpts = ?config(server_verification_opts, Config),
+ PrivDir = ?config(priv_dir, Config),
+
+ KeyFile = filename:join(PrivDir, "client/key.pem"),
+ [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
+ Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
+
+ ClientCertFile = proplists:get_value(certfile, ClientOpts),
+ NewClientCertFile = filename:join(PrivDir, "client/invalid_cert.pem"),
+ [{'Certificate', ClientDerCert, _}] = ssl_test_lib:pem_to_der(ClientCertFile),
+ ClientOTPCert = public_key:pkix_decode_cert(ClientDerCert, otp),
+ ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate,
+ NewClientDerCert = public_key:pkix_sign(ClientOTPTbsCert, Key),
+ ssl_test_lib:der_to_pem(NewClientCertFile, [{'Certificate', NewClientDerCert, not_encrypted}]),
+ 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()},
+ {options, [{verify, verify_peer} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {options, NewClientOpts}]),
+
+ tcp_delivery_workaround(Server, {error, "bad certificate"},
+ Client, {error,"bad certificate"}).
+
+
+%%--------------------------------------------------------------------
+
+client_with_cert_cipher_suites_handshake() ->
+ [{doc, "Test that client with a certificate without keyEncipherment usage "
+ " extension can connect to a server with restricted cipher suites "}].
+client_with_cert_cipher_suites_handshake(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_verification_opts_digital_signature_only, Config),
+ ServerOpts = ?config(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()}
+ | 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, [{active, true}
+ | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+
+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 = ?config(server_opts, Config),
+ {_, ServerNode, _} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, [{verify, verify_peer}
+ | ServerOpts]}]),
+
+ ssl_test_lib:check_result(Server, {error, {eoptions, {cacertfile, ""}}}).
+
+
+%%--------------------------------------------------------------------
+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 = ?config(client_opts, Config),
+ ServerOpts = ?config(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()},
+ {mfa, {ssl_test_lib,
+ no_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ FunAndState = {fun(_,{bad_cert, unknown_ca} = Reason, _) ->
+ {fail, Reason};
+ (_,{extension, _}, UserState) ->
+ {unknown, UserState};
+ (_, valid, UserState) ->
+ {valid, [test_to_update_user_state | UserState]};
+ (_, valid_peer, UserState) ->
+ {valid, UserState}
+ end, []},
+
+ Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ no_result, []}},
+ {options,
+ [{verify, verify_peer},
+ {verify_fun, FunAndState}
+ | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, {error,"unknown ca"},
+ Client, {error, "unknown ca"}).
+
+%%--------------------------------------------------------------------
+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 = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ send_recv_result_active, []}},
+ {options,
+ [{verify, verify_none}| ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+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 = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ FunAndState = {fun(_,{bad_cert, unknown_ca}, UserState) ->
+ {valid, UserState};
+ (_,{bad_cert, _} = Reason, _) ->
+ {fail, Reason};
+ (_,{extension, _}, UserState) ->
+ {unknown, UserState};
+ (_, valid, UserState) ->
+ {valid, UserState};
+ (_, valid_peer, UserState) ->
+ {valid, UserState}
+ end, []},
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ send_recv_result_active, []}},
+ {options,
+ [{verify, verify_peer},
+ {verify_fun, FunAndState}| ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+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 = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ AcceptBadCa = fun({bad_cert,unknown_ca}, Acc) -> Acc;
+ (Other, Acc) -> [Other | Acc]
+ end,
+ VerifyFun =
+ fun(ErrorList) ->
+ case lists:foldl(AcceptBadCa, [], ErrorList) of
+ [] -> true;
+ [_|_] -> false
+ end
+ end,
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ send_recv_result_active, []}},
+ {options,
+ [{verify, verify_peer},
+ {verify_fun, VerifyFun}| ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
+
+tcp_delivery_workaround(Server, ServerMsg, Client, ClientMsg) ->
+ receive
+ {Server, ServerMsg} ->
+ client_msg(Client, ClientMsg);
+ {Client, ClientMsg} ->
+ server_msg(Server, ServerMsg);
+ {Client, {error,closed}} ->
+ server_msg(Server, ServerMsg);
+ {Server, {error,closed}} ->
+ client_msg(Client, ClientMsg);
+ {Client, {error, esslconnect}} ->
+ server_msg(Server, ServerMsg);
+ {Server, {error, esslaccept}} ->
+ client_msg(Client, ClientMsg)
+ end.
+
+client_msg(Client, ClientMsg) ->
+ receive
+ {Client, ClientMsg} ->
+ ok;
+ {Client, {error,closed}} ->
+ ct:print("client got close"),
+ ok;
+ {Client, {error, esslconnect}} ->
+ ct:print("client got econnaborted"),
+ ok;
+ Unexpected ->
+ ct:fail(Unexpected)
+ end.
+server_msg(Server, ServerMsg) ->
+ receive
+ {Server, ServerMsg} ->
+ ok;
+ {Server, {error,closed}} ->
+ ct:print("server got close"),
+ ok;
+ {Server, {error, esslaccept}} ->
+ ct:print("server got econnaborted"),
+ ok;
+ Unexpected ->
+ ct:fail(Unexpected)
+ end.
diff --git a/lib/ssl/test/ssl_cipher_SUITE.erl b/lib/ssl/test/ssl_cipher_SUITE.erl
index ea1d9dc90c..9869812e6e 100644
--- a/lib/ssl/test/ssl_cipher_SUITE.erl
+++ b/lib/ssl/test/ssl_cipher_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -31,16 +31,18 @@
-define(TIMEOUT, 600000).
-%% Test server callback functions
%%--------------------------------------------------------------------
-%% Function: init_per_suite(Config) -> Config
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Initialization before the whole suite
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
+%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [aes_decipher_good, aes_decipher_good_tls11, aes_decipher_fail, aes_decipher_fail_tls11].
+
+groups() ->
+ [].
+
init_per_suite(Config) ->
try crypto:start() of
ok ->
@@ -48,81 +50,30 @@ init_per_suite(Config) ->
catch _:_ ->
{skip, "Crypto did not start"}
end.
-%%--------------------------------------------------------------------
-%% Function: end_per_suite(Config) -> _
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after the whole suite
-%%--------------------------------------------------------------------
+
end_per_suite(_Config) ->
ssl:stop(),
application:stop(crypto).
-%%--------------------------------------------------------------------
-%% Function: init_per_testcase(TestCase, Config) -> Config
-%% Case - atom()
-%% Name of the test case that is about to be run.
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%%
-%% Description: Initialization before each test case
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
-%% Description: Initialization before each test case
-%%--------------------------------------------------------------------
-init_per_testcase(_TestCase, Config0) ->
- Config = lists:keydelete(watchdog, 1, Config0),
- Dog = ssl_test_lib:timetrap(?TIMEOUT),
- [{watchdog, Dog} | Config].
-
-%%--------------------------------------------------------------------
-%% Function: end_per_testcase(TestCase, Config) -> _
-%% Case - atom()
-%% Name of the test case that is about to be run.
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after each test case
-%%--------------------------------------------------------------------
-end_per_testcase(_TestCase, Config) ->
- Dog = ?config(watchdog, Config),
- case Dog of
- undefined ->
- ok;
- _ ->
- test_server:timetrap_cancel(Dog)
- end.
-
-%%--------------------------------------------------------------------
-%% Function: all(Clause) -> TestCases
-%% Clause - atom() - suite | doc
-%% TestCases - [Case]
-%% Case - atom()
-%% Name of a test case.
-%% Description: Returns a list of all test cases in this test suite
-%%--------------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- [aes_decipher_good, aes_decipher_good_tls11, aes_decipher_fail, aes_decipher_fail_tls11].
-
-groups() ->
- [].
-
init_per_group(_GroupName, Config) ->
Config.
end_per_group(_GroupName, Config) ->
Config.
+init_per_testcase(_TestCase, Config0) ->
+ Config = lists:keydelete(watchdog, 1, Config0),
+ Dog = ct:timetrap(?TIMEOUT),
+ [{watchdog, Dog} | Config].
-%% Test cases starts here.
-%%--------------------------------------------------------------------
-aes_decipher_good(doc) ->
- ["Decipher a known cryptotext."];
+end_per_testcase(_TestCase, Config) ->
+ Config.
-aes_decipher_good(suite) ->
- [];
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+aes_decipher_good() ->
+ [{doc,"Decipher a known cryptotext."}].
aes_decipher_good(Config) when is_list(Config) ->
HashSz = 32,
@@ -142,11 +93,8 @@ aes_decipher_good(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-aes_decipher_good_tls11(doc) ->
- ["Decipher a known TLS 1.1 cryptotext."];
-
-aes_decipher_good_tls11(suite) ->
- [];
+aes_decipher_good_tls11() ->
+ [{doc,"Decipher a known TLS 1.1 cryptotext."}].
%% the fragment is actuall a TLS 1.1 record, with
%% Version = TLS 1.1, we get the correct NextIV in #cipher_state
@@ -169,11 +117,8 @@ aes_decipher_good_tls11(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-aes_decipher_fail(doc) ->
- ["Decipher a known cryptotext."];
-
-aes_decipher_fail(suite) ->
- [];
+aes_decipher_fail() ->
+ [{doc,"Decipher a known cryptotext."}].
%% same as above, last byte of key replaced
aes_decipher_fail(Config) when is_list(Config) ->
@@ -196,11 +141,8 @@ aes_decipher_fail(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-aes_decipher_fail_tls11(doc) ->
- ["Decipher a known TLS 1.1 cryptotext."];
-
-aes_decipher_fail_tls11(suite) ->
- [];
+aes_decipher_fail_tls11() ->
+ [{doc,"Decipher a known TLS 1.1 cryptotext."}].
%% same as above, last byte of key replaced
%% stricter padding checks in TLS 1.1 mean we get an alert instead
@@ -213,9 +155,11 @@ aes_decipher_fail_tls11(Config) when is_list(Config) ->
198,181,81,19,98,162,213,228,74,224,253,168,156,59,195,122,
108,101,107,242,20,15,169,150,163,107,101,94,93,104,241,165>>,
Version = {3,2},
- #alert{level = ?FATAL, description = ?BAD_RECORD_MAC} = ssl_cipher:decipher(?AES, HashSz, CipherState, Fragment, Version),
+ #alert{level = ?FATAL, description = ?BAD_RECORD_MAC} =
+ ssl_cipher:decipher(?AES, HashSz, CipherState, Fragment, Version),
Version1 = {3,3},
- #alert{level = ?FATAL, description = ?BAD_RECORD_MAC} = ssl_cipher:decipher(?AES, HashSz, CipherState, Fragment, Version1),
+ #alert{level = ?FATAL, description = ?BAD_RECORD_MAC} =
+ ssl_cipher:decipher(?AES, HashSz, CipherState, Fragment, Version1),
ok.
%%--------------------------------------------------------------------
diff --git a/lib/ssl/test/ssl_dist_SUITE.erl b/lib/ssl/test/ssl_dist_SUITE.erl
index 818f7f1897..7bfd678f4b 100644
--- a/lib/ssl/test/ssl_dist_SUITE.erl
+++ b/lib/ssl/test/ssl_dist_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -19,7 +19,7 @@
-module(ssl_dist_SUITE).
--include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct.hrl").
%% Note: This directive should only be used in test suites.
-compile(export_all).
@@ -35,7 +35,10 @@
nodename}
).
-%% Test server callback functions
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
suite() ->
[{ct_hooks,[ts_install_cth]}].
@@ -54,6 +57,7 @@ end_per_group(_GroupName, Config) ->
init_per_suite(Config0) ->
try crypto:start() of
ok ->
+ %% Currently no ct function avilable for is_cover!
case test_server:is_cover() of
false ->
Config = add_ssl_opts_config(Config0),
@@ -98,11 +102,13 @@ common_end(_, Config) ->
Dog = ?config(watchdog, Config),
?t:timetrap_cancel(Dog),
ok.
+
%%--------------------------------------------------------------------
-%% Test cases starts here.
+%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------
-basic(doc) ->
- ["Test that two nodes can connect via ssl distribution"];
+
+basic() ->
+ [{doc,"Test that two nodes can connect via ssl distribution"}].
basic(Config) when is_list(Config) ->
NH1 = start_ssl_node(Config),
Node1 = NH1#node_handle.nodename,
@@ -162,8 +168,8 @@ basic(Config) when is_list(Config) ->
success(Config).
%%--------------------------------------------------------------------
-payload(doc) ->
- ["Test that send a lot of data between the ssl distributed noes"];
+payload() ->
+ [{doc,"Test that send a lot of data between the ssl distributed noes"}].
payload(Config) when is_list(Config) ->
NH1 = start_ssl_node(Config),
Node1 = NH1#node_handle.nodename,
@@ -204,8 +210,8 @@ payload(Config) when is_list(Config) ->
stop_ssl_node(NH2),
success(Config).
%%--------------------------------------------------------------------
-plain_options(doc) ->
- ["Test specifying additional options"];
+plain_options() ->
+ [{doc,"Test specifying additional options"}].
plain_options(Config) when is_list(Config) ->
DistOpts = "-ssl_dist_opt server_secure_renegotiate true "
"client_secure_renegotiate true "
@@ -228,8 +234,8 @@ plain_options(Config) when is_list(Config) ->
stop_ssl_node(NH2),
success(Config).
%%--------------------------------------------------------------------
-plain_verify_options(doc) ->
- ["Test specifying additional options"];
+plain_verify_options() ->
+ [{doc,"Test specifying additional options"}].
plain_verify_options(Config) when is_list(Config) ->
DistOpts = "-ssl_dist_opt server_secure_renegotiate true "
"client_secure_renegotiate true "
@@ -251,7 +257,7 @@ plain_verify_options(Config) when is_list(Config) ->
success(Config).
%%--------------------------------------------------------------------
-%%% Internal functions
+%%% Internal functions -----------------------------------------------
%%--------------------------------------------------------------------
%% ssl_node side api
diff --git a/lib/ssl/test/ssl_handshake_SUITE.erl b/lib/ssl/test/ssl_handshake_SUITE.erl
index 363a0be594..aff0e0fbbc 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-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -27,6 +27,9 @@
-include("ssl_internal.hrl").
-include("ssl_handshake.hrl").
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
suite() -> [{ct_hooks,[ts_install_cth]}].
all() -> [
@@ -34,6 +37,9 @@ all() -> [
decode_single_hello_extension_correctly,
decode_unknown_hello_extension_correctly].
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
decode_hello_handshake(_Config) ->
HelloPacket = <<16#02, 16#00, 16#00,
16#44, 16#03, 16#03, 16#4e, 16#7f, 16#c1, 16#03, 16#35,
diff --git a/lib/ssl/test/ssl_npn_handshake_SUITE.erl b/lib/ssl/test/ssl_npn_handshake_SUITE.erl
index 8597aa6740..4e848095a5 100644
--- a/lib/ssl/test/ssl_npn_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_npn_handshake_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -24,6 +24,10 @@
-compile(export_all).
-include_lib("common_test/include/ct.hrl").
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
@@ -68,7 +72,7 @@ init_per_suite(Config) ->
Result =
(catch make_certs:all(?config(data_dir, Config),
?config(priv_dir, Config))),
- test_server:format("Make certs ~p~n", [Result]),
+ ct:print("Make certs ~p~n", [Result]),
ssl_test_lib:cert_options(Config)
catch _:_ ->
{skip, "Crypto did not start"}
@@ -94,12 +98,11 @@ init_per_group(GroupName, Config) ->
Config
end.
-
end_per_group(_GroupName, Config) ->
Config.
-
-%% Test cases starts here.
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------
validate_empty_protocols_are_not_allowed(Config) when is_list(Config) ->
@@ -229,9 +232,8 @@ npn_not_supported_server(Config) when is_list(Config)->
{error, {eoptions, {not_supported_in_sslv3, AdvProtocols}}} = ssl:listen(0, ServerOpts).
%%--------------------------------------------------------------------
-%%% Internal functions
+%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
-
run_npn_handshake(Config, ClientExtraOpts, ServerExtraOpts, ExpectedProtocol) ->
Data = "hello world",
@@ -257,13 +259,13 @@ run_npn_handshake(Config, ClientExtraOpts, ServerExtraOpts, ExpectedProtocol) ->
assert_npn(Socket, Protocol) ->
- test_server:format("Negotiated Protocol ~p, Expecting: ~p ~n",
+ ct:print("Negotiated Protocol ~p, Expecting: ~p ~n",
[ssl:negotiated_next_protocol(Socket), Protocol]),
Protocol = ssl:negotiated_next_protocol(Socket).
assert_npn_and_renegotiate_and_send_data(Socket, Protocol, Data) ->
assert_npn(Socket, Protocol),
- test_server:format("Renegotiating ~n", []),
+ ct:print("Renegotiating ~n", []),
ok = ssl:renegotiate(Socket),
ssl:send(Socket, Data),
assert_npn(Socket, Protocol),
@@ -278,7 +280,7 @@ ssl_receive_and_assert_npn(Socket, Protocol, Data) ->
ssl_receive(Socket, Data).
ssl_send(Socket, Data) ->
- test_server:format("Connection info: ~p~n",
+ ct:print("Connection info: ~p~n",
[ssl:connection_info(Socket)]),
ssl:send(Socket, Data).
@@ -286,11 +288,11 @@ ssl_receive(Socket, Data) ->
ssl_receive(Socket, Data, []).
ssl_receive(Socket, Data, Buffer) ->
- test_server:format("Connection info: ~p~n",
+ ct:print("Connection info: ~p~n",
[ssl:connection_info(Socket)]),
receive
{ssl, Socket, MoreData} ->
- test_server:format("Received ~p~n",[MoreData]),
+ ct:print("Received ~p~n",[MoreData]),
NewBuffer = Buffer ++ MoreData,
case NewBuffer of
Data ->
@@ -300,9 +302,9 @@ ssl_receive(Socket, Data, Buffer) ->
ssl_receive(Socket, Data, NewBuffer)
end;
Other ->
- test_server:fail({unexpected_message, Other})
+ ct:fail({unexpected_message, Other})
after 4000 ->
- test_server:fail({did_not_get, Data})
+ ct:fail({did_not_get, Data})
end.
diff --git a/lib/ssl/test/ssl_npn_hello_SUITE.erl b/lib/ssl/test/ssl_npn_hello_SUITE.erl
index 5102c74e87..72768bcb55 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-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -27,6 +27,10 @@
-include("ssl_record.hrl").
-include_lib("common_test/include/ct.hrl").
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
@@ -37,44 +41,26 @@ all() ->
create_server_hello_with_advertised_protocols_test,
create_server_hello_with_no_advertised_protocols_test].
-
-create_client_handshake(Npn) ->
- ssl_handshake:encode_handshake(#client_hello{
- client_version = {1, 2},
- random = <<1:256>>,
- session_id = <<>>,
- cipher_suites = "",
- compression_methods = "",
- next_protocol_negotiation = Npn,
- renegotiation_info = #renegotiation_info{}
- }, vsn).
-
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
encode_and_decode_client_hello_test(_Config) ->
HandShakeData = create_client_handshake(undefined),
Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
- {[{DecodedHandshakeMessage, _Raw}], _} = ssl_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>),
+ {[{DecodedHandshakeMessage, _Raw}], _} =
+ ssl_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>),
NextProtocolNegotiation = DecodedHandshakeMessage#client_hello.next_protocol_negotiation,
NextProtocolNegotiation = undefined.
-
+%%--------------------------------------------------------------------
encode_and_decode_npn_client_hello_test(_Config) ->
HandShakeData = create_client_handshake(#next_protocol_negotiation{extension_data = <<>>}),
Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
- {[{DecodedHandshakeMessage, _Raw}], _} = ssl_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>),
+ {[{DecodedHandshakeMessage, _Raw}], _} =
+ ssl_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>),
NextProtocolNegotiation = DecodedHandshakeMessage#client_hello.next_protocol_negotiation,
NextProtocolNegotiation = #next_protocol_negotiation{extension_data = <<>>}.
-
-create_server_handshake(Npn) ->
- ssl_handshake:encode_handshake(#server_hello{
- server_version = {1, 2},
- random = <<1:256>>,
- session_id = <<>>,
- cipher_suite = <<1,2>>,
- compression_method = 1,
- next_protocol_negotiation = Npn,
- renegotiation_info = #renegotiation_info{}
- }, vsn).
-
+%%--------------------------------------------------------------------
encode_and_decode_server_hello_test(_Config) ->
HandShakeData = create_server_handshake(undefined),
Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
@@ -82,15 +68,51 @@ encode_and_decode_server_hello_test(_Config) ->
ssl_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>),
NextProtocolNegotiation = DecodedHandshakeMessage#server_hello.next_protocol_negotiation,
NextProtocolNegotiation = undefined.
-
+%%--------------------------------------------------------------------
encode_and_decode_npn_server_hello_test(_Config) ->
HandShakeData = create_server_handshake(#next_protocol_negotiation{extension_data = <<6, "spdy/2">>}),
Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
- {[{DecodedHandshakeMessage, _Raw}], _} = ssl_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>),
+ {[{DecodedHandshakeMessage, _Raw}], _} =
+ ssl_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>),
NextProtocolNegotiation = DecodedHandshakeMessage#server_hello.next_protocol_negotiation,
ct:print("~p ~n", [NextProtocolNegotiation]),
NextProtocolNegotiation = #next_protocol_negotiation{extension_data = <<6, "spdy/2">>}.
+%%--------------------------------------------------------------------
+create_server_hello_with_no_advertised_protocols_test(_Config) ->
+ Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(), false, undefined),
+ undefined = Hello#server_hello.next_protocol_negotiation.
+%%--------------------------------------------------------------------
+create_server_hello_with_advertised_protocols_test(_Config) ->
+ Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(),
+ false, [<<"spdy/1">>, <<"http/1.0">>, <<"http/1.1">>]),
+ #next_protocol_negotiation{extension_data = <<6, "spdy/1", 8, "http/1.0", 8, "http/1.1">>} =
+ Hello#server_hello.next_protocol_negotiation.
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
+create_client_handshake(Npn) ->
+ ssl_handshake:encode_handshake(#client_hello{
+ client_version = {1, 2},
+ random = <<1:256>>,
+ session_id = <<>>,
+ cipher_suites = "",
+ compression_methods = "",
+ next_protocol_negotiation = Npn,
+ renegotiation_info = #renegotiation_info{}
+ }, vsn).
+
+create_server_handshake(Npn) ->
+ ssl_handshake:encode_handshake(#server_hello{
+ server_version = {1, 2},
+ random = <<1:256>>,
+ session_id = <<>>,
+ cipher_suite = <<1,2>>,
+ compression_method = 1,
+ next_protocol_negotiation = Npn,
+ renegotiation_info = #renegotiation_info{}
+ }, vsn).
+
create_connection_states() ->
#connection_states{
pending_read = #connection_state{
@@ -105,13 +127,3 @@ create_connection_states() ->
secure_renegotiation = false
}
}.
-
-create_server_hello_with_no_advertised_protocols_test(_Config) ->
- Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(), false, undefined),
- undefined = Hello#server_hello.next_protocol_negotiation.
-
-create_server_hello_with_advertised_protocols_test(_Config) ->
- Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(),
- false, [<<"spdy/1">>, <<"http/1.0">>, <<"http/1.1">>]),
- #next_protocol_negotiation{extension_data = <<6, "spdy/1", 8, "http/1.0", 8, "http/1.1">>} =
- Hello#server_hello.next_protocol_negotiation.
diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl
index 8ce80cb725..158c40e372 100644
--- a/lib/ssl/test/ssl_packet_SUITE.erl
+++ b/lib/ssl/test/ssl_packet_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -41,84 +41,10 @@
-define(MANY, 1000).
-define(SOME, 50).
-
-%% Test server callback functions
%%--------------------------------------------------------------------
-%% Function: init_per_suite(Config) -> Config
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Initialization before the whole suite
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
+%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
-init_per_suite(Config) ->
- catch crypto:stop(),
- try crypto:start() of
- ok ->
- application:start(public_key),
- ssl:start(),
- Result =
- (catch make_certs:all(?config(data_dir, Config),
- ?config(priv_dir, Config))),
- test_server:format("Make certs ~p~n", [Result]),
- ssl_test_lib:cert_options(Config)
- catch _:_ ->
- {skip, "Crypto did not start"}
- end.
-%%--------------------------------------------------------------------
-%% Function: end_per_suite(Config) -> _
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after the whole suite
-%%--------------------------------------------------------------------
-end_per_suite(_Config) ->
- ssl:stop(),
- application:stop(crypto).
-%%--------------------------------------------------------------------
-%% Function: init_per_testcase(TestCase, Config) -> Config
-%% Case - atom()
-%% Name of the test case that is about to be run.
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%%
-%% Description: Initialization before each test case
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
-%% Description: Initialization before each test case
-%%--------------------------------------------------------------------
-init_per_testcase(_TestCase, Config0) ->
- Config = lists:keydelete(watchdog, 1, Config0),
- Dog = ssl_test_lib:timetrap(?TIMEOUT),
- [{watchdog, Dog} | Config].
-
-%%--------------------------------------------------------------------
-%% Function: end_per_testcase(TestCase, Config) -> _
-%% Case - atom()
-%% Name of the test case that is about to be run.
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after each test case
-%%--------------------------------------------------------------------
-end_per_testcase(_TestCase, Config) ->
- Dog = ?config(watchdog, Config),
- case Dog of
- undefined ->
- ok;
- _ ->
- test_server:timetrap_cancel(Dog)
- end.
-
-%%--------------------------------------------------------------------
-%% Function: all(Clause) -> TestCases
-%% Clause - atom() - suite | doc
-%% TestCases - [Case]
-%% Case - atom()
-%% Name of a test case.
-%% Description: Returns a list of all test cases in this test suite
-%%--------------------------------------------------------------------
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
@@ -129,12 +55,6 @@ all() ->
{group, 'sslv3'}
].
-groups() ->
- [{'tlsv1.2', [], packet_tests()},
- {'tlsv1.1', [], packet_tests()},
- {'tlsv1', [], packet_tests()},
- {'sslv3', [], packet_tests()}].
-
packet_tests() ->
active_packet_tests() ++ active_once_packet_tests() ++ passive_packet_tests() ++
[packet_send_to_large,
@@ -208,6 +128,24 @@ active_packet_tests() ->
header_decode_two_bytes_one_sent_active
].
+init_per_suite(Config) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ application:start(public_key),
+ ssl:start(),
+ Result =
+ (catch make_certs:all(?config(data_dir, Config),
+ ?config(priv_dir, Config))),
+ ct:print("Make certs ~p~n", [Result]),
+ ssl_test_lib:cert_options(Config)
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto).
init_per_group(GroupName, Config) ->
case ssl_test_lib:is_tls_version(GroupName) of
@@ -228,1032 +166,262 @@ init_per_group(GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
+init_per_testcase(_TestCase, Config0) ->
+ Config = lists:keydelete(watchdog, 1, Config0),
+ Dog = ct:timetrap(?TIMEOUT),
+ [{watchdog, Dog} | Config].
-%% Test cases starts here.
-%%--------------------------------------------------------------------
-packet_raw_passive_many_small(doc) ->
- ["Test packet option {packet, raw} in passive mode."];
-
-packet_raw_passive_many_small(suite) ->
- [];
-packet_raw_passive_many_small(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "Packet option is {packet, raw}",
+end_per_testcase(_TestCase, Config) ->
+ Config.
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send_raw ,[Data, ?MANY]}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, passive_raw, [Data, ?MANY]}},
- {options,
- [{active, false},
- {packet, raw} |
- ClientOpts]}]),
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
- ssl_test_lib:check_result(Client, ok),
+packet_raw_passive_many_small() ->
+ [{doc,"Test packet option {packet, raw} in passive mode."}].
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
+packet_raw_passive_many_small(Config) when is_list(Config) ->
+ Data = "Packet option is {packet, raw}",
+ packet(Config, Data, send, passive_recv_packet, ?MANY, raw, false).
%%--------------------------------------------------------------------
-packet_raw_passive_some_big(doc) ->
- ["Test packet option {packet, raw} in passive mode."];
-
-packet_raw_passive_some_big(suite) ->
- [];
-
-packet_raw_passive_some_big(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+packet_raw_passive_some_big() ->
+ [{doc,"Test packet option {packet, raw} in passive mode."}].
+packet_raw_passive_some_big(Config) when is_list(Config) ->
Data = lists:append(lists:duplicate(100, "1234567890")),
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send_raw ,[Data, ?SOME]}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, passive_raw, [Data, ?SOME]}},
- {options,
- [{active, false},
- {packet, raw} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
+ packet(Config, Data, send, passive_recv_packet, ?SOME, raw, false).
%%--------------------------------------------------------------------
-packet_0_passive_many_small(doc) ->
- ["Test packet option {packet, 0} in passive mode."];
-
-packet_0_passive_many_small(suite) ->
- [];
-
-packet_0_passive_many_small(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+packet_0_passive_many_small() ->
+ [{doc,"Test packet option {packet, 0} in passive mode."}].
+packet_0_passive_many_small(Config) when is_list(Config) ->
Data = "Packet option is {packet, 0}, equivalent to packet raw.",
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send_raw ,[Data, ?MANY]}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, passive_raw, [Data, ?MANY]}},
- {options, [{active, false},
- {packet, 0} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
+ packet(Config, Data, send, passive_recv_packet, ?MANY, 0, false).
%%--------------------------------------------------------------------
-packet_0_passive_some_big(doc) ->
- ["Test packet option {packet, 0} in passive mode."];
-
-packet_0_passive_some_big(suite) ->
- [];
-
-packet_0_passive_some_big(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+packet_0_passive_some_big() ->
+ [{doc,"Test packet option {packet, 0} in passive mode."}].
+packet_0_passive_some_big(Config) when is_list(Config) ->
Data = lists:append(lists:duplicate(100, "1234567890")),
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send_raw ,[Data, ?SOME]}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, passive_raw, [Data, ?SOME]}},
- {options, [{active, false},
- {packet, 0} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
+ packet(Config, Data, send, passive_recv_packet, ?SOME, 0, false).
%%--------------------------------------------------------------------
-packet_1_passive_many_small(doc) ->
- ["Test packet option {packet, 1} in passive mode."];
-
-packet_1_passive_many_small(suite) ->
- [];
-
-packet_1_passive_many_small(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+packet_1_passive_many_small() ->
+ [{doc,"Test packet option {packet, 1} in passive mode."}].
+packet_1_passive_many_small(Config) when is_list(Config) ->
Data = "Packet option is {packet, 1}",
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send, [Data, ?MANY]}},
- {options, [{packet, 1}|ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, passive_recv_packet,
- [Data, ?MANY]}},
- {options, [{active, false},
- {packet, 1} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
+ packet(Config, Data, send, passive_recv_packet, ?MANY, 1, false).
%%--------------------------------------------------------------------
-packet_1_passive_some_big(doc) ->
- ["Test packet option {packet, 1} in passive mode."];
-
-packet_1_passive_some_big(suite) ->
- [];
-
-packet_1_passive_some_big(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+packet_1_passive_some_big() ->
+ [{doc,"Test packet option {packet, 1} in passive mode."}].
+packet_1_passive_some_big(Config) when is_list(Config) ->
Data = lists:append(lists:duplicate(255, "1")),
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send, [Data, ?SOME]}},
- {options, [{packet, 1}|ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, passive_recv_packet,
- [Data, ?SOME]}},
- {options, [{active, false},
- {packet, 1} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
+ packet(Config, Data, send, passive_recv_packet, ?SOME, 1, false).
%%--------------------------------------------------------------------
-packet_2_passive_many_small(doc) ->
- ["Test packet option {packet, 2} in passive mode"];
-
-packet_2_passive_many_small(suite) ->
- [];
-
-packet_2_passive_many_small(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+packet_2_passive_many_small() ->
+ [{doc,"Test packet option {packet, 2} in passive mode"}].
+packet_2_passive_many_small(Config) when is_list(Config) ->
Data = "Packet option is {packet, 2}",
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send, [Data, ?MANY]}},
- {options, [{packet, 2}|ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, passive_recv_packet,
- [Data, ?MANY]}},
- {options, [{active, false},
- {packet, 2} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
+ packet(Config, Data, send, passive_recv_packet, ?MANY, 2, false).
%%--------------------------------------------------------------------
-packet_2_passive_some_big(doc) ->
- ["Test packet option {packet, 2} in passive mode"];
-
-packet_2_passive_some_big(suite) ->
- [];
-
-packet_2_passive_some_big(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+packet_2_passive_some_big() ->
+ [{doc,"Test packet option {packet, 2} in passive mode"}].
+packet_2_passive_some_big(Config) when is_list(Config) ->
Data = lists:append(lists:duplicate(100, "1234567890")),
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send, [Data, ?SOME]}},
- {options, [{packet, 2}|ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, passive_recv_packet,
- [Data, ?SOME]}},
- {options, [{active, false},
- {packet, 2} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
+ packet(Config, Data, send, passive_recv_packet, ?SOME, 2, false).
%%--------------------------------------------------------------------
-packet_4_passive_many_small(doc) ->
- ["Test packet option {packet, 4} in passive mode"];
-
-packet_4_passive_many_small(suite) ->
- [];
-
-packet_4_passive_many_small(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+packet_4_passive_many_small() ->
+ [{doc,"Test packet option {packet, 4} in passive mode"}].
+packet_4_passive_many_small(Config) when is_list(Config) ->
Data = "Packet option is {packet, 4}",
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa,
- {?MODULE, send, [Data, ?MANY]}},
- {options, [{packet, 4}|ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, passive_recv_packet,
- [Data, ?MANY]}},
- {options, [{active, false},
- {packet, 4} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
+ packet(Config, Data, send, passive_recv_packet, ?MANY, 4, false).
%%--------------------------------------------------------------------
-packet_4_passive_some_big(doc) ->
- ["Test packet option {packet, 4} in passive mode"];
-
-packet_4_passive_some_big(suite) ->
- [];
-
-packet_4_passive_some_big(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+packet_4_passive_some_big() ->
+ [{doc,"Test packet option {packet, 4} in passive mode"}].
+packet_4_passive_some_big(Config) when is_list(Config) ->
Data = lists:append(lists:duplicate(100, "1234567890")),
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send, [Data, ?SOME]}},
- {options, [{packet, 4}|ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, passive_recv_packet,
- [Data, ?SOME]}},
- {options, [{active, false},
- {packet, 4} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
+ packet(Config, Data, send, passive_recv_packet, ?SOME, 4, false).
%%--------------------------------------------------------------------
-packet_raw_active_once_many_small(doc) ->
- ["Test packet option {packet, raw} in active once mode."];
-
-packet_raw_active_once_many_small(suite) ->
- [];
-
-packet_raw_active_once_many_small(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+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) ->
Data = "Packet option is {packet, raw}",
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send_raw ,[Data, ?MANY]}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, active_once_raw,
- [Data, ?MANY]}},
- {options, [{active, once},
- {packet, raw} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
+ packet(Config, Data, send_raw, active_once_raw, ?MANY, raw, once).
%%--------------------------------------------------------------------
-packet_raw_active_once_some_big(doc) ->
- ["Test packet option {packet, raw} in active once mode."];
-
-packet_raw_active_once_some_big(suite) ->
- [];
-
-packet_raw_active_once_some_big(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+packet_raw_active_once_some_big() ->
+ [{doc,"Test packet option {packet, raw} in active once mode."}].
+packet_raw_active_once_some_big(Config) when is_list(Config) ->
Data = lists:append(lists:duplicate(100, "1234567890")),
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send_raw ,[Data, ?SOME]}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, active_once_raw,
- [Data, ?SOME]}},
- {options, [{active, once},
- {packet, raw} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
+ packet(Config, Data, send_raw, active_once_raw, ?SOME, raw, once).
%%--------------------------------------------------------------------
-packet_0_active_once_many_small(doc) ->
- ["Test packet option {packet, 0} in active once mode."];
-
-packet_0_active_once_many_small(suite) ->
- [];
-
-packet_0_active_once_many_small(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+packet_0_active_once_many_small() ->
+ [{doc,"Test packet option {packet, 0} in active once mode."}].
+packet_0_active_once_many_small(Config) when is_list(Config) ->
Data = "Packet option is {packet, 0}",
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send_raw ,[Data, ?MANY]}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa,
- {?MODULE, active_once_raw,
- [Data, ?MANY]}},
- {options, [{active, once},
- {packet, 0} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
+ packet(Config, Data, send_raw, active_once_raw, ?MANY, 0, once).
%%--------------------------------------------------------------------
-packet_0_active_once_some_big(doc) ->
- ["Test packet option {packet, 0} in active once mode."];
-
-packet_0_active_once_some_big(suite) ->
- [];
-
-packet_0_active_once_some_big(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+packet_0_active_once_some_big() ->
+ [{doc,"Test packet option {packet, 0} in active once mode."}].
+packet_0_active_once_some_big(Config) when is_list(Config) ->
Data = lists:append(lists:duplicate(100, "1234567890")),
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send_raw ,
- [Data, ?SOME]}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa,
- {?MODULE, active_once_raw,
- [Data, ?SOME]}},
- {options, [{active, once},
- {packet, 0} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
+ packet(Config, Data, send_raw, active_once_raw, ?SOME, 0, once).
%%--------------------------------------------------------------------
-packet_1_active_once_many_small(doc) ->
- ["Test packet option {packet, 1} in active once mode."];
-
-packet_1_active_once_many_small(suite) ->
- [];
-
-packet_1_active_once_many_small(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+packet_1_active_once_many_small() ->
+ [{doc,"Test packet option {packet, 1} in active once mode."}].
+packet_1_active_once_many_small(Config) when is_list(Config) ->
Data = "Packet option is {packet, 1}",
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send, [Data, ?MANY]}},
- {options, [{packet, 1}|ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa,
- {?MODULE,
- active_once_packet,
- [Data, ?MANY]}},
- {options, [{active, once},
- {packet, 1} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
+ packet(Config, Data, send_raw, active_once_raw, ?MANY, 1, once).
%%--------------------------------------------------------------------
-packet_1_active_once_some_big(doc) ->
- ["Test packet option {packet, 1} in active once mode."];
-
-packet_1_active_once_some_big(suite) ->
- [];
-
-packet_1_active_once_some_big(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+packet_1_active_once_some_big() ->
+ [{doc,"Test packet option {packet, 1} in active once mode."}].
+packet_1_active_once_some_big(Config) when is_list(Config) ->
Data = lists:append(lists:duplicate(255, "1")),
+ packet(Config, Data, send_raw, active_once_raw, ?SOME, 1, once).
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send, [Data, ?SOME]}},
- {options, [{packet, 1}|ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa,
- {?MODULE,
- active_once_packet,
- [Data, ?SOME]}},
- {options, [{active, once},
- {packet, 1} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-packet_2_active_once_many_small(doc) ->
- ["Test packet option {packet, 2} in active once mode"];
-
-packet_2_active_once_many_small(suite) ->
- [];
-
-packet_2_active_once_many_small(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+packet_2_active_once_many_small() ->
+ [{doc,"Test packet option {packet, 2} in active once mode"}].
+packet_2_active_once_many_small(Config) when is_list(Config) ->
Data = "Packet option is {packet, 2}",
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send, [Data, ?MANY]}},
- {options, [{packet, 2}|ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa,
- {?MODULE,
- active_once_packet,
- [Data, ?MANY]}},
- {options, [{active, once},
- {packet, 2} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
+ packet(Config, Data, send_raw, active_once_raw, ?MANY, 2, once).
%%--------------------------------------------------------------------
-packet_2_active_once_some_big(doc) ->
- ["Test packet option {packet, 2} in active once mode"];
-
-packet_2_active_once_some_big(suite) ->
- [];
-
-packet_2_active_once_some_big(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+packet_2_active_once_some_big() ->
+ [{doc,"Test packet option {packet, 2} in active once mode"}].
+packet_2_active_once_some_big(Config) when is_list(Config) ->
Data = lists:append(lists:duplicate(100, "1234567890")),
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send, [Data, ?SOME]}},
- {options, [{packet, 2}|ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa,
- {?MODULE,
- active_once_packet,
- [Data, ?SOME]}},
- {options, [{active, once},
- {packet, 2} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
+ packet(Config, Data, send_raw, active_once_raw, ?SOME, 2, once).
%%--------------------------------------------------------------------
-packet_4_active_once_many_small(doc) ->
- ["Test packet option {packet, 4} in active once mode"];
-
-packet_4_active_once_many_small(suite) ->
- [];
-
-packet_4_active_once_many_small(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+packet_4_active_once_many_small() ->
+ [{doc,"Test packet option {packet, 4} in active once mode"}].
+packet_4_active_once_many_small(Config) when is_list(Config) ->
Data = "Packet option is {packet, 4}",
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send, [Data, ?MANY]}},
- {options, [{packet, 4}|ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa,
- {?MODULE,
- active_once_packet,
- [Data, ?MANY]}},
- {options, [{active, once},
- {packet, 4} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
+ packet(Config, Data, send_raw, active_once_raw, ?MANY, 4, once).
%%--------------------------------------------------------------------
-packet_4_active_once_some_big(doc) ->
- ["Test packet option {packet, 4} in active once mode"];
-
-packet_4_active_once_some_big(suite) ->
- [];
-
-packet_4_active_once_some_big(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+packet_4_active_once_some_big() ->
+ [{doc,"Test packet option {packet, 4} in active once mode"}].
+packet_4_active_once_some_big(Config) when is_list(Config) ->
Data = lists:append(lists:duplicate(100, "1234567890")),
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send, [Data, ?SOME]}},
- {options, [{packet, 4}|ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa,
- {?MODULE,
- active_once_packet,
- [Data, ?SOME]}},
- {options, [{active, once},
- {packet, 4} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
+ packet(Config, Data, send_raw, active_once_raw, ?SOME, 4, once).
%%--------------------------------------------------------------------
-packet_raw_active_many_small(doc) ->
- ["Test packet option {packet, raw} in active mode."];
-
-packet_raw_active_many_small(suite) ->
- [];
+packet_raw_active_many_small() ->
+ [{doc,"Test packet option {packet, raw} in active mode."}].
packet_raw_active_many_small(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
Data = "Packet option is {packet, raw}",
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send_raw ,[Data, ?MANY]}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, active_raw,
- [Data, ?MANY]}},
- {options, [{active, true},
- {packet, raw} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
+ packet(Config, Data, send_raw, active_raw, ?MANY, raw, active).
%%--------------------------------------------------------------------
-packet_raw_active_some_big(doc) ->
- ["Test packet option {packet, raw} in active mode."];
-
-packet_raw_active_some_big(suite) ->
- [];
+packet_raw_active_some_big() ->
+ [{doc,"Test packet option {packet, raw} in active mode."}].
packet_raw_active_some_big(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
Data = lists:append(lists:duplicate(100, "1234567890")),
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send_raw ,[Data, ?SOME]}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, active_raw, [Data, ?SOME]}},
- {options, [{active, true},
- {packet, raw} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
+ packet(Config, Data, send_raw, active_raw, ?SOME, raw, active).
%%--------------------------------------------------------------------
-packet_0_active_many_small(doc) ->
- ["Test packet option {packet, 0} in active mode."];
-
-packet_0_active_many_small(suite) ->
- [];
-
-packet_0_active_many_small(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+packet_0_active_many_small() ->
+ [{doc,"Test packet option {packet, 0} in active mode."}].
+packet_0_active_many_small(Config) when is_list(Config) ->
Data = "Packet option is {packet, 0}",
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send_raw ,[Data, ?MANY]}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa,
- {?MODULE, active_raw,
- [Data, ?MANY]}},
- {options, [{active, true},
- {packet, 0} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
+ packet(Config, Data, send_raw, active_raw, ?MANY, 0, active).
%%--------------------------------------------------------------------
-packet_0_active_some_big(doc) ->
- ["Test packet option {packet, 0} in active mode."];
-
-packet_0_active_some_big(suite) ->
- [];
-
-packet_0_active_some_big(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+packet_0_active_some_big() ->
+ [{doc,"Test packet option {packet, 0} in active mode."}].
+packet_0_active_some_big(Config) when is_list(Config) ->
Data = lists:append(lists:duplicate(100, "1234567890")),
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send_raw ,[Data, ?SOME]}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa,
- {?MODULE, active_raw,
- [Data, ?SOME]}},
- {options, [{active, true},
- {packet, 0} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
+ packet(Config, Data, send_raw, active_raw, ?SOME, 0, active).
%%--------------------------------------------------------------------
-packet_1_active_many_small(doc) ->
- ["Test packet option {packet, 1} in active mode."];
-
-packet_1_active_many_small(suite) ->
- [];
-
-packet_1_active_many_small(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+packet_1_active_many_small() ->
+ [{doc,"Test packet option {packet, 1} in active mode."}].
+packet_1_active_many_small(Config) when is_list(Config) ->
Data = "Packet option is {packet, 1}",
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send, [Data, ?MANY]}},
- {options, [{packet, 1}|ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa,
- {?MODULE,
- active_packet, [Data, ?MANY]}},
- {options, [{active, true},
- {packet, 1} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
+ packet(Config, Data, send_raw, active_raw, ?MANY, 1, active).
%%--------------------------------------------------------------------
-packet_1_active_some_big(doc) ->
- ["Test packet option {packet, 1} in active mode."];
-
-packet_1_active_some_big(suite) ->
- [];
-
-packet_1_active_some_big(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+packet_1_active_some_big() ->
+ [{doc,"Test packet option {packet, 1} in active mode."}].
+packet_1_active_some_big(Config) when is_list(Config) ->
Data = lists:append(lists:duplicate(255, "1")),
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send, [Data, ?SOME]}},
- {options, [{packet, 1}|ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa,
- {?MODULE,
- active_packet, [Data, ?SOME]}},
- {options, [{active, true},
- {packet, 1} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
+ packet(Config, Data, send_raw, active_raw, ?SOME, 1, active).
%%--------------------------------------------------------------------
-packet_2_active_many_small(doc) ->
- ["Test packet option {packet, 2} in active mode"];
-
-packet_2_active_many_small(suite) ->
- [];
-
-packet_2_active_many_small(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+packet_2_active_many_small() ->
+ [{doc,"Test packet option {packet, 2} in active mode"}].
+packet_2_active_many_small(Config) when is_list(Config) ->
Data = "Packet option is {packet, 2}",
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send, [Data, ?MANY]}},
- {options, [{packet, 2}|ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa,
- {?MODULE,
- active_packet, [Data, ?MANY]}},
- {options, [{active, true},
- {packet, 2} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
+ packet(Config, Data, send_raw, active_raw, ?MANY, 2, active).
%%--------------------------------------------------------------------
-packet_2_active_some_big(doc) ->
- ["Test packet option {packet, 2} in active mode"];
-
-packet_2_active_some_big(suite) ->
- [];
-
-packet_2_active_some_big(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+packet_2_active_some_big() ->
+ [{doc,"Test packet option {packet, 2} in active mode"}].
+packet_2_active_some_big(Config) when is_list(Config) ->
Data = lists:append(lists:duplicate(100, "1234567890")),
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send, [Data, ?SOME]}},
- {options, [{packet, 2}|ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa,
- {?MODULE,
- active_packet, [Data, ?SOME]}},
- {options, [{active, true},
- {packet, 2} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
+ packet(Config, Data, send_raw, active_raw, ?SOME, 2, active).
%%--------------------------------------------------------------------
-packet_4_active_many_small(doc) ->
- ["Test packet option {packet, 4} in active mode"];
-
-packet_4_active_many_small(suite) ->
- [];
-
-packet_4_active_many_small(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+packet_4_active_many_small() ->
+ [{doc,"Test packet option {packet, 4} in active mode"}].
+packet_4_active_many_small(Config) when is_list(Config) ->
Data = "Packet option is {packet, 4}",
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send, [Data, ?MANY]}},
- {options, [{packet, 4}|ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa,
- {?MODULE,
- active_packet, [Data, ?MANY]}},
- {options, [{active, true},
- {packet, 4} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
+ packet(Config, Data, send_raw, active_raw, ?MANY, 4, active).
%%--------------------------------------------------------------------
-packet_4_active_some_big(doc) ->
- ["Test packet option {packet, 4} in active mode"];
-
-packet_4_active_some_big(suite) ->
- [];
-
-packet_4_active_some_big(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+packet_4_active_some_big() ->
+ [{doc,"Test packet option {packet, 4} in active mode"}].
+packet_4_active_some_big(Config) when is_list(Config) ->
Data = lists:append(lists:duplicate(100, "1234567890")),
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send, [Data, ?SOME]}},
- {options, [{packet, 4} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa,
- {?MODULE,
- active_packet, [Data, ?SOME]}},
- {options, [{active, true},
- {packet, 4} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
+ packet(Config, Data, send_raw, active_raw, ?SOME, 4, active).
%%--------------------------------------------------------------------
-packet_send_to_large(doc) ->
- ["Test setting the packet option {packet, 2} on the send side"];
-
-packet_send_to_large(suite) -> [];
+packet_send_to_large() ->
+ [{doc,"Test setting the packet option {packet, 2} on the send side"}].
packet_send_to_large(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -1279,16 +447,9 @@ packet_send_to_large(Config) when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
-
-
-
-
%%--------------------------------------------------------------------
-packet_wait_active(doc) ->
- ["Test waiting when complete packages have not arrived"];
-
-packet_wait_active(suite) ->
- [];
+packet_wait_active() ->
+ [{doc,"Test waiting when complete packages have not arrived"}].
packet_wait_active(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -1320,11 +481,8 @@ packet_wait_active(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-packet_wait_passive(doc) ->
- ["Test waiting when complete packages have not arrived"];
-
-packet_wait_passive(suite) ->
- [];
+packet_wait_passive() ->
+ [{doc,"Test waiting when complete packages have not arrived"}].
packet_wait_passive(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -1353,10 +511,8 @@ packet_wait_passive(Config) when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-packet_baddata_active(doc) ->
- ["Test that if a bad packet arrives error msg is sent and socket is closed"];
-packet_baddata_active(suite) ->
- [];
+packet_baddata_active() ->
+ [{doc,"Test that if a bad packet arrives error msg is sent and socket is closed"}].
packet_baddata_active(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -1381,18 +537,15 @@ packet_baddata_active(Config) when is_list(Config) ->
{Client, {other, {ssl_error, _Socket,
{invalid_packet, _}},{error,closed},1}} -> ok;
Unexpected ->
- test_server:fail({unexpected, Unexpected})
+ ct:fail({unexpected, Unexpected})
end,
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-packet_baddata_passive(doc) ->
- ["Test that if a bad packet arrives error msg is sent and socket is closed"];
-
-packet_baddata_passive(suite) ->
- [];
+packet_baddata_passive() ->
+ [{doc,"Test that if a bad packet arrives error msg is sent and socket is closed"}].
packet_baddata_passive(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -1418,19 +571,16 @@ packet_baddata_passive(Config) when is_list(Config) ->
receive
{Client, {other, {error, {invalid_packet, _}},{error,closed}, 1}} -> ok;
Unexpected ->
- test_server:fail({unexpected, Unexpected})
+ ct:fail({unexpected, Unexpected})
end,
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-packet_size_active(doc) ->
- ["Test that if a packet of size larger than
- packet_size arrives error msg is sent and socket is closed"];
-
-packet_size_active(suite) ->
- [];
+packet_size_active() ->
+ [{doc,"Test that if a packet of size larger than
+ packet_size arrives error msg is sent and socket is closed"}].
packet_size_active(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -1455,17 +605,16 @@ packet_size_active(Config) when is_list(Config) ->
{Client, {other, {ssl_error, _Socket,
{invalid_packet, _}},{error,closed},1}} -> ok;
Unexpected ->
- test_server:fail({unexpected, Unexpected})
+ ct:fail({unexpected, Unexpected})
end,
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-packet_size_passive(doc) ->
- ["Test that if a packet of size larger
- than packet_size arrives error msg is sent and socket is closed"];
-packet_size_passive(suite) -> [];
+packet_size_passive() ->
+ [{doc, "Test that if a packet of size larger
+ than packet_size arrives error msg is sent and socket is closed"}].
packet_size_passive(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -1490,17 +639,15 @@ packet_size_passive(Config) when is_list(Config) ->
receive
{Client, {other, {error, {invalid_packet, _}},{error,closed},1}} -> ok;
Unexpected ->
- test_server:fail({unexpected, Unexpected})
+ ct:fail({unexpected, Unexpected})
end,
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-packet_cdr_decode(doc) ->
- ["Test setting the packet option {packet, cdr}, {mode, binary}"];
-packet_cdr_decode(suite) ->
- [];
+packet_cdr_decode() ->
+ [{doc,"Test setting the packet option {packet, cdr}, {mode, binary}"}].
packet_cdr_decode(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -1532,10 +679,8 @@ packet_cdr_decode(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-packet_cdr_decode_list(doc) ->
- ["Test setting the packet option {packet, cdr} {mode, list}"];
-packet_cdr_decode_list(suite) ->
- [];
+packet_cdr_decode_list() ->
+ [{doc,"Test setting the packet option {packet, cdr} {mode, list}"}].
packet_cdr_decode_list(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -1567,11 +712,9 @@ packet_cdr_decode_list(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-packet_http_decode(doc) ->
- ["Test setting the packet option {packet, http} {mode, binary} "
- "(Body will be binary http strings are lists)"];
-packet_http_decode(suite) ->
- [];
+packet_http_decode() ->
+ [{doc, "Test setting the packet option {packet, http} {mode, binary} "
+ "(Body will be binary http strings are lists)"}].
packet_http_decode(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -1652,11 +795,9 @@ client_http_decode(Socket, HttpRequest) ->
ok.
%%--------------------------------------------------------------------
-packet_http_decode_list(doc) ->
- ["Test setting the packet option {packet, http}, {mode, list}"
- "(Body will be list too)"];
-packet_http_decode_list(suite) ->
- [];
+packet_http_decode_list() ->
+ [{doc, "Test setting the packet option {packet, http}, {mode, list}"
+ "(Body will be list too)"}].
packet_http_decode_list(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -1712,11 +853,8 @@ client_http_decode_list(Socket, HttpRequest) ->
ok.
%%--------------------------------------------------------------------
-packet_http_bin_decode_multi(doc) ->
- ["Test setting the packet option {packet, http_bin} with multiple requests"];
-packet_http_bin_decode_multi(suite) ->
- [];
-
+packet_http_bin_decode_multi() ->
+ [{doc,"Test setting the packet option {packet, http_bin} with multiple requests"}].
packet_http_bin_decode_multi(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -1803,11 +941,10 @@ client_http_bin_decode(_, _, _) ->
ok.
%%--------------------------------------------------------------------
-packet_http_error_passive(doc) ->
- ["Test setting the packet option {packet, http}, {active, false}"
- " with a incorrect http header." ];
-packet_http_error_passive(suite) ->
- [];
+packet_http_error_passive() ->
+ [{doc,"Test setting the packet option {packet, http}, {active, false}"
+ " with a incorrect http header."}].
+
packet_http_error_passive(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -1865,10 +1002,9 @@ server_http_decode_error(Socket, HttpResponse) ->
ok = ssl:send(Socket, HttpResponse),
ok.
%%--------------------------------------------------------------------
-packet_httph_active(doc) ->
- ["Test setting the packet option {packet, httph}"];
-packet_httph_active(suite) ->
- [];
+packet_httph_active() ->
+ [{doc,"Test setting the packet option {packet, httph}"}].
+
packet_httph_active(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -1922,10 +1058,8 @@ client_http_decode_trailer_active(Socket) ->
ok.
%%--------------------------------------------------------------------
-packet_httph_bin_active(doc) ->
- ["Test setting the packet option {packet, httph_bin}"];
-packet_httph_bin_active(suite) ->
- [];
+packet_httph_bin_active() ->
+ [{doc,"Test setting the packet option {packet, httph_bin}"}].
packet_httph_bin_active(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -1973,10 +1107,9 @@ client_http_decode_trailer_bin_active(Socket) ->
end,
ok.
%%--------------------------------------------------------------------
-packet_httph_active_once(doc) ->
- ["Test setting the packet option {packet, httph}"];
-packet_httph_active_once(suite) ->
- [];
+packet_httph_active_once() ->
+ [{doc,"Test setting the packet option {packet, httph}"}].
+
packet_httph_active_once(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -2027,10 +1160,9 @@ client_http_decode_trailer_active_once(Socket) ->
end,
ok.
%%--------------------------------------------------------------------
-packet_httph_bin_active_once(doc) ->
- ["Test setting the packet option {packet, httph_bin}"];
-packet_httph_bin_active_once(suite) ->
- [];
+packet_httph_bin_active_once() ->
+ [{doc,"Test setting the packet option {packet, httph_bin}"}].
+
packet_httph_bin_active_once(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -2082,10 +1214,9 @@ client_http_decode_trailer_bin_active_once(Socket) ->
%%--------------------------------------------------------------------
-packet_httph_passive(doc) ->
- ["Test setting the packet option {packet, httph}"];
-packet_httph_passive(suite) ->
- [];
+packet_httph_passive() ->
+ [{doc,"Test setting the packet option {packet, httph}"}].
+
packet_httph_passive(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -2123,10 +1254,9 @@ client_http_decode_trailer_passive(Socket) ->
ok.
%%--------------------------------------------------------------------
-packet_httph_bin_passive(doc) ->
- ["Test setting the packet option {packet, httph_bin}"];
-packet_httph_bin_passive(suite) ->
- [];
+packet_httph_bin_passive() ->
+ [{doc,"Test setting the packet option {packet, httph_bin}"}].
+
packet_httph_bin_passive(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -2164,10 +1294,9 @@ client_http_decode_trailer_bin_passive(Socket) ->
ok.
%%--------------------------------------------------------------------
-packet_line_decode(doc) ->
- ["Test setting the packet option {packet, line}, {mode, binary}"];
-packet_line_decode(suite) ->
- [];
+packet_line_decode() ->
+ [{doc,"Test setting the packet option {packet, line}, {mode, binary}"}].
+
packet_line_decode(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -2201,10 +1330,9 @@ packet_line_decode(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-packet_line_decode_list(doc) ->
- ["Test setting the packet option {packet, line}, {mode, list}"];
-packet_line_decode_list(suite) ->
- [];
+packet_line_decode_list() ->
+ [{doc,"Test setting the packet option {packet, line}, {mode, list}"}].
+
packet_line_decode_list(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -2240,10 +1368,9 @@ packet_line_decode_list(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-packet_asn1_decode(doc) ->
- ["Test setting the packet option {packet, asn1}"];
-packet_asn1_decode(suite) ->
- [];
+packet_asn1_decode() ->
+ [{doc,"Test setting the packet option {packet, asn1}"}].
+
packet_asn1_decode(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -2276,10 +1403,9 @@ packet_asn1_decode(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-packet_asn1_decode_list(doc) ->
- ["Test setting the packet option {packet, asn1}"];
-packet_asn1_decode_list(suite) ->
- [];
+packet_asn1_decode_list() ->
+ [{doc,"Test setting the packet option {packet, asn1}"}].
+
packet_asn1_decode_list(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -2314,10 +1440,9 @@ packet_asn1_decode_list(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-packet_tpkt_decode(doc) ->
- ["Test setting the packet option {packet, tpkt}"];
-packet_tpkt_decode(suite) ->
- [];
+packet_tpkt_decode() ->
+ [{doc,"Test setting the packet option {packet, tpkt}"}].
+
packet_tpkt_decode(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -2347,10 +1472,9 @@ packet_tpkt_decode(Config) when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-packet_tpkt_decode_list(doc) ->
- ["Test setting the packet option {packet, tpkt}"];
-packet_tpkt_decode_list(suite) ->
- [];
+packet_tpkt_decode_list() ->
+ [{doc,"Test setting the packet option {packet, tpkt}"}].
+
packet_tpkt_decode_list(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -2381,10 +1505,9 @@ packet_tpkt_decode_list(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-%% packet_fcgi_decode(doc) ->
-%% ["Test setting the packet option {packet, fcgi}"];
-%% packet_fcgi_decode(suite) ->
-%% [];
+%% packet_fcgi_decode() ->
+%% [{doc,"Test setting the packet option {packet, fcgi}"}].
+
%% packet_fcgi_decode(Config) when is_list(Config) ->
%% ClientOpts = ?config(client_opts, Config),
%% ServerOpts = ?config(server_opts, Config),
@@ -2416,10 +1539,8 @@ packet_tpkt_decode_list(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-packet_sunrm_decode(doc) ->
- ["Test setting the packet option {packet, sunrm}"];
-packet_sunrm_decode(suite) ->
- [];
+packet_sunrm_decode() ->
+ [{doc,"Test setting the packet option {packet, sunrm}"}].
packet_sunrm_decode(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -2449,10 +1570,9 @@ packet_sunrm_decode(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-packet_sunrm_decode_list(doc) ->
- ["Test setting the packet option {packet, sunrm}"];
-packet_sunrm_decode_list(suite) ->
- [];
+packet_sunrm_decode_list() ->
+ [{doc,"Test setting the packet option {packet, sunrm}"}].
+
packet_sunrm_decode_list(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -2482,10 +1602,9 @@ packet_sunrm_decode_list(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-header_decode_one_byte_active(doc) ->
- ["Test setting the packet option {header, 1}"];
-header_decode_one_byte_active(suite) ->
- [];
+header_decode_one_byte_active() ->
+ [{doc,"Test setting the packet option {header, 1}"}].
+
header_decode_one_byte_active(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -2516,10 +1635,9 @@ header_decode_one_byte_active(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-header_decode_two_bytes_active(doc) ->
- ["Test setting the packet option {header, 2}"];
-header_decode_two_bytes_active(suite) ->
- [];
+header_decode_two_bytes_active() ->
+ [{doc,"Test setting the packet option {header, 2}"}].
+
header_decode_two_bytes_active(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -2551,10 +1669,9 @@ header_decode_two_bytes_active(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-header_decode_two_bytes_two_sent_active(doc) ->
- ["Test setting the packet option {header, 2} and sending two byte"];
-header_decode_two_bytes_two_sent_active(suite) ->
- [];
+header_decode_two_bytes_two_sent_active() ->
+ [{doc,"Test setting the packet option {header, 2} and sending two byte"}].
+
header_decode_two_bytes_two_sent_active(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -2586,10 +1703,9 @@ header_decode_two_bytes_two_sent_active(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-header_decode_two_bytes_one_sent_active(doc) ->
- ["Test setting the packet option {header, 2} and sending one byte"];
-header_decode_two_bytes_one_sent_active(suite) ->
- [];
+header_decode_two_bytes_one_sent_active() ->
+ [{doc,"Test setting the packet option {header, 2} and sending one byte"}].
+
header_decode_two_bytes_one_sent_active(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -2620,10 +1736,9 @@ header_decode_two_bytes_one_sent_active(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-header_decode_one_byte_passive(doc) ->
- ["Test setting the packet option {header, 1}"];
-header_decode_one_byte_passive(suite) ->
- [];
+header_decode_one_byte_passive() ->
+ [{doc,"Test setting the packet option {header, 1}"}].
+
header_decode_one_byte_passive(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -2654,10 +1769,9 @@ header_decode_one_byte_passive(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-header_decode_two_bytes_passive(doc) ->
- ["Test setting the packet option {header, 2}"];
-header_decode_two_bytes_passive(suite) ->
- [];
+header_decode_two_bytes_passive() ->
+ [{doc,"Test setting the packet option {header, 2}"}].
+
header_decode_two_bytes_passive(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -2689,10 +1803,9 @@ header_decode_two_bytes_passive(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-header_decode_two_bytes_two_sent_passive(doc) ->
- ["Test setting the packet option {header, 2} and sending two byte"];
-header_decode_two_bytes_two_sent_passive(suite) ->
- [];
+header_decode_two_bytes_two_sent_passive() ->
+ [{doc,"Test setting the packet option {header, 2} and sending two byte"}].
+
header_decode_two_bytes_two_sent_passive(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -2724,10 +1837,9 @@ header_decode_two_bytes_two_sent_passive(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-header_decode_two_bytes_one_sent_passive(doc) ->
- ["Test setting the packet option {header, 2} and sending one byte"];
-header_decode_two_bytes_one_sent_passive(suite) ->
- [];
+header_decode_two_bytes_one_sent_passive() ->
+ [{doc,"Test setting the packet option {header, 2} and sending one byte"}].
+
header_decode_two_bytes_one_sent_passive(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -2757,7 +1869,30 @@ header_decode_two_bytes_one_sent_passive(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-%% Internal functions
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
+packet(Config, Data, Send, Recv, Quantity, Packet, Active) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, Send ,[Data, Quantity]}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, Recv, [Data, Quantity]}},
+ {options, [{active, Active},
+ {packet, Packet} |
+ ClientOpts]}]),
+
+ ssl_test_lib:check_result(Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
send_raw(Socket,_, 0) ->
ssl:send(Socket, <<>>),
@@ -2928,7 +2063,7 @@ client_packet_decode(Socket, [Head | Tail] = Packet) ->
client_packet_decode(Socket, [Head], Tail, Packet).
client_packet_decode(Socket, P1, P2, Packet) ->
- test_server:format("Packet: ~p ~n", [Packet]),
+ ct:print("Packet: ~p ~n", [Packet]),
ok = ssl:send(Socket, P1),
ok = ssl:send(Socket, P2),
receive
diff --git a/lib/ssl/test/ssl_payload_SUITE.erl b/lib/ssl/test/ssl_payload_SUITE.erl
index c97f97e70b..77ad546420 100644
--- a/lib/ssl/test/ssl_payload_SUITE.erl
+++ b/lib/ssl/test/ssl_payload_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -26,79 +26,8 @@
-define(TIMEOUT, 600000).
-%% Test server callback functions
%%--------------------------------------------------------------------
-%% Function: init_per_suite(Config) -> Config
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Initialization before the whole suite
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
-%%--------------------------------------------------------------------
-init_per_suite(Config) ->
- catch crypto:stop(),
- try crypto:start() of
- ok ->
- application:start(public_key),
- ssl:start(),
- make_certs:all(?config(data_dir, Config), ?config(priv_dir, Config)),
- ssl_test_lib:cert_options(Config)
- catch _:_ ->
- {skip, "Crypto did not start"}
- end.
-%%--------------------------------------------------------------------
-%% Function: end_per_suite(Config) -> _
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after the whole suite
-%%--------------------------------------------------------------------
-end_per_suite(_Config) ->
- ssl:stop(),
- application:stop(crypto).
-
-%%--------------------------------------------------------------------
-%% Function: init_per_testcase(TestCase, Config) -> Config
-%% Case - atom()
-%% Name of the test case that is about to be run.
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%%
-%% Description: Initialization before each test case
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
-%% Description: Initialization before each test case
-%%--------------------------------------------------------------------
-init_per_testcase(_TestCase, Config0) ->
- Config = lists:keydelete(watchdog, 1, Config0),
- Dog = ssl_test_lib:timetrap(?TIMEOUT),
- [{watchdog, Dog} | Config].
-
-%%--------------------------------------------------------------------
-%% Function: end_per_testcase(TestCase, Config) -> _
-%% Case - atom()
-%% Name of the test case that is about to be run.
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after each test case
-%%--------------------------------------------------------------------
-end_per_testcase(_TestCase, Config) ->
- Dog = ?config(watchdog, Config),
- case Dog of
- undefined ->
- ok;
- _ ->
- test_server:timetrap_cancel(Dog)
- end.
-
-%%--------------------------------------------------------------------
-%% Function: all(Clause) -> TestCases
-%% Clause - atom() - suite | doc
-%% TestCases - [Case]
-%% Case - atom()
-%% Name of a test case.
-%% Description: Returns a list of all test cases in this test suite
+%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -138,6 +67,21 @@ payload_tests() ->
client_echos_active_once_huge,
client_echos_active_huge].
+init_per_suite(Config) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ application:start(public_key),
+ ssl:start(),
+ make_certs:all(?config(data_dir, Config), ?config(priv_dir, Config)),
+ ssl_test_lib:cert_options(Config)
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto).
init_per_group(GroupName, Config) ->
case ssl_test_lib:is_tls_version(GroupName) of
@@ -157,15 +101,20 @@ init_per_group(GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
+init_per_testcase(_TestCase, Config0) ->
+ Config = lists:keydelete(watchdog, 1, Config0),
+ Dog = ct:timetrap(?TIMEOUT),
+ [{watchdog, Dog} | Config].
-%% Test cases starts here.
+end_per_testcase(_TestCase, Config) ->
+ Config.
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------
-server_echos_passive_small(doc) ->
- ["Client sends 1000 bytes in passive mode to server, that receives them, "
- "sends them back, and closes."];
-server_echos_passive_small(suite) ->
- [];
+server_echos_passive_small() ->
+ [{doc, "Client sends 1000 bytes in passive mode to server, that receives them, "
+ "sends them back, and closes."}].
server_echos_passive_small(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -179,12 +128,9 @@ server_echos_passive_small(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-server_echos_active_once_small(doc) ->
- ["Client sends 1000 bytes in active once mode to server, that receives "
- " them, sends them back, and closes."];
-
-server_echos_active_once_small(suite) ->
- [];
+server_echos_active_once_small() ->
+ [{doc, "Client sends 1000 bytes in active once mode to server, that receives "
+ " them, sends them back, and closes."}].
server_echos_active_once_small(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -198,12 +144,9 @@ server_echos_active_once_small(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-server_echos_active_small(doc) ->
- ["Client sends 1000 bytes in active mode to server, that receives them, "
- "sends them back, and closes."];
-
-server_echos_active_small(suite) ->
- [];
+server_echos_active_small() ->
+ [{doc, "Client sends 1000 bytes in active mode to server, that receives them, "
+ "sends them back, and closes."}].
server_echos_active_small(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -216,12 +159,9 @@ server_echos_active_small(Config) when is_list(Config) ->
ClientNode, ServerNode, Hostname).
%%--------------------------------------------------------------------
-client_echos_passive_small(doc) ->
- ["Server sends 1000 bytes in passive mode to client, that receives them, "
- "sends them back, and closes."];
-
-client_echos_passive_small(suite) ->
- [];
+client_echos_passive_small() ->
+ [{doc, "Server sends 1000 bytes in passive mode to client, that receives them, "
+ "sends them back, and closes."}].
client_echos_passive_small(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -234,12 +174,9 @@ client_echos_passive_small(Config) when is_list(Config) ->
ServerNode, Hostname).
%%--------------------------------------------------------------------
-client_echos_active_once_small(doc) ->
+client_echos_active_once_small() ->
["Server sends 1000 bytes in active once mode to client, that receives "
- "them, sends them back, and closes."];
-
-client_echos_active_once_small(suite) ->
- [];
+ "them, sends them back, and closes."].
client_echos_active_once_small(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -252,15 +189,12 @@ client_echos_active_once_small(Config) when is_list(Config) ->
ServerNode, Hostname).
%%--------------------------------------------------------------------
-client_echos_active_small(doc) ->
- ["Server sends 1000 bytes in active mode to client, that receives them, "
- "sends them back, and closes."];
-
-client_echos_active_small(suite) ->
- [];
+client_echos_active_small() ->
+ [{doc, "Server sends 1000 bytes in active mode to client, that receives them, "
+ "sends them back, and closes."}].
client_echos_active_small(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
+ ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -271,12 +205,9 @@ client_echos_active_small(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-server_echos_passive_big(doc) ->
- ["Client sends 50000 bytes to server in passive mode, that receives them, "
- "sends them back, and closes."];
-
-server_echos_passive_big(suite) ->
- [];
+server_echos_passive_big() ->
+ [{doc, "Client sends 50000 bytes to server in passive mode, that receives them, "
+ "sends them back, and closes."}].
server_echos_passive_big(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -290,15 +221,12 @@ server_echos_passive_big(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-server_echos_active_once_big(doc) ->
- ["Client sends 50000 bytes to server in active once mode, that receives "
- "them, sends them back, and closes."];
-
-server_echos_active_once_big(suite) ->
- [];
+server_echos_active_once_big() ->
+ [{doc,"Client sends 50000 bytes to server in active once mode, that receives "
+ "them, sends them back, and closes."}].
server_echos_active_once_big(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
+ ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -309,12 +237,9 @@ server_echos_active_once_big(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-server_echos_active_big(doc) ->
- ["Client sends 50000 bytes to server in active once mode, that receives "
- " them, sends them back, and closes."];
-
-server_echos_active_big(suite) ->
- [];
+server_echos_active_big() ->
+ [{doc, "Client sends 50000 bytes to server in active once mode, that receives "
+ " them, sends them back, and closes."}].
server_echos_active_big(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -327,12 +252,9 @@ server_echos_active_big(Config) when is_list(Config) ->
ServerNode, Hostname).
%%--------------------------------------------------------------------
-client_echos_passive_big(doc) ->
- ["Server sends 50000 bytes to client in passive mode, that receives them, "
- "sends them back, and closes."];
-
-client_echos_passive_big(suite) ->
- [];
+client_echos_passive_big() ->
+ [{doc, "Server sends 50000 bytes to client in passive mode, that receives them, "
+ "sends them back, and closes."}].
client_echos_passive_big(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -345,12 +267,9 @@ client_echos_passive_big(Config) when is_list(Config) ->
ServerNode, Hostname).
%%--------------------------------------------------------------------
-client_echos_active_once_big(doc) ->
- ["Server sends 50000 bytes to client in active once mode, that receives"
- " them, sends them back, and closes."];
-
-client_echos_active_once_big(suite) ->
- [];
+client_echos_active_once_big() ->
+ [{doc, "Server sends 50000 bytes to client in active once mode, that receives"
+ " them, sends them back, and closes."}].
client_echos_active_once_big(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -363,12 +282,9 @@ client_echos_active_once_big(Config) when is_list(Config) ->
ServerNode, Hostname).
%%--------------------------------------------------------------------
-client_echos_active_big(doc) ->
- ["Server sends 50000 bytes to client in active mode, that receives them, "
- "sends them back, and closes."];
-
-client_echos_active_big(suite) ->
- [];
+client_echos_active_big() ->
+ [{doc, "Server sends 50000 bytes to client in active mode, that receives them, "
+ "sends them back, and closes."}].
client_echos_active_big(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -381,12 +297,9 @@ client_echos_active_big(Config) when is_list(Config) ->
ServerNode, Hostname).
%%--------------------------------------------------------------------
-server_echos_passive_huge(doc) ->
- ["Client sends 500000 bytes to server in passive mode, that receives "
- " them, sends them back, and closes."];
-
-server_echos_passive_huge(suite) ->
- [];
+server_echos_passive_huge() ->
+ [{doc, "Client sends 500000 bytes to server in passive mode, that receives "
+ " them, sends them back, and closes."}].
server_echos_passive_huge(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -399,12 +312,9 @@ server_echos_passive_huge(Config) when is_list(Config) ->
ServerNode, Hostname).
%%--------------------------------------------------------------------
-server_echos_active_once_huge(doc) ->
- ["Client sends 500000 bytes to server in active once mode, that receives "
- "them, sends them back, and closes."];
-
-server_echos_active_once_huge(suite) ->
- [];
+server_echos_active_once_huge() ->
+ [{doc, "Client sends 500000 bytes to server in active once mode, that receives "
+ "them, sends them back, and closes."}].
server_echos_active_once_huge(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -417,12 +327,9 @@ server_echos_active_once_huge(Config) when is_list(Config) ->
ServerNode, Hostname).
%%--------------------------------------------------------------------
-server_echos_active_huge(doc) ->
- ["Client sends 500000 bytes to server in active mode, that receives them, "
- "sends them back, and closes."];
-
-server_echos_active_huge(suite) ->
- [];
+server_echos_active_huge() ->
+ [{doc, "Client sends 500000 bytes to server in active mode, that receives them, "
+ "sends them back, and closes."}].
server_echos_active_huge(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -435,12 +342,9 @@ server_echos_active_huge(Config) when is_list(Config) ->
ServerNode, Hostname).
%%--------------------------------------------------------------------
-client_echos_passive_huge(doc) ->
- ["Server sends 500000 bytes to client in passive mode, that receives "
- "them, sends them back, and closes."];
-
-client_echos_passive_huge(suite) ->
- [];
+client_echos_passive_huge() ->
+ [{doc, "Server sends 500000 bytes to client in passive mode, that receives "
+ "them, sends them back, and closes."}].
client_echos_passive_huge(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -452,12 +356,9 @@ client_echos_passive_huge(Config) when is_list(Config) ->
ServerNode, Hostname).
%%--------------------------------------------------------------------
-client_echos_active_once_huge(doc) ->
- ["Server sends 500000 bytes to client in active once mode, that receives "
- "them, sends them back, and closes."];
-
-client_echos_active_once_huge(suite) ->
- [];
+client_echos_active_once_huge() ->
+ [{doc, "Server sends 500000 bytes to client in active once mode, that receives "
+ "them, sends them back, and closes."}].
client_echos_active_once_huge(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -469,12 +370,9 @@ client_echos_active_once_huge(Config) when is_list(Config) ->
ServerNode, Hostname).
%%--------------------------------------------------------------------
-client_echos_active_huge(doc) ->
- ["Server sends 500000 bytes to client in active mode, that receives them, "
- "sends them back, and closes."];
-
-client_echos_active_huge(suite) ->
- [];
+client_echos_active_huge() ->
+ [{doc, "Server sends 500000 bytes to client in active mode, that receives them, "
+ "sends them back, and closes."}].
client_echos_active_huge(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
@@ -486,6 +384,8 @@ client_echos_active_huge(Config) when is_list(Config) ->
ServerNode, Hostname).
%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
server_echos_passive(Data, Length, ClientOpts, ServerOpts,
ClientNode, ServerNode, Hostname) ->
@@ -656,33 +556,33 @@ send(Socket, Data, Size, Repeate,F) ->
sender(Socket, Data, Size) ->
ok = send(Socket, Data, Size, 100, fun() -> do_recv(Socket, Data, Size, <<>>, false) end),
- test_server:format("Sender recv: ~p~n", [ssl:getopts(Socket, [active])]),
+ ct:print("Sender recv: ~p~n", [ssl:getopts(Socket, [active])]),
ok.
sender_once(Socket, Data, Size) ->
send(Socket, Data, Size, 100,
fun() -> do_active_once(Socket, Data, Size, <<>>, false) end),
- test_server:format("Sender active once: ~p~n",
+ ct:print("Sender active once: ~p~n",
[ssl:getopts(Socket, [active])]),
ok.
sender_active(Socket, Data, Size) ->
F = fun() -> do_active(Socket, Data, Size, <<>>, false) end,
send(Socket, Data, Size, 100, F),
- test_server:format("Sender active: ~p~n", [ssl:getopts(Socket, [active])]),
+ ct:print("Sender active: ~p~n", [ssl:getopts(Socket, [active])]),
ok.
echoer(Socket, Data, Size) ->
- test_server:format("Echoer recv: ~p~n", [ssl:getopts(Socket, [active])]),
+ ct:print("Echoer recv: ~p~n", [ssl:getopts(Socket, [active])]),
echo(fun() -> do_recv(Socket, Data, Size, <<>>, true) end, 100).
echoer_once(Socket, Data, Size) ->
- test_server:format("Echoer active once: ~p ~n",
+ ct:print("Echoer active once: ~p ~n",
[ssl:getopts(Socket, [active])]),
echo(fun() -> do_active_once(Socket, Data, Size, <<>>, true) end, 100).
echoer_active(Socket, Data, Size) ->
- test_server:format("Echoer active: ~p~n", [ssl:getopts(Socket, [active])]),
+ ct:print("Echoer active: ~p~n", [ssl:getopts(Socket, [active])]),
echo(fun() -> do_active(Socket, Data, Size, <<>>, true) end, 100).
echo(_Fun, 0) -> ok;
diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl
index 1d71efd40c..fd9a0a594c 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-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -37,18 +37,22 @@
-export([init/1, terminate/1, lookup/2, update/3,
delete/2, foldl/3, select_session/2]).
-%% Test server callback functions
%%--------------------------------------------------------------------
-%% Function: init_per_suite(Config) -> Config
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Initialization before the whole suite
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
+%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [session_cleanup,
+ session_cache_process_list,
+ session_cache_process_mnesia].
+
+groups() ->
+ [].
+
init_per_suite(Config0) ->
- Dog = ssl_test_lib:timetrap(?LONG_TIMEOUT *2),
+ Dog = ct:timetrap(?LONG_TIMEOUT *2),
catch crypto:stop(),
try crypto:start() of
ok ->
@@ -59,7 +63,7 @@ init_per_suite(Config0) ->
Result =
(catch make_certs:all(?config(data_dir, Config0),
?config(priv_dir, Config0))),
- test_server:format("Make certs ~p~n", [Result]),
+ ct:print("Make certs ~p~n", [Result]),
Config1 = ssl_test_lib:make_dsa_cert(Config0),
Config = ssl_test_lib:cert_options(Config1),
@@ -68,29 +72,16 @@ init_per_suite(Config0) ->
{skip, "Crypto did not start"}
end.
-%%--------------------------------------------------------------------
-%% Function: end_per_suite(Config) -> _
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after the whole suite
-%%--------------------------------------------------------------------
end_per_suite(_Config) ->
ssl:stop(),
application:stop(crypto).
-%%--------------------------------------------------------------------
-%% Function: init_per_testcase(TestCase, Config) -> Config
-%% Case - atom()
-%% Name of the test case that is about to be run.
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%%
-%% Description: Initialization before each test case
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
-%% Description: Initialization before each test case
-%%--------------------------------------------------------------------
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
init_per_testcase(session_cache_process_list, Config) ->
init_customized_session_cache(list, Config);
@@ -100,7 +91,7 @@ init_per_testcase(session_cache_process_mnesia, Config) ->
init_per_testcase(session_cleanup, Config0) ->
Config = lists:keydelete(watchdog, 1, Config0),
- Dog = test_server:timetrap(?TIMEOUT),
+ Dog = ct:timetrap(?TIMEOUT),
ssl:stop(),
application:load(ssl),
application:set_env(ssl, session_lifetime, 5),
@@ -110,12 +101,12 @@ init_per_testcase(session_cleanup, Config0) ->
init_per_testcase(_TestCase, Config0) ->
Config = lists:keydelete(watchdog, 1, Config0),
- Dog = test_server:timetrap(?TIMEOUT),
+ Dog = ct:timetrap(?TIMEOUT),
[{watchdog, Dog} | Config].
init_customized_session_cache(Type, Config0) ->
Config = lists:keydelete(watchdog, 1, Config0),
- Dog = test_server:timetrap(?TIMEOUT),
+ Dog = ct:timetrap(?TIMEOUT),
ssl:stop(),
application:load(ssl),
application:set_env(ssl, session_cb, ?MODULE),
@@ -123,14 +114,6 @@ init_customized_session_cache(Type, Config0) ->
ssl:start(),
[{watchdog, Dog} | Config].
-%%--------------------------------------------------------------------
-%% Function: end_per_testcase(TestCase, Config) -> _
-%% Case - atom()
-%% Name of the test case that is about to be run.
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after each test case
-%%--------------------------------------------------------------------
end_per_testcase(session_cache_process_list, Config) ->
application:unset_env(ssl, session_cb),
end_per_testcase(default_action, Config);
@@ -146,43 +129,14 @@ end_per_testcase(session_cleanup, Config) ->
application:unset_env(ssl, session_lifetime),
end_per_testcase(default_action, Config);
end_per_testcase(_TestCase, Config) ->
- Dog = ?config(watchdog, Config),
- case Dog of
- undefined ->
- ok;
- _ ->
- test_server:timetrap_cancel(Dog)
- end.
-
-%%--------------------------------------------------------------------
-%% Function: all(Clause) -> TestCases
-%% Clause - atom() - suite | doc
-%% TestCases - [Case]
-%% Case - atom()
-%% Name of a test case.
-%% Description: Returns a list of all test cases in this test suite
-%%--------------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- [session_cleanup,
- session_cache_process_list,
- session_cache_process_mnesia].
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
Config.
-end_per_group(_GroupName, Config) ->
- Config.
%%--------------------------------------------------------------------
-session_cleanup(doc) ->
- ["Test that sessions are cleand up eventually, so that the session table "
- "does not grow and grow ..."];
-session_cleanup(suite) ->
- [];
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+session_cleanup() ->
+ [{doc, "Test that sessions are cleand up eventually, so that the session table "
+ "does not grow and grow ..."}].
session_cleanup(Config)when is_list(Config) ->
process_flag(trap_exit, true),
ClientOpts = ?config(client_opts, Config),
@@ -207,7 +161,7 @@ session_cleanup(Config)when is_list(Config) ->
end,
%% Make sure session is registered
- test_server:sleep(?SLEEP),
+ ct:sleep(?SLEEP),
{status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)),
[_, _,_, _, Prop] = StatusInfo,
@@ -224,14 +178,14 @@ session_cleanup(Config)when is_list(Config) ->
%% Make sure session has expired and been cleaned up
check_timer(SessionTimer),
- test_server:sleep(?DELAY *2), %% Delay time + some extra time
+ ct:sleep(?DELAY *2), %% Delay time + some extra time
{ServerDelayTimer, ClientDelayTimer} = get_delay_timers(),
check_timer(ServerDelayTimer),
check_timer(ClientDelayTimer),
- test_server:sleep(?SLEEP), %% Make sure clean has had time to run
+ ct:sleep(?SLEEP), %% Make sure clean has had time to run
undefined = ssl_session_cache:lookup(Cache, {{Hostname, Port}, Id}),
undefined = ssl_session_cache:lookup(Cache, {Port, Id}),
@@ -248,7 +202,7 @@ check_timer(Timer) ->
{status, _, _, _} = sys:get_status(whereis(ssl_manager)),
ok;
Int ->
- test_server:sleep(Int),
+ ct:sleep(Int),
check_timer(Timer)
end.
@@ -258,31 +212,25 @@ get_delay_timers() ->
State = ssl_test_lib:state(Prop),
case element(7, State) of
{undefined, undefined} ->
- test_server:sleep(?SLEEP),
+ ct:sleep(?SLEEP),
get_delay_timers();
{undefined, _} ->
- test_server:sleep(?SLEEP),
+ ct:sleep(?SLEEP),
get_delay_timers();
{_, undefined} ->
- test_server:sleep(?SLEEP),
+ ct:sleep(?SLEEP),
get_delay_timers();
DelayTimers ->
DelayTimers
end.
%%--------------------------------------------------------------------
-session_cache_process_list(doc) ->
- ["Test reuse of sessions (short handshake)"];
-
-session_cache_process_list(suite) ->
- [];
+session_cache_process_list() ->
+ [{doc,"Test reuse of sessions (short handshake)"}].
session_cache_process_list(Config) when is_list(Config) ->
session_cache_process(list,Config).
%%--------------------------------------------------------------------
-session_cache_process_mnesia(doc) ->
- ["Test reuse of sessions (short handshake)"];
-
-session_cache_process_mnesia(suite) ->
- [];
+session_cache_process_mnesia() ->
+ [{doc,"Test reuse of sessions (short handshake)"}].
session_cache_process_mnesia(Config) when is_list(Config) ->
session_cache_process(mnesia,Config).
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index 63731ee25c..76b302b1cb 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-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -20,8 +20,7 @@
%%
-module(ssl_test_lib).
--include("test_server.hrl").
--include("test_server_line.hrl").
+-include_lib("common_test/include/ct.hrl").
-include_lib("public_key/include/public_key.hrl").
%% Note: This directive should only be used in test suites.
@@ -29,12 +28,6 @@
-record(sslsocket, { fd = nil, pid = nil}).
-timetrap(Time) ->
- Mul = try
- test_server:timetrap_scale_factor()
- catch _:_ -> 1 end,
- test_server:timetrap(1000+Time*Mul).
-
%% For now always run locally
run_where(_) ->
ClientNode = node(),
@@ -65,24 +58,32 @@ run_server(Opts) ->
Port = proplists:get_value(port, Opts),
Options = proplists:get_value(options, Opts),
Pid = proplists:get_value(from, Opts),
- test_server:format("ssl:listen(~p, ~p)~n", [Port, Options]),
- {ok, ListenSocket} = rpc:call(Node, ssl, listen, [Port, Options]),
+ Transport = proplists:get_value(transport, Opts, ssl),
+ ct:print("ssl:listen(~p, ~p)~n", [Port, Options]),
+ {ok, ListenSocket} = rpc:call(Node, Transport, listen, [Port, Options]),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
run_server(ListenSocket, Opts).
run_server(ListenSocket, Opts) ->
- AcceptSocket = connect(ListenSocket, Opts),
+ do_run_server(ListenSocket, connect(ListenSocket, Opts), Opts).
+
+do_run_server(_, {error, timeout} = Result, Opts) ->
+ Pid = proplists:get_value(from, Opts),
+ Pid ! {self(), Result};
+
+do_run_server(ListenSocket, AcceptSocket, Opts) ->
Node = proplists:get_value(node, Opts),
Pid = proplists:get_value(from, Opts),
+ Transport = proplists:get_value(transport, Opts, ssl),
{Module, Function, Args} = proplists:get_value(mfa, Opts),
- test_server:format("Server: apply(~p,~p,~p)~n",
+ ct:print("Server: apply(~p,~p,~p)~n",
[Module, Function, [AcceptSocket | Args]]),
case rpc:call(Node, Module, Function, [AcceptSocket | Args]) of
no_result_msg ->
ok;
Msg ->
- test_server:format("Server Msg: ~p ~n", [Msg]),
+ ct:print("Server Msg: ~p ~n", [Msg]),
Pid ! {self(), Msg}
end,
receive
@@ -91,35 +92,49 @@ run_server(ListenSocket, Opts) ->
{listen, MFA} ->
run_server(ListenSocket, [MFA | proplists:delete(mfa, Opts)]);
close ->
- test_server:format("Server closing ~p ~n", [self()]),
- Result = rpc:call(Node, ssl, close, [AcceptSocket], 500),
- test_server:format("Result ~p ~n", [Result]);
+ ct:print("Server closing ~p ~n", [self()]),
+ Result = rpc:call(Node, Transport, close, [AcceptSocket], 500),
+ Result1 = rpc:call(Node, Transport, close, [ListenSocket], 500),
+ ct:print("Result ~p : ~p ~n", [Result, Result1]);
{ssl_closed, _} ->
ok
end.
%%% To enable to test with s_client -reconnect
-connect(ListenSocket, Opts) ->
+connect(#sslsocket{} = ListenSocket, Opts) ->
Node = proplists:get_value(node, Opts),
ReconnectTimes = proplists:get_value(reconnect_times, Opts, 0),
- AcceptSocket = connect(ListenSocket, Node, 1 + ReconnectTimes, dummy),
+ Timeout = proplists:get_value(timeout, Opts, infinity),
+ AcceptSocket = connect(ListenSocket, Node, 1 + ReconnectTimes, dummy, Timeout),
case ReconnectTimes of
0 ->
AcceptSocket;
_ ->
remove_close_msg(ReconnectTimes),
AcceptSocket
- end.
-
-connect(_, _, 0, AcceptSocket) ->
+ end;
+connect(ListenSocket, Opts) ->
+ Node = proplists:get_value(node, Opts),
+ ct:print("gen_tcp:accept(~p)~n", [ListenSocket]),
+ {ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept,
+ [ListenSocket]),
+ AcceptSocket.
+
+connect(_, _, 0, AcceptSocket, _) ->
AcceptSocket;
-connect(ListenSocket, Node, N, _) ->
- test_server:format("ssl:transport_accept(~p)~n", [ListenSocket]),
+connect(ListenSocket, Node, N, _, Timeout) ->
+ ct:print("ssl:transport_accept(~p)~n", [ListenSocket]),
{ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept,
[ListenSocket]),
- test_server:format("ssl:ssl_accept(~p)~n", [AcceptSocket]),
- ok = rpc:call(Node, ssl, ssl_accept, [AcceptSocket]),
- connect(ListenSocket, Node, N-1, AcceptSocket).
+ ct:print("ssl:ssl_accept(~p, ~p)~n", [AcceptSocket, Timeout]),
+
+ case rpc:call(Node, ssl, ssl_accept, [AcceptSocket, Timeout]) of
+ ok ->
+ connect(ListenSocket, Node, N-1, AcceptSocket, Timeout);
+ Result ->
+ Result
+ end.
+
remove_close_msg(0) ->
ok;
@@ -144,45 +159,48 @@ run_client(Opts) ->
Host = proplists:get_value(host, Opts),
Port = proplists:get_value(port, Opts),
Pid = proplists:get_value(from, Opts),
+ Transport = proplists:get_value(transport, Opts, ssl),
Options = proplists:get_value(options, Opts),
- test_server:format("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]),
- case rpc:call(Node, ssl, connect, [Host, Port, Options]) of
+ ct:print("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]),
+ case rpc:call(Node, Transport, connect, [Host, Port, Options]) of
{ok, Socket} ->
Pid ! { connected, Socket },
- test_server:format("Client: connected~n", []),
+ ct:print("Client: connected~n", []),
%% In special cases we want to know the client port, it will
%% be indicated by sending {port, 0} in options list!
send_selected_port(Pid, proplists:get_value(port, Options), Socket),
{Module, Function, Args} = proplists:get_value(mfa, Opts),
- test_server:format("Client: apply(~p,~p,~p)~n",
+ ct:print("Client: apply(~p,~p,~p)~n",
[Module, Function, [Socket | Args]]),
case rpc:call(Node, Module, Function, [Socket | Args]) of
no_result_msg ->
ok;
Msg ->
- test_server:format("Client Msg: ~p ~n", [Msg]),
+ ct:print("Client Msg: ~p ~n", [Msg]),
Pid ! {self(), Msg}
end,
receive
close ->
- test_server:format("Client closing~n", []),
- rpc:call(Node, ssl, close, [Socket]);
+ ct:print("Client closing~n", []),
+ rpc:call(Node, Transport, close, [Socket]);
{ssl_closed, Socket} ->
+ ok;
+ {gen_tcp, closed} ->
ok
end;
{error, Reason} ->
- test_server:format("Client: connection failed: ~p ~n", [Reason]),
+ ct:print("Client: connection failed: ~p ~n", [Reason]),
Pid ! {self(), {error, Reason}}
end.
close(Pid) ->
- test_server:format("Close ~p ~n", [Pid]),
+ ct:print("Close ~p ~n", [Pid]),
Monitor = erlang:monitor(process, Pid),
Pid ! close,
receive
{'DOWN', Monitor, process, Pid, Reason} ->
erlang:demonitor(Monitor),
- test_server:format("Pid: ~p down due to:~p ~n", [Pid, Reason])
+ ct:print("Pid: ~p down due to:~p ~n", [Pid, Reason])
end.
check_result(Server, ServerMsg, Client, ClientMsg) ->
@@ -194,7 +212,7 @@ check_result(Server, ServerMsg, Client, ClientMsg) ->
Unexpected ->
Reason = {{expected, {Client, ClientMsg}},
{got, Unexpected}},
- test_server:fail(Reason)
+ ct:fail(Reason)
end;
{Client, ClientMsg} ->
receive
@@ -203,7 +221,7 @@ check_result(Server, ServerMsg, Client, ClientMsg) ->
Unexpected ->
Reason = {{expected, {Server, ClientMsg}},
{got, Unexpected}},
- test_server:fail(Reason)
+ ct:fail(Reason)
end;
{Port, {data,Debug}} when is_port(Port) ->
io:format("openssl ~s~n",[Debug]),
@@ -212,7 +230,7 @@ check_result(Server, ServerMsg, Client, ClientMsg) ->
Unexpected ->
Reason = {{expected, {Client, ClientMsg}},
{expected, {Server, ServerMsg}}, {got, Unexpected}},
- test_server:fail(Reason)
+ ct:fail(Reason)
end.
check_result(Pid, Msg) ->
@@ -225,7 +243,7 @@ check_result(Pid, Msg) ->
Unexpected ->
Reason = {{expected, {Pid, Msg}},
{got, Unexpected}},
- test_server:fail(Reason)
+ ct:fail(Reason)
end.
wait_for_result(Server, ServerMsg, Client, ClientMsg) ->
@@ -392,33 +410,33 @@ run_upgrade_server(Opts) ->
SslOptions = proplists:get_value(ssl_options, Opts),
Pid = proplists:get_value(from, Opts),
- test_server:format("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]),
+ ct:print("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]),
{ok, ListenSocket} = rpc:call(Node, gen_tcp, listen, [Port, TcpOptions]),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- test_server:format("gen_tcp:accept(~p)~n", [ListenSocket]),
+ ct:print("gen_tcp:accept(~p)~n", [ListenSocket]),
{ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept, [ListenSocket]),
try
{ok, SslAcceptSocket} = case TimeOut of
infinity ->
- test_server:format("ssl:ssl_accept(~p, ~p)~n",
+ ct:print("ssl:ssl_accept(~p, ~p)~n",
[AcceptSocket, SslOptions]),
rpc:call(Node, ssl, ssl_accept,
[AcceptSocket, SslOptions]);
_ ->
- test_server:format("ssl:ssl_accept(~p, ~p, ~p)~n",
+ ct:print("ssl:ssl_accept(~p, ~p, ~p)~n",
[AcceptSocket, SslOptions, TimeOut]),
rpc:call(Node, ssl, ssl_accept,
[AcceptSocket, SslOptions, TimeOut])
end,
{Module, Function, Args} = proplists:get_value(mfa, Opts),
Msg = rpc:call(Node, Module, Function, [SslAcceptSocket | Args]),
- test_server:format("Upgrade Server Msg: ~p ~n", [Msg]),
+ ct:print("Upgrade Server Msg: ~p ~n", [Msg]),
Pid ! {self(), Msg},
receive
close ->
- test_server:format("Upgrade Server closing~n", []),
+ ct:print("Upgrade Server closing~n", []),
rpc:call(Node, ssl, close, [SslAcceptSocket])
end
catch error:{badmatch, Error} ->
@@ -436,24 +454,24 @@ run_upgrade_client(Opts) ->
TcpOptions = proplists:get_value(tcp_options, Opts),
SslOptions = proplists:get_value(ssl_options, Opts),
- test_server:format("gen_tcp:connect(~p, ~p, ~p)~n",
+ ct:print("gen_tcp:connect(~p, ~p, ~p)~n",
[Host, Port, TcpOptions]),
{ok, Socket} = rpc:call(Node, gen_tcp, connect, [Host, Port, TcpOptions]),
send_selected_port(Pid, Port, Socket),
- test_server:format("ssl:connect(~p, ~p)~n", [Socket, SslOptions]),
+ ct:print("ssl:connect(~p, ~p)~n", [Socket, SslOptions]),
{ok, SslSocket} = rpc:call(Node, ssl, connect, [Socket, SslOptions]),
{Module, Function, Args} = proplists:get_value(mfa, Opts),
- test_server:format("apply(~p, ~p, ~p)~n",
+ ct:print("apply(~p, ~p, ~p)~n",
[Module, Function, [SslSocket | Args]]),
Msg = rpc:call(Node, Module, Function, [SslSocket | Args]),
- test_server:format("Upgrade Client Msg: ~p ~n", [Msg]),
+ ct:print("Upgrade Client Msg: ~p ~n", [Msg]),
Pid ! {self(), Msg},
receive
close ->
- test_server:format("Upgrade Client closing~n", []),
+ ct:print("Upgrade Client closing~n", []),
rpc:call(Node, ssl, close, [SslSocket])
end.
@@ -472,20 +490,20 @@ run_upgrade_server_error(Opts) ->
SslOptions = proplists:get_value(ssl_options, Opts),
Pid = proplists:get_value(from, Opts),
- test_server:format("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]),
+ ct:print("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]),
{ok, ListenSocket} = rpc:call(Node, gen_tcp, listen, [Port, TcpOptions]),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- test_server:format("gen_tcp:accept(~p)~n", [ListenSocket]),
+ ct:print("gen_tcp:accept(~p)~n", [ListenSocket]),
{ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept, [ListenSocket]),
Error = case TimeOut of
infinity ->
- test_server:format("ssl:ssl_accept(~p, ~p)~n",
+ ct:print("ssl:ssl_accept(~p, ~p)~n",
[AcceptSocket, SslOptions]),
rpc:call(Node, ssl, ssl_accept,
[AcceptSocket, SslOptions]);
_ ->
- test_server:format("ssl:ssl_accept(~p, ~p, ~p)~n",
+ ct:print("ssl:ssl_accept(~p, ~p, ~p)~n",
[AcceptSocket, SslOptions, TimeOut]),
rpc:call(Node, ssl, ssl_accept,
[AcceptSocket, SslOptions, TimeOut])
@@ -504,22 +522,31 @@ run_server_error(Opts) ->
Port = proplists:get_value(port, Opts),
Options = proplists:get_value(options, Opts),
Pid = proplists:get_value(from, Opts),
- test_server:format("ssl:listen(~p, ~p)~n", [Port, Options]),
- case rpc:call(Node, ssl, listen, [Port, Options]) of
- {ok, ListenSocket} ->
+ Transport = proplists:get_value(transport, Opts, ssl),
+ ct:print("ssl:listen(~p, ~p)~n", [Port, Options]),
+ case rpc:call(Node, Transport, listen, [Port, Options]) of
+ {ok, #sslsocket{} = ListenSocket} ->
%% To make sure error_client will
%% get {error, closed} and not {error, connection_refused}
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- test_server:format("ssl:transport_accept(~p)~n", [ListenSocket]),
- case rpc:call(Node, ssl, transport_accept, [ListenSocket]) of
+ ct:print("ssl:transport_accept(~p)~n", [ListenSocket]),
+ case rpc:call(Node, Transport, transport_accept, [ListenSocket]) of
{error, _} = Error ->
Pid ! {self(), Error};
{ok, AcceptSocket} ->
- test_server:format("ssl:ssl_accept(~p)~n", [AcceptSocket]),
+ ct:print("ssl:ssl_accept(~p)~n", [AcceptSocket]),
Error = rpc:call(Node, ssl, ssl_accept, [AcceptSocket]),
Pid ! {self(), Error}
end;
+ {ok, ListenSocket} ->
+ Pid ! {listen, up},
+ send_selected_port(Pid, Port, ListenSocket),
+ ct:print("~p:accept(~p)~n", [Transport, ListenSocket]),
+ case rpc:call(Node, Transport, accept, [ListenSocket]) of
+ {error, _} = Error ->
+ Pid ! {self(), Error}
+ end;
Error ->
%% Not really true but as this is an error test
%% this is what we want.
@@ -535,9 +562,10 @@ run_client_error(Opts) ->
Host = proplists:get_value(host, Opts),
Port = proplists:get_value(port, Opts),
Pid = proplists:get_value(from, Opts),
+ Transport = proplists:get_value(transport, Opts, ssl),
Options = proplists:get_value(options, Opts),
- test_server:format("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]),
- Error = rpc:call(Node, ssl, connect, [Host, Port, Options]),
+ ct:print("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]),
+ Error = rpc:call(Node, Transport, connect, [Host, Port, Options]),
Pid ! {self(), Error}.
inet_port(Pid) when is_pid(Pid)->
@@ -564,7 +592,7 @@ trigger_renegotiate(Socket, [ErlData, N]) ->
trigger_renegotiate(Socket, ErlData, N, Id).
trigger_renegotiate(Socket, _, 0, Id) ->
- test_server:sleep(1000),
+ ct:sleep(1000),
case ssl:session_info(Socket) of
[{session_id, Id} | _ ] ->
fail_session_not_renegotiated;
@@ -657,7 +685,7 @@ der_to_pem(File, Entries) ->
cipher_result(Socket, Result) ->
Result = ssl:connection_info(Socket),
- test_server:format("Successfull connect: ~p~n", [Result]),
+ ct:print("Successfull connect: ~p~n", [Result]),
%% Importante to send two packets here
%% to properly test "cipher state" handling
ssl:send(Socket, "Hello\n"),
@@ -738,3 +766,33 @@ sufficient_crypto_support('tlsv1.2') ->
end;
sufficient_crypto_support(_) ->
true.
+
+send_recv_result_active(Socket) ->
+ ssl:send(Socket, "Hello world"),
+ receive
+ {ssl, Socket, "H"} ->
+ receive
+ {ssl, Socket, "ello world"} ->
+ ok
+ end;
+ {ssl, Socket, "Hello world"} ->
+ ok
+ end.
+
+send_recv_result(Socket) ->
+ ssl:send(Socket, "Hello world"),
+ {ok,"Hello world"} = ssl:recv(Socket, 11),
+ ok.
+
+send_recv_result_active_once(Socket) ->
+ ssl:send(Socket, "Hello world"),
+ receive
+ {ssl, Socket, "H"} ->
+ ssl:setopts(Socket, [{active, once}]),
+ receive
+ {ssl, Socket, "ello world"} ->
+ ok
+ end;
+ {ssl, Socket, "Hello world"} ->
+ ok
+ end.
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index 21797bee08..d5e7d515fd 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-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -16,7 +16,6 @@
%%
%% %CopyrightEnd%
%%
-
%%
-module(ssl_to_openssl_SUITE).
@@ -34,131 +33,10 @@
-define(OPENSSL_GARBAGE, "P\n").
-define(EXPIRE, 10).
-%% Test server callback functions
-%%--------------------------------------------------------------------
-%% Function: init_per_suite(Config) -> Config
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Initialization before the whole suite
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
-%%--------------------------------------------------------------------
-init_per_suite(Config0) ->
- Dog = ssl_test_lib:timetrap(?LONG_TIMEOUT *2),
- case os:find_executable("openssl") of
- false ->
- {skip, "Openssl not found"};
- _ ->
- catch crypto:stop(),
- try crypto:start() of
- ok ->
- application:start(public_key),
- ssl:start(),
- Result =
- (catch make_certs:all(?config(data_dir, Config0),
- ?config(priv_dir, Config0))),
- test_server:format("Make certs ~p~n", [Result]),
- Config1 = ssl_test_lib:make_dsa_cert(Config0),
- Config = ssl_test_lib:cert_options(Config1),
- [{watchdog, Dog} | Config]
- catch _:_ ->
- {skip, "Crypto did not start"}
- end
- end.
-
-%%--------------------------------------------------------------------
-%% Function: end_per_suite(Config) -> _
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after the whole suite
-%%--------------------------------------------------------------------
-end_per_suite(_Config) ->
- ssl:stop(),
- application:stop(crypto).
-
-%%--------------------------------------------------------------------
-%% Function: init_per_testcase(TestCase, Config) -> Config
-%% Case - atom()
-%% Name of the test case that is about to be run.
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%%
-%% Description: Initialization before each test case
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
-%% Description: Initialization before each test case
-%%--------------------------------------------------------------------
-init_per_testcase(expired_session, Config0) ->
- Config = lists:keydelete(watchdog, 1, Config0),
- Dog = ssl_test_lib:timetrap(?EXPIRE * 1000 * 5),
- ssl:stop(),
- application:load(ssl),
- application:set_env(ssl, session_lifetime, ?EXPIRE),
- ssl:start(),
- [{watchdog, Dog} | Config];
-
-init_per_testcase(TestCase, Config0) ->
- Config = lists:keydelete(watchdog, 1, Config0),
- Dog = ssl_test_lib:timetrap(?TIMEOUT),
- special_init(TestCase, [{watchdog, Dog} | Config]).
-
-special_init(TestCase, Config)
- when TestCase == erlang_client_openssl_server_renegotiate;
- TestCase == erlang_client_openssl_server_no_wrap_sequence_number;
- TestCase == erlang_server_openssl_client_no_wrap_sequence_number
- ->
- check_sane_openssl_renegotaite(Config);
-
-special_init(ssl2_erlang_server_openssl_client, Config) ->
- check_sane_openssl_sslv2(Config);
-
-special_init(TestCase, Config)
- when TestCase == erlang_client_openssl_server_npn;
- TestCase == erlang_server_openssl_client_npn;
- TestCase == erlang_server_openssl_client_npn_renegotiate;
- TestCase == erlang_client_openssl_server_npn_renegotiate;
- TestCase == erlang_server_openssl_client_npn_only_server;
- TestCase == erlang_server_openssl_client_npn_only_client;
- TestCase == erlang_client_openssl_server_npn_only_client;
- TestCase == erlang_client_openssl_server_npn_only_server ->
- check_openssl_npn_support(Config);
-
-special_init(_, Config) ->
- Config.
-
%%--------------------------------------------------------------------
-%% Function: end_per_testcase(TestCase, Config) -> _
-%% Case - atom()
-%% Name of the test case that is about to be run.
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after each test case
+%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
-end_per_testcase(reuse_session_expired, Config) ->
- application:unset_env(ssl, session_lifetime),
- end_per_testcase(default_action, Config);
-
-end_per_testcase(default_action, Config) ->
- Dog = ?config(watchdog, Config),
- case Dog of
- undefined ->
- ok;
- _ ->
- test_server:timetrap_cancel(Dog)
- end;
-end_per_testcase(_, Config) ->
- end_per_testcase(default_action, Config).
-%%--------------------------------------------------------------------
-%% Function: all(Clause) -> TestCases
-%% Clause - atom() - suite | doc
-%% TestCases - [Case]
-%% Case - atom()
-%% Name of a test case.
-%% Description: Returns a list of all test cases in this test suite
-%%--------------------------------------------------------------------
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
@@ -211,6 +89,34 @@ npn_tests() ->
erlang_client_openssl_server_npn_only_client,
erlang_client_openssl_server_npn_only_server].
+
+init_per_suite(Config0) ->
+ Dog = ct:timetrap(?LONG_TIMEOUT *2),
+ case os:find_executable("openssl") of
+ false ->
+ {skip, "Openssl not found"};
+ _ ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ application:start(public_key),
+ ssl:start(),
+ Result =
+ (catch make_certs:all(?config(data_dir, Config0),
+ ?config(priv_dir, Config0))),
+ ct:print("Make certs ~p~n", [Result]),
+ Config1 = ssl_test_lib:make_dsa_cert(Config0),
+ Config = ssl_test_lib:cert_options(Config1),
+ [{watchdog, Dog} | Config]
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto).
+
init_per_group(GroupName, Config) ->
case ssl_test_lib:is_tls_version(GroupName) of
true ->
@@ -229,13 +135,55 @@ init_per_group(GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
+init_per_testcase(expired_session, Config0) ->
+ Config = lists:keydelete(watchdog, 1, Config0),
+ Dog = ct:timetrap(?EXPIRE * 1000 * 5),
+ ssl:stop(),
+ application:load(ssl),
+ application:set_env(ssl, session_lifetime, ?EXPIRE),
+ ssl:start(),
+ [{watchdog, Dog} | Config];
+
+init_per_testcase(TestCase, Config0) ->
+ Config = lists:keydelete(watchdog, 1, Config0),
+ Dog = ct:timetrap(?TIMEOUT),
+ special_init(TestCase, [{watchdog, Dog} | Config]).
+
+special_init(TestCase, Config)
+ when TestCase == erlang_client_openssl_server_renegotiate;
+ TestCase == erlang_client_openssl_server_nowrap_seqnum;
+ TestCase == erlang_server_openssl_client_nowrap_seqnum
+ ->
+ check_sane_openssl_renegotaite(Config);
+
+special_init(ssl2_erlang_server_openssl_client, Config) ->
+ check_sane_openssl_sslv2(Config);
+
+special_init(TestCase, Config)
+ when TestCase == erlang_client_openssl_server_npn;
+ TestCase == erlang_server_openssl_client_npn;
+ TestCase == erlang_server_openssl_client_npn_renegotiate;
+ TestCase == erlang_client_openssl_server_npn_renegotiate;
+ TestCase == erlang_server_openssl_client_npn_only_server;
+ TestCase == erlang_server_openssl_client_npn_only_client;
+ TestCase == erlang_client_openssl_server_npn_only_client;
+ TestCase == erlang_client_openssl_server_npn_only_server ->
+ check_openssl_npn_support(Config);
+
+special_init(_, Config) ->
+ Config.
+
+end_per_testcase(reuse_session_expired, Config) ->
+ application:unset_env(ssl, session_lifetime),
+ Config;
+end_per_testcase(_, Config) ->
+ Config.
-%% Test cases starts here.
%%--------------------------------------------------------------------
-basic_erlang_client_openssl_server(doc) ->
- ["Test erlang client with openssl server"];
-basic_erlang_client_openssl_server(suite) ->
- [];
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+basic_erlang_client_openssl_server() ->
+ [{doc,"Test erlang client with openssl server"}].
basic_erlang_client_openssl_server(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ServerOpts = ?config(server_opts, Config),
@@ -252,7 +200,7 @@ basic_erlang_client_openssl_server(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile,
- test_server:format("openssl cmd: ~p~n", [Cmd]),
+ ct:print("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -271,14 +219,11 @@ basic_erlang_client_openssl_server(Config) when is_list(Config) ->
%% Clean close down! Server needs to be closed first !!
close_port(OpensslPort),
ssl_test_lib:close(Client),
- process_flag(trap_exit, false),
- ok.
+ process_flag(trap_exit, false).
%%--------------------------------------------------------------------
-basic_erlang_server_openssl_client(doc) ->
- ["Test erlang server with openssl client"];
-basic_erlang_server_openssl_client(suite) ->
- [];
+basic_erlang_server_openssl_client() ->
+ [{doc,"Test erlang server with openssl client"}].
basic_erlang_server_openssl_client(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ServerOpts = ?config(server_opts, Config),
@@ -296,7 +241,7 @@ basic_erlang_server_openssl_client(Config) when is_list(Config) ->
Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++
" -host localhost",
- test_server:format("openssl cmd: ~p~n", [Cmd]),
+ ct:print("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
port_command(OpenSslPort, Data),
@@ -309,10 +254,8 @@ basic_erlang_server_openssl_client(Config) when is_list(Config) ->
process_flag(trap_exit, false),
ok.
%%--------------------------------------------------------------------
-erlang_client_openssl_server(doc) ->
- ["Test erlang client with openssl server"];
-erlang_client_openssl_server(suite) ->
- [];
+erlang_client_openssl_server() ->
+ [{doc,"Test erlang client with openssl server"}].
erlang_client_openssl_server(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ServerOpts = ?config(server_opts, Config),
@@ -329,7 +272,7 @@ erlang_client_openssl_server(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile,
- test_server:format("openssl cmd: ~p~n", [Cmd]),
+ ct:print("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -348,15 +291,11 @@ erlang_client_openssl_server(Config) when is_list(Config) ->
%% Clean close down! Server needs to be closed first !!
close_port(OpensslPort),
ssl_test_lib:close(Client),
- process_flag(trap_exit, false),
- ok.
-
+ process_flag(trap_exit, false).
%%--------------------------------------------------------------------
-erlang_server_openssl_client(doc) ->
- ["Test erlang server with openssl client"];
-erlang_server_openssl_client(suite) ->
- [];
+erlang_server_openssl_client() ->
+ [{doc,"Test erlang server with openssl client"}].
erlang_server_openssl_client(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ServerOpts = ?config(server_opts, Config),
@@ -375,7 +314,7 @@ erlang_server_openssl_client(Config) when is_list(Config) ->
Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost",
- test_server:format("openssl cmd: ~p~n", [Cmd]),
+ ct:print("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
port_command(OpenSslPort, Data),
@@ -385,15 +324,12 @@ erlang_server_openssl_client(Config) when is_list(Config) ->
%% Clean close down! Server needs to be closed first !!
ssl_test_lib:close(Server),
close_port(OpenSslPort),
- process_flag(trap_exit, false),
- ok.
+ process_flag(trap_exit, false).
%%--------------------------------------------------------------------
-erlang_client_openssl_server_dsa_cert(doc) ->
- ["Test erlang server with openssl client"];
-erlang_client_openssl_server_dsa_cert(suite) ->
- [];
+erlang_client_openssl_server_dsa_cert() ->
+ [{doc,"Test erlang server with openssl client"}].
erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ClientOpts = ?config(client_dsa_opts, Config),
@@ -413,7 +349,7 @@ erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) ->
" -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile
++ " -key " ++ KeyFile ++ " -Verify 2 -msg",
- test_server:format("openssl cmd: ~p~n", [Cmd]),
+ ct:print("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -436,10 +372,8 @@ erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) ->
process_flag(trap_exit, false),
ok.
%%--------------------------------------------------------------------
-erlang_server_openssl_client_dsa_cert(doc) ->
- ["Test erlang server with openssl client"];
-erlang_server_openssl_client_dsa_cert(suite) ->
- [];
+erlang_server_openssl_client_dsa_cert() ->
+ [{doc,"Test erlang server with openssl client"}].
erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ClientOpts = ?config(client_dsa_opts, Config),
@@ -462,7 +396,7 @@ erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) ->
" -host localhost " ++ " -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile
++ " -key " ++ KeyFile ++ " -msg",
- test_server:format("openssl cmd: ~p~n", [Cmd]),
+ ct:print("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
port_command(OpenSslPort, Data),
@@ -472,16 +406,13 @@ erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) ->
%% Clean close down! Server needs to be closed first !!
ssl_test_lib:close(Server),
close_port(OpenSslPort),
- process_flag(trap_exit, false),
- ok.
+ process_flag(trap_exit, false).
%%--------------------------------------------------------------------
-erlang_server_openssl_client_reuse_session(doc) ->
- ["Test erlang server with openssl client that reconnects with the"
- "same session id, to test reusing of sessions."];
-erlang_server_openssl_client_reuse_session(suite) ->
- [];
+erlang_server_openssl_client_reuse_session() ->
+ [{doc, "Test erlang server with openssl client that reconnects with the"
+ "same session id, to test reusing of sessions."}].
erlang_server_openssl_client_reuse_session(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ServerOpts = ?config(server_opts, Config),
@@ -500,7 +431,7 @@ erlang_server_openssl_client_reuse_session(Config) when is_list(Config) ->
Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost -reconnect",
- test_server:format("openssl cmd: ~p~n", [Cmd]),
+ ct:print("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -516,10 +447,8 @@ erlang_server_openssl_client_reuse_session(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-erlang_client_openssl_server_renegotiate(doc) ->
- ["Test erlang client when openssl server issuses a renegotiate"];
-erlang_client_openssl_server_renegotiate(suite) ->
- [];
+erlang_client_openssl_server_renegotiate() ->
+ [{doc,"Test erlang client when openssl server issuses a renegotiate"}].
erlang_client_openssl_server_renegotiate(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ServerOpts = ?config(server_opts, Config),
@@ -538,7 +467,7 @@ erlang_client_openssl_server_renegotiate(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg",
- test_server:format("openssl cmd: ~p~n", [Cmd]),
+ ct:print("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -552,7 +481,7 @@ erlang_client_openssl_server_renegotiate(Config) when is_list(Config) ->
{options, ClientOpts}]),
port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
- test_server:sleep(?SLEEP),
+ ct:sleep(?SLEEP),
port_command(OpensslPort, OpenSslData),
ssl_test_lib:check_result(Client, ok),
@@ -565,13 +494,11 @@ erlang_client_openssl_server_renegotiate(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-erlang_client_openssl_server_nowrap_seqnum(doc) ->
- ["Test that erlang client will renegotiate session when",
+erlang_client_openssl_server_nowrap_seqnum() ->
+ [{doc, "Test that erlang client will renegotiate session when",
"max sequence number celing is about to be reached. Although"
"in the testcase we use the test option renegotiate_at"
- " to lower treashold substantially."];
-erlang_client_openssl_server_nowrap_seqnum(suite) ->
- [];
+ " to lower treashold substantially."}].
erlang_client_openssl_server_nowrap_seqnum(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ServerOpts = ?config(server_opts, Config),
@@ -589,7 +516,7 @@ erlang_client_openssl_server_nowrap_seqnum(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg",
- test_server:format("openssl cmd: ~p~n", [Cmd]),
+ ct:print("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -608,17 +535,13 @@ erlang_client_openssl_server_nowrap_seqnum(Config) when is_list(Config) ->
%% Clean close down! Server needs to be closed first !!
close_port(OpensslPort),
ssl_test_lib:close(Client),
- process_flag(trap_exit, false),
- ok.
+ process_flag(trap_exit, false).
%%--------------------------------------------------------------------
-erlang_server_openssl_client_nowrap_seqnum(doc) ->
- ["Test that erlang client will renegotiate session when",
+erlang_server_openssl_client_nowrap_seqnum() ->
+ [{doc, "Test that erlang client will renegotiate session when",
"max sequence number celing is about to be reached. Although"
"in the testcase we use the test option renegotiate_at"
- " to lower treashold substantially."];
-
-erlang_server_openssl_client_nowrap_seqnum(suite) ->
- [];
+ " to lower treashold substantially."}].
erlang_server_openssl_client_nowrap_seqnum(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ServerOpts = ?config(server_opts, Config),
@@ -639,7 +562,7 @@ erlang_server_openssl_client_nowrap_seqnum(Config) when is_list(Config) ->
Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost -msg",
- test_server:format("openssl cmd: ~p~n", [Cmd]),
+ ct:print("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -650,16 +573,14 @@ erlang_server_openssl_client_nowrap_seqnum(Config) when is_list(Config) ->
%% Clean close down! Server needs to be closed first !!
ssl_test_lib:close(Server),
close_port(OpenSslPort),
- process_flag(trap_exit, false),
- ok.
+ process_flag(trap_exit, false).
+
%%--------------------------------------------------------------------
-erlang_client_openssl_server_no_server_ca_cert(doc) ->
- ["Test erlang client when openssl server sends a cert chain not"
+erlang_client_openssl_server_no_server_ca_cert() ->
+ [{doc, "Test erlang client when openssl server sends a cert chain not"
"including the ca cert. Explicitly test this even if it is"
- "implicitly tested eleswhere."];
-erlang_client_openssl_server_no_server_ca_cert(suite) ->
- [];
+ "implicitly tested eleswhere."}].
erlang_client_openssl_server_no_server_ca_cert(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ServerOpts = ?config(server_opts, Config),
@@ -676,7 +597,7 @@ erlang_client_openssl_server_no_server_ca_cert(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg",
- test_server:format("openssl cmd: ~p~n", [Cmd]),
+ ct:print("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -696,14 +617,11 @@ erlang_client_openssl_server_no_server_ca_cert(Config) when is_list(Config) ->
%% Clean close down! Server needs to be closed first !!
close_port(OpensslPort),
ssl_test_lib:close(Client),
- process_flag(trap_exit, false),
- ok.
+ process_flag(trap_exit, false).
%%--------------------------------------------------------------------
-erlang_client_openssl_server_client_cert(doc) ->
- ["Test erlang client with openssl server when client sends cert"];
-erlang_client_openssl_server_client_cert(suite) ->
- [];
+erlang_client_openssl_server_client_cert() ->
+ [{doc,"Test erlang client with openssl server when client sends cert"}].
erlang_client_openssl_server_client_cert(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ServerOpts = ?config(server_verification_opts, Config),
@@ -722,7 +640,7 @@ erlang_client_openssl_server_client_cert(Config) when is_list(Config) ->
" -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile
++ " -key " ++ KeyFile ++ " -Verify 2",
- test_server:format("openssl cmd: ~p~n", [Cmd]),
+ ct:print("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -741,15 +659,12 @@ erlang_client_openssl_server_client_cert(Config) when is_list(Config) ->
%% Clean close down! Server needs to be closed first !!
close_port(OpensslPort),
ssl_test_lib:close(Client),
- process_flag(trap_exit, false),
- ok.
+ process_flag(trap_exit, false).
%%--------------------------------------------------------------------
-erlang_server_openssl_client_client_cert(doc) ->
- ["Test erlang server with openssl client when client sends cert"];
-erlang_server_openssl_client_client_cert(suite) ->
- [];
+erlang_server_openssl_client_client_cert() ->
+ [{doc,"Test erlang server with openssl client when client sends cert"}].
erlang_server_openssl_client_client_cert(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ServerOpts = ?config(server_verification_opts, Config),
@@ -776,7 +691,7 @@ erlang_server_openssl_client_client_cert(Config) when is_list(Config) ->
++ " -key " ++ KeyFile ++ " -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost",
- test_server:format("openssl cmd: ~p~n", [Cmd]),
+ ct:print("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
port_command(OpenSslPort, Data),
@@ -786,16 +701,12 @@ erlang_server_openssl_client_client_cert(Config) when is_list(Config) ->
%% Clean close down! Server needs to be closed first !!
close_port(OpenSslPort),
ssl_test_lib:close(Server),
- process_flag(trap_exit, false),
- ok.
-
+ process_flag(trap_exit, false).
%%--------------------------------------------------------------------
-erlang_server_erlang_client_client_cert(doc) ->
- ["Test erlang server with erlang client when client sends cert"];
-erlang_server_erlang_client_client_cert(suite) ->
- [];
+erlang_server_erlang_client_client_cert() ->
+ [{doc,"Test erlang server with erlang client when client sends cert"}].
erlang_server_erlang_client_client_cert(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ServerOpts = ?config(server_verification_opts, Config),
@@ -828,30 +739,22 @@ erlang_server_erlang_client_client_cert(Config) when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client),
- process_flag(trap_exit, false),
- ok.
-%%--------------------------------------------------------------------
+ process_flag(trap_exit, false).
-ciphers_rsa_signed_certs(doc) ->
- ["Test cipher suites that uses rsa certs"];
-
-ciphers_rsa_signed_certs(suite) ->
- [];
+%%--------------------------------------------------------------------
+ciphers_rsa_signed_certs() ->
+ [{doc,"Test cipher suites that uses rsa certs"}].
ciphers_rsa_signed_certs(Config) when is_list(Config) ->
Version =
ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:rsa_suites(),
run_suites(Ciphers, Version, Config, rsa).
+%%--------------------------------------------------------------------
-
-ciphers_dsa_signed_certs(doc) ->
- ["Test cipher suites that uses dsa certs"];
-
-ciphers_dsa_signed_certs(suite) ->
- [];
-
+ciphers_dsa_signed_certs() ->
+ [{doc,"Test cipher suites that uses dsa certs"}].
ciphers_dsa_signed_certs(Config) when is_list(Config) ->
Version =
ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
@@ -859,90 +762,9 @@ ciphers_dsa_signed_certs(Config) when is_list(Config) ->
Ciphers = ssl_test_lib:dsa_suites(),
run_suites(Ciphers, Version, Config, dsa).
-run_suites(Ciphers, Version, Config, Type) ->
- {ClientOpts, ServerOpts} =
- case Type of
- rsa ->
- {?config(client_opts, Config),
- ?config(server_opts, Config)};
- dsa ->
- {?config(client_opts, Config),
- ?config(server_dsa_opts, Config)}
- end,
-
- Result = lists:map(fun(Cipher) ->
- cipher(Cipher, Version, Config, ClientOpts, ServerOpts) end,
- Ciphers),
- case lists:flatten(Result) of
- [] ->
- ok;
- Error ->
- test_server:format("Cipher suite errors: ~p~n", [Error]),
- test_server:fail(cipher_suite_failed_see_test_case_log)
- end.
-
-cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
- process_flag(trap_exit, true),
- test_server:format("Testing CipherSuite ~p~n", [CipherSuite]),
- {ClientNode, _ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Port = ssl_test_lib:inet_port(node()),
- CertFile = proplists:get_value(certfile, ServerOpts),
- KeyFile = proplists:get_value(keyfile, ServerOpts),
-
- Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
- " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "",
-
- test_server:format("openssl cmd: ~p~n", [Cmd]),
-
- OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
-
- wait_for_openssl_server(),
-
- ConnectionInfo = {ok, {Version, CipherSuite}},
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}},
- {options,
- [{ciphers,[CipherSuite]} |
- ClientOpts]}]),
-
- port_command(OpenSslPort, "Hello\n"),
-
- receive
- {Port, {data, _}} when is_port(Port) ->
- ok
- after 500 ->
- test_server:format("Time out on openssl port, check that"
- " the messages Hello and world are received"
- " during close of port" , []),
- ok
- end,
-
- port_command(OpenSslPort, " world\n"),
-
- Result = ssl_test_lib:wait_for_result(Client, ok),
-
- %% Clean close down! Server needs to be closed first !!
- close_port(OpenSslPort),
- ssl_test_lib:close(Client),
-
- Return = case Result of
- ok ->
- [];
- Error ->
- [{CipherSuite, Error}]
- end,
- process_flag(trap_exit, false),
- Return.
-
%%--------------------------------------------------------------------
-erlang_client_bad_openssl_server(doc) ->
- [""];
-erlang_client_bad_openssl_server(suite) ->
- [];
+erlang_client_bad_openssl_server() ->
+ [{doc,"Test what happens if openssl server sends garbage to erlang ssl client"}].
erlang_client_bad_openssl_server(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ServerOpts = ?config(server_verification_opts, Config),
@@ -957,7 +779,7 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "",
- test_server:format("openssl cmd: ~p~n", [Cmd]),
+ ct:print("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -973,7 +795,7 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) ->
%% Send garbage
port_command(OpensslPort, ?OPENSSL_GARBAGE),
- test_server:sleep(?SLEEP),
+ ct:sleep(?SLEEP),
Client0 ! server_sent_garbage,
@@ -997,13 +819,9 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-expired_session(doc) ->
- ["Test our ssl client handling of expired sessions. Will make"
- "better code coverage of the ssl_manager module"];
-
-expired_session(suite) ->
- [];
-
+expired_session() ->
+ [{doc, "Test our ssl client handling of expired sessions. Will make"
+ "better code coverage of the ssl_manager module"}].
expired_session(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ClientOpts = ?config(client_opts, Config),
@@ -1017,7 +835,7 @@ expired_session(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "",
- test_server:format("openssl cmd: ~p~n", [Cmd]),
+ ct:print("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -1032,7 +850,7 @@ expired_session(Config) when is_list(Config) ->
ssl_test_lib:close(Client0),
%% Make sure session is registered
- test_server:sleep(?SLEEP),
+ ct:sleep(?SLEEP),
Client1 =
ssl_test_lib:start_client([{node, ClientNode},
@@ -1042,7 +860,7 @@ expired_session(Config) when is_list(Config) ->
ssl_test_lib:close(Client1),
%% Make sure session is unregistered due to expiration
- test_server:sleep((?EXPIRE+1) * 1000),
+ ct:sleep((?EXPIRE+1) * 1000),
Client2 =
ssl_test_lib:start_client([{node, ClientNode},
@@ -1056,10 +874,9 @@ expired_session(Config) when is_list(Config) ->
process_flag(trap_exit, false).
%%--------------------------------------------------------------------
-ssl2_erlang_server_openssl_client(doc) ->
- ["Test that ssl v2 clients are rejected"];
-ssl2_erlang_server_openssl_client(suite) ->
- [];
+ssl2_erlang_server_openssl_client() ->
+ [{doc,"Test that ssl v2 clients are rejected"}].
+
ssl2_erlang_server_openssl_client(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ServerOpts = ?config(server_opts, Config),
@@ -1076,24 +893,22 @@ ssl2_erlang_server_openssl_client(Config) when is_list(Config) ->
Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++
" -host localhost -ssl2 -msg",
- test_server:format("openssl cmd: ~p~n", [Cmd]),
+ ct:print("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
port_command(OpenSslPort, Data),
-
+ receive
+ {'EXIT', OpenSslPort, _} ->
+ ok
+
+ end,
ssl_test_lib:check_result(Server, {error,"protocol version"}),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close(Server),
- close_port(OpenSslPort),
- process_flag(trap_exit, false),
- ok.
+ process_flag(trap_exit, false).
%%--------------------------------------------------------------------
-erlang_client_openssl_server_npn(doc) ->
- ["Test erlang client with openssl server doing npn negotiation"];
-erlang_client_openssl_server_npn(suite) ->
- [];
+erlang_client_openssl_server_npn() ->
+ [{doc,"Test erlang client with openssl server doing npn negotiation"}].
+
erlang_client_openssl_server_npn(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, fun(Client, OpensslPort) ->
@@ -1101,33 +916,25 @@ erlang_client_openssl_server_npn(Config) when is_list(Config) ->
ssl_test_lib:check_result(Client, ok)
end),
-
ok.
-
%%--------------------------------------------------------------------
-erlang_client_openssl_server_npn_renegotiate(doc) ->
- ["Test erlang client with openssl server doing npn negotiation and renegotiate"];
-erlang_client_openssl_server_npn_renegotiate(suite) ->
- [];
+erlang_client_openssl_server_npn_renegotiate() ->
+ [{doc,"Test erlang client with openssl server doing npn negotiation and renegotiate"}].
+
erlang_client_openssl_server_npn_renegotiate(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, fun(Client, OpensslPort) ->
port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
- test_server:sleep(?SLEEP),
+ ct:sleep(?SLEEP),
port_command(OpensslPort, Data),
ssl_test_lib:check_result(Client, ok)
end),
ok.
-
-
%%--------------------------------------------------------------------------
+erlang_server_openssl_client_npn() ->
+ [{doc,"Test erlang server with openssl client and npn negotiation"}].
-
-erlang_server_openssl_client_npn(doc) ->
- ["Test erlang server with openssl client and npn negotiation"];
-erlang_server_openssl_client_npn(suite) ->
- [];
erlang_server_openssl_client_npn(Config) when is_list(Config) ->
Data = "From openssl to erlang",
@@ -1138,25 +945,23 @@ erlang_server_openssl_client_npn(Config) when is_list(Config) ->
ok.
%%--------------------------------------------------------------------------
+erlang_server_openssl_client_npn_renegotiate() ->
+ [{doc,"Test erlang server with openssl client and npn negotiation with renegotiation"}].
-erlang_server_openssl_client_npn_renegotiate(doc) ->
- ["Test erlang server with openssl client and npn negotiation with renegotiation"];
-erlang_server_openssl_client_npn_renegotiate(suite) ->
- [];
erlang_server_openssl_client_npn_renegotiate(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, fun(Server, OpensslPort) ->
port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
- test_server:sleep(?SLEEP),
+ ct:sleep(?SLEEP),
port_command(OpensslPort, Data),
ssl_test_lib:check_result(Server, ok)
end),
ok.
%%--------------------------------------------------------------------------
-
erlang_client_openssl_server_npn_only_server(Config) when is_list(Config) ->
Data = "From openssl to erlang",
- start_erlang_client_and_openssl_server_with_opts(Config, [], "-nextprotoneg spdy/2", Data, fun(Server, OpensslPort) ->
+ start_erlang_client_and_openssl_server_with_opts(Config, [],
+ "-nextprotoneg spdy/2", Data, fun(Server, OpensslPort) ->
port_command(OpensslPort, Data),
ssl_test_lib:check_result(Server, ok)
end),
@@ -1166,7 +971,10 @@ erlang_client_openssl_server_npn_only_server(Config) when is_list(Config) ->
erlang_client_openssl_server_npn_only_client(Config) when is_list(Config) ->
Data = "From openssl to erlang",
- start_erlang_client_and_openssl_server_with_opts(Config, [{client_preferred_next_protocols, {client, [<<"spdy/2">>], <<"http/1.1">>}}], "", Data, fun(Server, OpensslPort) ->
+ start_erlang_client_and_openssl_server_with_opts(Config,
+ [{client_preferred_next_protocols,
+ {client, [<<"spdy/2">>], <<"http/1.1">>}}], "",
+ Data, fun(Server, OpensslPort) ->
port_command(OpensslPort, Data),
ssl_test_lib:check_result(Server, ok)
end),
@@ -1175,7 +983,8 @@ erlang_client_openssl_server_npn_only_client(Config) when is_list(Config) ->
%%--------------------------------------------------------------------------
erlang_server_openssl_client_npn_only_server(Config) when is_list(Config) ->
Data = "From openssl to erlang",
- start_erlang_server_and_openssl_client_with_opts(Config, [{next_protocols_advertised, [<<"spdy/2">>]}], "", Data, fun(Server, OpensslPort) ->
+ start_erlang_server_and_openssl_client_with_opts(Config, [{next_protocols_advertised, [<<"spdy/2">>]}], "",
+ Data, fun(Server, OpensslPort) ->
port_command(OpensslPort, Data),
ssl_test_lib:check_result(Server, ok)
end),
@@ -1183,13 +992,94 @@ erlang_server_openssl_client_npn_only_server(Config) when is_list(Config) ->
erlang_server_openssl_client_npn_only_client(Config) when is_list(Config) ->
Data = "From openssl to erlang",
- start_erlang_server_and_openssl_client_with_opts(Config, [], "-nextprotoneg spdy/2", Data, fun(Server, OpensslPort) ->
+ start_erlang_server_and_openssl_client_with_opts(Config, [], "-nextprotoneg spdy/2",
+ Data, fun(Server, OpensslPort) ->
port_command(OpensslPort, Data),
ssl_test_lib:check_result(Server, ok)
end),
ok.
-%%--------------------------------------------------------------------------
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
+run_suites(Ciphers, Version, Config, Type) ->
+ {ClientOpts, ServerOpts} =
+ case Type of
+ rsa ->
+ {?config(client_opts, Config),
+ ?config(server_opts, Config)};
+ dsa ->
+ {?config(client_opts, Config),
+ ?config(server_dsa_opts, Config)}
+ end,
+
+ Result = lists:map(fun(Cipher) ->
+ cipher(Cipher, Version, Config, ClientOpts, ServerOpts) end,
+ Ciphers),
+ case lists:flatten(Result) of
+ [] ->
+ ok;
+ Error ->
+ ct:print("Cipher suite errors: ~p~n", [Error]),
+ ct:fail(cipher_suite_failed_see_test_case_log)
+ end.
+
+cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
+ process_flag(trap_exit, true),
+ ct:print("Testing CipherSuite ~p~n", [CipherSuite]),
+ {ClientNode, _ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Port = ssl_test_lib:inet_port(node()),
+ CertFile = proplists:get_value(certfile, ServerOpts),
+ KeyFile = proplists:get_value(keyfile, ServerOpts),
+
+ Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
+ " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "",
+
+ ct:print("openssl cmd: ~p~n", [Cmd]),
+
+ OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
+
+ wait_for_openssl_server(),
+
+ ConnectionInfo = {ok, {Version, CipherSuite}},
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}},
+ {options,
+ [{ciphers,[CipherSuite]} |
+ ClientOpts]}]),
+
+ port_command(OpenSslPort, "Hello\n"),
+
+ receive
+ {Port, {data, _}} when is_port(Port) ->
+ ok
+ after 500 ->
+ ct:print("Time out on openssl port, check that"
+ " the messages Hello and world are received"
+ " during close of port" , []),
+ ok
+ end,
+
+ port_command(OpenSslPort, " world\n"),
+
+ Result = ssl_test_lib:wait_for_result(Client, ok),
+
+ %% Clean close down! Server needs to be closed first !!
+ close_port(OpenSslPort),
+ ssl_test_lib:close(Client),
+
+ Return = case Result of
+ ok ->
+ [];
+ Error ->
+ [{CipherSuite, Error}]
+ end,
+ process_flag(trap_exit, false),
+ Return.
start_erlang_client_and_openssl_server_with_opts(Config, ErlangClientOpts, OpensslServerOpts, Data, Callback) ->
process_flag(trap_exit, true),
@@ -1210,7 +1100,7 @@ start_erlang_client_and_openssl_server_with_opts(Config, ErlangClientOpts, Opens
integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile,
- test_server:format("openssl cmd: ~p~n", [Cmd]),
+ ct:print("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -1249,7 +1139,7 @@ start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, Callbac
Cmd = "openssl s_server -msg -nextprotoneg http/1.1,spdy/2 -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile,
- test_server:format("openssl cmd: ~p~n", [Cmd]),
+ ct:print("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -1287,7 +1177,7 @@ start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, Callbac
Cmd = "openssl s_client -nextprotoneg http/1.0,spdy/2 -msg -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost",
- test_server:format("openssl cmd: ~p~n", [Cmd]),
+ ct:print("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -1298,6 +1188,7 @@ start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, Callbac
close_port(OpenSslPort),
process_flag(trap_exit, false).
+
start_erlang_server_and_openssl_client_with_opts(Config, ErlangServerOpts, OpenSSLClientOpts, Data, Callback) ->
process_flag(trap_exit, true),
ServerOpts0 = ?config(server_opts, Config),
@@ -1315,7 +1206,7 @@ start_erlang_server_and_openssl_client_with_opts(Config, ErlangServerOpts, OpenS
Cmd = "openssl s_client " ++ OpenSSLClientOpts ++ " -msg -port " ++ integer_to_list(Port) ++
" -host localhost",
- test_server:format("openssl cmd: ~p~n", [Cmd]),
+ ct:print("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -1334,7 +1225,7 @@ erlang_ssl_receive_and_assert_npn(Socket, Protocol, Data) ->
ok.
erlang_ssl_receive(Socket, Data) ->
- test_server:format("Connection info: ~p~n",
+ ct:print("Connection info: ~p~n",
[ssl:connection_info(Socket)]),
receive
{ssl, Socket, Data} ->
@@ -1348,15 +1239,15 @@ erlang_ssl_receive(Socket, Data) ->
io:format("openssl ~s~n",[Debug]),
erlang_ssl_receive(Socket,Data);
Other ->
- test_server:fail({unexpected_message, Other})
+ ct:fail({unexpected_message, Other})
after 4000 ->
- test_server:fail({did_not_get, Data})
+ ct:fail({did_not_get, Data})
end.
connection_info(Socket, Version) ->
case ssl:connection_info(Socket) of
{ok, {Version, _} = Info} ->
- test_server:format("Connection info: ~p~n", [Info]),
+ ct:print("Connection info: ~p~n", [Info]),
ok;
{ok, {OtherVersion, _}} ->
{wrong_version, OtherVersion}
@@ -1367,7 +1258,7 @@ connection_info_result(Socket) ->
delayed_send(Socket, [ErlData, OpenSslData]) ->
- test_server:sleep(?SLEEP),
+ ct:sleep(?SLEEP),
ssl:send(Socket, ErlData),
erlang_ssl_receive(Socket, OpenSslData).
@@ -1419,7 +1310,7 @@ wait_for_openssl_server() ->
%% it will be in accept. Parsing
%% output is too error prone. (Even
%% more so than sleep!)
- test_server:sleep(?SLEEP)
+ ct:sleep(?SLEEP)
end.
version_flag(tlsv1) ->
@@ -1451,11 +1342,27 @@ check_sane_openssl_renegotaite(Config) ->
end.
check_sane_openssl_sslv2(Config) ->
- case os:cmd("openssl version") of
- "OpenSSL 1." ++ _ ->
- {skip, "sslv2 by default turned of in 1.*"};
- _ ->
- Config
+ Port = open_port({spawn, "openssl s_client -ssl2 "}, [stderr_to_stdout]),
+ case supports_sslv2(Port) of
+ true ->
+ Config;
+ false ->
+ {skip, "sslv2 not supported by openssl"}
+ end.
+
+supports_sslv2(Port) ->
+ receive
+ {Port, {data, "unknown option -ssl2" ++ _}} ->
+ false;
+ {Port, {data, Data}} ->
+ case lists:member("error", string:tokens(Data, ":")) of
+ true ->
+ false;
+ false ->
+ supports_sslv2(Port)
+ end
+ after 500 ->
+ true
end.
check_sane_openssl_version(Version) ->
diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk
index e381b73c27..adfb29e639 100644
--- a/lib/ssl/vsn.mk
+++ b/lib/ssl/vsn.mk
@@ -1 +1 @@
-SSL_VSN = 5.1
+SSL_VSN = 5.1.2
diff --git a/lib/stdlib/doc/src/Makefile b/lib/stdlib/doc/src/Makefile
index 50f6427eaa..6f1e61e70c 100644
--- a/lib/stdlib/doc/src/Makefile
+++ b/lib/stdlib/doc/src/Makefile
@@ -101,7 +101,6 @@ XML_REF6_FILES = stdlib_app.xml
XML_PART_FILES = part.xml part_notes.xml part_notes_history.xml
XML_CHAPTER_FILES = io_protocol.xml unicode_usage.xml notes.xml notes_history.xml
-GIF_FILES = ushell1.gif ushell2.gif ushell3.gif
BOOK_FILES = book.xml
@@ -112,8 +111,7 @@ XML_FILES = \
# ----------------------------------------------------
HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \
- $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html) \
- $(GIF_FILES:%.gif=$(HTMLDIR)/%.gif)
+ $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html)
INFO_FILE = ../../info
@@ -138,21 +136,16 @@ SPECS_FLAGS = -I../../include -I../../../kernel/include
# ----------------------------------------------------
# Targets
# ----------------------------------------------------
-$(HTMLDIR)/%.gif: %.gif
- $(INSTALL_DATA) $< $@
-
docs: man pdf html
$(TOP_PDF_FILE): $(XML_FILES)
pdf: $(TOP_PDF_FILE)
-html: gifs $(HTML_REF_MAN_FILE)
+html: $(HTML_REF_MAN_FILE)
man: $(MAN3_FILES) $(MAN6_FILES)
-gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
-
debug opt:
clean clean_docs:
diff --git a/lib/stdlib/doc/src/epp.xml b/lib/stdlib/doc/src/epp.xml
index 386ed89fe1..3e8aba2e5f 100644
--- a/lib/stdlib/doc/src/epp.xml
+++ b/lib/stdlib/doc/src/epp.xml
@@ -37,6 +37,18 @@
<p>The Erlang code preprocessor includes functions which are used
by <c>compile</c> to preprocess macros and include files before
the actual parsing takes place.</p>
+ <p>The Erlang source file <marker
+ id="encoding"><em>encoding</em></marker> is selected by a
+ comment in one of the first two lines of the source file. The
+ first string that matches the regular expression
+ <c>coding\s*[:=]\s*([-a-zA-Z0-9])+</c> selects the encoding. If
+ the matching string is not a valid encoding it is ignored. The
+ valid encodings are <c>Latin-1</c> and <c>UTF-8</c> where the
+ case of the characters can be chosen freely. Examples:</p>
+ <pre>
+%% coding: utf-8
+%% For this file we have chosen encoding = Latin-1
+%% -*- coding: latin-1 -*-</pre>
</description>
<datatypes>
<datatype>
@@ -46,6 +58,9 @@
<name name="epp_handle"></name>
<desc><p>Handle to the epp server.</p></desc>
</datatype>
+ <datatype>
+ <name name="source_encoding"></name>
+ </datatype>
</datatypes>
<funcs>
<func>
@@ -83,6 +98,50 @@
</desc>
</func>
<func>
+ <name name="default_encoding" arity="0"/>
+ <fsummary>Return the default encoding of Erlang source files</fsummary>
+ <desc>
+ <p>Returns the default encoding of Erlang source files.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="encoding_to_string" arity="1"/>
+ <fsummary>Return a string representation of an encoding</fsummary>
+ <desc>
+ <p>Returns a string representation of an encoding. The string
+ is recognized by <c>read_encoding/1,2</c> and
+ <c>set_encoding/1</c> as a valid encoding.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="read_encoding" arity="1"/>
+ <name name="read_encoding" arity="2"/>
+ <fsummary>Read the encoding from a file</fsummary>
+ <desc>
+ <p>Read the <seealso marker="#encoding">encoding</seealso> from
+ a file. Returns the read encoding, or <c>none</c> if no
+ valid encoding was found.</p>
+ <p>The option <c>in_comment_only</c> is <c>true</c> by
+ default, which is correct for Erlang source files. If set to
+ <c>false</c> the encoding string does not necessarily have to
+ occur in a comment.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="set_encoding" arity="1"/>
+ <fsummary>Read and set the encoding of an IO device</fsummary>
+ <desc>
+ <p>Reads the <seealso marker="#encoding">encoding</seealso> from
+ an IO device and sets the encoding of the device
+ accordingly. The position of the IO device referenced by
+ <c><anno>File</anno></c> is not affected. If no valid
+ encoding can be read from the IO device the encoding of the
+ IO device is set to the default encoding.</p>
+ <p>Returns the read encoding, or <c>none</c> if no valid
+ encoding was found.</p>
+ </desc>
+ </func>
+ <func>
<name name="format_error" arity="1"/>
<fsummary>Format an error descriptor</fsummary>
<desc>
diff --git a/lib/stdlib/doc/src/erl_pp.xml b/lib/stdlib/doc/src/erl_pp.xml
index 57b5828bcd..9ae4f3d91f 100644
--- a/lib/stdlib/doc/src/erl_pp.xml
+++ b/lib/stdlib/doc/src/erl_pp.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>1996</year>
- <year>2011</year>
+ <year>2012</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -63,6 +63,12 @@
breaks and only a space is used as a separator.</p>
</desc>
</datatype>
+ <datatype>
+ <name name="option"/>
+ </datatype>
+ <datatype>
+ <name name="options"/>
+ </datatype>
</datatypes>
<funcs>
<func>
diff --git a/lib/stdlib/doc/src/io.xml b/lib/stdlib/doc/src/io.xml
index e6d262466c..22cd45a482 100644
--- a/lib/stdlib/doc/src/io.xml
+++ b/lib/stdlib/doc/src/io.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2011</year>
+ <year>1996</year><year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -28,9 +28,9 @@
<rev></rev>
</header>
<module>io</module>
- <modulesummary>Standard IO Server Interface Functions</modulesummary>
+ <modulesummary>Standard I/O Server Interface Functions</modulesummary>
<description>
- <p>This module provides an interface to standard Erlang IO servers.
+ <p>This module provides an interface to standard Erlang I/O servers.
The output functions all return <c>ok</c> if they are successful,
or exit if they are not.</p>
<p>In the following description, all functions have an optional
@@ -38,17 +38,16 @@
process which handles the IO protocols. Normally, it is the
<c>IoDevice</c> returned by
<seealso marker="kernel:file#open/2">file:open/2</seealso>.</p>
- <p>For a description of the IO protocols refer to the STDLIB Users Guide.</p>
+ <p>For a description of the IO protocols refer to the <seealso marker="io_protocol">STDLIB User's Guide</seealso>.</p>
<warning>
<p>As of R13A, data supplied to the <seealso
marker="#put_chars/2">put_chars</seealso> function should be in the
<seealso marker="unicode#type-chardata"><c>unicode:chardata()</c></seealso> format. This means that programs
supplying binaries to this function need to convert them to UTF-8
- before trying to output the data on an
- <c>io_device()</c>.</p>
+ before trying to output the data on an IO device.</p>
- <p>If an io_device() is set in binary mode, the functions <seealso
+ <p>If an IO device is set in binary mode, the functions <seealso
marker="#get_chars/3">get_chars</seealso> and <seealso
marker="#get_line/2">get_line</seealso> may return binaries
instead of lists. The binaries will, as of R13A, be encoded in
@@ -68,9 +67,9 @@
<datatype>
<name name="device"/>
<desc>
- <p>Either <c>standard_io</c>, <c>standard_error</c>, a
+ <p>An IO device. Either <c>standard_io</c>, <c>standard_error</c>, a
registered name, or a pid handling IO protocols (returned from
- <seealso marker="kernel:file#open/2">file:open/2</seealso>).</p>
+ <seealso marker="kernel:file#open/2">file:open/2</seealso>).</p>
</desc>
</datatype>
<datatype>
@@ -89,17 +88,14 @@
<name name="format"/>
</datatype>
<datatype>
- <name name="line"/>
+ <name name="location"/>
</datatype>
<datatype>
<name name="prompt"/>
</datatype>
<datatype>
- <name name="request_error"/>
- </datatype>
- <datatype>
- <name name="error_description"/>
- <desc><p>Whatever the I/O-server sends.</p></desc>
+ <name name="server_no_data"/>
+ <desc><p>What the I/O-server sends when there is no data.</p></desc>
</datatype>
</datatypes>
@@ -107,11 +103,11 @@
<func>
<name name="columns" arity="0"/>
<name name="columns" arity="1"/>
- <fsummary>Get the number of columns of a device</fsummary>
+ <fsummary>Get the number of columns of an IO device</fsummary>
<desc>
<p>Retrieves the number of columns of the
<c><anno>IoDevice</anno></c> (i.e. the width of a terminal). The function
- only succeeds for terminal devices, for all other devices
+ only succeeds for terminal devices, for all other IO devices
the function returns <c>{error, enotsup}</c></p>
</desc>
</func>
@@ -120,7 +116,7 @@
<name name="put_chars" arity="2"/>
<fsummary>Write a list of characters</fsummary>
<desc>
- <p>Writes the characters of <c><anno>CharData</anno></c> to the io_server()
+ <p>Writes the characters of <c><anno>CharData</anno></c> to the I/O server
(<c><anno>IoDevice</anno></c>).</p>
</desc>
</func>
@@ -135,6 +131,7 @@
<func>
<name name="get_chars" arity="2"/>
<name name="get_chars" arity="3"/>
+ <type name="server_no_data"/>
<fsummary>Read a specified number of characters</fsummary>
<desc>
<p>Reads <c><anno>Count</anno></c> characters from standard input
@@ -143,19 +140,19 @@
<taglist>
<tag><c><anno>Data</anno></c></tag>
<item>
- <p>The input characters. If the device supports Unicode,
+ <p>The input characters. If the IO device supports Unicode,
the data may represent codepoints larger than 255 (the
- latin1 range). If the io_server() is set to deliver
+ latin1 range). If the I/O server is set to deliver
binaries, they will be encoded in UTF-8 (regardless of if
- the device actually supports Unicode or not).</p>
+ the IO device actually supports Unicode or not).</p>
</item>
<tag><c>eof</c></tag>
<item>
<p>End of file was encountered.</p>
</item>
- <tag><c>{error,<anno>Reason</anno>}</c></tag>
+ <tag><c>{error, <anno>ErrorDescription</anno>}</c></tag>
<item>
- <p>Other (rare) error condition, for instance <c>{error,estale}</c>
+ <p>Other (rare) error condition, for instance <c>{error, estale}</c>
if reading from an NFS file system.</p>
</item>
</taglist>
@@ -164,6 +161,7 @@
<func>
<name name="get_line" arity="1"/>
<name name="get_line" arity="2"/>
+ <type name="server_no_data"/>
<fsummary>Read a line</fsummary>
<desc>
<p>Reads a line from the standard input (<c><anno>IoDevice</anno></c>),
@@ -172,19 +170,19 @@
<tag><c><anno>Data</anno></c></tag>
<item>
<p>The characters in the line terminated by a LF (or end of
- file). If the device supports Unicode,
+ file). If the IO device supports Unicode,
the data may represent codepoints larger than 255 (the
- latin1 range). If the io_server() is set to deliver
+ latin1 range). If the I/O server is set to deliver
binaries, they will be encoded in UTF-8 (regardless of if
- the device actually supports Unicode or not).</p>
+ the IO device actually supports Unicode or not).</p>
</item>
<tag><c>eof</c></tag>
<item>
<p>End of file was encountered.</p>
</item>
- <tag><c>{error,<anno>Reason</anno>}</c></tag>
+ <tag><c>{error, <anno>ErrorDescription</anno>}</c></tag>
<item>
- <p>Other (rare) error condition, for instance <c>{error,estale}</c>
+ <p>Other (rare) error condition, for instance <c>{error, estale}</c>
if reading from an NFS file system.</p>
</item>
</taglist>
@@ -195,7 +193,7 @@
<name name="getopts" arity="1"/>
<fsummary>Get the supported options and values from an I/O-server</fsummary>
<desc>
- <p>This function requests all available options and their current values for a specific io_device(). Example:</p>
+ <p>This function requests all available options and their current values for a specific IO device. Example:</p>
<pre>
1> <input>{ok,F} = file:open("/dev/null",[read]).</input>
{ok,&lt;0.42.0&gt;}
@@ -217,30 +215,30 @@
<name name="setopts" arity="2"/>
<fsummary>Set options</fsummary>
<desc>
- <p>Set options for the io_device() (<c><anno>IoDevice</anno></c>).</p>
+ <p>Set options for the standard IO device (<c><anno>IoDevice</anno></c>).</p>
<p>Possible options and values vary depending on the actual
- io_device(). For a list of supported options and their current values
- on a specific device, use the <seealso
+ IO device. For a list of supported options and their current values
+ on a specific IO device, use the <seealso
marker="#getopts/1">getopts/1</seealso> function.</p>
- <p>The options and values supported by the current OTP io_devices are:</p>
+ <p>The options and values supported by the current OTP IO devices are:</p>
<taglist>
<tag><c>binary, list or {binary, boolean()}</c></tag>
<item>
- <p>If set in binary mode (binary or {binary,true}), the io_server() sends binary data (encoded in UTF-8) as answers to the get_line, get_chars and, if possible, get_until requests (see the I/O protocol description in STDLIB User's Guide for details). The immediate effect is that <c>get_chars/2,3</c> and <c>get_line/1,2</c> return UTF-8 binaries instead of lists of chars for the affected device.</p>
- <p>By default, all io_devices in OTP are set in list mode, but the io functions can handle any of these modes and so should other, user written, modules behaving as clients to I/O-servers.</p>
- <p>This option is supported by the standard shell (group.erl), the 'oldshell' (user.erl) and the file I/O servers.</p>
+ <p>If set in binary mode (<c>binary</c> or <c>{binary, true}</c>), the I/O server sends binary data (encoded in UTF-8) as answers to the <c>get_line</c>, <c>get_chars</c> and, if possible, <c>get_until</c> requests (see the I/O protocol description in <seealso marker="io_protocol">STDLIB User's Guide</seealso> for details). The immediate effect is that <c>get_chars/2,3</c> and <c>get_line/1,2</c> return UTF-8 binaries instead of lists of chars for the affected IO device.</p>
+ <p>By default, all IO devices in OTP are set in list mode, but the I/O functions can handle any of these modes and so should other, user written, modules behaving as clients to I/O-servers.</p>
+ <p>This option is supported by the standard shell (<c>group.erl</c>), the 'oldshell' (<c>user.erl</c>) and the file I/O servers.</p>
</item>
<tag><c>{echo, boolean()}</c></tag>
<item>
- <p>Denotes if the terminal should echo input. Only supported for the standard shell I/O-server (group.erl)</p>
+ <p>Denotes if the terminal should echo input. Only supported for the standard shell I/O-server (<c>group.erl</c>)</p>
</item>
<tag><c>{expand_fun, expand_fun()}</c></tag>
<item>
<p>Provide a function for tab-completion (expansion)
- like the erlang shell. This function is called
- when the user presses the Tab key. The expansion is
+ like the Erlang shell. This function is called
+ when the user presses the TAB key. The expansion is
active when calling line-reading functions such as
<c>get_line/1,2</c>.</p>
<p>The function is called with the current line, upto
@@ -253,25 +251,25 @@
will be printed and the current input line will be written
once again.</p>
<p>Trivial example (beep on anything except empty line, which
- is expanded to "quit"):</p>
+ is expanded to <c>"quit"</c>):</p>
<code type="none">
fun("") -> {yes, "quit", []};
(_) -> {no, "", ["quit"]} end</code>
- <p>This option is supported by the standard shell only (group.erl).</p>
+ <p>This option is supported by the standard shell only (<c>group.erl</c>).</p>
</item>
<tag><c>{encoding, latin1 | unicode}</c></tag>
<item>
- <p>Specifies how characters are input or output from or to the actual device, implying that i.e. a terminal is set to handle Unicode input and output or a file is set to handle UTF-8 data encoding.</p>
- <p>The option <em>does not</em> affect how data is returned from the io-functions or how it is sent in the I/O-protocol, it only affects how the io_device() is to handle Unicode characters towards the &quot;physical&quot; device.</p>
- <p>The standard shell will be set for either unicode or latin1 encoding when the system is started. The actual encoding is set with the help of the "LANG" or "LC_CTYPE" environment variables on Unix-like system or by other means on other systems. The bottom line is that the user can input Unicode characters and the device will be in {encoding, unicode} mode if the device supports it. The mode can be changed, if the assumption of the runtime system is wrong, by setting this option.</p>
- <p>The io_device() used when Erlang is started with the "-oldshell" or "-noshell" flags is by default set to latin1 encoding, meaning that any characters beyond codepoint 255 will be escaped and that input is expected to be plain 8-bit ISO-latin-1. If the encoding is changed to Unicode, input and output from the standard file descriptors will be in UTF-8 (regardless of operating system).</p>
- <p>Files can also be set in {encoding, unicode}, meaning that data is written and read as UTF-8. More encodings are possible for files, see below.</p>
- <p>{encoding, unicode | latin1} is supported by both the standard shell (group.erl including werl on windows), the 'oldshell' (user.erl) and the file I/O servers.</p>
+ <p>Specifies how characters are input or output from or to the actual IO device, implying that i.e. a terminal is set to handle Unicode input and output or a file is set to handle UTF-8 data encoding.</p>
+ <p>The option <em>does not</em> affect how data is returned from the I/O functions or how it is sent in the I/O-protocol, it only affects how the IO device is to handle Unicode characters towards the &quot;physical&quot; device.</p>
+ <p>The standard shell will be set for either Unicode or latin1 encoding when the system is started. The actual encoding is set with the help of the <c>LANG</c> or <c>LC_CTYPE</c> environment variables on Unix-like system or by other means on other systems. The bottom line is that the user can input Unicode characters and the IO device will be in <c>{encoding, unicode}</c> mode if the IO device supports it. The mode can be changed, if the assumption of the runtime system is wrong, by setting this option.</p>
+ <p>The IO device used when Erlang is started with the "-oldshell" or "-noshell" flags is by default set to latin1 encoding, meaning that any characters beyond codepoint 255 will be escaped and that input is expected to be plain 8-bit ISO-latin-1. If the encoding is changed to Unicode, input and output from the standard file descriptors will be in UTF-8 (regardless of operating system).</p>
+ <p>Files can also be set in <c>{encoding, unicode}</c>, meaning that data is written and read as UTF-8. More encodings are possible for files, see below.</p>
+ <p><c>{encoding, unicode | latin1}</c> is supported by both the standard shell (<c>group.erl</c> including <c>werl</c> on Windows&reg;), the 'oldshell' (<c>user.erl</c>) and the file I/O servers.</p>
</item>
<tag><c>{encoding, utf8 | utf16 | utf32 | {utf16,big} | {utf16,little} | {utf32,big} | {utf32,little}}</c></tag>
<item>
<p>For disk files, the encoding can be set to various UTF variants. This will have the effect that data is expected to be read as the specified encoding from the file and the data will be written in the specified encoding to the disk file.</p>
- <p>{encoding, utf8} will have the same effect as {encoding,unicode} on files.</p>
+ <p><c>{encoding, utf8}</c> will have the same effect as <c>{encoding, unicode}</c> on files.</p>
<p>The extended encodings are only supported on disk files (opened by the <seealso marker="kernel:file#open/2">file:open/2</seealso> function)</p>
</item>
</taglist>
@@ -289,6 +287,7 @@
<func>
<name name="read" arity="1"/>
<name name="read" arity="2"/>
+ <type name="server_no_data"/>
<fsummary>Read a term</fsummary>
<desc>
<p>Reads a term <c><anno>Term</anno></c> from the standard input
@@ -312,21 +311,25 @@
</func>
<func>
<name name="read" arity="3"/>
+ <name name="read" arity="4"/>
+ <type name="server_no_data"/>
<fsummary>Read a term</fsummary>
<desc>
<p>Reads a term <c><anno>Term</anno></c> from <c><anno>IoDevice</anno></c>, prompting it
- with <c><anno>Prompt</anno></c>. Reading starts at line number
- <c><anno>StartLine</anno></c>. It returns:</p>
+ with <c><anno>Prompt</anno></c>. Reading starts at location
+ <c><anno>StartLocation</anno></c>. The argument
+ <c><anno>Options</anno></c> is passed on as the <c>Options</c>
+ argument of the <c>erl_scan:tokens/4</c> function. It returns:</p>
<taglist>
- <tag><c>{ok, Term, <anno>EndLine</anno>}</c></tag>
+ <tag><c>{ok, Term, <anno>EndLocation</anno>}</c></tag>
<item>
<p>The parsing was successful.</p>
</item>
- <tag><c>{eof, <anno>EndLine</anno>}</c></tag>
+ <tag><c>{eof, <anno>EndLocation</anno>}</c></tag>
<item>
<p>End of file was encountered.</p>
</item>
- <tag><c>{error, <anno>ErrorInfo</anno>, <anno>ErrorLine</anno>}</c></tag>
+ <tag><c>{error, <anno>ErrorInfo</anno>, <anno>ErrorLocation</anno>}</c></tag>
<item>
<p>The parsing failed.</p>
</item>
@@ -377,7 +380,7 @@ ok</pre>
applicable, it is used for both the field width and precision.
The default padding character is <c>' '</c> (space).</p>
<p><c>Mod</c> is the control sequence modifier. It is either a
- single character (currently only 't', for unicode translation,
+ single character (currently only <c>t</c>, for Unicode translation,
is supported) that changes the interpretation of Data.</p>
<p>The following control sequences are available:</p>
@@ -397,9 +400,9 @@ ok</pre>
2> <input>io:fwrite("|~10.5c|~-10.5c|~5c|~n", [$a, $b, $c]).</input>
| aaaaa|bbbbb |ccccc|
ok</pre>
- <p>If the Unicode translation modifier ('t') is in effect,
+ <p>If the Unicode translation modifier (<c>t</c>) is in effect,
the integer argument can be any number representing a
- valid unicode codepoint, otherwise it should be an integer
+ valid Unicode codepoint, otherwise it should be an integer
less than or equal to 255, otherwise it is masked with 16#FF:</p>
<pre>
1> <input>io:fwrite("~tc~n",[1024]).</input>
@@ -439,7 +442,7 @@ ok</pre>
<item>
<p>Prints the argument with the <c>string</c> syntax. The
argument is, if no Unicode translation modifier is present, an
- iolist(), a binary, or an atom. If the Unicode translation modifier ('t') is in effect, the argument is unicode:chardata(), meaning that binaries are in UTF-8. The characters
+ iolist(), a binary, or an atom. If the Unicode translation modifier (<c>t</c>) is in effect, the argument is unicode:chardata(), meaning that binaries are in UTF-8. The characters
are printed without quotes. The string is first truncated
by the given precision and then padded and justified
to the given field width. The default precision is the field width.</p>
@@ -476,8 +479,10 @@ ok
<p>Writes the data with standard syntax in the same way as
<c>~w</c>, but breaks terms whose printed representation
is longer than one line into many lines and indents each
- line sensibly. It also tries to detect lists of printable
- characters and to output these as strings. For example:</p>
+ line sensibly. It also tries to detect lists of
+ printable characters and to output these as strings. The
+ Unicode translation modifier is used for determining
+ what characters are printable. For example:</p>
<pre>
5> <input>T = [{attributes,[[{id,age,1.50000},{mode,explicit},</input>
<input>{typename,"INTEGER"}], [{id,cho},{mode,explicit},{typename,'Cho'}]]},</input>
@@ -516,6 +521,19 @@ Here T = [{attributes,[[{id,age,1.5},
{tag,{'PRIVATE',3}},
{mode,implicit}]
ok</pre>
+ <p>Binaries that look like UTF-8 encoded strings will be
+ output with the string syntax if the Unicode translation
+ modifier is given:</p>
+ <pre>
+9> <input>io:fwrite("~p~n",[[1024]]).</input>
+[1024]
+10> <input>io:fwrite("~tp~n",[[1024]]).</input>
+"\x{400}"
+11> <input>io:fwrite("~tp~n", [&lt;&lt;128,128&gt;&gt;]).</input>
+&lt;&lt;128,128&gt;&gt;
+12> <input>io:fwrite("~tp~n", [&lt;&lt;208,128&gt;&gt;]).</input>
+&lt;&lt;"\x{400}"/utf8&gt;&gt;
+ok</pre>
</item>
<tag><c>W</c></tag>
<item>
@@ -583,7 +601,7 @@ ok</pre>
<tag><c>#</c></tag>
<item>
<p>Like <c>B</c>, but prints the number with an Erlang style
- '#'-separated base prefix.</p>
+ <c>#</c>-separated base prefix.</p>
<pre>
16> <input>io:fwrite("~.10#~n", [31]).</input>
10#31
@@ -633,13 +651,14 @@ ok
{shell,eval_loop,3}]}
in function io:o_request/2</pre>
<p>In this example, an attempt was made to output the single
- character '65' with the aid of the string formatting directive
+ character 65 with the aid of the string formatting directive
"~s".</p>
</desc>
</func>
<func>
<name name="fread" arity="2"/>
<name name="fread" arity="3"/>
+ <type name="server_no_data"/>
<fsummary>Read formatted input</fsummary>
<desc>
<p>Reads characters from the standard input (<c><anno>IoDevice</anno></c>),
@@ -664,7 +683,7 @@ ok
return suppression character. It provides a method to
specify a field which is to be omitted. <c>F</c> is the
<c>field width</c> of the input field, <c>M</c> is an optional
- translation modifier (of which 't' is the only currently
+ translation modifier (of which <c>t</c> is the only currently
supported, meaning Unicode translation) and <c>C</c>
determines the type of control sequence.</p>
@@ -690,8 +709,8 @@ ok
<tag><c>-</c></tag>
<item>
<p>An optional sign character is expected. A sign
- character '-' gives the return value <c>-1</c>. Sign
- character '+' or none gives <c>1</c>. The field width
+ character <c>-</c> gives the return value <c>-1</c>. Sign
+ character <c>+</c> or none gives <c>1</c>. The field width
parameter is ignored. Leading white-space characters
are not skipped.</p>
</item>
@@ -713,7 +732,7 @@ ok
characters are stripped. An Erlang string (list of
characters) is returned.</p>
- <p>If Unicode translation is in effect (~ts),
+ <p>If Unicode translation is in effect (<c>~ts</c>),
characters larger than 255 are accepted, otherwise
not. With the translation modifier, the list
returned may as a consequence also contain
@@ -769,10 +788,15 @@ Prompt> <input>&lt;Character beyond latin1 range not printable in this medium&gt
<item>
<p>End of file was encountered.</p>
</item>
- <tag><c>{error, <anno>What</anno>}</c></tag>
+ <tag><c>{error, <anno>FreadError</anno>}</c></tag>
+ <item>
+ <p>The reading failed and <c>FreadError</c> gives a
+ hint about the error.</p>
+ </item>
+ <tag><c>{error, <anno>ErrorDescription</anno>}</c></tag>
<item>
<p>The read operation failed and the parameter
- <c><anno>What</anno></c> gives a hint about the error.</p>
+ <c><anno>ErrorDescription</anno></c> gives a hint about the error.</p>
</item>
</taglist>
</item>
@@ -793,11 +817,11 @@ enter><input>:</input> <input>alan</input> <input>:</input> <input>joe</in
<func>
<name name="rows" arity="0"/>
<name name="rows" arity="1"/>
- <fsummary>Get the number of rows of a device</fsummary>
+ <fsummary>Get the number of rows of an IO device</fsummary>
<desc>
<p>Retrieves the number of rows of the
<c><anno>IoDevice</anno></c> (i.e. the height of a terminal). The function
- only succeeds for terminal devices, for all other devices
+ only succeeds for terminal devices, for all other IO devices
the function returns <c>{error, enotsup}</c></p>
</desc>
</func>
@@ -805,23 +829,28 @@ enter><input>:</input> <input>alan</input> <input>:</input> <input>joe</in
<name name="scan_erl_exprs" arity="1"/>
<name name="scan_erl_exprs" arity="2"/>
<name name="scan_erl_exprs" arity="3"/>
+ <name name="scan_erl_exprs" arity="4"/>
+ <type name="server_no_data"/>
<fsummary>Read and tokenize Erlang expressions</fsummary>
<desc>
<p>Reads data from the standard input (<c>IoDevice</c>),
- prompting it with <c>Prompt</c>. Reading starts at line number
- <c>StartLine</c> (1). The data is tokenized as if it were a
- sequence of Erlang expressions until a final <c>'.'</c> is
+ prompting it with <c>Prompt</c>. Reading starts at location
+ <c>StartLocation</c> (<c>1</c>). The argument <c><anno>Options</anno></c>
+ is passed on as the <c>Options</c> argument of the
+ <c>erl_scan:tokens/4</c> function. The data is tokenized as if
+ it were a
+ sequence of Erlang expressions until a final dot (<c>.</c>) is
reached. This token is also returned. It returns:</p>
<taglist>
- <tag><c>{ok, Tokens, EndLine}</c></tag>
+ <tag><c>{ok, Tokens, EndLocation}</c></tag>
<item>
<p>The tokenization succeeded.</p>
</item>
- <tag><c>{eof, EndLine}</c></tag>
+ <tag><c>{eof, EndLocation}</c></tag>
<item>
<p>End of file was encountered.</p>
</item>
- <tag><c>{error, ErrorInfo, ErrorLine}</c></tag>
+ <tag><c>{error, ErrorInfo, ErrorLocation}</c></tag>
<item>
<p>An error occurred.</p>
</item>
@@ -840,13 +869,18 @@ enter><input>1.0er.</input>
<name name="scan_erl_form" arity="1"/>
<name name="scan_erl_form" arity="2"/>
<name name="scan_erl_form" arity="3"/>
+ <name name="scan_erl_form" arity="4"/>
+ <type name="server_no_data"/>
<fsummary>Read and tokenize an Erlang form</fsummary>
<desc>
<p>Reads data from the standard input (<c><anno>IoDevice</anno></c>),
- prompting it with <c><anno>Prompt</anno></c>. Starts reading at line number
- <c><anno>StartLine</anno></c> (1). The data is tokenized as if it were an
+ prompting it with <c><anno>Prompt</anno></c>. Starts reading
+ at location <c><anno>StartLocation</anno></c> (<c>1</c>). The
+ argument <c><anno>Options</anno></c> is passed on as the
+ <c>Options</c> argument of the <c>erl_scan:tokens/4</c>
+ function. The data is tokenized as if it were an
Erlang form - one of the valid Erlang expressions in an
- Erlang source file - until a final <c>'.'</c> is reached.
+ Erlang source file - until a final dot (<c>.</c>) is reached.
This last token is also returned. The return values are the
same as for <c>scan_erl_exprs/1,2,3</c> above.</p>
</desc>
@@ -855,24 +889,30 @@ enter><input>1.0er.</input>
<name name="parse_erl_exprs" arity="1"/>
<name name="parse_erl_exprs" arity="2"/>
<name name="parse_erl_exprs" arity="3"/>
+ <name name="parse_erl_exprs" arity="4"/>
<type name="parse_ret"/>
+ <type name="server_no_data"/>
<fsummary>Read, tokenize and parse Erlang expressions</fsummary>
<desc>
- <p>Reads data from the standard input (<c><anno>IoDevice</anno></c>),
- prompting it with <c><anno>Prompt</anno></c>. Starts reading at line number
- <c><anno>StartLine</anno></c> (1). The data is tokenized and parsed as if
- it were a sequence of Erlang expressions until a final '.' is
- reached. It returns:</p>
+ <p>Reads data from the standard input
+ (<c><anno>IoDevice</anno></c>), prompting it with
+ <c><anno>Prompt</anno></c>. Starts reading at location
+ <c><anno>StartLocation</anno></c> (<c>1</c>). The argument
+ <c><anno>Options</anno></c> is passed on as the
+ <c>Options</c> argument of the <c>erl_scan:tokens/4</c>
+ function. The data is tokenized and parsed as if it were a
+ sequence of Erlang expressions until a final dot (<c>.</c>) is reached.
+ It returns:</p>
<taglist>
- <tag><c>{ok, ExprList, EndLine}</c></tag>
+ <tag><c>{ok, ExprList, EndLocation}</c></tag>
<item>
<p>The parsing was successful.</p>
</item>
- <tag><c>{eof, EndLine}</c></tag>
+ <tag><c>{eof, EndLocation}</c></tag>
<item>
<p>End of file was encountered.</p>
</item>
- <tag><c>{error, ErrorInfo, ErrorLine}</c></tag>
+ <tag><c>{error, ErrorInfo, ErrorLocation}</c></tag>
<item>
<p>An error occurred.</p>
</item>
@@ -891,25 +931,30 @@ enter><input>abc("hey".</input>
<name name="parse_erl_form" arity="1"/>
<name name="parse_erl_form" arity="2"/>
<name name="parse_erl_form" arity="3"/>
+ <name name="parse_erl_form" arity="4"/>
<type name="parse_form_ret"/>
+ <type name="server_no_data"/>
<fsummary>Read, tokenize and parse an Erlang form</fsummary>
<desc>
<p>Reads data from the standard input (<c><anno>IoDevice</anno></c>),
- prompting it with <c><anno>Prompt</anno></c>. Starts reading at line number
- <c><anno>StartLine</anno></c> (1). The data is tokenized and parsed as if
+ prompting it with <c><anno>Prompt</anno></c>. Starts reading at
+ location <c><anno>StartLocation</anno></c> (<c>1</c>). The argument
+ <c><anno>Options</anno></c> is passed on as the
+ <c>Options</c> argument of the <c>erl_scan:tokens/4</c>
+ function. The data is tokenized and parsed as if
it were an Erlang form - one of the valid Erlang expressions
- in an Erlang source file - until a final '.' is reached. It
+ in an Erlang source file - until a final dot (<c>.</c>) is reached. It
returns:</p>
<taglist>
- <tag><c>{ok, AbsForm, EndLine}</c></tag>
+ <tag><c>{ok, AbsForm, EndLocation}</c></tag>
<item>
<p>The parsing was successful.</p>
</item>
- <tag><c>{eof, EndLine}</c></tag>
+ <tag><c>{eof, EndLocation}</c></tag>
<item>
<p>End of file was encountered.</p>
</item>
- <tag><c>{error, ErrorInfo, ErrorLine}</c></tag>
+ <tag><c>{error, ErrorInfo, ErrorLocation}</c></tag>
<item>
<p>An error occurred.</p>
</item>
@@ -940,7 +985,7 @@ enter><input>bar.</input>
</section>
<section>
<title>Standard Error</title>
- <p>In certain situations, especially when the standard output is redirected, access to an io_server() specific for error messages might be convenient. The io_device 'standard_error' can be used to direct output to whatever the current operating system considers a suitable device for error output. Example on a Unix-like operating system:</p>
+ <p>In certain situations, especially when the standard output is redirected, access to an I/O-server specific for error messages might be convenient. The IO device <c>standard_error</c> can be used to direct output to whatever the current operating system considers a suitable IO device for error output. Example on a Unix-like operating system:</p>
<pre>
$ <input>erl -noshell -noinput -eval 'io:format(standard_error,"Error: ~s~n",["error 11"]),'\</input>
<input>'init:stop().' > /dev/null</input>
@@ -956,7 +1001,7 @@ Error: error 11</pre>
<c>ErrorInfo</c> structure which is returned from all IO modules.
It has the format:</p>
<code type="none">
-{ErrorLine, Module, ErrorDescriptor}</code>
+{ErrorLocation, Module, ErrorDescriptor}</code>
<p>A string which describes the error is obtained with the following
call:</p>
<code type="none">
diff --git a/lib/stdlib/doc/src/io_lib.xml b/lib/stdlib/doc/src/io_lib.xml
index 506c1792f1..617a6b74fc 100644
--- a/lib/stdlib/doc/src/io_lib.xml
+++ b/lib/stdlib/doc/src/io_lib.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2011</year>
+ <year>1996</year><year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -43,6 +43,12 @@
<name name="chars"/>
</datatype>
<datatype>
+ <name name="unicode_chars"/>
+ </datatype>
+ <datatype>
+ <name name="unicode_string"/>
+ </datatype>
+ <datatype>
<name name="continuation"/>
<desc><p>A continuation as returned by <seealso marker="#fread/3"><c>fread/3</c></seealso>.</p>
</desc>
@@ -50,6 +56,9 @@
<datatype>
<name name="depth"/>
</datatype>
+ <datatype>
+ <name name="fread_error"/>
+ </datatype>
</datatypes>
<funcs>
<func>
@@ -209,6 +218,23 @@
</desc>
</func>
<func>
+ <name name="write_unicode_string" arity="1"/>
+ <fsummary>Write a Unicode string</fsummary>
+ <desc>
+ <p>Returns the list of characters needed to print
+ <c><anno>UnicodeString</anno></c> as a string.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="write_unicode_string_as_latin1" arity="1"/>
+ <fsummary>Write a Unicode string</fsummary>
+ <desc>
+ <p>Returns the list of characters needed to print
+ <c><anno>UnicodeString</anno></c> as a string. Non-Latin-1
+ characters are escaped.</p>
+ </desc>
+ </func>
+ <func>
<name name="write_char" arity="1"/>
<fsummary>Write a character</fsummary>
<desc>
@@ -217,6 +243,23 @@
</desc>
</func>
<func>
+ <name name="write_unicode_char" arity="1"/>
+ <fsummary>Write a Unicode character</fsummary>
+ <desc>
+ <p>Returns the list of characters needed to print a character
+ constant in the Unicode character set.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="write_unicode_char_as_latin1" arity="1"/>
+ <fsummary>Write a Unicode character</fsummary>
+ <desc>
+ <p>Returns the list of characters needed to print a character
+ constant in the Unicode character set. Non-Latin-1 characters
+ are escaped.</p>
+ </desc>
+ </func>
+ <func>
<name name="indentation" arity="2"/>
<fsummary>Indentation after printing string</fsummary>
<desc>
@@ -233,6 +276,14 @@
</desc>
</func>
<func>
+ <name name="unicode_char_list" arity="1"/>
+ <fsummary>Test for a list of Unicode characters</fsummary>
+ <desc>
+ <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a flat list of
+ characters in the Unicode range, otherwise it returns <c>false</c>.</p>
+ </desc>
+ </func>
+ <func>
<name name="deep_char_list" arity="1"/>
<fsummary>Test for a deep list of characters</fsummary>
<desc>
@@ -241,6 +292,14 @@
</desc>
</func>
<func>
+ <name name="deep_unicode_char_list" arity="1"/>
+ <fsummary>Test for a deep list of Unicode characters</fsummary>
+ <desc>
+ <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a, possibly deep, list
+ of characters in the Unicode range, otherwise it returns <c>false</c>.</p>
+ </desc>
+ </func>
+ <func>
<name name="printable_list" arity="1"/>
<fsummary>Test for a list of printable ISO-latin-1 characters</fsummary>
<desc>
@@ -248,6 +307,14 @@
printable ISO-latin-1 characters, otherwise it returns <c>false</c>.</p>
</desc>
</func>
+ <func>
+ <name name="printable_unicode_list" arity="1"/>
+ <fsummary>Test for a list of printable Unicode characters</fsummary>
+ <desc>
+ <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a flat list of
+ printable Unicode characters, otherwise it returns <c>false</c>.</p>
+ </desc>
+ </func>
</funcs>
</erlref>
diff --git a/lib/stdlib/doc/src/io_protocol.xml b/lib/stdlib/doc/src/io_protocol.xml
index 0ff3d5c1ee..d36bf2042f 100644
--- a/lib/stdlib/doc/src/io_protocol.xml
+++ b/lib/stdlib/doc/src/io_protocol.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>1999</year>
- <year>2011</year>
+ <year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -35,10 +35,10 @@
<p>The I/O-protocol in Erlang specifies a way for a client to communicate
-with an io_server and vice versa. The io_server is a process handling the
-requests and that performs the requested task on i.e. a device. The
+with an I/O server and vice versa. The I/O server is a process that handles
+the requests and performs the requested task on e.g. an IO device. The
client is any Erlang process wishing to read or write data from/to the
-device.</p>
+IO device.</p>
<p>The common I/O-protocol has been present in OTP since the
beginning, but has been fairly undocumented and has also somewhat
@@ -53,85 +53,85 @@ implement than the original. It can certainly be argumented that the
current protocol is too complex, but this text describes how it looks
today, not how it should have looked.</p>
-<p>The basic ideas from the original protocol still hold. The io_server
+<p>The basic ideas from the original protocol still hold. The I/O server
and client communicate with one single, rather simplistic protocol and
-no server state is ever present in the client. Any io_server can be
+no server state is ever present in the client. Any I/O server can be
used together with any client code and client code need not be aware
-of the actual device the io_server communicates with.</p>
+of the actual IO device the I/O server communicates with.</p>
<section>
-<title>Protocol basics</title>
+<title>Protocol Basics</title>
-<p>As described in Robert's paper, servers and clients communicate using
-io_request/io_reply tuples as follows:</p>
+<p>As described in Robert's paper, I/O servers and clients communicate using
+<c>io_request</c>/<c>io_reply</c> tuples as follows:</p>
<p><em>{io_request, From, ReplyAs, Request}</em><br/>
<em>{io_reply, ReplyAs, Reply}</em></p>
-<p>The client sends an io_request to the io_server and the server
-eventually sends a corresponding reply.</p>
+<p>The client sends an <c>io_request</c> tuple to the I/O server and
+the server eventually sends a corresponding <c>io_reply</c> tuple.</p>
<list type="bulleted">
-<item>From is the pid() of the client, the process which the io_server
-sends the reply to.</item>
-
-<item>ReplyAs can be any datum and is simply returned in the corresponding
-io_reply. The io-module in the Erlang standard library simply uses the pid()
-of the io_server as the ReplyAs datum, but a more complicated client
-could have several outstanding io-requests to the same server and
-would then use i.e. a reference() or something else to differentiate among
-the incoming io_reply's. The ReplyAs element should be considered
-opaque by the io_server. Note that the pid() of the server is not
-explicitly present in the io_reply. The reply can be sent from any
-process, not necessarily the actual io_server. The ReplyAs element is
-the only thing that connects one io_request with an io_reply.</item>
-
-<item>Request and Reply are described below.</item>
+<item><c>From</c> is the <c>pid()</c> of the client, the process which
+the I/O server sends the IO reply to.</item>
+
+<item><c>ReplyAs</c> can be any datum and is returned in the corresponding
+<c>io_reply</c>. The <seealso marker="stdlib:io">io</seealso> module simply uses the pid()
+of the I/O server as the <c>ReplyAs</c> datum, but a more complicated client
+could have several outstanding I/O requests to the same I/O server and
+would then use i.e. a <c>reference()</c> or something else to differentiate among
+the incoming IO replies. The <c>ReplyAs</c> element should be considered
+opaque by the I/O server. Note that the <c>pid()</c> of the I/O server is not
+explicitly present in the <c>io_reply</c> tuple. The reply can be sent from any
+process, not necessarily the actual I/O server. The <c>ReplyAs</c> element is
+the only thing that connects one I/O request with an I/O-reply.</item>
+
+<item><c>Request</c> and <c>Reply</c> are described below.</item>
</list>
-<p>When an io_server receives an io_request, it acts upon the actual
-Request part and eventually sends an io_reply with the corresponding
-Reply part.</p>
+<p>When an I/O server receives an <c>io_request</c> tuple, it acts upon the actual
+<c>Request</c> part and eventually sends an <c>io_reply</c> tuple with the corresponding
+<c>Reply</c> part.</p>
</section>
<section>
-<title>Output requests</title>
+<title>Output Requests</title>
-<p>To output characters on a device, the following Requests exist:</p>
+<p>To output characters on an IO device, the following <c>Request</c>s exist:</p>
<p>
<em>{put_chars, Encoding, Characters}</em><br/>
<em>{put_chars, Encoding, Module, Function, Args}</em>
</p>
<list type="bulleted">
-<item>Encoding is either 'unicode' or 'latin1', meaning that the
+<item><c>Encoding</c> is either <c>unicode</c> or <c>latin1</c>, meaning that the
characters are (in case of binaries) encoded as either UTF-8 or
- iso-latin-1 (pure bytes). A well behaved io_server should also
- return error if list elements contain integers > 255 when the
- Encoding is set to latin1. Note that this does not in any way tell
- how characters should be put on the actual device or how the
- io_server should handle them. Different io_servers may handle the
- characters however they want, this simply tells the io_server which
- format the data is expected to have. In the Module/Function/argument
- case, the Encoding tells which format the designated function
- produces. Note that byte-oriented data is simplest sent using latin1
- Encoding</item>
-
-<item>Characters are the data to be put on the device. If Encoding is
- latin1, this is an iolist(). If Encoding is unicode, this is an
- Erlang standard mixed unicode list (one integer in a list per
+ ISO-latin-1 (pure bytes). A well behaved I/O server should also
+ return error if list elements contain integers > 255 when
+ <c>Encoding</c> is set to <c>latin1</c>. Note that this does not in any way tell
+ how characters should be put on the actual IO device or how the
+ I/O server should handle them. Different I/O servers may handle the
+ characters however they want, this simply tells the I/O server which
+ format the data is expected to have. In the <c>Module</c>/<c>Function</c>/<c>Args</c>
+ case, <c>Encoding</c> tells which format the designated function
+ produces. Note that byte-oriented data is simplest sent using the ISO-latin-1
+ encoding.</item>
+
+<item>Characters are the data to be put on the IO device. If <c>Encoding</c> is
+ <c>latin1</c>, this is an <c>iolist()</c>. If <c>Encoding</c> is <c>unicode</c>, this is an
+ Erlang standard mixed Unicode list (one integer in a list per
character, characters in binaries represented as UTF-8).</item>
-<item>Module, Function, Args denotes a function which will be called to
- produce the data (like io_lib:format). Args is a list of arguments
+<item><c>Module</c>, <c>Function</c>, and <c>Args</c> denote a function which will be called to
+ produce the data (like <c>io_lib:format/2</c>). <c>Args</c> is a list of arguments
to the function. The function should produce data in the given
- Encoding. The io_server should call the function as apply(Mod, Func,
- Args) and will put the returned data on the device as if it was sent
- in a {put_chars, Encoding, Characters} request. If the function
+ <c>Encoding</c>. The I/O server should call the function as
+ <c>apply(Mod, Func, Args)</c> and will put the returned data on the IO device as if it was sent
+ in a <c>{put_chars, Encoding, Characters}</c> request. If the function
returns anything else than a binary or list or throws an exception,
an error should be sent back to the client.</item>
</list>
-<p>The server replies to the client with an io_reply where the Reply
+<p>The I/O server replies to the client with an <c>io_reply</c> tuple where the <c>Reply</c>
element is one of:</p>
<p>
<em>ok</em><br/>
@@ -139,49 +139,50 @@ element is one of:</p>
</p>
<list type="bulleted">
-<item>Error describes the error to the client, which may do whatever it
- wants with it. The Erlang io-module typically returns it as is.</item>
+<item><c>Error</c> describes the error to the client, which may do whatever
+ it wants with it. The Erlang <seealso marker="stdlib:io">io</seealso>
+ module typically returns it as is.</item>
</list>
-<p>For backward compatibility the following Requests should also be
-handled by an io_server (these messages should not be present after
+<p>For backward compatibility the following <c>Request</c>s should also be
+handled by an I/O server (these requests should not be present after
R15B of OTP):</p>
<p>
<em>{put_chars, Characters}</em><br/>
<em>{put_chars, Module, Function, Args}</em>
</p>
-<p>These should behave as {put_chars, latin1, Characters} and {put_chars,
-latin1, Module, Function, Args} respectively. </p>
+<p>These should behave as <c>{put_chars, latin1, Characters}</c> and
+<c>{put_chars, latin1, Module, Function, Args}</c> respectively. </p>
</section>
<section>
<title>Input Requests</title>
-<p>To read characters from a device, the following Requests exist:</p>
+<p>To read characters from an IO device, the following <c>Request</c>s exist:</p>
<p><em>{get_until, Encoding, Prompt, Module, Function, ExtraArgs}</em></p>
<list type="bulleted">
-<item>Encoding denotes how data is to be sent back to the client and
+<item><c>Encoding</c> denotes how data is to be sent back to the client and
what data is sent to the function denoted by
- Module/Function/ExtraArgs. If the function supplied returns data as a
+ <c>Module</c>/<c>Function</c>/<c>ExtraArgs</c>. If the function supplied returns data as a
list, the data is converted to this encoding. If however the
function supplied returns data in some other format, no conversion
- can be done and it's up to the client supplied function to return
- data in a proper way. If Encoding is latin1, lists of integers
+ can be done and it is up to the client supplied function to return
+ data in a proper way. If <c>Encoding</c> is <c>latin1</c>, lists of integers
0..255 or binaries containing plain bytes are sent back to the
- client when possible, if Encoding is unicode, lists with integers in
- the whole unicode range or binaries encoded in UTF-8 are sent to the
+ client when possible; if <c>Encoding</c> is <c>unicode</c>, lists with integers in
+ the whole Unicode range or binaries encoded in UTF-8 are sent to the
client. The user supplied function will always see lists of integers, never
- binaries, but the list may contain numbers > 255 if the Encoding is
- 'unicode'.</item>
+ binaries, but the list may contain numbers > 255 if the <c>Encoding</c> is
+ <c>unicode</c>.</item>
-<item>Prompt is a list of characters (not mixed, no binaries) or an atom()
- to be output as a prompt for input on the device. The Prompt is
- often ignored by the io_server and a Prompt set to '' should always
- be ignored (and result in nothing being written to the device).</item>
+<item><c>Prompt</c> is a list of characters (not mixed, no binaries) or an atom
+ to be output as a prompt for input on the IO device. <c>Prompt</c> is
+ often ignored by the I/O server and if set to <c>''</c> it should always
+ be ignored (and result in nothing being written to the IO device).</item>
-<item><p>Module, Function, ExtraArgs denotes a function and arguments to
+<item><p><c>Module</c>, <c>Function</c>, and <c>ExtraArgs</c> denote a function and arguments to
determine when enough data is written. The function should take two
additional arguments, the last state, and a list of characters. The
function should return one of:</p>
@@ -189,23 +190,23 @@ latin1, Module, Function, Args} respectively. </p>
<em>{done, Result, RestChars}</em><br/>
<em>{more, Continuation}</em>
</p>
- <p>The Result can be any Erlang term, but if it is a list(), the
- io_server may convert it to a binary() of appropriate format before
- returning it to the client, if the server is set in binary mode (see
+ <p>The <c>Result</c> can be any Erlang term, but if it is a <c>list()</c>, the
+ I/O server may convert it to a <c>binary()</c> of appropriate format before
+ returning it to the client, if the I/O server is set in binary mode (see
below).</p>
- <p>The function will be called with the data the io_server finds on
- its device, returning {done, Result, RestChars} when enough data is
- read (in which case Result is sent to the client and RestChars are
- kept in the io_server as a buffer for subsequent input) or {more,
- Continuation}, indicating that more characters are needed to
- complete the request. The Continuation will be sent as the state in
+ <p>The function will be called with the data the I/O server finds on
+ its IO device, returning <c>{done, Result, RestChars}</c> when enough data is
+ read (in which case <c>Result</c> is sent to the client and <c>RestChars</c> is
+ kept in the I/O server as a buffer for subsequent input) or
+ <c>{more, Continuation}</c>, indicating that more characters are needed to
+ complete the request. The <c>Continuation</c> will be sent as the state in
subsequent calls to the function when more characters are
available. When no more characters are available, the function
- shall return {done,eof,Rest}.
+ shall return <c>{done, eof, Rest}</c>.
The initial state is the empty list and the data when an
- end of file is reached on the device is the atom 'eof'. An emulation
- of the get_line request could be (inefficiently) implemented using
+ end of file is reached on the IO device is the atom <c>eof</c>. An emulation
+ of the <c>get_line</c> request could be (inefficiently) implemented using
the following functions:</p>
<code>
-module(demo).
@@ -214,7 +215,9 @@ latin1, Module, Function, Args} respectively. </p>
until_newline(_ThisFar,eof,_MyStopCharacter) -&gt;
{done,eof,[]};
until_newline(ThisFar,CharList,MyStopCharacter) -&gt;
- case lists:splitwith(fun(X) -&gt; X =/= MyStopCharacter end, CharList) of
+ case
+ lists:splitwith(fun(X) -&gt; X =/= MyStopCharacter end, CharList)
+ of
{L,[]} -&gt;
{more,ThisFar++L};
{L2,[MyStopCharacter|Rest]} -&gt;
@@ -222,45 +225,47 @@ until_newline(ThisFar,CharList,MyStopCharacter) -&gt;
end.
get_line(IoServer) -&gt;
- IoServer ! {io_request, self(), IoServer, {get_until, unicode, '',
- ?MODULE, until_newline, [$\n]}},
+ IoServer ! {io_request,
+ self(),
+ IoServer,
+ {get_until, unicode, '', ?MODULE, until_newline, [$\n]}},
receive
{io_reply, IoServer, Data} -&gt;
Data
end.
</code>
- <p>Note especially that the last element in the Request tuple ([$\n])
+ <p>Note especially that the last element in the <c>Request</c> tuple (<c>[$\n]</c>)
is appended to the argument list when the function is called. The
function should be called like
- apply(Module, Function, [ State, Data | ExtraArgs ]) by the io_server</p>
+ <c>apply(Module, Function, [ State, Data | ExtraArgs ])</c> by the I/O server</p>
</item>
</list>
-<p>A defined number of characters is requested using this Request:</p>
+<p>A fixed number of characters is requested using this <c>Request</c>:</p>
<p>
<em>{get_chars, Encoding, Prompt, N}</em>
</p>
<list type="bulleted">
-<item>Encoding and Prompt as for get_until.</item>
+<item><c>Encoding</c> and <c>Prompt</c> as for <c>get_until</c>.</item>
-<item>N is the number of characters to be read from the device.</item>
+<item><c>N</c> is the number of characters to be read from the IO device.</item>
</list>
-<p>A single line (like in the example above) is requested with this Request:</p>
+<p>A single line (like in the example above) is requested with this <c>Request</c>:</p>
<p>
<em>{get_line, Encoding, Prompt}</em>
</p>
<list type="bulleted">
-<item>Encoding and prompt as above.</item>
+<item><c>Encoding</c> and <c>Prompt</c> as above.</item>
</list>
-<p>Obviously, get_chars and get_line could be implemented with the
-get_until request (and indeed was originally), but demands for
+<p>Obviously, the <c>get_chars</c> and <c>get_line</c> could be implemented with the
+<c>get_until</c> request (and indeed they were originally), but demands for
efficiency has made these additions necessary.</p>
-<p>The server replies to the client with an io_reply where the Reply
+<p>The I/O server replies to the client with an <c>io_reply</c> tuple where the <c>Reply</c>
element is one of:</p>
<p>
<em>Data</em><br/>
@@ -269,16 +274,17 @@ element is one of:</p>
</p>
<list type="bulleted">
-<item>Data is the characters read, in either list or binary form
- (depending on the io_server mode, see below).</item>
-<item>Error describes the error to the client, which may do whatever it
- wants with it. The Erlang io-module typically returns it as is.</item>
-<item>eof is returned when input end is reached and no more data is
+<item><c>Data</c> is the characters read, in either list or binary form
+ (depending on the I/O server mode, see below).</item>
+<item><c>Error</c> describes the error to the client, which may do whatever it
+ wants with it. The Erlang <seealso marker="stdlib:io">io</seealso>
+ module typically returns it as is.</item>
+<item><c>eof</c> is returned when input end is reached and no more data is
available to the client process.</item>
</list>
-<p>For backward compatibility the following Requests should also be
-handled by an io_server (these messages should not be present after
+<p>For backward compatibility the following <c>Request</c>s should also be
+handled by an I/O server (these reqeusts should not be present after
R15B of OTP):</p>
<p>
@@ -287,30 +293,30 @@ R15B of OTP):</p>
<em>{get_line, Prompt}</em><br/>
</p>
-<p>These should behave as {get_until, latin1, Prompt, Module, Function,
-ExtraArgs}, {get_chars, latin1, Prompt, N} and {get_line, latin1,
-Prompt} respectively.</p>
+<p>These should behave as <c>{get_until, latin1, Prompt, Module, Function,
+ExtraArgs}</c>, <c>{get_chars, latin1, Prompt, N}</c> and <c>{get_line, latin1,
+Prompt}</c> respectively.</p>
</section>
<section>
-<title>I/O-server modes</title>
-
-<p>Demands for efficiency when reading data from an io_server has not
-only lead to the addition of the get_line and get_chars requests, but
-has also added the concept of io_server options. No options are
-mandatory to implement, but all io_servers in the Erlang standard
-libraries honor the 'binary' option, which allows the Data in the
-io_reply to be binary instead of in list form <em>when possible</em>.
+<title>I/O-server Modes</title>
+
+<p>Demands for efficiency when reading data from an I/O server has not
+only lead to the addition of the <c>get_line</c> and <c>get_chars</c> requests, but
+has also added the concept of I/O server options. No options are
+mandatory to implement, but all I/O servers in the Erlang standard
+libraries honor the <c>binary</c> option, which allows the <c>Data</c> element of the
+<c>io_reply</c> tuple to be a binary instead of a list <em>when possible</em>.
If the data is sent as a binary, Unicode data will be sent in the
-standard Erlang unicode
-format, i.e. UTF-8 (note that the function in get_until still gets
-list data regardless of the io_server mode).</p>
+standard Erlang Unicode
+format, i.e. UTF-8 (note that the function of the <c>get_until</c> request still gets
+list data regardless of the I/O server mode).</p>
-<p>Note that i.e. the <c>get_until</c> request allows for a function with the data specified as always being a list. Also the return value data from such a function can be of any type (as is indeed the case when an io:fread request is sent to an io_server). The client has to be prepared for data received as answers to those requests to be in a variety of forms, but the server should convert the results to binaries whenever possible (i.e. when the function supplied to get_until actually returns a list). The example shown later in this text does just that.</p>
+<p>Note that i.e. the <c>get_until</c> request allows for a function with the data specified as always being a list. Also the return value data from such a function can be of any type (as is indeed the case when an <c>io:fread</c> request is sent to an I/O server). The client has to be prepared for data received as answers to those requests to be in a variety of forms, but the I/O server should convert the results to binaries whenever possible (i.e. when the function supplied to <c>get_until</c> actually returns a list). The example shown later in this text does just that.</p>
<p>An I/O-server in binary mode will affect the data sent to the client,
so that it has to be able to handle binary data. For convenience, it
-is possible to set and retrieve the modes of an io_server using the
-following I/O-requests:</p>
+is possible to set and retrieve the modes of an I/O server using the
+following I/O requests:</p>
<p>
<em>{setopts, Opts}</em>
@@ -318,72 +324,72 @@ following I/O-requests:</p>
<list type="bulleted">
-<item>Opts is a list of options in the format recognized by proplists (and
- of course by the io_server itself).</item>
+<item><c>Opts</c> is a list of options in the format recognized by <seealso marker="stdlib:proplists">proplists</seealso> (and
+ of course by the I/O server itself).</item>
</list>
-<p>As an example, the io_server for the interactive shell (in group.erl)
+<p>As an example, the I/O server for the interactive shell (in <c>group.erl</c>)
understands the following options:</p>
<p>
-<em>{binary, bool()} (or 'binary'/'list')</em><br/>
-<em>{echo, bool()}</em><br/>
+<em>{binary, boolean()}</em> (or <em>binary</em>/<em>list</em>)<br/>
+<em>{echo, boolean()}</em><br/>
<em>{expand_fun, fun()}</em><br/>
-<em>{encoding, 'unicode'/'latin1'} (or 'unicode'/'latin1')</em>
+<em>{encoding, unicode/latin1}</em> (or <em>unicode</em>/<em>latin1</em>)
</p>
-<p>- of which the 'binary' and 'encoding' options are common for all
-io_servers in OTP, while 'echo' and 'expand' is valid only for this
-io_server. It's worth noting that the 'unicode' option notifies how
-characters are actually put on the physical device, i.e. if the
-terminal per se is unicode aware, it does not affect how characters
+<p>- of which the <c>binary</c> and <c>encoding</c> options are common for all
+I/O servers in OTP, while <c>echo</c> and <c>expand</c> are valid only for this
+I/O server. It is worth noting that the <c>unicode</c> option notifies how
+characters are actually put on the physical IO device, i.e. if the
+terminal per se is Unicode aware, it does not affect how characters
are sent in the I/O-protocol, where each request contains encoding
information for the provided or returned data.</p>
-<p>The server should send one of the following as Reply:</p>
+<p>The I/O server should send one of the following as <c>Reply</c>:</p>
<p>
<em>ok</em><br/>
<em>{error, Error}</em>
</p>
-<p>An error (preferably enotsup) is to be expected if the option is
-not supported by the io_server (like if an 'echo' option is sent in a
-setopt Request to a plain file).</p>
+<p>An error (preferably <c>enotsup</c>) is to be expected if the option is
+not supported by the I/O server (like if an <c>echo</c> option is sent in a
+<c>setopts</c> request to a plain file).</p>
-<p>To retrieve options, this message is used:</p>
+<p>To retrieve options, this request is used:</p>
<p>
<em>getopts</em>
</p>
-<p>The 'getopts' message requests a complete list of all options
-supported by the io_server as well as their current values.</p>
+<p>The <c>getopts</c> request asks for a complete list of all options
+supported by the I/O server as well as their current values.</p>
-<p>The server replies:</p>
+<p>The I/O server replies:</p>
<p>
<em>OptList</em><br/>
-<em>{error,Error}</em>
+<em>{error, Error}</em>
</p>
<list type="bulleted">
-<item>OptList is a list of tuples {Option, Value} where Option is always
+<item><c>OptList</c> is a list of tuples <c>{Option, Value}</c> where <c>Option</c> is always
an atom.</item>
</list>
</section>
<section>
-<title>Multiple I/O requests</title>
+<title>Multiple I/O Requests</title>
-<p>The Request element can in itself contain several Requests by using
+<p>The <c>Request</c> element can in itself contain several <c>Request</c>s by using
the following format:</p>
<p>
<em>{requests, Requests}</em>
</p>
<list type="bulleted">
-<item>Requests is a list of valid Request tuples for the protocol, they
+<item><c>Requests</c> is a list of valid <c>io_request</c> tuples for the protocol, they
shall be executed in the order in which they appear in the list and
the execution should continue until one of the requests result in an
error or the list is consumed. The result of the last request is
sent back to the client.</item>
</list>
-<p>The server can for a list of requests send any of the valid results in
+<p>The I/O server can for a list of requests send any of the valid results in
the reply:</p>
<p>
@@ -395,7 +401,7 @@ the reply:</p>
<p>- depending on the actual requests in the list.</p>
</section>
<section>
-<title>Optional I/O-requests</title>
+<title>Optional I/O Requests</title>
<p>The following I/O request is optional to implement and a client
should be prepared for an error return:</p>
@@ -403,47 +409,47 @@ should be prepared for an error return:</p>
<em>{get_geometry, Geometry}</em>
</p>
<list type="bulleted">
-<item>Geometry is either the atom 'rows' or the atom 'columns'.</item>
+<item><c>Geometry</c> is either the atom <c>rows</c> or the atom <c>columns</c>.</item>
</list>
-<p>The server should send the Reply as:</p>
+<p>The I/O server should send the <c>Reply</c> as:</p>
<p>
<em>{ok, N}</em><br/>
<em>{error, Error}</em>
</p>
<list type="bulleted">
-<item>N is the number of character rows or columns the device has, if
- applicable to the device the io_server handles, otherwise {error,
- enotsup} is a good answer.</item>
+<item><c>N</c> is the number of character rows or columns the IO device has, if
+ applicable to the IO device the I/O server handles, otherwise <c>{error,
+ enotsup}</c> is a good answer.</item>
</list>
</section>
<section>
-<title>Unimplemented request types:</title>
+<title>Unimplemented Request Types</title>
-<p>If an io_server encounters a request it does not recognize (i.e. the
-io_request tuple is in the expected format, but the actual Request is
-unknown), the server should send a valid reply with the error tuple:</p>
+<p>If an I/O server encounters a request it does not recognize (i.e. the
+<c>io_request</c> tuple is in the expected format, but the actual <c>Request</c> is
+unknown), the I/O server should send a valid reply with the error tuple:</p>
<p>
<em>{error, request}</em>
</p>
-<p>This makes it possible to extend the protocol with optional messages
+<p>This makes it possible to extend the protocol with optional requests
and for the clients to be somewhat backwards compatible.</p>
</section>
<section>
-<title>An annotated and working example io_server:</title>
+<title>An Annotated and Working Example I/O Server</title>
-<p>An io_server is any process capable of handling the protocol. There is
-no generic io_server behavior, but could well be. The framework is
+<p>An I/O server is any process capable of handling the I/O protocol. There is
+no generic I/O server behavior, but could well be. The framework is
simple enough, a process handling incoming requests, usually both
-io_requests and other device-specific requests (for i.e. positioning ,
+I/O-requests and other IO device-specific requests (for i.e. positioning,
closing etc.).</p>
-<p>Our example io_server stores characters in an ets table, making up a
+<p>Our example I/O server stores characters in an ETS table, making up a
fairly crude ram-file (it is probably not useful, but working).</p>
<p>The module begins with the usual directives, a function to start the
-server and a main loop handling the requests:</p>
+I/O server and a main loop handling the requests:</p>
<code>
-module(ets_io_server).
@@ -486,18 +492,19 @@ loop(State) -&gt;
</code>
<p>The main loop receives messages from the client (which might be using
-the io-module to send requests). For each request the function
-request/2 is called and a reply is eventually sent using the reply/3
+the <seealso marker="stdlib:io">io</seealso> module to send requests).
+For each request the function
+<c>request/2</c> is called and a reply is eventually sent using the <c>reply/3</c>
function.</p>
-<p>The &quot;private&quot; message {From, rewind} results in the
+<p>The &quot;private&quot; message <c>{From, rewind}</c> results in the
current position in the pseudo-file to be reset to 0 (the beginning of
-the &quot;file&quot;). This is a typical example of device-specific
+the &quot;file&quot;). This is a typical example of IO device-specific
messages not being part of the I/O-protocol. It is usually a bad idea
-to embed such private messages in io_request tuples, as that might be
+to embed such private messages in <c>io_request</c> tuples, as that might be
confusing to the reader.</p>
-<p>Let's look at the reply function first...</p>
+<p>Let us look at the reply function first...</p>
<code>
@@ -506,8 +513,8 @@ reply(From, ReplyAs, Reply) -&gt;
</code>
-<p>Simple enough, it sends the io_reply tuple back to the client,
-providing the ReplyAs element received in the request along with the
+<p>Simple enough, it sends the <c>io_reply</c> tuple back to the client,
+providing the <c>ReplyAs</c> element received in the request along with the
result of the request, as described above.</p>
<p>Now look at the different requests we need to handle. First the
@@ -525,18 +532,18 @@ request({put_chars, Encoding, Module, Function, Args}, State) -&gt;
end;
</code>
-<p>The Encoding tells us how the characters in the message are
+<p>The <c>Encoding</c> tells us how the characters in the request are
represented. We want to store the characters as lists in the
-ets-table, so we convert them to lists using the
-unicode:characters_to_list/2 function. The conversion function
-conveniently accepts the encoding types unicode or latin1, so we can
-use the Encoding parameter directly.</p>
+ETS table, so we convert them to lists using the
+<seealso marker="stdlib:unicode#characters_to_list/2"><c>unicode:characters_to_list/2</c></seealso> function. The conversion function
+conveniently accepts the encoding types <c>unicode</c> or <c>latin1</c>, so we can
+use <c>Encoding</c> directly.</p>
-<p>When Module, Function and Arguments are provided, we simply apply it
+<p>When <c>Module</c>, <c>Function</c> and <c>Arguments</c> are provided, we simply apply it
and do the same thing with the result as if the data was provided
directly.</p>
-<p>Let's handle the requests for retrieving data too:</p>
+<p>Let us handle the requests for retrieving data too:</p>
<code>
request({get_until, Encoding, _Prompt, M, F, As}, State) -&gt;
@@ -550,11 +557,11 @@ request({get_line, Encoding, _Prompt}, State) -&gt;
</code>
<p>Here we have cheated a little by more or less only implementing
-get_until and using internal helpers to implement get_chars and
-get_line. In production code, this might be to inefficient, but that
+<c>get_until</c> and using internal helpers to implement <c>get_chars</c> and
+<c>get_line</c>. In production code, this might be too inefficient, but that
of course depends on the frequency of the different requests. Before
-we start actually implementing the functions put_chars/2 and
-get_until/5, lets look into the few remaining requests:</p>
+we start actually implementing the functions <c>put_chars/2</c> and
+<c>get_until/5</c>, let us look into the few remaining requests:</p>
<code>
request({get_geometry,_}, State) -&gt;
@@ -567,18 +574,18 @@ request({requests, Reqs}, State) -&gt;
multi_request(Reqs, {ok, ok, State});
</code>
-<p>The get_geometry request has no meaning for this io_server, so the
-reply will be {error, enotsup}. The only option we handle is the
-binary/list option, which is done in separate functions.</p>
+<p>The <c>get_geometry</c> request has no meaning for this I/O server, so the
+reply will be <c>{error, enotsup}</c>. The only option we handle is the
+<c>binary</c>/<c>list</c> option, which is done in separate functions.</p>
-<p>The multi-request tag (requests) is handled in a separate loop
+<p>The multi-request tag (<c>requests</c>) is handled in a separate loop
function applying the requests in the list one after another,
returning the last result.</p>
-<p>What's left is to handle backward compatibility and the file-module
+<p>What is left is to handle backward compatibility and the <seealso marker="kernel:file">file</seealso> module
(which uses the old requests until backward compatibility with pre-R13
-nodes is no longer needed). Note that the io_server will not work with
-a simple file:write if these are not added:</p>
+nodes is no longer needed). Note that the I/O server will not work with
+a simple <c>file:write/2</c> if these are not added:</p>
<code>
request({put_chars,Chars}, State) -&gt;
@@ -593,7 +600,7 @@ request({get_until, Prompt,M,F,As}, State) -&gt;
request({get_until,latin1,Prompt,M,F,As}, State);
</code>
-<p>Ok, what's left now is to return {error, request} if the request is
+<p>OK, what is left now is to return <c>{error, request}</c> if the request is
not recognized:</p>
<code>
@@ -601,7 +608,7 @@ request(_Other, State) -&gt;
{error, {error, request}, State}.
</code>
-<p>Let's move further and actually handle the different requests, first
+<p>Let us move further and actually handle the different requests, first
the fairly generic multi-request type:</p>
<code>
@@ -615,10 +622,10 @@ multi_request([], Result) -&gt;
<p>We loop through the requests one at the time, stopping when we either
encounter an error or the list is exhausted. The last return value is
-sent back to the client (it's first returned to the main loop and then
-sent back by the function io_reply).</p>
+sent back to the client (it is first returned to the main loop and then
+sent back by the function <c>io_reply</c>).</p>
-<p>The getopt and setopt requests are also simple to handle, we just
+<p>The <c>getopts</c> and <c>setopts</c> requests are also simple to handle, we just
change or read our state record:</p>
<code>
@@ -656,24 +663,24 @@ getopts(#state{mode=M} = S) -&gt;
end}],S}.
</code>
-<p>As a convention, all io_servers handle both {setopts, [binary]},
-{setopts, [list]} and {setopts,[{binary, bool()}]}, hence the trick
-with proplists:substitute_negations/2 and proplists:unfold/1. If
-invalid options are sent to us, we send {error,enotsup} back to the
+<p>As a convention, all I/O servers handle both <c>{setopts, [binary]}</c>,
+<c>{setopts, [list]}</c> and <c>{setopts,[{binary, boolean()}]}</c>, hence the trick
+with <c>proplists:substitute_negations/2</c> and <c>proplists:unfold/1</c>. If
+invalid options are sent to us, we send <c>{error, enotsup}</c> back to the
client.</p>
-<p>The getopts request should return a list of {Option, Value} tuples,
+<p>The <c>getopts</c> request should return a list of <c>{Option, Value}</c> tuples,
which has the twofold function of providing both the current values
-and the available options of this io_server. We have only one option,
+and the available options of this I/O server. We have only one option,
and hence return that.</p>
-<p>So far our io_server has been fairly generic (except for the rewind
-request handled in the main loop and the creation of an ets table).
-Most io_servers contain code similar to what's above.</p>
+<p>So far our I/O server has been fairly generic (except for the <c>rewind</c>
+request handled in the main loop and the creation of an ETS table).
+Most I/O servers contain code similar to the one above.</p>
<p>To make the example runnable, we now start implementing the actual
-reading and writing of the data to/from the ets-table. First the
-put_chars function:</p>
+reading and writing of the data to/from the ETS table. First the
+<c>put_chars/3</c> function:</p>
<code>
put_chars(Chars, #state{table = T, position = P} = State) -&gt;
@@ -686,10 +693,10 @@ put_chars(Chars, #state{table = T, position = P} = State) -&gt;
<p>We already have the data as (Unicode) lists and therefore just split
the list in runs of a predefined size and put each run in the
table at the current position (and forward). The functions
-split_data/3 and apply_update/2 are implemented below.</p>
+<c>split_data/3</c> and <c>apply_update/2</c> are implemented below.</p>
-<p>Now we want to read data from the table. The get_until function reads
-data and applies the function until it says it's done. The result is
+<p>Now we want to read data from the table. The <c>get_until/5</c> function reads
+data and applies the function until it says it is done. The result is
sent back to the client:</p>
<code>
@@ -700,11 +707,12 @@ get_until(Encoding, Mod, Func, As,
if
M =:= binary -&gt;
{ok,
- unicode:characters_to_binary(Data,unicode,Encoding),
+ unicode:characters_to_binary(Data, unicode, Encoding),
State#state{position = NewP}};
true -&gt;
case check(Encoding,
- unicode:characters_to_list(Data, unicode)) of
+ unicode:characters_to_list(Data, unicode))
+ of
{error, _} = E -&gt;
{error, E, State};
List -&gt;
@@ -730,24 +738,24 @@ get_loop(M,F,A,T,P,C) -&gt;
end.
</code>
-<p>Here we also handle the mode (binary or list) that can be set by
-the setopts request. By default, all OTP io_servers send data back to
-the client as lists, but switching mode to binary might increase
-efficiency if the server handles it in an appropriate way. The
-implementation of get_until is hard to get efficient as the supplied
-function is defined to take lists as arguments, but get_chars and
-get_line can be optimized for binary mode. This example does not
+<p>Here we also handle the mode (<c>binary</c> or <c>list</c>) that can be set by
+the <c>setopts</c> request. By default, all OTP I/O servers send data back to
+the client as lists, but switching mode to <c>binary</c> might increase
+efficiency if the I/O server handles it in an appropriate way. The
+implementation of <c>get_until</c> is hard to get efficient as the supplied
+function is defined to take lists as arguments, but <c>get_chars</c> and
+<c>get_line</c> can be optimized for binary mode. This example does not
optimize anything however. It is important though that the returned
data is of the right type depending on the options set, so we convert
the lists to binaries in the correct encoding <em>if possible</em>
-before returning. The function supplied in the get_until request may,
+before returning. The function supplied in the <c>get_until</c> request tuple may,
as its final result return anything, so only functions actually
returning lists can get them converted to binaries. If the request
-contained the encoding tag unicode, the lists can contain all unicode
+contained the encoding tag <c>unicode</c>, the lists can contain all Unicode
codepoints and the binaries should be in UTF-8, if the encoding tag
-was latin1, the client should only get characters in the range
-0..255. The function check/2 takes care of not returning arbitrary
-unicode codepoints in lists if the encoding was given as latin1. If
+was <c>latin1</c>, the client should only get characters in the range
+0..255. The function <c>check/2</c> takes care of not returning arbitrary
+Unicode codepoints in lists if the encoding was given as <c>latin1</c>. If
the function did not return a list, the check cannot be performed and
the result will be that of the supplied function untouched.</p>
@@ -768,13 +776,13 @@ check(latin1, List) -&gt;
end.
</code>
-<p>The function check takes care of providing an error tuple if unicode
+<p>The function check takes care of providing an error tuple if Unicode
codepoints above 255 is to be returned if the client requested
latin1.</p>
-<p>The two functions until_newline/3 and until_enough/3 are helpers used
-together with the get_until function to implement get_chars and
-get_line (inefficiently):</p>
+<p>The two functions <c>until_newline/3</c> and <c>until_enough/3</c> are helpers used
+together with the <c>get_until/5</c> function to implement <c>get_chars</c> and
+<c>get_line</c> (inefficiently):</p>
<code>
until_newline([],eof,_MyStopCharacter) -&gt;
@@ -782,7 +790,9 @@ until_newline([],eof,_MyStopCharacter) -&gt;
until_newline(ThisFar,eof,_MyStopCharacter) -&gt;
{done,ThisFar,[]};
until_newline(ThisFar,CharList,MyStopCharacter) -&gt;
- case lists:splitwith(fun(X) -&gt; X =/= MyStopCharacter end, CharList) of
+ case
+ lists:splitwith(fun(X) -&gt; X =/= MyStopCharacter end, CharList)
+ of
{L,[]} -&gt;
{more,ThisFar++L};
{L2,[MyStopCharacter|Rest]} -&gt;
@@ -802,10 +812,10 @@ until_enough(ThisFar,CharList,_N) -&gt;
</code>
<p>As can be seen, the functions above are just the type of functions
-that should be provided in get_until requests.</p>
+that should be provided in <c>get_until</c> requests.</p>
<p>Now we only need to read and write the table in an appropriate way to
-complete the server:</p>
+complete the I/O server:</p>
<code>
get(P,Tab) -&gt;
@@ -847,13 +857,13 @@ apply_update(Table, {Row, Col, List}) -&gt;
end.
</code>
-<p>The table is read or written in chunks of ?CHARS_PER_REC, overwriting
+<p>The table is read or written in chunks of <c>?CHARS_PER_REC</c>, overwriting
when necessary. The implementation is obviously not efficient, it is
just working.</p>
<p>This concludes the example. It is fully runnable and you can read or
-write to the io_server by using i.e. the io_module or even the file
-module. It's as simple as that to implement a fully fledged io_server
+write to the I/O server by using i.e. the <seealso marker="stdlib:io">io</seealso> module or even the <seealso marker="kernel:file">file</seealso>
+module. It is as simple as that to implement a fully fledged I/O server
in Erlang.</p>
</section>
</chapter>
diff --git a/lib/stdlib/doc/src/notes.xml b/lib/stdlib/doc/src/notes.xml
index b4d9f9a444..2a308cbe09 100644
--- a/lib/stdlib/doc/src/notes.xml
+++ b/lib/stdlib/doc/src/notes.xml
@@ -30,6 +30,21 @@
</header>
<p>This document describes the changes made to the STDLIB application.</p>
+<section><title>STDLIB 1.18.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Minor test updates</p>
+ <p>
+ Own Id: OTP-10591</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>STDLIB 1.18.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/stdlib/doc/src/proplists.xml b/lib/stdlib/doc/src/proplists.xml
index 225c5e97eb..8d64319344 100644
--- a/lib/stdlib/doc/src/proplists.xml
+++ b/lib/stdlib/doc/src/proplists.xml
@@ -70,7 +70,7 @@
<fsummary></fsummary>
<desc>
<p>Minimizes the representation of all entries in the list. This is
- equivalent to <c><![CDATA[[property(P) || P <- List]]]></c>.</p>
+ equivalent to <c><![CDATA[[property(P) || P <- ListIn]]]></c>.</p>
<p>See also: <c>property/1</c>, <c>unfold/1</c>.</p>
</desc>
</func>
@@ -88,11 +88,11 @@
<desc>
<p>Expands particular properties to corresponding sets of
properties (or other terms). For each pair <c>{<anno>Property</anno>, <anno>Expansion</anno>}</c> in <c><anno>Expansions</anno></c>, if <c>E</c> is
- the first entry in <c><anno>List</anno></c> with the same key as
+ the first entry in <c><anno>ListIn</anno></c> with the same key as
<c><anno>Property</anno></c>, and <c>E</c> and <c><anno>Property</anno></c>
have equivalent normal forms, then <c>E</c> is replaced with
the terms in <c><anno>Expansion</anno></c>, and any following entries with
- the same key are deleted from <c><anno>List</anno></c>.</p>
+ the same key are deleted from <c><anno>ListIn</anno></c>.</p>
<p>For example, the following expressions all return <c>[fie, bar, baz, fum]</c>:</p>
<code type="none">
expand([{foo, [bar, baz]}],
@@ -198,7 +198,7 @@
<name name="normalize" arity="2"/>
<fsummary></fsummary>
<desc>
- <p>Passes <c><anno>List</anno></c> through a sequence of
+ <p>Passes <c><anno>ListIn</anno></c> through a sequence of
substitution/expansion stages. For an <c>aliases</c> operation,
the function <c>substitute_aliases/2</c> is applied using the
given list of aliases; for a <c>negations</c> operation,
@@ -221,9 +221,9 @@
<fsummary></fsummary>
<desc>
<p>Creates a normal form (minimal) representation of a property. If
- <c><anno>Property</anno></c> is <c>{Key, true}</c> where <c>Key</c> is
- an atom, this returns <c>Key</c>, otherwise the whole term
- <c><anno>Property</anno></c> is returned.</p>
+ <c><anno>PropertyIn</anno></c> is <c>{Key, true}</c> where
+ <c>Key</c> is an atom, this returns <c>Key</c>, otherwise
+ the whole term <c><anno>PropertyIn</anno></c> is returned.</p>
<p>See also: <c>property/2</c>.</p>
</desc>
</func>
@@ -260,7 +260,7 @@
<fsummary></fsummary>
<desc>
<p>Substitutes keys of properties. For each entry in
- <c><anno>List</anno></c>, if it is associated with some key <c>K1</c>
+ <c><anno>ListIn</anno></c>, if it is associated with some key <c>K1</c>
such that <c>{K1, K2}</c> occurs in <c><anno>Aliases</anno></c>, the
key of the entry is changed to <c>K2</c>. If the same
<c>K1</c> occurs more than once in <c><anno>Aliases</anno></c>, only
@@ -278,13 +278,13 @@
<desc>
<p>Substitutes keys of boolean-valued properties and
simultaneously negates their values. For each entry in
- <c><anno>List</anno></c>, if it is associated with some key <c>K1</c>
+ <c><anno>ListIn</anno></c>, if it is associated with some key <c>K1</c>
such that <c>{K1, K2}</c> occurs in <c><anno>Negations</anno></c>, then
if the entry was <c>{K1, true}</c> it will be replaced with
<c>{K2, false}</c>, otherwise it will be replaced with
<c>{K2, true}</c>, thus changing the name of the option and
simultaneously negating the value given by
- <c>get_bool(List)</c>. If the same <c>K1</c> occurs more
+ <c>get_bool(ListIn)</c>. If the same <c>K1</c> occurs more
than once in <c><anno>Negations</anno></c>, only the first occurrence is
used.</p>
<p>Example: <c>substitute_negations([{no_foo, foo}], L)</c>
@@ -300,7 +300,7 @@
<name name="unfold" arity="1"/>
<fsummary></fsummary>
<desc>
- <p>Unfolds all occurrences of atoms in <c><anno>List</anno></c> to tuples
+ <p>Unfolds all occurrences of atoms in <c><anno>ListIn</anno></c> to tuples
<c>{Atom, true}</c>.</p>
</desc>
</func>
diff --git a/lib/stdlib/doc/src/re.xml b/lib/stdlib/doc/src/re.xml
index 2211bfb925..71a6e34513 100644
--- a/lib/stdlib/doc/src/re.xml
+++ b/lib/stdlib/doc/src/re.xml
@@ -96,12 +96,12 @@
subjects during the program's lifetime. Compiling once and
executing many times is far more efficient than compiling each
time one wants to match.</p>
- <p>When the unicode option is given, the regular expression should be given as a valid unicode <c>charlist()</c>, otherwise as any valid <c>iodata()</c>.</p>
+ <p>When the unicode option is given, the regular expression should be given as a valid Unicode <c>charlist()</c>, otherwise as any valid <c>iodata()</c>.</p>
<p><marker id="compile_options"/>The options have the following meanings:</p>
<taglist>
<tag><c>unicode</c></tag>
- <item>The regular expression is given as a unicode <c>charlist()</c> and the resulting regular expression code is to be run against a valid unicode <c>charlist()</c> subject.</item>
+ <item>The regular expression is given as a Unicode <c>charlist()</c> and the resulting regular expression code is to be run against a valid Unicode <c>charlist()</c> subject.</item>
<tag><c>anchored</c></tag>
<item>The pattern is forced to be "anchored", that is, it is constrained to match only at the first matching point in the string that is being searched (the "subject string"). This effect can also be achieved by appropriate constructs in the pattern itself.</item>
<tag><c>caseless</c></tag>
@@ -478,7 +478,7 @@ This option makes it possible to include comments inside complicated patterns. N
<p>Replaces the matched part of the <c><anno>Subject</anno></c> string with the contents of <c><anno>Replacement</anno></c>.</p>
<p>The permissible options are the same as for <c>re:run/3</c>, except that the <c>capture</c> option is not allowed.
Instead a <c>{return, <anno>ReturnType</anno>}</c> is present. The default return type is <c>iodata</c>, constructed in a
- way to minimize copying. The <c>iodata</c> result can be used directly in many i/o-operations. If a flat <c>list()</c> is
+ way to minimize copying. The <c>iodata</c> result can be used directly in many I/O-operations. If a flat <c>list()</c> is
desired, specify <c>{return, list}</c> and if a binary is preferred, specify <c>{return, binary}</c>.</p>
<p>As in the <c>re:run/3</c> function, an <c>mp()</c> compiled
diff --git a/lib/stdlib/doc/src/supervisor.xml b/lib/stdlib/doc/src/supervisor.xml
index f9a5e245b4..9021d02ade 100644
--- a/lib/stdlib/doc/src/supervisor.xml
+++ b/lib/stdlib/doc/src/supervisor.xml
@@ -294,10 +294,10 @@ child_spec() = {Id,StartFunc,Restart,Shutdown,Type,Modules}
is a term with information about the error, and the supervisor
terminates with reason <c>Term</c>.</p>
<p>If any child process start function fails or returns an error
- tuple or an erroneous value, the function returns
- <c>{error,shutdown}</c> and the supervisor terminates all
- started child processes and then itself with reason
- <c>shutdown</c>.</p>
+ tuple or an erroneous value, the supervisor will first terminate
+ all already started child processes with reason <c>shutdown</c>
+ and then terminate itself and return
+ <c>{error, {shutdown, Reason}}</c>.</p>
</desc>
</func>
<func>
diff --git a/lib/stdlib/doc/src/unicode.xml b/lib/stdlib/doc/src/unicode.xml
index 1f6cbaccd7..d235f3e180 100644
--- a/lib/stdlib/doc/src/unicode.xml
+++ b/lib/stdlib/doc/src/unicode.xml
@@ -32,9 +32,9 @@
<module>unicode</module>
<modulesummary>Functions for converting Unicode characters</modulesummary>
<description>
- <p>This module contains functions for converting between different character representations. Basically it converts between iso-latin-1 characters and Unicode ditto, but it can also convert between different Unicode encodings (like UTF-8, UTF-16 and UTF-32).</p>
+ <p>This module contains functions for converting between different character representations. Basically it converts between ISO-latin-1 characters and Unicode ditto, but it can also convert between different Unicode encodings (like UTF-8, UTF-16 and UTF-32).</p>
<p>The default Unicode encoding in Erlang is in binaries UTF-8, which is also the format in which built in functions and libraries in OTP expect to find binary Unicode data. In lists, Unicode data is encoded as integers, each integer representing one character and encoded simply as the Unicode codepoint for the character.</p>
- <p>Other Unicode encodings than integers representing codepoints or UTF-8 in binaries are referred to as &quot;external encodings&quot;. The iso-latin-1 encoding is in binaries and lists referred to as latin1-encoding.</p>
+ <p>Other Unicode encodings than integers representing codepoints or UTF-8 in binaries are referred to as &quot;external encodings&quot;. The ISO-latin-1 encoding is in binaries and lists referred to as latin1-encoding.</p>
<p>It is recommended to only use external encodings for communication with external entities where this is required. When working inside the Erlang/OTP environment, it is recommended to keep binaries in UTF-8 when representing Unicode characters. Latin1 encoding is supported both for backward compatibility and for communication with external entities not supporting Unicode character sets.</p>
</description>
@@ -48,13 +48,13 @@
<datatype>
<name name="unicode_binary"/>
<desc>
- <p>A binary() with characters encoded in the UTF-8 coding standard.</p>
+ <p>A <c>binary()</c> with characters encoded in the UTF-8 coding standard.</p>
</desc>
</datatype>
<datatype>
<name name="unicode_char"/>
<desc>
- <p>An integer() representing a valid unicode codepoint.</p>
+ <p>An <c>integer()</c> representing a valid Unicode codepoint.</p>
</desc>
</datatype>
<datatype>
@@ -63,7 +63,7 @@
<datatype>
<name name="charlist"/>
<desc>
- <p>A unicode_binary is allowed as the tail of the list.</p>
+ <p>A <c>unicode_binary()</c> is allowed as the tail of the list.</p>
</desc>
</datatype>
<datatype>
@@ -85,7 +85,7 @@
</datatype>
<datatype>
<name name="latin1_binary"/>
- <desc><p>A <c>binary()</c> with characters coded in iso-latin-1.</p>
+ <desc><p>A <c>binary()</c> with characters coded in ISO-latin-1.</p>
</desc>
</datatype>
<datatype>
@@ -110,7 +110,9 @@
<name name="bom_to_encoding" arity="1"/>
<fsummary>Identify UTF byte order marks in a binary.</fsummary>
<type name="endian"/>
- <type_desc variable="Bin">A binary() of byte_size 4 or more.</type_desc>
+ <type_desc variable="Bin">
+ A <c>binary()</c> such that <c>byte_size(<anno>Bin</anno>) >= 4</c>.
+ </type_desc>
<desc>
<p>Check for a UTF byte order mark (BOM) in the beginning of a
@@ -126,7 +128,7 @@
<name name="characters_to_list" arity="1"/>
<fsummary>Convert a collection of characters to list of Unicode characters</fsummary>
<desc>
- <p>Same as characters_to_list(<anno>Data</anno>,unicode).</p>
+ <p>Same as <c>characters_to_list(<anno>Data</anno>, unicode)</c>.</p>
</desc>
</func>
<func>
@@ -134,8 +136,8 @@
<fsummary>Convert a collection of characters to list of Unicode characters</fsummary>
<desc>
- <p>This function converts a possibly deep list of integers and
- binaries into a list of integers representing unicode
+ <p>Converts a possibly deep list of integers and
+ binaries into a list of integers representing Unicode
characters. The binaries in the input may have characters
encoded as latin1 (0 - 255, one character per byte), in which
case the <c><anno>InEncoding</anno></c> parameter should be given as
@@ -148,18 +150,18 @@
<p>If <c><anno>InEncoding</anno></c> is <c>latin1</c>, the <c><anno>Data</anno></c> parameter
corresponds to the <c>iodata()</c> type, but for <c>unicode</c>,
the <c><anno>Data</anno></c> parameter can contain integers greater than 255
- (unicode characters beyond the iso-latin-1 range), which would
+ (Unicode characters beyond the ISO-latin-1 range), which would
make it invalid as <c>iodata()</c>.</p>
<p>The purpose of the function is mainly to be able to convert
- combinations of unicode characters into a pure unicode
+ combinations of Unicode characters into a pure Unicode
string in list representation for further processing. For
writing the data to an external entity, the reverse function
<seealso
- marker="#characters_to_binary/3">characters_to_binary/3</seealso>
+ marker="#characters_to_binary/3"><c>characters_to_binary/3</c></seealso>
comes in handy.</p>
- <p>The option <c>unicode</c> is an alias for <c>utf8</c>, as this is the
+ <p>The option <c>unicode</c> is an alias for <c>utf8</c>, as this is the
preferred encoding for Unicode characters in
binaries. <c>utf16</c> is an alias for <c>{utf16,big}</c> and
<c>utf32</c> is an alias for <c>{utf32,big}</c>. The <c>big</c>
@@ -167,7 +169,7 @@
encoding.</p>
<p>If for some reason, the data cannot be converted, either
- because of illegal unicode/latin1 characters in the list, or
+ because of illegal Unicode/latin1 characters in the list, or
because of invalid UTF encoding in any binaries, an error
tuple is returned. The error tuple contains the tag
<c>error</c>, a list representing the characters that could be
@@ -176,7 +178,7 @@
last part is mostly for debugging as it still constitutes a
possibly deep and/or mixed list, not necessarily of the same
depth as the original data. The error occurs when traversing the
- list and whatever's left to decode is simply returned as is.</p>
+ list and whatever is left to decode is simply returned as is.</p>
<p>However, if the input <c><anno>Data</anno></c> is a pure binary, the third
part of the error tuple is guaranteed to be a binary as
@@ -191,7 +193,7 @@
of a Unicode type, an error occurs whenever an integer
<list type="bulleted">
<item>greater than <c>16#10FFFF</c>
- (the maximum unicode character),</item>
+ (the maximum Unicode character),</item>
<item>in the range <c>16#D800</c> to <c>16#DFFF</c>
(invalid range reserved for UTF-16 surrogate pairs)</item>
</list>
@@ -205,14 +207,14 @@
(like the upper
bits of the bytes being wrong), the bytes are decoded to a
too large number, the bytes are decoded to a code-point in the
- invalid unicode
- range or encoding is &quot;overlong&quot;, meaning that a
+ invalid Unicode
+ range, or encoding is &quot;overlong&quot;, meaning that a
number should have been encoded in fewer bytes. The
case of a truncated UTF is handled specially, see the
paragraph about incomplete binaries below. If
<c><anno>InEncoding</anno></c> is <c>latin1</c>, binaries are always valid
as long as they contain whole bytes,
- as each byte falls into the valid iso-latin-1 range.</item>
+ as each byte falls into the valid ISO-latin-1 range.</item>
</list>
@@ -250,7 +252,7 @@
ever be decoded.</p>
<p>If any parameters are of the wrong type, the list structure
- is invalid (a number as tail) or the binaries does not contain
+ is invalid (a number as tail) or the binaries do not contain
whole bytes (bit-strings), a <c>badarg</c> exception is
thrown.</p>
@@ -258,28 +260,27 @@
</func>
<func>
<name name="characters_to_binary" arity="1"/>
- <fsummary>Convert a collection of characters to an UTF-8 binary</fsummary>
+ <fsummary>Convert a collection of characters to a UTF-8 binary</fsummary>
<desc>
- <p>Same as characters_to_binary(Data, unicode, unicode).</p>
+ <p>Same as <c>characters_to_binary(<anno>Data</anno>, unicode, unicode)</c>.</p>
</desc>
</func>
<func>
<name name="characters_to_binary" arity="2"/>
- <fsummary>Convert a collection of characters to an UTF-8 binary</fsummary>
+ <fsummary>Convert a collection of characters to a UTF-8 binary</fsummary>
<desc>
- <p>Same as characters_to_binary(<anno>Data</anno>, <anno>InEncoding</anno>, unicode).</p>
+ <p>Same as <c>characters_to_binary(<anno>Data</anno>, <anno>InEncoding</anno>, unicode)</c>.</p>
</desc>
</func>
<func>
<name name="characters_to_binary" arity="3"/>
- <fsummary>Convert a collection of characters to an UTF-8 binary</fsummary>
+ <fsummary>Convert a collection of characters to a UTF-8 binary</fsummary>
<desc>
- <p>This function behaves as <seealso
- marker="#characters_to_list/2">
- characters_to_list/2</seealso>, but produces an binary
- instead of a unicode list. The
+ <p>Behaves as <seealso marker="#characters_to_list/2">
+ <c>characters_to_list/2</c></seealso>, but produces an binary
+ instead of a Unicode list. The
<c><anno>InEncoding</anno></c> defines how input is to be interpreted if
binaries are present in the <c>Data</c>, while
<c><anno>OutEncoding</anno></c> defines in what format output is to be
@@ -294,7 +295,7 @@
<p>Errors and exceptions occur as in <seealso
marker="#characters_to_list/2">
- characters_to_list/2</seealso>, but the second element
+ <c>characters_to_list/2</c></seealso>, but the second element
in the <c>error</c> or
<c>incomplete</c> tuple will be a <c>binary()</c> and not a
<c>list()</c>.</p>
@@ -304,16 +305,18 @@
<func>
<name name="encoding_to_bom" arity="1"/>
<fsummary>Create a binary UTF byte order mark from encoding.</fsummary>
- <type_desc variable="Bin">A binary() of byte_size 4 or more.</type_desc>
+ <type_desc variable="Bin">
+ A <c>binary()</c> such that <c>byte_size(<anno>Bin</anno>) >= 4</c>.
+ </type_desc>
<desc>
- <p>Create an UTF byte order mark (BOM) as a binary from the
+ <p>Create a UTF byte order mark (BOM) as a binary from the
supplied <c><anno>InEncoding</anno></c>. The BOM is, if supported at all,
expected to be placed first in UTF encoded files or
messages.</p>
<p>The function returns <c>&lt;&lt;&gt;&gt;</c> for the
- <c>latin1</c> encoding, there is no BOM for ISO-latin-1.</p>
+ <c>latin1</c> encoding as there is no BOM for ISO-latin-1.</p>
<p>It can be noted that the BOM for UTF-8 is seldom used, and it
is really not a <em>byte order</em> mark. There are obviously no
diff --git a/lib/stdlib/doc/src/unicode_usage.xml b/lib/stdlib/doc/src/unicode_usage.xml
index bbcd49a934..320b5b2e84 100644
--- a/lib/stdlib/doc/src/unicode_usage.xml
+++ b/lib/stdlib/doc/src/unicode_usage.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf8" ?>
<!DOCTYPE chapter SYSTEM "chapter.dtd">
<chapter>
@@ -33,14 +33,14 @@
<file>unicode_usage.xml</file>
</header>
<p>Implementing support for Unicode character sets is an ongoing process. The Erlang Enhancement Proposal (EEP) 10 outlines the basics of Unicode support and also specifies a default encoding in binaries that all Unicode-aware modules should handle in the future.</p>
-<p>The functionality described in EEP10 is implemented in Erlang/OTP as of R13A, but that's by no means the end of it. More functionality will be needed in the future and more OTP-libraries might need updating to cope with Unicode data. One example of future development is obvious when reading this manual, our documentation format is limited to the ISO-latin-1 character range, why no Unicode characters beyond that range will occur in this document.</p>
+<p>The functionality described in EEP10 is implemented in Erlang/OTP as of R13A, but that is by no means the end of it. More functionality will be needed in the future and more OTP-libraries might need updating to cope with Unicode data.</p>
<p>This guide outlines the current Unicode support and gives a couple of recipes for working with Unicode data.</p>
<section>
-<title>What Unicode is</title>
+<title>What Unicode Is</title>
<p>Unicode is a standard defining codepoints (numbers) for all known, living or dead, scripts. In principle, every known symbol used in any language has a Unicode codepoint.</p>
<p>Unicode codepoints are defined and published by the <em>Unicode Consortium</em>, which is a non profit organization.</p>
<p>Support for Unicode is increasing throughout the world of computing, as the benefits of one common character set are overwhelming when programs are used in a global environment.</p>
-<p>Along with the base of the standard, the codepoints for all the scripts, there are a couple of encoding standards available. Different operating systems and tools support different encodings. For example Linux and MacOS X has chosen the UTF-8 encoding, which is backwards compatible with 7-bit ASCII and therefore affects programs written in plain English the least. Windows&reg; on the other hand supports a limited version of UTF-16, namely all the code planes where the characters can be stored in one single 16-bit entity, which includes most living languages.</p>
+<p>Along with the base of the standard, the codepoints for all the scripts, there are a couple of encoding standards available. Different operating systems and tools support different encodings. For example Linux and MacOSX has chosen the UTF-8 encoding, which is backwards compatible with 7-bit ASCII and therefore affects programs written in plain English the least. Windows&reg; on the other hand supports a limited version of UTF-16, namely all the code planes where the characters can be stored in one single 16-bit entity, which includes most living languages.</p>
<p>The most widely spread encodings are:</p>
<taglist>
<tag>UTF-8</tag>
@@ -56,38 +56,47 @@
<p>Additionally, the codepoint 16#FEFF is used for byte order marks (BOM's) and use of that character is not encouraged in other contexts than that. It actually is valid though, as the character "ZWNBS" (Zero Width Non Breaking Space). BOM's are used to identify encodings and byte order for programs where such parameters are not known in advance. Byte order marks are more seldom used than one could expect, but their use is becoming more widely spread as they provide the means for programs to make educated guesses about the Unicode format of a certain file.</p>
</section>
<section>
-<title>Standard Unicode representation in Erlang</title>
+<title>Standard Unicode Representation in Erlang</title>
<p>In Erlang, strings are actually lists of integers. A string is defined to be encoded in the ISO-latin-1 (ISO8859-1) character set, which is, codepoint by codepoint, a sub-range of the Unicode character set.</p>
<p>The standard list encoding for strings is therefore easily extendible to cope with the whole Unicode range: A Unicode string in Erlang is simply a list containing integers, each integer being a valid Unicode codepoint and representing one character in the Unicode character set.</p>
-<p>Regular Erlang strings in ISO-latin-1 are a subset of their Unicode strings.</p>
+<p>Regular Erlang strings in ISO-latin-1 are a subset of their Unicode
+strings.</p>
-<p>Binaries on the other hand are more troublesome. For performance reasons, programs often store textual data in binaries instead of lists, mainly because they are more compact (one byte per character instead of two words per character, as is the case with lists). Using erlang:list_to_binary/1, an regular Erlang string can be converted into a binary, effectively using the ISO-latin-1 encoding in the binary - one byte per character. This is very convenient for those regular Erlang strings, but cannot be done for Unicode lists.</p>
+<p>Binaries on the other hand are more troublesome. For performance reasons, programs often store textual data in binaries instead of lists, mainly because they are more compact (one byte per character instead of two words per character, as is the case with lists). Using <c>erlang:list_to_binary/1</c>, a regular Erlang string can be converted into a binary, effectively using the ISO-latin-1 encoding in the binary - one byte per character. This is very convenient for those regular Erlang strings, but cannot be done for Unicode lists.</p>
<p>As the UTF-8 encoding is widely spread and provides the most compact storage, it is selected as the standard encoding of Unicode characters in binaries for Erlang.</p>
<p>The standard binary encoding is used whenever a library function in Erlang should cope with Unicode data in binaries, but is of course not enforced when communicating externally. Functions and bit-syntax exist to encode and decode both UTF-8, UTF-16 and UTF-32 in binaries. Library functions dealing with binaries and Unicode in general, however, only deal with the default encoding.</p>
-<p>Character data may be combined from several sources, sometimes available in a mix of strings and binaries. Erlang has for long had the concept of iodata or iolists, where binaries and lists can be combined to represent a sequence of bytes. In the same way, the Unicode aware modules often allow for combinations of binaries and lists where the binaries have characters encoded in UTF-8 and the lists contain such binaries or numbers representing Unicode codepoints:</p>
+<p>Character data may be combined from several sources, sometimes available in a mix of strings and binaries. Erlang has for long had the concept of <c>iodata</c> or <c>iolists</c>, where binaries and lists can be combined to represent a sequence of bytes. In the same way, the Unicode aware modules often allow for combinations of binaries and lists where the binaries have characters encoded in UTF-8 and the lists contain such binaries or numbers representing Unicode codepoints:</p>
<code type="none">
unicode_binary() = binary() with characters encoded in UTF-8 coding standard
-unicode_char() = integer() representing valid unicode codepoint
+unicode_char() = integer() >= 0 representing valid Unicode codepoint
chardata() = charlist() | unicode_binary()
charlist() = [unicode_char() | unicode_binary() | charlist()]
a unicode_binary is allowed as the tail of the list</code>
-<p>The module <c>unicode</c> in stdlib even supports similar mixes with binaries containing other encodings than UTF-8, but that is a special case to allow for conversions to and from external data:</p>
+<p>The module <c>unicode</c> in STDLIB even supports similar mixes with binaries containing other encodings than UTF-8, but that is a special case to allow for conversions to and from external data:</p>
<code type="none">
-external_unicode_binary() = binary() with characters coded in a user specified Unicode
- encoding other than UTF-8 (UTF-16 or UTF-32)
+external_unicode_binary() = binary() with characters coded in
+ a user specified Unicode encoding other than UTF-8 (UTF-16 or UTF-32)
external_chardata() = external_charlist() | external_unicode_binary()
-external_charlist() = [unicode_char() | external_unicode_binary() | external_charlist()]
- an external_unicode_binary is allowed as the tail of the list</code>
+external_charlist() = [unicode_char() |
+ external_unicode_binary() |
+ external_charlist()]
+ an external_unicode_binary() is allowed as the tail of the list</code>
</section>
<section>
-<title>Basic language support for Unicode</title>
-<p>First of all, Erlang is still defined to be written in the ISO-latin-1 character set. Functions have to be named in that character set, atoms are restricted to ISO-latin-1 and regular strings are still lists of characters 0..255 in the ISO-latin-1 encoding. This has not (yet) changed, but the language has been slightly extended to cope with Unicode characters and encodings.</p>
-
+<title>Basic Language Support for Unicode</title>
+<p><marker id="unicode_in_erlang"/>As of Erlang/OTP R16 Erlang can be
+written in ISO-latin-1 or Unicode (UTF-8). The details on how to state
+the encoding of an Erlang source file can be found in <seealso
+marker="stdlib:epp#encoding">epp(3)</seealso>. Strings and comments
+can be written using Unicode, but functions still have to be named in
+ISO-latin-1 and atoms are restricted to ISO-latin-1. Erlang/OTP R18 is
+expected to handle functions named in Unicode as well as Unicode
+atoms.</p>
<section>
<title>Bit-syntax</title>
<p>The bit-syntax contains types for coping with binary data in the three main encodings. The types are named <c>utf8</c>, <c>utf16</c> and <c>utf32</c> respectively. The <c>utf16</c> and <c>utf32</c> types can be in a big- or little-endian variant:</p>
@@ -101,74 +110,79 @@ Bin3 = &lt;&lt;$H/utf32-little, $e/utf32-little, $l/utf32-little, $l/utf32-littl
Bin4 = &lt;&lt;"Hello"/utf16&gt;&gt;,</code>
</section>
<section>
-<title>String- and character-literals</title>
-<warning>
-<p>The literal syntax described here may be subject to change in R13B, it has not yet passed the usual process for language changes approval.</p>
-</warning>
-<p>It is convenient to be able to write a list of Unicode characters in the string syntax. However, the language specifies strings as being in the ISO-latin-1 character set which the compiler tool chain as well as many other tools expect.</p>
-<p>Also the source code is (for now) still expected to be written using the ISO-latin-1 character set, why Unicode characters beyond that range cannot be entered in string literals.</p>
-<p>To make it easier to enter Unicode characters in the shell, it allows strings with Unicode characters on input, immediately converting them to regular lists of integers. They will, by the evaluator etc be viewed as if they were input using the regular list syntax, which is - in the end - how the language actually treats them. They will in the same way not be output as strings by i.e <c>io:write/2</c> or <c>io:format/3</c> unless the format string supplied to <c>io:format</c> uses the Unicode translation modifier (which we will talk about later).</p>
-<p>For source code, there is an extension to the \OOO (backslash followed by three octal numbers) and \xHH (backslash followed by 'x', followed by two hexadecimal characters) syntax, namely \x{H ...} (a backslash followed by an 'x', followed by left curly bracket, any number of hexadecimal digits and a terminating right curly bracket). This allows for entering characters of any codepoint literally in a string. The string is immediately converted into a list by the scanner however, which is obvious when calling it directly:</p>
-<pre>
-1> <input>erl_scan:string("\"X\".").</input>
-{ok,[{string,1,"X"},{dot,1}],1}
-2> <input>erl_scan:string("\"\x{400}\".").</input>
-{ok,[{'[',1},{integer,1,1024},{']',1},{dot,1}],1}</pre>
-<p>Character literals, or rather integers representing Unicode codepoints can be expressed in a similar way using $\x{H ...}:</p>
-<pre>
-4> <input>$\x{400}.</input>
-1024</pre>
-<p>This also is a translation by the scanner:</p>
-<pre>
-5> <input>erl_scan:string("$Y.").</input>
-{ok,[{char,1,89},{dot,1}],1}
-6> <input>erl_scan:string("$\x{400}.").</input>
-{ok,[{integer,1,1024},{dot,1}],1}</pre>
-<p>In the shell, if using a Unicode input device, '$' can be followed directly by a Unicode character producing an integer. In the following example, let's imagine the character 'c' is actually a Cyrillic 's' (looking fairly similar):</p>
+<title>String- and Character-literals</title>
+<p>For source code, there is an extension to the <c>\</c>OOO (backslash
+followed by three octal numbers) and <c>\x</c>HH (backslash followed by <c>x</c>,
+followed by two hexadecimal characters) syntax, namely <c>\x{</c>H ...<c>}</c> (a
+backslash followed by an <c>x</c>, followed by left curly bracket, any
+number of hexadecimal digits and a terminating right curly bracket).
+This allows for entering characters of any codepoint literally in a
+string even when the encoding is ISO-latin-1.</p>
+</section>
+<p>In the shell, if using a Unicode input device, <c>$</c> can be followed directly by a Unicode character producing an integer. In the following example the codepoint of a Cyrillic <c>s</c> is output:</p>
<pre>
-7> <input>$c.</input>
+7> <input>$с.</input>
1089</pre>
</section>
-<p>The literal syntax allowing Unicode characters is to be viewed as "syntactic sugar", but is, as such, fairly useful.</p>
-</section>
<section>
-<title>The interactive shell</title>
+<title>The Interactive Shell</title>
<p>The interactive Erlang shell, when started towards a terminal or started using the <c>werl</c> command on windows, can support Unicode input and output.</p>
-<p>On Windows&reg;, proper operation requires that a suitable font is installed and selected for the Erlang application to use. If no suitable font is available on your system, try installing the DejaVu fonts (dejavu-fonts.org), which are freely available and then select that font in the Erlang shell application.</p>
-<p>On Unix&reg;-like operating systems, the terminal should be able to handle UTF-8 on input and output (modern versions of XTerm, KDE konsole and the Gnome terminal do for example) and your locale settings have to be proper. As an example, my LANG environment variable is set as this:</p>
+<p>On Windows&reg;, proper operation requires that a suitable font is installed and selected for the Erlang application to use. If no suitable font is available on your system, try installing the DejaVu fonts (<c>dejavu-fonts.org</c>), which are freely available and then select that font in the Erlang shell application.</p>
+<p>On Unix&reg;-like operating systems, the terminal should be able to handle UTF-8 on input and output (modern versions of XTerm, KDE konsole and the Gnome terminal do for example) and your locale settings have to be proper. As an example, my <c>LANG</c> environment variable is set as this:</p>
<pre>
$ <input>echo $LANG</input>
en_US.UTF-8</pre>
-<p>Actually, most systems handle the LC_CTYPE variable before LANG, so if that is set, it has to be set to UTF-8:</p>
+<p>Actually, most systems handle the <c>LC_CTYPE</c> variable before <c>LANG</c>, so if that is set, it has to be set to <c>UTF-8</c>:</p>
<pre>
$ echo <input>$LC_CTYPE</input>
en_US.UTF-8</pre>
-<p>The LANG or LC_CTYPE setting should be consistent with what the terminal is capable of, there is no portable way for Erlang to ask the actual terminal about its UTF-8 capacity, we have to rely on the language and character type settings.</p>
+<p>The <c>LANG</c> or <c>LC_CTYPE</c> setting should be consistent with what the terminal is capable of, there is no portable way for Erlang to ask the actual terminal about its UTF-8 capacity, we have to rely on the language and character type settings.</p>
<p>To investigate what Erlang thinks about the terminal, the <c>io:getopts()</c> call can be used when the shell is started:</p>
<pre>
$ <input>LC_CTYPE=en_US.ISO-8859-1 erl</input>
-Erlang R13A (erts-5.7) [source] [64-bit] [smp:4:4] [rq:4] [async-threads:0] [kernel-poll:false]
+Erlang R16B (erts-5.10) [source] [async-threads:0] [hipe] [kernel-poll:false]
-Eshell V5.7 (abort with ^G)
-1> <input>lists:keyfind(encoding,1,io:getopts()).</input>
+Eshell V5.10 (abort with ^G)
+1> <input>lists:keyfind(encoding, 1, io:getopts()).</input>
{encoding,latin1}
2> <input>q().</input>
ok
$ <input>LC_CTYPE=en_US.UTF-8 erl</input>
-Erlang R13A (erts-5.7) [source] [64-bit] [smp:4:4] [rq:4] [async-threads:0] [kernel-poll:false]
+Erlang R16B (erts-5.10) [source] [async-threads:0] [hipe] [kernel-poll:false]
-Eshell V5.7 (abort with ^G)
-1> <input>lists:keyfind(encoding,1,io:getopts()).</input>
+Eshell V5.10 (abort with ^G)
+1> <input>lists:keyfind(encoding, 1, io:getopts()).</input>
{encoding,unicode}
2></pre>
<p>When (finally?) everything is in order with the locale settings, fonts and the terminal emulator, you probably also have discovered a way to input characters in the script you desire. For testing, the simplest way is to add some keyboard mappings for other languages, usually done with some applet in your desktop environment. In my KDE environment, I start the KDE Control Center (Personal Settings), select "Regional and Accessibility" and then "Keyboard Layout". On Windows XP&reg;, I start Control Panel->Regional and Language Options, select the Language tab and click the Details... button in the square named "Text services and input Languages". Your environment probably provides similar means of changing the keyboard layout. Make sure you have a way to easily switch back and forth between keyboards if you are not used to this, entering commands using a Cyrillic character set is, as an example, not easily done in the Erlang shell.</p>
<p>Now you are set up for some Unicode input and output. The simplest thing to do is of course to enter a string in the shell:</p>
-<image file="ushell1.gif"><icaption>Cyrillic characters in an Erlang shell</icaption></image>
+<pre>
+$ <input>erl</input>
+Erlang R16B (erts-5.10) [source] [async-threads:0] [hipe] [kernel-poll:false]
+
+Eshell V5.10 (abort with ^G)
+1> <input>lists:keyfind(encoding, 1, io:getopts()).</input>
+{encoding,unicode}
+2> <input>"уницоде"</input>
+"уницоде"
+3> <input>io:format("~ts~n", [v(2)]).</input>
+уницоде
+ok
+4> </pre>
<p>While strings can be input as Unicode characters, the language elements are still limited to the ISO-latin-1 character set. Only character constants and strings are allowed to be beyond that range:</p>
-<image file="ushell2.gif"><icaption>Unicode characters in allowed and disallowed context</icaption></image>
+<pre>
+$ <input>erl</input>
+Erlang R16B (erts-5.10) [source] [async-threads:0] [hipe] [kernel-poll:false]
+
+Eshell V5.10 (abort with ^G)
+1> <input>$ξ</input>
+958
+2> <input>уницоде.</input>
+* 1: illegal character
+2> </pre>
</section>
<section>
-<title>Unicode file names</title>
+<title>Unicode File Names</title>
<p>Most modern operating systems support Unicode file names in some way or another. There are several different ways to do this and Erlang by default treats the different approaches differently:</p>
<taglist>
<tag>Mandatory Unicode file naming</tag>
@@ -183,7 +197,7 @@ Eshell V5.7 (abort with ^G)
<p>A raw file name is not a list, but a binary. Many non core applications still do not handle file names given as binaries, why such raw names are avoided by default. This means that systems having implemented Unicode file naming through transparent file systems and an UTF-8 convention, do not by default have Unicode file naming turned on. Explicitly turning Unicode file name handling on for these types of systems is considered experimental.</p>
</item>
</taglist>
-<p>The Unicode file naming support was introduced with OTP release R14B01. A VM operating in Unicode file mode can work with files having names in any language or character set (as long as it's supported by the underlying OS and file system). The Unicode character list is used to denote file or directory names and if the file system content is listed, you will also be able to get Unicode lists as return value. The support lies in the kernel and stdlib modules, why most applications (that does not explicitly require the file names to be in the ISO-latin-1 range) will benefit from the Unicode support without change.</p>
+<p>The Unicode file naming support was introduced with OTP release R14B01. A VM operating in Unicode file mode can work with files having names in any language or character set (as long as it is supported by the underlying OS and file system). The Unicode character list is used to denote file or directory names and if the file system content is listed, you will also be able to get Unicode lists as return value. The support lies in the Kernel and STDLIB modules, why most applications (that does not explicitly require the file names to be in the ISO-latin-1 range) will benefit from the Unicode support without change.</p>
<p>On Operating systems with mandatory Unicode file names, this means that you more easily conform to the file names of other (non Erlang) applications, and you can also process file names that, at least on Windows, were completely inaccessible (due to having names that could not be represented in ISO-latin-1). Also you will avoid creating incomprehensible file names on MacOSX as the vfs layer of the OS will accept all your file names as UTF-8 and will not rewrite them.</p>
@@ -193,31 +207,32 @@ Eshell V5.7 (abort with ^G)
<p>It is worth noting that the file <c>encoding</c> options given when opening a file has nothing to do with the file <em>name</em> encoding convention. You can very well open files containing UTF-8 but having file names in ISO-latin-1 or vice versa.</p>
-<note>Erlang drivers and NIF shared objects still can not be named with names containing codepoints beyond 127. This is a known limitation to be removed in a future release. Erlang modules however can, but it is definitely not a good idea and is still considered experimental.</note>
+<note><p>Erlang drivers and NIF shared objects still can not be named with names containing codepoints beyond 127. This is a known limitation to be removed in a future release. Erlang modules however can, but it is definitely not a good idea and is still considered experimental.</p></note>
<section>
-<title>Notes about raw file names and automatic file name conversion</title>
-<p>Raw file names is introduced together with Unicode file name support in erts-5.8.2 (OTP R14B01). The reason &quot;raw file names&quot; is introduced in the system is to be able to consistently represent file names given in different encodings on the same system. Having the VM automatically translate a file name that is not in UTF-8 to a list of Unicode characters might seem practical, but this would open up for both duplicate file names and other inconsistent behavior. Consider a directory containing a file named &quot;bj�rn&quot; in ISO-latin-1, while the Erlang VM is operating in Unicode file name mode (and therefore expecting UTF-8 file naming). The ISO-latin-1 name is not valid UTF-8 and one could be tempted to think that automatic conversion in for example <c>file:list_dir/1</c> is a good idea. But what would happen if we later tried to open the file and have the name as a Unicode list (magically converted from the ISO-latin-1 file name)? The VM will convert the file name given to UTF-8, as this is the encoding expected. Effectively this means trying to open the file named &lt;&lt;&quot;bj�rn&quot;/utf8&gt;&gt;. This file does not exist, and even if it existed it would not be the same file as the one that was listed. We could even create two files named &quot;bj�rn&quot;, one named in the UTF-8 encoding and one not. If <c>file:list_dir/1</c> would automatically convert the ISO-latin-1 file name to a list, we would get two identical file names as the result. To avoid this, we need to differentiate between file names being properly encoded according to the Unicode file naming convention (i.e. UTF-8) and file names being invalid under the encoding. This is done by representing invalid encoding as &quot;raw&quot; file names, i.e. as binaries.</p>
-<p>The core system of Erlang (kernel and stdlib) accepts raw file names except for loadable drivers and executables invoked using <c>open_port({spawn, ...} ...)</c>. <c>open_port({spawn_executable, ...} ...)</c> however does accept them. As mentioned earlier, the arguments given in the option list to <c>open_port({spawn_executable, ...} ...)</c> undergo the same conversion as the file names, meaning that the executable will be provided with arguments in UTF-8 as well. This translation is avoided consistently with how the file names are treated, by giving the argument as a binary.</p>
+<title>Notes About Raw File Names and Automatic File Name Conversion</title>
+
+<p>Raw file names is introduced together with Unicode file name support in erts-5.8.2 (OTP R14B01). The reason &quot;raw file names&quot; is introduced in the system is to be able to consistently represent file names given in different encodings on the same system. Having the VM automatically translate a file name that is not in UTF-8 to a list of Unicode characters might seem practical, but this would open up for both duplicate file names and other inconsistent behavior. Consider a directory containing a file named &quot;björn&quot; in ISO-latin-1, while the Erlang VM is operating in Unicode file name mode (and therefore expecting UTF-8 file naming). The ISO-latin-1 name is not valid UTF-8 and one could be tempted to think that automatic conversion in for example <c>file:list_dir/1</c> is a good idea. But what would happen if we later tried to open the file and have the name as a Unicode list (magically converted from the ISO-latin-1 file name)? The VM will convert the file name given to UTF-8, as this is the encoding expected. Effectively this means trying to open the file named &lt;&lt;&quot;björn&quot;/utf8&gt;&gt;. This file does not exist, and even if it existed it would not be the same file as the one that was listed. We could even create two files named &quot;björn&quot;, one named in the UTF-8 encoding and one not. If <c>file:list_dir/1</c> would automatically convert the ISO-latin-1 file name to a list, we would get two identical file names as the result. To avoid this, we need to differentiate between file names being properly encoded according to the Unicode file naming convention (i.e. UTF-8) and file names being invalid under the encoding. This is done by representing invalid encoding as &quot;raw&quot; file names, i.e. as binaries.</p>
+<p>The core system of Erlang (Kernel and STDLIB) accepts raw file names except for loadable drivers and executables invoked using <c>open_port({spawn, ...} ...)</c>. <c>open_port({spawn_executable, ...} ...)</c> however does accept them. As mentioned earlier, the arguments given in the option list to <c>open_port({spawn_executable, ...} ...)</c> undergo the same conversion as the file names, meaning that the executable will be provided with arguments in UTF-8 as well. This translation is avoided consistently with how the file names are treated, by giving the argument as a binary.</p>
<p>To force Unicode file name translation mode on systems where this is not the default is considered experimental in OTP R14B01 due to the raw file names possibly being a new experience to the programmer and that the non core applications of OTP are not tested for compliance with raw file names yet. Unicode file name translation is expected to be default in future releases.</p>
-<p>If working with raw file names, one can still conform to the encoding convention of the Erlang VM by using the <c>file:native_name_encoding/0</c> function, which returns either the atom <c>latin1</c> or the atom <c>utf8</c> depending on the file name translation mode. On Linux, a VM started without explicitly stating the file name translation mode will default to <c>latin1</c> as the native file name encoding, why file names on the disk encoded as UTF-8 will be returned as a list of the names interpreted as ISO-latin-1. The &quot;UTF-8 list&quot; is not a practical type for displaying or operating on in Erlang, but it is backward compatible and usable in all functions requiring a file name. On Windows and MacOSX, the default behavior is that of file name translation, why the <c>file:native_name_encoding/0</c> by default returns <c>utf8</c> on those systems (the fact that Windows actually does not use UTF-8 on the file system level can safely be ignored by the Erlang programmer). The default behavior can be changed using the <c>+fnu</c> or <c>+fnl</c> options to the VM, see the <c>erl</c> command manual page.</p>
+<p>If working with raw file names, one can still conform to the encoding convention of the Erlang VM by using the <c>file:native_name_encoding/0</c> function, which returns either the atom <c>latin1</c> or the atom <c>utf8</c> depending on the file name translation mode. On Linux, a VM started without explicitly stating the file name translation mode will default to <c>latin1</c> as the native file name encoding, why file names on the disk encoded as UTF-8 will be returned as a list of the names interpreted as ISO-latin-1. The &quot;UTF-8 list&quot; is not a practical type for displaying or operating on in Erlang, but it is backward compatible and usable in all functions requiring a file name. On Windows and MacOSX, the default behavior is that of file name translation, why the <c>file:native_name_encoding/0</c> by default returns <c>utf8</c> on those systems (the fact that Windows actually does not use UTF-8 on the file system level can safely be ignored by the Erlang programmer). The default behavior can be changed using the <c>+fnu</c> or <c>+fnl</c> options to the VM, see the <seealso marker="erts:erl"><c>erl(1)</c></seealso> command manual page.</p>
<p>Even if you are operating without Unicode file naming translation automatically done by the VM, you can access and create files with names in UTF-8 encoding by using raw file names encoded as UTF-8. Enforcing the UTF-8 encoding regardless of the mode the Erlang VM is started in might, in some circumstances be a good idea, as the convention of using UTF-8 file names is spreading.</p>
</section>
<section>
-<title>Notes about MacOSX</title>
+<title>Notes About MacOSX</title>
<p>MacOSXs vfs layer enforces UTF-8 file names in a quite aggressive way. Older versions did this by simply refusing to create non UTF-8 conforming file names, while newer versions replace offending bytes with the sequence &quot;%HH&quot;, where HH is the original character in hexadecimal notation. As Unicode translation is enabled by default on MacOSX, the only way to come up against this is to either start the VM with the <c>+fnl</c> flag or to use a raw file name in <c>latin1</c> encoding. In that case, the file can not be opened with the same name as the one used to create this. The problem is by design in newer versions of MacOSX.</p>
-<p>MacOSX also reorganizes the names of files so that the representation of accents etc is denormalized, i.e. the character <c>�</c> is represented as the codepoints [111,776], where 111 is the character <c>o</c> and 776 is a special accent character. This type of denormalized Unicode is otherwise very seldom used and Erlang normalizes those file names on retrieval, so that denormalized file names is not passed up to the Erlang application. In Erlang the file name &quot;bj�rn&quot; is retrieved as [98,106,246,114,110], not as [98,106,117,776,114,110], even though the file system might think differently.</p>
+<p>MacOSX also reorganizes the names of files so that the representation of accents etc is denormalized, i.e. the character <c>ö</c> is represented as the codepoints [111,776], where 111 is the character <c>o</c> and 776 is a special accent character. This type of denormalized Unicode is otherwise very seldom used and Erlang normalizes those file names on retrieval, so that denormalized file names is not passed up to the Erlang application. In Erlang the file name &quot;björn&quot; is retrieved as [98,106,246,114,110], not as [98,106,117,776,114,110], even though the file system might think differently.</p>
</section>
</section>
<section>
-<title>Unicode in environment variables and parameters</title>
+<title>Unicode in Environment Variables and Parameters</title>
<p>Environment variables and their interpretation is handled much in the same way as file names. If Unicode file names are enabled, environment variables as well as parameters to the Erlang VM are expected to be in Unicode.</p>
<p>If Unicode file names are enabled, the calls to <seealso marker="kernel:os#getenv/0"><c>os:getenv/0</c></seealso>, <seealso marker="kernel:os#getenv/1"><c>os:getenv/1</c></seealso> and <seealso marker="kernel:os#putenv/2"><c>os:putenv/2</c></seealso> will handle Unicode strings. On Unix-like platforms, the built-in functions will translate environment variables in UTF-8 to/from Unicode strings, possibly with codepoints > 255. On Windows the Unicode versions of the environment system API will be used, also allowing for codepoints > 255.</p>
<p>On Unix-like operating systems, parameters are expected to be UTF-8 without translation if Unicode file names are enabled.</p>
</section>
<section>
-<title>Unicode-aware modules</title>
-<p>Most of the modules in Erlang/OTP are of course Unicode-unaware in the sense that they have no notion of Unicode and really shouldn't have. Typically they handle non-textual or byte-oriented data (like <c>gen_tcp</c> etc).</p>
+<title>Unicode-aware Modules</title>
+<p>Most of the modules in Erlang/OTP are of course Unicode-unaware in the sense that they have no notion of Unicode and really should not have. Typically they handle non-textual or byte-oriented data (like <c>gen_tcp</c> etc).</p>
<p>Modules that actually handle textual data (like <c>io_lib</c>, <c>string</c> etc) are sometimes subject to conversion or extension to be able to handle Unicode characters.</p>
<p>Fortunately, most textual data has been stored in lists and range checking has been sparse, why modules like <c>string</c> works well for Unicode lists with little need for conversion or extension.</p>
<p>Some modules are however changed to be explicitly Unicode-aware. These modules include:</p>
@@ -230,7 +245,7 @@ Eshell V5.7 (abort with ^G)
<item>
<p>The <seealso marker="stdlib:io">io</seealso> module has been extended along with the actual I/O-protocol to handle Unicode data. This means that several functions require binaries to be in UTF-8 and there are modifiers to formatting control sequences to allow for outputting of Unicode strings.</p>
</item>
-<tag><c>file</c>, <c>group</c> and <c>user</c></tag>
+<tag><c>file</c>, <c>group</c>, <c>user</c></tag>
<item>
<p>I/O-servers throughout the system are able both to handle Unicode data and has options for converting data upon actual output or input to/from the device. As shown earlier, the <seealso marker="stdlib:shell">shell</seealso> has support for Unicode terminals and the <seealso marker="kernel:file">file</seealso> module allows for translation to and from various Unicode formats on disk.</p>
<p>The actual reading and writing of files with Unicode data is however not best done with the <c>file</c> module as its interface is byte oriented. A file opened with a Unicode encoding (like UTF-8), is then best read or written using the <seealso marker="stdlib:io">io</seealso> module.</p>
@@ -247,10 +262,10 @@ Eshell V5.7 (abort with ^G)
<p>The module <seealso marker="stdlib:string">string</seealso> works perfect for Unicode strings as well as for ISO-latin-1 strings with the exception of the language-dependent <seealso marker="stdlib:string#to_upper/1">to_upper</seealso> and <seealso marker="stdlib:string#to_lower/1">to_lower</seealso> functions, which are only correct for the ISO-latin-1 character set. Actually they can never function correctly for Unicode characters in their current form, there are language and locale issues as well as multi-character mappings to consider when conversion text between cases. Converting case in an international environment is a big subject not yet addressed in OTP.</p>
</section>
<section>
-<title>Unicode recipes</title>
+<title>Unicode Recipes</title>
<p>When starting with Unicode, one often stumbles over some common issues. I try to outline some methods of dealing with Unicode data in this section.</p>
<section>
-<title>Byte order marks</title>
+<title>Byte Order Marks</title>
<p>A common method of identifying encoding in text-files is to put a byte order mark (BOM) first in the file. The BOM is the codepoint 16#FEFF encoded in the same way as the rest of the file. If such a file is to be read, the first few bytes (depending on encoding) is not part of the actual text. This code outlines how to open a file which is believed to have a BOM and set the files encoding and position for further sequential reading (preferably using the <seealso marker="stdlib:io">io</seealso> module). Note that error handling is omitted from the code:</p>
<code>
open_bom_file_for_reading(File) -&gt;
@@ -261,7 +276,7 @@ open_bom_file_for_reading(File) -&gt;
io:setopts(F,[{encoding,Type}]),
{ok,F}.
</code>
-<p>The <c>unicode:bom_to_encoding/1</c> function identifies the encoding from a binary of at least four bytes. It returns, along with an term suitable for setting the encoding of the file, the actual length of the BOM, so that the file position can be set accordingly. Note that <c>file:position</c> always works on byte-offsets, so that the actual byte-length of the BOM is needed.</p>
+<p>The <c>unicode:bom_to_encoding/1</c> function identifies the encoding from a binary of at least four bytes. It returns, along with an term suitable for setting the encoding of the file, the actual length of the BOM, so that the file position can be set accordingly. Note that <c>file:position/2</c> always works on byte-offsets, so that the actual byte-length of the BOM is needed.</p>
<p>To open a file for writing and putting the BOM first is even simpler:</p>
<code>
open_bom_file_for_writing(File,Encoding) -&gt;
@@ -273,24 +288,33 @@ open_bom_file_for_writing(File,Encoding) -&gt;
<p>In both cases the file is then best processed using the <c>io</c> module, as the functions in <c>io</c> can handle codepoints beyond the ISO-latin-1 range.</p>
</section>
<section>
-<title>Formatted input and output</title>
-<p>When reading and writing to Unicode-aware entities, like the User or a file opened for Unicode translation, you will probably want to format text strings using the functions in <seealso marker="stdlib:io">io</seealso> or <seealso marker="stdlib:io_lib">io_lib</seealso>. For backward compatibility reasons, these functions don't accept just any list as a string, but require e special "translation modifier" when working with Unicode texts. The modifier is "t". When applied to the "s" control character in a formatting string, it accepts all Unicode codepoints and expect binaries to be in UTF-8:</p>
+<title>Formatted Input and Output</title>
+<p>When reading and writing to Unicode-aware entities, like the User or a file opened for Unicode translation, you will probably want to format text strings using the functions in <seealso marker="stdlib:io">io</seealso> or <seealso marker="stdlib:io_lib">io_lib</seealso>. For backward compatibility reasons, these functions do not accept just any list as a string, but require a special <em>translation modifier</em> when working with Unicode texts. The modifier is <c>t</c>. When applied to the <c>s</c> control character in a formatting string, it accepts all Unicode codepoints and expect binaries to be in UTF-8:</p>
<pre>
-1> <input>io:format("~ts~n",[&lt;&lt;"���"/utf8&gt;&gt;]).</input>
-���
-ok
-2> <input>io:format("~s~n",[&lt;&lt;"���"/utf8&gt;&gt;]).</input>
+1> <input>io:format("~ts~n",[&lt;&lt;"åäö"/utf8&gt;&gt;]).</input>
åäö
+ok
+2> <input>io:format("~s~n",[&lt;&lt;"åäö"/utf8&gt;&gt;]).</input>
+åäö
+ok</pre>
+<p>Obviously the second <c>io:format/2</c> gives undesired output because the UTF-8 binary is not in latin1. Because ISO-latin-1 is still the defined character set of Erlang, the non prefixed <c>s</c> control character expects ISO-latin-1 in binaries as well as lists.</p>
+<p>As long as the data is always lists, the <c>t</c> modifier can be used for any string, but when binary data is involved, care must be taken to make the right choice of formatting characters.</p>
+<p>The function <c>format/2</c> in <c>io_lib</c> behaves similarly. This function is defined to return a deep list of characters and the output could easily be converted to binary data for outputting on a device of any kind by a simple <c>erlang:list_to_binary/1</c>. When the translation modifier is used, the list can however contain characters that cannot be stored in one byte. The call to <c>erlang:list_to_binary/1</c> will in that case fail. However, if the I/O server you want to communicate with is Unicode-aware, the list returned can still be used directly:</p>
+<pre>
+$ <input>erl</input>
+Erlang R16B (erts-5.10) [source] [async-threads:0] [hipe] [kernel-poll:false]
+
+Eshell V5.10 (abort with ^G)
+1> <input>io_lib:format("~ts~n", ["θνιψοδε"]).</input>
+["θνιψοδε","\n"]
+2> <input>io:put_chars(io_lib:format("~ts~n", ["θνιψοδε"])).</input>
+θνιψοδε
ok</pre>
-<p>Obviously the second <c>io:format</c> gives undesired output because the UTF-8 binary is not in latin1. Because ISO-latin-1 is still the defined character set of Erlang, the non prefixed "s" control character expects ISO-latin-1 in binaries as well as lists.</p>
-<p>As long as the data is always lists, the "t" modifier can be used for any string, but when binary data is involved, care must be taken to make the tight choice of formatting characters.</p>
-<p>The function <c>format</c> in <c>io_lib</c> behaves similarly. This function is defined to return a deep list of characters and the output could easily be converted to binary data for outputting on a device of any kind by a simple <c>erlang:list_to_binary</c>. When the translation modifier is used, the list can however contain characters that cannot be stored in one byte. The call to <c>erlang:list_to_binary</c> will in that case fail. However, if the io_server you want to communicate with is Unicode-aware, the list returned can still be used directly:</p>
-<image file="ushell3.gif"><icaption>io_lib:format with Unicode translation</icaption></image>
-<p>The Unicode string is returned as a Unicode list, why the return value of <c>io_lib:format</c> no longer qualifies as a regular Erlang string (the function <seealso marker="stdlib:io_lib#deep_char_list/1">io_lib:deep_char_list</seealso> will, as an example, return <c>false</c>). The Unicode list is however valid input to the <seealso marker="stdlib:io#put_chars/2">io:put_chars</seealso> function, so data can be output on any Unicode capable device anyway. If the device is a terminal, characters will be output in the \x{H ...} format if encoding is <c>latin1</c> otherwise in UTF-8 (for the non-interactive terminal - "oldshell" or "noshell") or whatever is suitable to show the character properly (for an interactive terminal - the regular shell). The bottom line is that you can always send Unicode data to the <c>standard_io</c> device. Files will however only accept Unicode codepoints beyond ISO-latin-1 if <c>encoding</c> is set to something else than <c>latin1</c>.</p>
+<p>The Unicode string is returned as a Unicode list, which is recognized as such since the Erlang shell uses the Unicode encoding. The Unicode list is valid input to the <seealso marker="stdlib:io#put_chars/2">io:put_chars/2</seealso> function, so data can be output on any Unicode capable device. If the device is a terminal, characters will be output in the <c>\x{</c>H ...<c>}</c> format if encoding is <c>latin1</c> otherwise in UTF-8 (for the non-interactive terminal - "oldshell" or "noshell") or whatever is suitable to show the character properly (for an interactive terminal - the regular shell). The bottom line is that you can always send Unicode data to the <c>standard_io</c> device. Files will however only accept Unicode codepoints beyond ISO-latin-1 if <c>encoding</c> is set to something else than <c>latin1</c>.</p>
</section>
<section>
-<title>Heuristic identification of UTF-8</title>
-<p>While it's strongly encouraged that the actual encoding of characters in binary data is known prior to processing, that is not always possible. On a typical Linux&reg; system, there is a mix of UTF-8 and ISO-latin-1 text files and there are seldom any BOM's in the files to identify them.</p>
+<title>Heuristic Identification of UTF-8</title>
+<p>While it iss strongly encouraged that the actual encoding of characters in binary data is known prior to processing, that is not always possible. On a typical Linux&reg; system, there is a mix of UTF-8 and ISO-latin-1 text files and there are seldom any BOM's in the files to identify them.</p>
<p>UTF-8 is designed in such a way that ISO-latin-1 characters with numbers beyond the 7-bit ASCII range are seldom considered valid when decoded as UTF-8. Therefore one can usually use heuristics to determine if a file is in UTF-8 or if it is encoded in ISO-latin-1 (one byte per character) encoding. The <c>unicode</c> module can be used to determine if data can be interpreted as UTF-8:</p>
<code>
heuristic_encoding_bin(Bin) when is_binary(Bin) -&gt;
diff --git a/lib/stdlib/doc/src/ushell1.gif b/lib/stdlib/doc/src/ushell1.gif
deleted file mode 100644
index 7c46464fd2..0000000000
--- a/lib/stdlib/doc/src/ushell1.gif
+++ /dev/null
Binary files differ
diff --git a/lib/stdlib/doc/src/ushell1.ps b/lib/stdlib/doc/src/ushell1.ps
deleted file mode 100644
index 95bfebf194..0000000000
--- a/lib/stdlib/doc/src/ushell1.ps
+++ /dev/null
@@ -1,1196 +0,0 @@
-%!PS-Adobe-3.0
-%%Creator: GIMP PostScript file plugin V 1.17 by Peter Kirchgessner
-%%Title: ushell1.ps
-%%CreationDate: Mon Mar 16 09:53:27 2009
-%%DocumentData: Clean7Bit
-%%LanguageLevel: 2
-%%Pages: 1
-%%BoundingBox: 14 14 468 142
-%%EndComments
-%%BeginProlog
-% Use own dictionary to avoid conflicts
-10 dict begin
-%%EndProlog
-%%Page: 1 1
-% Translate for offset
-14.173228346456694 14.173228346456694 translate
-% Translate to begin of first scanline
-0 127.55905511811024 translate
-453.54330708661422 -127.55905511811024 scale
-% Image geometry
-640 180 8
-% Transformation matrix
-[ 640 0 0 180 0 0 ]
-% Strings to hold RGB-samples per scanline
-/rstr 640 string def
-/gstr 640 string def
-/bstr 640 string def
-{currentfile /ASCII85Decode filter /RunLengthDecode filter rstr readstring pop}
-{currentfile /ASCII85Decode filter /RunLengthDecode filter gstr readstring pop}
-{currentfile /ASCII85Decode filter /RunLengthDecode filter bstr readstring pop}
-true 3
-%%BeginData: 67571 ASCII Bytes
-colorimage
-JP1PeJP1PeJP1L~>
-JP1PeJP1PeJP1L~>
-JP1PeJP1PeJP1L~>
-!!e'9JNA?CJNABDJ,~>
-!!e'9JNA?CJNABDJ,~>
-!!e'9JNA?CJNABDJ,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$2%<!Lr-2rr]6=Dt\b^JcC<$JcD\KJ,~>
-!$2%<!Lr-2rr]6=Dt\b^JcC<$JcD\KJ,~>
-!$2%<!Lr-2rr]6=Dt\b^JcC<$JcD\KJ,~>
-#9EjEY>Q6)=6BMbc`J;XJcC<$JcC<$W;hA~>
-#9EjEY>Q6)=6BMbc`J;XJcC<$JcC<$W;hA~>
-#9EjEY>Q6)=6BMbc`J;XJcC<$JcC<$W;hA~>
-#T`rUH-/@H`Dbmu!A3bks+13$s+13Ks*t~>
-#T`rUH-/@H`Dbmu!A3bks+13$s+13Ks*t~>
-#T`rUH-/@H`Dbmu!A3bks+13$s+13Ks*t~>
-#T`rEG5Y4]rp0@Z!W@cP*=4P!s-oDP9H?1krVlmMmt(Lis+13$s/>sJ~>
-#T`rEG5Y4]rp0@Z!W@cP*=4P!s-oDP9H?1krVlmMmt(Lis+13$s/>sJ~>
-#T`rEG5Y4]rp0@Z!W@cP*=4P!s-oDP9H?1krVlmMmt(Lis+13$s/>sJ~>
-#9EjER>jY@r:g3lQA5D=$0F2Hs)Ak%s4op<rrF_?JcC<$JcC<$W;hA~>
-#9EjER>jY@r:g3lQA5D=$0F2Hs)Ak%s4op<rrF_?JcC<$JcC<$W;hA~>
-#9EjER>jY@r:g3lQA5D=$0F2Hs)Ak%s4op<rrF_?JcC<$JcC<$W;hA~>
-!$2(="-F9Q\G-"(Q=^'2$*?/ds)G.?s5e.srrF_?JcC<$JcC<$W;hA~>
-!$2(="-F9Q\G-"(Q=^'2$*?/ds)G.?s5e.srrF_?JcC<$JcC<$W;hA~>
-!$2(="-F9Q\G-"(Q=^'2$*?/ds)G.?s5e.srrF_?JcC<$JcC<$W;hA~>
-!$2%<"&I0WZ2">"Q8&8B"FpIOENK!9!A3bks+13$s+13Ks*t~>
-!$2%<"&I0WZ2">"Q8&8B"FpIOENK!9!A3bks+13$s+13Ks*t~>
-!$2%<"&I0WZ2">"Q8&8B"FpIOENK!9!A3bks+13$s+13Ks*t~>
-#T`rq^Ah!RpEo\8!LAK:rrI,@q>UIImt(Lis+13$s/>sJ~>
-#T`rq^Ah!RpEo\8!LAK:rrI,@q>UIImt(Lis+13$s/>sJ~>
-#T`rq^Ah!RpEo\8!LAK:rrI,@q>UIImt(Lis+13$s/>sJ~>
-#T`s"JSH?.CSgh+!RuStC&iMXrrI,@qu6esC(k*/JcC<$JcC<$WW.J~>
-#T`s"JSH?.CSgh+!RuStC&iMXrrI,@qu6esC(k*/JcC<$JcC<$WW.J~>
-#T`s"JSH?.CSgh+!RuStC&iMXrrI,@qu6esC(k*/JcC<$JcC<$WW.J~>
-#9EjEgp/o#[J'V#fD`&U])M^1eE6Z.!7LkP!5F*bJcC<$JcD_LJ,~>
-#9EjEgp/o#[J'V#fD`&U])M^1eE6Z.!7LkP!5F*bJcC<$JcD_LJ,~>
-#9EjEgp/o#[J'V#fD`&U])M^1eE6Z.!7LkP!5F*bJcC<$JcD_LJ,~>
-!$2%<!T*O$s+13$s+13+s*t~>
-!$2%<!T*O$s+13$s+13+s*t~>
-!$2%<!T*O$s+13$s+13+s*t~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$.X1!VbZgrrMcToD\g]rn%5Fci4"4rn%5Kp&>-Vf\#!)rr_95f\lE%"5DJ\kK!T&r;P=KmIgJZ
-p&<SDo\]ZKoD[ABp@\Fcm/GW;rJ1CTgXt0Ap&>$hrn%5=kPp&~>
-!$.X1!VbZgrrMcToD\g]rn%5Fci4"4rn%5Kp&>-Vf\#!)rr_95f\lE%"5DJ\kK!T&r;P=KmIgJZ
-p&<SDo\]ZKoD[ABp@\Fcm/GW;rJ1CTgXt0Ap&>$hrn%5=kPp&~>
-!$.X1!VbZgrrMcToD\g]rn%5Fci4"4rn%5Kp&>-Vf\#!)rr_95f\lE%"5DJ\kK!T&r;P=KmIgJZ
-p&<SDo\]ZKoD[ABp@\Fcm/GW;rJ1CTgXt0Ap&>$hrn%5=kPp&~>
-!Zh=)r4;sJp\t?M]=[dnrrC^M])^+RrrBt8rrCOG])^O`rrN,;oD\mfUOUkp!5JHD!:K[_!<2l-
-"nM]nb];P3rrf;C6q#_Srrf>i6k8JSrrZO_6rs9d"4Ffn`;BQ8r5SL2!SZc5rrL6To`##66p3I#
-rrWs'7#p%%s5ESL#i+SBs6i?D-]@Zt"M5R?7*O]k#gN&Bs2.5m(WQ.J"Fqsi7/+e&!SceorrM<;
-mf3=!!7LiG"&[email protected])jpjdIXT/=<lMlA~>
-!Zh=)r4;sJp\t?M]=[dnrrC^M])^+RrrBt8rrCOG])^O`rrN,;oD\mfUOUkp!5JHD!:K[_!<2l-
-"nM]nb];P3rrf;C6q#_Srrf>i6k8JSrrZO_6rs9d"4Ffn`;BQ8r5SL2!SZc5rrL6To`##66p3I#
-rrWs'7#p%%s5ESL#i+SBs6i?D-]@Zt"M5R?7*O]k#gN&Bs2.5m(WQ.J"Fqsi7/+e&!SceorrM<;
-mf3=!!7LiG"&[email protected])jpjdIXT/=<lMlA~>
-!Zh=)r4;sJp\t?M]=[dnrrC^M])^+RrrBt8rrCOG])^O`rrN,;oD\mfUOUkp!5JHD!:K[_!<2l-
-"nM]nb];P3rrf;C6q#_Srrf>i6k8JSrrZO_6rs9d"4Ffn`;BQ8r5SL2!SZc5rrL6To`##66p3I#
-rrWs'7#p%%s5ESL#i+SBs6i?D-]@Zt"M5R?7*O]k#gN&Bs2.5m(WQ.J"Fqsi7/+e&!SceorrM<;
-mf3=!!7LiG"&[email protected])jpjdIXT/=<lMlA~>
-"!.E>/H&uWGk_4?XC2t&hZ!Um6iLKpEPqeU!Nm==rrAJc@0&Z7rr3%sBt![6!U2E,rrMo!m/I&"
-r*]TWq>UHor*]UHci3qFSUgA4!NC.^rrFq?p&>%u_#438a`V$#Fo21>SLO=5!Hk=9rrIX^qu6]"
-qYL3mju2l3!$0bm!oI+@o`#!G9q_Fa!Ki<5rrK`?iVrtr.,4\"!ER55rrIY@bPqUQnGW@fGGa6s
-!Mju/rrf?1@<TfkrrKf@p&>'T2Z3RT*U<ZT~>
-"!.E>/H&uWGk_4?XC2t&hZ!Um6iLKpEPqeU!Nm==rrAJc@0&Z7rr3%sBt![6!U2E,rrMo!m/I&"
-r*]TWq>UHor*]UHci3qFSUgA4!NC.^rrFq?p&>%u_#438a`V$#Fo21>SLO=5!Hk=9rrIX^qu6]"
-qYL3mju2l3!$0bm!oI+@o`#!G9q_Fa!Ki<5rrK`?iVrtr.,4\"!ER55rrIY@bPqUQnGW@fGGa6s
-!Mju/rrf?1@<TfkrrKf@p&>'T2Z3RT*U<ZT~>
-"!.E>/H&uWGk_4?XC2t&hZ!Um6iLKpEPqeU!Nm==rrAJc@0&Z7rr3%sBt![6!U2E,rrMo!m/I&"
-r*]TWq>UHor*]UHci3qFSUgA4!NC.^rrFq?p&>%u_#438a`V$#Fo21>SLO=5!Hk=9rrIX^qu6]"
-qYL3mju2l3!$0bm!oI+@o`#!G9q_Fa!Ki<5rrK`?iVrtr.,4\"!ER55rrIY@bPqUQnGW@fGGa6s
-!Mju/rrf?1@<TfkrrKf@p&>'T2Z3RT*U<ZT~>
-"!.E>Fn#D352P/r!Go">rs$)Ds8SmD(]"(;jFF`>s."Z-J$8PF!JQp-rrML@m/I&+mf*?sJ*6h2
-!mQ8Ap&>&lF34F_1[4T4!F<M>rrU8keG9+GR!:(SrrI8?nc&V>o(r@eju2l3!$0en"6=u%O7iMT
-gjhP\r;Qe[MtR)N]4'_!"297-g\h'P<lXh4!J$`arrGO?rVlnBVV_=RUj2D/#+pAEs3lJ>rVlo3
[email protected]#ju3/;!$1A)J,~>
-"!.E>Fn#D352P/r!Go">rs$)Ds8SmD(]"(;jFF`>s."Z-J$8PF!JQp-rrML@m/I&+mf*?sJ*6h2
-!mQ8Ap&>&lF34F_1[4T4!F<M>rrU8keG9+GR!:(SrrI8?nc&V>o(r@eju2l3!$0en"6=u%O7iMT
-gjhP\r;Qe[MtR)N]4'_!"297-g\h'P<lXh4!J$`arrGO?rVlnBVV_=RUj2D/#+pAEs3lJ>rVlo3
[email protected]#ju3/;!$1A)J,~>
-"!.E>Fn#D352P/r!Go">rs$)Ds8SmD(]"(;jFF`>s."Z-J$8PF!JQp-rrML@m/I&+mf*?sJ*6h2
-!mQ8Ap&>&lF34F_1[4T4!F<M>rrU8keG9+GR!:(SrrI8?nc&V>o(r@eju2l3!$0en"6=u%O7iMT
-gjhP\r;Qe[MtR)N]4'_!"297-g\h'P<lXh4!J$`arrGO?rVlnBVV_=RUj2D/#+pAEs3lJ>rVlo3
[email protected]#ju3/;!$1A)J,~>
-"!.E>Fo21B`NfH(A8hDG!C#B=rrB%tA-dJ\s0]Y*A7U/grro!)A9-Unq#:A2Yl=Y,]4(`5N:.e`
-rsS:7]`8"tO7rV9LTgFO!$1t:!-S9O&?Pp3K(J/9A?l17I9dLsA@MR<!+u4@!5/(+!?L;$A,sX@
-rrHo@r;QeISb<!`WH8";!8%0["6KR_df!\YlMob-rr3C]n,M+2s.s7:o`+s/rF?$+s8Th3A,uW,
-rrFq?p&>%u_#=96O,`u8"-Sf5.JNiGFf1%+A;L6b!gR;1rVm%pA.`0ZP5P=\ju2l3!$1t:!.4]U%
-&a.*Lh(\`A?>h2KC/YK!3uM&!omgerVm#hE4h0krVlrPA?Pn2"QaaBIA$N<!Ki<5rrK`?rVm2rJ
-cEJqAD7(`h>Updc%Y]errTT=df'1K_1:6*g\h'P<lXh4!J$a=rrBe3A-;i2s1/,>"DIi8`ioCA#
-^67J_6fbDA97bM!36$/!-n8<'sV9g<Fg^]s*(>sA7UJqs/40BEb(..rrA/[A,qbkrr@uVA,qqpr
-s4?iA;[1-s8RZLA,r>%rrVe&PlC[`45p2=!K3->rrKf@p&>'T2Z3RT*W?!?Us]5;rF?8Ss8R9Bc
-X^S/s8RT~>
-"!.E>Fo21B`NfH(A8hDG!C#B=rrB%tA-dJ\s0]Y*A7U/grro!)A9-Unq#:A2Yl=Y,]4(`5N:.e`
-rsS:7]`8"tO7rV9LTgFO!$1t:!-S9O&?Pp3K(J/9A?l17I9dLsA@MR<!+u4@!5/(+!?L;$A,sX@
-rrHo@r;QeISb<!`WH8";!8%0["6KR_df!\YlMob-rr3C]n,M+2s.s7:o`+s/rF?$+s8Th3A,uW,
-rrFq?p&>%u_#=96O,`u8"-Sf5.JNiGFf1%+A;L6b!gR;1rVm%pA.`0ZP5P=\ju2l3!$1t:!.4]U%
-&a.*Lh(\`A?>h2KC/YK!3uM&!omgerVm#hE4h0krVlrPA?Pn2"QaaBIA$N<!Ki<5rrK`?rVm2rJ
-cEJqAD7(`h>Updc%Y]errTT=df'1K_1:6*g\h'P<lXh4!J$a=rrBe3A-;i2s1/,>"DIi8`ioCA#
-^67J_6fbDA97bM!36$/!-n8<'sV9g<Fg^]s*(>sA7UJqs/40BEb(..rrA/[A,qbkrr@uVA,qqpr
-s4?iA;[1-s8RZLA,r>%rrVe&PlC[`45p2=!K3->rrKf@p&>'T2Z3RT*W?!?Us]5;rF?8Ss8R9Bc
-X^S/s8RT~>
-"!.E>Fo21B`NfH(A8hDG!C#B=rrB%tA-dJ\s0]Y*A7U/grro!)A9-Unq#:A2Yl=Y,]4(`5N:.e`
-rsS:7]`8"tO7rV9LTgFO!$1t:!-S9O&?Pp3K(J/9A?l17I9dLsA@MR<!+u4@!5/(+!?L;$A,sX@
-rrHo@r;QeISb<!`WH8";!8%0["6KR_df!\YlMob-rr3C]n,M+2s.s7:o`+s/rF?$+s8Th3A,uW,
-rrFq?p&>%u_#=96O,`u8"-Sf5.JNiGFf1%+A;L6b!gR;1rVm%pA.`0ZP5P=\ju2l3!$1t:!.4]U%
-&a.*Lh(\`A?>h2KC/YK!3uM&!omgerVm#hE4h0krVlrPA?Pn2"QaaBIA$N<!Ki<5rrK`?rVm2rJ
-cEJqAD7(`h>Updc%Y]errTT=df'1K_1:6*g\h'P<lXh4!J$a=rrBe3A-;i2s1/,>"DIi8`ioCA#
-^67J_6fbDA97bM!36$/!-n8<'sV9g<Fg^]s*(>sA7UJqs/40BEb(..rrA/[A,qbkrr@uVA,qqpr
-s4?iA;[1-s8RZLA,r>%rrVe&PlC[`45p2=!K3->rrKf@p&>'T2Z3RT*W?!?Us]5;rF?8Ss8R9Bc
-X^S/s8RT~>
-"!.E>+oY"=nGiOLJ4Q':Y\F(9!C#B=rrC[M[h5T^s+Mqh\$r2\s.PF]\#s&_q#:A21B'fKA^g\.
-li/"%rrth%K`D'Nb5VDAU3cP5!$2";!HG1>[hOJ#s2@f;\$pmts21i\\$t2ns'E/5[fL`lq#:@.
->Q2)4ER=CY!i_%@r;QeISb<!`WH8%<!Tdkj[f]k-he;tt"'>BB;Z?\)39C2.O@Y5;[oi[TF8`QM
->5uWerO2c3r;QdRl1P&W?,6F="cnXr84[+erreOOo(+=)rsNs&T!u2#L]@D"[ho#C"k:"&Y.)XQ
-rrM7?o`"n3r;QeBVuF.6Lo^P:UT.b3KX(P47fKjtJ@GOX!mgp]rVm"#a8_-[rVlr7!.+YE"nc'C
-s*^R<rrJ7?p&>')@K$34qP-T)\$ol2lsTh%!c/D1rr3%Q!4Dh+"j;#Cs$>E;rrH0?p&>&CSc&Kf
-iVg4f>lVWdrjN$<@K3$Jrr3BIs8SH4NjlL"D?$enrjMp-F85bQgUAo,\&JCIG;#Mr\"8?Sen[gZ
-\!r?VOdQ-W"IG;Os2k8L%$R(YKV,`_S1]'dI\ZnO!K<iRrrVKd:]C@p45p2=!K3->rrKf@p&>'T
-2Z3R\*WQ/Q8;ZX3=oGf:EmOcj88>WCDUnc;~>
-"!.E>+oY"=nGiOLJ4Q':Y\F(9!C#B=rrC[M[h5T^s+Mqh\$r2\s.PF]\#s&_q#:A21B'fKA^g\.
-li/"%rrth%K`D'Nb5VDAU3cP5!$2";!HG1>[hOJ#s2@f;\$pmts21i\\$t2ns'E/5[fL`lq#:@.
->Q2)4ER=CY!i_%@r;QeISb<!`WH8%<!Tdkj[f]k-he;tt"'>BB;Z?\)39C2.O@Y5;[oi[TF8`QM
->5uWerO2c3r;QdRl1P&W?,6F="cnXr84[+erreOOo(+=)rsNs&T!u2#L]@D"[ho#C"k:"&Y.)XQ
-rrM7?o`"n3r;QeBVuF.6Lo^P:UT.b3KX(P47fKjtJ@GOX!mgp]rVm"#a8_-[rVlr7!.+YE"nc'C
-s*^R<rrJ7?p&>')@K$34qP-T)\$ol2lsTh%!c/D1rr3%Q!4Dh+"j;#Cs$>E;rrH0?p&>&CSc&Kf
-iVg4f>lVWdrjN$<@K3$Jrr3BIs8SH4NjlL"D?$enrjMp-F85bQgUAo,\&JCIG;#Mr\"8?Sen[gZ
-\!r?VOdQ-W"IG;Os2k8L%$R(YKV,`_S1]'dI\ZnO!K<iRrrVKd:]C@p45p2=!K3->rrKf@p&>'T
-2Z3R\*WQ/Q8;ZX3=oGf:EmOcj88>WCDUnc;~>
-"!.E>+oY"=nGiOLJ4Q':Y\F(9!C#B=rrC[M[h5T^s+Mqh\$r2\s.PF]\#s&_q#:A21B'fKA^g\.
-li/"%rrth%K`D'Nb5VDAU3cP5!$2";!HG1>[hOJ#s2@f;\$pmts21i\\$t2ns'E/5[fL`lq#:@.
->Q2)4ER=CY!i_%@r;QeISb<!`WH8%<!Tdkj[f]k-he;tt"'>BB;Z?\)39C2.O@Y5;[oi[TF8`QM
->5uWerO2c3r;QdRl1P&W?,6F="cnXr84[+erreOOo(+=)rsNs&T!u2#L]@D"[ho#C"k:"&Y.)XQ
-rrM7?o`"n3r;QeBVuF.6Lo^P:UT.b3KX(P47fKjtJ@GOX!mgp]rVm"#a8_-[rVlr7!.+YE"nc'C
-s*^R<rrJ7?p&>')@K$34qP-T)\$ol2lsTh%!c/D1rr3%Q!4Dh+"j;#Cs$>E;rrH0?p&>&CSc&Kf
-iVg4f>lVWdrjN$<@K3$Jrr3BIs8SH4NjlL"D?$enrjMp-F85bQgUAo,\&JCIG;#Mr\"8?Sen[gZ
-\!r?VOdQ-W"IG;Os2k8L%$R(YKV,`_S1]'dI\ZnO!K<iRrrVKd:]C@p45p2=!K3->rrKf@p&>'T
-2Z3R\*WQ/Q8;ZX3=oGf:EmOcj88>WCDUnc;~>
-"!.E>@K+aVr;Q`rJHPNDmOnJ<!C#B9rt+!Ns+Ppms8UV?s*^O>s62?6rrm5&e/6]nr;Qa;qYpcM
-e=;Er;p,+>!MXo6rr=);rrG.?rr3F`PlLb'g].;(SH&WV0`:qO+T;<>"6]4S55Zo5_Z/6Crr3"*
-^@hL,Lm7f:!Ip[5rrK*?rVloQ62gfch#5\orVlsEq8uV7rsUmKs8Sm*mJm2,s1)Y<rr^sSZ#'C=
-!$2";!Aj!5rrHE@rVmFi(nB+*^0^i/Nq35A.KBF4r$r%hs)j7ms8U&>rVlj<qu6[Ho(r@eju2l3
-!$2";!CPT?rs\;\s#T/u49(2%s"_RmrrI\?rr3&oeE6c1"\.)Cs,E*<rrViBl2L\d6/2G>IA$N<
-!Ki<5rrK`?r;R&L5j&+H4l>?\rr3&Z/Ed$4$gQ75s8UhXjo>?Hg\h'P<lXh4!J$a8rrX;AWH8(=
-"TI-TTmQe=$m#BJQu;Bms6)??OGs2="8^pTS,=c:AcD]17+hJ<&U0-*s8U)>s8Prqqu=?:s(8b>
-rrKN?qu7)+E;rqZs8VbKGlLIarr3#elMgebr7'^)rrG4?rr3"WP5YC]]jUO5!Tl<<rs0Y*.qmH"
-s8O,<rsE/Hs6;)ns8Q3>s*t~>
-"!.E>@K+aVr;Q`rJHPNDmOnJ<!C#B9rt+!Ns+Ppms8UV?s*^O>s62?6rrm5&e/6]nr;Qa;qYpcM
-e=;Er;p,+>!MXo6rr=);rrG.?rr3F`PlLb'g].;(SH&WV0`:qO+T;<>"6]4S55Zo5_Z/6Crr3"*
-^@hL,Lm7f:!Ip[5rrK*?rVloQ62gfch#5\orVlsEq8uV7rsUmKs8Sm*mJm2,s1)Y<rr^sSZ#'C=
-!$2";!Aj!5rrHE@rVmFi(nB+*^0^i/Nq35A.KBF4r$r%hs)j7ms8U&>rVlj<qu6[Ho(r@eju2l3
-!$2";!CPT?rs\;\s#T/u49(2%s"_RmrrI\?rr3&oeE6c1"\.)Cs,E*<rrViBl2L\d6/2G>IA$N<
-!Ki<5rrK`?r;R&L5j&+H4l>?\rr3&Z/Ed$4$gQ75s8UhXjo>?Hg\h'P<lXh4!J$a8rrX;AWH8(=
-"TI-TTmQe=$m#BJQu;Bms6)??OGs2="8^pTS,=c:AcD]17+hJ<&U0-*s8U)>s8Prqqu=?:s(8b>
-rrKN?qu7)+E;rqZs8VbKGlLIarr3#elMgebr7'^)rrG4?rr3"WP5YC]]jUO5!Tl<<rs0Y*.qmH"
-s8O,<rsE/Hs6;)ns8Q3>s*t~>
-"!.E>@K+aVr;Q`rJHPNDmOnJ<!C#B9rt+!Ns+Ppms8UV?s*^O>s62?6rrm5&e/6]nr;Qa;qYpcM
-e=;Er;p,+>!MXo6rr=);rrG.?rr3F`PlLb'g].;(SH&WV0`:qO+T;<>"6]4S55Zo5_Z/6Crr3"*
-^@hL,Lm7f:!Ip[5rrK*?rVloQ62gfch#5\orVlsEq8uV7rsUmKs8Sm*mJm2,s1)Y<rr^sSZ#'C=
-!$2";!Aj!5rrHE@rVmFi(nB+*^0^i/Nq35A.KBF4r$r%hs)j7ms8U&>rVlj<qu6[Ho(r@eju2l3
-!$2";!CPT?rs\;\s#T/u49(2%s"_RmrrI\?rr3&oeE6c1"\.)Cs,E*<rrViBl2L\d6/2G>IA$N<
-!Ki<5rrK`?r;R&L5j&+H4l>?\rr3&Z/Ed$4$gQ75s8UhXjo>?Hg\h'P<lXh4!J$a8rrX;AWH8(=
-"TI-TTmQe=$m#BJQu;Bms6)??OGs2="8^pTS,=c:AcD]17+hJ<&U0-*s8U)>s8Prqqu=?:s(8b>
-rrKN?qu7)+E;rqZs8VbKGlLIarr3#elMgebr7'^)rrG4?rr3"WP5YC]]jUO5!Tl<<rs0Y*.qmH"
-s8O,<rsE/Hs6;)ns8Q3>s*t~>
-"!.E>Fo)+AJXc]>rq-0h!C#B>rrMn@rZ)+Z5Q?G(rr38S8H4C6nF56up\tD5YlF#Po_e^h*VfX;
-WcJ,<(]GEU&pj9O!$2";!BD(t*<[.Hs8O,=rrr2os8VI?r;Qfh+9!8_PktFNr:'daqu6\'^@qR.
-Wd+@:rrIV?p&>&lF8c+>rO`"K"3gbn9)\bl,PfJ[rr3-]jo>@VGlI^FoDc@2qu6]%%/h1H.fB;I
-1[4T4!F<M>rt(6GqZ$TP56$WZ*??+'>Q=KrnH8IaFf56=!QA.=rr=):rrFV?qYpTY2Y@"L*W5p<
-ofW3o%!VLH3o]*[s,*$?1@+r>!J-a8rr=\N*WHZN[eTk&+9!8^%MHbZrrJ7?p&>')@Jp-+cqXN>
-"82WS3;rjX2<Xf8!S.q`*<HH`q>L<o<lXh4!J$a>rrMt`r>btZs8%lW*<[SWs.Of=rraABs-SK=
-rrhOCs,`3:rrDlmnGr7]rrGO?rVlnBVZ-T(``E->;9](?qtC&%(&f3V)0#WK;Z7[>'QF(PaSu2B
-Uj2q47/e2-Dts,-!B]9>rrJ%@[email protected]#ju3/;!ua,Xm/?qa')`gR'Ysb61B.:TpAFr@~>
-"!.E>Fo)+AJXc]>rq-0h!C#B>rrMn@rZ)+Z5Q?G(rr38S8H4C6nF56up\tD5YlF#Po_e^h*VfX;
-WcJ,<(]GEU&pj9O!$2";!BD(t*<[.Hs8O,=rrr2os8VI?r;Qfh+9!8_PktFNr:'daqu6\'^@qR.
-Wd+@:rrIV?p&>&lF8c+>rO`"K"3gbn9)\bl,PfJ[rr3-]jo>@VGlI^FoDc@2qu6]%%/h1H.fB;I
-1[4T4!F<M>rt(6GqZ$TP56$WZ*??+'>Q=KrnH8IaFf56=!QA.=rr=):rrFV?qYpTY2Y@"L*W5p<
-ofW3o%!VLH3o]*[s,*$?1@+r>!J-a8rr=\N*WHZN[eTk&+9!8^%MHbZrrJ7?p&>')@Jp-+cqXN>
-"82WS3;rjX2<Xf8!S.q`*<HH`q>L<o<lXh4!J$a>rrMt`r>btZs8%lW*<[SWs.Of=rraABs-SK=
-rrhOCs,`3:rrDlmnGr7]rrGO?rVlnBVZ-T(``E->;9](?qtC&%(&f3V)0#WK;Z7[>'QF(PaSu2B
-Uj2q47/e2-Dts,-!B]9>rrJ%@[email protected]#ju3/;!ua,Xm/?qa')`gR'Ysb61B.:TpAFr@~>
-"!.E>Fo)+AJXc]>rq-0h!C#B>rrMn@rZ)+Z5Q?G(rr38S8H4C6nF56up\tD5YlF#Po_e^h*VfX;
-WcJ,<(]GEU&pj9O!$2";!BD(t*<[.Hs8O,=rrr2os8VI?r;Qfh+9!8_PktFNr:'daqu6\'^@qR.
-Wd+@:rrIV?p&>&lF8c+>rO`"K"3gbn9)\bl,PfJ[rr3-]jo>@VGlI^FoDc@2qu6]%%/h1H.fB;I
-1[4T4!F<M>rt(6GqZ$TP56$WZ*??+'>Q=KrnH8IaFf56=!QA.=rr=):rrFV?qYpTY2Y@"L*W5p<
-ofW3o%!VLH3o]*[s,*$?1@+r>!J-a8rr=\N*WHZN[eTk&+9!8^%MHbZrrJ7?p&>')@Jp-+cqXN>
-"82WS3;rjX2<Xf8!S.q`*<HH`q>L<o<lXh4!J$a>rrMt`r>btZs8%lW*<[SWs.Of=rraABs-SK=
-rrhOCs,`3:rrDlmnGr7]rrGO?rVlnBVZ-T(``E->;9](?qtC&%(&f3V)0#WK;Z7[>'QF(PaSu2B
-Uj2q47/e2-Dts,-!B]9>rrJ%@[email protected]#ju3/;!ua,Xm/?qa')`gR'Ysb61B.:TpAFr@~>
-"!.E>Fo)+=JXcK8!C#B>s8S,ZrrrD25Q?G(rr35R8H7pi/1a!Yrs!;Ds8UtYjSf)Y*W?!=j7N?N
-"KHMB;p,+>!MXo6rrGC?rVlmYj8/cU*W#d@m4eS?kjSQ)rVln:Xn_nrf_tgN?G?F=!qFb*rVlrl
-R#h.E!q(Q@p&>&lF8c+>q;2)M""Woj9)\bl,PfJ[rr3-]jo>@VGl7RB\RYU<"5*XYD"mr11[4T4
-!F<M>rrJ1?rr3#U55bE]o-sG6#'Ggrs8U&>rVlj<qu6dKo)J:BrVlo\2Y@"L*W5p<htd9O%$HMJ
-3o]*[s,*$?1;s1l!J-a>rrVrDjneuXNK=&<!qat*qYpSET`"fjOc/o4!P;e<rrLJ@r;QfZ3<&pZ
-i@O0krrVK7o(r@e6/2>;!ER55rrIY@rVlo(C]=>:fH("]kPkJiq'?!6HiO-#)uor*K`:uSkV`C%
-N;ihXqVLrG#=R5EpYc'qVZ-T!``E->;9\t<!G8h<rt/POs8VeRE;rqZs8V_IGlQ^rrr3"hJc>ZN
-r6sX(rrucDs8VSDV>^Dp]jUO5!Tl<<rs0Y+/83N"s8O,9rrMC?qu;0~>
-"!.E>Fo)+=JXcK8!C#B>s8S,ZrrrD25Q?G(rr35R8H7pi/1a!Yrs!;Ds8UtYjSf)Y*W?!=j7N?N
-"KHMB;p,+>!MXo6rrGC?rVlmYj8/cU*W#d@m4eS?kjSQ)rVln:Xn_nrf_tgN?G?F=!qFb*rVlrl
-R#h.E!q(Q@p&>&lF8c+>q;2)M""Woj9)\bl,PfJ[rr3-]jo>@VGl7RB\RYU<"5*XYD"mr11[4T4
-!F<M>rrJ1?rr3#U55bE]o-sG6#'Ggrs8U&>rVlj<qu6dKo)J:BrVlo\2Y@"L*W5p<htd9O%$HMJ
-3o]*[s,*$?1;s1l!J-a>rrVrDjneuXNK=&<!qat*qYpSET`"fjOc/o4!P;e<rrLJ@r;QfZ3<&pZ
-i@O0krrVK7o(r@e6/2>;!ER55rrIY@rVlo(C]=>:fH("]kPkJiq'?!6HiO-#)uor*K`:uSkV`C%
-N;ihXqVLrG#=R5EpYc'qVZ-T!``E->;9\t<!G8h<rt/POs8VeRE;rqZs8V_IGlQ^rrr3"hJc>ZN
-r6sX(rrucDs8VSDV>^Dp]jUO5!Tl<<rs0Y+/83N"s8O,9rrMC?qu;0~>
-"!.E>Fo)+=JXcK8!C#B>s8S,ZrrrD25Q?G(rr35R8H7pi/1a!Yrs!;Ds8UtYjSf)Y*W?!=j7N?N
-"KHMB;p,+>!MXo6rrGC?rVlmYj8/cU*W#d@m4eS?kjSQ)rVln:Xn_nrf_tgN?G?F=!qFb*rVlrl
-R#h.E!q(Q@p&>&lF8c+>q;2)M""Woj9)\bl,PfJ[rr3-]jo>@VGl7RB\RYU<"5*XYD"mr11[4T4
-!F<M>rrJ1?rr3#U55bE]o-sG6#'Ggrs8U&>rVlj<qu6dKo)J:BrVlo\2Y@"L*W5p<htd9O%$HMJ
-3o]*[s,*$?1;s1l!J-a>rrVrDjneuXNK=&<!qat*qYpSET`"fjOc/o4!P;e<rrLJ@r;QfZ3<&pZ
-i@O0krrVK7o(r@e6/2>;!ER55rrIY@rVlo(C]=>:fH("]kPkJiq'?!6HiO-#)uor*K`:uSkV`C%
-N;ihXqVLrG#=R5EpYc'qVZ-T!``E->;9\t<!G8h<rt/POs8VeRE;rqZs8V_IGlQ^rrr3"hJc>ZN
-r6sX(rrucDs8VSDV>^Dp]jUO5!Tl<<rs0Y+/83N"s8O,9rrMC?qu;0~>
-"!.E><;j6._>jOdS,<3sfsWK(^&S,8L:4Ot5<o1%Qi@!feO]_7NW-?d`V9B5Cp<p=%(fsJe$c\"
-[^O]cMOa[S"Ho5R;p,+>!MXo6rrM@?rVln=WrBF,f`(mN*W#dAnm/]4I)#\h[JmT8GfBIX!*]?0
-!HHNdrrT>'N;`bW_HQg9!M+c5rrK*?rVlo[Ac9%>>P6lerO)f1qq5fb[KU*@s8Sm>r;QfBF8`NL
->Q;`frO2V'!Aj!5rrHE@rVlo%L&SL]W-/%<!V7c7rsa*)S[PttL]@D![M?6mrVm"5Z*os^rVlo\
-2Y@"L*W5p<Gc(JK%#:qa3o]FGs,*$?1.V>P!J%]ZrrUOIC&7i1NK=&<!l+e^qYpSET`"fjOc/o4
-!P;e<rrLJ@r;Qfa@K*\:C_,_.rrRiR[JKn(6/2>;!ER55rrIY@rVlo>GQ,#R<ZM.VHN(>]ZXWsI
-I^Z[i'EA*"K`:uSkV`CEL&SL]WH@k6#C<5TTn35fVZ-T!``E->;9\t<!Ki`J[M6pbs,3AT[\#9n
-s+R&Q[[]!qs*pdB[K2>`rr3&c!)NRn"CAOFOdu@L!PMn6rrM7?r;R$Cs8Tc(M<Y%DrO)jhs8V@>
-qu;0~>
-"!.E><;j6._>jOdS,<3sfsWK(^&S,8L:4Ot5<o1%Qi@!feO]_7NW-?d`V9B5Cp<p=%(fsJe$c\"
-[^O]cMOa[S"Ho5R;p,+>!MXo6rrM@?rVln=WrBF,f`(mN*W#dAnm/]4I)#\h[JmT8GfBIX!*]?0
-!HHNdrrT>'N;`bW_HQg9!M+c5rrK*?rVlo[Ac9%>>P6lerO)f1qq5fb[KU*@s8Sm>r;QfBF8`NL
->Q;`frO2V'!Aj!5rrHE@rVlo%L&SL]W-/%<!V7c7rsa*)S[PttL]@D![M?6mrVm"5Z*os^rVlo\
-2Y@"L*W5p<Gc(JK%#:qa3o]FGs,*$?1.V>P!J%]ZrrUOIC&7i1NK=&<!l+e^qYpSET`"fjOc/o4
-!P;e<rrLJ@r;Qfa@K*\:C_,_.rrRiR[JKn(6/2>;!ER55rrIY@rVlo>GQ,#R<ZM.VHN(>]ZXWsI
-I^Z[i'EA*"K`:uSkV`CEL&SL]WH@k6#C<5TTn35fVZ-T!``E->;9\t<!Ki`J[M6pbs,3AT[\#9n
-s+R&Q[[]!qs*pdB[K2>`rr3&c!)NRn"CAOFOdu@L!PMn6rrM7?r;R$Cs8Tc(M<Y%DrO)jhs8V@>
-qu;0~>
-"!.E><;j6._>jOdS,<3sfsWK(^&S,8L:4Ot5<o1%Qi@!feO]_7NW-?d`V9B5Cp<p=%(fsJe$c\"
-[^O]cMOa[S"Ho5R;p,+>!MXo6rrM@?rVln=WrBF,f`(mN*W#dAnm/]4I)#\h[JmT8GfBIX!*]?0
-!HHNdrrT>'N;`bW_HQg9!M+c5rrK*?rVlo[Ac9%>>P6lerO)f1qq5fb[KU*@s8Sm>r;QfBF8`NL
->Q;`frO2V'!Aj!5rrHE@rVlo%L&SL]W-/%<!V7c7rsa*)S[PttL]@D![M?6mrVm"5Z*os^rVlo\
-2Y@"L*W5p<Gc(JK%#:qa3o]FGs,*$?1.V>P!J%]ZrrUOIC&7i1NK=&<!l+e^qYpSET`"fjOc/o4
-!P;e<rrLJ@r;Qfa@K*\:C_,_.rrRiR[JKn(6/2>;!ER55rrIY@rVlo>GQ,#R<ZM.VHN(>]ZXWsI
-I^Z[i'EA*"K`:uSkV`CEL&SL]WH@k6#C<5TTn35fVZ-T!``E->;9\t<!Ki`J[M6pbs,3AT[\#9n
-s+R&Q[[]!qs*pdB[K2>`rr3&c!)NRn"CAOFOdu@L!PMn6rrM7?r;R$Cs8Tc(M<Y%DrO)jhs8V@>
-qu;0~>
-!Zh<`r+6(Zs8TIDqu6Z!ral.Qrr38'AnGcCN;p?%rr3,`OoNUMral1M\bQ1*VpPGC"4j.FUASU*
-V>pRRral;$s8SGCrr3#>YP.ttno2/<rr@6AAcSt4rr@9=rr_7mB".d>!,):C!5/(+!;?A'!65!;
-!mYDhrVloQSGW<fj+Xf2rs,MlR@3@?s4I9^"6KR_e,<k\lMpn0ral>jGQ7]bY5A5!_u40Lq>^K/
-rFQ<6s8UK7R31\drrZPJRA9c]!36$1!."[email protected];Qh8As<5o"1">P
-2Y@"O(n$f.rr2tGral;2s8RrDrr3,2^AftMral/8rVlrZAu5A(!P?#CrrUkcYPS8)Z,ZhDp6h=M
-MtR)U]/uFKj8]/>Pl(I\hYq*gc8FearrTT?e,'(MNTpKChjKlh`qB?:J6nY3qu?]2ral<"GQ7]S
-ral.Frr383AnL-Fs8TpCrr3,kL&_1Rral.Uo`#,DAqU-`Xi^SB"l5XIs-DU?rrA2\AcS"nrt(-$
-AqnR0s8RjdArFa5s8R]MAcSS(rrVe(Q2L[^AcS:urr]!`EFAJ>#Nd.sRF;-8GQ%ODV:,D=rFQ2O
-s8VYCqu;0~>
-!Zh<`r+6(Zs8TIDqu6Z!ral.Qrr38'AnGcCN;p?%rr3,`OoNUMral1M\bQ1*VpPGC"4j.FUASU*
-V>pRRral;$s8SGCrr3#>YP.ttno2/<rr@6AAcSt4rr@9=rr_7mB".d>!,):C!5/(+!;?A'!65!;
-!mYDhrVloQSGW<fj+Xf2rs,MlR@3@?s4I9^"6KR_e,<k\lMpn0ral>jGQ7]bY5A5!_u40Lq>^K/
-rFQ<6s8UK7R31\drrZPJRA9c]!36$1!."[email protected];Qh8As<5o"1">P
-2Y@"O(n$f.rr2tGral;2s8RrDrr3,2^AftMral/8rVlrZAu5A(!P?#CrrUkcYPS8)Z,ZhDp6h=M
-MtR)U]/uFKj8]/>Pl(I\hYq*gc8FearrTT?e,'(MNTpKChjKlh`qB?:J6nY3qu?]2ral<"GQ7]S
-ral.Frr383AnL-Fs8TpCrr3,kL&_1Rral.Uo`#,DAqU-`Xi^SB"l5XIs-DU?rrA2\AcS"nrt(-$
-AqnR0s8RjdArFa5s8R]MAcSS(rrVe(Q2L[^AcS:urr]!`EFAJ>#Nd.sRF;-8GQ%ODV:,D=rFQ2O
-s8VYCqu;0~>
-!Zh<`r+6(Zs8TIDqu6Z!ral.Qrr38'AnGcCN;p?%rr3,`OoNUMral1M\bQ1*VpPGC"4j.FUASU*
-V>pRRral;$s8SGCrr3#>YP.ttno2/<rr@6AAcSt4rr@9=rr_7mB".d>!,):C!5/(+!;?A'!65!;
-!mYDhrVloQSGW<fj+Xf2rs,MlR@3@?s4I9^"6KR_e,<k\lMpn0ral>jGQ7]bY5A5!_u40Lq>^K/
-rFQ<6s8UK7R31\drrZPJRA9c]!36$1!."[email protected];Qh8As<5o"1">P
-2Y@"O(n$f.rr2tGral;2s8RrDrr3,2^AftMral/8rVlrZAu5A(!P?#CrrUkcYPS8)Z,ZhDp6h=M
-MtR)U]/uFKj8]/>Pl(I\hYq*gc8FearrTT?e,'(MNTpKChjKlh`qB?:J6nY3qu?]2ral<"GQ7]S
-ral.Frr383AnL-Fs8TpCrr3,kL&_1Rral.Uo`#,DAqU-`Xi^SB"l5XIs-DU?rrA2\AcS"nrt(-$
-AqnR0s8RjdArFa5s8R]MAcSS(rrVe(Q2L[^AcS:urr]!`EFAJ>#Nd.sRF;-8GQ%ODV:,D=rFQ2O
-s8VYCqu;0~>
-!$0_l!I^U>rrL>?c2Rh,WkJE5h6Z_Q!7h($!9VW-!65"j!;,sa"0dE1O3[b-Tn@ugo`##OK7gQ"
-rrFn@g]%9Grdt3jp&>$Krdt4,o)A_JkOAKOfD^C&j7WEP_>]&eqXFLccb08W!$.[2"-%qcZ1\+s
-oDX@BaQNSR~>
-!$0_l!I^U>rrL>?c2Rh,WkJE5h6Z_Q!7h($!9VW-!65"j!;,sa"0dE1O3[b-Tn@ugo`##OK7gQ"
-rrFn@g]%9Grdt3jp&>$Krdt4,o)A_JkOAKOfD^C&j7WEP_>]&eqXFLccb08W!$.[2"-%qcZ1\+s
-oDX@BaQNSR~>
-!$0_l!I^U>rrL>?c2Rh,WkJE5h6Z_Q!7h($!9VW-!65"j!;,sa"0dE1O3[b-Tn@ugo`##OK7gQ"
-rrFn@g]%9Grdt3jp&>$Krdt4,o)A_JkOAKOfD^C&j7WEP_>]&eqXFLccb08W!$.[2"-%qcZ1\+s
-oDX@BaQNSR~>
-!$0_l!R>og?NFuWJcC<$dJj5&laHfo2<W*]!Si8*?N?dNs6ou<~>
-!$0_l!R>og?NFuWJcC<$dJj5&laHfo2<W*]!Si8*?N?dNs6ou<~>
-!$0_l!R>og?NFuWJcC<$dJj5&laHfo2<W*]!Si8*?N?dNs6ou<~>
-!$0\k!7h(]!6TlmJcF*s!Qk2HrrL:<aSu7trk&7.JcG3=J,~>
-!$0\k!7h(]!6TlmJcF*s!Qk2HrrL:<aSu7trk&7.JcG3=J,~>
-!$0\k!7h(]!6TlmJcF*s!Qk2HrrL:<aSu7trk&7.JcG3=J,~>
-!$..#"#_JQH%H!Hs+13$s7lVE~>
-!$..#"#_JQH%H!Hs+13$s7lVE~>
-!$..#"#_JQH%H!Hs+13$s7lVE~>
-!$1P.",Is-hrXk>C)m`\rrQ[N'D)5,m2m?Wo_8@e73")Lrr`#hZsnUdJcC<$JcGNFJ,~>
-!$1P.",Is-hrXk>C)m`\rrQ[N'D)5,m2m?Wo_8@e73")Lrr`#hZsnUdJcC<$JcGNFJ,~>
-!$1P.",Is-hrXk>C)m`\rrQ[N'D)5,m2m?Wo_8@e73")Lrr`#hZsnUdJcC<$JcGNFJ,~>
-!$1J,!C#B#rr=)9rr=)2rraJBs/L,5rrMX?lMgms@Y+Q1s+13$s7lVE~>
-!$1J,!C#B#rr=)9rr=)2rraJBs/L,5rrMX?lMgms@Y+Q1s+13$s7lVE~>
-!$1J,!C#B#rr=)9rr=)2rraJBs/L,5rrMX?lMgms@Y+Q1s+13$s7lVE~>
-#9Ej*e^C_-[/U(*g&A5V[f$.+52Q#5"kqkTZ*D%BrrC@DYlMW<rr=)9rr=)9rrKOBr;R!Er;X^+
-s8Tq7YlN)JrrMX?r;Qc0rilIPrr2u0rilIRr;Qf0@Y+Q1s+13$s7lVE~>
-#9Ej*e^C_-[/U(*g&A5V[f$.+52Q#5"kqkTZ*D%BrrC@DYlMW<rr=)9rr=)9rrKOBr;R!Er;X^+
-s8Tq7YlN)JrrMX?r;Qc0rilIPrr2u0rilIRr;Qf0@Y+Q1s+13$s7lVE~>
-#9Ej*e^C_-[/U(*g&A5V[f$.+52Q#5"kqkTZ*D%BrrC@DYlMW<rr=)9rr=)9rrKOBr;R!Er;X^+
-s8Tq7YlN)JrrMX?r;Qc0rilIPrr2u0rilIRr;Qf0@Y+Q1s+13$s7lVE~>
-$Q]8F7!rccCo%*_JGs<bDQ*O6!C#B6rs=B]GACu7ZN&$mrbDOU[f-4+*W#d9*W#d:$nqPY!?h=<
-rr@rUCB8b%rr3#h/,fJKY]9YX"F\VrXDe)R!IiJqrrK`@JcC<$JcC<$q#>j~>
-$Q]8F7!rccCo%*_JGs<bDQ*O6!C#B6rs=B]GACu7ZN&$mrbDOU[f-4+*W#d9*W#d:$nqPY!?h=<
-rr@rUCB8b%rr3#h/,fJKY]9YX"F\VrXDe)R!IiJqrrK`@JcC<$JcC<$q#>j~>
-$Q]8F7!rccCo%*_JGs<bDQ*O6!C#B6rs=B]GACu7ZN&$mrbDOU[f-4+*W#d9*W#d:$nqPY!?h=<
-rr@rUCB8b%rr3#h/,fJKY]9YX"F\VrXDe)R!IiJqrrK`@JcC<$JcC<$q#>j~>
-$Q]8F50X',pEop4IfB?JmOnJ<!C#B>rrBt7G70i=Ki$S)s4'[?I@pN=!R+C=rr=)9rr=)9rrJ+N
-rr3,"G7Sk^q>UJiHN*pFnLOS<!CGQ?rrgQfs#K-=rrIq?rVlo1@Y+Q1s+13$s7lVE~>
-$Q]8F50X',pEop4IfB?JmOnJ<!C#B>rrBt7G70i=Ki$S)s4'[?I@pN=!R+C=rr=)9rr=)9rrJ+N
-rr3,"G7Sk^q>UJiHN*pFnLOS<!CGQ?rrgQfs#K-=rrIq?rVlo1@Y+Q1s+13$s7lVE~>
-$Q]8F50X',pEop4IfB?JmOnJ<!C#B>rrBt7G70i=Ki$S)s4'[?I@pN=!R+C=rr=)9rr=)9rrJ+N
-rr3,"G7Sk^q>UJiHN*pFnLOS<!CGQ?rrgQfs#K-=rrIq?rVlo1@Y+Q1s+13$s7lVE~>
-"!.E>FoMCDpEop4/cJoS<%e.L!C#B>rrC[KV$"@0KpVf="P$'CI@pN=!R+C=rr=)9rr=)4rrg<;
-'r/;;rr@KH=ogX0rr3#h/,fJK]Oh(G"JPkq3DocZ!AKc:rrK`@JcC<$JcC<$q#>j~>
-"!.E>FoMCDpEop4/cJoS<%e.L!C#B>rrC[KV$"@0KpVf="P$'CI@pN=!R+C=rr=)9rr=)4rrg<;
-'r/;;rr@KH=ogX0rr3#h/,fJK]Oh(G"JPkq3DocZ!AKc:rrK`@JcC<$JcC<$q#>j~>
-"!.E>FoMCDpEop4/cJoS<%e.L!C#B>rrC[KV$"@0KpVf="P$'CI@pN=!R+C=rr=)9rr=)4rrg<;
-'r/;;rr@KH=ogX0rr3#h/,fJK]Oh(G"JPkq3DocZ!AKc:rrK`@JcC<$JcC<$q#>j~>
-"!.E>FoMCDpEop4?i@e@c2IYC52Q#5!JQm>rrgkCs*^O=rrL>?rVlj<qYpO9oD\h6r;HWrI&?nZ
-!IK.lrrMX?r;Qc>rkS_oVuJcYrP8KqrVlo1@Y+Q1s+13$s7lVE~>
-"!.E>FoMCDpEop4?i@e@c2IYC52Q#5!JQm>rrgkCs*^O=rrL>?rVlj<qYpO9oD\h6r;HWrI&?nZ
-!IK.lrrMX?r;Qc>rkS_oVuJcYrP8KqrVlo1@Y+Q1s+13$s7lVE~>
-"!.E>FoMCDpEop4?i@e@c2IYC52Q#5!JQm>rrgkCs*^O=rrL>?rVlj<qYpO9oD\h6r;HWrI&?nZ
-!IK.lrrMX?r;Qc>rkS_oVuJcYrP8KqrVlo1@Y+Q1s+13$s7lVE~>
-"!.E>FoMCDpEop4Ie`pD52Q#5$&'&,s8UV?s*^O=rrL>?rVlj<qYpO9qYpRH9)S\i+T23<##i\E
-s2Pk#rr3#h/,fJK>2T>Z"HeWB3TKo7!P;fls+13$s+14Fs*t~>
-"!.E>FoMCDpEop4Ie`pD52Q#5$&'&,s8UV?s*^O=rrL>?rVlj<qYpO9qYpRH9)S\i+T23<##i\E
-s2Pk#rr3#h/,fJK>2T>Z"HeWB3TKo7!P;fls+13$s+14Fs*t~>
-"!.E>FoMCDpEop4Ie`pD52Q#5$&'&,s8UV?s*^O=rrL>?rVlj<qYpO9qYpRH9)S\i+T23<##i\E
-s2Pk#rr3#h/,fJK>2T>Z"HeWB3TKo7!P;fls+13$s+14Fs*t~>
-"!.EGKDtlRpH/ESNrC%!/H5YPL`IBR1\^nUKp>sb*CB](rG_`V#YFsos(WPm*Duh9"CiGj*Ei=?
-!@1&1rrG%UrVmK-9-#$QWJCNR73*9eGQ7^@4oQH)IJs3D2?"TrLAq2TkiSgQJcC<$JcC<$q#>j~>
-"!.EGKDtlRpH/ESNrC%!/H5YPL`IBR1\^nUKp>sb*CB](rG_`V#YFsos(WPm*Duh9"CiGj*Ei=?
-!@1&1rrG%UrVmK-9-#$QWJCNR73*9eGQ7^@4oQH)IJs3D2?"TrLAq2TkiSgQJcC<$JcC<$q#>j~>
-"!.EGKDtlRpH/ESNrC%!/H5YPL`IBR1\^nUKp>sb*CB](rG_`V#YFsos(WPm*Duh9"CiGj*Ei=?
-!@1&1rrG%UrVmK-9-#$QWJCNR73*9eGQ7^@4oQH)IJs3D2?"TrLAq2TkiSgQJcC<$JcC<$q#>j~>
-!$1"t!JQlGrrY\J2M6S\JcC<$JcGNFJ,~>
-!$1"t!JQlGrrY\J2M6S\JcC<$JcGNFJ,~>
-!$1"t!JQlGrrY\J2M6S\JcC<$JcGNFJ,~>
-!$1"t!JQkks+13$s+13Hs*t~>
-!$1"t!JQkks+13$s+13Hs*t~>
-!$1"t!JQkks+13$s+13Hs*t~>
-!$1"t!P?=%s+13$s+13Hs*t~>
-!$1"t!P?=%s+13$s+13Hs*t~>
-!$1"t!P?=%s+13$s+13Hs*t~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$.@)!V"X)rrM*>JcC<$JcFU,J,~>
-!$.@)!V"X)rrM*>JcC<$JcFU,J,~>
-!$.@)!V"X)rrM*>JcC<$JcFU,J,~>
-!Zh<ur1X1qq#:BJe+3M@aJ,F)rVlu=U8%SZrrL7$rr3)_`W*sUU&`:0rrBk4U&`O-rrVhUQM1=Z
-Z2;uL!p66)pAY0d\+'Cuce\R"!9*mN!;6?k!jdU@JcC<$JcFX-J,~>
-!Zh<ur1X1qq#:BJe+3M@aJ,F)rVlu=U8%SZrrL7$rr3)_`W*sUU&`:0rrBk4U&`O-rrVhUQM1=Z
-Z2;uL!p66)pAY0d\+'Cuce\R"!9*mN!;6?k!jdU@JcC<$JcFX-J,~>
-!Zh<ur1X1qq#:BJe+3M@aJ,F)rVlu=U8%SZrrL7$rr3)_`W*sUU&`:0rrBk4U&`O-rrVhUQM1=Z
-Z2;uL!p66)pAY0d\+'Cuce\R"!9*mN!;6?k!jdU@JcC<$JcFX-J,~>
-"!.E>3;n.'NqiVTQA4u1"0d(en,<7gXEkNRpAY/0Yl=Y*]4(_L=T*OGZ2">!V>Y]@9mZ7-!T6*5
-rrFP?lMgnMW9aHbgNpR2rrLi`rVloY3V!+Sc@:E's8V55rH\HtrVln5Z@W%,s+14-s*t~>
-"!.E>3;n.'NqiVTQA4u1"0d(en,<7gXEkNRpAY/0Yl=Y*]4(_L=T*OGZ2">!V>Y]@9mZ7-!T6*5
-rrFP?lMgnMW9aHbgNpR2rrLi`rVloY3V!+Sc@:E's8V55rH\HtrVln5Z@W%,s+14-s*t~>
-"!.E>3;n.'NqiVTQA4u1"0d(en,<7gXEkNRpAY/0Yl=Y*]4(_L=T*OGZ2">!V>Y]@9mZ7-!T6*5
-rrFP?lMgnMW9aHbgNpR2rrLi`rVloY3V!+Sc@:E's8V55rH\HtrVln5Z@W%,s+14-s*t~>
-"!.E>Fn>V6QA4o/!A3d;rrFG?pAY/0Yl=Y*]4(_L\aTP"fm1^.rrW1;YP%nr..lg)!RjX#rrKB?
-rVloY3V*1UdsK?QFR&nK;Z6UqU](2o_KOsjs+13$s5<p-~>
-"!.E>Fn>V6QA4o/!A3d;rrFG?pAY/0Yl=Y*]4(_L\aTP"fm1^.rrW1;YP%nr..lg)!RjX#rrKB?
-rVloY3V*1UdsK?QFR&nK;Z6UqU](2o_KOsjs+13$s5<p-~>
-"!.E>Fn>V6QA4o/!A3d;rrFG?pAY/0Yl=Y*]4(_L\aTP"fm1^.rrW1;YP%nr..lg)!RjX#rrKB?
-rVloY3V*1UdsK?QFR&nK;Z6UqU](2o_KOsjs+13$s5<p-~>
-"!.E>Fo)+<VuB<p=9&;dL5\bu?2jj(S,Q%\A,Q?-/arT:!@@L6rsdIoh#HGJd/RUdBM2!LoD\j+
-?1.^nrZD%;!*T:o"Ju.u.-LS&!3?,!!)<Gc&@)98@/nYJ9=Os$<^%9l9>1-#!WHO+rs")2s5QaF
-V>gK%nk1e^92!h8j#P!U9*!]@rs@Uudf9?f>5QH?p\t7gd"24Js+14.s*t~>
-"!.E>Fo)+<VuB<p=9&;dL5\bu?2jj(S,Q%\A,Q?-/arT:!@@L6rsdIoh#HGJd/RUdBM2!LoD\j+
-?1.^nrZD%;!*T:o"Ju.u.-LS&!3?,!!)<Gc&@)98@/nYJ9=Os$<^%9l9>1-#!WHO+rs")2s5QaF
-V>gK%nk1e^92!h8j#P!U9*!]@rs@Uudf9?f>5QH?p\t7gd"24Js+14.s*t~>
-"!.E>Fo)+<VuB<p=9&;dL5\bu?2jj(S,Q%\A,Q?-/arT:!@@L6rsdIoh#HGJd/RUdBM2!LoD\j+
-?1.^nrZD%;!*T:o"Ju.u.-LS&!3?,!!)<Gc&@)98@/nYJ9=Os$<^%9l9>1-#!WHO+rs")2s5QaF
-V>gK%nk1e^92!h8j#P!U9*!]@rs@Uudf9?f>5QH?p\t7gd"24Js+14.s*t~>
-"!.E>(&ffgmf3<kIf@_'``2u((m`Rs^g$i5M>km']41a=!A3d;rrFG?p&>IscMuQcs8QRQ\'`Tr
-L%YHIj&b4-rrN*@qu6ZGrm:k!Y5]n0rm:jp[JreDrm;:"]`6A3=4,E7_uJ2f4OMREq#:Bn+8u3D
-:!`k7d=?cHrsJ\OO]TrXo`*qYAcC'X:[RuX!VbILrr^mPb#8!6!DUpls+13$s5<p-~>
-"!.E>(&ffgmf3<kIf@_'``2u((m`Rs^g$i5M>km']41a=!A3d;rrFG?p&>IscMuQcs8QRQ\'`Tr
-L%YHIj&b4-rrN*@qu6ZGrm:k!Y5]n0rm:jp[JreDrm;:"]`6A3=4,E7_uJ2f4OMREq#:Bn+8u3D
-:!`k7d=?cHrsJ\OO]TrXo`*qYAcC'X:[RuX!VbILrr^mPb#8!6!DUpls+13$s5<p-~>
-"!.E>(&ffgmf3<kIf@_'``2u((m`Rs^g$i5M>km']41a=!A3d;rrFG?p&>IscMuQcs8QRQ\'`Tr
-L%YHIj&b4-rrN*@qu6ZGrm:k!Y5]n0rm:jp[JreDrm;:"]`6A3=4,E7_uJ2f4OMREq#:Bn+8u3D
-:!`k7d=?cHrsJ\OO]TrXo`*qYAcC'X:[RuX!VbILrr^mPb#8!6!DUpls+13$s5<p-~>
-"!.E>D>ro*rr<"nIfAsJoC;jHIJNpCju<=#M#R#Idm*g2!A3d;rrFG?p&>J%a8XI[s8V`Yr;Zf'
-C%_K,e4B!,!WF2<rrD`koE9K1s!Zt-rrdSCruh:>rs`nKs7mi/s8QrHs8UP>p&>9q+9/Bms%Ui=
-rrJ[@r;Qf&C]487j#-H-rrFt?nc&g9;ZHc1*>SMP!DUpls+13$s5<p-~>
-"!.E>D>ro*rr<"nIfAsJoC;jHIJNpCju<=#M#R#Idm*g2!A3d;rrFG?p&>J%a8XI[s8V`Yr;Zf'
-C%_K,e4B!,!WF2<rrD`koE9K1s!Zt-rrdSCruh:>rs`nKs7mi/s8QrHs8UP>p&>9q+9/Bms%Ui=
-rrJ[@r;Qf&C]487j#-H-rrFt?nc&g9;ZHc1*>SMP!DUpls+13$s5<p-~>
-"!.E>D>ro*rr<"nIfAsJoC;jHIJNpCju<=#M#R#Idm*g2!A3d;rrFG?p&>J%a8XI[s8V`Yr;Zf'
-C%_K,e4B!,!WF2<rrD`koE9K1s!Zt-rrdSCruh:>rs`nKs7mi/s8QrHs8UP>p&>9q+9/Bms%Ui=
-rrJ[@r;Qf&C]487j#-H-rrFt?nc&g9;ZHc1*>SMP!DUpls+13$s5<p-~>
-"!.E>Fo)+<Q2W071uA7uLAq2Uju<=#(B#W]?2ad(/arT:!@@L4rrOq7-MdZBZYB.5!W"&-rrN*@
-r;QfS2?#!,'V,1Oo`"jnGbtE_rVlg"Dls'8,PqE@dn064#Q5bEV0Dr6ci3qFSUgY<!O6G=rrM.?
-rVlmTkjeZRb#83<!$2";!DUpls+13$s5<p-~>
-"!.E>Fo)+<Q2W071uA7uLAq2Uju<=#(B#W]?2ad(/arT:!@@L4rrOq7-MdZBZYB.5!W"&-rrN*@
-r;QfS2?#!,'V,1Oo`"jnGbtE_rVlg"Dls'8,PqE@dn064#Q5bEV0Dr6ci3qFSUgY<!O6G=rrM.?
-rVlmTkjeZRb#83<!$2";!DUpls+13$s5<p-~>
-"!.E>Fo)+<Q2W071uA7uLAq2Uju<=#(B#W]?2ad(/arT:!@@L4rrOq7-MdZBZYB.5!W"&-rrN*@
-r;QfS2?#!,'V,1Oo`"jnGbtE_rVlg"Dls'8,PqE@dn064#Q5bEV0Dr6ci3qFSUgY<!O6G=rrM.?
-rVlmTkjeZRb#83<!$2";!DUpls+13$s5<p-~>
-"!.E>Fo21>jkTk8"R[oBQA5D="QhZCNfNo7!A3d;rrFG?o`"tIi[4[)!S-Q9rrKH?rVlo1ao)/>
-^0^1+!rc-@rVm0Ym/R+I?(CpC\,QC1GbtE_rVlg"Dls'8,PqEDdn0T>e*Zu2#Q5b5OaQ._ci3qF
-SUgY<#I/(Es2t)r3W8sY2!FK0!Qn==rr=)<rrUech1>TWs+14.s*t~>
-"!.E>Fo21>jkTk8"R[oBQA5D="QhZCNfNo7!A3d;rrFG?o`"tIi[4[)!S-Q9rrKH?rVlo1ao)/>
-^0^1+!rc-@rVm0Ym/R+I?(CpC\,QC1GbtE_rVlg"Dls'8,PqEDdn0T>e*Zu2#Q5b5OaQ._ci3qF
-SUgY<#I/(Es2t)r3W8sY2!FK0!Qn==rr=)<rrUech1>TWs+14.s*t~>
-"!.E>Fo21>jkTk8"R[oBQA5D="QhZCNfNo7!A3d;rrFG?o`"tIi[4[)!S-Q9rrKH?rVlo1ao)/>
-^0^1+!rc-@rVm0Ym/R+I?(CpC\,QC1GbtE_rVlg"Dls'8,PqEDdn0T>e*Zu2#Q5b5OaQ._ci3qF
-SUgY<#I/(Es2t)r3W8sY2!FK0!Qn==rr=)<rrUech1>TWs+14.s*t~>
-"!.E>8H#(]XT-4grga1[IfG^grr3,`2ugF@rga%hrr3,?SK*iqrr3,<SJRZup&>)DQ?rQ1!M>AN
-SH4YDrVlm#2uN[U*U<Y*i&pu<$%SG7SVAkhs!V@USHOD^s)sq3SHO>bs7mo9rrqJ)SXk#Wq>Us(
-Boe[jKQQ2Qn=<r_S`TkN#L@afST*rU3W8sY2!FK0!T%ttSH*F'rrHl?JcC<$JcFX-J,~>
-"!.E>8H#(]XT-4grga1[IfG^grr3,`2ugF@rga%hrr3,?SK*iqrr3,<SJRZup&>)DQ?rQ1!M>AN
-SH4YDrVlm#2uN[U*U<Y*i&pu<$%SG7SVAkhs!V@USHOD^s)sq3SHO>bs7mo9rrqJ)SXk#Wq>Us(
-Boe[jKQQ2Qn=<r_S`TkN#L@afST*rU3W8sY2!FK0!T%ttSH*F'rrHl?JcC<$JcFX-J,~>
-"!.E>8H#(]XT-4grga1[IfG^grr3,`2ugF@rga%hrr3,?SK*iqrr3,<SJRZup&>)DQ?rQ1!M>AN
-SH4YDrVlm#2uN[U*U<Y*i&pu<$%SG7SVAkhs!V@USHOD^s)sq3SHO>bs7mo9rrqJ)SXk#Wq>Us(
-Boe[jKQQ2Qn=<r_S`TkN#L@afST*rU3W8sY2!FK0!T%ttSH*F'rrHl?JcC<$JcFX-J,~>
-!Zh<ir-ng3s8Tn6IftQ,s2r4Xrrhn]s8TS-IfPT0rrBD)IfP`4rrB8%IfPl.rrA)WrrAemIfQ>C
-rrIY>r;QbWlMgqTJ$&\L#`4%\YeSH_POSR$!5ng9!.b&u"NUQBr/pgT"586Sd.dPGn"'LY[+PEY
-lhu;5h#76Waa\g!s7)TWrrJP[nG`L>rI4h<rr3&;J(]DQJcC<$huA3~>
-!Zh<ir-ng3s8Tn6IftQ,s2r4Xrrhn]s8TS-IfPT0rrBD)IfP`4rrB8%IfPl.rrA)WrrAemIfQ>C
-rrIY>r;QbWlMgqTJ$&\L#`4%\YeSH_POSR$!5ng9!.b&u"NUQBr/pgT"586Sd.dPGn"'LY[+PEY
-lhu;5h#76Waa\g!s7)TWrrJP[nG`L>rI4h<rr3&;J(]DQJcC<$huA3~>
-!Zh<ir-ng3s8Tn6IftQ,s2r4Xrrhn]s8TS-IfPT0rrBD)IfP`4rrB8%IfPl.rrA)WrrAemIfQ>C
-rrIY>r;QbWlMgqTJ$&\L#`4%\YeSH_POSR$!5ng9!.b&u"NUQBr/pgT"586Sd.dPGn"'LY[+PEY
-lhu;5h#76Waa\g!s7)TWrrJP[nG`L>rI4h<rr3&;J(]DQJcC<$huA3~>
-!$.@)!U.7_rrLKtJcC<$JcFU,J,~>
-!$.@)!U.7_rrLKtJcC<$JcFU,J,~>
-!$.@)!U.7_rrLKtJcC<$JcFU,J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$2%<!VH<grrMlioD\pdn*g5QrrVf\rndYUo_[nQ"9.cXpAP!ln+6&K!VZ?grrW(rKA$8/oDJXg
-qX=1=rrMiio`#!en,'Hk!THTHrrG4Kqu6[UnU^^ks2P(h~>
-!$2%<!VH<grrMlioD\pdn*g5QrrVf\rndYUo_[nQ"9.cXpAP!ln+6&K!VZ?grrW(rKA$8/oDJXg
-qX=1=rrMiio`#!en,'Hk!THTHrrG4Kqu6[UnU^^ks2P(h~>
-!$2%<!VH<grrMlioD\pdn*g5QrrVf\rndYUo_[nQ"9.cXpAP!ln+6&K!VZ?grrW(rKA$8/oDJXg
-qX=1=rrMiio`#!en,'Hk!THTHrrG4Kqu6[UnU^^ks2P(h~>
-!$2(=!p)_mrVlqdOn//E",\Z;k5>5\CG#,LrrLpOmJd2k_<Lt+`@WZ`lMpn`/RS#I!I1I?rrL/?
-f`).EfDklc/Y1u&!pa0mo`"uX/]ZZH!TE_;rrLpOo)A\1qYpO9qu6]o,(]cFs2P(h~>
-!$2(=!p)_mrVlqdOn//E",\Z;k5>5\CG#,LrrLpOmJd2k_<Lt+`@WZ`lMpn`/RS#I!I1I?rrL/?
-f`).EfDklc/Y1u&!pa0mo`"uX/]ZZH!TE_;rrLpOo)A\1qYpO9qu6]o,(]cFs2P(h~>
-!$2(=!p)_mrVlqdOn//E",\Z;k5>5\CG#,LrrLpOmJd2k_<Lt+`@WZ`lMpn`/RS#I!I1I?rrL/?
-f`).EfDklc/Y1u&!pa0mo`"uX/]ZZH!TE_;rrLpOo)A\1qYpO9qu6]o,(]cFs2P(h~>
-"s*aDh09a\r;Qh\Qh0hK!B0*,rrG1?mJd2k_<Lt&*WQ/%MsLBIGbtH?pRR)lrrGR?i;WoBL*<S@
-rrH*?li-uIiUd'M_-?d9!Ed>=rrW+#a+=8As2Y.i~>
-"s*aDh09a\r;Qh\Qh0hK!B0*,rrG1?mJd2k_<Lt&*WQ/%MsLBIGbtH?pRR)lrrGR?i;WoBL*<S@
-rrH*?li-uIiUd'M_-?d9!Ed>=rrW+#a+=8As2Y.i~>
-"s*aDh09a\r;Qh\Qh0hK!B0*,rrG1?mJd2k_<Lt&*WQ/%MsLBIGbtH?pRR)lrrGR?i;WoBL*<S@
-rrH*?li-uIiUd'M_-?d9!Ed>=rrW+#a+=8As2Y.i~>
-"s*a!J\Fq)qu6_[OS\VL!B0*=rr^-*R/$X[!5JN##d+.,a-\'+R'?Si!4`#q!42V'!M-:jrrH??
-rr3,W`rH(Arg3u*s8TOps8V)prVm0Es8TdDs8Sj]Yl4S&XRlFY!6bBA$(RBM_g&$Xs5Z0;rrE#r
-Qiu"?s.o&]Qil%As7ZDY"5NqVo)4pXi;`iGrg3rB7G%S*R$c5!rrVhrh#<ZClMpnGrg3cHWqlJj
-"R:fBEiSg4"4rp-jSf)YeGYd4rrT]tpAY'lc2O(5o;_ijao7Y5UAt8AQnilQV>gJp_Z#o6WW3"A
-fX$s4XT/=@Qm7?QYl=Y&\GhiqZi0n).e<H9!Tl<;rrLq?JcC<$a8^Y~>
-"s*a!J\Fq)qu6_[OS\VL!B0*=rr^-*R/$X[!5JN##d+.,a-\'+R'?Si!4`#q!42V'!M-:jrrH??
-rr3,W`rH(Arg3u*s8TOps8V)prVm0Es8TdDs8Sj]Yl4S&XRlFY!6bBA$(RBM_g&$Xs5Z0;rrE#r
-Qiu"?s.o&]Qil%As7ZDY"5NqVo)4pXi;`iGrg3rB7G%S*R$c5!rrVhrh#<ZClMpnGrg3cHWqlJj
-"R:fBEiSg4"4rp-jSf)YeGYd4rrT]tpAY'lc2O(5o;_ijao7Y5UAt8AQnilQV>gJp_Z#o6WW3"A
-fX$s4XT/=@Qm7?QYl=Y&\GhiqZi0n).e<H9!Tl<;rrLq?JcC<$a8^Y~>
-"s*a!J\Fq)qu6_[OS\VL!B0*=rr^-*R/$X[!5JN##d+.,a-\'+R'?Si!4`#q!42V'!M-:jrrH??
-rr3,W`rH(Arg3u*s8TOps8V)prVm0Es8TdDs8Sj]Yl4S&XRlFY!6bBA$(RBM_g&$Xs5Z0;rrE#r
-Qiu"?s.o&]Qil%As7ZDY"5NqVo)4pXi;`iGrg3rB7G%S*R$c5!rrVhrh#<ZClMpnGrg3cHWqlJj
-"R:fBEiSg4"4rp-jSf)YeGYd4rrT]tpAY'lc2O(5o;_ijao7Y5UAt8AQnilQV>gJp_Z#o6WW3"A
-fX$s4XT/=@Qm7?QYl=Y&\GhiqZi0n).e<H9!Tl<;rrLq?JcC<$a8^Y~>
-"s*`o]`1dPqYpS`K_59F2Wju<"1Ek"n,E=f]Rg'8%"b>U]S%>KKVAGGZ[r+/!J7HPrrEN]rr3:/
-_>j(QI_5WWK)UE/J\(kRdf9?VB)V`0*W,j<O`W_arrFipre(B(bl<e(KEcrfV>pSV3;idVL])l/
-J(ai;IK"m%Ibk$RrIb9%ir4?(KEH\cqL&9q#C[iJs6,,1M#RDUiu<IHKEHYom!\kd!e,arq>UTZ
-XT*=@p&>-?KJL1=rrL`$rIb0.rVm'u!9sO`c@>hH"FQ[<aajAD%"joHab23XKTuN:_1;N<'S<"X
-IS>?HKS$$"]n@GLKV8AFZ[r+/!J7HQrrFV?qYpTY2Z*LTh*6JjJcEdjJ,~>
-"s*`o]`1dPqYpS`K_59F2Wju<"1Ek"n,E=f]Rg'8%"b>U]S%>KKVAGGZ[r+/!J7HPrrEN]rr3:/
-_>j(QI_5WWK)UE/J\(kRdf9?VB)V`0*W,j<O`W_arrFipre(B(bl<e(KEcrfV>pSV3;idVL])l/
-J(ai;IK"m%Ibk$RrIb9%ir4?(KEH\cqL&9q#C[iJs6,,1M#RDUiu<IHKEHYom!\kd!e,arq>UTZ
-XT*=@p&>-?KJL1=rrL`$rIb0.rVm'u!9sO`c@>hH"FQ[<aajAD%"joHab23XKTuN:_1;N<'S<"X
-IS>?HKS$$"]n@GLKV8AFZ[r+/!J7HQrrFV?qYpTY2Z*LTh*6JjJcEdjJ,~>
-"s*`o]`1dPqYpS`K_59F2Wju<"1Ek"n,E=f]Rg'8%"b>U]S%>KKVAGGZ[r+/!J7HPrrEN]rr3:/
-_>j(QI_5WWK)UE/J\(kRdf9?VB)V`0*W,j<O`W_arrFipre(B(bl<e(KEcrfV>pSV3;idVL])l/
-J(ai;IK"m%Ibk$RrIb9%ir4?(KEH\cqL&9q#C[iJs6,,1M#RDUiu<IHKEHYom!\kd!e,arq>UTZ
-XT*=@p&>-?KJL1=rrL`$rIb0.rVm'u!9sO`c@>hH"FQ[<aajAD%"joHab23XKTuN:_1;N<'S<"X
-IS>?HKS$$"]n@GLKV8AFZ[r+/!J7HQrrFV?qYpTY2Z*LTh*6JjJcEdjJ,~>
-!$2%<!Dgu9rr=)3rrG%?qu6[Kn,E=fI@pN=!URQ"rrG1?rVln7Yl=Y'k/I<!!N!+$rs;oGF(M&\
-s8Q$?rr3M'HN-Ucs8TQ?s8Rm]$XStnrrM%?rVlmQR/[*pJ=QWfo`+sD9;V[gj>d);!$2%<"D>1C
-(pX)?"(&_A*W?!?_!:k?rVlsoch&XbrrU.ifDbdNP_f>=!okQBrr3'WkhAE&rrG^@p&>&5Wq65k
-@CuO=!O6J>rr=)<rs$32p](8dIK'6L*WQ/+L&V)Qk;N>>!E@/=rrIk?rr3;U8,n$Kk5YJ+:]C@p
-45p/<!H#%>rrM9#rr3!Ko(r@eju3,:!Sotks+13js*t~>
-!$2%<!Dgu9rr=)3rrG%?qu6[Kn,E=fI@pN=!URQ"rrG1?rVln7Yl=Y'k/I<!!N!+$rs;oGF(M&\
-s8Q$?rr3M'HN-Ucs8TQ?s8Rm]$XStnrrM%?rVlmQR/[*pJ=QWfo`+sD9;V[gj>d);!$2%<"D>1C
-(pX)?"(&_A*W?!?_!:k?rVlsoch&XbrrU.ifDbdNP_f>=!okQBrr3'WkhAE&rrG^@p&>&5Wq65k
-@CuO=!O6J>rr=)<rs$32p](8dIK'6L*WQ/+L&V)Qk;N>>!E@/=rrIk?rr3;U8,n$Kk5YJ+:]C@p
-45p/<!H#%>rrM9#rr3!Ko(r@eju3,:!Sotks+13js*t~>
-!$2%<!Dgu9rr=)3rrG%?qu6[Kn,E=fI@pN=!URQ"rrG1?rVln7Yl=Y'k/I<!!N!+$rs;oGF(M&\
-s8Q$?rr3M'HN-Ucs8TQ?s8Rm]$XStnrrM%?rVlmQR/[*pJ=QWfo`+sD9;V[gj>d);!$2%<"D>1C
-(pX)?"(&_A*W?!?_!:k?rVlsoch&XbrrU.ifDbdNP_f>=!okQBrr3'WkhAE&rrG^@p&>&5Wq65k
-@CuO=!O6J>rr=)<rs$32p](8dIK'6L*WQ/+L&V)Qk;N>>!E@/=rrIk?rr3;U8,n$Kk5YJ+:]C@p
-45p/<!H#%>rrM9#rr3!Ko(r@eju3,:!Sotks+13js*t~>
-!$2%<!Dgu:rrHN?o`"qMk55/Z/ar]=!T%ep5lbQrrrG1?rVloOB`:9tFSGe;>;EA"rVlms2#]cO
-.=2"ddf9?VB)hnV^)"H2r;QfU4T59\1$no>"G!$B..mN="aHmDs5Z0;rr<r85m&%6ruM(<"(&_A
-*W,j;r?)"<"&7,6./j/H7G%P=!L/E>rrM.?rVlsVkhAE&rrG^@p&>&5Wq65k@CuO=!O6J>rr=)7
-rrJd@rr3*As8SE0r]pQH2ZE^W<65%<!JZp>rrgnCs*gR=rrLA?rr3!\iVicWg1^IO!-A,=!@m[:
-rrM7?qu6]Q5Crics2Y.i~>
-!$2%<!Dgu:rrHN?o`"qMk55/Z/ar]=!T%ep5lbQrrrG1?rVloOB`:9tFSGe;>;EA"rVlms2#]cO
-.=2"ddf9?VB)hnV^)"H2r;QfU4T59\1$no>"G!$B..mN="aHmDs5Z0;rr<r85m&%6ruM(<"(&_A
-*W,j;r?)"<"&7,6./j/H7G%P=!L/E>rrM.?rVlsVkhAE&rrG^@p&>&5Wq65k@CuO=!O6J>rr=)7
-rrJd@rr3*As8SE0r]pQH2ZE^W<65%<!JZp>rrgnCs*gR=rrLA?rr3!\iVicWg1^IO!-A,=!@m[:
-rrM7?qu6]Q5Crics2Y.i~>
-!$2%<!Dgu:rrHN?o`"qMk55/Z/ar]=!T%ep5lbQrrrG1?rVloOB`:9tFSGe;>;EA"rVlms2#]cO
-.=2"ddf9?VB)hnV^)"H2r;QfU4T59\1$no>"G!$B..mN="aHmDs5Z0;rr<r85m&%6ruM(<"(&_A
-*W,j;r?)"<"&7,6./j/H7G%P=!L/E>rrM.?rVlsVkhAE&rrG^@p&>&5Wq65k@CuO=!O6J>rr=)7
-rrJd@rr3*As8SE0r]pQH2ZE^W<65%<!JZp>rrgnCs*gR=rrLA?rr3!\iVicWg1^IO!-A,=!@m[:
-rrM7?qu6]Q5Crics2Y.i~>
-!$2%<!Dgu;rrQWBrUg*j2Wjo:!A3d=rrD9^gB"`srr3![ir&fVk5O*9Wd+=="'_Wb48o0[;m$#Q
-#OMI_df9?VB)V`0*W#d:i&pu<!AWs?rrdkBs![O=rrmYDs8V.>r;Qa:r7_;GruM(<"(&_A*W,j;
-r?)"<"&7,6./j/H7G%P=!L/E>rrM.?rVlsVkk_C[,QXh=p&>&5Wq65k@CuO=!O6J>rr=)7rrMYA
-rZhWqs8SF+rS%>3rr3!uaSl,>L6hi="P-*CI\-Q=!R4F>rrG4?r;[email protected]<H9!Tl<;
-rrLq?JcC<$a8^Y~>
-!$2%<!Dgu;rrQWBrUg*j2Wjo:!A3d=rrD9^gB"`srr3![ir&fVk5O*9Wd+=="'_Wb48o0[;m$#Q
-#OMI_df9?VB)V`0*W#d:i&pu<!AWs?rrdkBs![O=rrmYDs8V.>r;Qa:r7_;GruM(<"(&_A*W,j;
-r?)"<"&7,6./j/H7G%P=!L/E>rrM.?rVlsVkk_C[,QXh=p&>&5Wq65k@CuO=!O6J>rr=)7rrMYA
-rZhWqs8SF+rS%>3rr3!uaSl,>L6hi="P-*CI\-Q=!R4F>rrG4?r;[email protected]<H9!Tl<;
-rrLq?JcC<$a8^Y~>
-!$2%<!Dgu;rrQWBrUg*j2Wjo:!A3d=rrD9^gB"`srr3![ir&fVk5O*9Wd+=="'_Wb48o0[;m$#Q
-#OMI_df9?VB)V`0*W#d:i&pu<!AWs?rrdkBs![O=rrmYDs8V.>r;Qa:r7_;GruM(<"(&_A*W,j;
-r?)"<"&7,6./j/H7G%P=!L/E>rrM.?rVlsVkk_C[,QXh=p&>&5Wq65k@CuO=!O6J>rr=)7rrMYA
-rZhWqs8SF+rS%>3rr3!uaSl,>L6hi="P-*CI\-Q=!R4F>rrG4?r;[email protected]<H9!Tl<;
-rrLq?JcC<$a8^Y~>
-%NYTElKUsRlL"WOoPM5>p&>0dl7pcSrr38pl71QUs8S%KrosO!?iL'19%*"9C]Ag_rosNhDZ0S9
-'/fdh$!Y7@i>l@us'`V?l3Qq[s&m;*`t`4brr=):rs7u:2sU&8s"Wm>rsjRLs#T-(lBDdTs8W)9
->5eI$0`C8=pAb.5rVlt+^Afhal2tM?r@e-7"'3nD2u`(NC^AYmqs&uclMCP@3W8s[2!Egmro*tA
-qu-O&IgEmjs82*HBq4JRrVlq:#grYO#l!UeX6T]a[r;61!&4BO#$)#ps8T-Jro+(Hs8SaFrosLM
-rVm+4]^!gBs,`ECl3YL3s*bTflKZ/krr33rdH\>Ys*h!Il2e2-rr3#p,l7NA,Ph9;!rFA@r;Qii
-#YfmMJcF'rJ,~>
-%NYTElKUsRlL"WOoPM5>p&>0dl7pcSrr38pl71QUs8S%KrosO!?iL'19%*"9C]Ag_rosNhDZ0S9
-'/fdh$!Y7@i>l@us'`V?l3Qq[s&m;*`t`4brr=):rs7u:2sU&8s"Wm>rsjRLs#T-(lBDdTs8W)9
->5eI$0`C8=pAb.5rVlt+^Afhal2tM?r@e-7"'3nD2u`(NC^AYmqs&uclMCP@3W8s[2!Egmro*tA
-qu-O&IgEmjs82*HBq4JRrVlq:#grYO#l!UeX6T]a[r;61!&4BO#$)#ps8T-Jro+(Hs8SaFrosLM
-rVm+4]^!gBs,`ECl3YL3s*bTflKZ/krr33rdH\>Ys*h!Il2e2-rr3#p,l7NA,Ph9;!rFA@r;Qii
-#YfmMJcF'rJ,~>
-%NYTElKUsRlL"WOoPM5>p&>0dl7pcSrr38pl71QUs8S%KrosO!?iL'19%*"9C]Ag_rosNhDZ0S9
-'/fdh$!Y7@i>l@us'`V?l3Qq[s&m;*`t`4brr=):rs7u:2sU&8s"Wm>rsjRLs#T-(lBDdTs8W)9
->5eI$0`C8=pAb.5rVlt+^Afhal2tM?r@e-7"'3nD2u`(NC^AYmqs&uclMCP@3W8s[2!Egmro*tA
-qu-O&IgEmjs82*HBq4JRrVlq:#grYO#l!UeX6T]a[r;61!&4BO#$)#ps8T-Jro+(Hs8SaFrosLM
-rVm+4]^!gBs,`ECl3YL3s*bTflKZ/krr33rdH\>Ys*h!Il2e2-rr3#p,l7NA,Ph9;!rFA@r;Qii
-#YfmMJcF'rJ,~>
-!Zh<Nr%\CPs8SOkoD\fMr\=IJrr2tQr\=IQrr2tJr\=IXr;Qgi11L7_!-.un!,;B2!BaK`rrIJk
-rr3,5NrT,br\=J%rr3+%10(eqrVljiqu6Xfr\=V=s8Q6jrr3:mYlF_b1,=WJ\,QC/dUqP=rrDoo
-1'=ZYs%<7i"+JGnmJSdB])VfmrA"Jks8V!U1'FgqhuD@-1'>l&l!XJi"'k6gV>W.MZMa_%"dK_8
-s8UXI1&s31rrRrdd/O%FYPg3Yp](8mrA"BPrVm(C1@>,Am",-k"?b98s-3L<!(Qnd!a[WVrr2tR
-r\=aXs8RP>BJM>Hr;Qgj11C1^!-8&o!,2<1!CkZ<rrLS?qu6]C:&FqloeL<6s+13rs*t~>
-!Zh<Nr%\CPs8SOkoD\fMr\=IJrr2tQr\=IQrr2tJr\=IXr;Qgi11L7_!-.un!,;B2!BaK`rrIJk
-rr3,5NrT,br\=J%rr3+%10(eqrVljiqu6Xfr\=V=s8Q6jrr3:mYlF_b1,=WJ\,QC/dUqP=rrDoo
-1'=ZYs%<7i"+JGnmJSdB])VfmrA"Jks8V!U1'FgqhuD@-1'>l&l!XJi"'k6gV>W.MZMa_%"dK_8
-s8UXI1&s31rrRrdd/O%FYPg3Yp](8mrA"BPrVm(C1@>,Am",-k"?b98s-3L<!(Qnd!a[WVrr2tR
-r\=aXs8RP>BJM>Hr;Qgj11C1^!-8&o!,2<1!CkZ<rrLS?qu6]C:&FqloeL<6s+13rs*t~>
-!Zh<Nr%\CPs8SOkoD\fMr\=IJrr2tQr\=IQrr2tJr\=IXr;Qgi11L7_!-.un!,;B2!BaK`rrIJk
-rr3,5NrT,br\=J%rr3+%10(eqrVljiqu6Xfr\=V=s8Q6jrr3:mYlF_b1,=WJ\,QC/dUqP=rrDoo
-1'=ZYs%<7i"+JGnmJSdB])VfmrA"Jks8V!U1'FgqhuD@-1'>l&l!XJi"'k6gV>W.MZMa_%"dK_8
-s8UXI1&s31rrRrdd/O%FYPg3Yp](8mrA"BPrVm(C1@>,Am",-k"?b98s-3L<!(Qnd!a[WVrr2tR
-r\=aXs8RP>BJM>Hr;Qgj11C1^!-8&o!,2<1!CkZ<rrLS?qu6]C:&FqloeL<6s+13rs*t~>
-!$/$<"ip05s0lUqrrL'0a8Z1p62gfa/+NT<!F<J3rrGj@kPkRUIK'6Imk*c'!IgX(rrMb1r;Qe0
-r;6Ko@tFZ2s2G"g~>
-!$/$<"ip05s0lUqrrL'0a8Z1p62gfa/+NT<!F<J3rrGj@kPkRUIK'6Imk*c'!IgX(rrMb1r;Qe0
-r;6Ko@tFZ2s2G"g~>
-!$/$<"ip05s0lUqrrL'0a8Z1p62gfa/+NT<!F<J3rrGj@kPkRUIK'6Imk*c'!IgX(rrMb1r;Qe0
-r;6Ko@tFZ2s2G"g~>
-!$/$<"db13PDH-0rrMD.rK@8'p\t0oa*QJ3rrTu\jQHODaFF2Q!Ki-#rrIS?JcC<$SH"*~>
-!$/$<"db13PDH-0rrMD.rK@8'p\t0oa*QJ3rrTu\jQHODaFF2Q!Ki-#rrIS?JcC<$SH"*~>
-!$/$<"db13PDH-0rrMD.rK@8'p\t0oa*QJ3rrTu\jQHODaFF2Q!Ki-#rrIS?JcC<$SH"*~>
-!$/!;".k@+Wh04jiVeT5li$ha_US2W!P7(JrrC%;M#`Y#rrL$cJcC<$SH"*~>
-!$/!;".k@+Wh04jiVeT5li$ha_US2W!P7(JrrC%;M#`Y#rrL$cJcC<$SH"*~>
-!$/!;".k@+Wh04jiVeT5li$ha_US2W!P7(JrrC%;M#`Y#rrL$cJcC<$SH"*~>
-!$2";!d\!iJc>iPBN]t=s+13$s,R,0~>
-!$2";!d\!iJc>iPBN]t=s+13$s,R,0~>
-!$2";!d\!iJc>iPBN]t=s+13$s,R,0~>
-!$2%<"*pi_bhN-ufQmJr!GFXFrrGGskl1[N](l:-aMX^)JcC<$JcCf2J,~>
-!$2%<"*pi_bhN-ufQmJr!GFXFrrGGskl1[N](l:-aMX^)JcC<$JcCf2J,~>
-!$2%<"*pi_bhN-ufQmJr!GFXFrrGGskl1[N](l:-aMX^)JcC<$JcCf2J,~>
-!$2%<!DgtnrrL>?rr3#^i7%],i9'8'!I1I7rrKi?JcC<$JcCf2J,~>
-!$2%<!DgtnrrL>?rr3#^i7%],i9'8'!I1I7rrKi?JcC<$JcCf2J,~>
-!$2%<!DgtnrrL>?rr3#^i7%],i9'8'!I1I7rrKi?JcC<$JcCf2J,~>
-!$2%<!b/kArr2uhroFFJs8V`^mcEQnrr2ufroF.Drr2ueroF.Err3>ojlP[L;#gR`jlQI@"n;9O
-jlPk.rrqcNjluO/q#:fjq>^Kimf3=RqW?o$n,E=gkiM+-rrD9^jT+iMrrD6]jT+lNrs.]Jjm[Mk
-s8W&Z!;-9j!rK6?JcC<$JcCf2J,~>
-!$2%<!b/kArr2uhroFFJs8V`^mcEQnrr2ufroF.Drr2ueroF.Err3>ojlP[L;#gR`jlQI@"n;9O
-jlPk.rrqcNjluO/q#:fjq>^Kimf3=RqW?o$n,E=gkiM+-rrD9^jT+iMrrD6]jT+lNrs.]Jjm[Mk
-s8W&Z!;-9j!rK6?JcC<$JcCf2J,~>
-!$2%<!b/kArr2uhroFFJs8V`^mcEQnrr2ufroF.Drr2ueroF.Err3>ojlP[L;#gR`jlQI@"n;9O
-jlPk.rrqcNjluO/q#:fjq>^Kimf3=RqW?o$n,E=gkiM+-rrD9^jT+iMrrD6]jT+lNrs.]Jjm[Mk
-s8W&Z!;-9j!rK6?JcC<$JcCf2J,~>
-!$2(=#N*U%n,NFQJc7S:6.5e!BkoXd7b%J#GQ'N(9%Et'ErJ!-:Y5X,D)XC@TMY[gHoD</rsik&
-;`?XAh>c;<2`FX*MYR2b;p,.?^Kpm>8u4d32f[pYs&:a0rVloJ8,bFMHKbCW6N/nPJ*R'\4Z><@
-?D[\J3W:rBM=(?Cj'9[bJcC<$JcCi3J,~>
-!$2(=#N*U%n,NFQJc7S:6.5e!BkoXd7b%J#GQ'N(9%Et'ErJ!-:Y5X,D)XC@TMY[gHoD</rsik&
-;`?XAh>c;<2`FX*MYR2b;p,.?^Kpm>8u4d32f[pYs&:a0rVloJ8,bFMHKbCW6N/nPJ*R'\4Z><@
-?D[\J3W:rBM=(?Cj'9[bJcC<$JcCi3J,~>
-!$2(=#N*U%n,NFQJc7S:6.5e!BkoXd7b%J#GQ'N(9%Et'ErJ!-:Y5X,D)XC@TMY[gHoD</rsik&
-;`?XAh>c;<2`FX*MYR2b;p,.?^Kpm>8u4d32f[pYs&:a0rVloJ8,bFMHKbCW6N/nPJ*R'\4Z><@
-?D[\J3W:rBM=(?Cj'9[bJcC<$JcCi3J,~>
-!$2(=!c7q^rr3"kIfB?UmOnO*/AhGeju<=#NrK%]k^NPcQi@!keO]^gTE"r]6W!a]!$2%<%;\)^
-s8T]>s'rV>s3OI6rshuMs8Ti>s8P\[p&G&[KDtlOkqi;<!BK3>rrfR8s"Wm>rsXFJs![O>s0sGQ
-ruh:>rrI&?rr3&6!.0:sJcC<$OT0h~>
-!$2(=!c7q^rr3"kIfB?UmOnO*/AhGeju<=#NrK%]k^NPcQi@!keO]^gTE"r]6W!a]!$2%<%;\)^
-s8T]>s'rV>s3OI6rshuMs8Ti>s8P\[p&G&[KDtlOkqi;<!BK3>rrfR8s"Wm>rsXFJs![O>s0sGQ
-ruh:>rrI&?rr3&6!.0:sJcC<$OT0h~>
-!$2(=!c7q^rr3"kIfB?UmOnO*/AhGeju<=#NrK%]k^NPcQi@!keO]^gTE"r]6W!a]!$2%<%;\)^
-s8T]>s'rV>s3OI6rshuMs8Ti>s8P\[p&G&[KDtlOkqi;<!BK3>rrfR8s"Wm>rsXFJs![O>s0sGQ
-ruh:>rrI&?rr3&6!.0:sJcC<$OT0h~>
-!$2(=#Hi'&pAb/b7fJDNKeECkLAq2Uju<=#Nr/hWKpVf="P$'CI@pN=!R+C=rr=)<rrHr?rr389
-@K0iJs8UG>p\tOub5_LV?2spsdf07IR=kM=!U2E=rrG.?qu6[Om/I"fJ=QWfo`"jnGbtE_NW+qC
-5-=kbmtYnkJcC<$JcCi3J,~>
-!$2(=#Hi'&pAb/b7fJDNKeECkLAq2Uju<=#Nr/hWKpVf="P$'CI@pN=!R+C=rr=)<rrHr?rr389
-@K0iJs8UG>p\tOub5_LV?2spsdf07IR=kM=!U2E=rrG.?qu6[Om/I"fJ=QWfo`"jnGbtE_NW+qC
-5-=kbmtYnkJcC<$JcCi3J,~>
-!$2(=#Hi'&pAb/b7fJDNKeECkLAq2Uju<=#Nr/hWKpVf="P$'CI@pN=!R+C=rr=)<rrHr?rr389
-@K0iJs8UG>p\tOub5_LV?2spsdf07IR=kM=!U2E=rrG.?qu6[Om/I"fJ=QWfo`"jnGbtE_NW+qC
-5-=kbmtYnkJcC<$JcCi3J,~>
-!$2%<#+^SDs8S]\rJguSs-AE=rrhICs,N-:rrIh?rr3,O8H4+1rr3#C;#UCo*W?!=Cp<p=#eOOF
-\p8:8G-L`@#uf"Hs1_k>s%:`=rrJO?rr3#`1]@=S3TL#:!AWs?rrdkBs![O=rrdSCrud="NWn2;
-s6k`>JcC<$JcCf2J,~>
-!$2%<#+^SDs8S]\rJguSs-AE=rrhICs,N-:rrIh?rr3,O8H4+1rr3#C;#UCo*W?!=Cp<p=#eOOF
-\p8:8G-L`@#uf"Hs1_k>s%:`=rrJO?rr3#`1]@=S3TL#:!AWs?rrdkBs![O=rrdSCrud="NWn2;
-s6k`>JcC<$JcCf2J,~>
-!$2%<#+^SDs8S]\rJguSs-AE=rrhICs,N-:rrIh?rr3,O8H4+1rr3#C;#UCo*W?!=Cp<p=#eOOF
-\p8:8G-L`@#uf"Hs1_k>s%:`=rrJO?rr3#`1]@=S3TL#:!AWs?rrdkBs![O=rrdSCrud="NWn2;
-s6k`>JcC<$JcCf2J,~>
-!$2%<!Dgu>rrJa@qu6\_LAq2Uju<=#NrK%]k^NPcQi@!keO]^gTE"r]6W!a]!$2%<!Go">rs-/E
-s-JqMX1J3.!EOLFrs;WHs8Ti>s8P^>rr3"eKDtlOkqi;<!BK3>rrfR8s"Wm>rsXFJs![O>s0sGQ
-ruh:9rrKi?JcC<$JcCf2J,~>
-!$2%<!Dgu>rrJa@qu6\_LAq2Uju<=#NrK%]k^NPcQi@!keO]^gTE"r]6W!a]!$2%<!Go">rs-/E
-s-JqMX1J3.!EOLFrs;WHs8Ti>s8P^>rr3"eKDtlOkqi;<!BK3>rrfR8s"Wm>rsXFJs![O>s0sGQ
-ruh:9rrKi?JcC<$JcCf2J,~>
-!$2%<!Dgu>rrJa@qu6\_LAq2Uju<=#NrK%]k^NPcQi@!keO]^gTE"r]6W!a]!$2%<!Go">rs-/E
-s-JqMX1J3.!EOLFrs;WHs8Ti>s8P^>rr3"eKDtlOkqi;<!BK3>rrfR8s"Wm>rsXFJs![O>s0sGQ
-ruh:9rrKi?JcC<$JcCf2J,~>
-!$2%<!Dgu>rrMD9r\jsKs8SC>rr3,`2ui#ar\jsPec4`Or\kNefDjlJ2`F*s;#gQC2[23Qs8Qo>
-rr3,[email protected]\jgur;Qd"2u`g`g/U'j>EbER9%*_=%%2bJs&:`]2i[k;e49Ks"FB;3dR*pl%"IRB
-coj<HF'b^CcT1t`!3#kr!PVlks+13$s,[21~>
-!$2%<!Dgu>rrMD9r\jsKs8SC>rr3,`2ui#ar\jsPec4`Or\kNefDjlJ2`F*s;#gQC2[23Qs8Qo>
-rr3,[email protected]\jgur;Qd"2u`g`g/U'j>EbER9%*_=%%2bJs&:`]2i[k;e49Ks"FB;3dR*pl%"IRB
-coj<HF'b^CcT1t`!3#kr!PVlks+13$s,[21~>
-!$2%<!Dgu>rrMD9r\jsKs8SC>rr3,`2ui#ar\jsPec4`Or\kNefDjlJ2`F*s;#gQC2[23Qs8Qo>
-rr3,[email protected]\jgur;Qd"2u`g`g/U'j>EbER9%*_=%%2bJs&:`]2i[k;e49Ks"FB;3dR*pl%"IRB
-coj<HF'b^CcT1t`!3#kr!PVlks+13$s,[21~>
-!$2%<#44f!56(ZRroF:Fs8V`^rr3-!lMpnRroF.Drr2ueroF.Err38mjlP\%mJm4SroF:Ks8VT_
-rr3,rn,IL3roF0ZH2[aDc8Y_%#jUO5lh0fJm/$_]"SD9bs60ID!:^!f!9jFD!:g'g!9a@C!:p-h
-#Nk.0nF?5Ps8D$`o`+qH*Dc*Ss+13$s,[21~>
-!$2%<#44f!56(ZRroF:Fs8V`^rr3-!lMpnRroF.Drr2ueroF.Err38mjlP\%mJm4SroF:Ks8VT_
-rr3,rn,IL3roF0ZH2[aDc8Y_%#jUO5lh0fJm/$_]"SD9bs60ID!:^!f!9jFD!:g'g!9a@C!:p-h
-#Nk.0nF?5Ps8D$`o`+qH*Dc*Ss+13$s,[21~>
-!$2%<#44f!56(ZRroF:Fs8V`^rr3-!lMpnRroF.Drr2ueroF.Err38mjlP\%mJm4SroF:Ks8VT_
-rr3,rn,IL3roF0ZH2[aDc8Y_%#jUO5lh0fJm/$_]"SD9bs60ID!:^!f!9jFD!:g'g!9a@C!:p-h
-#Nk.0nF?5Ps8D$`o`+qH*Dc*Ss+13$s,[21~>
-!$/lT!I(UDhuT^&rVloB:kAXts+13$s3Udr~>
-!$/lT!I(UDhuT^&rVloB:kAXts+13$s3Udr~>
-!$/lT!I(UDhuT^&rVloB:kAXts+13$s3Udr~>
-!$/iS!-8'$!-\;?!)nIKJcC<$JcF'rJ,~>
-!$/iS!-8'$!-\;?!)nIKJcC<$JcF'rJ,~>
-!$/iS!-8'$!-\;?!)nIKJcC<$JcF'rJ,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-"!.FAao7+sNW/qY`R48V"0^kcRDo1.QN,gOJcC<$JcC<$iW"E~>
-"!.FAao7+sNW/qY`R48V"0^kcRDo1.QN,gOJcC<$JcC<$iW"E~>
-"!.FAao7+sNW/qY`R48V"0^kcRDo1.QN,gOJcC<$JcC<$iW"E~>
-"!.EcIf>N8P(N`6b'V_2rrZ3AqBEoY"!.ENAqBu5s+13$s5F!.~>
-"!.EcIf>N8P(N`6b'V_2rrZ3AqBEoY"!.ENAqBu5s+13$s5F!.~>
-"!.EcIf>N8P(N`6b'V_2rrZ3AqBEoY"!.ENAqBu5s+13$s5F!.~>
-"!.E>FoMCApEon>!mbW@o`#"land4#rrX;A[q:3kJcC<$JcF^/J,~>
-"!.E>FoMCApEon>!mbW@o`#"land4#rrX;A[q:3kJcC<$JcF^/J,~>
-"!.E>FoMCApEon>!mbW@o`#"land4#rrX;A[q:3kJcC<$JcF^/J,~>
-"!.F0jSo/[8C[V<!o$B@p&>9Qo`!>>s.-4irrh.os-Btirrgnos,aejrs6qrs,"Pks57Vjrr?j6
-1&u7krrYqM13WZs!+#RZ!.FhG"4R;?iIV#[s+13$s5F!.~>
-"!.F0jSo/[8C[V<!o$B@p&>9Qo`!>>s.-4irrh.os-Btirrgnos,aejrs6qrs,"Pks57Vjrr?j6
-1&u7krrYqM13WZs!+#RZ!.FhG"4R;?iIV#[s+13$s5F!.~>
-"!.F0jSo/[8C[V<!o$B@p&>9Qo`!>>s.-4irrh.os-Btirrgnos,aejrs6qrs,"Pks57Vjrr?j6
-1&u7krrYqM13WZs!+#RZ!.FhG"4R;?iIV#[s+13$s5F!.~>
-!$2%<!r>IAqu6]a0CSoAKpVf="P$'CI@pN='[0DRFK#6>hA08oCp<s>fgPl?E3K9+!NL>Brs'\0
-[oNJ.@D2[*!M"jps+13$s+14(s*t~>
-!$2%<!r>IAqu6]a0CSoAKpVf="P$'CI@pN='[0DRFK#6>hA08oCp<s>fgPl?E3K9+!NL>Brs'\0
-[oNJ.@D2[*!M"jps+13$s+14(s*t~>
-!$2%<!r>IAqu6]a0CSoAKpVf="P$'CI@pN='[0DRFK#6>hA08oCp<s>fgPl?E3K9+!NL>Brs'\0
-[oNJ.@D2[*!M"jps+13$s+14(s*t~>
-!$2(=!pX(@qYpTT4R`:NKpVf="P$'CI>RsX'X(@5FK#5r5/^V(Cp<s>fgPl?A%DU=!OHM>rs'\E
-aAr9?;m$&R!K28Ts+13$s+14(s*t~>
-!$2(=!pX(@qYpTT4R`:NKpVf="P$'CI>RsX'X(@5FK#5r5/^V(Cp<s>fgPl?A%DU=!OHM>rs'\E
-aAr9?;m$&R!K28Ts+13$s+14(s*t~>
-!$2(=!pX(@qYpTT4R`:NKpVf="P$'CI>RsX'X(@5FK#5r5/^V(Cp<s>fgPl?A%DU=!OHM>rs'\E
-aAr9?;m$&R!K28Ts+13$s+14(s*t~>
-"WdXCiHE09rrUPJp@&"^KpVf="P$'CI4>.]'JrYdFK!D[s28(?Cp<s>fgPl?A%DU=%'s[Js34F>
-aAr9?;`+G=!1\W?JcC<$JcFI(J,~>
-"WdXCiHE09rrUPJp@&"^KpVf="P$'CI4>.]'JrYdFK!D[s28(?Cp<s>fgPl?A%DU=%'s[Js34F>
-aAr9?;`+G=!1\W?JcC<$JcFI(J,~>
-"WdXCiHE09rrUPJp@&"^KpVf="P$'CI4>.]'JrYdFK!D[s28(?Cp<s>fgPl?A%DU=%'s[Js34F>
-aAr9?;`+G=!1\W?JcC<$JcFI(J,~>
-"<IO"K"LmZ!lf6Amf*TIQiI*^L.M>mTDnj)bY\=]C2NA<`**+VYlFaV70!9s\c2U;ZYBI>52ZC]
-<WE(tb45K5pS#?Qs+13$s+146s*t~>
-"<IO"K"LmZ!lf6Amf*TIQiI*^L.M>mTDnj)bY\=]C2NA<`**+VYlFaV70!9s\c2U;ZYBI>52ZC]
-<WE(tb45K5pS#?Qs+13$s+146s*t~>
-"<IO"K"LmZ!lf6Amf*TIQiI*^L.M>mTDnj)bY\=]C2NA<`**+VYlFaV70!9s\c2U;ZYBI>52ZC]
-<WE(tb45K5pS#?Qs+13$s+146s*t~>
-"!.E>4oL$;QN.!%J(j;i$,D(EKS*o.s*^O=rtN[Rs)_,ss8U#?s(knmKQ&0Bs0%"QKFEF;s0*Ve
-KP)jJs/(DIKE/:MrrVEb;1\aus+13$s60K5~>
-"!.E>4oL$;QN.!%J(j;i$,D(EKS*o.s*^O=rtN[Rs)_,ss8U#?s(knmKQ&0Bs0%"QKFEF;s0*Ve
-KP)jJs/(DIKE/:MrrVEb;1\aus+13$s60K5~>
-"!.E>4oL$;QN.!%J(j;i$,D(EKS*o.s*^O=rtN[Rs)_,ss8U#?s(knmKQ&0Bs0%"QKFEF;s0*Ve
-KP)jJs/(DIKE/:MrrVEb;1\aus+13$s60K5~>
-!Zh<rr0RVbs8U<pli.7-R$aGp8H6ibrr3,d\GsV)rr3)`]`5qKQiqA:s8TJ*Qisnus''RDQiq#A
-s8T8$QiOknrrVn]\Ujd3s+13$s60K5~>
-!Zh<rr0RVbs8U<pli.7-R$aGp8H6ibrr3,d\GsV)rr3)`]`5qKQiqA:s8TJ*Qisnus''RDQiq#A
-s8T8$QiOknrrVn]\Ujd3s+13$s60K5~>
-!Zh<rr0RVbs8U<pli.7-R$aGp8H6ibrr3,d\GsV)rr3)`]`5qKQiqA:s8TJ*Qisnus''RDQiq#A
-s8T8$QiOknrrVn]\Ujd3s+13$s60K5~>
-!$1"t!NEL+rrLY@li.!t@JKj'cgC`3!Tqsas+13$s+13us*t~>
-!$1"t!NEL+rrLY@li.!t@JKj'cgC`3!Tqsas+13$s+13us*t~>
-!$1"t!NEL+rrLY@li.!t@JKj'cgC`3!Tqsas+13$s+13us*t~>
-!$1"t!U4S&/HJH"li."Wj+75]s+13$s2+ed~>
-!$1"t!U4S&/HJH"li."Wj+75]s+13$s2+ed~>
-!$1"t!U4S&/HJH"li."Wj+75]s+13$s2+ed~>
-!$2(="8MHXoB-&Qp&=C[nU^_$rr`#do(.G4JcDABJ,~>
-!$2(="8MHXoB-&Qp&=C[nU^_$rr`#do(.G4JcDABJ,~>
-!$2(="8MHXoB-&Qp&=C[nU^_$rr`#do(.G4JcDABJ,~>
-!$2(=")T&-1&V%PiV<?N"6A%arr2otkl0-5g\h'Ph>HmE!8@>M!oDM`r;QiRf%p?*!9F(/!9j.V
-!WCjOrrUg'j8ArWec=e0rr`5Nf&cQ(!VYROrr`)Jf'<87!<)lI!:]mc!U0(HrrMTRr;Qlif%0?h
-rr_fBf(/e>!:^!=!;Q6e!U0(Ors%i@f(]4Eo_d8?g&D!Ol2K9+rrM*Rr;Qu_f%0j#s6]a8!oX+E
-r72)2s8RBo.2IL7JcDABJ,~>
-!$2(=")T&-1&V%PiV<?N"6A%arr2otkl0-5g\h'Ph>HmE!8@>M!oDM`r;QiRf%p?*!9F(/!9j.V
-!WCjOrrUg'j8ArWec=e0rr`5Nf&cQ(!VYROrr`)Jf'<87!<)lI!:]mc!U0(HrrMTRr;Qlif%0?h
-rr_fBf(/e>!:^!=!;Q6e!U0(Ors%i@f(]4Eo_d8?g&D!Ol2K9+rrM*Rr;Qu_f%0j#s6]a8!oX+E
-r72)2s8RBo.2IL7JcDABJ,~>
-!$2(=")T&-1&V%PiV<?N"6A%arr2otkl0-5g\h'Ph>HmE!8@>M!oDM`r;QiRf%p?*!9F(/!9j.V
-!WCjOrrUg'j8ArWec=e0rr`5Nf&cQ(!VYROrr`)Jf'<87!<)lI!:]mc!U0(HrrMTRr;Qlif%0?h
-rr_fBf(/e>!:^!=!;Q6e!U0(Ors%i@f(]4Eo_d8?g&D!Ol2K9+rrM*Rr;Qu_f%0j#s6]a8!oX+E
-r72)2s8RBo.2IL7JcDABJ,~>
-!$2(=!H#(<rrU\+ec#LRg2BGM^An5kH2^86<m(FA!mMnWo`"s6(&\(7c<Nh@bPqMIbZRD>cN!oK
-2>ouERJ-X]ZRbtR"N*i$CY/Rc"MdJrDV>$h"M.&lEnpBg!r.jWrVm0%WCB@+j8].frC-gJmJ[%d
-i)?WKrrVP,JGoK[ns2a7ORE/Kmug.0Pk"eRm>h08!9!SN!oR"WrVm,bK18>*qZ"e;7KaM,s5A>(
-7KEG]rrU_-eG]CPg2KMN^&S,8rC-lP56%S[7KGS@r;Qa;JcC<$TDsE~>
-!$2(=!H#(<rrU\+ec#LRg2BGM^An5kH2^86<m(FA!mMnWo`"s6(&\(7c<Nh@bPqMIbZRD>cN!oK
-2>ouERJ-X]ZRbtR"N*i$CY/Rc"MdJrDV>$h"M.&lEnpBg!r.jWrVm0%WCB@+j8].frC-gJmJ[%d
-i)?WKrrVP,JGoK[ns2a7ORE/Kmug.0Pk"eRm>h08!9!SN!oR"WrVm,bK18>*qZ"e;7KaM,s5A>(
-7KEG]rrU_-eG]CPg2KMN^&S,8rC-lP56%S[7KGS@r;Qa;JcC<$TDsE~>
-!$2(=!H#(<rrU\+ec#LRg2BGM^An5kH2^86<m(FA!mMnWo`"s6(&\(7c<Nh@bPqMIbZRD>cN!oK
-2>ouERJ-X]ZRbtR"N*i$CY/Rc"MdJrDV>$h"M.&lEnpBg!r.jWrVm0%WCB@+j8].frC-gJmJ[%d
-i)?WKrrVP,JGoK[ns2a7ORE/Kmug.0Pk"eRm>h08!9!SN!oR"WrVm,bK18>*qZ"e;7KaM,s5A>(
-7KEG]rrU_-eG]CPg2KMN^&S,8rC-lP56%S[7KGS@r;Qa;JcC<$TDsE~>
-!$2(=!H#(=rr^Pl*7b&g$.aRGs8Ql>s,N-=rs.@Es8U#Z'(>Mn!krU^rVmJLFlEAaEl.jnF6<M^
-FN+8a_=IU-X^NaYrt`"Xqu=rhdf6Ufs8U/hec2gjs8Tudg%YLJQVCKYrs5BFs8TH[ir:%trrHH?
-rr3)XK.X(srr__K4b3P3')7TQs8SOJoCS*2s8S@Gp@4-5oD\pMK.O&%rs%YBXT/<NSGW<iX)\0u
-KX^RQ"4)95eGfIPf7(a>s(nt<rrW1aM>[ATqNHs;rr='js+13Bs*t~>
-!$2(=!H#(=rr^Pl*7b&g$.aRGs8Ql>s,N-=rs.@Es8U#Z'(>Mn!krU^rVmJLFlEAaEl.jnF6<M^
-FN+8a_=IU-X^NaYrt`"Xqu=rhdf6Ufs8U/hec2gjs8Tudg%YLJQVCKYrs5BFs8TH[ir:%trrHH?
-rr3)XK.X(srr__K4b3P3')7TQs8SOJoCS*2s8S@Gp@4-5oD\pMK.O&%rs%YBXT/<NSGW<iX)\0u
-KX^RQ"4)95eGfIPf7(a>s(nt<rrW1aM>[ATqNHs;rr='js+13Bs*t~>
-!$2(=!H#(=rr^Pl*7b&g$.aRGs8Ql>s,N-=rs.@Es8U#Z'(>Mn!krU^rVmJLFlEAaEl.jnF6<M^
-FN+8a_=IU-X^NaYrt`"Xqu=rhdf6Ufs8U/hec2gjs8Tudg%YLJQVCKYrs5BFs8TH[ir:%trrHH?
-rr3)XK.X(srr__K4b3P3')7TQs8SOJoCS*2s8S@Gp@4-5oD\pMK.O&%rs%YBXT/<NSGW<iX)\0u
-KX^RQ"4)95eGfIPf7(a>s(nt<rrW1aM>[ATqNHs;rr='js+13Bs*t~>
-!$2(=!H#(>rrgYtbt$=`rrJF?rr3,`2uenurr35Z5QATNg+Dderr]f^iZ8!t!Go">rt)eNs0@.>
-s6"m>s'*=#It+Hlrr]'Il7;i5!CGQ?rsY$Js.+]?s3cD>s"Wm>rrIY?q#:GWNQ5&trr=)<rrZoB
-ruM(<#[Y7Fs5ea>F/es7"T!VCSUg_>!UMN=rsLsInURY>s/:J?gHkH2"QY'BEiT-=!Q&(>rr=):
-rra_Bs06D3rrgYtbt-@`rrJI?rr3#^2Z3RUq]Yk:!V7c;rr='js+13Bs*t~>
-!$2(=!H#(>rrgYtbt$=`rrJF?rr3,`2uenurr35Z5QATNg+Dderr]f^iZ8!t!Go">rt)eNs0@.>
-s6"m>s'*=#It+Hlrr]'Il7;i5!CGQ?rsY$Js.+]?s3cD>s"Wm>rrIY?q#:GWNQ5&trr=)<rrZoB
-ruM(<#[Y7Fs5ea>F/es7"T!VCSUg_>!UMN=rsLsInURY>s/:J?gHkH2"QY'BEiT-=!Q&(>rr=):
-rra_Bs06D3rrgYtbt-@`rrJI?rr3#^2Z3RUq]Yk:!V7c;rr='js+13Bs*t~>
-!$2(=!H#(>rrgYtbt$=`rrJF?rr3,`2uenurr35Z5QATNg+Dderr]f^iZ8!t!Go">rt)eNs0@.>
-s6"m>s'*=#It+Hlrr]'Il7;i5!CGQ?rsY$Js.+]?s3cD>s"Wm>rrIY?q#:GWNQ5&trr=)<rrZoB
-ruM(<#[Y7Fs5ea>F/es7"T!VCSUg_>!UMN=rsLsInURY>s/:J?gHkH2"QY'BEiT-=!Q&(>rr=):
-rra_Bs06D3rrgYtbt-@`rrJI?rr3#^2Z3RUq]Yk:!V7c;rr='js+13Bs*t~>
-!$2(=!H#(>rrh'#s$tW=rrJF?rr3Mk2uenus8W!s5QB*^s"3^5rr^F#ruM(<!Go">rt2kOs8TTE
-@Vr^Vs'&*]SXkV9q#:H,mdVh+rrGI@rr3ChMuWgT@UaQ)s8Oh?rr3"LSG<*dWW'q<rVlj<rVlt4
-[f7BIrs>hR^Am_@]`3&Pq#:KoXT+iArr3#c0`D"[4Q-8(M.0qOli5^*`Vs<HjS8`Xlb3==WrE#!
-_H[!=!$2";#)nfDs06C@raGm,q#:KNc2U>arr3"cL&V)Qk;N8<!HY:<rrI&?qu6X:JcC<$TDsE~>
-!$2(=!H#(>rrh'#s$tW=rrJF?rr3Mk2uenus8W!s5QB*^s"3^5rr^F#ruM(<!Go">rt2kOs8TTE
-@Vr^Vs'&*]SXkV9q#:H,mdVh+rrGI@rr3ChMuWgT@UaQ)s8Oh?rr3"LSG<*dWW'q<rVlj<rVlt4
-[f7BIrs>hR^Am_@]`3&Pq#:KoXT+iArr3#c0`D"[4Q-8(M.0qOli5^*`Vs<HjS8`Xlb3==WrE#!
-_H[!=!$2";#)nfDs06C@raGm,q#:KNc2U>arr3"cL&V)Qk;N8<!HY:<rrI&?qu6X:JcC<$TDsE~>
-!$2(=!H#(>rrh'#s$tW=rrJF?rr3Mk2uenus8W!s5QB*^s"3^5rr^F#ruM(<!Go">rt2kOs8TTE
-@Vr^Vs'&*]SXkV9q#:H,mdVh+rrGI@rr3ChMuWgT@UaQ)s8Oh?rr3"LSG<*dWW'q<rVlj<rVlt4
-[f7BIrs>hR^Am_@]`3&Pq#:KoXT+iArr3#c0`D"[4Q-8(M.0qOli5^*`Vs<HjS8`Xlb3==WrE#!
-_H[!=!$2";#)nfDs06C@raGm,q#:KNc2U>arr3"cL&V)Qk;N8<!HY:<rrI&?qu6X:JcC<$TDsE~>
-!$2(=!H#(;rrGX?rr3"bLAq2Zju<=uGst.lTg/MU!A3d3rr=)<rrHr?rr3SB@K6@PVn/[Ps8UQZ
-pAb/mEq]M6nLOS<!CGQ?rsY$Js8Q96\riK^s"Wm>rrIY?pAY06<W2pt*W?!?B=@iLr^@-E7DAe$
-aT)9]WV-8lSUg_>!UMN=rsV$Js42%u\n]pugCeK)\cGt,pAY/6WrE#!_H[!=!$2";#"7,Ds03St
-rji)5p&>%`eGfIKQ\GG=!TuB=rr=)9rr=)9rr='js+13Bs*t~>
-!$2(=!H#(;rrGX?rr3"bLAq2Zju<=uGst.lTg/MU!A3d3rr=)<rrHr?rr3SB@K6@PVn/[Ps8UQZ
-pAb/mEq]M6nLOS<!CGQ?rsY$Js8Q96\riK^s"Wm>rrIY?pAY06<W2pt*W?!?B=@iLr^@-E7DAe$
-aT)9]WV-8lSUg_>!UMN=rsV$Js42%u\n]pugCeK)\cGt,pAY/6WrE#!_H[!=!$2";#"7,Ds03St
-rji)5p&>%`eGfIKQ\GG=!TuB=rr=)9rr=)9rr='js+13Bs*t~>
-!$2(=!H#(;rrGX?rr3"bLAq2Zju<=uGst.lTg/MU!A3d3rr=)<rrHr?rr3SB@K6@PVn/[Ps8UQZ
-pAb/mEq]M6nLOS<!CGQ?rsY$Js8Q96\riK^s"Wm>rrIY?pAY06<W2pt*W?!?B=@iLr^@-E7DAe$
-aT)9]WV-8lSUg_>!UMN=rsV$Js42%u\n]pugCeK)\cGt,pAY/6WrE#!_H[!=!$2";#"7,Ds03St
-rji)5p&>%`eGfIKQ\GG=!TuB=rr=)9rr=)9rr='js+13Bs*t~>
-!$2(=!H#(;rrGX?rr3"bLAq2Zju<>?l.=P>h*:l<!A3d3rr=)<rrHr?rr3;:@K1_Qq>^5bJc#HJ
-WcIh5!V%]=rrGI@rr3ChMuQnts8VVDV>i::rr3"LSG)s`a&W*<!$2%<")#(BrVkCOls@F+$N;FT
-&f]0jrrJ[@rr3#c0`D"[4Q,F!jT#8@9^LLmk5PA]/+N?5!HP4>rrKu@rVlj<rVm+KW;6JnZ!6So
-rr=)4rrG[?rr3"cL&V)Qk;N;=!E[;<rrGp?qYpO9JcC<$TDsE~>
-!$2(=!H#(;rrGX?rr3"bLAq2Zju<>?l.=P>h*:l<!A3d3rr=)<rrHr?rr3;:@K1_Qq>^5bJc#HJ
-WcIh5!V%]=rrGI@rr3ChMuQnts8VVDV>i::rr3"LSG)s`a&W*<!$2%<")#(BrVkCOls@F+$N;FT
-&f]0jrrJ[@rr3#c0`D"[4Q,F!jT#8@9^LLmk5PA]/+N?5!HP4>rrKu@rVlj<rVm+KW;6JnZ!6So
-rr=)4rrG[?rr3"cL&V)Qk;N;=!E[;<rrGp?qYpO9JcC<$TDsE~>
-!$2(=!H#(;rrGX?rr3"bLAq2Zju<>?l.=P>h*:l<!A3d3rr=)<rrHr?rr3;:@K1_Qq>^5bJc#HJ
-WcIh5!V%]=rrGI@rr3ChMuQnts8VVDV>i::rr3"LSG)s`a&W*<!$2%<")#(BrVkCOls@F+$N;FT
-&f]0jrrJ[@rr3#c0`D"[4Q,F!jT#8@9^LLmk5PA]/+N?5!HP4>rrKu@rVlj<rVm+KW;6JnZ!6So
-rr=)4rrG[?rr3"cL&V)Qk;N;=!E[;<rrGp?qYpO9JcC<$TDsE~>
-!$2(=!H#(;rrGX?rr31nL&(cKfL5W:!ROO=rrF_?qu6]dn,*+b*W?!MG,kK?r3L5>DR'->r2b#?
-o_\Xf!NL2=rrMNXr;Qff/,fJ`:X9"?q2^a>8(IY>q1kI>5McA>pjf.=rrW,cp&+gja&W*<"t]9D
-s7^9?r;QlmA&J?FoE&p)r;Q]tq<dtTrrJ[@rr3St47iLPoL@j%6hC?Xo02Ho62gfa/+NW=!qu$Y
-r;Qe<WrE#&`aJN?s7%Z>rrVn+_#F?7Z#'C=!$2%<!qYgXr;QdgeGfIPSqQq>s4Kd=rrVdXkPY>]
-o/c@:rr='js+13Bs*t~>
-!$2(=!H#(;rrGX?rr31nL&(cKfL5W:!ROO=rrF_?qu6]dn,*+b*W?!MG,kK?r3L5>DR'->r2b#?
-o_\Xf!NL2=rrMNXr;Qff/,fJ`:X9"?q2^a>8(IY>q1kI>5McA>pjf.=rrW,cp&+gja&W*<"t]9D
-s7^9?r;QlmA&J?FoE&p)r;Q]tq<dtTrrJ[@rr3St47iLPoL@j%6hC?Xo02Ho62gfa/+NW=!qu$Y
-r;Qe<WrE#&`aJN?s7%Z>rrVn+_#F?7Z#'C=!$2%<!qYgXr;QdgeGfIPSqQq>s4Kd=rrVdXkPY>]
-o/c@:rr='js+13Bs*t~>
-!$2(=!H#(;rrGX?rr31nL&(cKfL5W:!ROO=rrF_?qu6]dn,*+b*W?!MG,kK?r3L5>DR'->r2b#?
-o_\Xf!NL2=rrMNXr;Qff/,fJ`:X9"?q2^a>8(IY>q1kI>5McA>pjf.=rrW,cp&+gja&W*<"t]9D
-s7^9?r;QlmA&J?FoE&p)r;Q]tq<dtTrrJ[@rr3St47iLPoL@j%6hC?Xo02Ho62gfa/+NW=!qu$Y
-r;Qe<WrE#&`aJN?s7%Z>rrVn+_#F?7Z#'C=!$2%<!qYgXr;QdgeGfIPSqQq>s4Kd=rrVdXkPY>]
-o/c@:rr='js+13Bs*t~>
-!$2(=!H#(>rseACd5nGXg&M)7QI4)Lrr3GhdF$63s8V?2d3Z]XhYmHT,o6L[%Hc'c(t$ais8R#B
-dC<ffrs3;IdBd]is*:UCd/f_qrr3&r!'pP`%GoLO,LOp&s8Pd:d@H*mrrbg=d?p!orrbd<d?9go
-rrULHCB"5Ef$U6^dF%I`qF/fZJueqOr;P(EIBrbM!HY7=ruS!:PlLd^dF!JXdF%ahf3m"RB?pPW
-d:L_Q@b(M<=T-VJ9(W&^'70_os8Vc>d9V[XdJs6SHdU58nG`FgJ"HW=!P`^Sd/ZZ7rt8-.l2UeO
-dEt%YdFnR"P*XMC7fE>f<64t:!DLl9rr='js+13Bs*t~>
-!$2(=!H#(>rseACd5nGXg&M)7QI4)Lrr3GhdF$63s8V?2d3Z]XhYmHT,o6L[%Hc'c(t$ais8R#B
-dC<ffrs3;IdBd]is*:UCd/f_qrr3&r!'pP`%GoLO,LOp&s8Pd:d@H*mrrbg=d?p!orrbd<d?9go
-rrULHCB"5Ef$U6^dF%I`qF/fZJueqOr;P(EIBrbM!HY7=ruS!:PlLd^dF!JXdF%ahf3m"RB?pPW
-d:L_Q@b(M<=T-VJ9(W&^'70_os8Vc>d9V[XdJs6SHdU58nG`FgJ"HW=!P`^Sd/ZZ7rt8-.l2UeO
-dEt%YdFnR"P*XMC7fE>f<64t:!DLl9rr='js+13Bs*t~>
-!$2(=!H#(>rseACd5nGXg&M)7QI4)Lrr3GhdF$63s8V?2d3Z]XhYmHT,o6L[%Hc'c(t$ais8R#B
-dC<ffrs3;IdBd]is*:UCd/f_qrr3&r!'pP`%GoLO,LOp&s8Pd:d@H*mrrbg=d?p!orrbd<d?9go
-rrULHCB"5Ef$U6^dF%I`qF/fZJueqOr;P(EIBrbM!HY7=ruS!:PlLd^dF!JXdF%ahf3m"RB?pPW
-d:L_Q@b(M<=T-VJ9(W&^'70_os8Vc>d9V[XdJs6SHdU58nG`FgJ"HW=!P`^Sd/ZZ7rt8-.l2UeO
-dEt%YdFnR"P*XMC7fE>f<64t:!DLl9rr='js+13Bs*t~>
-!$2(=#&Sap[f?B>r(@$+rr3(Z92#3^rr\``92GQe!3,lh!.OnH!G*,IrrAVf9)skKrrR(2B)MZ1
-BM31?rr@9B9)sbGrrW'`5lUc`JG`%?W;ceu:eQK?rr`6n98`]J"8GM^OSo+[h)/sHrr?O+9*WB8
-s5lsIUAk/mp&7SaW;?MpSAY=*"i)ONs8Vlk9*XGVs2[i+_#=98_FmPArr2uGrC[.KrVm%q*5DOR
-gAFSD:&b.pX%Q+BrVlnp]);R.Zi*Msrr)j#KFd>Is1J8&!,MT6"-#rHr;HWrLY2M(!J0,*rr^WT
-Zl=SrJcDABJ,~>
-!$2(=#&Sap[f?B>r(@$+rr3(Z92#3^rr\``92GQe!3,lh!.OnH!G*,IrrAVf9)skKrrR(2B)MZ1
-BM31?rr@9B9)sbGrrW'`5lUc`JG`%?W;ceu:eQK?rr`6n98`]J"8GM^OSo+[h)/sHrr?O+9*WB8
-s5lsIUAk/mp&7SaW;?MpSAY=*"i)ONs8Vlk9*XGVs2[i+_#=98_FmPArr2uGrC[.KrVm%q*5DOR
-gAFSD:&b.pX%Q+BrVlnp]);R.Zi*Msrr)j#KFd>Is1J8&!,MT6"-#rHr;HWrLY2M(!J0,*rr^WT
-Zl=SrJcDABJ,~>
-!$2(=#&Sap[f?B>r(@$+rr3(Z92#3^rr\``92GQe!3,lh!.OnH!G*,IrrAVf9)skKrrR(2B)MZ1
-BM31?rr@9B9)sbGrrW'`5lUc`JG`%?W;ceu:eQK?rr`6n98`]J"8GM^OSo+[h)/sHrr?O+9*WB8
-s5lsIUAk/mp&7SaW;?MpSAY=*"i)ONs8Vlk9*XGVs2[i+_#=98_FmPArr2uGrC[.KrVm%q*5DOR
-gAFSD:&b.pX%Q+BrVlnp]);R.Zi*Msrr)j#KFd>Is1J8&!,MT6"-#rHr;HWrLY2M(!J0,*rr^WT
-Zl=SrJcDABJ,~>
-!$2(="/omHD;5'j*S^Spgd'Wo!O?IprrIq?g]%:[^YAbh1[3cr"/0CAFFjICs.B=A~>
-!$2(="/omHD;5'j*S^Spgd'Wo!O?IprrIq?g]%:[^YAbh1[3cr"/0CAFFjICs.B=A~>
-!$2(="/omHD;5'j*S^Spgd'Wo!O?IprrIq?g]%:[^YAbh1[3cr"/0CAFFjICs.B=A~>
-!$0Vi!KE/qrrW+FUtktOk'abprrUPsbhW4"\q/eprrT!Kon!-os+14Fs*t~>
-!$0Vi!KE/qrrW+FUtktOk'abprrUPsbhW4"\q/eprrT!Kon!-os+14Fs*t~>
-!$0Vi!KE/qrrW+FUtktOk'abprrUPsbhW4"\q/eprrT!Kon!-os+14Fs*t~>
-!$0Vi!O2LWrrN)%g]%<B^>&YghTjmU!RKTVrrKn$JcC<$JcGKEJ,~>
-!$0Vi!O2LWrrN)%g]%<B^>&YghTjmU!RKTVrrKn$JcC<$JcGKEJ,~>
-!$0Vi!O2LWrrN)%g]%<B^>&YghTjmU!RKTVrrKn$JcC<$JcGKEJ,~>
-!$.X1!SDh6rrC7A5QK%#rrJ>#p&>&uU\t,l_>Z\"ec#LKV6GONJcC<$hZ&*~>
-!$.X1!SDh6rrC7A5QK%#rrJ>#p&>&uU\t,l_>Z\"ec#LKV6GONJcC<$hZ&*~>
-!$.X1!SDh6rrC7A5QK%#rrJ>#p&>&uU\t,l_>Z\"ec#LKV6GONJcC<$hZ&*~>
-!Zh<Ir$)>4s8S:^o)Ac,,O4Up!^%].ec,^;8E]sO"TCUbZAJS\"Z/[Js,sDOrs&<E>Q=_N_"[j3
-dV8`9[J'V'\lIP@p@\FeS;d+>rrC+<,66HsrrV_<Y5SA'o\A4na8Q#>mVojjs+13$s53j,~>
-!Zh<Ir$)>4s8S:^o)Ac,,O4Up!^%].ec,^;8E]sO"TCUbZAJS\"Z/[Js,sDOrs&<E>Q=_N_"[j3
-dV8`9[J'V'\lIP@p@\FeS;d+>rrC+<,66HsrrV_<Y5SA'o\A4na8Q#>mVojjs+13$s53j,~>
-!Zh<Ir$)>4s8S:^o)Ac,,O4Up!^%].ec,^;8E]sO"TCUbZAJS\"Z/[Js,sDOrs&<E>Q=_N_"[j3
-dV8`9[J'V'\lIP@p@\FeS;d+>rrC+<,66HsrrV_<Y5SA'o\A4na8Q#>mVojjs+13$s53j,~>
-!Zh=>rV6]S3WK-WF0PQ6rrW)nrp9Xf5Ml4O?/GS],PqE@f1,]<&cNmPVK`(?2WiUik^]N0s6V]9
-rrs_D_.`%J]_DF/b>J:\WV6>m\mk:2!r%S@rr3#S7/co^0_,/B!f!3?qu6[sa8Gr=GH(Ijs+13$
-s5<p-~>
-!Zh=>rV6]S3WK-WF0PQ6rrW)nrp9Xf5Ml4O?/GS],PqE@f1,]<&cNmPVK`(?2WiUik^]N0s6V]9
-rrs_D_.`%J]_DF/b>J:\WV6>m\mk:2!r%S@rr3#S7/co^0_,/B!f!3?qu6[sa8Gr=GH(Ijs+13$
-s5<p-~>
-!Zh=>rV6]S3WK-WF0PQ6rrW)nrp9Xf5Ml4O?/GS],PqE@f1,]<&cNmPVK`(?2WiUik^]N0s6V]9
-rrs_D_.`%J]_DF/b>J:\WV6>m\mk:2!r%S@rr3#S7/co^0_,/B!f!3?qu6[sa8Gr=GH(Ijs+13$
-s5<p-~>
-!$2";!S0d=rrR#CrV$6nilfOArVllVrlY;kr;QfHd/<nK3o^1dHN4$"rlYl+s8V$Is3AgBs8Us!
-bPB?;rr2uLrlYT(s8Ufr(X("[rVlj<qu7B09`MVcs8Q9ls2[$bs8UT^-HjTqrr2uBrlY`7s8Pal
-s0OVbs8UL?rlY<.rr3,OFoRN7pAY0)@f?<-qpkZF"k`YNs/C)<rrM+mrr3&R:%\Da!F<J;rrH-?
-qu6[kd"24Js+14.s*t~>
-!$2";!S0d=rrR#CrV$6nilfOArVllVrlY;kr;QfHd/<nK3o^1dHN4$"rlYl+s8V$Is3AgBs8Us!
-bPB?;rr2uLrlYT(s8Ufr(X("[rVlj<qu7B09`MVcs8Q9ls2[$bs8UT^-HjTqrr2uBrlY`7s8Pal
-s0OVbs8UL?rlY<.rr3,OFoRN7pAY0)@f?<-qpkZF"k`YNs/C)<rrM+mrr3&R:%\Da!F<J;rrH-?
-qu6[kd"24Js+14.s*t~>
-!$2";!S0d=rrR#CrV$6nilfOArVllVrlY;kr;QfHd/<nK3o^1dHN4$"rlYl+s8V$Is3AgBs8Us!
-bPB?;rr2uLrlYT(s8Ufr(X("[rVlj<qu7B09`MVcs8Q9ls2[$bs8UT^-HjTqrr2uBrlY`7s8Pal
-s0OVbs8UL?rlY<.rr3,OFoRN7pAY0)@f?<-qpkZF"k`YNs/C)<rrM+mrr3&R:%\Da!F<J;rrH-?
-qu6[kd"24Js+14.s*t~>
-!$2%<!luR\qu6\6YP.tuSPTp\rr3#PGQ(D>@)`*E!@8NZrrG1?rVloGD>m?GC!H[BQ*41aD:&;e
-4]%qNE7=jeFoG2CF4L;C:^KrpQMpg`*UNe4CeG:8:p'ct\P`?&!J]_2rrF"/r_NWSlgOiS\mkX<
-!UMN=rrkOCs8T'>q>UNBCZ53k!F<J;rrH-?qu6[kd"24Js+14.s*t~>
-!$2%<!luR\qu6\6YP.tuSPTp\rr3#PGQ(D>@)`*E!@8NZrrG1?rVloGD>m?GC!H[BQ*41aD:&;e
-4]%qNE7=jeFoG2CF4L;C:^KrpQMpg`*UNe4CeG:8:p'ct\P`?&!J]_2rrF"/r_NWSlgOiS\mkX<
-!UMN=rrkOCs8T'>q>UNBCZ53k!F<J;rrH-?qu6[kd"24Js+14.s*t~>
-!$2%<!luR\qu6\6YP.tuSPTp\rr3#PGQ(D>@)`*E!@8NZrrG1?rVloGD>m?GC!H[BQ*41aD:&;e
-4]%qNE7=jeFoG2CF4L;C:^KrpQMpg`*UNe4CeG:8:p'ct\P`?&!J]_2rrF"/r_NWSlgOiS\mkX<
-!UMN=rrkOCs8T'>q>UNBCZ53k!F<J;rrH-?qu6[kd"24Js+14.s*t~>
-!$2%<".O.FUAOrj*VB@42Wk#=!JQm>rrLY@rVlnMHN*pI`0)9pTDnikCp<p=&\DKOs$g8gs0HG>
->J^=[s/L,:rrJj?rr2s=qYpO9li."Q0`:qO+T;<>!Nj`DrrEjhrr3"*^@2(&\mkX<$hSPIs8TTP
-mJm3cF8Gn<b'_b:rrHE?qu6[sa8>l;:!eIkJcC<$i;\<~>
-!$2%<".O.FUAOrj*VB@42Wk#=!JQm>rrLY@rVlnMHN*pI`0)9pTDnikCp<p=&\DKOs$g8gs0HG>
->J^=[s/L,:rrJj?rr2s=qYpO9li."Q0`:qO+T;<>!Nj`DrrEjhrr3"*^@2(&\mkX<$hSPIs8TTP
-mJm3cF8Gn<b'_b:rrHE?qu6[sa8>l;:!eIkJcC<$i;\<~>
-!$2%<".O.FUAOrj*VB@42Wk#=!JQm>rrLY@rVlnMHN*pI`0)9pTDnikCp<p=&\DKOs$g8gs0HG>
->J^=[s/L,:rrJj?rr2s=qYpO9li."Q0`:qO+T;<>!Nj`DrrEjhrr3"*^@2(&\mkX<$hSPIs8TTP
-mJm3cF8Gn<b'_b:rrHE?qu6[sa8>l;:!eIkJcC<$i;\<~>
-!$1t:!V[r=rrJ%?o`"qMk5PA]KpVf=!S'a9rrg)o++'CSrrHr?rr3\E@K6?sf)Pd*])Q!NruM->
-ErZ0&rcJ66HN*pE*W#d9*UE_+m4eJ<!1Ee.!5nR2!$2%<!FEM/rrK]?r;QrH:B1>t_uBZ:WH7t:
-!mH/@qYpS%^\e$3<QG":!DUpls+13$s5<p-~>
-!$1t:!V[r=rrJ%?o`"qMk5PA]KpVf=!S'a9rrg)o++'CSrrHr?rr3\E@K6?sf)Pd*])Q!NruM->
-ErZ0&rcJ66HN*pE*W#d9*UE_+m4eJ<!1Ee.!5nR2!$2%<!FEM/rrK]?r;QrH:B1>t_uBZ:WH7t:
-!mH/@qYpS%^\e$3<QG":!DUpls+13$s5<p-~>
-!$1t:!V[r=rrJ%?o`"qMk5PA]KpVf=!S'a9rrg)o++'CSrrHr?rr3\E@K6?sf)Pd*])Q!NruM->
-ErZ0&rcJ66HN*pE*W#d9*UE_+m4eJ<!1Ee.!5nR2!$2%<!FEM/rrK]?r;QrH:B1>t_uBZ:WH7t:
-!mH/@qYpS%^\e$3<QG":!DUpls+13$s5<p-~>
-!$1t:!V[r>rrRqDqt0mh2Wk#=!JQm>[email protected]/lXCp<p="hS4Cs$kT;rs;oGruM->ErV/d
-rhfd3HN*pE*W#d9*UE_+m4eG;!3#mp!IDl_rr=)<rrHH?n,EF"@f660mZ3s:MsC<A!NC/<rrU\m
-deWnD?,-::!EI2;rrGj@JcC<$JcF[.J,~>
-!$1t:!V[r>rrRqDqt0mh2Wk#=!JQm>[email protected]/lXCp<p="hS4Cs$kT;rs;oGruM->ErV/d
-rhfd3HN*pE*W#d9*UE_+m4eG;!3#mp!IDl_rr=)<rrHH?n,EF"@f660mZ3s:MsC<A!NC/<rrU\m
-deWnD?,-::!EI2;rrGj@JcC<$JcF[.J,~>
-!$1t:!V[r>rrRqDqt0mh2Wk#=!JQm>[email protected]/lXCp<p="hS4Cs$kT;rs;oGruM->ErV/d
-rhfd3HN*pE*W#d9*UE_+m4eG;!3#mp!IDl_rr=)<rrHH?n,EF"@f660mZ3s:MsC<A!NC/<rrU\m
-deWnD?,-::!EI2;rrGj@JcC<$JcF[.J,~>
-"!.ESQ2^dapEon>!f3H@oD\hLk5PA]KpVf=!S'a>rrH1pr;QdYir/lXCp<p="hS4Cs$kT;rsi8L
-ruM->ErT(\s8U@jHN*pI*WQ/ET`4rl\mt+,#jj>Gs-L=s;uQ^q!H5+8rr=)<rrHH?pAY3*40AJ]
-!P2b;rr]NAGGY9<!pbT@rr3&[?J>5T!h#5@qu6[sa8Gr=N19J;rrRp:iIV#[s+146s*t~>
-"!.ESQ2^dapEon>!f3H@oD\hLk5PA]KpVf=!S'a>rrH1pr;QdYir/lXCp<p="hS4Cs$kT;rsi8L
-ruM->ErT(\s8U@jHN*pI*WQ/ET`4rl\mt+,#jj>Gs-L=s;uQ^q!H5+8rr=)<rrHH?pAY3*40AJ]
-!P2b;rr]NAGGY9<!pbT@rr3&[?J>5T!h#5@qu6[sa8Gr=N19J;rrRp:iIV#[s+146s*t~>
-"!.ESQ2^dapEon>!f3H@oD\hLk5PA]KpVf=!S'a>rrH1pr;QdYir/lXCp<p="hS4Cs$kT;rsi8L
-ruM->ErT(\s8U@jHN*pI*WQ/ET`4rl\mt+,#jj>Gs-L=s;uQ^q!H5+8rr=)<rrHH?pAY3*40AJ]
-!P2b;rr]NAGGY9<!pbT@rr3&[?J>5T!h#5@qu6[sa8Gr=N19J;rrRp:iIV#[s+146s*t~>
-"!.F7L]/>!-0>1,OHfM3rs4/s"rf])s7("+*W\IhrVlmE(B"153o^,<!Ua.j*X,I.s8PR>r;R72
-_>iTrWcJ.*7ii^IO*^g*"P=b:D".H(!U2E,rs8S9*Zg(.s5bC&*W_5mq#:=7rVln)^@qR.V#ZbY
-rrK]?qu6clO,!<)rrJ(@rr3#R#lG_DoD\ajH_UB:!EI2<rrHl?qu6_+!8)l&JcC<$kl6/~>
-"!.F7L]/>!-0>1,OHfM3rs4/s"rf])s7("+*W\IhrVlmE(B"153o^,<!Ua.j*X,I.s8PR>r;R72
-_>iTrWcJ.*7ii^IO*^g*"P=b:D".H(!U2E,rs8S9*Zg(.s5bC&*W_5mq#:=7rVln)^@qR.V#ZbY
-rrK]?qu6clO,!<)rrJ(@rr3#R#lG_DoD\ajH_UB:!EI2<rrHl?qu6_+!8)l&JcC<$kl6/~>
-"!.F7L]/>!-0>1,OHfM3rs4/s"rf])s7("+*W\IhrVlmE(B"153o^,<!Ua.j*X,I.s8PR>r;R72
-_>iTrWcJ.*7ii^IO*^g*"P=b:D".H(!U2E,rs8S9*Zg(.s5bC&*W_5mq#:=7rVln)^@qR.V#ZbY
-rrK]?qu6clO,!<)rrJ(@rr3#R#lG_DoD\ajH_UB:!EI2<rrHl?qu6_+!8)l&JcC<$kl6/~>
-!Zh=@r;Q]q!<2Qhr;Q]qr;QWos8Mrr!<2lqr;Q]q!<2lq!<2or!ri6"rVcitrr)lrrqucsct2PC
-rr2osr;QHj!<2rs!<2Wj!Jcp<rrg.X*?E#qs8W)qrrW1K\,QF)rr2ouUltZU"L]<k*6nH^!L9>S
-s8W(Ls+13$s6'E4~>
-!Zh=@r;Q]q!<2Qhr;Q]qr;QWos8Mrr!<2lqr;Q]q!<2lq!<2or!ri6"rVcitrr)lrrqucsct2PC
-rr2osr;QHj!<2rs!<2Wj!Jcp<rrg.X*?E#qs8W)qrrW1K\,QF)rr2ouUltZU"L]<k*6nH^!L9>S
-s8W(Ls+13$s6'E4~>
-!Zh=@r;Q]q!<2Qhr;Q]qr;QWos8Mrr!<2lqr;Q]q!<2lq!<2or!ri6"rVcitrr)lrrqucsct2PC
-rr2osr;QHj!<2rs!<2Wj!Jcp<rrg.X*?E#qs8W)qrrW1K\,QF)rr2ouUltZU"L]<k*6nH^!L9>S
-s8W(Ls+13$s6'E4~>
-!$-XjhZ!ZCKWKb)JcC<$W;hA~>
-!$-XjhZ!ZCKWKb)JcC<$W;hA~>
-!$-XjhZ!ZCKWKb)JcC<$W;hA~>
-!$-XjhZ!VoV1JYts+13Js*t~>
-!$-XjhZ!VoV1JYts+13Js*t~>
-!$-XjhZ!VoV1JYts+13Js*t~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-"!.EGKDtlRpH/DRMZ3VYn3d5LP5bIij\#Q@RfEEb3<0$WGlA]a6N$i_#?;`a8,rVfC&T+R;>l(G
-JcC<$JcE=]J,~>
-"!.EGKDtlRpH/DRMZ3VYn3d5LP5bIij\#Q@RfEEb3<0$WGlA]a6N$i_#?;`a8,rVfC&T+R;>l(G
-JcC<$JcE=]J,~>
-"!.EGKDtlRpH/DRMZ3VYn3d5LP5bIij\#Q@RfEEb3<0$WGlA]a6N$i_#?;`a8,rVfC&T+R;>l(G
-JcC<$JcE=]J,~>
-"!.E>FoMCDpEop4IfB?]mOnO*LB%;6+?0=\NrT.U,6.[sQi@!ceO]]>#=@//1]RJsW;cet`*%Zk
-JcC<$JcE=]J,~>
-"!.E>FoMCDpEop4IfB?]mOnO*LB%;6+?0=\NrT.U,6.[sQi@!ceO]]>#=@//1]RJsW;cet`*%Zk
-JcC<$JcE=]J,~>
-"!.E>FoMCDpEop4IfB?]mOnO*LB%;6+?0=\NrT.U,6.[sQi@!ceO]]>#=@//1]RJsW;cet`*%Zk
-JcC<$JcE=]J,~>
-"!.E>FoMCDpEop4?iIkU[4_KFLB#Xsj#@!uNrT.U,6.[sQi@!ceO]]>#=@//1]RJsJ,[7bPZ`S;
-JcC<$JcE=]J,~>
-"!.E>FoMCDpEop4?iIkU[4_KFLB#Xsj#@!uNrT.U,6.[sQi@!ceO]]>#=@//1]RJsJ,[7bPZ`S;
-JcC<$JcE=]J,~>
-"!.E>FoMCDpEop4?iIkU[4_KFLB#Xsj#@!uNrT.U,6.[sQi@!ceO]]>#=@//1]RJsJ,[7bPZ`S;
-JcC<$JcE=]J,~>
-"!.E>FoMCDpEop4/cJof<%e3:L;e#pju<=#NrT.U,6.[sQi@!neO]`?`bsu(1]RJs4T/F`P_&jc
-s+13$s185\~>
-"!.E>FoMCDpEop4/cJof<%e3:L;e#pju<=#NrT.U,6.[sQi@!neO]`?`bsu(1]RJs4T/F`P_&jc
-s+13$s185\~>
-"!.E>FoMCDpEop4/cJof<%e3:L;e#pju<=#NrT.U,6.[sQi@!neO]`?`bsu(1]RJs4T/F`P_&jc
-s+13$s185\~>
-"!.E>FoMCDN@+[tIfB?]mOnO*7t'7oju<=#NrT.U,6.[sQi@!neO]`?@(lU)1]RJsW.Fu"s+13$
-s0_lW~>
-"!.E>FoMCDN@+[tIfB?]mOnO*7t'7oju<=#NrT.U,6.[sQi@!neO]`?@(lU)1]RJsW.Fu"s+13$
-s0_lW~>
-"!.E>FoMCDN@+[tIfB?]mOnO*7t'7oju<=#NrT.U,6.[sQi@!neO]`?@(lU)1]RJsW.Fu"s+13$
-s0_lW~>
-"!.EqJc9EfN$eRsIfB?]mOnO*:>,[Iju<=#4DS_H%ZgY6I/[miEjG_O-r4Vf'q,*@H2_RZNIh+\
-s+13$s1//[~>
-"!.EqJc9EfN$eRsIfB?]mOnO*:>,[Iju<=#4DS_H%ZgY6I/[miEjG_O-r4Vf'q,*@H2_RZNIh+\
-s+13$s1//[~>
-"!.EqJc9EfN$eRsIfB?]mOnO*:>,[Iju<=#4DS_H%ZgY6I/[miEjG_O-r4Vf'q,*@H2_RZNIh+\
-s+13$s1//[~>
-"!.FAg]"G\n0\1pfDbdQqS3'fgA_*SpVQscrNQKo5QCc2rilU?s8RLcrilTd;#gR>rilI@JcC<$
-JcC<$\c70~>
-"!.FAg]"G\n0\1pfDbdQqS3'fgA_*SpVQscrNQKo5QCc2rilU?s8RLcrilTd;#gR>rilI@JcC<$
-JcC<$\c70~>
-"!.FAg]"G\n0\1pfDbdQqS3'fgA_*SpVQscrNQKo5QCc2rilU?s8RLcrilTd;#gR>rilI@JcC<$
-JcC<$\c70~>
-"!.EOOT,7\pEo5+!Sp!8rrM9Lrr3#lh1>TWs+13$s0DZT~>
-"!.EOOT,7\pEo5+!Sp!8rrM9Lrr3#lh1>TWs+13$s0DZT~>
-"!.EOOT,7\pEo5+!Sp!8rrM9Lrr3#lh1>TWs+13$s0DZT~>
-"!.F:N;agu,jt!u!W;G<s+13$s+13Es*t~>
-"!.F:N;agu,jt!u!W;G<s+13$s+13Es*t~>
-"!.F:N;agu,jt!u!W;G<s+13$s+13Es*t~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$1k7!Tr3hs+13$s+130s*t~>
-!$1k7!Tr3hs+13$s+130s*t~>
-!$1k7!Tr3hs+13$s+130s*t~>
-!$1k7!M=gls+13$s+130s*t~>
-!$1k7!M=gls+13$s+130s*t~>
-!$1k7!M=gls+13$s+130s*t~>
-!$1k7!M=gls+13$s+130s*t~>
-!$1k7!M=gls+13$s+130s*t~>
-!$1k7!M=gls+13$s+130s*t~>
-"!.FA\c-1DC]FF,IfB?Jon%bpJcC<$JcCo5J,~>
-"!.FA\c-1DC]FF,IfB?Jon%bpJcC<$JcCo5J,~>
-"!.FA\c-1DC]FF,IfB?Jon%bpJcC<$JcCo5J,~>
-"!.EWHiCG[ZXj*.IfKF\:r@kaJcC<$JcCo5J,~>
-"!.EWHiCG[ZXj*.IfKF\:r@kaJcC<$JcCo5J,~>
-"!.EWHiCG[ZXj*.IfKF\:r@kaJcC<$JcCo5J,~>
-"!.E>FoMCHpEop4IX`oYeq*jPs+13$s,m>3~>
-"!.E>FoMCHpEop4IX`oYeq*jPs+13$s,m>3~>
-"!.E>FoMCHpEop4IX`oYeq*jPs+13$s,m>3~>
-"!.E>FoMCGpEop4%[H&MJcC<$JcC<$OT0h~>
-"!.E>FoMCGpEop4%[H&MJcC<$JcC<$OT0h~>
-"!.E>FoMCGpEop4%[H&MJcC<$JcC<$OT0h~>
-"!.E>FoMCHpEop4IXWfXf7EsQs+13$s,m>3~>
-"!.E>FoMCHpEop4IXWfXf7EsQs+13$s,m>3~>
-"!.E>FoMCHpEop4IXWfXf7EsQs+13$s,m>3~>
-"!.EWHiCJ\Zt'-.IfKF[:W.haJcC<$JcCo5J,~>
-"!.EWHiCJ\Zt'-.IfKF[:W.haJcC<$JcCo5J,~>
-"!.EWHiCJ\Zt'-.IfKF[:W.haJcC<$JcCo5J,~>
-"!.FA\Gg"ACB+=QZ2Xb(omhVnJcC<$JcCo5J,~>
-"!.FA\Gg"ACB+=QZ2Xb(omhVnJcC<$JcCo5J,~>
-"!.FA\Gg"ACB+=QZ2Xb(omhVnJcC<$JcCo5J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$1>(!5\M"!/Q4+JcC<$JcDMFJ,~>
-!$1>(!5\M"!/Q4+JcC<$JcDMFJ,~>
-!$1>(!5\M"!/Q4+JcC<$JcDMFJ,~>
-!$1>(!NTW+fE%aPJcC<$JcC<$U]5i~>
-!$1>(!NTW+fE%aPJcC<$JcC<$U]5i~>
-!$1>(!NTW+fE%aPJcC<$JcC<$U]5i~>
-!$2";!UqE7rrS:OqY'piX)\(;!Phrks+13$s+13Fs*t~>
-!$2";!UqE7rrS:OqY'piX)\(;!Phrks+13$s+13Fs*t~>
-!$2";!UqE7rrS:OqY'piX)\(;!Phrks+13$s+13Fs*t~>
-!$2%<!o?]]rVlqMU\FN_!NU5<rrKo?JcC<$JcC<$U]5i~>
-!$2%<!o?]]rVlqMU\FN_!NU5<rrKo?JcC<$JcC<$U]5i~>
-!$2%<!o?]]rVlqMU\FN_!NU5<rrKo?JcC<$JcC<$U]5i~>
-!$2(="4M)A*W5p=I\Q`7rrK0?r;Qf5>_2p+s+13$s.fUE~>
-!$2(="4M)A*W5p=I\Q`7rrK0?r;Qf5>_2p+s+13$s.fUE~>
-!$2(="4M)A*W5p=I\Q`7rrK0?r;Qf5>_2p+s+13$s.fUE~>
-#9EjEc[=+>*W,j;JsuK7!NU5<rrKo?JcC<$JcC<$U]5i~>
-#9EjEc[=+>*W,j;JsuK7!NU5<rrKo?JcC<$JcC<$U]5i~>
-#9EjEc[=+>*W,j;JsuK7!NU5<rrKo?JcC<$JcC<$U]5i~>
-#9EilJ'@rm*W#d9*VfX8X)\(;!Phrks+13$s+13Fs*t~>
-#9EilJ'@rm*W#d9*VfX8X)\(;!Phrks+13$s+13Fs*t~>
-#9EilJ'@rm*W#d9*VfX8X)\(;!Phrks+13$s+13Fs*t~>
-"!.E>.fNZR$Zu=H!Ht@8rrK0?r;Qf5>_2p+s+13$s.fUE~>
-"!.E>.fNZR$Zu=H!Ht@8rrK0?r;Qf5>_2p+s+13$s.fUE~>
-"!.E>.fNZR$Zu=H!Ht@8rrK0?r;Qf5>_2p+s+13$s.fUE~>
-!Zh=*rP/FLao25@FK>?7rrK0?r;Qf5>_2p+s+13$s.fUE~>
-!Zh=*rP/FLao25@FK>?7rrK0?r;Qf5>_2p+s+13$s.fUE~>
-!Zh=*rP/FLao25@FK>?7rrK0?r;Qf5>_2p+s+13$s.fUE~>
-!$1t:!$2%<!dUd@p\t8pEW#h;^g)HjJcC<$JcDMFJ,~>
-!$1t:!$2%<!dUd@p\t8pEW#h;^g)HjJcC<$JcDMFJ,~>
-!$1t:!$2%<!dUd@p\t8pEW#h;^g)HjJcC<$JcDMFJ,~>
-!$1t:!&FQR!g'2VpAY/oEW#h;^g)HjJcC<$JcDMFJ,~>
-!$1t:!&FQR!g'2VpAY/oEW#h;^g)HjJcC<$JcDMFJ,~>
-!$1t:!&FQR!g'2VpAY/oEW#h;^g)HjJcC<$JcDMFJ,~>
-!$1>(!NU5<rrKo?JcC<$JcC<$U]5i~>
-!$1>(!NU5<rrKo?JcC<$JcC<$U]5i~>
-!$1>(!NU5<rrKo?JcC<$JcC<$U]5i~>
-!$1>(!NSrmXT=#YJcC<$JcC<$U]5i~>
-!$1>(!NSrmXT=#YJcC<$JcC<$U]5i~>
-!$1>(!NSrmXT=#YJcC<$JcC<$U]5i~>
-!$1>(!71L[!2G,FJcC<$JcDMFJ,~>
-!$1>(!71L[!2G,FJcC<$JcDMFJ,~>
-!$1>(!71L[!2G,FJcC<$JcDMFJ,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-!$-XjJcC<$JcC?%J,~>
-%%EndData
-showpage
-%%Trailer
-end
-%%EOF
diff --git a/lib/stdlib/doc/src/ushell2.gif b/lib/stdlib/doc/src/ushell2.gif
deleted file mode 100644
index 273cf2078a..0000000000
--- a/lib/stdlib/doc/src/ushell2.gif
+++ /dev/null
Binary files differ
diff --git a/lib/stdlib/doc/src/ushell2.ps b/lib/stdlib/doc/src/ushell2.ps
deleted file mode 100644
index e6db3c2be2..0000000000
--- a/lib/stdlib/doc/src/ushell2.ps
+++ /dev/null
@@ -1,404 +0,0 @@
-%!PS-Adobe-3.0
-%%Creator: GIMP PostScript file plugin V 1.17 by Peter Kirchgessner
-%%Title: ushell2.ps
-%%CreationDate: Mon Mar 16 09:52:14 2009
-%%DocumentData: Clean7Bit
-%%LanguageLevel: 2
-%%Pages: 1
-%%BoundingBox: 14 14 468 74
-%%EndComments
-%%BeginProlog
-% Use own dictionary to avoid conflicts
-10 dict begin
-%%EndProlog
-%%Page: 1 1
-% Translate for offset
-14.173228346456694 14.173228346456694 translate
-% Translate to begin of first scanline
-0 59.527559055118118 translate
-453.54330708661422 -59.527559055118118 scale
-% Image geometry
-640 84 8
-% Transformation matrix
-[ 640 0 0 84 0 0 ]
-% Strings to hold RGB-samples per scanline
-/rstr 640 string def
-/gstr 640 string def
-/bstr 640 string def
-{currentfile /ASCII85Decode filter /RunLengthDecode filter rstr readstring pop}
-{currentfile /ASCII85Decode filter /RunLengthDecode filter gstr readstring pop}
-{currentfile /ASCII85Decode filter /RunLengthDecode filter bstr readstring pop}
-true 3
-%%BeginData: 18704 ASCII Bytes
-colorimage
-J`MCCJ`MCCJ`M=~>
-J`MCCJ`MCCJ`M=~>
-J`MCCJ`MCCJ`M=~>
-!)nG7JO+iQJO+lRJ,~>
-!)nG7JO+iQJO+lRJ,~>
-!)nG7JO+iQJO+lRJ,~>
-!D=/Y=b0_,=b0_.=b$~>
-!D=/Y=b0_,=b0_.=b$~>
-!D=/Y=b0_,=b0_.=b$~>
-!D>M*s+13$s+13&s*t~>
-!D>M*s+13$s+13&s*t~>
-!D>M*s+13$s+13&s*t~>
-!D>M>rrKOJQ2^i3JcC<$JcFU,J,~>
-!D>M>rrKOJQ2^i3JcC<$JcFU,J,~>
-!D>M>rrKOJQ2^i3JcC<$JcFU,J,~>
-"%t`UXo(ooJ,'$ES](+!!dROKr;Qh<:2'>#!I!f.rr]@2s).a0!581-!+,Ru!6ss3!kNp@p\t9X
-H-uWnOA=s3rrK.0nG`Jtr;QbGr_<HIrVlo/@tFZ2s+14-s*t~>
-"%t`UXo(ooJ,'$ES](+!!dROKr;Qh<:2'>#!I!f.rr]@2s).a0!581-!+,Ru!6ss3!kNp@p\t9X
-H-uWnOA=s3rrK.0nG`Jtr;QbGr_<HIrVlo/@tFZ2s+14-s*t~>
-"%t`UXo(ooJ,'$ES](+!!dROKr;Qh<:2'>#!I!f.rr]@2s).a0!581-!+,Ru!6ss3!kNp@p\t9X
-H-uWnOA=s3rrK.0nG`Jtr;QbGr_<HIrVlo/@tFZ2s+14-s*t~>
-"A:iVM0T!F!8RAL!HP42rrUp#*W5p=fZ5E4rrG1@rr3+VQ2`JQrQbK2q#:?CrQbLB\*j7sS:L>5
-!T-**rrJOjli.%FchRG<!HlihrrIe?nc&Yn]MJP,!J%!FcN0Vnrr3#u++aHCs+14-s*t~>
-"A:iVM0T!F!8RAL!HP42rrUp#*W5p=fZ5E4rrG1@rr3+VQ2`JQrQbK2q#:?CrQbLB\*j7sS:L>5
-!T-**rrJOjli.%FchRG<!HlihrrIe?nc&Yn]MJP,!J%!FcN0Vnrr3#u++aHCs+14-s*t~>
-"A:iVM0T!F!8RAL!HP42rrUp#*W5p=fZ5E4rrG1@rr3+VQ2`JQrQbK2q#:?CrQbLB\*j7sS:L>5
-!T-**rrJOjli.%FchRG<!HlihrrIe?nc&Yn]MJP,!J%!FcN0Vnrr3#u++aHCs+14-s*t~>
-"A:iVM3Rl:!;QQc#kn;uEiSm+o_8@b!;HKb!;HEk!$;%;!V[r6rs;$Hs8VtORf>#.rq$3eoD\lN
-QMU(M!l&CArVllrrU^6ks5-$;rq$<ks8W#qoFLs$rV6Ego^r._r:GB$o^qnX!W2]krs&2ss8)B[
-rVlg+qXdY#o_/=bKUDN+o_/%Z$2J#IrQSC<s'rY>rrMrfrVloH97d+os+14.s*t~>
-"A:iVM3Rl:!;QQc#kn;uEiSm+o_8@b!;HKb!;HEk!$;%;!V[r6rs;$Hs8VtORf>#.rq$3eoD\lN
-QMU(M!l&CArVllrrU^6ks5-$;rq$<ks8W#qoFLs$rV6Ego^r._r:GB$o^qnX!W2]krs&2ss8)B[
-rVlg+qXdY#o_/=bKUDN+o_/%Z$2J#IrQSC<s'rY>rrMrfrVloH97d+os+14.s*t~>
-"A:iVM3Rl:!;QQc#kn;uEiSm+o_8@b!;HKb!;HEk!$;%;!V[r6rs;$Hs8VtORf>#.rq$3eoD\lN
-QMU(M!l&CArVllrrU^6ks5-$;rq$<ks8W#qoFLs$rV6Ego^r._r:GB$o^qnX!W2]krs&2ss8)B[
-rVlg+qXdY#o_/=bKUDN+o_/%Z$2J#IrQSC<s'rY>rrMrfrVloH97d+os+14.s*t~>
-#>7/YM1+"-g&D!PlY?DI$r#a^Efa$E-rf=.k?@j5!F+acrr=,;rrMj@o`#1<s8Sp?s8O^er[7f!
-nFce_n:I\.rrK]@r;QcHr?qfQqqj5tr[7lYrV35f-kO2nd:1^L-n*1:a!_W=-n+farrK!?rr35q
-.KBF2-jn]-rsk_N%3R&fs8Rb&=stdhj7rWTKtI?a"NGcfA%MI8!T6+ls+13$s5<p-~>
-#>7/YM1+"-g&D!PlY?DI$r#a^Efa$E-rf=.k?@j5!F+acrr=,;rrMj@o`#1<s8Sp?s8O^er[7f!
-nFce_n:I\.rrK]@r;QcHr?qfQqqj5tr[7lYrV35f-kO2nd:1^L-n*1:a!_W=-n+farrK!?rr35q
-.KBF2-jn]-rsk_N%3R&fs8Rb&=stdhj7rWTKtI?a"NGcfA%MI8!T6+ls+13$s5<p-~>
-#>7/YM1+"-g&D!PlY?DI$r#a^Efa$E-rf=.k?@j5!F+acrr=,;rrMj@o`#1<s8Sp?s8O^er[7f!
-nFce_n:I\.rrK]@r;QcHr?qfQqqj5tr[7lYrV35f-kO2nd:1^L-n*1:a!_W=-n+farrK!?rr35q
-.KBF2-jn]-rsk_N%3R&fs8Rb&=stdhj7rWTKtI?a"NGcfA%MI8!T6+ls+13$s5<p-~>
-#>7/YM'th_:B(7oI@pN=%,$43E\H&Es1hq?B=@g>!OQP=rr=,;rrMj@o`#1<s8Sp?s8Qb.rr3"H
-U%SEdTmZ8-!P2e8rrb=Bh[t\DrrXkBdn0N<#U90GWZSDDruV1>!J6g6rs#?Ds3C3-.K08I6JDA;
-!EI5>rs"-+b5_Li9CVrcA%M^:\[g>jrrM%@JcC<$JcF[.J,~>
-#>7/YM'th_:B(7oI@pN=%,$43E\H&Es1hq?B=@g>!OQP=rr=,;rrMj@o`#1<s8Sp?s8Qb.rr3"H
-U%SEdTmZ8-!P2e8rrb=Bh[t\DrrXkBdn0N<#U90GWZSDDruV1>!J6g6rs#?Ds3C3-.K08I6JDA;
-!EI5>rs"-+b5_Li9CVrcA%M^:\[g>jrrM%@JcC<$JcF[.J,~>
-#>7/YM'th_:B(7oI@pN=%,$43E\H&Es1hq?B=@g>!OQP=rr=,;rrMj@o`#1<s8Sp?s8Qb.rr3"H
-U%SEdTmZ8-!P2e8rrb=Bh[t\DrrXkBdn0N<#U90GWZSDDruV1>!J6g6rs#?Ds3C3-.K08I6JDA;
-!EI5>rs"-+b5_Li9CVrcA%M^:\[g>jrrM%@JcC<$JcF[.J,~>
-"A:iVM3Ro;!O.@YS-6(rs)P.=rrg,Cs(?9LS,mM@rVlj=qu6]k-M7<@Ff=JZXSVqtI%g96!p59A
-mJd3uA,Q?,li!=U,37WFrVlsOnC'u-rraPCs/L,=rr@3@rrI_@p&>5nG5k:_oI9b=!CGN<rrH-@
-rVlnOR/[*ddS'*0#%P7Eo4(4*rVloV4b<Was+14.s*t~>
-"A:iVM3Ro;!O.@YS-6(rs)P.=rrg,Cs(?9LS,mM@rVlj=qu6]k-M7<@Ff=JZXSVqtI%g96!p59A
-mJd3uA,Q?,li!=U,37WFrVlsOnC'u-rraPCs/L,=rr@3@rrI_@p&>5nG5k:_oI9b=!CGN<rrH-@
-rVlnOR/[*ddS'*0#%P7Eo4(4*rVloV4b<Was+14.s*t~>
-"A:iVM3Ro;!O.@YS-6(rs)P.=rrg,Cs(?9LS,mM@rVlj=qu6]k-M7<@Ff=JZXSVqtI%g96!p59A
-mJd3uA,Q?,li!=U,37WFrVlsOnC'u-rraPCs/L,=rr@3@rrI_@p&>5nG5k:_oI9b=!CGN<rrH-@
-rVlnOR/[*ddS'*0#%P7Eo4(4*rVloV4b<Was+14.s*t~>
-"A:iVM3Rl:!3lHR"G!EMEiT-="Me=CB3bCd!4;_)!$;%;!V[r5rr`6B_HQd8!IUU7rrKi?m/I*t
-A,ZE.oRHgj"!$CZ55kK`/b%4\rVm!Equ<[:qYpSJS+ZdcVKVu6ch&[brrGI?r;QdtaSl,>KUDc=
-!RaX1rrHW@rr3#'D#OA7i&uYkJcC<$i;\<~>
-"A:iVM3Rl:!3lHR"G!EMEiT-="Me=CB3bCd!4;_)!$;%;!V[r5rr`6B_HQd8!IUU7rrKi?m/I*t
-A,ZE.oRHgj"!$CZ55kK`/b%4\rVm!Equ<[:qYpSJS+ZdcVKVu6ch&[brrGI?r;QdtaSl,>KUDc=
-!RaX1rrHW@rr3#'D#OA7i&uYkJcC<$i;\<~>
-"A:iVM3Rl:!3lHR"G!EMEiT-="Me=CB3bCd!4;_)!$;%;!V[r5rr`6B_HQd8!IUU7rrKi?m/I*t
-A,ZE.oRHgj"!$CZ55kK`/b%4\rVm!Equ<[:qYpSJS+ZdcVKVu6ch&[brrGI?r;QdtaSl,>KUDc=
-!RaX1rrHW@rr3#'D#OA7i&uYkJcC<$i;\<~>
-"A:iVM3Ro;!O'H@rrgMCs)P.=rrg,Cs(Ae8rr=,;rrMj@o`#$m+2V4\rrITArr3"HU&P&nhI3>\
-rrVG(_X.:(jbC#[email protected]($+6gRf<<h/b%4\rVm!Equ<[:qYp\MS,`M0q#:PqG,("4kUHK1
-!CGN<rs)QFs6>F?KUDc=!RaX1rrHW@rr3#'D#XG9rb/]js+13$s5<p-~>
-"A:iVM3Ro;!O'H@rrgMCs)P.=rrg,Cs(Ae8rr=,;rrMj@o`#$m+2V4\rrITArr3"HU&P&nhI3>\
-rrVG(_X.:(jbC#[email protected]($+6gRf<<h/b%4\rVm!Equ<[:qYp\MS,`M0q#:PqG,("4kUHK1
-!CGN<rs)QFs6>F?KUDc=!RaX1rrHW@rr3#'D#XG9rb/]js+13$s5<p-~>
-"A:iVM3Ro;!O'H@rrgMCs)P.=rrg,Cs(Ae8rr=,;rrMj@o`#$m+2V4\rrITArr3"HU&P&nhI3>\
-rrVG(_X.:(jbC#[email protected]($+6gRf<<h/b%4\rVm!Equ<[:qYp\MS,`M0q#:PqG,("4kUHK1
-!CGN<rs)QFs6>F?KUDc=!RaX1rrHW@rr3#'D#XG9rb/]js+13$s5<p-~>
-"A:iVM'r6h"*ae$E;i3->g`RlWrE#$^g6ulB)Y-tHN*pIEC1"!K)YcQBL)tmMtR)OX^KZXrrL26
-r^-^;k5PA^aT->ZrrLn@lMgmTJH#QLq5"!W"d:Fsh_(&j6Na7`oU5YF"K_V&WcIt9"Q"/d6bE-n%
-HrJ%lcE#Es8S]Y&NNhhrs-tX6W;80KUDc=!RaX1rrL\]r^-^"f`(mOrZ?^kJcC<$huA3~>
-"A:iVM'r6h"*ae$E;i3->g`RlWrE#$^g6ulB)Y-tHN*pIEC1"!K)YcQBL)tmMtR)OX^KZXrrL26
-r^-^;k5PA^aT->ZrrLn@lMgmTJH#QLq5"!W"d:Fsh_(&j6Na7`oU5YF"K_V&WcIt9"Q"/d6bE-n%
-HrJ%lcE#Es8S]Y&NNhhrs-tX6W;80KUDc=!RaX1rrL\]r^-^"f`(mOrZ?^kJcC<$huA3~>
-"A:iVM'r6h"*ae$E;i3->g`RlWrE#$^g6ulB)Y-tHN*pIEC1"!K)YcQBL)tmMtR)OX^KZXrrL26
-r^-^;k5PA^aT->ZrrLn@lMgmTJH#QLq5"!W"d:Fsh_(&j6Na7`oU5YF"K_V&WcIt9"Q"/d6bE-n%
-HrJ%lcE#Es8S]Y&NNhhrs-tX6W;80KUDc=!RaX1rrL\]r^-^"f`(mOrZ?^kJcC<$huA3~>
-"%t`Umek`?jT#8Drn.G5s8VBUrr3,pkPtSCrn.;4rr2uYrn.;6rr2uWrn.;8p&>'hir&fVh#>t,
-mJ[%dpY"j1rrMuVlMgqTJ#rYL!;QQH"nL[MqW%/Gf`V$Ls7H9C"T&/uoBQ/O"6eFkrV-<pmdL2U
-hZ!NTm/GZ<h>I9Win<2gs6]=TrrMoUn,ECKrn.;5rVlm_hLY]Xs+14-s*t~>
-"%t`Umek`?jT#8Drn.G5s8VBUrr3,pkPtSCrn.;4rr2uYrn.;6rr2uWrn.;8p&>'hir&fVh#>t,
-mJ[%dpY"j1rrMuVlMgqTJ#rYL!;QQH"nL[MqW%/Gf`V$Ls7H9C"T&/uoBQ/O"6eFkrV-<pmdL2U
-hZ!NTm/GZ<h>I9Win<2gs6]=TrrMoUn,ECKrn.;5rVlm_hLY]Xs+14-s*t~>
-"%t`Umek`?jT#8Drn.G5s8VBUrr3,pkPtSCrn.;4rr2uYrn.;6rr2uWrn.;8p&>'hir&fVh#>t,
-mJ[%dpY"j1rrMuVlMgqTJ#rYL!;QQH"nL[MqW%/Gf`V$Ls7H9C"T&/uoBQ/O"6eFkrV-<pmdL2U
-hZ!NTm/GZ<h>I9Win<2gs6]=TrrMoUn,ECKrn.;5rVlm_hLY]Xs+14-s*t~>
-!D>M>rrN#pQ2^jZJcC<$JcFU,J,~>
-!D>M>rrN#pQ2^jZJcC<$JcFU,J,~>
-!D>M>rrN#pQ2^jZJcC<$JcFU,J,~>
-!D>M*s+13$s+13&s*t~>
-!D>M*s+13$s+13&s*t~>
-!D>M*s+13$s+13&s*t~>
-!D>M*s+13$s+13&s*t~>
-!D>M*s+13$s+13&s*t~>
-!D>M*s+13$s+13&s*t~>
-!D>NQrrK"krVlo0ipm$KT)JZh\GVHh_h%i=s+13$s/Z0M~>
-!D>NQrrK"krVlo0ipm$KT)JZh\GVHh_h%i=s+13$s/Z0M~>
-!D>NQrrK"krVlo0ipm$KT)JZh\GVHh_h%i=s+13$s/Z0M~>
-!D>NRrrSc-mJ[%d[sIB4rsbK>%<J'>s0[duMN!M0JcC<$JcC<$X8d\~>
-!D>NRrrSc-mJ[%d[sIB4rsbK>%<J'>s0[duMN!M0JcC<$JcC<$X8d\~>
-!D>NRrrSc-mJ[%d[sIB4rsbK>%<J'>s0[duMN!M0JcC<$JcC<$X8d\~>
-#>7/Ys.,5omJQtc^LI'5rsP9XW>)=oS,`M<TDjEAJcC<$JcD\KJ,~>
-#>7/Ys.,5omJQtc^LI'5rsP9XW>)=oS,`M<TDjEAJcC<$JcD\KJ,~>
-#>7/Ys.,5omJQtc^LI'5rsP9XW>)=oS,`M<TDjEAJcC<$JcD\KJ,~>
-#>7/YUPnOomJHnacVF36$>6gI*rkZbs8P:?JcC<$JcC<$VuM8~>
-#>7/YUPnOomJHnacVF36$>6gI*rkZbs8P:?JcC<$JcC<$VuM8~>
-#>7/YUPnOomJHnacVF36$>6gI*rkZbs8P:?JcC<$JcC<$VuM8~>
-#>7/YoCW&:mJ?h`dn0<6"RfFC*W>s:"6h]b:P&Oss+13$s/H$K~>
-#>7/YoCW&:mJ?h`dn0<6"RfFC*W>s:"6h]b:P&Oss+13$s/H$K~>
-#>7/YoCW&:mJ?h`dn0<6"RfFC*W>s:"6h]b:P&Oss+13$s/H$K~>
-!D>NQrrFh@qYpTB:A+Vm7Kc'As8V@[j+75]s+13$s/5mI~>
-!D>NQrrFh@qYpTB:A+Vm7Kc'As8V@[j+75]s+13$s/5mI~>
-!D>NQrrFh@qYpTB:A+Vm7Kc'As8V@[j+75]s+13$s/5mI~>
-!D>NQrrFh@qu6]>;Y0nm*o1A]s'3Bks+13$s+13Is*t~>
-!D>NQrrFh@qu6]>;Y0nm*o1A]s'3Bks+13$s+13Is*t~>
-!D>NQrrFh@qu6]>;Y0nm*o1A]s'3Bks+13$s+13Is*t~>
-!D>NQrrFh@r;Qi1B);6$$-D</*riT\s'3D9rrW+o]Rg*6s+13$s0;TS~>
-!D>NQrrFh@r;Qi1B);6$$-D</*riT\s'3D9rrW+o]Rg*6s+13$s0;TS~>
-!D>NQrrFh@r;Qi1B);6$$-D</*riT\s'3D9rrW+o]Rg*6s+13$s0;TS~>
-%SJn`a+f<dI>4^#s0R1?p&>?%JqahkK!>9SKDpT*YPnJ&pAdU4s+13$s+13Ts*t~>
-%SJn`a+f<dI>4^#s0R1?p&>?%JqahkK!>9SKDpT*YPnJ&pAdU4s+13$s+13Ts*t~>
-%SJn`a+f<dI>4^#s0R1?p&>?%JqahkK!>9SKDpT*YPnJ&pAdU4s+13$s+13Ts*t~>
-"%t`UcMWt2ZiC'>jR`BS[$D;i[Jp1+Yl9phLTURU!rS@iJcC<$JcC<$Z2]=~>
-"%t`UcMWt2ZiC'>jR`BS[$D;i[Jp1+Yl9phLTURU!rS@iJcC<$JcC<$Z2]=~>
-"%t`UcMWt2ZiC'>jR`BS[$D;i[Jp1+Yl9phLTURU!rS@iJcC<$JcC<$Z2]=~>
-!D>N9rrBb-rrK*@JcC<$JcC<$X8d\~>
-!D>N9rrBb-rrK*@JcC<$JcC<$X8d\~>
-!D>N9rrBb-rrK*@JcC<$JcC<$X8d\~>
-!D>N1rr_L<A`eRDJcC<$JcDeNJ,~>
-!D>N1rr_L<A`eRDJcC<$JcDeNJ,~>
-!D>N1rr_L<A`eRDJcC<$JcDeNJ,~>
-!D>N1rrW/foR[$ns+13$s/Q*L~>
-!D>N1rrW/foR[$ns+13$s/Q*L~>
-!D>N1rrW/foR[$ns+13$s/Q*L~>
-"A:iVs5s=1"5EkUl29$2ir8rZh:1/0s+13$s+13<s*t~>
-"A:iVs5s=1"5EkUl29$2ir8rZh:1/0s+13$s+13<s*t~>
-"A:iVs5s=1"5EkUl29$2ir8rZh:1/0s+13$s+13<s*t~>
-"A:iVh08ih"Bs"KI4bCg#D<'VcX9:FaasJCs+13$s-it<~>
-"A:iVh08ih"Bs"KI4bCg#D<'VcX9:FaasJCs+13$s-it<~>
-"A:iVh08ih"Bs"KI4bCg#D<'VcX9:FaasJCs+13$s-it<~>
-"A:iVM3S#>"P-'BI@pE:#01rEs6Fa?JcC<$JcC<$S,\!~>
-"A:iVM3S#>"P-'BI@pE:#01rEs6Fa?JcC<$JcC<$S,\!~>
-"A:iVM3S#>"P-'BI@pE:#01rEs6Fa?JcC<$JcC<$S,\!~>
-"A:iVM3S#>&_9GOI@m*XH^=^3]7/f?mX;?ks+13$s+13>s*t~>
-"A:iVM3S#>&_9GOI@m*XH^=^3]7/f?mX;?ks+13$s+13>s*t~>
-"A:iVM3S#>&_9GOI@m*XH^=^3]7/f?mX;?ks+13$s+13>s*t~>
-(eZsjM3S&?peOBZI63OaTp(Z>s1iGWB=NNmJcC<$JcD2=J,~>
-(eZsjM3S&?peOBZI63OaTp(Z>s1iGWB=NNmJcC<$JcD2=J,~>
-(eZsjM3S&?peOBZI63OaTp(Z>s1iGWB=NNmJcC<$JcD2=J,~>
-(eZsjiH7CN7\E6NhS8LYs3"=?s+$lZY&JslJcC<$JcD2=J,~>
-(eZsjiH7CN7\E6NhS8LYs3"=?s+$lZY&JslJcC<$JcD2=J,~>
-(eZsjiH7CN7\E6NhS8LYs3"=?s+$lZY&JslJcC<$JcD2=J,~>
-#tmA[s6JIqhUY0nrs?kHs+R*>s8&m>JcC<$JcC<$S,\!~>
-#tmA[s6JIqhUY0nrs?kHs+R*>s8&m>JcC<$JcC<$S,\!~>
-#tmA[s6JIqhUY0nrs?kHs+R*>s8&m>JcC<$JcC<$S,\!~>
-!D>NPrrrDA=TA!drr3;J;ZD6@qZ$K"Ck;V;s+13$s-s%=~>
-!D>NPrrrDA=TA!drr3;J;ZD6@qZ$K"Ck;V;s+13$s-s%=~>
-!D>NPrrrDA=TA!drr3;J;ZD6@qZ$K"Ck;V;s+13$s-s%=~>
-$qi\^s5;#@_cHg;R?IQk#ci.Ks*1Qc[V16lJcC<$JcD2=J,~>
-$qi\^s5;#@_cHg;R?IQk#ci.Ks*1Qc[V16lJcC<$JcD2=J,~>
-$qi\^s5;#@_cHg;R?IQk#ci.Ks*1Qc[V16lJcC<$JcD2=J,~>
-#>7/Ys-lqc>Q+R%Pl=S]G5_FBGZ/@.s+13$s+13<s*t~>
-#>7/Ys-lqc>Q+R%Pl=S]G5_FBGZ/@.s+13$s+13<s*t~>
-#>7/Ys-lqc>Q+R%Pl=S]G5_FBGZ/@.s+13$s+13<s*t~>
-!D>M*s+13$s+13&s*t~>
-!D>M*s+13$s+13&s*t~>
-!D>M*s+13$s+13&s*t~>
-!D>M*s+13$s+13&s*t~>
-!D>M*s+13$s+13&s*t~>
-!D>M*s+13$s+13&s*t~>
-!D>M*s+13$s+13&s*t~>
-!D>M*s+13$s+13&s*t~>
-!D>M*s+13$s+13&s*t~>
-!D>M*s+13$s+13&s*t~>
-!D>M*s+13$s+13&s*t~>
-!D>M*s+13$s+13&s*t~>
-"A:iVrHeGa#!r.ds)PpSp&>3n>ok%TqqqDSq^h^f!K[21s+13$s+13ns*t~>
-"A:iVrHeGa#!r.ds)PpSp&>3n>ok%TqqqDSq^h^f!K[21s+13$s+13ns*t~>
-"A:iVrHeGa#!r.ds)PpSp&>3n>ok%TqqqDSq^h^f!K[21s+13$s+13ns*t~>
-"A:iVM3S#>!S0a>rrQHBrq??qB=@j?dS&Kt!DCl?rrJ._JcC<$JcC<$bQ!(~>
-"A:iVM3S#>!S0a>rrQHBrq??qB=@j?dS&Kt!DCl?rrJ._JcC<$JcC<$bQ!(~>
-"A:iVM3S#>!S0a>rrQHBrq??qB=@j?dS&Kt!DCl?rrJ._JcC<$JcC<$bQ!(~>
-#tmA[Vm$.#r2Oo<rrHB@pAYG3[f?BU9E5%Cn,E=fl.l:<!64s:$./AAbQ$Y^s8U+<^B!*hrr<u:
-^B!3krrBk6^B!;Fs+13$s+13us*t~>
-#tmA[Vm$.#r2Oo<rrHB@pAYG3[f?BU9E5%Cn,E=fl.l:<!64s:$./AAbQ$Y^s8U+<^B!*hrr<u:
-^B!3krrBk6^B!;Fs+13$s+13us*t~>
-#tmA[Vm$.#r2Oo<rrHB@pAYG3[f?BU9E5%Cn,E=fl.l:<!64s:$./AAbQ$Y^s8U+<^B!*hrr<u:
-^B!3krrBk6^B!;Fs+13$s+13us*t~>
-!D>NPrrJs@qu6\1[.jS,B60c?KhMIG>f$F>!NC2?rr=,<rs;-HlS8F'MZ:+rra#_Uf`/6dra#_X
-h#FNara#VXi.:oZs+13$s3q!u~>
-!D>NPrrJs@qu6\1[.jS,B60c?KhMIG>f$F>!NC2?rr=,<rs;-HlS8F'MZ:+rra#_Uf`/6dra#_X
-h#FNara#VXi.:oZs+13$s3q!u~>
-!D>NPrrJs@qu6\1[.jS,B60c?KhMIG>f$F>!NC2?rr=,<rs;-HlS8F'MZ:+rra#_Uf`/6dra#_X
-h#FNara#VXi.:oZs+13$s3q!u~>
-!D>NQrrJU@qYpT[2#%"[B39M-AkW1(X+Kg?jFOf>rr=,<rs;-HlS8F'MZ5`trr3+VQ2`K)rr3+K
-U&QA5rr3#-e:IXNs+13$s3q!u~>
-!D>NQrrJU@qYpT[2#%"[B39M-AkW1(X+Kg?jFOf>rr=,<rs;-HlS8F'MZ5`trr3+VQ2`K)rr3+K
-U&QA5rr3#-e:IXNs+13$s3q!u~>
-!D>NQrrJU@qYpT[2#%"[B39M-AkW1(X+Kg?jFOf>rr=,<rs;-HlS8F'MZ5`trr3+VQ2`K)rr3+K
-U&QA5rr3#-e:IXNs+13$s3q!u~>
-!D>NRrrSFGq"k!kDm&j7"_Y:Ds3aR>rrbOCs2S1=rr=,<rs;-HlS8F'MZ5`trr3+VQ2`K)rr34N
-U&V$'AnJ&os+13$s+13ts*t~>
-!D>NRrrSFGq"k!kDm&j7"_Y:Ds3aR>rrbOCs2S1=rr=,<rs;-HlS8F'MZ5`trr3+VQ2`K)rr34N
-U&V$'AnJ&os+13$s+13ts*t~>
-!D>NRrrSFGq"k!kDm&j7"_Y:Ds3aR>rrbOCs2S1=rr=,<rs;-HlS8F'MZ5`trr3+VQ2`K)rr34N
-U&V$'AnJ&os+13$s+13ts*t~>
-#"q&Xs-8l>qYpS+](Z.-B=@j?dS'T>"NXX/@F+oP!$;(<#t<M41&mGps#T3>rre+Bs"<a=rs*qF
-s'i@E\(?32JcC<$JcF-tJ,~>
-#"q&Xs-8l>qYpS+](Z.-B=@j?dS'T>"NXX/@F+oP!$;(<#t<M41&mGps#T3>rre+Bs"<a=rs*qF
-s'i@E\(?32JcC<$JcF-tJ,~>
-#"q&Xs-8l>qYpS+](Z.-B=@j?dS'T>"NXX/@F+oP!$;(<#t<M41&mGps#T3>rre+Bs"<a=rs*qF
-s'i@E\(?32JcC<$JcF-tJ,~>
-"\UrWSW34:rrQZBrq??qB=@j?dS'Q=![-G]r;R9Ks2TNes$bT+1&mGps#T3>rre+Bs"<a=rrd_C
-s!.@=rrItfrr3&A/!>J`JcC<$JcFF'J,~>
-"\UrWSW34:rrQZBrq??qB=@j?dS'Q=![-G]r;R9Ks2TNes$bT+1&mGps#T3>rre+Bs"<a=rrd_C
-s!.@=rrItfrr3&A/!>J`JcC<$JcFF'J,~>
-"\UrWSW34:rrQZBrq??qB=@j?dS'Q=![-G]r;R9Ks2TNes$bT+1&mGps#T3>rre+Bs"<a=rrd_C
-s!.@=rrItfrr3&A/!>J`JcC<$JcFF'J,~>
-"A:iVO;Rp;"^M*-EkD;Crrr.#*Zd]BrVlrj2YI"J&*t?<p](9d4rX\IGkqC42?"X"Jbf?</H-[n
-MYdAE,5rVaPl(I[!l>M%JcC<$JcC<$g&HR~>
-"A:iVO;Rp;"^M*-EkD;Crrr.#*Zd]BrVlrj2YI"J&*t?<p](9d4rX\IGkqC42?"X"Jbf?</H-[n
-MYdAE,5rVaPl(I[!l>M%JcC<$JcC<$g&HR~>
-"A:iVO;Rp;"^M*-EkD;Crrr.#*Zd]BrVlrj2YI"J&*t?<p](9d4rX\IGkqC42?"X"Jbf?</H-[n
-MYdAE,5rVaPl(I[!l>M%JcC<$JcC<$g&HR~>
-!D>N"rrMF?JcC<$JcC<$\Gq'~>
-!D>N"rrMF?JcC<$JcC<$\Gq'~>
-!D>N"rrMF?JcC<$JcC<$\Gq'~>
-!D>N"rrMF?JcC<$JcC<$\Gq'~>
-!D>N"rrMF?JcC<$JcC<$\Gq'~>
-!D>N"rrMF?JcC<$JcC<$\Gq'~>
-!D>N"rrM_GJcC<$JcC<$\Gq'~>
-!D>N"rrM_GJcC<$JcC<$\Gq'~>
-!D>N"rrM_GJcC<$JcC<$\Gq'~>
-!D>M*s+13$s+13&s*t~>
-!D>M*s+13$s+13&s*t~>
-!D>M*s+13$s+13&s*t~>
-!D>NQrrIH;oD\f.li.!"FSu.?F^'4jrrR%AK'!"7oNPOlmf*=XI"D<Ks+13$s7QDB~>
-!D>NQrrIH;oD\f.li.!"FSu.?F^'4jrrR%AK'!"7oNPOlmf*=XI"D<Ks+13$s7QDB~>
-!D>NQrrIH;oD\f.li.!"FSu.?F^'4jrrR%AK'!"7oNPOlmf*=XI"D<Ks+13$s7QDB~>
-#tmA[V69hPmGN'ZrrHa>li."*b5D8@bH`l#rrU9A4lu\Gqn\)'mf*=Q1YMd/Qb7nLJcC<$TDsE~>
-#tmA[V69hPmGN'ZrrHa>li."*b5D8@bH`l#rrU9A4lu\Gqn\)'mf*=Q1YMd/Qb7nLJcC<$TDsE~>
-#tmA[V69hPmGN'ZrrHa>li."*b5D8@bH`l#rrU9A4lu\Gqn\)'mf*=Q1YMd/Qb7nLJcC<$TDsE~>
-#tmA[n8Punj$2c%rrQrD)WUhulS8;:!T6-$rrKH@mf*=Q1YMd/G,BijJcC<$TDsE~>
-#tmA[n8Punj$2c%rrQrD)WUhulS8;:!T6-$rrKH@mf*=Q1YMd/G,BijJcC<$TDsE~>
-#tmA[n8Punj$2c%rrQrD)WUhulS8;:!T6-$rrKH@mf*=Q1YMd/G,BijJcC<$TDsE~>
-#YR8Zs6a"o,j+k$"+miX*r>m;&MNhW!_OI]qu6]_1&LtOi'%&=!U2-6*XdYos6(XJ*d)V6s8)[8
-!L<EYrrKH@pAY0m`Vgh\YP[T:VZ%V=\GZBJr>l?_rRb34I3'HPs8TJ)*WsmkpmV.&$f1io*Y&i)
-*rl96M#JG%-KtK-K&fcM0C",gJcC<$ZN#F~>
-#YR8Zs6a"o,j+k$"+miX*r>m;&MNhW!_OI]qu6]_1&LtOi'%&=!U2-6*XdYos6(XJ*d)V6s8)[8
-!L<EYrrKH@pAY0m`Vgh\YP[T:VZ%V=\GZBJr>l?_rRb34I3'HPs8TJ)*WsmkpmV.&$f1io*Y&i)
-*rl96M#JG%-KtK-K&fcM0C",gJcC<$ZN#F~>
-#YR8Zs6a"o,j+k$"+miX*r>m;&MNhW!_OI]qu6]_1&LtOi'%&=!U2-6*XdYos6(XJ*d)V6s8)[8
-!L<EYrrKH@pAY0m`Vgh\YP[T:VZ%V=\GZBJr>l?_rRb34I3'HPs8TJ)*WsmkpmV.&$f1io*Y&i)
-*rl96M#JG%-KtK-K&fcM0C",gJcC<$ZN#F~>
-#tmA[j`JBojA4A"rr=,:rrGJko`"sd-N!fDlS8;:!T6->rrFb?rr37OU&QA5s8S+>qYpS-\,QC.
-ZYK46!VIi=rrd2tl3hh8rrG+?qu6sSnGfp5T`>$9qtpBq*rio]rVljnrr3"BVZ$MqVKVt=$1o\H
-s*Z-8s6):js+13$s0DZT~>
-#tmA[j`JBojA4A"rr=,:rrGJko`"sd-N!fDlS8;:!T6->rrFb?rr37OU&QA5s8S+>qYpS-\,QC.
-ZYK46!VIi=rrd2tl3hh8rrG+?qu6sSnGfp5T`>$9qtpBq*rio]rVljnrr3"BVZ$MqVKVt=$1o\H
-s*Z-8s6):js+13$s0DZT~>
-#tmA[j`JBojA4A"rr=,:rrGJko`"sd-N!fDlS8;:!T6->rrFb?rr37OU&QA5s8S+>qYpS-\,QC.
-ZYK46!VIi=rrd2tl3hh8rrG+?qu6sSnGfp5T`>$9qtpBq*rio]rVljnrr3"BVZ$MqVKVt=$1o\H
-s*Z-8s6):js+13$s0DZT~>
-#tmA[Z+0ffmGruorr=,+rrMj@qu6]_1&LtOi'%&=!A9uCW=)Uts!.@>s,N->s8Dnq!CO?qrrKH@
-pAY0d-i<oEl8/D="$#BAlM[[b*q93<BE%o5D#F=nrM]l7s1Mh9rrI;?rVlnq:B%4!U+--BI@pQ>
-n9BNaJcC<$ZN#F~>
-#tmA[Z+0ffmGruorr=,+rrMj@qu6]_1&LtOi'%&=!A9uCW=)Uts!.@>s,N->s8Dnq!CO?qrrKH@
-pAY0d-i<oEl8/D="$#BAlM[[b*q93<BE%o5D#F=nrM]l7s1Mh9rrI;?rVlnq:B%4!U+--BI@pQ>
-n9BNaJcC<$ZN#F~>
-#tmA[Z+0ffmGruorr=,+rrMj@qu6]_1&LtOi'%&=!A9uCW=)Uts!.@>s,N->s8Dnq!CO?qrrKH@
-pAY0d-i<oEl8/D="$#BAlM[[b*q93<BE%o5D#F=nrM]l7s1Mh9rrI;?rVlnq:B%4!U+--BI@pQ>
-n9BNaJcC<$ZN#F~>
-!D>NQrrJ/QoD\e3li."[-N!fDlS8;:!T6->rrF`grGr=hs+cMkN.JhFs-EV)!A:k\rrKH@pAY0d
--i<oEl8/D="$#B2LAc/r'_).2BDhc1k(N\S!tkRH@/9g'G,G6<!N%dREs.C#s*^Mjs+13$s/uBP~>
-!D>NQrrJ/QoD\e3li."[-N!fDlS8;:!T6->rrF`grGr=hs+cMkN.JhFs-EV)!A:k\rrKH@pAY0d
--i<oEl8/D="$#B2LAc/r'_).2BDhc1k(N\S!tkRH@/9g'G,G6<!N%dREs.C#s*^Mjs+13$s/uBP~>
-!D>NQrrJ/QoD\e3li."[-N!fDlS8;:!T6->rrF`grGr=hs+cMkN.JhFs-EV)!A:k\rrKH@pAY0d
--i<oEl8/D="$#B2LAc/r'_).2BDhc1k(N\S!tkRH@/9g'G,G6<!N%dREs.C#s*^Mjs+13$s/uBP~>
-!D>NArr=,:rrI;!o`"sd-N!fDlS8;:!T6->rrFb?qu6eNOHG[Brr2s>rr3&1/@YWY!OHP7rrMd?
-rVltal0:)'rrY7Ah`h&>"dftms0cS<rrL2@rr3+[&c]OPrVlkIrr34HVZ6[Gs/'u9rrIP?JcC<$
-JcDnQJ,~>
-!D>NArr=,:rrI;!o`"sd-N!fDlS8;:!T6->rrFb?qu6eNOHG[Brr2s>rr3&1/@YWY!OHP7rrMd?
-rVltal0:)'rrY7Ah`h&>"dftms0cS<rrL2@rr3+[&c]OPrVlkIrr34HVZ6[Gs/'u9rrIP?JcC<$
-JcDnQJ,~>
-!D>NArr=,:rrI;!o`"sd-N!fDlS8;:!T6->rrFb?qu6eNOHG[Brr2s>rr3&1/@YWY!OHP7rrMd?
-rVltal0:)'rrY7Ah`h&>"dftms0cS<rrL2@rr3+[&c]OPrVlkIrr34HVZ6[Gs/'u9rrIP?JcC<$
-JcDnQJ,~>
-!D>NDrs#)m;$g)sOT#1[%P@AR"ER<H;3V"Z"Dg[A;4IRb#\6F=;54*j]iY21"KMM%\l8T*"1%t,
-[/No/IRUaGo2.Lk;8N&-!W8Vh;$3-Ul8/D="$#B7R/TqdP99;o[V,O<!Uc$J;$<@(s6>O@;#mj"
-rs.%n;,Ok'j+I>.!*K7#!I^Sks+13$s/uBP~>
-!D>NDrs#)m;$g)sOT#1[%P@AR"ER<H;3V"Z"Dg[A;4IRb#\6F=;54*j]iY21"KMM%\l8T*"1%t,
-[/No/IRUaGo2.Lk;8N&-!W8Vh;$3-Ul8/D="$#B7R/TqdP99;o[V,O<!Uc$J;$<@(s6>O@;#mj"
-rs.%n;,Ok'j+I>.!*K7#!I^Sks+13$s/uBP~>
-!D>NDrs#)m;$g)sOT#1[%P@AR"ER<H;3V"Z"Dg[A;4IRb#\6F=;54*j]iY21"KMM%\l8T*"1%t,
-[/No/IRUaGo2.Lk;8N&-!W8Vh;$3-Ul8/D="$#B7R/TqdP99;o[V,O<!Uc$J;$<@(s6>O@;#mj"
-rs.%n;,Ok'j+I>.!*K7#!I^Sks+13$s/uBP~>
-!D>NDrrD*WbQ-Q!rrLHrp&>$CrlbB"rr2uJrlbB%rr2uHrlbB'rr2uErlbN-s8Pm:rlbIg^&S*2
-bQR%cnc/OcbQ.&)rrDflbQID8qpt`G"5!DLoDZr;nC@I:nDX9E!:Kj1"SL4Cs6T^.!<)lr!oD/F
-rr2u]rlbAfrr3#\m",1fs+13Qs*t~>
-!D>NDrrD*WbQ-Q!rrLHrp&>$CrlbB"rr2uJrlbB%rr2uHrlbB'rr2uErlbN-s8Pm:rlbIg^&S*2
-bQR%cnc/OcbQ.&)rrDflbQID8qpt`G"5!DLoDZr;nC@I:nDX9E!:Kj1"SL4Cs6T^.!<)lr!oD/F
-rr2u]rlbAfrr3#\m",1fs+13Qs*t~>
-!D>NDrrD*WbQ-Q!rrLHrp&>$CrlbB"rr2uJrlbB%rr2uHrlbB'rr2uErlbN-s8Pm:rlbIg^&S*2
-bQR%cnc/OcbQ.&)rrDflbQID8qpt`G"5!DLoDZr;nC@I:nDX9E!:Kj1"SL4Cs6T^.!<)lr!oD/F
-rr2u]rlbAfrr3#\m",1fs+13Qs*t~>
-!D>MarrFV?rq?G6YCZ_)s+13$s3q!u~>
-!D>MarrFV?rq?G6YCZ_)s+13$s3q!u~>
-!D>MarrFV?rq?G6YCZ_)s+13$s3q!u~>
-!D>M`rr=PJ-30Zhs+13$s+13us*t~>
-!D>M`rr=PJ-30Zhs+13$s+13us*t~>
-!D>M`rr=PJ-30Zhs+13$s+13us*t~>
-!D>M*s+13$s+13&s*t~>
-!D>M*s+13$s+13&s*t~>
-!D>M*s+13$s+13&s*t~>
-"A:iVs2Y,1!3Z>$!Q4&Ns+13$s+132s*t~>
-"A:iVs2Y,1!3Z>$!Q4&Ns+13$s+132s*t~>
-"A:iVs2Y,1!3Z>$!Q4&Ns+13$s+132s*t~>
-"A:iV`..c8#(NHKs0$t?JcC<$JcC<$OT0h~>
-"A:iV`..c8#(NHKs0$t?JcC<$JcC<$OT0h~>
-"A:iV`..c8#(NHKs0$t?JcC<$JcC<$OT0h~>
-"A:iVM3S#>!S0a>rrTTDqgncus+13$s,m>3~>
-"A:iVM3S#>!S0a>rrTTDqgncus+13$s,m>3~>
-"A:iVM3S#>!S0a>rrTTDqgncus+13$s,m>3~>
-#tmA[hr=\9pK5Z<rrL#?JcC<$JcC<$OoKq~>
-#tmA[hr=\9pK5Z<rrL#?JcC<$JcC<$OoKq~>
-#tmA[hr=\9pK5Z<rrL#?JcC<$JcC<$OoKq~>
-!D>NPrrG@?qu6]<<.Y(#s+13$s-!D4~>
-!D>NPrrG@?qu6]<<.Y(#s+13$s-!D4~>
-!D>NPrrG@?qu6]<<.Y(#s+13$s-!D4~>
-!D>NRrrVaZjneuXg-^GkJcC<$JcCo5J,~>
-!D>NRrrVaZjneuXg-^GkJcC<$JcCo5J,~>
-!D>NRrrVaZjneuXg-^GkJcC<$JcCo5J,~>
-#"q&Xs5RM>qYpTI7tL\ks+13$s,m>3~>
-#"q&Xs5RM>qYpTI7tL\ks+13$s,m>3~>
-#"q&Xs5RM>qYpTI7tL\ks+13$s,m>3~>
-"\UrWgN^j:rrU/EqLSZts+13$s,m>3~>
-"\UrWgN^j:rrU/EqLSZts+13$s,m>3~>
-"\UrWgN^j:rrU/EqLSZts+13$s,m>3~>
-"A:iVM,sS>"gS+-]QWRks+13$s+133s*t~>
-"A:iVM,sS>"gS+-]QWRks+13$s+133s*t~>
-"A:iVM,sS>"gS+-]QWRks+13$s+133s*t~>
-"%t`UaS^ktWrN+,i.:oZs+13$s,[21~>
-"%t`UaS^ktWrN+,i.:oZs+13$s,[21~>
-"%t`UaS^ktWrN+,i.:oZs+13$s,[21~>
-!D>M*s+13$s+13&s*t~>
-!D>M*s+13$s+13&s*t~>
-!D>M*s+13$s+13&s*t~>
-!D>M*s+13$s+13&s*t~>
-!D>M*s+13$s+13&s*t~>
-!D>M*s+13$s+13&s*t~>
-!D>M*s+13$s+13&s*t~>
-!D>M*s+13$s+13&s*t~>
-!D>M*s+13$s+13&s*t~>
-%%EndData
-showpage
-%%Trailer
-end
-%%EOF
diff --git a/lib/stdlib/doc/src/ushell3.gif b/lib/stdlib/doc/src/ushell3.gif
deleted file mode 100644
index 2141268b91..0000000000
--- a/lib/stdlib/doc/src/ushell3.gif
+++ /dev/null
Binary files differ
diff --git a/lib/stdlib/doc/src/ushell3.ps b/lib/stdlib/doc/src/ushell3.ps
deleted file mode 100644
index dd64eeab5c..0000000000
--- a/lib/stdlib/doc/src/ushell3.ps
+++ /dev/null
@@ -1,662 +0,0 @@
-%!PS-Adobe-3.0
-%%Creator: GIMP PostScript file plugin V 1.17 by Peter Kirchgessner
-%%Title: ushell3.ps
-%%CreationDate: Mon Mar 16 12:15:17 2009
-%%DocumentData: Clean7Bit
-%%LanguageLevel: 2
-%%Pages: 1
-%%BoundingBox: 14 14 468 78
-%%EndComments
-%%BeginProlog
-% Use own dictionary to avoid conflicts
-10 dict begin
-%%EndProlog
-%%Page: 1 1
-% Translate for offset
-14.173228346456694 14.173228346456694 translate
-% Translate to begin of first scanline
-0 63.070866141732289 translate
-453.54330708661422 -63.070866141732289 scale
-% Image geometry
-640 89 8
-% Transformation matrix
-[ 640 0 0 89 0 0 ]
-% Strings to hold RGB-samples per scanline
-/rstr 640 string def
-/gstr 640 string def
-/bstr 640 string def
-{currentfile /ASCII85Decode filter /RunLengthDecode filter rstr readstring pop}
-{currentfile /ASCII85Decode filter /RunLengthDecode filter gstr readstring pop}
-{currentfile /ASCII85Decode filter /RunLengthDecode filter bstr readstring pop}
-true 3
-%%BeginData: 37475 ASCII Bytes
-colorimage
-!1\W%J`VIEJ`VLFJ,~>
-!1\W%J`VIEJ`VLFJ,~>
-!1\W%J`VIEJ`VLFJ,~>
-!T[+/6@hIS6@hIU6@]~>
-!T[+/6@hIS6@hIU6@]~>
-!T[+/6@hIS6@hIU6@]~>
-!ouWfJQ.2"JQ.2"KN*I~>
-!ouWfJQ.2"JQ.2"KN*I~>
-!ouWfJQ.2"JQ.2"KN*I~>
-!ouXLJcC<$JcC<$K`?Q~>
-!ouXLJcC<$JcC<$K`?Q~>
-!ouXLJcC<$JcC<$K`?Q~>
-!ouXLQ2^m!`0L?'S`PG&JcC<$i;\<~>
-!ouXLQ2^m!`0L?'S`PG&JcC<$i;\<~>
-!ouXLQ2^m!`0L?'S`PG&JcC<$i;\<~>
-"QVjNs.9-i!1*E[!L)+*rrR=EF8Z%>Dc_2VrrI?7rr3)%^&N-N<rg/5rr?^0<rgP6rrU,eg\:^K
-o6/O]!ioDNpAY05U[\9aJa!(4!2BHo!,VW6!lAR@JcC<$JcF^/J,~>
-"QVjNs.9-i!1*E[!L)+*rrR=EF8Z%>Dc_2VrrI?7rr3)%^&N-N<rg/5rr?^0<rgP6rrU,eg\:^K
-o6/O]!ioDNpAY05U[\9aJa!(4!2BHo!,VW6!lAR@JcC<$JcF^/J,~>
-"QVjNs.9-i!1*E[!L)+*rrR=EF8Z%>Dc_2VrrI?7rr3)%^&N-N<rg/5rr?^0<rgP6rrU,eg\:^K
-o6/O]!ioDNpAY05U[\9aJa!(4!2BHo!,VW6!lAR@JcC<$JcF^/J,~>
-"lqsOs)!Pi_uSNdrrHB@o)Ad;\gmXX!mS).p&>%Ili-neJXl`h]D]YJlM1AZb5K6Z:po`k!N()7
-rrML@l2LdgT^2UZil(<`rrJFsrVlntF7K88K;)-<s8T'RrkniDCAn/50C=>jJcC<$iW"E~>
-"lqsOs)!Pi_uSNdrrHB@o)Ad;\gmXX!mS).p&>%Ili-neJXl`h]D]YJlM1AZb5K6Z:po`k!N()7
-rrML@l2LdgT^2UZil(<`rrJFsrVlntF7K88K;)-<s8T'RrkniDCAn/50C=>jJcC<$iW"E~>
-"lqsOs)!Pi_uSNdrrHB@o)Ad;\gmXX!mS).p&>%Ili-neJXl`h]D]YJlM1AZb5K6Z:po`k!N()7
-rrML@l2LdgT^2UZil(<`rrJFsrVlntF7K88K;)-<s8T'RrkniDCAn/50C=>jJcC<$iW"E~>
-"lqsOs)#"3rrHB@nc&X\.f95Hkqi#4!AWp>rrdnCs!dR.rrSCIp@&"_b$si5rrML@l2LdPK]E(5
-GGY9<!NC/2rs4ONpZ4C7s,`6>rrN#\rVlo\2M(mZs+14/s*t~>
-"lqsOs)#"3rrHB@nc&X\.f95Hkqi#4!AWp>rrdnCs!dR.rrSCIp@&"_b$si5rrML@l2LdPK]E(5
-GGY9<!NC/2rs4ONpZ4C7s,`6>rrN#\rVlo\2M(mZs+14/s*t~>
-"lqsOs)#"3rrHB@nc&X\.f95Hkqi#4!AWp>rrdnCs!dR.rrSCIp@&"_b$si5rrML@l2LdPK]E(5
-GGY9<!NC/2rs4ONpZ4C7s,`6>rrN#\rVlo\2M(mZs+14/s*t~>
-#in9Rs)"@hjludE!Us(f*"5s=s'2Za*#r;Ts6`DV*!'XArr3#i.f95Hkqi#4$2ktGs.=c>s!c4l
-*!(ffp&>*eKVIo7!Q/(<rrCjQ*!EJBm4518*!<VHr42bG&A7u":Z[6L*5hd.*"`Z#*8gPk!Q/1@
-rrsVGs/-hF]Dhg?\f;.l*$"qWWG$>m*$OSArs>H^rr<#^9E1*5p\t46JcC<$JcF^/J,~>
-#in9Rs)"@hjludE!Us(f*"5s=s'2Za*#r;Ts6`DV*!'XArr3#i.f95Hkqi#4$2ktGs.=c>s!c4l
-*!(ffp&>*eKVIo7!Q/(<rrCjQ*!EJBm4518*!<VHr42bG&A7u":Z[6L*5hd.*"`Z#*8gPk!Q/1@
-rrsVGs/-hF]Dhg?\f;.l*$"qWWG$>m*$OSArs>H^rr<#^9E1*5p\t46JcC<$JcF^/J,~>
-#in9Rs)"@hjludE!Us(f*"5s=s'2Za*#r;Ts6`DV*!'XArr3#i.f95Hkqi#4$2ktGs.=c>s!c4l
-*!(ffp&>*eKVIo7!Q/(<rrCjQ*!EJBm4518*!<VHr42bG&A7u":Z[6L*5hd.*"`Z#*8gPk!Q/1@
-rrsVGs/-hF]Dhg?\f;.l*$"qWWG$>m*$OSArs>H^rr<#^9E1*5p\t46JcC<$JcF^/J,~>
-#in9Rs(s&?2H0VT!G&_>rsZf$s'-u6s8T->s&7&=rrJm@rr3#i.f95Hkqhu3#T`sFSpp_><^Zld
-!I1F5rrJj?mJd4)=nhq!7G$o6ErQ(@4l><[rVm<akl8@2QiI(:nGiNVK_>?L_HQutn,FF,rrHT?
-r;QeAV>^DuW>MT6s7dl/rs"REs8UEef)5OJ*J+6As+14/s*t~>
-#in9Rs(s&?2H0VT!G&_>rsZf$s'-u6s8T->s&7&=rrJm@rr3#i.f95Hkqhu3#T`sFSpp_><^Zld
-!I1F5rrJj?mJd4)=nhq!7G$o6ErQ(@4l><[rVm<akl8@2QiI(:nGiNVK_>?L_HQutn,FF,rrHT?
-r;QeAV>^DuW>MT6s7dl/rs"REs8UEef)5OJ*J+6As+14/s*t~>
-#in9Rs(s&?2H0VT!G&_>rsZf$s'-u6s8T->s&7&=rrJm@rr3#i.f95Hkqhu3#T`sFSpp_><^Zld
-!I1F5rrJj?mJd4)=nhq!7G$o6ErQ(@4l><[rVm<akl8@2QiI(:nGiNVK_>?L_HQutn,FF,rrHT?
-r;QeAV>^DuW>MT6s7dl/rs"REs8UEef)5OJ*J+6As+14/s*t~>
-"lqsOs)#";rrJFMriH=Cs8Q??rr3,%EW8soriH3>HN*pFngaP:!U2E4rrciCl&)D8rrIA?pAY3[
-N2>qA!Q/(<rrDWgXTL6.m4eM="$PQ&3;rj[2<b(S?N0s.E:s82R=t85#/XRDCU3s\rVln-]);R/
-GGY9<!NC/>rrMm?nG`]SNW9#h7m6eM!$-XjJcC<$iW"E~>
-"lqsOs)#";rrJFMriH=Cs8Q??rr3,%EW8soriH3>HN*pFngaP:!U2E4rrciCl&)D8rrIA?pAY3[
-N2>qA!Q/(<rrDWgXTL6.m4eM="$PQ&3;rj[2<b(S?N0s.E:s82R=t85#/XRDCU3s\rVln-]);R/
-GGY9<!NC/>rrMm?nG`]SNW9#h7m6eM!$-XjJcC<$iW"E~>
-"lqsOs)#";rrJFMriH=Cs8Q??rr3,%EW8soriH3>HN*pFngaP:!U2E4rrciCl&)D8rrIA?pAY3[
-N2>qA!Q/(<rrDWgXTL6.m4eM="$PQ&3;rj[2<b(S?N0s.E:s82R=t85#/XRDCU3s\rVln-]);R/
-GGY9<!NC/>rrMm?nG`]SNW9#h7m6eM!$-XjJcC<$iW"E~>
-"lqsOs)#":rrAAaD?P3us'3D>rrfBBs&2tsD?.$BrrM[?qu6]]1\C\Lp*RC[q>UJ?V"Xfh^Kp4+
-!Q/(=rrN"UrGD]YfBk9jrrYFAj>d,<"?#EC^0^[9!L\W6rs$>Ds(eq?*W?!=@_2L;!I(C=rrK*?
-rr3#o,k1g7OH'8>!T-'<rr='js+13$s5F!.~>
-"lqsOs)#":rrAAaD?P3us'3D>rrfBBs&2tsD?.$BrrM[?qu6]]1\C\Lp*RC[q>UJ?V"Xfh^Kp4+
-!Q/(=rrN"UrGD]YfBk9jrrYFAj>d,<"?#EC^0^[9!L\W6rs$>Ds(eq?*W?!=@_2L;!I(C=rrK*?
-rr3#o,k1g7OH'8>!T-'<rr='js+13$s5F!.~>
-"lqsOs)#":rrAAaD?P3us'3D>rrfBBs&2tsD?.$BrrM[?qu6]]1\C\Lp*RC[q>UJ?V"Xfh^Kp4+
-!Q/(=rrN"UrGD]YfBk9jrrYFAj>d,<"?#EC^0^[9!L\W6rs$>Ds(eq?*W?!=@_2L;!I(C=rrK*?
-rr3#o,k1g7OH'8>!T-'<rr='js+13$s5F!.~>
-"lqsOs)#";rrK1Rrr3,.C&_GSrr3,%EW8tZq>UKd.f95Hkqhu3"84(R@K-9-Mu!AP!I1F>rrV/%
-Zi0n*m!?)+rrV55[Jp1,odBb="fictm1u>nrrYFAj>d,<"?#EC^0^[9"dt&Ds,$[Lrs$>D^O^an
-*W?!=@_2L;#C!$Es+UKPF8l1?pa#A/!K`<?rrM"?rVlnZNIh+\s+14/s*t~>
-"lqsOs)#";rrK1Rrr3,.C&_GSrr3,%EW8tZq>UKd.f95Hkqhu3"84(R@K-9-Mu!AP!I1F>rrV/%
-Zi0n*m!?)+rrV55[Jp1,odBb="fictm1u>nrrYFAj>d,<"?#EC^0^[9"dt&Ds,$[Lrs$>D^O^an
-*W?!=@_2L;#C!$Es+UKPF8l1?pa#A/!K`<?rrM"?rVlnZNIh+\s+14/s*t~>
-"lqsOs)#";rrK1Rrr3,.C&_GSrr3,%EW8tZq>UKd.f95Hkqhu3"84(R@K-9-Mu!AP!I1F>rrV/%
-Zi0n*m!?)+rrV55[Jp1,odBb="fictm1u>nrrYFAj>d,<"?#EC^0^[9"dt&Ds,$[Lrs$>D^O^an
-*W?!=@_2L;#C!$Es+UKPF8l1?pa#A/!K`<?rrM"?rVlnZNIh+\s+14/s*t~>
-"lqsOs(spt=Tb&ka`%/]"E;N`>f$F>"KQPB_eK*Q!1!Q`"F!iV=e#Ej"E@<P=ePKg"8nU*aSu2?
-ZsEZ6!J95.rrU7AErH"=gd(0)!N()?rrN%dr`KD\/_BA3O8`8aPP"R6rE08hp]%s6qYp`RIT]gC
-rV?I'lAL)E_.]YEs1_\\6!=!^rs-kl=]qs.WH8(=!Vdr0rrLc"r`K83]D_a10C=>jJcC<$iW"E~>
-"lqsOs(spt=Tb&ka`%/]"E;N`>f$F>"KQPB_eK*Q!1!Q`"F!iV=e#Ej"E@<P=ePKg"8nU*aSu2?
-ZsEZ6!J95.rrU7AErH"=gd(0)!N()?rrN%dr`KD\/_BA3O8`8aPP"R6rE08hp]%s6qYp`RIT]gC
-rV?I'lAL)E_.]YEs1_\\6!=!^rs-kl=]qs.WH8(=!Vdr0rrLc"r`K83]D_a10C=>jJcC<$iW"E~>
-"lqsOs(spt=Tb&ka`%/]"E;N`>f$F>"KQPB_eK*Q!1!Q`"F!iV=e#Ej"E@<P=ePKg"8nU*aSu2?
-ZsEZ6!J95.rrU7AErH"=gd(0)!N()?rrN%dr`KD\/_BA3O8`8aPP"R6rE08hp]%s6qYp`RIT]gC
-rV?I'lAL)E_.]YEs1_\\6!=!^rs-kl=]qs.WH8(=!Vdr0rrLc"r`K83]D_a10C=>jJcC<$iW"E~>
-"QVjNs4mOh"53_Se,I2eeGoR$nG`FjleVU@ci1c]f`(mNc2PQ[gA_*PbPo?Yh"C[Jp<rm=!6+rS
-!93tW!qO4arVlomdH^`5l@c>>rrDcl_?K,Np&!#$rk\d,s8VZg_?BH0s7"\:rr_/q_Y3a(#jL4G
-s3:H@s6'?t!<)lr#1p`/s8VB?rr3#tb4#?1h>Y7kb5M>AGH(Ijs+13$s5F!.~>
-"QVjNs4mOh"53_Se,I2eeGoR$nG`FjleVU@ci1c]f`(mNc2PQ[gA_*PbPo?Yh"C[Jp<rm=!6+rS
-!93tW!qO4arVlomdH^`5l@c>>rrDcl_?K,Np&!#$rk\d,s8VZg_?BH0s7"\:rr_/q_Y3a(#jL4G
-s3:H@s6'?t!<)lr#1p`/s8VB?rr3#tb4#?1h>Y7kb5M>AGH(Ijs+13$s5F!.~>
-"QVjNs4mOh"53_Se,I2eeGoR$nG`FjleVU@ci1c]f`(mNc2PQ[gA_*PbPo?Yh"C[Jp<rm=!6+rS
-!93tW!qO4arVlomdH^`5l@c>>rrDcl_?K,Np&!#$rk\d,s8VZg_?BH0s7"\:rr_/q_Y3a(#jL4G
-s3:H@s6'?t!<)lr#1p`/s8VB?rr3#tb4#?1h>Y7kb5M>AGH(Ijs+13$s5F!.~>
-!ouXLQ2^mSnWj+TkkTf0JcC<$i;\<~>
-!ouXLQ2^mSnWj+TkkTf0JcC<$i;\<~>
-!ouXLQ2^mSnWj+TkkTf0JcC<$i;\<~>
-!ouXLJcC<$JcC<$K`?Q~>
-!ouXLJcC<$JcC<$K`?Q~>
-!ouXLJcC<$JcC<$K`?Q~>
-!ouXLJcG]K!TNR]rr_0&bgEm!"4YQ=h#.0PdXhFLs/5mI~>
-!ouXLJcG]K!TNR]rr_0&bgEm!"4YQ=h#.0PdXhFLs/5mI~>
-!ouXLJcG]K!TNR]rr_0&bgEm!"4YQ=h#.0PdXhFLs/5mI~>
-!ouXLrVll.r;Qf;o()e]\@V&,!kGPPr;QirYf6S@!PSC#rr_SkYi""2!o&"@rVm>df)Ne\s8V;e
-g&M)arUBgji3;2?s1.k'"4H?3\b5t)>rthhrVluBmf'fsrr^ZQYd<0c!6"l@!6Y!7"1eHrci3qH
-Bhpuir;Qe$_L_`<s/>sJ~>
-!ouXLrVll.r;Qf;o()e]\@V&,!kGPPr;QirYf6S@!PSC#rr_SkYi""2!o&"@rVm>df)Ne\s8V;e
-g&M)arUBgji3;2?s1.k'"4H?3\b5t)>rthhrVluBmf'fsrr^ZQYd<0c!6"l@!6Y!7"1eHrci3qH
-Bhpuir;Qe$_L_`<s/>sJ~>
-!ouXLrVll.r;Qf;o()e]\@V&,!kGPPr;QirYf6S@!PSC#rr_SkYi""2!o&"@rVm>df)Ne\s8V;e
-g&M)arUBgji3;2?s1.k'"4H?3\b5t)>rthhrVluBmf'fsrr^ZQYd<0c!6"l@!6Y!7"1eHrci3qH
-Bhpuir;Qe$_L_`<s/>sJ~>
-!ouXLrr3"u(&\(5P`>P2rrICpm/I-7?T\2c!r?\qrVlmIoCDnbn;;!sKAbYe!T1]hrrJ(?r;RA&
-HiH[ds6YVXJCjfHq>^KAch7;Bie2*#ir:%mrr[/AruLe4!F<J;rsMiIr#l%>c$X;BD5H.i!P<LR
-CB8[tpAY48s0uV;rrLA?r;QfW3e@<^s/>sJ~>
-!ouXLrr3"u(&\(5P`>P2rrICpm/I-7?T\2c!r?\qrVlmIoCDnbn;;!sKAbYe!T1]hrrJ(?r;RA&
-HiH[ds6YVXJCjfHq>^KAch7;Bie2*#ir:%mrr[/AruLe4!F<J;rsMiIr#l%>c$X;BD5H.i!P<LR
-CB8[tpAY48s0uV;rrLA?r;QfW3e@<^s/>sJ~>
-!ouXLrr3"u(&\(5P`>P2rrICpm/I-7?T\2c!r?\qrVlmIoCDnbn;;!sKAbYe!T1]hrrJ(?r;RA&
-HiH[ds6YVXJCjfHq>^KAch7;Bie2*#ir:%mrr[/AruLe4!F<J;rsMiIr#l%>c$X;BD5H.i!P<LR
-CB8[tpAY48s0uV;rrLA?r;QfW3e@<^s/>sJ~>
-#NS0Qs8SgH'Dqe1RtBDp!T?-5rrFS?o)AmK5l^js[GUubZ>0::!n)SAr;RA&HiH[ds3jR>_1$W_
-r;ZeYN:m2T\mk]II!C_Grr[/AruLe4!F<J;rsMiIr#l%>LR%o>oI8\t#.&^Es8U`apAY48s0uV;
-rrLA?r;QigKVj>#JcD_LJ,~>
-#NS0Qs8SgH'Dqe1RtBDp!T?-5rrFS?o)AmK5l^js[GUubZ>0::!n)SAr;RA&HiH[ds3jR>_1$W_
-r;ZeYN:m2T\mk]II!C_Grr[/AruLe4!F<J;rsMiIr#l%>LR%o>oI8\t#.&^Es8U`apAY48s0uV;
-rrLA?r;QigKVj>#JcD_LJ,~>
-#NS0Qs8SgH'Dqe1RtBDp!T?-5rrFS?o)AmK5l^js[GUubZ>0::!n)SAr;RA&HiH[ds3jR>_1$W_
-r;ZeYN:m2T\mk]II!C_Grr[/AruLe4!F<J;rsMiIr#l%>LR%o>oI8\t#.&^Es8U`apAY48s0uV;
-rrLA?r;QigKVj>#JcD_LJ,~>
-#NS0Qs.PG>*W#d:UNuP4!e+Bor;QbBr`fGnp&>'O48f*[Bj?GlrrFS4r`fH/rVlrS>c%E!#M_TE
-s2a:$pAJ50_Z0XSs3"YPaT)6E>a;X#c2[h+rEKWWs79J\-<sg.rr3#!F8PtRh9c29n,Mjis8U'5
-o)IQO1br<@mf3=+rEKd&s5qB%s1G-(s3748r`fI&rr3)Dir?1SrrHE?qu72Dli+*fs+cm>s7@c?
-s/j-:rrM&<rr3"Nm/?qjU<NXUs4*P;s,-e\!/pjV"@#[e>`o$c!.XuQ!1*T`"0V[da8Gr<btn6:
-!QA,ks+13Ls*t~>
-#NS0Qs.PG>*W#d:UNuP4!e+Bor;QbBr`fGnp&>'O48f*[Bj?GlrrFS4r`fH/rVlrS>c%E!#M_TE
-s2a:$pAJ50_Z0XSs3"YPaT)6E>a;X#c2[h+rEKWWs79J\-<sg.rr3#!F8PtRh9c29n,Mjis8U'5
-o)IQO1br<@mf3=+rEKd&s5qB%s1G-(s3748r`fI&rr3)Dir?1SrrHE?qu72Dli+*fs+cm>s7@c?
-s/j-:rrM&<rr3"Nm/?qjU<NXUs4*P;s,-e\!/pjV"@#[e>`o$c!.XuQ!1*T`"0V[da8Gr<btn6:
-!QA,ks+13Ls*t~>
-#NS0Qs.PG>*W#d:UNuP4!e+Bor;QbBr`fGnp&>'O48f*[Bj?GlrrFS4r`fH/rVlrS>c%E!#M_TE
-s2a:$pAJ50_Z0XSs3"YPaT)6E>a;X#c2[h+rEKWWs79J\-<sg.rr3#!F8PtRh9c29n,Mjis8U'5
-o)IQO1br<@mf3=+rEKd&s5qB%s1G-(s3748r`fI&rr3)Dir?1SrrHE?qu72Dli+*fs+cm>s7@c?
-s/j-:rrM&<rr3"Nm/?qjU<NXUs4*P;s,-e\!/pjV"@#[e>`o$c!.XuQ!1*T`"0V[da8Gr<btn6:
-!QA,ks+13Ls*t~>
-#NS0Qs4Zf=*W#d;ql"c5rrUHX,5qNBGcC\W!KEfHrrM(?r;Qi:U."t[!@^M;^B&_orr3&@!-8&<
-!Sfs<rr>sq^CtP2s0b1+^V=R6rYN>5HbX4Is7Q?*#\)ch^P5S"^[V7&!NL5.rsA82Ch^Z!q#AcZ
-rP&>0q#:E#)he4*!*/Ie!F<J5rs=H,5X7I]s8RS?rr3#E:B(7o4Q68=$#ZsH*WNf[s,<HH^BC!c
-s+R-F^BBjes*pjD^B'Ldp&>';:](.m`E.WjJcD_LJ,~>
-#NS0Qs4Zf=*W#d;ql"c5rrUHX,5qNBGcC\W!KEfHrrM(?r;Qi:U."t[!@^M;^B&_orr3&@!-8&<
-!Sfs<rr>sq^CtP2s0b1+^V=R6rYN>5HbX4Is7Q?*#\)ch^P5S"^[V7&!NL5.rsA82Ch^Z!q#AcZ
-rP&>0q#:E#)he4*!*/Ie!F<J5rs=H,5X7I]s8RS?rr3#E:B(7o4Q68=$#ZsH*WNf[s,<HH^BC!c
-s+R-F^BBjes*pjD^B'Ldp&>';:](.m`E.WjJcD_LJ,~>
-#NS0Qs4Zf=*W#d;ql"c5rrUHX,5qNBGcC\W!KEfHrrM(?r;Qi:U."t[!@^M;^B&_orr3&@!-8&<
-!Sfs<rr>sq^CtP2s0b1+^V=R6rYN>5HbX4Is7Q?*#\)ch^P5S"^[V7&!NL5.rsA82Ch^Z!q#AcZ
-rP&>0q#:E#)he4*!*/Ie!F<J5rs=H,5X7I]s8RS?rr3#E:B(7o4Q68=$#ZsH*WNf[s,<HH^BC!c
-s+R-F^BBjes*pjD^B'Ldp&>';:](.m`E.WjJcD_LJ,~>
-!ouXLrVlj<q>UKC9D/;cqBGn<!DCl?rrJR?pAY0P48]$YfgPf=!@cOtrrIA?rr3&og["k="?7J0
-,`Vg'!$2%<&RW6Okq)#ts&R/=+9/3^s%^l:rrkjCs8TB>qu6\sF6ii,OGs/<!Q&%=rrCsOrrTH1
-mf*4d*U`q.?,-(4%YoShgX7PNs6XR>s6`D>rr3!]iVic_DQj'\s1Me>A[h[="LVqC?,6I>"KZSB
-<65(=!V5UMrrLA?qu6]9=+UC&s/H$K~>
-!ouXLrVlj<q>UKC9D/;cqBGn<!DCl?rrJR?pAY0P48]$YfgPf=!@cOtrrIA?rr3&og["k="?7J0
-,`Vg'!$2%<&RW6Okq)#ts&R/=+9/3^s%^l:rrkjCs8TB>qu6\sF6ii,OGs/<!Q&%=rrCsOrrTH1
-mf*4d*U`q.?,-(4%YoShgX7PNs6XR>s6`D>rr3!]iVic_DQj'\s1Me>A[h[="LVqC?,6I>"KZSB
-<65(=!V5UMrrLA?qu6]9=+UC&s/H$K~>
-!ouXLrVlj<q>UKC9D/;cqBGn<!DCl?rrJR?pAY0P48]$YfgPf=!@cOtrrIA?rr3&og["k="?7J0
-,`Vg'!$2%<&RW6Okq)#ts&R/=+9/3^s%^l:rrkjCs8TB>qu6\sF6ii,OGs/<!Q&%=rrCsOrrTH1
-mf*4d*U`q.?,-(4%YoShgX7PNs6XR>s6`D>rr3!]iVic_DQj'\s1Me>A[h[="LVqC?,6I>"KZSB
-<65(=!V5UMrrLA?qu6]9=+UC&s/H$K~>
-!ouXLrVlj<qYpWR7/HTV!W"#=rrGd@rr3"fK(f3FiB-r:!SKm>rrFS?rr3"DV"jrmpsqY'qu6Tq
-*W?!@?bQL(1]IC^qYgC8s/(#?:<rj^r>YtHfDklVCA\#3WcRM+!K`9=rrN(ur>Ygmq#:B"C]485
-*U`q.?,-(4"c&BCs7@c>rrd5Er7aR:rrG7@rVm1AYQ#XC]jLeN\,QC1[:oSG_#F?=XDn4+7iWLI
-oD\j9:](.m`E.WjJcD_LJ,~>
-!ouXLrVlj<qYpWR7/HTV!W"#=rrGd@rr3"fK(f3FiB-r:!SKm>rrFS?rr3"DV"jrmpsqY'qu6Tq
-*W?!@?bQL(1]IC^qYgC8s/(#?:<rj^r>YtHfDklVCA\#3WcRM+!K`9=rrN(ur>Ygmq#:B"C]485
-*U`q.?,-(4"c&BCs7@c>rrd5Er7aR:rrG7@rVm1AYQ#XC]jLeN\,QC1[:oSG_#F?=XDn4+7iWLI
-oD\j9:](.m`E.WjJcD_LJ,~>
-!ouXLrVlj<qYpWR7/HTV!W"#=rrGd@rr3"fK(f3FiB-r:!SKm>rrFS?rr3"DV"jrmpsqY'qu6Tq
-*W?!@?bQL(1]IC^qYgC8s/(#?:<rj^r>YtHfDklVCA\#3WcRM+!K`9=rrN(ur>Ygmq#:B"C]485
-*U`q.?,-(4"c&BCs7@c>rrd5Er7aR:rrG7@rVm1AYQ#XC]jLeN\,QC1[:oSG_#F?=XDn4+7iWLI
-oD\j9:](.m`E.WjJcD_LJ,~>
-!ouXLrVlj<qu6]J7e?W\qBGn<!DCl?rrJR?pAY0P48]$YfgPf=!@c+hrrIA?rr3&lcfG')!Sfs<
-rr=)<rrc]Bs62?;rsAZHs/(#?:<rM[rr3Mf37n31Z>0F>gA1dK\p3N,rs+XEs8UUKoAKTI!$1k7
-!O6G=rr=)4rrV!%r;HWr?,-(4"c&BCs7@c=rrPU@*W5pJ4Q6.is8Qu?ruM-Q?iO]Hrr3,/B`DAR
-rr3,&E;rnYrr3#ejn8WSbtn9;!rAp@r;Qincf'HTJcE"TJ,~>
-!ouXLrVlj<qu6]J7e?W\qBGn<!DCl?rrJR?pAY0P48]$YfgPf=!@c+hrrIA?rr3&lcfG')!Sfs<
-rr=)<rrc]Bs62?;rsAZHs/(#?:<rM[rr3Mf37n31Z>0F>gA1dK\p3N,rs+XEs8UUKoAKTI!$1k7
-!O6G=rr=)4rrV!%r;HWr?,-(4"c&BCs7@c=rrPU@*W5pJ4Q6.is8Qu?ruM-Q?iO]Hrr3,/B`DAR
-rr3,&E;rnYrr3#ejn8WSbtn9;!rAp@r;Qincf'HTJcE"TJ,~>
-!ouXLrVlj<qu6]J7e?W\qBGn<!DCl?rrJR?pAY0P48]$YfgPf=!@c+hrrIA?rr3&lcfG')!Sfs<
-rr=)<rrc]Bs62?;rsAZHs/(#?:<rM[rr3Mf37n31Z>0F>gA1dK\p3N,rs+XEs8UUKoAKTI!$1k7
-!O6G=rr=)4rrV!%r;HWr?,-(4"c&BCs7@c=rrPU@*W5pJ4Q6.is8Qu?ruM-Q?iO]Hrr3,/B`DAR
-rr3,&E;rnYrr3#ejn8WSbtn9;!rAp@r;Qincf'HTJcE"TJ,~>
-&*-#Ys3n9Z'XG$js8U/Gp@S@j_ljo_cN!oqT`24tMQ$:L"M:6SZI]$T#e?<UZIo3W.8^#L!I_`^
-rrU7AErH"=gd(f;!+#Q/"EMoikqi8;$2u%H_4Ua&cM1ZDZ3k[gfDklmGI"Mcl2L\`N0*E+#I/ug
-Z<@4XE;d'B>PS4!Z"s=<!$1b4!_EC^rVln(^\.U1X,+'eY%dk7!dpbLr;R:NVPeS:s-]%U'XF*e
-s-&cJZN$0ks,EHGZ36;Zs+m3EZ2ouZp&>';:]14ni]?u:!nmW^JcC<$Z2]=~>
-&*-#Ys3n9Z'XG$js8U/Gp@S@j_ljo_cN!oqT`24tMQ$:L"M:6SZI]$T#e?<UZIo3W.8^#L!I_`^
-rrU7AErH"=gd(f;!+#Q/"EMoikqi8;$2u%H_4Ua&cM1ZDZ3k[gfDklmGI"Mcl2L\`N0*E+#I/ug
-Z<@4XE;d'B>PS4!Z"s=<!$1b4!_EC^rVln(^\.U1X,+'eY%dk7!dpbLr;R:NVPeS:s-]%U'XF*e
-s-&cJZN$0ks,EHGZ36;Zs+m3EZ2ouZp&>';:]14ni]?u:!nmW^JcC<$Z2]=~>
-&*-#Ys3n9Z'XG$js8U/Gp@S@j_ljo_cN!oqT`24tMQ$:L"M:6SZI]$T#e?<UZIo3W.8^#L!I_`^
-rrU7AErH"=gd(f;!+#Q/"EMoikqi8;$2u%H_4Ua&cM1ZDZ3k[gfDklmGI"Mcl2L\`N0*E+#I/ug
-Z<@4XE;d'B>PS4!Z"s=<!$1b4!_EC^rVln(^\.U1X,+'eY%dk7!dpbLr;R:NVPeS:s-]%U'XF*e
-s-&cJZN$0ks,EHGZ36;Zs+m3EZ2ouZp&>';:]14ni]?u:!nmW^JcC<$Z2]=~>
-"QVjNs/Gp1"JPkqP32B9!/UVg!2'8j!/(8b!i5k1qj%?1s8RBDB`P=8rr@0?B`tdBs+0V;B`P[A
-rrV%kXSr/"l]1oC!;HG+"NUQBnq[/C!WIHErr\VIs60Gr!l^>crr3)9Bkc?#rrTfah<b.GXD)D;
-s8U7?B`Rf#rrLNGrVlkDp&>)W'(Pr#"'oo4T_ABfVeKj`qu6\Hq>:0mH?oJh"INm3Boi8n!0dCr
-!0mK_!07%m!1Eid!/^\h!1roa"/_B0:]14nOc0,:!pOEmJcC<$Z2]=~>
-"QVjNs/Gp1"JPkqP32B9!/UVg!2'8j!/(8b!i5k1qj%?1s8RBDB`P=8rr@0?B`tdBs+0V;B`P[A
-rrV%kXSr/"l]1oC!;HG+"NUQBnq[/C!WIHErr\VIs60Gr!l^>crr3)9Bkc?#rrTfah<b.GXD)D;
-s8U7?B`Rf#rrLNGrVlkDp&>)W'(Pr#"'oo4T_ABfVeKj`qu6\Hq>:0mH?oJh"INm3Boi8n!0dCr
-!0mK_!07%m!1Eid!/^\h!1roa"/_B0:]14nOc0,:!pOEmJcC<$Z2]=~>
-"QVjNs/Gp1"JPkqP32B9!/UVg!2'8j!/(8b!i5k1qj%?1s8RBDB`P=8rr@0?B`tdBs+0V;B`P[A
-rrV%kXSr/"l]1oC!;HG+"NUQBnq[/C!WIHErr\VIs60Gr!l^>crr3)9Bkc?#rrTfah<b.GXD)D;
-s8U7?B`Rf#rrLNGrVlkDp&>)W'(Pr#"'oo4T_ABfVeKj`qu6\Hq>:0mH?oJh"INm3Boi8n!0dCr
-!0mK_!07%m!1Eid!/^\h!1roa"/_B0:]14nOc0,:!pOEmJcC<$Z2]=~>
-!ouXLg&D&Xqh5$jXoAF5fYd^i/+NT<"0mQ6OPKj9*SgYsQ\C-or;Qb\JcC<$VuM8~>
-!ouXLg&D&Xqh5$jXoAF5fYd^i/+NT<"0mQ6OPKj9*SgYsQ\C-or;Qb\JcC<$VuM8~>
-!ouXLg&D&Xqh5$jXoAF5fYd^i/+NT<"0mQ6OPKj9*SgYsQ\C-or;Qb\JcC<$VuM8~>
-!ouXLJcEIa!fWE@eGfLhJcC<$JcGNFJ,~>
-!ouXLJcEIa!fWE@eGfLhJcC<$JcGNFJ,~>
-!ouXLJcEIa!fWE@eGfLhJcC<$JcGNFJ,~>
-!ouXLJcEIa!RUJfrrBugs+13$s7lVE~>
-!ouXLJcEIa!RUJfrrBugs+13$s7lVE~>
-!ouXLJcEIa!RUJfrrBugs+13$s7lVE~>
-!ouXLrr3't-73*urrYk?->%i/VuHj>-71q,rrYb<->A&2JcDGDJ,~>
-!ouXLrr3't-73*urrYk?->%i/VuHj>-71q,rrYb<->A&2JcDGDJ,~>
-!ouXLrr3't-73*urrYk?->%i/VuHj>-71q,rrYb<->A&2JcDGDJ,~>
-!ouXLrr3'UiUusDrs(%<p%\ReoM>H+"C_!'=r@2X",R!J62hi)Dt`u+!V%uF*!C]as#M+t*!3#;
-5lDZ''<(^+!:'M&".8rb)Z1QV`W%.\*!$Vlq>UKpc2AUb[/Bt%Y5TCHaoDD<V]6\VqtU0lr3?2?
-"47(m&H*RN*rl,4r>Ygpq#:BkQMhd'mem(cnKn27"SQdS*96en!V^p>*!%tfr;Qr]1&q:ID#PCZ
-7.^HYq"=;#o`#1Qo$gS;s)5IHo)Ae=s1<%Frr_uf`D;'bJcDGDJ,~>
-!ouXLrr3'UiUusDrs(%<p%\ReoM>H+"C_!'=r@2X",R!J62hi)Dt`u+!V%uF*!C]as#M+t*!3#;
-5lDZ''<(^+!:'M&".8rb)Z1QV`W%.\*!$Vlq>UKpc2AUb[/Bt%Y5TCHaoDD<V]6\VqtU0lr3?2?
-"47(m&H*RN*rl,4r>Ygpq#:BkQMhd'mem(cnKn27"SQdS*96en!V^p>*!%tfr;Qr]1&q:ID#PCZ
-7.^HYq"=;#o`#1Qo$gS;s)5IHo)Ae=s1<%Frr_uf`D;'bJcDGDJ,~>
-!ouXLrr3'UiUusDrs(%<p%\ReoM>H+"C_!'=r@2X",R!J62hi)Dt`u+!V%uF*!C]as#M+t*!3#;
-5lDZ''<(^+!:'M&".8rb)Z1QV`W%.\*!$Vlq>UKpc2AUb[/Bt%Y5TCHaoDD<V]6\VqtU0lr3?2?
-"47(m&H*RN*rl,4r>Ygpq#:BkQMhd'mem(cnKn27"SQdS*96en!V^p>*!%tfr;Qr]1&q:ID#PCZ
-7.^HYq"=;#o`#1Qo$gS;s)5IHo)Ae=s1<%Frr_uf`D;'bJcDGDJ,~>
-!ouXLrr3!SlMLS^.eEW=!F3J?rrfBBs&7&:rrGd@rr3"fK)#?H3o^/="Gr?B1$eT6!pk9@q#:=7
-rVlt4[Jq9@rrV=od/!\BodB_<"@^r?ZYfX?#PtQEs8R)Bqt^6mdn0N<"!m]c;>^@o_HQp<!$1k7
-!O6G=rr=)<rsRa\$ig7pJueqO6eV87!K`<?rrM"?rVm)U2_"e,J"HZ>!R=I<rr=)3rrXeBdRsN=
-!C,E2rrX;A\7GO;!R4Dks+13Ds*t~>
-!ouXLrr3!SlMLS^.eEW=!F3J?rrfBBs&7&:rrGd@rr3"fK)#?H3o^/="Gr?B1$eT6!pk9@q#:=7
-rVlt4[Jq9@rrV=od/!\BodB_<"@^r?ZYfX?#PtQEs8R)Bqt^6mdn0N<"!m]c;>^@o_HQp<!$1k7
-!O6G=rr=)<rsRa\$ig7pJueqO6eV87!K`<?rrM"?rVm)U2_"e,J"HZ>!R=I<rr=)3rrXeBdRsN=
-!C,E2rrX;A\7GO;!R4Dks+13Ds*t~>
-!ouXLrr3!SlMLS^.eEW=!F3J?rrfBBs&7&:rrGd@rr3"fK)#?H3o^/="Gr?B1$eT6!pk9@q#:=7
-rVlt4[Jq9@rrV=od/!\BodB_<"@^r?ZYfX?#PtQEs8R)Bqt^6mdn0N<"!m]c;>^@o_HQp<!$1k7
-!O6G=rr=)<rsRa\$ig7pJueqO6eV87!K`<?rrM"?rVm)U2_"e,J"HZ>!R=I<rr=)3rrXeBdRsN=
-!C,E2rrX;A\7GO;!R4Dks+13Ds*t~>
-!ouXLrr3!SlMLS^.eEW=!F3J?rt2;Os&7%P[C+B]s*rr+s6>N>q#:@Uir8r\M3Irokl.sigACmN
-QA>57!$2%<"D>.B*V99<!9="W!oJ@Aq#:Bf-iO&I7G$o\qu6of@a>#Rc!]u8rrLS?rVm!Gq9)Xm
-rj;k&s2%t<rr=)7rrKB?rVlj<rr3DWCt]p0s1Eg>s8TE?q#:AVNW/qYh`^u=#KpH:.KBEtT)S`j
-c;+<;!$1_3").AbJ,]HLGGkH=rrp[9]sY8prVlt,s36](rrLA?JcC<$U&TW~>
-!ouXLrr3!SlMLS^.eEW=!F3J?rt2;Os&7%P[C+B]s*rr+s6>N>q#:@Uir8r\M3Irokl.sigACmN
-QA>57!$2%<"D>.B*V99<!9="W!oJ@Aq#:Bf-iO&I7G$o\qu6of@a>#Rc!]u8rrLS?rVm!Gq9)Xm
-rj;k&s2%t<rr=)7rrKB?rVlj<rr3DWCt]p0s1Eg>s8TE?q#:AVNW/qYh`^u=#KpH:.KBEtT)S`j
-c;+<;!$1_3").AbJ,]HLGGkH=rrp[9]sY8prVlt,s36](rrLA?JcC<$U&TW~>
-!ouXLrr3!SlMLS^.eEW=!F3J?rt2;Os&7%P[C+B]s*rr+s6>N>q#:@Uir8r\M3Irokl.sigACmN
-QA>57!$2%<"D>.B*V99<!9="W!oJ@Aq#:Bf-iO&I7G$o\qu6of@a>#Rc!]u8rrLS?rVm!Gq9)Xm
-rj;k&s2%t<rr=)7rrKB?rVlj<rr3DWCt]p0s1Eg>s8TE?q#:AVNW/qYh`^u=#KpH:.KBEtT)S`j
-c;+<;!$1_3").AbJ,]HLGGkH=rrp[9]sY8prVlt,s36](rrLA?JcC<$U&TW~>
-!ouXLrr3!SlMLS^.eEW=%U?jMs6409s&42YAnH;1rVlreMkg%H#s.)Gs4gM9s"TH2Ac[D5rVlrX
-KX^^U!$2(="jT<>rtpjsAc[YJrr3)X=&duMrrMd?rr3/<.bF&Ai;T,MkPtS<GF=kBht[3Pdn0Q=
-"g\s>b;"YKAcn:t_HQs=!N[(3rrKB?rr38#*WQ/eI*Va4rr3,/Kpe?Lp\u"jNW9%XL->S:_fb#3
-.KBEtT)\ibHqsV>!$1G+!ILR>rruGICM%1'an>Z7btiojJcDGDJ,~>
-!ouXLrr3!SlMLS^.eEW=%U?jMs6409s&42YAnH;1rVlreMkg%H#s.)Gs4gM9s"TH2Ac[D5rVlrX
-KX^^U!$2(="jT<>rtpjsAc[YJrr3)X=&duMrrMd?rr3/<.bF&Ai;T,MkPtS<GF=kBht[3Pdn0Q=
-"g\s>b;"YKAcn:t_HQs=!N[(3rrKB?rr38#*WQ/eI*Va4rr3,/Kpe?Lp\u"jNW9%XL->S:_fb#3
-.KBEtT)\ibHqsV>!$1G+!ILR>rruGICM%1'an>Z7btiojJcDGDJ,~>
-!ouXLrr3!SlMLS^.eEW=%U?jMs6409s&42YAnH;1rVlreMkg%H#s.)Gs4gM9s"TH2Ac[D5rVlrX
-KX^^U!$2(="jT<>rtpjsAc[YJrr3)X=&duMrrMd?rr3/<.bF&Ai;T,MkPtS<GF=kBht[3Pdn0Q=
-"g\s>b;"YKAcn:t_HQs=!N[(3rrKB?rr38#*WQ/eI*Va4rr3,/Kpe?Lp\u"jNW9%XL->S:_fb#3
-.KBEtT)\ibHqsV>!$1G+!ILR>rruGICM%1'an>Z7btiojJcDGDJ,~>
-!ouXLrr3!SlMLS^.eEW=%^1>0I=>7;s/UbCs8Sj?rr3&pI\lc<$(cToI=F_Ms-e`BrrI\@rVlo)
-C%hQ,NrFG1Il4Y6MO4>B!FNP>rrgr*Jq)eUrrMtIrd=s#,M2<!If=p)Idd<rItE9%jS8`Ul@Jq_
-"b@<^jat#ArrX;AiILoU!J(s[rrLf'rd>''*<4K;aoDA]rr3,:J:`B,p\t98J,Xj)E]sH>JD'tp
-.KBF`J,XisBhnU+!$1D*!$2%<##o4*s8Sm?p&>';:P&Oss.TIC~>
-!ouXLrr3!SlMLS^.eEW=%^1>0I=>7;s/UbCs8Sj?rr3&pI\lc<$(cToI=F_Ms-e`BrrI\@rVlo)
-C%hQ,NrFG1Il4Y6MO4>B!FNP>rrgr*Jq)eUrrMtIrd=s#,M2<!If=p)Idd<rItE9%jS8`Ul@Jq_
-"b@<^jat#ArrX;AiILoU!J(s[rrLf'rd>''*<4K;aoDA]rr3,:J:`B,p\t98J,Xj)E]sH>JD'tp
-.KBF`J,XisBhnU+!$1D*!$2%<##o4*s8Sm?p&>';:P&Oss.TIC~>
-!ouXLrr3!SlMLS^.eEW=%^1>0I=>7;s/UbCs8Sj?rr3&pI\lc<$(cToI=F_Ms-e`BrrI\@rVlo)
-C%hQ,NrFG1Il4Y6MO4>B!FNP>rrgr*Jq)eUrrMtIrd=s#,M2<!If=p)Idd<rItE9%jS8`Ul@Jq_
-"b@<^jat#ArrX;AiILoU!J(s[rrLf'rd>''*<4K;aoDA]rr3,:J:`B,p\t98J,Xj)E]sH>JD'tp
-.KBF`J,XisBhnU+!$1D*!$2%<##o4*s8Sm?p&>';:P&Oss.TIC~>
-!ouXLrr3!SlMLS^.eET<"h("oZ`A*CrrJm@rr3":Y4V_tWLf]sM3Ii:!J-d?rrV2$`qKE4rViAi
-c"FH]rrHK?qu6[t`q]Q6nG]!_fgXN[*kVFO#sI26DSQ5O]l*B8rrD*YSc\%"q>:0o*WQ/qrgj/X
-*V]R6f)D6Do,[k1/H0&a$[;WhJ(Xf$TR?M6(!<,>TAMg3LH/dO>n;nos21G"VTqs7rr=)*rrJR?
-rr3!uaSu2?Uj;Y5!R4Dks+13Ds*t~>
-!ouXLrr3!SlMLS^.eET<"h("oZ`A*CrrJm@rr3":Y4V_tWLf]sM3Ii:!J-d?rrV2$`qKE4rViAi
-c"FH]rrHK?qu6[t`q]Q6nG]!_fgXN[*kVFO#sI26DSQ5O]l*B8rrD*YSc\%"q>:0o*WQ/qrgj/X
-*V]R6f)D6Do,[k1/H0&a$[;WhJ(Xf$TR?M6(!<,>TAMg3LH/dO>n;nos21G"VTqs7rr=)*rrJR?
-rr3!uaSu2?Uj;Y5!R4Dks+13Ds*t~>
-!ouXLrr3!SlMLS^.eET<"h("oZ`A*CrrJm@rr3":Y4V_tWLf]sM3Ii:!J-d?rrV2$`qKE4rViAi
-c"FH]rrHK?qu6[t`q]Q6nG]!_fgXN[*kVFO#sI26DSQ5O]l*B8rrD*YSc\%"q>:0o*WQ/qrgj/X
-*V]R6f)D6Do,[k1/H0&a$[;WhJ(Xf$TR?M6(!<,>TAMg3LH/dO>n;nos21G"VTqs7rr=)*rrJR?
-rr3!uaSu2?Uj;Y5!R4Dks+13Ds*t~>
-!ouXLrr3!SlMLS^.eEH8!NU5;rro0Ds8Q]>n,EEFPPb@\JXl`>!ROO0rrHc?qu6\(^&.g1<lXb2
-"%Ci/0`D"R4l><[rVlmUkk"fT,l.?;!$1q9!$1Y1!Zh=)rON+H`;cKXrr3#g/G&lDh`_"srji0:
-*mOT^!R=I<rr=)*rs&7lJcGaLaSu2?Uj;Y5!R4Dks+13Ds*t~>
-!ouXLrr3!SlMLS^.eEH8!NU5;rro0Ds8Q]>n,EEFPPb@\JXl`>!ROO0rrHc?qu6\(^&.g1<lXb2
-"%Ci/0`D"R4l><[rVlmUkk"fT,l.?;!$1q9!$1Y1!Zh=)rON+H`;cKXrr3#g/G&lDh`_"srji0:
-*mOT^!R=I<rr=)*rs&7lJcGaLaSu2?Uj;Y5!R4Dks+13Ds*t~>
-!ouXLrr3!SlMLS^.eEH8!NU5;rro0Ds8Q]>n,EEFPPb@\JXl`>!ROO0rrHc?qu6\(^&.g1<lXb2
-"%Ci/0`D"R4l><[rVlmUkk"fT,l.?;!$1q9!$1Y1!Zh=)rON+H`;cKXrr3#g/G&lDh`_"srji0:
-*mOT^!R=I<rr=)*rs&7lJcGaLaSu2?Uj;Y5!R4Dks+13Ds*t~>
-!ouXLrr3!SlMLS^.eEK9"jpfCs)6?brro0Ds(Jn>qYpWa.;\k\"grXDs&/:ars"%Es8VR[iqr`W
-cmaeIrre^NoD_,TrrZWAs$?V`!ER5>rrTPVV>C2pI&Hf-0`D"X4l?.@E<#rUZMXY$!gkFQqYp\*
-^AcSurVlj<qu6[obPhGBHR[hJrrGL?qu6sCs8VS?WW2u_h>R?T?RbjKrrW-`i;ETUoI9\;!q&\@
-r;Qa;qu6[Y8Flcaa]&6><65(=!Mk#6rrLA?JcC<$U&TW~>
-!ouXLrr3!SlMLS^.eEK9"jpfCs)6?brro0Ds(Jn>qYpWa.;\k\"grXDs&/:ars"%Es8VR[iqr`W
-cmaeIrre^NoD_,TrrZWAs$?V`!ER5>rrTPVV>C2pI&Hf-0`D"X4l?.@E<#rUZMXY$!gkFQqYp\*
-^AcSurVlj<qu6[obPhGBHR[hJrrGL?qu6sCs8VS?WW2u_h>R?T?RbjKrrW-`i;ETUoI9\;!q&\@
-r;Qa;qu6[Y8Flcaa]&6><65(=!Mk#6rrLA?JcC<$U&TW~>
-!ouXLrr3!SlMLS^.eEK9"jpfCs)6?brro0Ds(Jn>qYpWa.;\k\"grXDs&/:ars"%Es8VR[iqr`W
-cmaeIrre^NoD_,TrrZWAs$?V`!ER5>rrTPVV>C2pI&Hf-0`D"X4l?.@E<#rUZMXY$!gkFQqYp\*
-^AcSurVlj<qu6[obPhGBHR[hJrrGL?qu6sCs8VS?WW2u_h>R?T?RbjKrrW-`i;ETUoI9\;!q&\@
-r;Qa;qu6[Y8Flcaa]&6><65(=!Mk#6rrLA?JcC<$U&TW~>
-!ouXLrr3'Uh!jt7rrXb3nFZ_[#ZMc`9(r;bp.>6'"D[`3<Z:oV!0I3[!p^7krVm-\*#rScs8VaD
-rYu)rqZ$T`48SsYb6i:hrrDop*!Cojs8V9\*!;u6s5<hq!NQ(srrT5,PlC[_h#88rTD\`gb5E:c
-^]"31WuN+^r;HWsM[$WhrrBe4*!EqQs89%u*!>!rs0)DA!QtE?rrQs=fDbdMT`,o2f_YUJ/,oPO
-q/RGpkPY>]9EP%hrrdon*$4bLrrMaLrr3+B*#pR'rr3)nnF.IqrrF>jo)AmkXapFYbPqMBWIagD
-"7krt:P&Oss.TIC~>
-!ouXLrr3'Uh!jt7rrXb3nFZ_[#ZMc`9(r;bp.>6'"D[`3<Z:oV!0I3[!p^7krVm-\*#rScs8VaD
-rYu)rqZ$T`48SsYb6i:hrrDop*!Cojs8V9\*!;u6s5<hq!NQ(srrT5,PlC[_h#88rTD\`gb5E:c
-^]"31WuN+^r;HWsM[$WhrrBe4*!EqQs89%u*!>!rs0)DA!QtE?rrQs=fDbdMT`,o2f_YUJ/,oPO
-q/RGpkPY>]9EP%hrrdon*$4bLrrMaLrr3+B*#pR'rr3)nnF.IqrrF>jo)AmkXapFYbPqMBWIagD
-"7krt:P&Oss.TIC~>
-!ouXLrr3'Uh!jt7rrXb3nFZ_[#ZMc`9(r;bp.>6'"D[`3<Z:oV!0I3[!p^7krVm-\*#rScs8VaD
-rYu)rqZ$T`48SsYb6i:hrrDop*!Cojs8V9\*!;u6s5<hq!NQ(srrT5,PlC[_h#88rTD\`gb5E:c
-^]"31WuN+^r;HWsM[$WhrrBe4*!EqQs89%u*!>!rs0)DA!QtE?rrQs=fDbdMT`,o2f_YUJ/,oPO
-q/RGpkPY>]9EP%hrrdon*$4bLrrMaLrr3+B*#pR'rr3)nnF.IqrrF>jo)AmkXapFYbPqMBWIagD
-"7krt:P&Oss.TIC~>
-!ouXLrr3(#.k>-.rrZ"H.r+/F!R+C#rrK-?j8T.9PiMcEB=?k#!CbW#rrFA?k5PO+.k=!arrMm@
-h>[RM.k>Ifs+13Ds*t~>
-!ouXLrr3(#.k>-.rrZ"H.r+/F!R+C#rrK-?j8T.9PiMcEB=?k#!CbW#rrFA?k5PO+.k=!arrMm@
-h>[RM.k>Ifs+13Ds*t~>
-!ouXLrr3(#.k>-.rrZ"H.r+/F!R+C#rrK-?j8T.9PiMcEB=?k#!CbW#rrFA?k5PO+.k=!arrMm@
-h>[RM.k>Ifs+13Ds*t~>
-!ouXLf)GgITn2;)!q2;?jSo;DK<jS<!o8"AjSo;1B&htP!m4UAh#@Dd@Y+Q1s+14Gs*t~>
-!ouXLf)GgITn2;)!q2;?jSo;DK<jS<!o8"AjSo;1B&htP!m4UAh#@Dd@Y+Q1s+14Gs*t~>
-!ouXLf)GgITn2;)!q2;?jSo;DK<jS<!o8"AjSo;1B&htP!m4UAh#@Dd@Y+Q1s+14Gs*t~>
-!ouXLf)GdAK&ck3h3[1%!QhG'rrKLBj8T.Pe`6Z1MsB's!-NkmJcC<$q#>j~>
-!ouXLf)GdAK&ck3h3[1%!QhG'rrKLBj8T.Pe`6Z1MsB's!-NkmJcC<$q#>j~>
-!ouXLf)GdAK&ck3h3[1%!QhG'rrKLBj8T.Pe`6Z1MsB's!-NkmJcC<$q#>j~>
-!ouXLL&V1cdZa\2NkPGmp\oXB_RKOFg\u[&hYmHTaMn&V!Q<*2s-Nb9~>
-!ouXLL&V1cdZa\2NkPGmp\oXB_RKOFg\u[&hYmHTaMn&V!Q<*2s-Nb9~>
-!ouXLL&V1cdZa\2NkPGmp\oXB_RKOFg\u[&hYmHTaMn&V!Q<*2s-Nb9~>
-"lqsOs8S>_@fVJerrJ2Co)A`3GfB[_Fl<9$^4G)<rrUAR]C#V#c!t8,r;Qi,A'k5T!S*h3rrSHq
-B[m%_G,G3;",$1/N;ih\O(7qad\H:2"b:Cgs2))8rr[EDb,b79"R[8"SC%98#OmHI]"7qAr;L1+
-Xks'Xj8EHfg%PFR`if?(j8]/>S=DXRrVlrKIEMKf!muA@JcD,;J,~>
-"lqsOs8S>_@fVJerrJ2Co)A`3GfB[_Fl<9$^4G)<rrUAR]C#V#c!t8,r;Qi,A'k5T!S*h3rrSHq
-B[m%_G,G3;",$1/N;ih\O(7qad\H:2"b:Cgs2))8rr[EDb,b79"R[8"SC%98#OmHI]"7qAr;L1+
-Xks'Xj8EHfg%PFR`if?(j8]/>S=DXRrVlrKIEMKf!muA@JcD,;J,~>
-"lqsOs8S>_@fVJerrJ2Co)A`3GfB[_Fl<9$^4G)<rrUAR]C#V#c!t8,r;Qi,A'k5T!S*h3rrSHq
-B[m%_G,G3;",$1/N;ih\O(7qad\H:2"b:Cgs2))8rr[EDb,b79"R[8"SC%98#OmHI]"7qAr;L1+
-Xks'Xj8EHfg%PFR`if?(j8]/>S=DXRrVlrKIEMKf!muA@JcD,;J,~>
-"lqsOs-ArL\-AC]s8U8Gp@J:b^VS_*!V0skrr=(trrJC?r;Qi]\DZcS"6d6nWVlbthRMhLrrK]?
-nc&`YPdn,0hZ!V$j8/cV*rc*;$o@/%6N@(IR(-<![:oR>!FYftrs!qIZ=X'*JbK*G*WN'\pAY0]
-0)PYRju37"NrT,`rjVu\[,Crbo3D7(!Ft<errf'Bs%:`;rrHK?r;Qe>W;HSqCpAQkR/_[~>
-"lqsOs-ArL\-AC]s8U8Gp@J:b^VS_*!V0skrr=(trrJC?r;Qi]\DZcS"6d6nWVlbthRMhLrrK]?
-nc&`YPdn,0hZ!V$j8/cV*rc*;$o@/%6N@(IR(-<![:oR>!FYftrs!qIZ=X'*JbK*G*WN'\pAY0]
-0)PYRju37"NrT,`rjVu\[,Crbo3D7(!Ft<errf'Bs%:`;rrHK?r;Qe>W;HSqCpAQkR/_[~>
-"lqsOs-ArL\-AC]s8U8Gp@J:b^VS_*!V0skrr=(trrJC?r;Qi]\DZcS"6d6nWVlbthRMhLrrK]?
-nc&`YPdn,0hZ!V$j8/cV*rc*;$o@/%6N@(IR(-<![:oR>!FYftrs!qIZ=X'*JbK*G*WN'\pAY0]
-0)PYRju37"NrT,`rjVu\[,Crbo3D7(!Ft<errf'Bs%:`;rrHK?r;Qe>W;HSqCpAQkR/_[~>
-"lqsOs)#">rrKc?rr3#R6HoH1m4[i+!$1%u!l&a@j8T.$WV6>m\mk40"E(CBpa"_r!CYT;rrHE@
-qu7'\l.SK(s(/\>b:?iZrr3!CqXsjm9[NaJ.rFSFrrX;AW-.h6!U_T;rs.[Es,N->ruM+=!JZs!
-rrW,+CB"56hYHpG"JU5B9%*Y;!FNP<rrV@pci!eEk$Q\js-`n;~>
-"lqsOs)#">rrKc?rr3#R6HoH1m4[i+!$1%u!l&a@j8T.$WV6>m\mk40"E(CBpa"_r!CYT;rrHE@
-qu7'\l.SK(s(/\>b:?iZrr3!CqXsjm9[NaJ.rFSFrrX;AW-.h6!U_T;rs.[Es,N->ruM+=!JZs!
-rrW,+CB"56hYHpG"JU5B9%*Y;!FNP<rrV@pci!eEk$Q\js-`n;~>
-"lqsOs)#">rrKc?rr3#R6HoH1m4[i+!$1%u!l&a@j8T.$WV6>m\mk40"E(CBpa"_r!CYT;rrHE@
-qu7'\l.SK(s(/\>b:?iZrr3!CqXsjm9[NaJ.rFSFrrX;AW-.h6!U_T;rs.[Es,N->ruM+=!JZs!
-rrW,+CB"56hYHpG"JU5B9%*Y;!FNP<rrV@pci!eEk$Q\js-`n;~>
-$KOKTs7Z<hs3js?rVlrY6h^6R!_aRerVlol6N.r*EV]V6!p^A$rr3!gf_uj%J,91/m/R*]LB%9=
-)?h*#PkY1Xn,44/S,<4+cMedcU\t/Xr>Z3Fr;JVFV]6\]rVt:D*!NkNs8TB>r;QlD*#=n?rrN)2
-r>Yj_rq??mF/f-<"0W[Z[f6:.\m:*j*!#='rrQ^Air/l^DQa$>o)JQDrYuV$o`(\EnkpG]p&C<n
-*5aNjp&G&<rYu2-pA^*l#8eFOrVlm\iVWWkoD\^\s8Vfis8MN[s8R!W"<8Cns8VdbrYuMaq#C!a
-s8DH\s8PmA,9.\Iq>UBrnc/I[pAY0]0)PYRrU^'aq#C@7rpg2AQiI(9rVm%8_#OG]>5\C+/,u]"
-s'!eLdet-g\,H<I&cNaP^A\&Lr>Z*^rr<#op]'m`r;Qe)^&.g1=2t.;!D^pks-`n;~>
-$KOKTs7Z<hs3js?rVlrY6h^6R!_aRerVlol6N.r*EV]V6!p^A$rr3!gf_uj%J,91/m/R*]LB%9=
-)?h*#PkY1Xn,44/S,<4+cMedcU\t/Xr>Z3Fr;JVFV]6\]rVt:D*!NkNs8TB>r;QlD*#=n?rrN)2
-r>Yj_rq??mF/f-<"0W[Z[f6:.\m:*j*!#='rrQ^Air/l^DQa$>o)JQDrYuV$o`(\EnkpG]p&C<n
-*5aNjp&G&<rYu2-pA^*l#8eFOrVlm\iVWWkoD\^\s8Vfis8MN[s8R!W"<8Cns8VdbrYuMaq#C!a
-s8DH\s8PmA,9.\Iq>UBrnc/I[pAY0]0)PYRrU^'aq#C@7rpg2AQiI(9rVm%8_#OG]>5\C+/,u]"
-s'!eLdet-g\,H<I&cNaP^A\&Lr>Z*^rr<#op]'m`r;Qe)^&.g1=2t.;!D^pks-`n;~>
-$KOKTs7Z<hs3js?rVlrY6h^6R!_aRerVlol6N.r*EV]V6!p^A$rr3!gf_uj%J,91/m/R*]LB%9=
-)?h*#PkY1Xn,44/S,<4+cMedcU\t/Xr>Z3Fr;JVFV]6\]rVt:D*!NkNs8TB>r;QlD*#=n?rrN)2
-r>Yj_rq??mF/f-<"0W[Z[f6:.\m:*j*!#='rrQ^Air/l^DQa$>o)JQDrYuV$o`(\EnkpG]p&C<n
-*5aNjp&G&<rYu2-pA^*l#8eFOrVlm\iVWWkoD\^\s8Vfis8MN[s8R!W"<8Cns8VdbrYuMaq#C!a
-s8DH\s8PmA,9.\Iq>UBrnc/I[pAY0]0)PYRrU^'aq#C@7rpg2AQiI(9rVm%8_#OG]>5\C+/,u]"
-s'!eLdet-g\,H<I&cNaP^A\&Lr>Z*^rr<#op]'m`r;Qe)^&.g1=2t.;!D^pks-`n;~>
-!ouXLrVloJ8c&Gfd7a04!W"#=rrGd@rr3"fK)YcOm3ulNrrG/,rr37\PQ*B's8S[>rr3#d0D,8E
-*W?!@JAM6u:&b.n?bQ@:$Wb:Ii!OT+s%^l4-iO&KA)71bZ>079!K<->rrLn@rVlmLnFlk_F/f':
-!Gf"?rrTbCPlC[_*W?!JF=H>Os7+ZGP1KO1s.Fc=rt4`Os8REaaoCN]s,`6?39B$\qu6]J7fNDg
-7+hD:!Bf?,rrF>?rVlmtaSu2?ZB"_[#"'X1s8S:?n,EFV0(f/D)ZD/q'pnt#5McA>l>"B>s34C<
-rs0\GVfi#8c1WL_rrYdBmP"P="$YT'2uWaW<pTGY!FNP;rrH3@qu6[lc@Q"`s*t~>
-!ouXLrVloJ8c&Gfd7a04!W"#=rrGd@rr3"fK)YcOm3ulNrrG/,rr37\PQ*B's8S[>rr3#d0D,8E
-*W?!@JAM6u:&b.n?bQ@:$Wb:Ii!OT+s%^l4-iO&KA)71bZ>079!K<->rrLn@rVlmLnFlk_F/f':
-!Gf"?rrTbCPlC[_*W?!JF=H>Os7+ZGP1KO1s.Fc=rt4`Os8REaaoCN]s,`6?39B$\qu6]J7fNDg
-7+hD:!Bf?,rrF>?rVlmtaSu2?ZB"_[#"'X1s8S:?n,EFV0(f/D)ZD/q'pnt#5McA>l>"B>s34C<
-rs0\GVfi#8c1WL_rrYdBmP"P="$YT'2uWaW<pTGY!FNP;rrH3@qu6[lc@Q"`s*t~>
-!ouXLrVloJ8c&Gfd7a04!W"#=rrGd@rr3"fK)YcOm3ulNrrG/,rr37\PQ*B's8S[>rr3#d0D,8E
-*W?!@JAM6u:&b.n?bQ@:$Wb:Ii!OT+s%^l4-iO&KA)71bZ>079!K<->rrLn@rVlmLnFlk_F/f':
-!Gf"?rrTbCPlC[_*W?!JF=H>Os7+ZGP1KO1s.Fc=rt4`Os8REaaoCN]s,`6?39B$\qu6]J7fNDg
-7+hD:!Bf?,rrF>?rVlmtaSu2?ZB"_[#"'X1s8S:?n,EFV0(f/D)ZD/q'pnt#5McA>l>"B>s34C<
-rs0\GVfi#8c1WL_rrYdBmP"P="$YT'2uWaW<pTGY!FNP;rrH3@qu6[lc@Q"`s*t~>
-!ouXLrr3#?<Vl^sqPAT4rrMs?rVlmkdf07IRY(>7!BT6>rs4IFs"Wj>s.4]=rrML?o`"n3qYpO9
-rVlt,^&Rp,\cb7;s56$=rr[`)pfIF*!:9^b!O?J:rrJ(?rr3#S62gfa/F`B5!HY7;rrHo@rr3#1
-@f?<,*VfX@^dT:t7IU9VTR?b='_![Rs*LL?s6a\&OH'9"jki6$s4@7]!M)^ZrrGO?qu6[ZiTpLE
-,5V9<!J7$E\cC4RrrGL?rr3"_MXUQGmOn/3!$2(=$&4fHs7.Z>s*^O=rrLA@r;R$Ds/1#>:X/S[
-rVlsif'Y3irrYIAlsB\&!9s+T!FNP;rrH3@qu6[lc@Q"`s*t~>
-!ouXLrr3#?<Vl^sqPAT4rrMs?rVlmkdf07IRY(>7!BT6>rs4IFs"Wj>s.4]=rrML?o`"n3qYpO9
-rVlt,^&Rp,\cb7;s56$=rr[`)pfIF*!:9^b!O?J:rrJ(?rr3#S62gfa/F`B5!HY7;rrHo@rr3#1
-@f?<,*VfX@^dT:t7IU9VTR?b='_![Rs*LL?s6a\&OH'9"jki6$s4@7]!M)^ZrrGO?qu6[ZiTpLE
-,5V9<!J7$E\cC4RrrGL?rr3"_MXUQGmOn/3!$2(=$&4fHs7.Z>s*^O=rrLA@r;R$Ds/1#>:X/S[
-rVlsif'Y3irrYIAlsB\&!9s+T!FNP;rrH3@qu6[lc@Q"`s*t~>
-!ouXLrr3#?<Vl^sqPAT4rrMs?rVlmkdf07IRY(>7!BT6>rs4IFs"Wj>s.4]=rrML?o`"n3qYpO9
-rVlt,^&Rp,\cb7;s56$=rr[`)pfIF*!:9^b!O?J:rrJ(?rr3#S62gfa/F`B5!HY7;rrHo@rr3#1
-@f?<,*VfX@^dT:t7IU9VTR?b='_![Rs*LL?s6a\&OH'9"jki6$s4@7]!M)^ZrrGO?qu6[ZiTpLE
-,5V9<!J7$E\cC4RrrGL?rr3"_MXUQGmOn/3!$2(=$&4fHs7.Z>s*^O=rrLA@r;R$Ds/1#>:X/S[
-rVlsif'Y3irrYIAlsB\&!9s+T!FNP;rrH3@qu6[lc@Q"`s*t~>
-#NS0Qs8T`Ko(r@eT76G4!W"#=rrGd@rr3"fK)#?H3o^/=#`4cF1$el>Spp\=!UVQ4rr=)9rr=)<
-rrZWAs-rsq"<kebi&po:!9a;h"c`$Os0?D9rrJ(?rr3#S62gfa/F`B5!HY7;rrHo@rr3#1@f?<,
-*VTL6DQ`s<!MFi>rrqmCs8RG?r;R(bNW2!"h`_"eHN%=R;+CQb!CYT;rrG7@li-u0qY^?nKDo9[
-GKfj^!CPQ>rrJ=@n,EFV0(f/D*WH'FL6qr?pM7=mJ&M?d!R4I=rs0\GVfi#8c1WL_rrYdBmP"P=
-"$YT7OoAbhbk(i8?bQ@:!E[;<rrGm?JcD/<J,~>
-#NS0Qs8T`Ko(r@eT76G4!W"#=rrGd@rr3"fK)#?H3o^/=#`4cF1$el>Spp\=!UVQ4rr=)9rr=)<
-rrZWAs-rsq"<kebi&po:!9a;h"c`$Os0?D9rrJ(?rr3#S62gfa/F`B5!HY7;rrHo@rr3#1@f?<,
-*VTL6DQ`s<!MFi>rrqmCs8RG?r;R(bNW2!"h`_"eHN%=R;+CQb!CYT;rrG7@li-u0qY^?nKDo9[
-GKfj^!CPQ>rrJ=@n,EFV0(f/D*WH'FL6qr?pM7=mJ&M?d!R4I=rs0\GVfi#8c1WL_rrYdBmP"P=
-"$YT7OoAbhbk(i8?bQ@:!E[;<rrGm?JcD/<J,~>
-#NS0Qs8T`Ko(r@eT76G4!W"#=rrGd@rr3"fK)#?H3o^/=#`4cF1$el>Spp\=!UVQ4rr=)9rr=)<
-rrZWAs-rsq"<kebi&po:!9a;h"c`$Os0?D9rrJ(?rr3#S62gfa/F`B5!HY7;rrHo@rr3#1@f?<,
-*VTL6DQ`s<!MFi>rrqmCs8RG?r;R(bNW2!"h`_"eHN%=R;+CQb!CYT;rrG7@li-u0qY^?nKDo9[
-GKfj^!CPQ>rrJ=@n,EFV0(f/D*WH'FL6qr?pM7=mJ&M?d!R4I=rs0\GVfi#8c1WL_rrYdBmP"P=
-"$YT7OoAbhbk(i8?bQ@:!E[;<rrGm?JcD/<J,~>
-#38'Ps0mL>qYpS^L@bEGqBGn<!DCl?rrJR?rr3&lJuSbL!BP?%rs4IFs"Wj>s.4]=rrqdCs8Td\
-q#:=7rVlu-g]&;mrrZWAruM+="hQ>*s56$;rrMt]rVm'jfDkm'J&M6a!K<->rrLn@rVlmLnFlk_
-F/f':!Gf"?rrTbe_>aH7*W?!>Y(H0ArrI#?rVlnkI/a-Ln1=V>H_UH<%Zl\M39B$\s+cm>s7pM$
-rr3*hf`1-5rr3%hJc>$9#9s$Ef"(g]jSo/[Uj;b8!CPQ>rrJ=@pAY3]K!G:S!U_T4rr=)=rrIk@
-rr3)N8",&.rt!@Ns1?e\ruV3<FoP7^p*Tb<"%Ur10E(nQ52PB[rVlngoC`+a?bQC;!kWsAr;Qi-
-J*-\/!jdLEJcDGDJ,~>
-#38'Ps0mL>qYpS^L@bEGqBGn<!DCl?rrJR?rr3&lJuSbL!BP?%rs4IFs"Wj>s.4]=rrqdCs8Td\
-q#:=7rVlu-g]&;mrrZWAruM+="hQ>*s56$;rrMt]rVm'jfDkm'J&M6a!K<->rrLn@rVlmLnFlk_
-F/f':!Gf"?rrTbe_>aH7*W?!>Y(H0ArrI#?rVlnkI/a-Ln1=V>H_UH<%Zl\M39B$\s+cm>s7pM$
-rr3*hf`1-5rr3%hJc>$9#9s$Ef"(g]jSo/[Uj;b8!CPQ>rrJ=@pAY3]K!G:S!U_T4rr=)=rrIk@
-rr3)N8",&.rt!@Ns1?e\ruV3<FoP7^p*Tb<"%Ur10E(nQ52PB[rVlngoC`+a?bQC;!kWsAr;Qi-
-J*-\/!jdLEJcDGDJ,~>
-#38'Ps0mL>qYpS^L@bEGqBGn<!DCl?rrJR?rr3&lJuSbL!BP?%rs4IFs"Wj>s.4]=rrqdCs8Td\
-q#:=7rVlu-g]&;mrrZWAruM+="hQ>*s56$;rrMt]rVm'jfDkm'J&M6a!K<->rrLn@rVlmLnFlk_
-F/f':!Gf"?rrTbe_>aH7*W?!>Y(H0ArrI#?rVlnkI/a-Ln1=V>H_UH<%Zl\M39B$\s+cm>s7pM$
-rr3*hf`1-5rr3%hJc>$9#9s$Ef"(g]jSo/[Uj;b8!CPQ>rrJ=@pAY3]K!G:S!U_T4rr=)=rrIk@
-rr3)N8",&.rt!@Ns1?e\ruV3<FoP7^p*Tb<"%Ur10E(nQ52PB[rVlngoC`+a?bQC;!kWsAr;Qi-
-J*-\/!jdLEJcDGDJ,~>
-"lqsOs(t7(Ad+k-s,iH?o`#2OA.E4Bs8TQHral1Wc2R_Ekl=QZrrG0:ralakeGlXcAnH==_uKc3
-OCi*Ug\CdKUA\[+K]2qOrVlt,^&OGuAd*cC`rFsZr;QfpOo8kmMspZF!L8H=rs7Fm3'([/s7)'H
-Ac\"hq#:rOAhHJ`n,NF0Ah-A`o`)KaJ,X$[TDeck=odLZrrI#?rVloOJGs-aBrh:6H_UH<%Zl\M
-YOp^8s3H%(AnZ`brr3,.DJ!jtrVlm>rp9XiVe9Uc`rEYjral1UanYl:6eVJ=!L&E7rrUmS@/^*+
-mOn/3!2BI)!IiSurr_\IHHlEg&*o'aK&$D+P@d08Ar5jNOo8koMsgA%rFQ.ko(A%AAc[qbp&>&"
-^&7m2FK#*:!Go%<rrQ[1eq*jps*t~>
-"lqsOs(t7(Ad+k-s,iH?o`#2OA.E4Bs8TQHral1Wc2R_Ekl=QZrrG0:ralakeGlXcAnH==_uKc3
-OCi*Ug\CdKUA\[+K]2qOrVlt,^&OGuAd*cC`rFsZr;QfpOo8kmMspZF!L8H=rs7Fm3'([/s7)'H
-Ac\"hq#:rOAhHJ`n,NF0Ah-A`o`)KaJ,X$[TDeck=odLZrrI#?rVloOJGs-aBrh:6H_UH<%Zl\M
-YOp^8s3H%(AnZ`brr3,.DJ!jtrVlm>rp9XiVe9Uc`rEYjral1UanYl:6eVJ=!L&E7rrUmS@/^*+
-mOn/3!2BI)!IiSurr_\IHHlEg&*o'aK&$D+P@d08Ar5jNOo8koMsgA%rFQ.ko(A%AAc[qbp&>&"
-^&7m2FK#*:!Go%<rrQ[1eq*jps*t~>
-"lqsOs(t7(Ad+k-s,iH?o`#2OA.E4Bs8TQHral1Wc2R_Ekl=QZrrG0:ralakeGlXcAnH==_uKc3
-OCi*Ug\CdKUA\[+K]2qOrVlt,^&OGuAd*cC`rFsZr;QfpOo8kmMspZF!L8H=rs7Fm3'([/s7)'H
-Ac\"hq#:rOAhHJ`n,NF0Ah-A`o`)KaJ,X$[TDeck=odLZrrI#?rVloOJGs-aBrh:6H_UH<%Zl\M
-YOp^8s3H%(AnZ`brr3,.DJ!jtrVlm>rp9XiVe9Uc`rEYjral1UanYl:6eVJ=!L&E7rrUmS@/^*+
-mOn/3!2BI)!IiSurr_\IHHlEg&*o'aK&$D+P@d08Ar5jNOo8koMsgA%rFQ.ko(A%AAc[qbp&>&"
-^&7m2FK#*:!Go%<rrQ[1eq*jps*t~>
-"QVjNs4.%T"O[8Lb4G6)!6+rF!7:`F!5e`C!7LiG!r97Jrr3![ir6=cfDbdR]=#&og>`,3"nB".
-h#DQp8cls2rVa,+iW&qlrVluIm/Qn\[0>C3mf3"#qu6ZgrNuXkrVlrWI)#[\!:Tlo"7Z?jm/=<m
-o(DiO!rDr[rNub%s8V3Z[06@+ldFMd[/g.'rrUNSpAP!le`Zl1!8IL\!4i+/!SQQ3rrM$6rr3;u
-a8c1h[C*O9ao25@^pV)XrrKi?li.$p[E\^N!6+rF!7:K?!Qk!5rrM'6pAY3dL1'u["RZ^k8u_Rb
-!<2u*!8.5L!UA,1rrVDlh>[E[p9f'B[HRYjo_l0"li7"TrNuaps8VQd[/f[irrgP<8fYPCrrTHY
-k5>5\X,-!:rrUWVo7?q8s*t~>
-"QVjNs4.%T"O[8Lb4G6)!6+rF!7:`F!5e`C!7LiG!r97Jrr3![ir6=cfDbdR]=#&og>`,3"nB".
-h#DQp8cls2rVa,+iW&qlrVluIm/Qn\[0>C3mf3"#qu6ZgrNuXkrVlrWI)#[\!:Tlo"7Z?jm/=<m
-o(DiO!rDr[rNub%s8V3Z[06@+ldFMd[/g.'rrUNSpAP!le`Zl1!8IL\!4i+/!SQQ3rrM$6rr3;u
-a8c1h[C*O9ao25@^pV)XrrKi?li.$p[E\^N!6+rF!7:K?!Qk!5rrM'6pAY3dL1'u["RZ^k8u_Rb
-!<2u*!8.5L!UA,1rrVDlh>[E[p9f'B[HRYjo_l0"li7"TrNuaps8VQd[/f[irrgP<8fYPCrrTHY
-k5>5\X,-!:rrUWVo7?q8s*t~>
-"QVjNs4.%T"O[8Lb4G6)!6+rF!7:`F!5e`C!7LiG!r97Jrr3![ir6=cfDbdR]=#&og>`,3"nB".
-h#DQp8cls2rVa,+iW&qlrVluIm/Qn\[0>C3mf3"#qu6ZgrNuXkrVlrWI)#[\!:Tlo"7Z?jm/=<m
-o(DiO!rDr[rNub%s8V3Z[06@+ldFMd[/g.'rrUNSpAP!le`Zl1!8IL\!4i+/!SQQ3rrM$6rr3;u
-a8c1h[C*O9ao25@^pV)XrrKi?li.$p[E\^N!6+rF!7:K?!Qk!5rrM'6pAY3dL1'u["RZ^k8u_Rb
-!<2u*!8.5L!UA,1rrVDlh>[E[p9f'B[HRYjo_l0"li7"TrNuaps8VQd[/f[irrgP<8fYPCrrTHY
-k5>5\X,-!:rrUWVo7?q8s*t~>
-!ouXLd/O,-ip?[Fh##J!nC@O>kO7p?!;u]@!<0,#!7o'f!PDh=rrDurd/`FerrK$?h>[KGrm:`;
-rVloalMLS^lKj*%QiDR~>
-!ouXLd/O,-ip?[Fh##J!nC@O>kO7p?!;u]@!<0,#!7o'f!PDh=rrDurd/`FerrK$?h>[KGrm:`;
-rVloalMLS^lKj*%QiDR~>
-!ouXLd/O,-ip?[Fh##J!nC@O>kO7p?!;u]@!<0,#!7o'f!PDh=rrDurd/`FerrK$?h>[KGrm:`;
-rVloalMLS^lKj*%QiDR~>
-!ouXLd/O,5jFR>grrV%Uo[NmAWdB<sJcF[.J,~>
-!ouXLd/O,5jFR>grrV%Uo[NmAWdB<sJcF[.J,~>
-!ouXLd/O,5jFR>grrV%Uo[NmAWdB<sJcF[.J,~>
-!ouXLJcC<$JcC<$K`?Q~>
-!ouXLJcC<$JcC<$K`?Q~>
-!ouXLJcC<$JcC<$K`?Q~>
-#in9Rs8UK[]uSt/!65#O!82r'JcC<$JcE(VJ,~>
-#in9Rs8UK[]uSt/!65#O!82r'JcC<$JcE(VJ,~>
-#in9Rs8UK[]uSt/!65#O!82r'JcC<$JcE(VJ,~>
-$04BSs2f=g?>-n,rrKZDra#VPe:IXNs+13$s0VfV~>
-$04BSs2f=g?>-n,rrKZDra#VPe:IXNs+13$s0VfV~>
-$04BSs2f=g?>-n,rrKZDra#VPe:IXNs+13$s0VfV~>
-$04BSs)#"?s4Kcsrs#$Hqu?]9_L_`<s+13$s0VfV~>
-$04BSs)#"?s4Kcsrs#$Hqu?]9_L_`<s+13$s0VfV~>
-$04BSs)#"?s4Kcsrs#$Hqu?]9_L_`<s+13$s0VfV~>
-%HKfWs)#"?s4Kd>s.n3ErrLQFrr3"HrVca&Rc"$ks2_GEs+C;b!2TVo"=7VnBrV+3!."QX!3UnQ
-JcC<$JcE@^J,~>
-%HKfWs)#"?s4Kd>s.n3ErrLQFrr3"HrVca&Rc"$ks2_GEs+C;b!2TVo"=7VnBrV+3!."QX!3UnQ
-JcC<$JcE@^J,~>
-%HKfWs)#"?s4Kd>s.n3ErrLQFrr3"HrVca&Rc"$ks2_GEs+C;b!2TVo"=7VnBrV+3!."QX!3UnQ
-JcC<$JcE@^J,~>
-%HKfWs(sVe9L2&Gs(&Y=rrKK@rr3!Bqu-O$;p"k[s.ao?JY<"K"H'/XH_gYI"Ga/[Ff55F!J@_0
-s+13$s+13_s*t~>
-%HKfWs(sVe9L2&Gs(&Y=rrKK@rr3!Bqu-O$;p"k[s.ao?JY<"K"H'/XH_gYI"Ga/[Ff55F!J@_0
-s+13$s+13_s*t~>
-%HKfWs(sVe9L2&Gs(&Y=rrKK@rr3!Bqu-O$;p"k[s.ao?JY<"K"H'/XH_gYI"Ga/[Ff55F!J@_0
-s+13$s+13_s*t~>
-'')>\s)!eBc`fe:s5I;>s4Ui>rr3!Bqu-O$;p"k[s.ao?9@Eh>"IarB6JDG="Hn]C3o^/=!U8m#
-s+13$s+13_s*t~>
-'')>\s)!eBc`fe:s5I;>s4Ui>rr3!Bqu-O$;p"k[s.ao?9@Eh>"IarB6JDG="Hn]C3o^/=!U8m#
-s+13$s+13_s*t~>
-'')>\s)!eBc`fe:s5I;>s4Ui>rr3!Bqu-O$;p"k[s.ao?9@Eh>"IarB6JDG="Hn]C3o^/=!U8m#
-s+13$s+13_s*t~>
-$04BSs)#"?s4Kd=rrc$Brle7<rrF;?rVm1&and4]UO)r5df07LRY(Q+gA_*WP)KA)1)q9LJcC<$
-JcC<$])R9~>
-$04BSs)#"?s4Kd=rrc$Brle7<rrF;?rVm1&and4]UO)r5df07LRY(Q+gA_*WP)KA)1)q9LJcC<$
-JcC<$])R9~>
-$04BSs)#"?s4Kd=rrc$Brle7<rrF;?rVm1&and4]UO)r5df07LRY(Q+gA_*WP)KA)1)q9LJcC<$
-JcC<$])R9~>
-$04BSs)#"?s4Kd<rrO\00)Y_[+oD#ss8Q$>qBGs7HN-Xdrr3+iK)\0krr3+aMuPitrr3#fn:CUj
-s+13$s1JA^~>
-$04BSs)#"?s4Kd<rrO\00)Y_[+oD#ss8Q$>qBGs7HN-Xdrr3+iK)\0krr3+aMuPitrr3#fn:CUj
-s+13$s1JA^~>
-$04BSs)#"?s4Kd<rrO\00)Y_[+oD#ss8Q$>qBGs7HN-Xdrr3+iK)\0krr3+aMuPitrr3#fn:CUj
-s+13$s1JA^~>
-$04BSs,i\`^T;JSrrQQ4@f66:=hUV\s8RPD]G\JHS,[`4rkASqU&T,7rkASmW;gY<rkAJeY(?V(
-s+13$s1JA^~>
-$04BSs,i\`^T;JSrrQQ4@f66:=hUV\s8RPD]G\JHS,[`4rkASqU&T,7rkASmW;gY<rkAJeY(?V(
-s+13$s1JA^~>
-$04BSs,i\`^T;JSrrQQ4@f66:=hUV\s8RPD]G\JHS,[`4rkASqU&T,7rkASmW;gY<rkAJeY(?V(
-s+13$s1JA^~>
-#in9Rs8S-b>]flC!,q`6!FC9SrrddS$s].urr@?D>QC;nrr@0?>QCMtrr?s9>QC[Qs+13$s+13^
-s*t~>
-#in9Rs8S-b>]flC!,q`6!FC9SrrddS$s].urr@?D>QC;nrr@0?>QCMtrr?s9>QC[Qs+13$s+13^
-s*t~>
-#in9Rs8S-b>]flC!,q`6!FC9SrrddS$s].urr@?D>QC;nrr@0?>QCMtrr?s9>QC[Qs+13$s+13^
-s*t~>
-!ouXLk5PJY,(]cFs+13$s.TIC~>
-!ouXLk5PJY,(]cFs+13$s.TIC~>
-!ouXLk5PJY,(]cFs+13$s.TIC~>
-!ouXLk5PJY,(]cFs+13$s.TIC~>
-!ouXLk5PJY,(]cFs+13$s.TIC~>
-!ouXLk5PJY,(]cFs+13$s.TIC~>
-!ouXLk5PJ]\q0m4s+13$s.TIC~>
-!ouXLk5PJ]\q0m4s+13$s.TIC~>
-!ouXLk5PJ]\q0m4s+13$s.TIC~>
-!ouXLJcC<$JcC<$K`?Q~>
-!ouXLJcC<$JcC<$K`?Q~>
-!ouXLJcC<$JcC<$K`?Q~>
-!ouXLq#:A8^4H<8s+13$s,[21~>
-!ouXLq#:A8^4H<8s+13$s,[21~>
-!ouXLq#:A8^4H<8s+13$s,[21~>
-!ouXLq#:A*\:O[2s+13$s,[21~>
-!ouXLq#:A*\:O[2s+13$s,[21~>
-!ouXLq#:A*\:O[2s+13$s,[21~>
-"lqsOs8UXK_?A<es(&Y=rrMNAJcC<$JcC<$PlH7~>
-"lqsOs8UXK_?A<es(&Y=rrMNAJcC<$JcC<$PlH7~>
-"lqsOs8UXK_?A<es(&Y=rrMNAJcC<$JcC<$PlH7~>
-"lqsOs3,K^=UArcs(&Y>q504DJcC<$JcC<$PlH7~>
-"lqsOs3,K^=UArcs(&Y>q504DJcC<$JcC<$PlH7~>
-"lqsOs3,K^=UArcs(&Y>q504DJcC<$JcC<$PlH7~>
-"lqsOs)#">rs68Fs(&X1Lio;?s+13$s+136s*t~>
-"lqsOs)#">rs68Fs(&X1Lio;?s+13$s+136s*t~>
-"lqsOs)#">rs68Fs(&X1Lio;?s+13$s+136s*t~>
-"lqsOs)#">rs$,Ds("oaR=YBhs+13$s,m>3~>
-"lqsOs)#">rs$,Ds("oaR=YBhs+13$s,m>3~>
-"lqsOs)#">rs$,Ds("oaR=YBhs+13$s,m>3~>
-"lqsOs)#">rs$,Ds($Od?%N$,s+13$s,m>3~>
-"lqsOs)#">rs$,Ds($Od?%N$,s+13$s,m>3~>
-"lqsOs)#">rs$,Ds($Od?%N$,s+13$s,m>3~>
-"lqsOs)#">rs68Fs(&Xf^c$1`s+13$s+136s*t~>
-"lqsOs)#">rs68Fs(&Xf^c$1`s+13$s+136s*t~>
-"lqsOs)#">rs68Fs(&Xf^c$1`s+13$s+136s*t~>
-"lqsOs6s7l*!oL2s(8hArT1&)JcC<$JcC<$PlH7~>
-"lqsOs6s7l*!oL2s(8hArT1&)JcC<$JcC<$PlH7~>
-"lqsOs6s7l*!oL2s(8hArT1&)JcC<$JcC<$PlH7~>
-!ouXLJcC<$JcC<$K`?Q~>
-!ouXLJcC<$JcC<$K`?Q~>
-!ouXLJcC<$JcC<$K`?Q~>
-!ouXLJcC<$JcC<$K`?Q~>
-!ouXLJcC<$JcC<$K`?Q~>
-!ouXLJcC<$JcC<$K`?Q~>
-!ouXLJcC<$JcC<$K`?Q~>
-!ouXLJcC<$JcC<$K`?Q~>
-!ouXLJcC<$JcC<$K`?Q~>
-!ouXLJcC<$JcC<$K`?Q~>
-!ouXLJcC<$JcC<$K`?Q~>
-!ouXLJcC<$JcC<$K`?Q~>
-"QVjNs/l3<"K)5!R-9,$JcC<$JcCi3J,~>
-"QVjNs/l3<"K)5!R-9,$JcC<$JcCi3J,~>
-"QVjNs/l3<"K)5!R-9,$JcC<$JcCi3J,~>
-"QVjNs3LYE#(Bt[s2&7>JcC<$JcC<$OoKq~>
-"QVjNs3LYE#(Bt[s2&7>JcC<$JcC<$OoKq~>
-"QVjNs3LYE#(Bt[s2&7>JcC<$JcC<$OoKq~>
-!ouXLr;QiX?JPP[!ROMks+13$s+134s*t~>
-!ouXLr;QiX?JPP[!ROMks+13$s+134s*t~>
-!ouXLr;QiX?JPP[!ROMks+13$s+134s*t~>
-!ouXLrVlrn3U6PB!S9bks+13$s+135s*t~>
-!ouXLrVlrn3U6PB!S9bks+13$s+135s*t~>
-!ouXLrVlrn3U6PB!S9bks+13$s+135s*t~>
-%%EndData
-showpage
-%%Trailer
-end
-%%EOF
diff --git a/lib/stdlib/doc/src/zip.xml b/lib/stdlib/doc/src/zip.xml
index cf0d581352..61f49f5940 100644
--- a/lib/stdlib/doc/src/zip.xml
+++ b/lib/stdlib/doc/src/zip.xml
@@ -217,7 +217,7 @@
<tag><c>{uncompress, <anno>What</anno>}</c></tag>
<item>
<p>Controls what types of files will be uncompressed. It is by
- default set to <c>[".Z",".zip",".zoo",".arc",".lzh",".arj"]</c>.
+ default set to <c>[".Z", ".zip", ".zoo", ".arc", ".lzh", ".arj"]</c>.
The following values of <c>What</c> are allowed:</p>
<taglist>
<tag><c>all</c></tag>
@@ -355,7 +355,7 @@
{ok,{"dummy.zip",
&lt;&lt;80,75,3,4,20,0,0,0,0,0,74,152,97,60,171,39,212,26,3,0,
0,0,3,0,0,...&gt;&gt;}}
-&gt; <input>catch zip:foldl(fun("foo", _, B, _) -> throw(B()); (_, _, _, Acc) -> Acc end, [], {Name, Bin}). </input>
+&gt; <input>catch zip:foldl(fun("foo", _, B, _) -> throw(B()); (_,_,_,Acc) -> Acc end, [], {Name, Bin}). </input>
&lt;&lt;"FOO"&gt;&gt;
</pre>
</desc>
diff --git a/lib/stdlib/src/Makefile b/lib/stdlib/src/Makefile
index 14304824d3..2bab46b72a 100644
--- a/lib/stdlib/src/Makefile
+++ b/lib/stdlib/src/Makefile
@@ -171,27 +171,29 @@ primary_bootstrap_compiler: \
$(BOOTSTRAP_COMPILER)/ebin/erl_scan.beam \
$(BOOTSTRAP_COMPILER)/ebin/erl_parse.beam \
$(BOOTSTRAP_COMPILER)/ebin/erl_lint.beam \
+ $(BOOTSTRAP_COMPILER)/ebin/io.beam \
$(BOOTSTRAP_COMPILER)/ebin/otp_internal.beam
$(BOOTSTRAP_COMPILER)/ebin/erl_parse.beam: erl_parse.yrl
- $(ERLC) -o $(BOOTSTRAP_COMPILER)/egen erl_parse.yrl
- $(ERLC) -o $(BOOTSTRAP_COMPILER)/ebin $(BOOTSTRAP_COMPILER)/egen/erl_parse.erl
+ $(gen_verbose)
+ $(V_at)$(ERLC) -o $(BOOTSTRAP_COMPILER)/egen erl_parse.yrl
+ $(V_at)$(ERLC) -o $(BOOTSTRAP_COMPILER)/ebin $(BOOTSTRAP_COMPILER)/egen/erl_parse.erl
$(BOOTSTRAP_TOP)/lib/stdlib/egen/erl_parse.erl: erl_parse.yrl
- $(ERLC) $(YRL_FLAGS) -o$(BOOTSTRAP_TOP)/lib/stdlib/egen erl_parse.yrl
+ $(yecc_verbose)$(ERLC) $(YRL_FLAGS) -o$(BOOTSTRAP_TOP)/lib/stdlib/egen erl_parse.yrl
$(BOOTSTRAP_COMPILER)/ebin/%.beam: %.erl
- $(ERLC) -o $(BOOTSTRAP_COMPILER)/ebin $<
+ $(V_ERLC) -o $(BOOTSTRAP_COMPILER)/ebin $<
# ----------------------------------------------------
# Special Build Targets
# ----------------------------------------------------
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
# ----------------------------------------------------
# Release Target
diff --git a/lib/stdlib/src/binary.erl b/lib/stdlib/src/binary.erl
index 1ed3422bc5..41b6ab1d5f 100644
--- a/lib/stdlib/src/binary.erl
+++ b/lib/stdlib/src/binary.erl
@@ -21,6 +21,8 @@
%% Implemented in this module:
-export([split/2,split/3,replace/3,replace/4]).
+-export_type([cp/0]).
+
-opaque cp() :: {'am' | 'bm', binary()}.
-type part() :: {Start :: non_neg_integer(), Length :: integer()}.
diff --git a/lib/stdlib/src/c.erl b/lib/stdlib/src/c.erl
index a920921a5e..4c1c0f904b 100644
--- a/lib/stdlib/src/c.erl
+++ b/lib/stdlib/src/c.erl
@@ -116,7 +116,7 @@ machine_load(Mod, File, Opts) ->
File2 = filename:join(Dir, filename:basename(File, ".erl")),
case compile:output_generated(Opts) of
true ->
- Base = packages:last(Mod),
+ Base = atom_to_list(Mod),
case filename:basename(File, ".erl") of
Base ->
code:purge(Mod),
diff --git a/lib/stdlib/src/dets.erl b/lib/stdlib/src/dets.erl
index 6a937f8fa2..845fae4bf4 100644
--- a/lib/stdlib/src/dets.erl
+++ b/lib/stdlib/src/dets.erl
@@ -88,7 +88,8 @@
%% Not documented, or not ready for publication.
-export([lookup_keys/2]).
--export_type([tab_name/0]).
+-export_type([bindings_cont/0, cont/0, object_cont/0, select_cont/0,
+ tab_name/0]).
-compile({inline, [{einval,2},{badarg,2},{undefined,1},
{badarg_exit,2},{lookup_reply,2}]}).
diff --git a/lib/stdlib/src/dict.erl b/lib/stdlib/src/dict.erl
index 2e9eba4bfa..4f8d45dc8d 100644
--- a/lib/stdlib/src/dict.erl
+++ b/lib/stdlib/src/dict.erl
@@ -1,7 +1,8 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -17,7 +18,7 @@
%% %CopyrightEnd%
%%
-%% We use the dynamic hashing techniques by Per-�ke Larsson as
+%% We use the dynamic hashing techniques by Per-Åke Larsson as
%% described in "The Design and Implementation of Dynamic Hashing for
%% Sets and Tables in Icon" by Griswold and Townsend. Much of the
%% terminology comes from that paper as well.
diff --git a/lib/stdlib/src/edlin.erl b/lib/stdlib/src/edlin.erl
index 026bd9038f..1164ee49eb 100644
--- a/lib/stdlib/src/edlin.erl
+++ b/lib/stdlib/src/edlin.erl
@@ -1,7 +1,8 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -317,9 +318,9 @@ over_non_word([], Stack, N) ->
{[],Stack,N}.
word_char(C) when C >= $A, C =< $Z -> true;
-word_char(C) when C >= $�, C =< $�, C =/= $� -> true;
+word_char(C) when C >= $À, C =< $Þ, C =/= $× -> true;
word_char(C) when C >= $a, C =< $z -> true;
-word_char(C) when C >= $�, C =< $�, C =/= $� -> true;
+word_char(C) when C >= $ß, C =< $ÿ, C =/= $÷ -> true;
word_char(C) when C >= $0, C =< $9 -> true;
word_char(C) when C =:= $_ -> true;
word_char(C) when C =:= $. -> true; % accept dot-separated names
diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl
index 2c8d84a9e1..a0f7660ecf 100644
--- a/lib/stdlib/src/epp.erl
+++ b/lib/stdlib/src/epp.erl
@@ -23,13 +23,18 @@
-export([open/2,open/3,open/5,close/1,format_error/1]).
-export([scan_erl_form/1,parse_erl_form/1,macro_defs/1]).
-export([parse_file/1, parse_file/3]).
+-export([default_encoding/0, encoding_to_string/1,
+ read_encoding/1, read_encoding/2, set_encoding/1]).
-export([interpret_file_attribute/1]).
-export([normalize_typed_record_fields/1,restore_typed_record_fields/1]).
%%------------------------------------------------------------------------
+-export_type([source_encoding/0]).
+
-type macros() :: [{atom(), term()}].
-type epp_handle() :: pid().
+-type source_encoding() :: latin1 | utf8.
%% Epp state record.
-record(epp, {file, %Current file
@@ -213,6 +218,173 @@ parse_file(Epp) ->
[{eof,Location}]
end.
+-define(DEFAULT_ENCODING, latin1).
+
+-spec default_encoding() -> source_encoding().
+
+default_encoding() ->
+ ?DEFAULT_ENCODING.
+
+-spec encoding_to_string(Encoding) -> string() when
+ Encoding :: source_encoding().
+
+encoding_to_string(latin1) -> "coding: latin-1";
+encoding_to_string(utf8) -> "coding: utf-8".
+
+-spec read_encoding(FileName) -> source_encoding() | none when
+ FileName :: file:name().
+
+read_encoding(Name) ->
+ read_encoding(Name, []).
+
+-spec read_encoding(FileName, Options) -> source_encoding() | none when
+ FileName :: file:name(),
+ Options :: [Option],
+ Option :: {in_comment_only, boolean()}.
+
+read_encoding(Name, Options) ->
+ InComment = proplists:get_value(in_comment_only, Options, true),
+ case file:open(Name, [read]) of
+ {ok,File} ->
+ try read_encoding_from_file(File, InComment)
+ after ok = file:close(File)
+ end;
+ _Error ->
+ none
+ end.
+
+-spec set_encoding(File) -> source_encoding() | none when
+ File :: io:device(). % pid(); raw files don't work
+
+set_encoding(File) ->
+ Encoding = read_encoding_from_file(File, true),
+ Enc = case Encoding of
+ none -> default_encoding();
+ Encoding -> Encoding
+ end,
+ ok = io:setopts(File, [{encoding, Enc}]),
+ Encoding.
+
+-spec read_encoding_from_file(File, InComment) -> source_encoding() | none when
+ File :: io:device(),
+ InComment :: boolean().
+
+-define(ENC_CHUNK, 32).
+-define(N_ENC_CHUNK, 16). % a total of 512 bytes
+
+read_encoding_from_file(File, InComment) ->
+ {ok, Pos0} = file:position(File, cur),
+ Opts = io:getopts(File),
+ Encoding0 = lists:keyfind(encoding, 1, Opts),
+ Binary0 = lists:keyfind(binary, 1, Opts),
+ ok = io:setopts(File, [binary, {encoding, latin1}]),
+ try
+ {B, Fun} = (reader(File, 0))(),
+ com_nl(B, Fun, 0, InComment)
+ catch
+ throw:no ->
+ none
+ after
+ {ok, Pos0} = file:position(File, Pos0),
+ ok = io:setopts(File, [Binary0, Encoding0])
+ end.
+
+reader(Fd, N) ->
+ fun() when N =:= ?N_ENC_CHUNK ->
+ throw(no);
+ () ->
+ case file:read(Fd, ?ENC_CHUNK) of
+ eof ->
+ {<<>>, reader(Fd, N+1)};
+ {ok, Bin} ->
+ {Bin, reader(Fd, N+1)};
+ {error, _} ->
+ throw(no) % ignore errors
+ end
+ end.
+
+com_nl(_, _, 2, _) ->
+ throw(no);
+com_nl(B, Fun, N, false=Com) ->
+ com_c(B, Fun, N, Com);
+com_nl(B, Fun, N, true=Com) ->
+ com(B, Fun, N, Com).
+
+com(<<"\n",B/binary>>, Fun, N, Com) ->
+ com_nl(B, Fun, N+1, Com);
+com(<<"%", B/binary>>, Fun, N, Com) ->
+ com_c(B, Fun, N, Com);
+com(<<_:1/unit:8,B/binary>>, Fun, N, Com) ->
+ com(B, Fun, N, Com);
+com(<<>>, Fun, N, Com) ->
+ {B, Fun1} = Fun(),
+ com(B, Fun1, N, Com).
+
+com_c(<<"c",B/binary>>, Fun, N, Com) ->
+ com_oding(B, Fun, N, Com);
+com_c(<<"\n",B/binary>>, Fun, N, Com) ->
+ com_nl(B, Fun, N+1, Com);
+com_c(<<_:1/unit:8,B/binary>>, Fun, N, Com) ->
+ com_c(B, Fun, N, Com);
+com_c(<<>>, Fun, N, Com) ->
+ {B, Fun1} = Fun(),
+ com_c(B, Fun1, N, Com).
+
+com_oding(<<"oding",B/binary>>, Fun, N, Com) ->
+ com_sep(B, Fun, N, Com);
+com_oding(B, Fun, N, Com) when byte_size(B) >= length("oding") ->
+ com_c(B, Fun, N, Com);
+com_oding(B, Fun, N, Com) ->
+ {B1, Fun1} = Fun(),
+ com_oding(list_to_binary([B, B1]), Fun1, N, Com).
+
+com_sep(<<":",B/binary>>, Fun, N, Com) ->
+ com_space(B, Fun, N, Com);
+com_sep(<<"=",B/binary>>, Fun, N, Com) ->
+ com_space(B, Fun, N, Com);
+com_sep(<<"\s",B/binary>>, Fun, N, Com) ->
+ com_sep(B, Fun, N, Com);
+com_sep(<<>>, Fun, N, Com) ->
+ {B, Fun1} = Fun(),
+ com_sep(B, Fun1, N, Com);
+com_sep(B, Fun, N, Com) ->
+ com_c(B, Fun, N, Com).
+
+com_space(<<"\s",B/binary>>, Fun, N, Com) ->
+ com_space(B, Fun, N, Com);
+com_space(<<>>, Fun, N, Com) ->
+ {B, Fun1} = Fun(),
+ com_space(B, Fun1, N, Com);
+com_space(B, Fun, N, _Com) ->
+ com_enc(B, Fun, N, [], []).
+
+com_enc(<<C:1/unit:8,B/binary>>, Fun, N, L, Ps) when C >= $a, C =< $z;
+ C >= $A, C =< $Z;
+ C >= $0, C =< $9 ->
+ com_enc(B, Fun, N, [C | L], Ps);
+com_enc(<<>>, Fun, N, L, Ps) ->
+ case Fun() of
+ {<<>>, _} ->
+ com_enc_end([L | Ps]);
+ {B, Fun1} ->
+ com_enc(B, Fun1, N, L, Ps)
+ end;
+com_enc(<<"-",B/binary>>, Fun, N, L, Ps) ->
+ com_enc(B, Fun, N, [], [L | Ps]);
+com_enc(_B, _Fun, _N, L, Ps) ->
+ com_enc_end([L | Ps]).
+
+com_enc_end(Ps0) ->
+ Ps = lists:reverse([lists:reverse(string:to_lower(P)) || P <- Ps0]),
+ com_encoding(Ps).
+
+com_encoding(["latin","1"|_]) ->
+ latin1;
+com_encoding(["utf","8"|_]) ->
+ utf8;
+com_encoding(_) ->
+ throw(no). % Don't try any further
+
normalize_typed_record_fields([]) ->
{typed, []};
normalize_typed_record_fields(Fields) ->
@@ -266,14 +438,17 @@ init_server(Pid, Name, File, AtLocation, Path, Pdm, Pre) ->
Ms0 = predef_macros(Name),
case user_predef(Pdm, Ms0) of
{ok,Ms1} ->
- epp_reply(Pid, {ok,self()}),
- %% ensure directory of current source file is first in path
+ _ = set_encoding(File),
+ epp_reply(Pid, {ok,self()}),
+ %% ensure directory of current source file is
+ %% first in path
Path1 = [filename:dirname(Name) | Path],
- St = #epp{file=File, location=AtLocation, delta=0, name=Name,
- name2=Name, path=Path1, macs=Ms1, pre_opened = Pre},
- From = wait_request(St),
- enter_file_reply(From, Name, AtLocation, AtLocation),
- wait_req_scan(St);
+ St = #epp{file=File, location=AtLocation, delta=0,
+ name=Name, name2=Name, path=Path1, macs=Ms1,
+ pre_opened = Pre},
+ From = wait_request(St),
+ enter_file_reply(From, Name, AtLocation, AtLocation),
+ wait_req_scan(St);
{error,E} ->
epp_reply(Pid, {error,E})
end.
@@ -385,19 +560,20 @@ enter_file(NewName, Inc, From, St) ->
%% enter_file2(File, FullName, From, EppState, AtLocation) -> EppState.
%% Set epp to use this file and "enter" it.
-enter_file2(NewF, Pname, From, St, AtLocation) ->
+enter_file2(NewF, Pname, From, St0, AtLocation) ->
Loc = start_loc(AtLocation),
enter_file_reply(From, Pname, Loc, AtLocation),
- Ms = dict:store({atom,'FILE'}, {none,[{string,Loc,Pname}]}, St#epp.macs),
+ Ms = dict:store({atom,'FILE'}, {none,[{string,Loc,Pname}]}, St0#epp.macs),
%% update the head of the include path to be the directory of the new
%% source file, so that an included file can always include other files
%% relative to its current location (this is also how C does it); note
%% that the directory of the parent source file (the previous head of
%% the path) must be dropped, otherwise the path used within the current
%% file will depend on the order of file inclusions in the parent files
- Path = [filename:dirname(Pname) | tl(St#epp.path)],
+ Path = [filename:dirname(Pname) | tl(St0#epp.path)],
+ _ = set_encoding(NewF),
#epp{file=NewF,location=Loc,name=Pname,delta=0,
- sstk=[St|St#epp.sstk],path=Path,macs=Ms}.
+ sstk=[St0|St0#epp.sstk],path=Path,macs=Ms}.
enter_file_reply(From, Name, Location, AtLocation) ->
Attr = loc_attr(AtLocation),
@@ -456,7 +632,7 @@ leave_file(From, St) ->
%% scan_toks(Tokens, From, EppState)
scan_toks(From, St) ->
- case io:scan_erl_form(St#epp.file, '', St#epp.location) of
+ case io:scan_erl_form(St#epp.file, '', St#epp.location, [unicode]) of
{ok,Toks,Cl} ->
scan_toks(Toks, From, St#epp{location=Cl});
{error,E,Cl} ->
@@ -830,7 +1006,7 @@ new_location(Ln, {Le,_}, {Lf,_}) ->
%% nested conditionals and repeated 'else's.
skip_toks(From, St, [I|Sis]) ->
- case io:scan_erl_form(St#epp.file, '', St#epp.location) of
+ case io:scan_erl_form(St#epp.file, '', St#epp.location, [unicode]) of
{ok,[{'-',_Lh},{atom,_Li,ifdef}|_Toks],Cl} ->
skip_toks(From, St#epp{location=Cl}, [ifdef,I|Sis]);
{ok,[{'-',_Lh},{atom,_Li,ifndef}|_Toks],Cl} ->
@@ -1094,6 +1270,7 @@ expand_arg([], Ts, L, Rest, Bs) ->
%%% tokenized would yield the token list Ts.
%% erl_scan:token_info(T, text) is not backward compatible with this.
+%% Note that escaped characters will be replaced by themselves.
token_src({dot, _}) ->
".";
token_src({X, _}) when is_atom(X) ->
@@ -1101,16 +1278,16 @@ token_src({X, _}) when is_atom(X) ->
token_src({var, _, X}) ->
atom_to_list(X);
token_src({char,_,C}) ->
- io_lib:write_char(C);
+ io_lib:write_unicode_char(C);
token_src({string, _, X}) ->
- lists:flatten(io_lib:format("~p", [X]));
+ io_lib:write_unicode_string(X);
token_src({_, _, X}) ->
- lists:flatten(io_lib:format("~w", [X])).
+ io_lib:format("~w", [X]).
stringify1([]) ->
[];
stringify1([T | Tokens]) ->
- [io_lib:format(" ~s", [token_src(T)]) | stringify1(Tokens)].
+ [io_lib:format(" ~ts", [token_src(T)]) | stringify1(Tokens)].
stringify(Ts, L) ->
[$\s | S] = lists:flatten(stringify1(Ts)),
diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl
index 95ba6b1096..8471ae6b64 100644
--- a/lib/stdlib/src/erl_eval.erl
+++ b/lib/stdlib/src/erl_eval.erl
@@ -227,13 +227,6 @@ expr({bc,_,E,Qs}, Bs, Lf, Ef, RBs) ->
expr({tuple,_,Es}, Bs0, Lf, Ef, RBs) ->
{Vs,Bs} = expr_list(Es, Bs0, Lf, Ef),
ret_expr(list_to_tuple(Vs), Bs, RBs);
-expr({record_field,_,_,_}=Mod, Bs, _Lf, _Ef, RBs) ->
- case expand_module_name(Mod, Bs) of
- {atom,_,A} ->
- ret_expr(A, Bs, RBs); %% This is the "x.y" syntax
- _ ->
- erlang:raise(error, {badexpr, '.'}, stacktrace())
- end;
expr({record_field,_,_,Name,_}, _Bs, _Lf, _Ef, _RBs) ->
erlang:raise(error, {undef_record,Name}, stacktrace());
expr({record_index,_,Name,_}, _Bs, _Lf, _Ef, _RBs) ->
@@ -332,8 +325,7 @@ expr({call,L1,{remote,L2,{record_field,_,{atom,_,''},{atom,_,qlc}=Mod},
Bs, Lf, Ef, RBs) when length(As0) =< 1 ->
expr({call,L1,{remote,L2,Mod,Func},As}, Bs, Lf, Ef, RBs);
expr({call,_,{remote,_,Mod,Func},As0}, Bs0, Lf, Ef, RBs) ->
- Mod1 = expand_module_name(Mod, Bs0),
- {value,M,Bs1} = expr(Mod1, Bs0, Lf, Ef, none),
+ {value,M,Bs1} = expr(Mod, Bs0, Lf, Ef, none),
{value,F,Bs2} = expr(Func, Bs0, Lf, Ef, none),
{As,Bs3} = expr_list(As0, merge_bindings(Bs1, Bs2), Lf, Ef),
%% M could be a parameterized module (not an atom).
@@ -1210,41 +1202,6 @@ ret_expr(_Old, New) ->
line(Expr) -> element(2, Expr).
-%% In syntax trees, module/package names are atoms or lists of atoms.
-
-expand_module_name({atom,L,A} = M, Bs) ->
- case binding({module,A}, Bs) of
- {value, A1} ->
- {atom,L,A1};
- unbound ->
- case packages:is_segmented(A) of
- true ->
- M;
- false ->
-%%% P = case binding({module,'$package'}, Bs) of
-%%% {value, P1} -> P1;
-%%% unbound -> ""
-%%% end,
-%%% A1 = list_to_atom(packages:concat(P, A)),
-%%% {atom,L,list_to_atom(A1)}
- {atom,L,A}
- end
- end;
-expand_module_name(M, _) ->
- case erl_parse:package_segments(M) of
- error ->
- M;
- M1 ->
- L = element(2,M),
- Mod = packages:concat(M1),
- case packages:is_valid(Mod) of
- true ->
- {atom,L,list_to_atom(Mod)};
- false ->
- erlang:raise(error, {bad_module_name, Mod}, stacktrace())
- end
- end.
-
%% {?MODULE,expr,3} is still the stacktrace, despite the
%% fact that expr() now takes two, three or four arguments...
stacktrace() -> [{?MODULE,expr,3}].
diff --git a/lib/stdlib/src/erl_expand_records.erl b/lib/stdlib/src/erl_expand_records.erl
index 9759a8f001..d05f630d8e 100644
--- a/lib/stdlib/src/erl_expand_records.erl
+++ b/lib/stdlib/src/erl_expand_records.erl
@@ -135,8 +135,6 @@ pattern({tuple,Line,Ps}, St0) ->
%%pattern({struct,Line,Tag,Ps}, St0) ->
%% {TPs,TPsvs,St1} = pattern_list(Ps, St0),
%% {{struct,Line,Tag,TPs},TPsvs,St1};
-pattern({record_field,_,_,_}=M, St) ->
- {M,St}; % must be a package name
pattern({record_index,Line,Name,Field}, St) ->
{index_expr(Line, Field, Name, record_fields(Name, St)),St};
pattern({record,Line,Name,Pfs}, St0) ->
@@ -306,8 +304,6 @@ expr({tuple,Line,Es0}, St0) ->
%%expr({struct,Line,Tag,Es0}, Vs, St0) ->
%% {Es1,Esvs,Esus,St1} = expr_list(Es0, Vs, St0),
%% {{struct,Line,Tag,Es1},Esvs,Esus,St1};
-expr({record_field,_,_,_}=M, St) ->
- {M,St}; % must be a package name
expr({record_index,Line,Name,F}, St) ->
I = index_expr(Line, F, Name, record_fields(Name, St)),
expr(I, St);
@@ -375,15 +371,9 @@ expr({call,Line,{atom,_La,N}=Atom,As0}, St0) ->
end
end
end;
-expr({call,Line,{record_field,_,_,_}=M,As0}, St0) ->
- {As,St1} = expr_list(As0, St0),
- {{call,Line,M,As},St1};
expr({call,Line,{remote,Lr,M,F},As0}, St0) ->
{[M1,F1 | As1],St1} = expr_list([M,F | As0], St0),
{{call,Line,{remote,Lr,M1,F1},As1},St1};
-expr({call,Line,{tuple,Lt,[{atom,_,_}=M,{atom,_,_}=F]},As0}, St0) ->
- {As,St1} = expr_list(As0, St0),
- {{call,Line,{tuple,Lt,[M,F]},As},St1};
expr({call,Line,F,As0}, St0) ->
{[Fun1 | As1],St1} = expr_list([F | As0], St0),
{{call,Line,Fun1,As1},St1};
diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index 1e5f962375..9a01e85006 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -94,12 +94,9 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) ->
%% the other function collections contain {Function, Arity}.
-record(lint, {state=start :: 'start' | 'attribute' | 'function',
module=[], %Module
- package="", %Module package
- extends=[], %Extends
behaviour=[], %Behaviour
exports=gb_sets:empty() :: gb_set(), %Exports
imports=[], %Imports
- mod_imports=dict:new() :: dict(), %Module Imports
compile=[], %Compile flags
records=dict:new() :: dict(), %Record definitions
locals=gb_sets:empty() :: gb_set(), %All defined functions (prescanned)
@@ -114,7 +111,6 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) ->
enabled_warnings=[], %All enabled warnings (ordset).
errors=[], %Current errors
warnings=[], %Current warnings
- global_vt=[], %The global VarTable
file = "" :: string(), %From last file attribute
recdef_top=false :: boolean(), %true in record initialisation
%outside any fun or lc
@@ -144,10 +140,8 @@ format_error({bad_module_name, M}) ->
io_lib:format("bad module name '~s'", [M]);
format_error(redefine_module) ->
"redefining module";
-format_error(redefine_extends) ->
- "redefining extends attribute";
-format_error(extends_self) ->
- "cannot extend from self";
+format_error(pmod_unsupported) ->
+ "parameterized modules are no longer supported";
%% format_error({redefine_mod_import, M, P}) ->
%% io_lib:format("module '~s' already imported from package '~s'", [M, P]);
@@ -168,10 +162,6 @@ format_error({bad_inline,{F,A}}) ->
io_lib:format("inlined function ~w/~w undefined", [F,A]);
format_error({invalid_deprecated,D}) ->
io_lib:format("badly formed deprecated attribute ~w", [D]);
-format_error(invalid_extends) ->
- "badly formed extends attribute";
-format_error(define_instance) ->
- "defining instance function not allowed in abstract module";
format_error({bad_deprecated,{F,A}}) ->
io_lib:format("deprecated function ~w/~w undefined or not exported", [F,A]);
format_error({bad_nowarn_unused_function,{F,A}}) ->
@@ -539,7 +529,6 @@ start(File, Opts) ->
end,
#lint{state = start,
exports = gb_sets:from_list([{module_info,0},{module_info,1}]),
- mod_imports = dict:from_list([{erlang,erlang}]),
compile = Opts,
%% Internal pseudo-functions must appear as defined/reached.
defined = gb_sets:from_list(pseudolocals()),
@@ -625,8 +614,6 @@ forms(Forms0, St0) ->
pre_scan([{function,_L,new,_A,_Cs} | Fs], St) ->
pre_scan(Fs, St#lint{new=true});
-pre_scan([{attribute,_L,extends,M} | Fs], St) when is_atom(M) ->
- pre_scan(Fs, St#lint{extends=true});
pre_scan([{attribute,L,compile,C} | Fs], St) ->
case is_warn_enabled(export_all, St) andalso
member(export_all, lists:flatten([C])) of
@@ -681,51 +668,15 @@ form(Form, #lint{state=State}=St) ->
%% start_state(Form, State) -> State'
-start_state({attribute,L,module,{M,Ps}}, St) ->
- St1 = set_module(M, L, St),
- Arity = length(Ps),
- Ps1 = if is_atom(St1#lint.extends) ->
- ['BASE', 'THIS' | Ps];
- true ->
- ['THIS' | Ps]
- end,
- Vt = orddict:from_list([{V, {bound, used, []}} || V <- Ps1]),
- St2 = add_instance(Arity, St1),
- St3 = ensure_new(Arity, St2),
- St3#lint{state=attribute, extends=[], global_vt=Vt};
-start_state({attribute,L,module,M}, St) ->
- St1 = set_module(M, L, St),
- St1#lint{state=attribute, extends=[]};
+start_state({attribute,Line,module,{_,_}}=Form, St0) ->
+ St1 = add_error(Line, pmod_unsupported, St0),
+ attribute_state(Form, St1#lint{state=attribute});
+start_state({attribute,_,module,M}, St0) ->
+ St1 = St0#lint{module=M},
+ St1#lint{state=attribute};
start_state(Form, St) ->
St1 = add_error(element(2, Form), undefined_module, St),
- attribute_state(Form, St1#lint{state=attribute, extends=[]}).
-
-set_module(M, L, St) ->
- M1 = package_to_string(M),
- case packages:is_valid(M1) of
- true ->
- St#lint{module=list_to_atom(M1),
- package=packages:strip_last(M1)};
- false ->
- add_error(L, {bad_module_name, M1}, St)
- end.
-
-ensure_new(Arity, St) ->
- case St#lint.new of
- true ->
- St;
- false ->
- add_func(new, Arity, St)
- end.
-
-add_instance(Arity, St) ->
- A = Arity + (if is_atom(St#lint.extends) -> 1; true -> 0 end),
- add_func(instance, A, St).
-
-add_func(Name, Arity, St) ->
- F = {Name, Arity},
- St#lint{exports = gb_sets:add_element(F, St#lint.exports),
- defined = gb_sets:add_element(F, St#lint.defined)}.
+ attribute_state(Form, St1#lint{state=attribute}).
%% attribute_state(Form, State) ->
%% State'
@@ -734,15 +685,6 @@ attribute_state({attribute,_L,module,_M}, #lint{module=[]}=St) ->
St;
attribute_state({attribute,L,module,_M}, St) ->
add_error(L, redefine_module, St);
-attribute_state({attribute,L,extends,M}, #lint{module=M}=St) when is_atom(M) ->
- add_error(L, extends_self, St);
-attribute_state({attribute,_L,extends,M}, #lint{extends=[]}=St)
- when is_atom(M) ->
- St#lint{extends=M};
-attribute_state({attribute,L,extends,M}, St) when is_atom(M) ->
- add_error(L, redefine_extends, St);
-attribute_state({attribute,L,extends,_M}, St) ->
- add_error(L, invalid_extends, St);
attribute_state({attribute,L,export,Es}, St) ->
export(L, Es, St);
attribute_state({attribute,L,export_type,Es}, St) ->
@@ -1007,9 +949,9 @@ check_imports(Forms, St0) ->
true ->
Usage = St0#lint.usage,
Unused = ordsets:subtract(St0#lint.imports, Usage#usage.imported),
- Imports = [{{FA,list_to_atom(package_to_string(Mod))},L}
- || {attribute,L,import,{Mod,Fs}} <- Forms,
- FA <- lists:usort(Fs)],
+ Imports = [{{FA,Mod},L} ||
+ {attribute,L,import,{Mod,Fs}} <- Forms,
+ FA <- lists:usort(Fs)],
Bad = [{FM,L} || FM <- Unused, {FM2,L} <- Imports, FM =:= FM2],
func_line_warning(unused_import, Bad, St0)
end.
@@ -1222,73 +1164,46 @@ export_type(Line, ETs, #lint{usage = Usage, exp_types = ETs0} = St0) ->
-spec import(line(), import(), lint_state()) -> lint_state().
import(Line, {Mod,Fs}, St) ->
- Mod1 = package_to_string(Mod),
- case packages:is_valid(Mod1) of
- true ->
- Mfs = ordsets:from_list(Fs),
- case check_imports(Line, Mfs, St#lint.imports) of
- [] ->
- St#lint{imports=add_imports(list_to_atom(Mod1), Mfs,
- St#lint.imports)};
- Efs ->
- {Err, St1} =
- foldl(fun ({bif,{F,A},_}, {Err,St0}) ->
- %% BifClash - import directive
- Warn = is_warn_enabled(bif_clash, St0)
- and (not bif_clash_specifically_disabled(St0,{F,A})),
- AutoImpSup = is_autoimport_suppressed(St0#lint.no_auto,{F,A}),
- OldBif = erl_internal:old_bif(F,A),
- {Err,if
- Warn and (not AutoImpSup) and OldBif ->
- add_error
- (Line,
- {redefine_old_bif_import, {F,A}},
- St0);
- Warn and (not AutoImpSup) ->
- add_warning
- (Line,
- {redefine_bif_import, {F,A}},
- St0);
- true ->
- St0
- end};
- (Ef, {_Err,St0}) ->
- {true,add_error(Line,
- {redefine_import,Ef},
- St0)}
- end,
- {false,St}, Efs),
- if
- not Err ->
- St1#lint{imports=
- add_imports(list_to_atom(Mod1), Mfs,
+ Mfs = ordsets:from_list(Fs),
+ case check_imports(Line, Mfs, St#lint.imports) of
+ [] ->
+ St#lint{imports=add_imports(Mod, Mfs,
+ St#lint.imports)};
+ Efs ->
+ {Err, St1} =
+ foldl(fun ({bif,{F,A},_}, {Err,St0}) ->
+ %% BifClash - import directive
+ Warn = is_warn_enabled(bif_clash, St0) andalso
+ (not bif_clash_specifically_disabled(St0,{F,A})),
+ AutoImpSup = is_autoimport_suppressed(St0#lint.no_auto,{F,A}),
+ OldBif = erl_internal:old_bif(F,A),
+ {Err,if
+ Warn and (not AutoImpSup) and OldBif ->
+ add_error
+ (Line,
+ {redefine_old_bif_import, {F,A}},
+ St0);
+ Warn and (not AutoImpSup) ->
+ add_warning
+ (Line,
+ {redefine_bif_import, {F,A}},
+ St0);
+ true ->
+ St0
+ end};
+ (Ef, {_Err,St0}) ->
+ {true,add_error(Line,
+ {redefine_import,Ef},
+ St0)}
+ end,
+ {false,St}, Efs),
+ if
+ not Err ->
+ St1#lint{imports=add_imports(Mod, Mfs,
St#lint.imports)};
- true ->
- St1
- end
- end;
- false ->
- add_error(Line, {bad_module_name, Mod1}, St)
- end;
-import(Line, Mod, St) ->
- Mod1 = package_to_string(Mod),
- case packages:is_valid(Mod1) of
- true ->
- Key = list_to_atom(packages:last(Mod1)),
- Imps = St#lint.mod_imports,
-%%% case dict:is_key(Key, Imps) of
-%%% true ->
-%%% M = packages:last(Mod1),
-%%% P = packages:strip_last(Mod1),
-%%% add_error(Line, {redefine_mod_import, M, P}, St);
-%%% false ->
-%%% St#lint{mod_imports =
-%%% dict:store(Key, list_to_atom(Mod1), Imps)}
-%%% end;
- St#lint{mod_imports = dict:store(Key, list_to_atom(Mod1),
- Imps)};
- false ->
- add_error(Line, {bad_module_name, Mod1}, St)
+ true ->
+ St1
+ end
end.
check_imports(_Line, Fs, Is) ->
@@ -1362,11 +1277,9 @@ call_function(Line, F, A, #lint{usage=Usage0,called=Cd,func=Func}=St) ->
%% function(Line, Name, Arity, Clauses, State) -> State.
-function(Line, instance, _Arity, _Cs, St) when St#lint.global_vt =/= [] ->
- add_error(Line, define_instance, St);
function(Line, Name, Arity, Cs, St0) ->
St1 = define_function(Line, Name, Arity, St0#lint{func={Name,Arity}}),
- clauses(Cs, St1#lint.global_vt, St1).
+ clauses(Cs, St1).
-spec define_function(line(), atom(), arity(), lint_state()) -> lint_state().
@@ -1389,15 +1302,16 @@ function_check_max_args(Line, Arity, St) when Arity > ?MAX_ARGUMENTS ->
add_error(Line, {too_many_arguments,Arity}, St);
function_check_max_args(_, _, St) -> St.
-%% clauses([Clause], VarTable, State) -> {VarTable, State}.
+%% clauses([Clause], State) -> {VarTable, State}.
-clauses(Cs, Vt, St) ->
+clauses(Cs, St) ->
foldl(fun (C, St0) ->
- {_,St1} = clause(C, Vt, St0),
+ {_,St1} = clause(C, St0),
St1
end, St, Cs).
-clause({clause,_Line,H,G,B}, Vt0, St0) ->
+clause({clause,_Line,H,G,B}, St0) ->
+ Vt0 = [],
{Hvt,Binvt,St1} = head(H, Vt0, St0),
%% Cannot ignore BinVt since "binsize variables" may have been used.
Vt1 = vtupdate(Hvt, vtupdate(Binvt, Vt0)),
@@ -1463,13 +1377,6 @@ pattern({record_index,Line,Name,Field}, _Vt, _Old, _Bvt, St) ->
pattern_field(Field, Name, Dfs, St1)
end),
{Vt1,[],St1};
-pattern({record_field,Line,_,_}=M, _Vt, _Old, _Bvt, St0) ->
- case expand_package(M, St0) of
- {error, St1} ->
- {[],[],add_error(Line, illegal_expr, St1)};
- {_, St1} ->
- {[],[],St1}
- end;
pattern({record,Line,Name,Pfs}, Vt, Old, Bvt, St) ->
case dict:find(Name, St#lint.records) of
{ok,{_Line,Fields}} ->
@@ -1851,13 +1758,6 @@ gexpr({tuple,_Line,Es}, Vt, St) ->
gexpr({record_index,Line,Name,Field}, _Vt, St) ->
check_record(Line, Name, St,
fun (Dfs, St1) -> record_field(Field, Name, Dfs, St1) end );
-gexpr({record_field,Line,_,_}=M, _Vt, St0) ->
- case expand_package(M, St0) of
- {error, St1} ->
- {[],add_error(Line, illegal_expr, St1)};
- {_, St1} ->
- {[], St1}
- end;
gexpr({record_field,Line,Rec,Name,Field}, Vt, St0) ->
{Rvt,St1} = gexpr(Rec, Vt, St0),
{Fvt,St2} = check_record(Line, Name, St1,
@@ -1996,8 +1896,6 @@ is_gexpr({tuple,_L,Es}, RDs) -> is_gexpr_list(Es, RDs);
%% is_gexpr_list(Es, RDs);
is_gexpr({record_index,_L,_Name,Field}, RDs) ->
is_gexpr(Field, RDs);
-is_gexpr({record_field,_L,_,_}=M, _RDs) ->
- erl_parse:package_segments(M) =/= error;
is_gexpr({record_field,_L,Rec,_Name,Field}, RDs) ->
is_gexpr_list([Rec,Field], RDs);
is_gexpr({record,L,Name,Inits}, RDs) ->
@@ -2086,13 +1984,6 @@ expr({record,Line,Name,Inits}, Vt, St) ->
fun (Dfs, St1) ->
init_fields(Inits, Line, Name, Dfs, Vt, St1)
end);
-expr({record_field,Line,_,_}=M, _Vt, St0) ->
- case expand_package(M, St0) of
- {error, St1} ->
- {[],add_error(Line, illegal_expr, St1)};
- {_, St1} ->
- {[], St1}
- end;
expr({record_field,Line,Rec,Name,Field}, Vt, St0) ->
{Rvt,St1} = record_expr(Line, Rec, Vt, St0),
{Fvt,St2} = check_record(Line, Name, St1,
@@ -2163,20 +2054,14 @@ expr({call,Line,{remote,_Lr,{atom,_Lm,erlang},{atom,Lf,is_record}},[E,A]},
expr({call,Line,{atom,Lf,is_record},[E,A]}, Vt, St0);
expr({call,L,{tuple,Lt,[{atom,Lm,erlang},{atom,Lf,is_record}]},As}, Vt, St) ->
expr({call,L,{remote,Lt,{atom,Lm,erlang},{atom,Lf,is_record}},As}, Vt, St);
+expr({call,Line,{remote,_Lr,{atom,_Lm,M},{atom,Lf,F}},As}, Vt, St0) ->
+ St1 = keyword_warning(Lf, F, St0),
+ St2 = check_remote_function(Line, M, F, As, St1),
+ expr_list(As, Vt, St2);
expr({call,Line,{remote,_Lr,M,F},As}, Vt, St0) ->
- case expand_package(M, St0) of
- {error, _} ->
- expr_list([M,F|As], Vt, St0);
- {{atom,_La,M1}, St1} ->
- case F of
- {atom,Lf,F1} ->
- St2 = keyword_warning(Lf, F1, St1),
- St3 = check_remote_function(Line, M1, F1, As, St2),
- expr_list(As, Vt, St3);
- _ ->
- expr_list([F|As], Vt, St1)
- end
- end;
+ St1 = keyword_warning(Line, M, St0),
+ St2 = keyword_warning(Line, F, St1),
+ expr_list([M,F|As], Vt, St2);
expr({call,Line,{atom,La,F},As}, Vt, St0) ->
St1 = keyword_warning(La, F, St0),
{Asvt,St2} = expr_list(As, Vt, St1),
@@ -2232,13 +2117,6 @@ expr({call,Line,{atom,La,F},As}, Vt, St0) ->
end
end}
end;
-expr({call,Line,{record_field,_,_,_}=F,As}, Vt, St0) ->
- case expand_package(F, St0) of
- {error, _} ->
- expr_list([F|As], Vt, St0);
- {A, St1} ->
- expr({call,Line,A,As}, Vt, St1)
- end;
expr({call,Line,F,As}, Vt, St0) ->
St = warn_invalid_call(Line,F,St0),
expr_list([F|As], Vt, St); %They see the same variables
@@ -3618,6 +3496,10 @@ extract_sequence(4, [$t, $c | Fmt], Need) ->
extract_sequence(5, [$c|Fmt], Need);
extract_sequence(4, [$t, $s | Fmt], Need) ->
extract_sequence(5, [$s|Fmt], Need);
+extract_sequence(4, [$t, $p | Fmt], Need) ->
+ extract_sequence(5, [$p|Fmt], Need);
+extract_sequence(4, [$t, $P | Fmt], Need) ->
+ extract_sequence(5, [$P|Fmt], Need);
extract_sequence(4, [$t, C | _Fmt], _Need) ->
{error,"invalid control ~t" ++ [C]};
extract_sequence(4, Fmt, Need) ->
@@ -3654,49 +3536,6 @@ control_type($n, Need) -> Need;
control_type($i, Need) -> [term|Need];
control_type(_C, _Need) -> error.
-%% In syntax trees, module/package names are atoms or lists of atoms.
-
-package_to_string(A) when is_atom(A) -> atom_to_list(A);
-package_to_string(L) when is_list(L) -> packages:concat(L).
-
-expand_package({atom,L,A} = M, St0) ->
- St1 = keyword_warning(L, A, St0),
- case dict:find(A, St1#lint.mod_imports) of
- {ok, A1} ->
- {{atom,L,A1}, St1};
- error ->
- Name = atom_to_list(A),
- case packages:is_valid(Name) of
- true ->
- case packages:is_segmented(Name) of
- true ->
- {M, St1};
- false ->
- M1 = packages:concat(St1#lint.package,
- Name),
- {{atom,L,list_to_atom(M1)}, St1}
- end;
- false ->
- St2 = add_error(L, {bad_module_name, Name}, St1),
- {error, St2}
- end
- end;
-expand_package(M, St0) ->
- L = element(2, M),
- case erl_parse:package_segments(M) of
- error ->
- {error, St0};
- M1 ->
- Name = package_to_string(M1),
- case packages:is_valid(Name) of
- true ->
- {{atom,L,list_to_atom(Name)}, St0};
- false ->
- St1 = add_error(L, {bad_module_name, Name}, St0),
- {error, St1}
- end
- end.
-
%% Prebuild set of local functions (to override auto-import)
local_functions(Forms) ->
diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl
index 928c10f7f2..002abc11e8 100644
--- a/lib/stdlib/src/erl_parse.yrl
+++ b/lib/stdlib/src/erl_parse.yrl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -26,7 +26,7 @@ attribute attr_val
function function_clauses function_clause
clause_args clause_guard clause_body
expr expr_100 expr_150 expr_160 expr_200 expr_300 expr_400 expr_500
-expr_600 expr_700 expr_800 expr_900
+expr_600 expr_700 expr_800
expr_max
list tail
list_comprehension lc_expr lc_exprs
@@ -253,15 +253,9 @@ expr_700 -> function_call : '$1'.
expr_700 -> record_expr : '$1'.
expr_700 -> expr_800 : '$1'.
-expr_800 -> expr_900 ':' expr_max :
+expr_800 -> expr_max ':' expr_max :
{remote,?line('$2'),'$1','$3'}.
-expr_800 -> expr_900 : '$1'.
-
-expr_900 -> '.' atom :
- {record_field,?line('$1'),{atom,?line('$1'),''},'$2'}.
-expr_900 -> expr_900 '.' atom :
- {record_field,?line('$2'),'$1','$3'}.
-expr_900 -> expr_max : '$1'.
+expr_800 -> expr_max : '$1'.
expr_max -> var : '$1'.
expr_max -> atomic : '$1'.
@@ -510,7 +504,7 @@ Erlang code.
-export([parse_form/1,parse_exprs/1,parse_term/1]).
-export([normalise/1,abstract/1,tokens/1,tokens/2]).
--export([abstract/2, package_segments/1]).
+-export([abstract/2]).
-export([inop_prec/1,preop_prec/1,func_prec/0,max_prec/0]).
-export([set_line/2,get_attribute/2,get_attributes/1]).
@@ -679,20 +673,6 @@ build_attribute({atom,La,module}, Val) ->
{attribute,La,module,Module};
[{atom,_Lm,Module},ExpList] ->
{attribute,La,module,{Module,var_list(ExpList)}};
- [Name] ->
- case package_segments(Name) of
- error ->
- error_bad_decl(La, module);
- Module ->
- {attribute,La,module,Module}
- end;
- [Name,ExpList] ->
- case package_segments(Name) of
- error ->
- error_bad_decl(La, module);
- Module ->
- {attribute,La,module,{Module,var_list(ExpList)}}
- end;
_Other ->
error_bad_decl(La, module)
end;
@@ -704,22 +684,8 @@ build_attribute({atom,La,export}, Val) ->
end;
build_attribute({atom,La,import}, Val) ->
case Val of
- [Name] ->
- case package_segments(Name) of
- error ->
- error_bad_decl(La, import);
- Module ->
- {attribute,La,import,Module}
- end;
[{atom,_Lm,Mod},ImpList] ->
{attribute,La,import,{Mod,farity_list(ImpList)}};
- [Name, ImpList] ->
- case package_segments(Name) of
- error ->
- error_bad_decl(La, import);
- Module ->
- {attribute,La,import,{Module,farity_list(ImpList)}}
- end;
_Other -> error_bad_decl(La, import)
end;
build_attribute({atom,La,record}, Val) ->
@@ -820,18 +786,6 @@ term(Expr) ->
catch _:_R -> ret_err(?line(Expr), "bad attribute")
end.
-package_segments(Name) ->
- package_segments(Name, [], []).
-
-package_segments({record_field, _, F1, F2}, Fs, As) ->
- package_segments(F1, [F2 | Fs], As);
-package_segments({atom, _, A}, [F | Fs], As) ->
- package_segments(F, Fs, [A | As]);
-package_segments({atom, _, A}, [], As) ->
- lists:reverse([A | As]);
-package_segments(_, _, _) ->
- error.
-
%% build_function([Clause]) -> {function,Line,Name,Arity,[Clause]}
build_function(Cs) ->
@@ -900,12 +854,6 @@ normalise({cons,_,Head,Tail}) ->
[normalise(Head)|normalise(Tail)];
normalise({tuple,_,Args}) ->
list_to_tuple(normalise_list(Args));
-%% Atom dot-notation, as in 'foo.bar.baz'
-normalise({record_field,_,_,_}=A) ->
- case package_segments(A) of
- error -> erlang:error({badarg, A});
- As -> list_to_atom(packages:concat(As))
- end;
%% Special case for unary +/-.
normalise({op,_,'+',{char,_,I}}) -> I;
normalise({op,_,'+',{integer,_,I}}) -> I;
@@ -923,73 +871,77 @@ normalise_list([]) ->
-spec abstract(Data) -> AbsTerm when
Data :: term(),
AbsTerm :: abstract_expr().
-abstract(T) when is_integer(T) -> {integer,0,T};
-abstract(T) when is_float(T) -> {float,0,T};
-abstract(T) when is_atom(T) -> {atom,0,T};
-abstract([]) -> {nil,0};
-abstract(B) when is_bitstring(B) ->
- {bin, 0, [abstract_byte(Byte, 0) || Byte <- bitstring_to_list(B)]};
-abstract([C|T]) when is_integer(C), 0 =< C, C < 256 ->
- abstract_string(T, [C]);
-abstract([H|T]) ->
- {cons,0,abstract(H),abstract(T)};
-abstract(Tuple) when is_tuple(Tuple) ->
- {tuple,0,abstract_list(tuple_to_list(Tuple))}.
-
-abstract_string([C|T], String) when is_integer(C), 0 =< C, C < 256 ->
- abstract_string(T, [C|String]);
-abstract_string([], String) ->
- {string, 0, lists:reverse(String)};
-abstract_string(T, String) ->
- not_string(String, abstract(T)).
-
-not_string([C|T], Result) ->
- not_string(T, {cons, 0, {integer, 0, C}, Result});
-not_string([], Result) ->
+abstract(T) ->
+ abstract(T, 0, epp:default_encoding()).
+
+%%% abstract/2 takes line and encoding options
+-spec abstract(Data, Options) -> AbsTerm when
+ Data :: term(),
+ Options :: Line | [Option],
+ Option :: {line, Line} | {encoding, Encoding},
+ Encoding :: latin1 | unicode | utf8,
+ Line :: erl_scan:line(),
+ AbsTerm :: abstract_expr().
+
+abstract(T, Line) when is_integer(Line) ->
+ abstract(T, Line, epp:default_encoding());
+abstract(T, Options) when is_list(Options) ->
+ Line = proplists:get_value(line, Options, 0),
+ Encoding = proplists:get_value(encoding, Options,epp:default_encoding()),
+ abstract(T, Line, Encoding).
+
+-define(UNICODE(C),
+ (C >= 0 andalso C < 16#D800 orelse
+ C > 16#DFFF andalso C < 16#FFFE orelse
+ C > 16#FFFF andalso C =< 16#10FFFF)).
+
+abstract(T, L, _E) when is_integer(T) -> {integer,L,T};
+abstract(T, L, _E) when is_float(T) -> {float,L,T};
+abstract(T, L, _E) when is_atom(T) -> {atom,L,T};
+abstract([], L, _E) -> {nil,L};
+abstract(B, L, _E) when is_bitstring(B) ->
+ {bin, L, [abstract_byte(Byte, L) || Byte <- bitstring_to_list(B)]};
+abstract([C|T], L, unicode=E) when ?UNICODE(C) ->
+ abstract_unicode_string(T, [C], L, E);
+abstract([C|T], L, utf8=E) when ?UNICODE(C) ->
+ abstract_unicode_string(T, [C], L, E);
+abstract([C|T], L, latin1=E) when is_integer(C), 0 =< C, C < 256 ->
+ abstract_string(T, [C], L, E);
+abstract([H|T], L, E) ->
+ {cons,L,abstract(H, L, E),abstract(T, L, E)};
+abstract(Tuple, L, E) when is_tuple(Tuple) ->
+ {tuple,L,abstract_list(tuple_to_list(Tuple), L, E)}.
+
+abstract_string([C|T], String, L, E) when is_integer(C), 0 =< C, C < 256 ->
+ abstract_string(T, [C|String], L, E);
+abstract_string([], String, L, _E) ->
+ {string, L, lists:reverse(String)};
+abstract_string(T, String, L, E) ->
+ not_string(String, abstract(T, L, E), L, E).
+
+abstract_unicode_string([C|T], String, L, E) when ?UNICODE(C) ->
+ abstract_unicode_string(T, [C|String], L, E);
+abstract_unicode_string([], String, L, _E) ->
+ {string, L, lists:reverse(String)};
+abstract_unicode_string(T, String, L, E) ->
+ not_string(String, abstract(T, L, E), L, E).
+
+not_string([C|T], Result, L, E) ->
+ not_string(T, {cons, L, {integer, L, C}, Result}, L, E);
+not_string([], Result, _L, _E) ->
Result.
-abstract_list([H|T]) ->
- [abstract(H)|abstract_list(T)];
-abstract_list([]) ->
+abstract_list([H|T], L, E) ->
+ [abstract(H, L, E)|abstract_list(T, L, E)];
+abstract_list([], _L, _E) ->
[].
-abstract_byte(Byte, Line) when is_integer(Byte) ->
- {bin_element, Line, {integer, Line, Byte}, default, default};
-abstract_byte(Bits, Line) ->
+abstract_byte(Byte, L) when is_integer(Byte) ->
+ {bin_element, L, {integer, L, Byte}, default, default};
+abstract_byte(Bits, L) ->
Sz = bit_size(Bits),
<<Val:Sz>> = Bits,
- {bin_element, Line, {integer, Line, Val}, {integer, Line, Sz}, default}.
-
-%%% abstract/2 keeps the line number
-abstract(T, Line) when is_integer(T) -> {integer,Line,T};
-abstract(T, Line) when is_float(T) -> {float,Line,T};
-abstract(T, Line) when is_atom(T) -> {atom,Line,T};
-abstract([], Line) -> {nil,Line};
-abstract(B, Line) when is_bitstring(B) ->
- {bin, Line, [abstract_byte(Byte, Line) || Byte <- bitstring_to_list(B)]};
-abstract([C|T], Line) when is_integer(C), 0 =< C, C < 256 ->
- abstract_string(T, [C], Line);
-abstract([H|T], Line) ->
- {cons,Line,abstract(H, Line),abstract(T, Line)};
-abstract(Tuple, Line) when is_tuple(Tuple) ->
- {tuple,Line,abstract_list(tuple_to_list(Tuple), Line)}.
-
-abstract_string([C|T], String, Line) when is_integer(C), 0 =< C, C < 256 ->
- abstract_string(T, [C|String], Line);
-abstract_string([], String, Line) ->
- {string, Line, lists:reverse(String)};
-abstract_string(T, String, Line) ->
- not_string(String, abstract(T, Line), Line).
-
-not_string([C|T], Result, Line) ->
- not_string(T, {cons, Line, {integer, Line, C}, Result}, Line);
-not_string([], Result, _Line) ->
- Result.
-
-abstract_list([H|T], Line) ->
- [abstract(H, Line)|abstract_list(T, Line)];
-abstract_list([], _Line) ->
- [].
+ {bin_element, L, {integer, L, Val}, {integer, L, Sz}, default}.
%% Generate a list of tokens representing the abstract term.
@@ -1079,9 +1031,9 @@ preop_prec('#') -> {700,800}.
func_prec() -> {800,700}.
--spec max_prec() -> 1000.
+-spec max_prec() -> 900.
-max_prec() -> 1000.
+max_prec() -> 900.
%%% [Experimental]. The parser just copies the attributes of the
%%% scanner tokens to the abstract format. This design decision has
diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl
index 6b5aa951cf..0383ce6839 100644
--- a/lib/stdlib/src/erl_pp.erl
+++ b/lib/stdlib/src/erl_pp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -26,7 +26,7 @@
guard/1,guard/2,exprs/1,exprs/2,exprs/3,expr/1,expr/2,expr/3,expr/4]).
-import(lists, [append/1,foldr/3,mapfoldl/3,reverse/1,reverse/2]).
--import(io_lib, [write/1,format/2,write_char/1,write_string/1]).
+-import(io_lib, [write/1,format/2]).
-import(erl_parse, [inop_prec/1,preop_prec/1,func_prec/0,max_prec/0]).
-define(MAXLINE, 72).
@@ -36,7 +36,15 @@
CurrentIndentation :: integer(),
CurrentPrecedence :: non_neg_integer(),
HookFunction :: hook_function()) ->
- io_lib:chars())).
+ io_lib:chars())).
+
+-type(option() :: {hook, hook_function()}
+ | {encoding, latin1 | unicode | utf8}).
+-type(options() :: hook_function() | [option()]).
+
+-record(pp, {string_fun, char_fun}).
+
+-record(options, {hook, encoding, opts}).
%%%
%%% Exported functions
@@ -48,12 +56,12 @@
form(Thing) ->
form(Thing, none).
--spec(form(Form, HookFunction) -> io_lib:chars() when
+-spec(form(Form, Options) -> io_lib:chars() when
Form :: erl_parse:abstract_form(),
- HookFunction :: hook_function()).
+ Options :: options()).
-form(Thing, Hook) ->
- frmt(lform(Thing, Hook)).
+form(Thing, Options) ->
+ frmt(lform(Thing, options(Options)), state(Options)).
-spec(attribute(Attribute) -> io_lib:chars() when
Attribute :: erl_parse:abstract_form()).
@@ -61,12 +69,12 @@ form(Thing, Hook) ->
attribute(Thing) ->
attribute(Thing, none).
--spec(attribute(Attribute, HookFunction) -> io_lib:chars() when
+-spec(attribute(Attribute, Options) -> io_lib:chars() when
Attribute :: erl_parse:abstract_form(),
- HookFunction :: hook_function()).
+ Options :: options()).
-attribute(Thing, Hook) ->
- frmt(lattribute(Thing, Hook)).
+attribute(Thing, Options) ->
+ frmt(lattribute(Thing, options(Options)), state(Options)).
-spec(function(Function) -> io_lib:chars() when
Function :: erl_parse:abstract_form()).
@@ -74,18 +82,18 @@ attribute(Thing, Hook) ->
function(F) ->
function(F, none).
--spec(function(Function, HookFunction) -> io_lib:chars() when
+-spec(function(Function, Options) -> io_lib:chars() when
Function :: erl_parse:abstract_form(),
- HookFunction :: hook_function()).
+ Options :: options()).
-function(F, Hook) ->
- frmt(lfunction(F, Hook)).
+function(F, Options) ->
+ frmt(lfunction(F, options(Options)), state(Options)).
rule(R) ->
rule(R, none).
-rule(R, Hook) ->
- frmt(lrule(R, Hook)).
+rule(R, Options) ->
+ frmt(lrule(R, options(Options)), state(Options)).
-spec(guard(Guard) -> io_lib:chars() when
Guard :: [erl_parse:abstract_expr()]).
@@ -93,12 +101,12 @@ rule(R, Hook) ->
guard(Gs) ->
guard(Gs, none).
--spec(guard(Guard, HookFunction) -> io_lib:chars() when
+-spec(guard(Guard, Options) -> io_lib:chars() when
Guard :: [erl_parse:abstract_expr()],
- HookFunction :: hook_function()).
+ Options :: options()).
-guard(Gs, Hook) ->
- frmt(lguard(Gs, Hook)).
+guard(Gs, Options) ->
+ frmt(lguard(Gs, options(Options)), state(Options)).
-spec(exprs(Expressions) -> io_lib:chars() when
Expressions :: [erl_parse:abstract_expr()]).
@@ -106,99 +114,129 @@ guard(Gs, Hook) ->
exprs(Es) ->
exprs(Es, 0, none).
--spec(exprs(Expressions, HookFunction) -> io_lib:chars() when
+-spec(exprs(Expressions, Options) -> io_lib:chars() when
Expressions :: [erl_parse:abstract_expr()],
- HookFunction :: hook_function()).
+ Options :: options()).
-exprs(Es, Hook) ->
- exprs(Es, 0, Hook).
+exprs(Es, Options) ->
+ exprs(Es, 0, Options).
--spec(exprs(Expressions, Indent, HookFunction) -> io_lib:chars() when
+-spec(exprs(Expressions, Indent, Options) -> io_lib:chars() when
Expressions :: [erl_parse:abstract_expr()],
Indent :: integer(),
- HookFunction :: hook_function()).
+ Options :: options()).
-exprs(Es, I, Hook) ->
- frmt({seq,[],[],[$,],lexprs(Es, Hook)}, I).
+exprs(Es, I, Options) ->
+ frmt({seq,[],[],[$,],lexprs(Es, options(Options))}, I, state(Options)).
-spec(expr(Expression) -> io_lib:chars() when
Expression :: erl_parse:abstract_expr()).
expr(E) ->
- frmt(lexpr(E, 0, none)).
+ frmt(lexpr(E, 0, options(none)), state(none)).
--spec(expr(Expression, HookFunction) -> io_lib:chars() when
+-spec(expr(Expression, Options) -> io_lib:chars() when
Expression :: erl_parse:abstract_expr(),
- HookFunction :: hook_function()).
+ Options :: options()).
-expr(E, Hook) ->
- frmt(lexpr(E, 0, Hook)).
+expr(E, Options) ->
+ frmt(lexpr(E, 0, options(Options)), state(Options)).
--spec(expr(Expression, Indent, HookFunction) -> io_lib:chars() when
+-spec(expr(Expression, Indent, Options) -> io_lib:chars() when
Expression :: erl_parse:abstract_expr(),
Indent :: integer(),
- HookFunction :: hook_function()).
+ Options :: options()).
-expr(E, I, Hook) ->
- frmt(lexpr(E, 0, Hook), I).
+expr(E, I, Options) ->
+ frmt(lexpr(E, 0, options(Options)), I, state(Options)).
--spec(expr(Expression, Indent, Precedence, HookFunction) -> io_lib:chars() when
+-spec(expr(Expression, Indent, Precedence, Options) -> io_lib:chars() when
Expression :: erl_parse:abstract_expr(),
Indent :: integer(),
Precedence :: non_neg_integer(),
- HookFunction :: hook_function()).
+ Options :: options()).
-expr(E, I, P, Hook) ->
- frmt(lexpr(E, P, Hook), I).
+expr(E, I, P, Options) ->
+ frmt(lexpr(E, P, options(Options)), I, state(Options)).
%%%
%%% Local functions
%%%
-lform({attribute,Line,Name,Arg}, Hook) ->
- lattribute({attribute,Line,Name,Arg}, Hook);
-lform({function,Line,Name,Arity,Clauses}, Hook) ->
- lfunction({function,Line,Name,Arity,Clauses}, Hook);
-lform({rule,Line,Name,Arity,Clauses}, Hook) ->
- lrule({rule,Line,Name,Arity,Clauses}, Hook);
+options(Options) when is_list(Options) ->
+ Hook = proplists:get_value(hook, Options, none),
+ Encoding = encoding(Options),
+ #options{hook = Hook, encoding = Encoding, opts = Options};
+options(Hook) ->
+ #options{hook = Hook, encoding = encoding([]), opts = Hook}.
+
+state(Options) when is_list(Options) ->
+ case encoding(Options) of
+ latin1 -> state();
+ unicode -> unicode_state()
+ end;
+state(_Hook) ->
+ state().
+
+state() ->
+ #pp{string_fun = fun io_lib:write_unicode_string_as_latin1/1,
+ char_fun = fun io_lib:write_unicode_char_as_latin1/1}.
+
+unicode_state() ->
+ #pp{string_fun = fun io_lib:write_unicode_string/1,
+ char_fun = fun io_lib:write_unicode_char/1}.
+
+encoding(Options) ->
+ case proplists:get_value(encoding, Options, epp:default_encoding()) of
+ latin1 -> latin1;
+ utf8 -> unicode;
+ unicode -> unicode
+ end.
+
+lform({attribute,Line,Name,Arg}, Opts) ->
+ lattribute({attribute,Line,Name,Arg}, Opts);
+lform({function,Line,Name,Arity,Clauses}, Opts) ->
+ lfunction({function,Line,Name,Arity,Clauses}, Opts);
+lform({rule,Line,Name,Arity,Clauses}, Opts) ->
+ lrule({rule,Line,Name,Arity,Clauses}, Opts);
%% These are specials to make it easier for the compiler.
-lform({error,E}, _Hook) ->
+lform({error,E}, _Opts) ->
leaf(format("~p\n", [{error,E}]));
-lform({warning,W}, _Hook) ->
+lform({warning,W}, _Opts) ->
leaf(format("~p\n", [{warning,W}]));
-lform({eof,_Line}, _Hook) ->
+lform({eof,_Line}, _Opts) ->
$\n.
-lattribute({attribute,_Line,type,Type}, Hook) ->
- [typeattr(type, Type, Hook),leaf(".\n")];
-lattribute({attribute,_Line,opaque,Type}, Hook) ->
- [typeattr(opaque, Type, Hook),leaf(".\n")];
-lattribute({attribute,_Line,spec,Arg}, _Hook) ->
+lattribute({attribute,_Line,type,Type}, Opts) ->
+ [typeattr(type, Type, Opts),leaf(".\n")];
+lattribute({attribute,_Line,opaque,Type}, Opts) ->
+ [typeattr(opaque, Type, Opts),leaf(".\n")];
+lattribute({attribute,_Line,spec,Arg}, _Opts) ->
[specattr(Arg),leaf(".\n")];
-lattribute({attribute,_Line,Name,Arg}, Hook) ->
- [lattribute(Name, Arg, Hook),leaf(".\n")].
+lattribute({attribute,_Line,Name,Arg}, Opts) ->
+ [lattribute(Name, Arg, Opts),leaf(".\n")].
-lattribute(module, {M,Vs}, _Hook) ->
+lattribute(module, {M,Vs}, _Opts) ->
attr("module",[{var,0,pname(M)},
foldr(fun(V, C) -> {cons,0,{var,0,V},C}
end, {nil,0}, Vs)]);
-lattribute(module, M, _Hook) ->
+lattribute(module, M, _Opts) ->
attr("module", [{var,0,pname(M)}]);
-lattribute(export, Falist, _Hook) ->
+lattribute(export, Falist, _Opts) ->
call({var,0,"-export"}, [falist(Falist)], 0, none);
-lattribute(import, Name, _Hook) when is_list(Name) ->
+lattribute(import, Name, _Opts) when is_list(Name) ->
attr("import", [{var,0,pname(Name)}]);
-lattribute(import, {From,Falist}, _Hook) ->
+lattribute(import, {From,Falist}, _Opts) ->
attr("import",[{var,0,pname(From)},falist(Falist)]);
-lattribute(file, {Name,Line}, _Hook) ->
+lattribute(file, {Name,Line}, _Opts) ->
attr("file", [{var,0,format("~p", [Name])},{integer,0,Line}]);
-lattribute(record, {Name,Is}, Hook) ->
+lattribute(record, {Name,Is}, Opts) ->
Nl = leaf(format("-record(~w,", [Name])),
- [{first,Nl,record_fields(Is, Hook)},$)];
-lattribute(Name, Arg, _Hook) ->
- attr(write(Name), [erl_parse:abstract(Arg)]).
+ [{first,Nl,record_fields(Is, Opts)},$)];
+lattribute(Name, Arg, #options{encoding = Encoding}) ->
+ attr(write(Name), [erl_parse:abstract(Arg, [{encoding,Encoding}])]).
-typeattr(Tag, {TypeName,Type,Args}, _Hook) ->
+typeattr(Tag, {TypeName,Type,Args}, _Opts) ->
{first,leaf("-"++atom_to_list(Tag)++" "),
typed(call({atom,0,TypeName}, Args, 0, none), Type)}.
@@ -293,7 +331,7 @@ guard_type(Before, Gs) ->
Gl = {list,[{step,'when',expr_list(Gs, [$,], fun constraint/2, none)}]},
{list,[{step,Before,Gl}]}.
-constraint({type,_Line,constraint,[Tag,As]}, _Hook) ->
+constraint({type,_Line,constraint,[Tag,As]}, _Opts) ->
simple_type(Tag, As).
fun_type(Before, {type,_,'fun',[FType,Ret]}) ->
@@ -333,231 +371,232 @@ falist([]) ->
falist([{Name,Arity}|Falist]) ->
{cons,0,{var,0,format("~w/~w", [Name,Arity])},falist(Falist)}.
-lfunction({function,_Line,Name,_Arity,Cs}, Hook) ->
- Cll = nl_clauses(fun (C, H) -> func_clause(Name, C, H) end, $;, Hook, Cs),
+lfunction({function,_Line,Name,_Arity,Cs}, Opts) ->
+ Cll = nl_clauses(fun (C, H) -> func_clause(Name, C, H) end, $;, Opts, Cs),
[Cll,leaf(".\n")].
-func_clause(Name, {clause,Line,Head,Guard,Body}, Hook) ->
- Hl = call({atom,Line,Name}, Head, 0, Hook),
- Gl = guard_when(Hl, Guard, Hook),
- Bl = body(Body, Hook),
+func_clause(Name, {clause,Line,Head,Guard,Body}, Opts) ->
+ Hl = call({atom,Line,Name}, Head, 0, Opts),
+ Gl = guard_when(Hl, Guard, Opts),
+ Bl = body(Body, Opts),
{step,Gl,Bl}.
-lrule({rule,_Line,Name,_Arity,Cs}, Hook) ->
- Cll = nl_clauses(fun (C, H) -> rule_clause(Name, C, H) end, $;, Hook, Cs),
+lrule({rule,_Line,Name,_Arity,Cs}, Opts) ->
+ Cll = nl_clauses(fun (C, H) -> rule_clause(Name, C, H) end, $;, Opts, Cs),
[Cll,leaf(".\n")].
-rule_clause(Name, {clause,Line,Head,Guard,Body}, Hook) ->
- Hl = call({atom,Line,Name}, Head, 0, Hook),
- Gl = guard_when(Hl, Guard, Hook, leaf(" :-")),
- Bl = rule_body(Body, Hook),
+rule_clause(Name, {clause,Line,Head,Guard,Body}, Opts) ->
+ Hl = call({atom,Line,Name}, Head, 0, Opts),
+ Gl = guard_when(Hl, Guard, Opts, leaf(" :-")),
+ Bl = rule_body(Body, Opts),
{step,Gl,Bl}.
-rule_body(Es, Hook) ->
- lc_quals(Es, Hook).
+rule_body(Es, Opts) ->
+ lc_quals(Es, Opts).
-guard_when(Before, Guard, Hook) ->
- guard_when(Before, Guard, Hook, ' ->').
+guard_when(Before, Guard, Opts) ->
+ guard_when(Before, Guard, Opts, ' ->').
-guard_when(Before, Guard, Hook, After) ->
- Gl = lguard(Guard, Hook),
+guard_when(Before, Guard, Opts, After) ->
+ Gl = lguard(Guard, Opts),
[{list,[{step,Before,Gl}]},After].
-lguard([E|Es], Hook) when is_list(E) ->
- {list,[{step,'when',expr_list([E|Es], [$;], fun guard0/2, Hook)}]};
-lguard([E|Es], Hook) -> % before R6
- lguard([[E|Es]], Hook);
+lguard([E|Es], Opts) when is_list(E) ->
+ {list,[{step,'when',expr_list([E|Es], [$;], fun guard0/2, Opts)}]};
+lguard([E|Es], Opts) -> % before R6
+ lguard([[E|Es]], Opts);
lguard([], _) ->
[].
-guard0(Es, Hook) ->
- expr_list(Es, [$,], fun lexpr/2, Hook).
+guard0(Es, Opts) ->
+ expr_list(Es, [$,], fun lexpr/2, Opts).
-%% body(Before, Es, Hook) -> [Char].
+%% body(Before, Es, Opts) -> [Char].
-body([E], Hook) ->
- lexpr(E, Hook);
-body(Es, Hook) ->
- {prefer_nl,[$,],lexprs(Es, Hook)}.
+body([E], Opts) ->
+ lexpr(E, Opts);
+body(Es, Opts) ->
+ {prefer_nl,[$,],lexprs(Es, Opts)}.
-lexpr(E, Hook) ->
- lexpr(E, 0, Hook).
+lexpr(E, Opts) ->
+ lexpr(E, 0, Opts).
lexpr({var,_,V}, _, _) when is_integer(V) -> %Special hack for Robert
leaf(format("_~w", [V]));
lexpr({var,_,V}, _, _) -> leaf(format("~s", [V]));
-lexpr({char,_,C}, _, _) -> leaf(write_char(C));
+lexpr({char,_,C}, _, _) -> {char,C};
lexpr({integer,_,N}, _, _) -> leaf(write(N));
lexpr({float,_,F}, _, _) -> leaf(write(F));
lexpr({atom,_,A}, _, _) -> leaf(write(A));
lexpr({string,_,S}, _, _) -> {string,S};
lexpr({nil,_}, _, _) -> '[]';
-lexpr({cons,_,H,T}, _, Hook) ->
- list(T, [H], Hook);
-lexpr({lc,_,E,Qs}, _Prec, Hook) ->
- Lcl = {list,[{step,[lexpr(E, Hook),leaf(" ||")],lc_quals(Qs, Hook)}]},
+lexpr({cons,_,H,T}, _, Opts) ->
+ list(T, [H], Opts);
+lexpr({lc,_,E,Qs}, _Prec, Opts) ->
+ Lcl = {list,[{step,[lexpr(E, Opts),leaf(" ||")],lc_quals(Qs, Opts)}]},
{list,[{seq,$[,[],[[]],[{force_nl,leaf(" "),[Lcl]}]},$]]};
%% {list,[{step,$[,Lcl},$]]};
-lexpr({bc,_,E,Qs}, _Prec, Hook) ->
- Lcl = {list,[{step,[lexpr(E, Hook),leaf(" ||")],lc_quals(Qs, Hook)}]},
+lexpr({bc,_,E,Qs}, _Prec, Opts) ->
+ Lcl = {list,[{step,[lexpr(E, Opts),leaf(" ||")],lc_quals(Qs, Opts)}]},
{list,[{seq,'<<',[],[[]],[{force_nl,leaf(" "),[Lcl]}]},'>>']};
%% {list,[{step,'<<',Lcl},'>>']};
-lexpr({tuple,_,Elts}, _, Hook) ->
- tuple(Elts, Hook);
-%%lexpr({struct,_,Tag,Elts}, _, Hook) ->
-%% {first,format("~w", [Tag]),tuple(Elts, Hook)};
-lexpr({record_index, _, Name, F}, Prec, Hook) ->
+lexpr({tuple,_,Elts}, _, Opts) ->
+ tuple(Elts, Opts);
+%%lexpr({struct,_,Tag,Elts}, _, Opts) ->
+%% {first,format("~w", [Tag]),tuple(Elts, Opts)};
+lexpr({record_index, _, Name, F}, Prec, Opts) ->
{P,R} = preop_prec('#'),
Nl = record_name(Name),
- El = [Nl,$.,lexpr(F, R, Hook)],
+ El = [Nl,$.,lexpr(F, R, Opts)],
maybe_paren(P, Prec, El);
-lexpr({record, _, Name, Fs}, Prec, Hook) ->
+lexpr({record, _, Name, Fs}, Prec, Opts) ->
{P,_R} = preop_prec('#'),
Nl = record_name(Name),
- El = {first,Nl,record_fields(Fs, Hook)},
+ El = {first,Nl,record_fields(Fs, Opts)},
maybe_paren(P, Prec, El);
-lexpr({record_field, _, Rec, Name, F}, Prec, Hook) ->
+lexpr({record_field, _, Rec, Name, F}, Prec, Opts) ->
{L,P,R} = inop_prec('#'),
- Rl = lexpr(Rec, L, Hook),
+ Rl = lexpr(Rec, L, Opts),
Nl = leaf(format("#~w.", [Name])),
- El = [Rl,Nl,lexpr(F, R, Hook)],
+ El = [Rl,Nl,lexpr(F, R, Opts)],
maybe_paren(P, Prec, El);
-lexpr({record, _, Rec, Name, Fs}, Prec, Hook) ->
+lexpr({record, _, Rec, Name, Fs}, Prec, Opts) ->
{L,P,_R} = inop_prec('#'),
- Rl = lexpr(Rec, L, Hook),
+ Rl = lexpr(Rec, L, Opts),
Nl = record_name(Name),
- El = {first,[Rl,Nl],record_fields(Fs, Hook)},
+ El = {first,[Rl,Nl],record_fields(Fs, Opts)},
maybe_paren(P, Prec, El);
-lexpr({record_field, _, {atom,_,''}, F}, Prec, Hook) ->
+lexpr({record_field, _, {atom,_,''}, F}, Prec, Opts) ->
{_L,P,R} = inop_prec('.'),
- El = [$.,lexpr(F, R, Hook)],
+ El = [$.,lexpr(F, R, Opts)],
maybe_paren(P, Prec, El);
-lexpr({record_field, _, Rec, F}, Prec, Hook) ->
+lexpr({record_field, _, Rec, F}, Prec, Opts) ->
{L,P,R} = inop_prec('.'),
- El = [lexpr(Rec, L, Hook),$.,lexpr(F, R, Hook)],
+ El = [lexpr(Rec, L, Opts),$.,lexpr(F, R, Opts)],
maybe_paren(P, Prec, El);
-lexpr({block,_,Es}, _, Hook) ->
- {list,[{step,'begin',body(Es, Hook)},'end']};
-lexpr({'if',_,Cs}, _, Hook) ->
- {list,[{step,'if',if_clauses(Cs, Hook)},'end']};
-lexpr({'case',_,Expr,Cs}, _, Hook) ->
- {list,[{step,{list,[{step,'case',lexpr(Expr, Hook)},'of']},
- cr_clauses(Cs, Hook)},
+lexpr({block,_,Es}, _, Opts) ->
+ {list,[{step,'begin',body(Es, Opts)},'end']};
+lexpr({'if',_,Cs}, _, Opts) ->
+ {list,[{step,'if',if_clauses(Cs, Opts)},'end']};
+lexpr({'case',_,Expr,Cs}, _, Opts) ->
+ {list,[{step,{list,[{step,'case',lexpr(Expr, Opts)},'of']},
+ cr_clauses(Cs, Opts)},
'end']};
-lexpr({'cond',_,Cs}, _, Hook) ->
- {list,[{step,leaf("cond"),cond_clauses(Cs, Hook)},'end']};
-lexpr({'receive',_,Cs}, _, Hook) ->
- {list,[{step,'receive',cr_clauses(Cs, Hook)},'end']};
-lexpr({'receive',_,Cs,To,ToOpt}, _, Hook) ->
- Al = {list,[{step,[lexpr(To, Hook),' ->'],body(ToOpt, Hook)}]},
- {list,[{step,'receive',cr_clauses(Cs, Hook)},
+lexpr({'cond',_,Cs}, _, Opts) ->
+ {list,[{step,leaf("cond"),cond_clauses(Cs, Opts)},'end']};
+lexpr({'receive',_,Cs}, _, Opts) ->
+ {list,[{step,'receive',cr_clauses(Cs, Opts)},'end']};
+lexpr({'receive',_,Cs,To,ToOpt}, _, Opts) ->
+ Al = {list,[{step,[lexpr(To, Opts),' ->'],body(ToOpt, Opts)}]},
+ {list,[{step,'receive',cr_clauses(Cs, Opts)},
{step,'after',Al},
'end']};
-lexpr({'fun',_,{function,F,A}}, _Prec, _Hook) ->
+lexpr({'fun',_,{function,F,A}}, _Prec, _Opts) ->
leaf(format("fun ~w/~w", [F,A]));
-lexpr({'fun',_,{function,F,A},Extra}, _Prec, _Hook) ->
+lexpr({'fun',_,{function,F,A},Extra}, _Prec, _Opts) ->
{force_nl,fun_info(Extra),leaf(format("fun ~w/~w", [F,A]))};
-lexpr({'fun',_,{function,M,F,A}}, _Prec, _Hook)
+lexpr({'fun',_,{function,M,F,A}}, _Prec, _Opts)
when is_atom(M), is_atom(F), is_integer(A) ->
%% For backward compatibility with pre-R15 abstract format.
leaf(format("fun ~w:~w/~w", [M,F,A]));
-lexpr({'fun',_,{function,M,F,A}}, _Prec, Hook) ->
+lexpr({'fun',_,{function,M,F,A}}, _Prec, Opts) ->
%% New format in R15.
- NameItem = lexpr(M, Hook),
- CallItem = lexpr(F, Hook),
- ArityItem = lexpr(A, Hook),
+ NameItem = lexpr(M, Opts),
+ CallItem = lexpr(F, Opts),
+ ArityItem = lexpr(A, Opts),
["fun ",NameItem,$:,CallItem,$/,ArityItem];
-lexpr({'fun',_,{clauses,Cs}}, _Prec, Hook) ->
- {list,[{first,'fun',fun_clauses(Cs, Hook)},'end']};
-lexpr({'fun',_,{clauses,Cs},Extra}, _Prec, Hook) ->
+lexpr({'fun',_,{clauses,Cs}}, _Prec, Opts) ->
+ {list,[{first,'fun',fun_clauses(Cs, Opts)},'end']};
+lexpr({'fun',_,{clauses,Cs},Extra}, _Prec, Opts) ->
{force_nl,fun_info(Extra),
- {list,[{first,'fun',fun_clauses(Cs, Hook)},'end']}};
-lexpr({'query',_,Lc}, _Prec, Hook) ->
- {list,[{step,leaf("query"),lexpr(Lc, 0, Hook)},'end']};
-lexpr({call,_,{remote,_,{atom,_,M},{atom,_,F}=N}=Name,Args}, Prec, Hook) ->
+ {list,[{first,'fun',fun_clauses(Cs, Opts)},'end']}};
+lexpr({'query',_,Lc}, _Prec, Opts) ->
+ {list,[{step,leaf("query"),lexpr(Lc, 0, Opts)},'end']};
+lexpr({call,_,{remote,_,{atom,_,M},{atom,_,F}=N}=Name,Args}, Prec, Opts) ->
case erl_internal:bif(M, F, length(Args)) of
true ->
- call(N, Args, Prec, Hook);
+ call(N, Args, Prec, Opts);
false ->
- call(Name, Args, Prec, Hook)
+ call(Name, Args, Prec, Opts)
end;
-lexpr({call,_,Name,Args}, Prec, Hook) ->
- call(Name, Args, Prec, Hook);
-lexpr({'try',_,Es,Scs,Ccs,As}, _, Hook) ->
+lexpr({call,_,Name,Args}, Prec, Opts) ->
+ call(Name, Args, Prec, Opts);
+lexpr({'try',_,Es,Scs,Ccs,As}, _, Opts) ->
{list,[if
Scs =:= [] ->
- {step,'try',body(Es, Hook)};
+ {step,'try',body(Es, Opts)};
true ->
- {step,{list,[{step,'try',body(Es, Hook)},'of']},
- cr_clauses(Scs, Hook)}
+ {step,{list,[{step,'try',body(Es, Opts)},'of']},
+ cr_clauses(Scs, Opts)}
end,
if
Ccs =:= [] ->
[];
true ->
- {step,'catch',try_clauses(Ccs, Hook)}
+ {step,'catch',try_clauses(Ccs, Opts)}
end,
if
As =:= [] ->
[];
true ->
- {step,'after',body(As, Hook)}
+ {step,'after',body(As, Opts)}
end,
'end']};
-lexpr({'catch',_,Expr}, Prec, Hook) ->
+lexpr({'catch',_,Expr}, Prec, Opts) ->
{P,R} = preop_prec('catch'),
- El = {list,[{step,'catch',lexpr(Expr, R, Hook)}]},
+ El = {list,[{step,'catch',lexpr(Expr, R, Opts)}]},
maybe_paren(P, Prec, El);
-lexpr({match,_,Lhs,Rhs}, Prec, Hook) ->
+lexpr({match,_,Lhs,Rhs}, Prec, Opts) ->
{L,P,R} = inop_prec('='),
- Pl = lexpr(Lhs, L, Hook),
- Rl = lexpr(Rhs, R, Hook),
+ Pl = lexpr(Lhs, L, Opts),
+ Rl = lexpr(Rhs, R, Opts),
El = {list,[{cstep,[Pl,' ='],Rl}]},
maybe_paren(P, Prec, El);
-lexpr({op,_,Op,Arg}, Prec, Hook) ->
+lexpr({op,_,Op,Arg}, Prec, Opts) ->
{P,R} = preop_prec(Op),
Ol = leaf(format("~s ", [Op])),
- El = [Ol,lexpr(Arg, R, Hook)],
+ El = [Ol,lexpr(Arg, R, Opts)],
maybe_paren(P, Prec, El);
-lexpr({op,_,Op,Larg,Rarg}, Prec, Hook) when Op =:= 'orelse';
+lexpr({op,_,Op,Larg,Rarg}, Prec, Opts) when Op =:= 'orelse';
Op =:= 'andalso' ->
%% Breaks lines since R12B.
{L,P,R} = inop_prec(Op),
- Ll = lexpr(Larg, L, Hook),
+ Ll = lexpr(Larg, L, Opts),
Ol = leaf(format("~s", [Op])),
- Lr = lexpr(Rarg, R, Hook),
+ Lr = lexpr(Rarg, R, Opts),
El = {prefer_nl,[[]],[Ll,Ol,Lr]},
maybe_paren(P, Prec, El);
-lexpr({op,_,Op,Larg,Rarg}, Prec, Hook) ->
+lexpr({op,_,Op,Larg,Rarg}, Prec, Opts) ->
{L,P,R} = inop_prec(Op),
- Ll = lexpr(Larg, L, Hook),
+ Ll = lexpr(Larg, L, Opts),
Ol = leaf(format("~s", [Op])),
- Lr = lexpr(Rarg, R, Hook),
+ Lr = lexpr(Rarg, R, Opts),
El = {list,[Ll,Ol,Lr]},
maybe_paren(P, Prec, El);
%% Special expressions which are not really legal everywhere.
-lexpr({remote,_,M,F}, Prec, Hook) ->
+lexpr({remote,_,M,F}, Prec, Opts) ->
{L,P,R} = inop_prec(':'),
- NameItem = lexpr(M, L, Hook),
- CallItem = lexpr(F, R, Hook),
+ NameItem = lexpr(M, L, Opts),
+ CallItem = lexpr(F, R, Opts),
maybe_paren(P, Prec, [NameItem,$:,CallItem]);
%% BIT SYNTAX:
-lexpr({bin,_,Fs}, _, Hook) ->
- bit_grp(Fs, Hook);
+lexpr({bin,_,Fs}, _, Opts) ->
+ bit_grp(Fs, Opts);
%% Special case for straight values.
lexpr({value,_,Val}, _,_) ->
leaf(write(Val));
%% Now do the hook.
-lexpr(Other, _Precedence, none) ->
+lexpr(Other, _Precedence, #options{hook = none}) ->
leaf(format("INVALID-FORM:~w:",[Other]));
-lexpr(HookExpr, Precedence, {Mod,Func,Eas}) when Mod =/= 'fun' ->
+lexpr(HookExpr, Precedence, #options{hook = {Mod,Func,Eas}})
+ when Mod =/= 'fun' ->
{ehook,HookExpr,Precedence,{Mod,Func,Eas}};
-lexpr(HookExpr, Precedence, Func) ->
- {hook,HookExpr,Precedence,Func}.
+lexpr(HookExpr, Precedence, #options{hook = Func, opts = Options}) ->
+ {hook,HookExpr,Precedence,Func,Options}.
-call(Name, Args, Prec, Hook) ->
+call(Name, Args, Prec, Opts) ->
{F,P} = func_prec(),
- Item = {first,lexpr(Name, F, Hook),args(Args, Hook)},
+ Item = {first,lexpr(Name, F, Opts),args(Args, Opts)},
maybe_paren(P, Prec, Item).
fun_info(Extra) ->
@@ -565,32 +604,18 @@ fun_info(Extra) ->
%% BITS:
-bit_grp(Fs, Hook) ->
- append([['<<'],
- [try
- true = Fs =/= [],
- S = bin_string(Fs),
- true = io_lib:printable_list(S),
- {string,S}
- catch _:_ ->
- bit_elems(Fs, Hook)
- end],
- ['>>']]).
-
-bin_string([]) ->
- [];
-bin_string([{bin_element,_,{char,_,C},_,_}|Bin]) ->
- [C | bin_string(Bin)].
+bit_grp(Fs, Opts) ->
+ append([['<<'], [bit_elems(Fs, Opts)], ['>>']]).
-bit_elems(Es, Hook) ->
- expr_list(Es, $,, fun bit_elem/2, Hook).
+bit_elems(Es, Opts) ->
+ expr_list(Es, $,, fun bit_elem/2, Opts).
-bit_elem({bin_element,_,Expr,Sz,Types}, Hook) ->
+bit_elem({bin_element,_,Expr,Sz,Types}, Opts) ->
P = max_prec(),
- VChars = lexpr(Expr, P, Hook),
+ VChars = lexpr(Expr, P, Opts),
SChars = if
Sz =/= default ->
- [VChars,$:,lexpr(Sz, P, Hook)];
+ [VChars,$:,lexpr(Sz, P, Opts)];
true ->
VChars
end,
@@ -618,157 +643,157 @@ bit_elem_type(T) ->
record_name(Name) ->
leaf(format("#~w", [Name])).
-record_fields(Fs, Hook) ->
- tuple(Fs, fun record_field/2, Hook).
+record_fields(Fs, Opts) ->
+ tuple(Fs, fun record_field/2, Opts).
-record_field({record_field,_,F,Val}, Hook) ->
+record_field({record_field,_,F,Val}, Opts) ->
{L,_P,R} = inop_prec('='),
- Fl = lexpr(F, L, Hook),
- Vl = lexpr(Val, R, Hook),
+ Fl = lexpr(F, L, Opts),
+ Vl = lexpr(Val, R, Opts),
{list,[{cstep,[Fl,' ='],Vl}]};
-record_field({typed_record_field,{record_field,_,F,Val},Type}, Hook) ->
+record_field({typed_record_field,{record_field,_,F,Val},Type}, Opts) ->
{L,_P,R} = inop_prec('='),
- Fl = lexpr(F, L, Hook),
- Vl = typed(lexpr(Val, R, Hook), Type),
+ Fl = lexpr(F, L, Opts),
+ Vl = typed(lexpr(Val, R, Opts), Type),
{list,[{cstep,[Fl,' ='],Vl}]};
-record_field({typed_record_field,Field,Type}, Hook) ->
- typed(record_field(Field, Hook), Type);
-record_field({record_field,_,F}, Hook) ->
- lexpr(F, 0, Hook).
-
-list({cons,_,H,T}, Es, Hook) ->
- list(T, [H|Es], Hook);
-list({nil,_}, Es, Hook) ->
- proper_list(reverse(Es), Hook);
-list(Other, Es, Hook) ->
- improper_list(reverse(Es, [Other]), Hook).
-
-%% if_clauses(Clauses, Hook) -> [Char].
+record_field({typed_record_field,Field,Type}, Opts) ->
+ typed(record_field(Field, Opts), Type);
+record_field({record_field,_,F}, Opts) ->
+ lexpr(F, 0, Opts).
+
+list({cons,_,H,T}, Es, Opts) ->
+ list(T, [H|Es], Opts);
+list({nil,_}, Es, Opts) ->
+ proper_list(reverse(Es), Opts);
+list(Other, Es, Opts) ->
+ improper_list(reverse(Es, [Other]), Opts).
+
+%% if_clauses(Clauses, Opts) -> [Char].
%% Print 'if' clauses.
-if_clauses(Cs, Hook) ->
- clauses(fun if_clause/2, Hook, Cs).
+if_clauses(Cs, Opts) ->
+ clauses(fun if_clause/2, Opts, Cs).
-if_clause({clause,_,[],G,B}, Hook) ->
- Gl = [guard_no_when(G, Hook),' ->'],
- {step,Gl,body(B, Hook)}.
+if_clause({clause,_,[],G,B}, Opts) ->
+ Gl = [guard_no_when(G, Opts),' ->'],
+ {step,Gl,body(B, Opts)}.
-guard_no_when([E|Es], Hook) when is_list(E) ->
- expr_list([E|Es], $;, fun guard0/2, Hook);
-guard_no_when([E|Es], Hook) -> % before R6
- guard_no_when([[E|Es]], Hook);
+guard_no_when([E|Es], Opts) when is_list(E) ->
+ expr_list([E|Es], $;, fun guard0/2, Opts);
+guard_no_when([E|Es], Opts) -> % before R6
+ guard_no_when([[E|Es]], Opts);
guard_no_when([], _) -> % cannot happen
leaf("true").
-%% cr_clauses(Clauses, Hook) -> [Char].
+%% cr_clauses(Clauses, Opts) -> [Char].
%% Print 'case'/'receive' clauses.
-cr_clauses(Cs, Hook) ->
- clauses(fun cr_clause/2, Hook, Cs).
+cr_clauses(Cs, Opts) ->
+ clauses(fun cr_clause/2, Opts, Cs).
-cr_clause({clause,_,[T],G,B}, Hook) ->
- El = lexpr(T, 0, Hook),
- Gl = guard_when(El, G, Hook),
- Bl = body(B, Hook),
+cr_clause({clause,_,[T],G,B}, Opts) ->
+ El = lexpr(T, 0, Opts),
+ Gl = guard_when(El, G, Opts),
+ Bl = body(B, Opts),
{step,Gl,Bl}.
-%% try_clauses(Clauses, Hook) -> [Char].
+%% try_clauses(Clauses, Opts) -> [Char].
%% Print 'try' clauses.
-try_clauses(Cs, Hook) ->
- clauses(fun try_clause/2, Hook, Cs).
+try_clauses(Cs, Opts) ->
+ clauses(fun try_clause/2, Opts, Cs).
-try_clause({clause,_,[{tuple,_,[{atom,_,throw},V,S]}],G,B}, Hook) ->
- El = lexpr(V, 0, Hook),
- Sl = stack_backtrace(S, [El], Hook),
- Gl = guard_when(Sl, G, Hook),
- Bl = body(B, Hook),
+try_clause({clause,_,[{tuple,_,[{atom,_,throw},V,S]}],G,B}, Opts) ->
+ El = lexpr(V, 0, Opts),
+ Sl = stack_backtrace(S, [El], Opts),
+ Gl = guard_when(Sl, G, Opts),
+ Bl = body(B, Opts),
{step,Gl,Bl};
-try_clause({clause,_,[{tuple,_,[C,V,S]}],G,B}, Hook) ->
- Cs = lexpr(C, 0, Hook),
- El = lexpr(V, 0, Hook),
+try_clause({clause,_,[{tuple,_,[C,V,S]}],G,B}, Opts) ->
+ Cs = lexpr(C, 0, Opts),
+ El = lexpr(V, 0, Opts),
CsEl = [Cs,$:,El],
- Sl = stack_backtrace(S, CsEl, Hook),
- Gl = guard_when(Sl, G, Hook),
- Bl = body(B, Hook),
+ Sl = stack_backtrace(S, CsEl, Opts),
+ Gl = guard_when(Sl, G, Opts),
+ Bl = body(B, Opts),
{step,Gl,Bl}.
-stack_backtrace({var,_,'_'}, El, _Hook) ->
+stack_backtrace({var,_,'_'}, El, _Opts) ->
El;
-stack_backtrace(S, El, Hook) ->
- El++[$:,lexpr(S, 0, Hook)].
+stack_backtrace(S, El, Opts) ->
+ El++[$:,lexpr(S, 0, Opts)].
-%% fun_clauses(Clauses, Hook) -> [Char].
+%% fun_clauses(Clauses, Opts) -> [Char].
%% Print 'fun' clauses.
-fun_clauses(Cs, Hook) ->
- nl_clauses(fun fun_clause/2, [$;], Hook, Cs).
+fun_clauses(Cs, Opts) ->
+ nl_clauses(fun fun_clause/2, [$;], Opts, Cs).
-fun_clause({clause,_,A,G,B}, Hook) ->
- El = args(A, Hook),
- Gl = guard_when(El, G, Hook),
- Bl = body(B, Hook),
+fun_clause({clause,_,A,G,B}, Opts) ->
+ El = args(A, Opts),
+ Gl = guard_when(El, G, Opts),
+ Bl = body(B, Opts),
{step,Gl,Bl}.
-%% cond_clauses(Clauses, Hook) -> [Char].
+%% cond_clauses(Clauses, Opts) -> [Char].
%% Print 'cond' clauses.
-cond_clauses(Cs, Hook) ->
- clauses(fun cond_clause/2, Hook, Cs).
+cond_clauses(Cs, Opts) ->
+ clauses(fun cond_clause/2, Opts, Cs).
-cond_clause({clause,_,[],[[E]],B}, Hook) ->
- {step,[lexpr(E, Hook),' ->'],body(B, Hook)}.
+cond_clause({clause,_,[],[[E]],B}, Opts) ->
+ {step,[lexpr(E, Opts),' ->'],body(B, Opts)}.
-%% nl_clauses(Type, Hook, Clauses) -> [Char].
+%% nl_clauses(Type, Opts, Clauses) -> [Char].
%% Generic clause printing function (always breaks lines).
-nl_clauses(Type, Sep, Hook, Cs) ->
- {prefer_nl,Sep,lexprs(Cs, Type, Hook)}.
+nl_clauses(Type, Sep, Opts, Cs) ->
+ {prefer_nl,Sep,lexprs(Cs, Type, Opts)}.
-%% clauses(Type, Hook, Clauses) -> [Char].
+%% clauses(Type, Opts, Clauses) -> [Char].
%% Generic clause printing function (breaks lines since R12B).
-clauses(Type, Hook, Cs) ->
- {prefer_nl,[$;],lexprs(Cs, Type, Hook)}.
+clauses(Type, Opts, Cs) ->
+ {prefer_nl,[$;],lexprs(Cs, Type, Opts)}.
-%% lc_quals(Qualifiers, After, Hook)
+%% lc_quals(Qualifiers, After, Opts)
%% List comprehension qualifiers (breaks lines since R12B).
-lc_quals(Qs, Hook) ->
- {prefer_nl,[$,],lexprs(Qs, fun lc_qual/2, Hook)}.
+lc_quals(Qs, Opts) ->
+ {prefer_nl,[$,],lexprs(Qs, fun lc_qual/2, Opts)}.
-lc_qual({b_generate,_,Pat,E}, Hook) ->
- Pl = lexpr(Pat, 0, Hook),
- {list,[{step,[Pl,leaf(" <=")],lexpr(E, 0, Hook)}]};
-lc_qual({generate,_,Pat,E}, Hook) ->
- Pl = lexpr(Pat, 0, Hook),
- {list,[{step,[Pl,leaf(" <-")],lexpr(E, 0, Hook)}]};
-lc_qual(Q, Hook) ->
- lexpr(Q, 0, Hook).
+lc_qual({b_generate,_,Pat,E}, Opts) ->
+ Pl = lexpr(Pat, 0, Opts),
+ {list,[{step,[Pl,leaf(" <=")],lexpr(E, 0, Opts)}]};
+lc_qual({generate,_,Pat,E}, Opts) ->
+ Pl = lexpr(Pat, 0, Opts),
+ {list,[{step,[Pl,leaf(" <-")],lexpr(E, 0, Opts)}]};
+lc_qual(Q, Opts) ->
+ lexpr(Q, 0, Opts).
-proper_list(Es, Hook) ->
- {seq,$[,$],$,,lexprs(Es, Hook)}.
+proper_list(Es, Opts) ->
+ {seq,$[,$],$,,lexprs(Es, Opts)}.
-improper_list(Es, Hook) ->
- {seq,$[,$],{$,,$|},lexprs(Es, Hook)}.
+improper_list(Es, Opts) ->
+ {seq,$[,$],{$,,$|},lexprs(Es, Opts)}.
-tuple(L, Hook) ->
- tuple(L, fun lexpr/2, Hook).
+tuple(L, Opts) ->
+ tuple(L, fun lexpr/2, Opts).
-tuple(Es, F, Hook) ->
- {seq,${,$},$,,lexprs(Es, F, Hook)}.
+tuple(Es, F, Opts) ->
+ {seq,${,$},$,,lexprs(Es, F, Opts)}.
-args(As, Hook) ->
- {seq,$(,$),[$,],lexprs(As, Hook)}.
+args(As, Opts) ->
+ {seq,$(,$),[$,],lexprs(As, Opts)}.
-expr_list(Es, Sep, F, Hook) ->
- {seq,[],[],Sep,lexprs(Es, F, Hook)}.
+expr_list(Es, Sep, F, Opts) ->
+ {seq,[],[],Sep,lexprs(Es, F, Opts)}.
-lexprs(Es, Hook) ->
- lexprs(Es, fun lexpr/2, Hook).
+lexprs(Es, Opts) ->
+ lexprs(Es, fun lexpr/2, Opts).
-lexprs(Es, F, Hook) ->
- [F(E, Hook) || E <- Es].
+lexprs(Es, F, Opts) ->
+ [F(E, Opts) || E <- Es].
maybe_paren(P, Prec, Expr) when P < Prec ->
[$(,Expr,$)];
@@ -781,13 +806,13 @@ leaf(S) ->
%%% Do the formatting. Currently nothing fancy. Could probably have
%%% done it in one single pass.
-frmt(Item) ->
- frmt(Item, 0).
+frmt(Item, PP) ->
+ frmt(Item, 0, PP).
-frmt(Item, I) ->
+frmt(Item, I, PP) ->
ST = spacetab(),
WT = wordtable(),
- {Chars,_Length} = f(Item, I, ST, WT),
+ {Chars,_Length} = f(Item, I, ST, WT, PP),
[Chars].
%%% What the tags mean:
@@ -803,6 +828,7 @@ frmt(Item, I) ->
%%% - {force_nl,ExtraInfo,I}: fun-info (a comment) forces linebreak before I.
%%% - {prefer_nl,Sep,IPs}: forces linebreak between Is unlesss negative
%%% indentation.
+%%% - {char,C}: a character
%%% - {string,S}: a string.
%%% - {hook,...}, {ehook,...}: hook expressions.
%%%
@@ -812,22 +838,22 @@ frmt(Item, I) ->
%%% cstep works similarly, but no linebreak if the width of I1 is less
%%% than the indentation (this is for "A = <expression over several lines>).
-f([]=Nil, _I0, _ST, _WT) ->
+f([]=Nil, _I0, _ST, _WT, _PP) ->
{Nil,0};
-f(C, _I0, _ST, _WT) when is_integer(C) ->
+f(C, _I0, _ST, _WT, _PP) when is_integer(C) ->
{C,1};
-f({leaf,Length,Chars}, _I0, _ST, _WT) ->
+f({leaf,Length,Chars}, _I0, _ST, _WT, _PP) ->
{Chars,Length};
-f([Item|Items], I0, ST, WT) ->
- consecutive(Items, f(Item, I0, ST, WT), I0, ST, WT);
-f({list,Items}, I0, ST, WT) ->
- f({seq,[],[],[[]],Items}, I0, ST, WT);
-f({first,E,Item}, I0, ST, WT) ->
- f({seq,E,[],[[]],[Item]}, I0, ST, WT);
-f({seq,Before,After,Sep,LItems}, I0, ST, WT) ->
- BCharsSize = f(Before, I0, ST, WT),
+f([Item|Items], I0, ST, WT, PP) ->
+ consecutive(Items, f(Item, I0, ST, WT, PP), I0, ST, WT, PP);
+f({list,Items}, I0, ST, WT, PP) ->
+ f({seq,[],[],[[]],Items}, I0, ST, WT, PP);
+f({first,E,Item}, I0, ST, WT, PP) ->
+ f({seq,E,[],[[]],[Item]}, I0, ST, WT, PP);
+f({seq,Before,After,Sep,LItems}, I0, ST, WT, PP) ->
+ BCharsSize = f(Before, I0, ST, WT, PP),
I = indent(BCharsSize, I0),
- CharsSizeL = fl(LItems, Sep, I, After, ST, WT),
+ CharsSizeL = fl(LItems, Sep, I, After, ST, WT, PP),
{CharsL,SizeL} = unz(CharsSizeL),
{BCharsL,BSizeL} = unz1([BCharsSize]),
Sizes = BSizeL ++ SizeL,
@@ -848,15 +874,15 @@ f({seq,Before,After,Sep,LItems}, I0, ST, WT) ->
{BCharsL++insert_newlines(CharsSizeL, I, ST),
nsz(lists:last(Sizes), I0)}
end;
-f({force_nl,_ExtraInfoItem,Item}, I, ST, WT) when I < 0 ->
+f({force_nl,_ExtraInfoItem,Item}, I, ST, WT, PP) when I < 0 ->
%% Extra info is a comment; cannot have that on the same line
- f(Item, I, ST, WT);
-f({force_nl,ExtraInfoItem,Item}, I, ST, WT) ->
- f({prefer_nl,[],[ExtraInfoItem,Item]}, I, ST, WT);
-f({prefer_nl,Sep,LItems}, I, ST, WT) when I < 0 ->
- f({seq,[],[],Sep,LItems}, I, ST, WT);
-f({prefer_nl,Sep,LItems}, I0, ST, WT) ->
- CharsSize2L = fl(LItems, Sep, I0, [], ST, WT),
+ f(Item, I, ST, WT, PP);
+f({force_nl,ExtraInfoItem,Item}, I, ST, WT, PP) ->
+ f({prefer_nl,[],[ExtraInfoItem,Item]}, I, ST, WT, PP);
+f({prefer_nl,Sep,LItems}, I, ST, WT, PP) when I < 0 ->
+ f({seq,[],[],Sep,LItems}, I, ST, WT, PP);
+f({prefer_nl,Sep,LItems}, I0, ST, WT, PP) ->
+ CharsSize2L = fl(LItems, Sep, I0, [], ST, WT, PP),
{_CharsL,Sizes} = unz(CharsSize2L),
if
Sizes =:= [] ->
@@ -864,37 +890,40 @@ f({prefer_nl,Sep,LItems}, I0, ST, WT) ->
true ->
{insert_newlines(CharsSize2L, I0, ST),nsz(lists:last(Sizes), I0)}
end;
-f({string,S}, I, ST, WT) ->
- f(write_a_string(S, I), I, ST, WT);
-f({hook,HookExpr,Precedence,Func}, I, _ST, _WT) ->
- Chars = Func(HookExpr, I, Precedence, Func),
+f({char,C}, I, ST, WT, PP) ->
+ f(write_a_char(C, PP), I, ST, WT, PP);
+f({string,S}, I, ST, WT, PP) ->
+ f(write_a_string(S, I, PP), I, ST, WT, PP);
+f({hook,HookExpr,Precedence,Func,Options}, I, _ST, _WT, _PP) ->
+ Chars = Func(HookExpr, I, Precedence, Options),
{Chars,indentation(Chars, I)};
-f({ehook,HookExpr,Precedence,{Mod,Func,Eas}=ModFuncEas}, I, _ST, _WT) ->
+f({ehook,HookExpr,Precedence,{Mod,Func,Eas}=ModFuncEas}, I, _ST, _WT, _PP) ->
Chars = apply(Mod, Func, [HookExpr,I,Precedence,ModFuncEas|Eas]),
{Chars,indentation(Chars, I)};
-f(WordName, _I, _ST, WT) -> % when is_atom(WordName)
+f(WordName, _I, _ST, WT, _PP) -> % when is_atom(WordName)
word(WordName, WT).
-define(IND, 4).
%% fl(ListItems, I0, ST, WT) -> [[CharsSize1,CharsSize2]]
%% ListItems = [{Item,Items}|Item]
-fl([], _Sep, I0, After, ST, WT) ->
- [[f(After, I0, ST, WT),{[],0}]];
-fl(CItems, Sep0, I0, After, ST, WT) ->
+fl([], _Sep, I0, After, ST, WT, PP) ->
+ [[f(After, I0, ST, WT, PP),{[],0}]];
+fl(CItems, Sep0, I0, After, ST, WT, PP) ->
F = fun({step,Item1,Item2}, S) ->
- [f(Item1, I0, ST, WT),f([Item2,S], incr(I0, ?IND), ST, WT)];
+ [f(Item1, I0, ST, WT, PP),
+ f([Item2,S], incr(I0, ?IND), ST, WT, PP)];
({cstep,Item1,Item2}, S) ->
- {_,Sz1} = CharSize1 = f(Item1, I0, ST, WT),
+ {_,Sz1} = CharSize1 = f(Item1, I0, ST, WT, PP),
if
is_integer(Sz1), Sz1 < ?IND ->
Item2p = [leaf("\s"),Item2,S],
- [consecutive(Item2p, CharSize1, I0, ST, WT),{[],0}];
+ [consecutive(Item2p, CharSize1, I0, ST, WT, PP),{[],0}];
true ->
- [CharSize1,f([Item2,S], incr(I0, ?IND), ST, WT)]
+ [CharSize1,f([Item2,S], incr(I0, ?IND), ST, WT, PP)]
end;
(Item, S) ->
- [f([Item,S], I0, ST, WT),{[],0}]
+ [f([Item,S], I0, ST, WT, PP),{[],0}]
end,
{Sep,LastSep} = case Sep0 of {_,_} -> Sep0; _ -> {Sep0,Sep0} end,
fl1(CItems, F, Sep, LastSep, After).
@@ -906,10 +935,10 @@ fl1([CItem1,CItem2], F, _Sep, LastSep, After) ->
fl1([CItem|CItems], F, Sep, LastSep, After) ->
[F(CItem, Sep)|fl1(CItems, F, Sep, LastSep, After)].
-consecutive(Items, CharSize1, I0, ST, WT) ->
+consecutive(Items, CharSize1, I0, ST, WT, PP) ->
{CharsSizes,_Length} =
mapfoldl(fun(Item, Len) ->
- CharsSize = f(Item, Len, ST, WT),
+ CharsSize = f(Item, Len, ST, WT, PP),
{CharsSize,indent(CharsSize, Len)}
end, indent(CharSize1, I0), Items),
{CharsL,SizeL} = unz1([CharSize1|CharsSizes]),
@@ -999,26 +1028,40 @@ has_nl([C|Cs]) ->
has_nl([]) ->
false.
+write_a_char(C, PP) ->
+ flat_leaf(write_char(C, PP)).
+
-define(MIN_SUBSTRING, 5).
-write_a_string(S, I) when I < 0; S =:= [] ->
- leaf(write_string(S));
-write_a_string(S, I) ->
+write_a_string(S, I, PP) when I < 0; S =:= [] ->
+ flat_leaf(write_string(S, PP));
+write_a_string(S, I, PP) ->
Len = erlang:max(?MAXLINE-I, ?MIN_SUBSTRING),
- {list,write_a_string(S, Len, Len)}.
+ {list,write_a_string(S, Len, Len, PP)}.
-write_a_string([], _N, _Len) ->
+write_a_string([], _N, _Len, _PP) ->
[];
-write_a_string(S, N, Len) ->
+write_a_string(S, N, Len, PP) ->
SS = string:sub_string(S, 1, N),
- Sl = write_string(SS),
- case (iolist_size(Sl) > Len) and (N > ?MIN_SUBSTRING) of
+ Sl = write_string(SS, PP),
+ case (length(Sl) > Len) and (N > ?MIN_SUBSTRING) of
true ->
- write_a_string(S, N-1, Len);
+ write_a_string(S, N-1, Len, PP);
false ->
- [leaf(Sl)|write_a_string(lists:nthtail(length(SS), S), Len, Len)]
+ [flat_leaf(Sl) |
+ write_a_string(lists:nthtail(length(SS), S), Len, Len, PP)]
end.
+flat_leaf(S) ->
+ L = lists:flatten(S),
+ {leaf,length(L),L}.
+
+write_string(S, PP) ->
+ lists:flatten((PP#pp.string_fun)(S)).
+
+write_char(C, PP) ->
+ lists:flatten((PP#pp.char_fun)(C)).
+
%%
%% Utilities
%%
diff --git a/lib/stdlib/src/erl_scan.erl b/lib/stdlib/src/erl_scan.erl
index 8e59e01f48..e5bb287c45 100644
--- a/lib/stdlib/src/erl_scan.erl
+++ b/lib/stdlib/src/erl_scan.erl
@@ -1,3 +1,4 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
@@ -32,19 +33,19 @@
%% 173 - 176 { - ~ punctuation
%% 177 DEL control
%% 200 - 237 control
-%% 240 - 277 NBSP - � punctuation
-%% 300 - 326 � - � uppercase
-%% 327 � punctuation
-%% 330 - 336 � - � uppercase
-%% 337 - 366 � - � lowercase
-%% 367 � punctuation
-%% 370 - 377 � - � lowercase
+%% 240 - 277 NBSP - ¿ punctuation
+%% 300 - 326 À - Ö uppercase
+%% 327 × punctuation
+%% 330 - 336 Ø - Þ uppercase
+%% 337 - 366 ß - ö lowercase
+%% 367 ÷ punctuation
+%% 370 - 377 ø - ÿ lowercase
%%
%% Many punctuation characters have special meaning:
%% $\s, $_, $", $$, $%, $', $.
%% DEL is a punctuation.
%%
-%% Must watch using � \327, very close to x \170.
+%% Must watch using × \327, very close to x \170.
-module(erl_scan).
@@ -55,7 +56,15 @@
token_info/1,token_info/2,
attributes_info/1,attributes_info/2,set_attribute/3]).
--export_type([error_info/0, line/0, tokens_result/0]).
+%%% Private
+-export([continuation_location/1]).
+
+-export_type([error_info/0,
+ line/0,
+ location/0,
+ options/0,
+ return_cont/0,
+ tokens_result/0]).
%%%
%%% Defines and type definitions
@@ -74,7 +83,8 @@
-type location() :: line() | {line(),column()}.
-type resword_fun() :: fun((atom()) -> boolean()).
-type option() :: 'return' | 'return_white_spaces' | 'return_comments'
- | 'text' | {'reserved_word_fun', resword_fun()}.
+ | 'text' | {'reserved_word_fun', resword_fun()}
+ | 'unicode'.
-type options() :: option() | [option()].
-type symbol() :: atom() | float() | integer() | string().
-type info_line() :: integer() | term().
@@ -95,7 +105,8 @@
{resword_fun = fun reserved_word/1 :: resword_fun(),
ws = false :: boolean(),
comment = false :: boolean(),
- text = false :: boolean()}).
+ text = false :: boolean(),
+ unicode = false :: boolean()}).
%%----------------------------------------------------------------------------
@@ -183,6 +194,11 @@ tokens({erl_scan_continuation,Cs,Col,Toks,Line,St,Any,Fun},
CharSpec, _Loc, _Opts) ->
tokens1(Cs++CharSpec, St, Line, Col, Toks, Fun, Any).
+continuation_location({erl_scan_continuation,_,no_col,_,Line,_,_,_}) ->
+ Line;
+continuation_location({erl_scan_continuation,_,Col,_,Line,_,_,_}) ->
+ {Line,Col}.
+
-type attribute_item() :: 'column' | 'length' | 'line'
| 'location' | 'text'.
-type info_location() :: location() | term().
@@ -201,15 +217,14 @@ token_info(Token) ->
Items = [category,column,length,line,symbol,text], % undefined order
token_info(Token, Items).
--spec token_info(Token, TokenItem) -> TokenInfo | 'undefined' when
- Token :: token(),
- TokenItem :: token_item(),
- TokenInfo :: TokenInfoTuple :: token_info();
- (Token, TokenItems) -> [TokenInfo] when
- Token :: token(),
- TokenItems :: [TokenItem],
- TokenItem :: token_item(),
- TokenInfo :: [TokenInfoTuple :: token_info()].
+-spec token_info(Token, TokenItem) -> TokenInfoTuple | 'undefined' when
+ Token :: token(),
+ TokenItem :: token_item(),
+ TokenInfoTuple :: token_info();
+ (Token, TokenItems) -> TokenInfo when
+ Token :: token(),
+ TokenItems :: [TokenItem :: token_item()],
+ TokenInfo :: [TokenInfoTuple :: token_info()].
token_info(_Token, []) ->
[];
token_info(Token, [Item|Items]) when is_atom(Item) ->
@@ -239,16 +254,15 @@ attributes_info(Attributes) ->
Items = [column,length,line,text], % undefined order
attributes_info(Attributes, Items).
--spec attributes_info(Attributes, AttributeItem) ->
- AttributeInfo | 'undefined' when
- Attributes :: attributes(),
- AttributeItem :: attribute_item(),
- AttributeInfo :: AttributeInfoTuple :: attribute_info();
- (Attributes, AttributeItems) -> [AttributeInfo] when
- Attributes :: attributes(),
- AttributeItems :: [AttributeItem],
- AttributeItem :: attribute_item(),
- AttributeInfo :: [AttributeInfoTuple :: attribute_info()].
+-spec attributes_info
+ (Attributes, AttributeItem) -> AttributeInfoTuple | 'undefined' when
+ Attributes :: attributes(),
+ AttributeItem :: attribute_item(),
+ AttributeInfoTuple :: attribute_info();
+ (Attributes, AttributeItems) -> AttributeInfo when
+ Attributes :: attributes(),
+ AttributeItems :: [AttributeItem :: attribute_item()],
+ AttributeInfo :: [AttributeInfoTuple :: attribute_info()].
attributes_info(_Attrs, []) ->
[];
attributes_info(Attrs, [A|As]) when is_atom(A) ->
@@ -324,13 +338,20 @@ string_thing(_) -> "string".
(C >= $\000 andalso C =< $\s orelse C >= $\200 andalso C =< $\240)).
-define(DIGIT(C), C >= $0, C =< $9).
-define(CHAR(C), is_integer(C), C >= 0).
-
-%% A workaround: Unicode strings are not returned as strings, but as
-%% lists of integers. For instance, "b\x{aaa}c" => [98,2730,99]. This
-%% is to protect the system from character codes greater than 255. To
-%% be removed. Search for UNI to find workaround code.
+-define(UNICODE(C),
+ (C >= 0 andalso C < 16#D800 orelse
+ C > 16#DFFF andalso C < 16#FFFE orelse
+ C > 16#FFFF andalso C =< 16#10FFFF)).
+
+%% When the option 'unicode' is false: return Unicode strings as lists
+%% of integers and Unicode characters as integers. For instance,
+%% erl_scan:string("\"b\x{aaa}c\".") is equivalent to
+%% erl_scan:string("[98,2730,99]."). This is to protect the caller
+%% from character codes greater than 255. Search for UNI to find code
+%% implementing this "feature". The 'unicode' option is undocumented
+%% and will probably be removed later.
-define(NO_UNICODE, 0).
--define(UNI255(C), (C) =< 16#ff).
+-define(UNI255(C), (C =< 16#ff)).
options(Opts0) when is_list(Opts0) ->
Opts = lists:foldr(fun expand_opt/2, [], Opts0),
@@ -344,10 +365,12 @@ options(Opts0) when is_list(Opts0) ->
Comment = proplists:get_bool(return_comments, Opts),
WS = proplists:get_bool(return_white_spaces, Opts),
Txt = proplists:get_bool(text, Opts),
+ Unicode = proplists:get_bool(unicode, Opts),
#erl_scan{resword_fun = RW_fun,
comment = Comment,
ws = WS,
- text = Txt};
+ text = Txt,
+ unicode = Unicode};
options(Opt) ->
options([Opt]).
@@ -513,9 +536,9 @@ scan1([$$|Cs], St, Line, Col, Toks) ->
scan_char(Cs, St, Line, Col, Toks);
scan1([$\r|Cs], St, Line, Col, Toks) when St#erl_scan.ws ->
white_space_end(Cs, St, Line, Col, Toks, 1, "\r");
-scan1([C|Cs], St, Line, Col, Toks) when C >= $�, C =< $�, C =/= $� ->
+scan1([C|Cs], St, Line, Col, Toks) when C >= $ß, C =< $ÿ, C =/= $÷ ->
scan_atom(Cs, St, Line, Col, Toks, [C]);
-scan1([C|Cs], St, Line, Col, Toks) when C >= $�, C =< $�, C /= $� ->
+scan1([C|Cs], St, Line, Col, Toks) when C >= $À, C =< $Þ, C /= $× ->
scan_variable(Cs, St, Line, Col, Toks, [C]);
scan1([$\t|Cs], St, Line, Col, Toks) when St#erl_scan.ws ->
scan_tabs(Cs, St, Line, Col, Toks, 1);
@@ -628,15 +651,12 @@ scan1([$~|Cs], St, Line, Col, Toks) ->
scan1([$&|Cs], St, Line, Col, Toks) ->
tok2(Cs, St, Line, Col, Toks, "&", '&', 1);
%% End of optimization.
-scan1([C|Cs], St, Line, Col, Toks) when ?CHAR(C) ->
+scan1([C|Cs], St, Line, Col, Toks) when ?CHAR(C), ?UNI255(C) ->
Str = [C],
- case catch list_to_atom(Str) of
- Sym when is_atom(Sym) ->
- tok2(Cs, St, Line, Col, Toks, Str, Sym, 1);
- _ ->
- Ncol = incr_column(Col, 1),
- scan_error({illegal,character}, Line, Col, Line, Ncol, Cs)
- end;
+ tok2(Cs, St, Line, Col, Toks, Str, list_to_atom(Str), 1);
+scan1([C|Cs], _St, Line, Col, _Toks) when ?CHAR(C) ->
+ Ncol = incr_column(Col, 1),
+ scan_error({illegal,character}, Line, Col, Line, Ncol, Cs);
scan1([]=Cs, _St, Line, Col, Toks) ->
{more,{Cs,Col,Toks,Line,[],fun scan/6}};
scan1(eof=Cs, _St, Line, Col, Toks) ->
@@ -685,9 +705,9 @@ scan_name([C|Cs], Ncs) when ?DIGIT(C) ->
scan_name(Cs, [C|Ncs]);
scan_name([$@=C|Cs], Ncs) ->
scan_name(Cs, [C|Ncs]);
-scan_name([C|Cs], Ncs) when C >= $�, C =< $�, C =/= $� ->
+scan_name([C|Cs], Ncs) when C >= $ß, C =< $ÿ, C =/= $÷ ->
scan_name(Cs, [C|Ncs]);
-scan_name([C|Cs], Ncs) when C >= $�, C =< $�, C =/= $� ->
+scan_name([C|Cs], Ncs) when C >= $À, C =< $Þ, C =/= $× ->
scan_name(Cs, [C|Ncs]);
scan_name([], Ncs) ->
{more,Ncs};
@@ -834,32 +854,44 @@ scan_char([$\\|Cs]=Cs0, St, Line, Col, Toks) ->
{eof,Ncol} ->
scan_error(char, Line, Col, Line, Ncol, eof);
{nl,Val,Str,Ncs,Ncol} ->
- Attrs = attributes(Line, Col, St, "$\\"++Str),
+ Attrs = attributes(Line, Col, St, "$\\"++Str), %"
Ntoks = [{char,Attrs,Val}|Toks],
scan1(Ncs, St, Line+1, Ncol, Ntoks);
{unicode,Val,Str,Ncs,Ncol} ->
- Attrs = attributes(Line, Col, St, "$\\"++Str),
- Ntoks = [{integer,Attrs,Val}|Toks], % UNI
+ Attrs = attributes(Line, Col, St, "$\\"++Str), %"
+ Tag = char_tag(Val, St), % UNI
+ Ntoks = [{Tag,Attrs,Val}|Toks],
scan1(Ncs, St, Line, Ncol, Ntoks);
{Val,Str,Ncs,Ncol} ->
- Attrs = attributes(Line, Col, St, "$\\"++Str),
+ Attrs = attributes(Line, Col, St, "$\\"++Str), %"
Ntoks = [{char,Attrs,Val}|Toks],
scan1(Ncs, St, Line, Ncol, Ntoks)
end;
scan_char([$\n=C|Cs], St, Line, Col, Toks) ->
Attrs = attributes(Line, Col, St, [$$,C]),
scan1(Cs, St, Line+1, new_column(Col, 1), [{char,Attrs,C}|Toks]);
-scan_char([C|Cs], St, Line, Col, Toks) when ?CHAR(C) ->
- Tag = if ?UNI255(C) -> char; true -> integer end, % UNI
+scan_char([C|Cs], St, Line, Col, Toks) when ?UNICODE(C) ->
+ Tag = char_tag(C, St), % UNI
Attrs = attributes(Line, Col, St, [$$,C]),
scan1(Cs, St, Line, incr_column(Col, 2), [{Tag,Attrs,C}|Toks]);
+scan_char([C|_Cs], _St, Line, Col, _Toks) when ?CHAR(C) ->
+ scan_error({illegal,character}, Line, Col, Line, incr_column(Col, 1), eof);
scan_char([], _St, Line, Col, Toks) ->
{more,{[$$],Col,Toks,Line,[],fun scan/6}};
scan_char(eof, _St, Line, Col, _Toks) ->
scan_error(char, Line, Col, Line, incr_column(Col, 1), eof).
+-compile({inline,[char_tag/2]}).
+
+char_tag(C, _St) when ?UNI255(C) ->
+ char;
+char_tag(_C, #erl_scan{unicode = true}) ->
+ char;
+char_tag(_C, _St) ->
+ integer.
+
scan_string(Cs, St, Line, Col, Toks, {Wcs,Str,Line0,Col0,Uni0}) ->
- case scan_string0(Cs, St, Line, Col, $\", Str, Wcs, Uni0) of
+ case scan_string0(Cs, St, Line, Col, $\", true, Str, Wcs, Uni0) of %"
{more,Ncs,Nline,Ncol,Nstr,Nwcs,Uni} ->
State = {Nwcs,Nstr,Line0,Col0,Uni},
{more,{Ncs,Ncol,Toks,Nline,State,fun scan_string/6}};
@@ -867,8 +899,9 @@ scan_string(Cs, St, Line, Col, Toks, {Wcs,Str,Line0,Col0,Uni0}) ->
scan_error(Error, Nline, Ncol, Nline, EndCol, Ncs);
{error,Nline,Ncol,Nwcs,Ncs} ->
Estr = string:substr(Nwcs, 1, 16), % Expanded escape chars.
- scan_error({string,$\",Estr}, Line0, Col0, Nline, Ncol, Ncs);
- {Ncs,Nline,Ncol,Nstr,Nwcs,?NO_UNICODE} ->
+ scan_error({string,$\",Estr}, Line0, Col0, Nline, Ncol, Ncs); %"
+ {Ncs,Nline,Ncol,Nstr,Nwcs,Uni} when Uni =:= ?NO_UNICODE;
+ St#erl_scan.unicode ->
Attrs = attributes(Line0, Col0, St, Nstr),
scan1(Ncs, St, Nline, Ncol, [{string,Attrs,Nwcs}|Toks]);
{Ncs,Nline,Ncol,Nstr,_Nwcs,_Uni} ->
@@ -920,7 +953,8 @@ unicode_tokens(Line, Col, Str, Val, St, Toks, Cs, Cline, Ccol) ->
[{',',attributes(Cline, Ccol, St, "")} || Cs =/= "\""] ++ [Token|Toks].
scan_qatom(Cs, St, Line, Col, Toks, {Wcs,Str,Line0,Col0,Uni0}) ->
- case scan_string0(Cs, St, Line, Col, $\', Str, Wcs, Uni0) of
+ AllowUni = St#erl_scan.unicode,
+ case scan_string0(Cs, St, Line, Col, $\', AllowUni, Str, Wcs, Uni0) of %'
{more,Ncs,Nline,Ncol,Nstr,Nwcs,Uni} ->
State = {Nwcs,Nstr,Line0,Col0,Uni},
{more,{Ncs,Ncol,Toks,Nline,State,fun scan_qatom/6}};
@@ -928,8 +962,9 @@ scan_qatom(Cs, St, Line, Col, Toks, {Wcs,Str,Line0,Col0,Uni0}) ->
scan_error(Error, Nline, Ncol, Nline, EndCol, Ncs);
{error,Nline,Ncol,Nwcs,Ncs} ->
Estr = string:substr(Nwcs, 1, 16), % Expanded escape chars.
- scan_error({string,$\',Estr}, Line0, Col0, Nline, Ncol, Ncs);
- {Ncs,Nline,Ncol,Nstr,Nwcs,?NO_UNICODE} ->
+ scan_error({string,$\',Estr}, Line0, Col0, Nline, Ncol, Ncs); %'
+ {Ncs,Nline,Ncol,Nstr,Nwcs,Uni} ->
+ true = Uni =:= ?NO_UNICODE orelse AllowUni,
case catch list_to_atom(Nwcs) of
A when is_atom(A) ->
Attrs = attributes(Line0, Col0, St, Nstr),
@@ -939,38 +974,40 @@ scan_qatom(Cs, St, Line, Col, Toks, {Wcs,Str,Line0,Col0,Uni0}) ->
end
end.
-scan_string0(Cs, #erl_scan{text=false}, Line, no_col=Col, Q, [], Wcs, Uni) ->
- scan_string_no_col(Cs, Line, Col, Q, Wcs, Uni);
-scan_string0(Cs, #erl_scan{text=true}, Line, no_col=Col, Q, Str, Wcs, Uni) ->
- scan_string1(Cs, Line, Col, Q, Str, Wcs, Uni);
-scan_string0(Cs, _St, Line, Col, Q, [], Wcs, Uni) ->
- scan_string_col(Cs, Line, Col, Q, Wcs, Uni);
-scan_string0(Cs, _St, Line, Col, Q, Str, Wcs, Uni) ->
- scan_string1(Cs, Line, Col, Q, Str, Wcs, Uni).
+scan_string0(Cs, #erl_scan{text=false}, Line, no_col=Col, Q, U, [], Wcs, Uni) ->
+ scan_string_no_col(Cs, Line, Col, Q, U, Wcs, Uni);
+scan_string0(Cs, #erl_scan{text=true}, Line, no_col=Col, Q, U, Str, Wcs, Uni) ->
+ scan_string1(Cs, Line, Col, Q, U, Str, Wcs, Uni);
+scan_string0(Cs, _St, Line, Col, Q, U, [], Wcs, Uni) ->
+ scan_string_col(Cs, Line, Col, Q, U, Wcs, Uni);
+scan_string0(Cs, _St, Line, Col, Q, U, Str, Wcs, Uni) ->
+ scan_string1(Cs, Line, Col, Q, U, Str, Wcs, Uni).
%% Optimization. Col =:= no_col.
-scan_string_no_col([Q|Cs], Line, Col, Q, Wcs, Uni) ->
+scan_string_no_col([Q|Cs], Line, Col, Q, _U, Wcs, Uni) ->
{Cs,Line,Col,_DontCare=[],lists:reverse(Wcs),Uni};
-scan_string_no_col([$\n=C|Cs], Line, Col, Q, Wcs, Uni) ->
- scan_string_no_col(Cs, Line+1, Col, Q, [C|Wcs], Uni);
-scan_string_no_col([C|Cs], Line, Col, Q, Wcs, Uni) when C =/= $\\,
- ?CHAR(C), ?UNI255(C) ->
- scan_string_no_col(Cs, Line, Col, Q, [C|Wcs], Uni);
-scan_string_no_col(Cs, Line, Col, Q, Wcs, Uni) ->
- scan_string1(Cs, Line, Col, Q, Wcs, Wcs, Uni).
+scan_string_no_col([$\n=C|Cs], Line, Col, Q, U, Wcs, Uni) ->
+ scan_string_no_col(Cs, Line+1, Col, Q, U, [C|Wcs], Uni);
+scan_string_no_col([C|Cs], Line, Col, Q, U, Wcs, Uni) when C =/= $\\,
+ ?CHAR(C),
+ ?UNI255(C) ->
+ scan_string_no_col(Cs, Line, Col, Q, U, [C|Wcs], Uni);
+scan_string_no_col(Cs, Line, Col, Q, U, Wcs, Uni) ->
+ scan_string1(Cs, Line, Col, Q, U, Wcs, Wcs, Uni).
%% Optimization. Col =/= no_col.
-scan_string_col([Q|Cs], Line, Col, Q, Wcs0, Uni) ->
+scan_string_col([Q|Cs], Line, Col, Q, _U, Wcs0, Uni) ->
Wcs = lists:reverse(Wcs0),
Str = [Q|Wcs++[Q]],
{Cs,Line,Col+1,Str,Wcs,Uni};
-scan_string_col([$\n=C|Cs], Line, _xCol, Q, Wcs, Uni) ->
- scan_string_col(Cs, Line+1, 1, Q, [C|Wcs], Uni);
-scan_string_col([C|Cs], Line, Col, Q, Wcs, Uni) when C =/= $\\,
- ?CHAR(C), ?UNI255(C) ->
- scan_string_col(Cs, Line, Col+1, Q, [C|Wcs], Uni);
-scan_string_col(Cs, Line, Col, Q, Wcs, Uni) ->
- scan_string1(Cs, Line, Col, Q, Wcs, Wcs, Uni).
+scan_string_col([$\n=C|Cs], Line, _xCol, Q, U, Wcs, Uni) ->
+ scan_string_col(Cs, Line+1, 1, Q, U, [C|Wcs], Uni);
+scan_string_col([C|Cs], Line, Col, Q, U, Wcs, Uni) when C =/= $\\,
+ ?CHAR(C),
+ ?UNI255(C) ->
+ scan_string_col(Cs, Line, Col+1, Q, U, [C|Wcs], Uni);
+scan_string_col(Cs, Line, Col, Q, U, Wcs, Uni) ->
+ scan_string1(Cs, Line, Col, Q, U, Wcs, Wcs, Uni).
%% UNI_STR is to be replaced by STR when the Unicode-string-to-list
%% workaround is eventually removed.
@@ -981,14 +1018,14 @@ scan_string_col(Cs, Line, Col, Q, Wcs, Uni) ->
%% but then the end location of the error tuple would not correspond
%% to the start location of the returned Rest string. (Maybe the end
%% location could be modified, but that too is ugly.)
-scan_string1([Q|Cs], Line, Col, Q, Str0, Wcs0, Uni) ->
+scan_string1([Q|Cs], Line, Col, Q, _U, Str0, Wcs0, Uni) ->
Wcs = lists:reverse(Wcs0),
Str = ?UNI_STR(Col, [Q|lists:reverse(Str0, [Q])]),
{Cs,Line,incr_column(Col, 1),Str,Wcs,Uni};
-scan_string1([$\n=C|Cs], Line, Col, Q, Str, Wcs, Uni) ->
+scan_string1([$\n=C|Cs], Line, Col, Q, U, Str, Wcs, Uni) ->
Ncol = new_column(Col, 1),
- scan_string1(Cs, Line+1, Ncol, Q, ?UNI_STR(Col, [C|Str]), [C|Wcs], Uni);
-scan_string1([$\\|Cs]=Cs0, Line, Col, Q, Str, Wcs, Uni) ->
+ scan_string1(Cs, Line+1, Ncol, Q, U, ?UNI_STR(Col, [C|Str]), [C|Wcs], Uni);
+scan_string1([$\\|Cs]=Cs0, Line, Col, Q, U, Str, Wcs, Uni) ->
case scan_escape(Cs, Col) of
more ->
{more,Cs0,Line,Col,Str,Wcs,Uni};
@@ -999,31 +1036,33 @@ scan_string1([$\\|Cs]=Cs0, Line, Col, Q, Str, Wcs, Uni) ->
{nl,Val,ValStr,Ncs,Ncol} ->
Nstr = ?UNI_STR(Ncol, lists:reverse(ValStr, [$\\|Str])),
Nwcs = [Val|Wcs],
- scan_string1(Ncs, Line+1, Ncol, Q, Nstr, Nwcs, Uni);
- {unicode,_Val,_ValStr,Ncs,Ncol} when Q =:= $' -> %' Emacs
+ scan_string1(Ncs, Line+1, Ncol, Q, U, Nstr, Nwcs, Uni);
+ {unicode,_Val,_ValStr,Ncs,Ncol} when not U -> %' Emacs
{char_error,Ncs,{illegal,character},Line,Col,incr_column(Ncol, 1)};
{unicode,Val,ValStr,Ncs,Ncol} -> % UNI. Uni is set to Val.
Nstr = ?UNI_STR(Ncol, lists:reverse(ValStr, [$\\|Str])),
Nwcs = [Val|Wcs], % not used
- scan_string1(Ncs, Line, incr_column(Ncol, 1), Q, Nstr, Nwcs, Val);
+ scan_string1(Ncs, Line, incr_column(Ncol, 1), Q, U, Nstr, Nwcs, Val);
{Val,ValStr,Ncs,Ncol} ->
Nstr = ?UNI_STR(Ncol, lists:reverse(ValStr, [$\\|Str])),
Nwcs = [Val|Wcs],
- scan_string1(Ncs, Line, incr_column(Ncol, 1), Q, Nstr, Nwcs, Uni)
+ scan_string1(Ncs, Line, incr_column(Ncol, 1), Q, U, Nstr, Nwcs, Uni)
end;
-scan_string1([C|Cs], Line, no_col=Col, Q, Str, Wcs, Uni) when ?CHAR(C),
- ?UNI255(C) ->
- %% scan_string1(Cs, Line, Col, Q, Str, [C|Wcs], Uni);
- scan_string1(Cs, Line, Col, Q, [C|Str], [C|Wcs], Uni); % UNI
-scan_string1([C|Cs], Line, Col, Q, Str, Wcs, Uni) when ?CHAR(C), ?UNI255(C) ->
- scan_string1(Cs, Line, Col+1, Q, [C|Str], [C|Wcs], Uni);
-scan_string1([C|Cs], Line, Col, $', _Str, _Wcs, _Uni) when ?CHAR(C) -> %' UNI
+scan_string1([C|Cs], Line, no_col=Col, Q, U, Str, Wcs, Uni) when ?CHAR(C),
+ ?UNI255(C) ->
+ %% scan_string1(Cs, Line, Col, Q, U, Str, [C|Wcs], Uni);
+ scan_string1(Cs, Line, Col, Q, U, [C|Str], [C|Wcs], Uni); % UNI
+scan_string1([C|Cs], Line, Col, Q, U, Str, Wcs, Uni) when ?CHAR(C), ?UNI255(C) ->
+ scan_string1(Cs, Line, Col+1, Q, U, [C|Str], [C|Wcs], Uni);
+scan_string1([C|Cs], Line, Col, _Q, false, _Str, _Wcs, _Uni) when ?CHAR(C) -> %' UNI
+ {char_error,Cs,{illegal,character},Line,Col,incr_column(Col, 1)};
+scan_string1([C|Cs], Line, Col, Q, U, Str, Wcs, _Uni) when ?UNICODE(C) ->
+ scan_string1(Cs, Line, incr_column(Col, 1), Q, U, [C|Str], [C|Wcs], C);
+scan_string1([C|Cs], Line, Col, _Q, _U, _Str, _Wcs, _Uni) when ?CHAR(C) -> % UNI
{char_error,Cs,{illegal,character},Line,Col,incr_column(Col, 1)};
-scan_string1([C|Cs], Line, Col, Q, Str, Wcs, _Uni) when ?CHAR(C) -> % UNI
- scan_string1(Cs, Line, incr_column(Col, 1), Q, [C|Str], [C|Wcs], C);
-scan_string1([]=Cs, Line, Col, _Q, Str, Wcs, Uni) ->
+scan_string1([]=Cs, Line, Col, _Q, _U, Str, Wcs, Uni) ->
{more,Cs,Line,Col,Str,Wcs,Uni};
-scan_string1(eof, Line, Col, _Q, _Str, Wcs, _Uni) ->
+scan_string1(eof, Line, Col, _Q, _U, _Str, Wcs, _Uni) ->
{error,Line,Col,lists:reverse(Wcs),eof}.
-define(OCT(C), C >= $0, C =< $7).
@@ -1074,8 +1113,10 @@ scan_escape([$\n=C|Cs], Col) ->
scan_escape([C0|Cs], Col) when ?CHAR(C0), ?UNI255(C0) ->
C = escape_char(C0),
{C,?UNI_STR(Col, [C0]),Cs,incr_column(Col, 1)};
-scan_escape([C|Cs], Col) when ?CHAR(C) -> % UNI
+scan_escape([C|Cs], Col) when ?UNICODE(C) ->
{unicode,C,?UNI_STR(Col, [C]),Cs,incr_column(Col, 1)};
+scan_escape([C|Cs], Col) when ?CHAR(C) -> % UNI
+ {error,Cs,{illegal,character},incr_column(Col, 1)};
scan_escape([], _Col) ->
more;
scan_escape(eof, Col) ->
@@ -1093,7 +1134,7 @@ scan_esc_end([$}|Cs], Col, Wcs0, B, Str0) ->
case catch erlang:list_to_integer(Wcs, B) of
Val when Val =< 16#FF ->
{Val,?UNI_STR(Col, Str0++Wcs++[$}]),Cs,incr_column(Col, 1)};
- Val when Val =< 16#10FFFF ->
+ Val when ?UNICODE(Val) ->
{unicode,Val,?UNI_STR(Col, Str0++Wcs++[$}]),Cs,incr_column(Col,1)};
_ ->
{error,Cs,{illegal,character},incr_column(Col, 1)}
@@ -1199,18 +1240,36 @@ float_end(Cs, St, Line, Col, Toks, Ncs0) ->
scan_error({illegal,float}, Line, Col, Line, Ncol, Cs)
end.
-skip_comment([C|Cs], St, Line, Col, Toks, N) when C =/= $\n, ?CHAR(C) ->
- skip_comment(Cs, St, Line, Col, Toks, N+1);
-skip_comment([]=Cs, _St, Line, Col, Toks, N) ->
- {more,{Cs,Col,Toks,Line,N,fun skip_comment/6}};
skip_comment(Cs, St, Line, Col, Toks, N) ->
+ skip_comment(Cs, St, Line, Col, Toks, N, St#erl_scan.unicode).
+
+skip_comment([C|Cs], St, Line, Col, Toks, N, U) when C =/= $\n, ?CHAR(C) ->
+ case ?UNI255(C) orelse U andalso ?UNICODE(C) of
+ true ->
+ skip_comment(Cs, St, Line, Col, Toks, N+1, U);
+ false ->
+ Ncol = incr_column(Col, N+1),
+ scan_error({illegal,character}, Line, Col, Line, Ncol, Cs)
+ end;
+skip_comment([]=Cs, _St, Line, Col, Toks, N, _U) ->
+ {more,{Cs,Col,Toks,Line,N,fun skip_comment/6}};
+skip_comment(Cs, St, Line, Col, Toks, N, _U) ->
scan1(Cs, St, Line, incr_column(Col, N), Toks).
-scan_comment([C|Cs], St, Line, Col, Toks, Ncs) when C =/= $\n, ?CHAR(C) ->
- scan_comment(Cs, St, Line, Col, Toks, [C|Ncs]);
-scan_comment([]=Cs, _St, Line, Col, Toks, Ncs) ->
+scan_comment(Cs, St, Line, Col, Toks, Ncs) ->
+ scan_comment(Cs, St, Line, Col, Toks, Ncs, St#erl_scan.unicode).
+
+scan_comment([C|Cs], St, Line, Col, Toks, Ncs, U) when C =/= $\n, ?CHAR(C) ->
+ case ?UNI255(C) orelse U andalso ?UNICODE(C) of
+ true ->
+ scan_comment(Cs, St, Line, Col, Toks, [C|Ncs], U);
+ false ->
+ Ncol = incr_column(Col, length(Ncs)+1),
+ scan_error({illegal,character}, Line, Col, Line, Ncol, Cs)
+ end;
+scan_comment([]=Cs, _St, Line, Col, Toks, Ncs, _U) ->
{more,{Cs,Col,Toks,Line,Ncs,fun scan_comment/6}};
-scan_comment(Cs, St, Line, Col, Toks, Ncs0) ->
+scan_comment(Cs, St, Line, Col, Toks, Ncs0, _U) ->
Ncs = lists:reverse(Ncs0),
tok3(Cs, St, Line, Col, Toks, comment, Ncs, Ncs).
diff --git a/lib/stdlib/src/escript.erl b/lib/stdlib/src/escript.erl
index 498d850df3..99a9d138ac 100644
--- a/lib/stdlib/src/escript.erl
+++ b/lib/stdlib/src/escript.erl
@@ -710,7 +710,7 @@ epp_parse_file2(Epp, S, Forms, Parsed) ->
epp_parse_file(Epp, S, [Form | Forms])
end;
{error,{Ln,Mod,Args}} = Form ->
- io:format("~s:~w: ~s\n",
+ io:format("~s:~w: ~ts\n",
[S#state.file,Ln,Mod:format_error(Args)]),
epp_parse_file(Epp, S#state{n_errors = S#state.n_errors + 1}, [Form | Forms]);
{eof, _LastLine} = Eof ->
@@ -780,10 +780,10 @@ report_errors(Errors) ->
Errors).
list_errors(F, [{Line,Mod,E}|Es]) ->
- io:fwrite("~s:~w: ~s\n", [F,Line,Mod:format_error(E)]),
+ io:fwrite("~s:~w: ~ts\n", [F,Line,Mod:format_error(E)]),
list_errors(F, Es);
list_errors(F, [{Mod,E}|Es]) ->
- io:fwrite("~s: ~s\n", [F,Mod:format_error(E)]),
+ io:fwrite("~s: ~ts\n", [F,Mod:format_error(E)]),
list_errors(F, Es);
list_errors(_F, []) -> ok.
@@ -795,10 +795,10 @@ report_warnings(Ws0) ->
lists:foreach(fun({_,Str}) -> io:put_chars(Str) end, Ws).
format_message(F, [{Line,Mod,E}|Es]) ->
- M = {{F,Line},io_lib:format("~s:~w: Warning: ~s\n", [F,Line,Mod:format_error(E)])},
+ M = {{F,Line},io_lib:format("~s:~w: Warning: ~ts\n", [F,Line,Mod:format_error(E)])},
[M|format_message(F, Es)];
format_message(F, [{Mod,E}|Es]) ->
- M = {none,io_lib:format("~s: Warning: ~s\n", [F,Mod:format_error(E)])},
+ M = {none,io_lib:format("~s: Warning: ~ts\n", [F,Mod:format_error(E)])},
[M|format_message(F, Es)];
format_message(_, []) -> [].
@@ -851,12 +851,27 @@ eval_exprs([E|Es], Bs0, Lf, Ef, RBs) ->
eval_exprs(Es, Bs, Lf, Ef, RBs).
format_exception(Class, Reason) ->
+ Enc = encoding(),
+ P = case Enc of
+ latin1 -> "P";
+ _ -> "tP"
+ end,
PF = fun(Term, I) ->
- io_lib:format("~." ++ integer_to_list(I) ++ "P", [Term, 50])
+ io_lib:format("~." ++ integer_to_list(I) ++ P, [Term, 50])
end,
StackTrace = erlang:get_stacktrace(),
StackFun = fun(M, _F, _A) -> (M =:= erl_eval) or (M =:= ?MODULE) end,
- lib:format_exception(1, Class, Reason, StackTrace, StackFun, PF).
+ lib:format_exception(1, Class, Reason, StackTrace, StackFun, PF, Enc).
+
+encoding() ->
+ [{encoding, Encoding}] = enc(),
+ Encoding.
+
+enc() ->
+ case lists:keyfind(encoding, 1, io:getopts()) of
+ false -> [{encoding,latin1}]; % should never happen
+ Enc -> [Enc]
+ end.
fatal(Str) ->
throw(Str).
diff --git a/lib/stdlib/src/ets.erl b/lib/stdlib/src/ets.erl
index ee6cff1b75..61bb038737 100644
--- a/lib/stdlib/src/ets.erl
+++ b/lib/stdlib/src/ets.erl
@@ -42,7 +42,7 @@
-export([i/0, i/1, i/2, i/3]).
--export_type([tab/0, tid/0, match_spec/0, comp_match_spec/0]).
+-export_type([tab/0, tid/0, match_spec/0, comp_match_spec/0, match_pattern/0]).
%%-----------------------------------------------------------------------------
diff --git a/lib/stdlib/src/filename.erl b/lib/stdlib/src/filename.erl
index a6b42cc68c..0c50eb34e6 100644
--- a/lib/stdlib/src/filename.erl
+++ b/lib/stdlib/src/filename.erl
@@ -69,7 +69,7 @@ absname(Name) ->
-spec absname(Filename, Dir) -> file:filename() when
Filename :: file:name(),
- Dir :: file:filename().
+ Dir :: file:name().
absname(Name, AbsBase) when is_binary(Name), is_list(AbsBase) ->
absname(Name,filename_string_to_binary(AbsBase));
absname(Name, AbsBase) when is_list(Name), is_binary(AbsBase) ->
@@ -123,7 +123,7 @@ absname_vr([[X, $:]|Name], _, _AbsBase) ->
%% AbsBase must be absolute and Name must be relative.
-spec absname_join(Dir, Filename) -> file:filename() when
- Dir :: file:filename(),
+ Dir :: file:name(),
Filename :: file:name().
absname_join(AbsBase, Name) ->
join(AbsBase, flatten(Name)).
@@ -388,7 +388,7 @@ extension([], Result, _OsType) ->
%% Joins a list of filenames with directory separators.
-spec join(Components) -> file:filename() when
- Components :: [file:filename()].
+ Components :: [file:name()].
join([Name1, Name2|Rest]) ->
join([join(Name1, Name2)|Rest]);
join([Name]) when is_list(Name) ->
@@ -401,8 +401,8 @@ join([Name]) when is_atom(Name) ->
%% Joins two filenames with directory separators.
-spec join(Name1, Name2) -> file:filename() when
- Name1 :: file:filename(),
- Name2 :: file:filename().
+ Name1 :: file:name(),
+ Name2 :: file:name().
join(Name1, Name2) when is_list(Name1), is_list(Name2) ->
OsType = major_os_type(),
case pathtype(Name2) of
@@ -624,7 +624,7 @@ rootname2([Char|Rest], Ext, Result) when is_integer(Char) ->
-spec split(Filename) -> Components when
Filename :: file:name(),
- Components :: [file:filename()].
+ Components :: [file:name()].
split(Name) when is_binary(Name) ->
case os:type() of
{win32, _} -> win32_splitb(Name);
@@ -718,7 +718,7 @@ split([], Comp, Components, OsType) ->
%% name will be normalized as done by join/1.
-spec nativename(Path) -> file:filename() when
- Path :: file:filename().
+ Path :: file:name().
nativename(Name0) ->
Name = join([Name0]), %Normalize.
case os:type() of
@@ -878,7 +878,7 @@ filter_options(_Base, [], Result) ->
%% Gets the source file given path of object code and module name.
get_source_file(Obj, Mod, Rules) ->
- source_by_rules(dirname(Obj), packages:last(Mod), Rules).
+ source_by_rules(dirname(Obj), atom_to_list(Mod), Rules).
source_by_rules(Dir, Base, [{From, To}|Rest]) ->
case try_rule(Dir, Base, From, To) of
@@ -915,10 +915,8 @@ make_abs_path(BasePath, Path) ->
join(BasePath, Path).
major_os_type() ->
- case os:type() of
- {OsT, _} -> OsT;
- OsT -> OsT
- end.
+ {OsT, _} = os:type(),
+ OsT.
%% flatten(List)
%% Flatten a list, also accepting atoms.
diff --git a/lib/stdlib/src/gb_sets.erl b/lib/stdlib/src/gb_sets.erl
index 91d21d869c..ba35a7170a 100644
--- a/lib/stdlib/src/gb_sets.erl
+++ b/lib/stdlib/src/gb_sets.erl
@@ -1,7 +1,8 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -165,7 +166,7 @@
-export([new/0, is_element/2, add_element/2, del_element/2,
subtract/2]).
-%% GB-trees adapted from Sven-Olof Nystr�m's implementation for
+%% GB-trees adapted from Sven-Olof Nyström's implementation for
%% representation of sets.
%%
%% Data structures:
@@ -196,6 +197,8 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Some types.
+-export_type([iter/0]).
+
-type gb_set_node() :: 'nil' | {term(), _, _}.
-opaque iter() :: [gb_set_node()].
diff --git a/lib/stdlib/src/gb_trees.erl b/lib/stdlib/src/gb_trees.erl
index 6ad861ff5b..de0c239e26 100644
--- a/lib/stdlib/src/gb_trees.erl
+++ b/lib/stdlib/src/gb_trees.erl
@@ -1,7 +1,8 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -19,7 +20,7 @@
%% =====================================================================
%% General Balanced Trees - highly efficient dictionaries.
%%
-%% Copyright (C) 1999-2001 Sven-Olof Nystr�m, Richard Carlsson
+%% Copyright (C) 1999-2001 Sven-Olof Nyström, Richard Carlsson
%%
%% An efficient implementation of Prof. Arne Andersson's General
%% Balanced Trees. These have no storage overhead compared to plain
@@ -152,6 +153,8 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Some types.
+-export_type([iter/0]).
+
-type gb_tree_node() :: 'nil' | {_, _, _, _}.
-opaque iter() :: [gb_tree_node()].
diff --git a/lib/stdlib/src/io.erl b/lib/stdlib/src/io.erl
index 9f65bbfa3a..ecf2aeb375 100644
--- a/lib/stdlib/src/io.erl
+++ b/lib/stdlib/src/io.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -22,28 +22,28 @@
get_chars/2,get_chars/3,get_line/1,get_line/2,
get_password/0, get_password/1,
setopts/1, setopts/2, getopts/0, getopts/1]).
--export([write/1,write/2,read/1,read/2,read/3]).
+-export([write/1,write/2,read/1,read/2,read/3,read/4]).
-export([columns/0,columns/1,rows/0,rows/1]).
-export([fwrite/1,fwrite/2,fwrite/3,fread/2,fread/3,
format/1,format/2,format/3]).
--export([scan_erl_exprs/1,scan_erl_exprs/2,scan_erl_exprs/3,
- scan_erl_form/1,scan_erl_form/2,scan_erl_form/3,
+-export([scan_erl_exprs/1,scan_erl_exprs/2,scan_erl_exprs/3,scan_erl_exprs/4,
+ scan_erl_form/1,scan_erl_form/2,scan_erl_form/3,scan_erl_form/4,
parse_erl_exprs/1,parse_erl_exprs/2,parse_erl_exprs/3,
- parse_erl_form/1,parse_erl_form/2,parse_erl_form/3]).
+ parse_erl_exprs/4,parse_erl_form/1,parse_erl_form/2,
+ parse_erl_form/3,parse_erl_form/4]).
-export([request/1,request/2,requests/1,requests/2]).
--export_type([device/0, format/0]).
+-export_type([device/0, format/0, server_no_data/0]).
%%-------------------------------------------------------------------------
-type device() :: atom() | pid().
-type prompt() :: atom() | string().
--type error_description() :: term(). % Whatever the io-server sends.
--type request_error() :: {'error',error_description()}.
+%% ErrorDescription is whatever the I/O-server sends.
+-type server_no_data() :: {'error', ErrorDescription :: term()} | 'eof'.
-%% XXX: Some uses of line() in this file may need to read erl_scan:location()
--type line() :: pos_integer().
+-type location() :: erl_scan:location().
%%-------------------------------------------------------------------------
@@ -73,9 +73,9 @@ o_request(Io, Request, Func) ->
put_chars(Chars) ->
put_chars(default_output(), Chars).
--spec put_chars(IoDevice, IoData) -> 'ok' when
+-spec put_chars(IoDevice, CharData) -> 'ok' when
IoDevice :: device(),
- IoData :: unicode:chardata().
+ CharData :: unicode:chardata().
put_chars(Io, Chars) ->
o_request(Io, {put_chars,unicode,Chars}, put_chars).
@@ -124,7 +124,7 @@ rows(Io) ->
{error,enotsup}
end.
--spec get_chars(Prompt, Count) -> Data | 'eof' when
+-spec get_chars(Prompt, Count) -> Data | server_no_data() when
Prompt :: prompt(),
Count :: non_neg_integer(),
Data :: [unicode:unicode_char()] | unicode:unicode_binary().
@@ -132,25 +132,23 @@ rows(Io) ->
get_chars(Prompt, N) ->
get_chars(default_input(), Prompt, N).
--spec get_chars(IoDevice, Prompt, Count) -> Data | 'eof' | {error, Reason} when
+-spec get_chars(IoDevice, Prompt, Count) -> Data | server_no_data() when
IoDevice :: device(),
Prompt :: prompt(),
Count :: non_neg_integer(),
- Reason :: term(),
Data :: [unicode:unicode_char()] | unicode:unicode_binary().
get_chars(Io, Prompt, N) when is_integer(N), N >= 0 ->
request(Io, {get_chars,unicode,Prompt,N}).
--spec get_line(Prompt) -> Data | 'eof' | {'error', Reason} when
+-spec get_line(Prompt) -> Data | server_no_data() when
Prompt :: prompt(),
- Reason :: term(),
Data :: [unicode:unicode_char()] | unicode:unicode_binary().
get_line(Prompt) ->
get_line(default_input(), Prompt).
--spec get_line(IoDevice, Prompt) -> Data | 'eof' | {'error', term()} when
+-spec get_line(IoDevice, Prompt) -> Data | server_no_data() when
IoDevice :: device(),
Prompt :: prompt(),
Data :: [unicode:unicode_char()] | unicode:unicode_binary().
@@ -219,8 +217,9 @@ write(Io, Term) ->
-spec read(Prompt) -> Result when
Prompt :: prompt(),
Result :: {'ok', Term :: term()}
- | 'eof'
- | {'error', ErrorInfo :: erl_scan:error_info()}.
+ | server_no_data()
+ | {'error', ErrorInfo},
+ ErrorInfo :: erl_scan:error_info() | erl_parse:error_info().
% Read does not use get_until as erl_scan does not work with unicode
% XXX:PaN fixme?
@@ -231,8 +230,9 @@ read(Prompt) ->
IoDevice :: device(),
Prompt :: prompt(),
Result :: {'ok', Term :: term()}
- | 'eof'
- | {'error', ErrorInfo :: erl_scan:error_info()}.
+ | server_no_data()
+ | {'error', ErrorInfo},
+ ErrorInfo :: erl_scan:error_info() | erl_parse:error_info().
read(Io, Prompt) ->
case request(Io, {get_until,unicode,Prompt,erl_scan,tokens,[1]}) of
@@ -248,24 +248,41 @@ read(Io, Prompt) ->
Other
end.
--spec read(IoDevice, Prompt, StartLine) -> Result when
+-spec read(IoDevice, Prompt, StartLocation) -> Result when
+ IoDevice :: device(),
+ Prompt :: prompt(),
+ StartLocation :: location(),
+ Result :: {'ok', Term :: term(), EndLocation :: location()}
+ | {'eof', EndLocation :: location()}
+ | server_no_data()
+ | {'error', ErrorInfo, ErrorLocation :: location()},
+ ErrorInfo :: erl_scan:error_info() | erl_parse:error_info().
+
+read(Io, Prompt, Pos0) ->
+ read(Io, Prompt, Pos0, []).
+
+-spec read(IoDevice, Prompt, StartLocation, Options) -> Result when
IoDevice :: device(),
Prompt :: prompt(),
- StartLine :: line(),
- Result :: {'ok', Term :: term(), EndLine :: line()}
- | {'eof', EndLine :: line()}
- | {'error', ErrorInfo :: erl_scan:error_info(), ErrorLine :: line()}.
-
-read(Io, Prompt, StartLine) when is_integer(StartLine) ->
- case request(Io, {get_until,unicode,Prompt,erl_scan,tokens,[StartLine]}) of
- {ok,Toks,EndLine} ->
+ StartLocation :: location(),
+ Options :: erl_scan:options(),
+ Result :: {'ok', Term :: term(), EndLocation :: location()}
+ | {'eof', EndLocation :: location()}
+ | server_no_data()
+ | {'error', ErrorInfo, ErrorLocation :: location()},
+ ErrorInfo :: erl_scan:error_info() | erl_parse:error_info().
+
+read(Io, Prompt, Pos0, Options) ->
+ Args = [Pos0,Options],
+ case request(Io, {get_until,unicode,Prompt,erl_scan,tokens,Args}) of
+ {ok,Toks,EndLocation} ->
case erl_parse:parse_term(Toks) of
- {ok,Term} -> {ok,Term,EndLine};
- {error,ErrorInfo} -> {error,ErrorInfo,EndLine}
+ {ok,Term} -> {ok,Term,EndLocation};
+ {error,ErrorInfo} -> {error,ErrorInfo,EndLocation}
end;
- {error,_E,_EndLine} = Error ->
+ {error,_E,_EndLocation} = Error ->
Error;
- {eof,_EndLine} = Eof ->
+ {eof,_EndLocation} = Eof ->
Eof;
Other ->
Other
@@ -313,7 +330,9 @@ fread(Prompt, Format) ->
IoDevice :: device(),
Prompt :: prompt(),
Format :: format(),
- Result :: {'ok', Terms :: [term()]} | 'eof' | {'error', What :: term()}.
+ Result :: {'ok', Terms :: [term()]}
+ | {'error', FreadError :: io_lib:fread_error()}
+ | server_no_data().
fread(Io, Prompt, Format) ->
case request(Io, {fread,Prompt,Format}) of
@@ -348,7 +367,7 @@ format(Io, Format, Args) ->
-spec scan_erl_exprs(Prompt) -> Result when
Prompt :: prompt(),
- Result :: erl_scan:tokens_result() | request_error().
+ Result :: erl_scan:tokens_result() | server_no_data().
scan_erl_exprs(Prompt) ->
scan_erl_exprs(default_input(), Prompt, 1).
@@ -356,23 +375,33 @@ scan_erl_exprs(Prompt) ->
-spec scan_erl_exprs(Device, Prompt) -> Result when
Device :: device(),
Prompt :: prompt(),
- Result :: erl_scan:tokens_result() | request_error().
+ Result :: erl_scan:tokens_result() | server_no_data().
scan_erl_exprs(Io, Prompt) ->
scan_erl_exprs(Io, Prompt, 1).
--spec scan_erl_exprs(Device, Prompt, StartLine) -> Result when
+-spec scan_erl_exprs(Device, Prompt, StartLocation) -> Result when
Device :: device(),
Prompt :: prompt(),
- StartLine :: line(),
- Result :: erl_scan:tokens_result() | request_error().
+ StartLocation :: location(),
+ Result :: erl_scan:tokens_result() | server_no_data().
scan_erl_exprs(Io, Prompt, Pos0) ->
- request(Io, {get_until,unicode,Prompt,erl_scan,tokens,[Pos0]}).
+ scan_erl_exprs(Io, Prompt, Pos0, []).
+
+-spec scan_erl_exprs(Device, Prompt, StartLocation, Options) -> Result when
+ Device :: device(),
+ Prompt :: prompt(),
+ StartLocation :: location(),
+ Options :: erl_scan:options(),
+ Result :: erl_scan:tokens_result() | server_no_data().
+
+scan_erl_exprs(Io, Prompt, Pos0, Options) ->
+ request(Io, {get_until,unicode,Prompt,erl_scan,tokens,[Pos0,Options]}).
-spec scan_erl_form(Prompt) -> Result when
Prompt :: prompt(),
- Result :: erl_scan:tokens_result() | request_error().
+ Result :: erl_scan:tokens_result() | server_no_data().
scan_erl_form(Prompt) ->
scan_erl_form(default_input(), Prompt, 1).
@@ -380,26 +409,41 @@ scan_erl_form(Prompt) ->
-spec scan_erl_form(IoDevice, Prompt) -> Result when
IoDevice :: device(),
Prompt :: prompt(),
- Result :: erl_scan:tokens_result() | request_error().
+ Result :: erl_scan:tokens_result() | server_no_data().
scan_erl_form(Io, Prompt) ->
scan_erl_form(Io, Prompt, 1).
--spec scan_erl_form(IoDevice, Prompt, StartLine) -> Result when
+-spec scan_erl_form(IoDevice, Prompt, StartLocation) -> Result when
IoDevice :: device(),
Prompt :: prompt(),
- StartLine :: line(),
- Result :: erl_scan:tokens_result() | request_error().
+ StartLocation :: location(),
+ Result :: erl_scan:tokens_result() | server_no_data().
scan_erl_form(Io, Prompt, Pos0) ->
- request(Io, {get_until,unicode,Prompt,erl_scan,tokens,[Pos0]}).
+ scan_erl_form(Io, Prompt, Pos0, []).
+
+-spec scan_erl_form(IoDevice, Prompt, StartLocation, Options) -> Result when
+ IoDevice :: device(),
+ Prompt :: prompt(),
+ StartLocation :: location(),
+ Options :: erl_scan:options(),
+ Result :: erl_scan:tokens_result() | server_no_data().
+
+scan_erl_form(Io, Prompt, Pos0, Options) ->
+ request(Io, {get_until,unicode,Prompt,erl_scan,tokens,[Pos0,Options]}).
%% Parsing Erlang code.
--type parse_ret() :: {'ok', ExprList :: erl_parse:abstract_expr(), EndLine :: line()}
- | {'eof', EndLine :: line()}
- | {'error', ErrorInfo :: erl_scan:error_info(), ErrorLine :: line()}
- | request_error().
+-type parse_ret() :: {'ok',
+ ExprList :: erl_parse:abstract_expr(),
+ EndLocation :: location()}
+ | {'eof', EndLocation :: location()}
+ | {'error',
+ ErrorInfo :: erl_scan:error_info()
+ | erl_parse:error_info(),
+ ErrorLocation :: location()}
+ | server_no_data().
-spec parse_erl_exprs(Prompt) -> Result when
Prompt :: prompt(),
@@ -416,14 +460,24 @@ parse_erl_exprs(Prompt) ->
parse_erl_exprs(Io, Prompt) ->
parse_erl_exprs(Io, Prompt, 1).
--spec parse_erl_exprs(IoDevice, Prompt, StartLine) -> Result when
+-spec parse_erl_exprs(IoDevice, Prompt, StartLocation) -> Result when
IoDevice :: device(),
Prompt :: prompt(),
- StartLine :: line(),
+ StartLocation :: location(),
Result :: parse_ret().
parse_erl_exprs(Io, Prompt, Pos0) ->
- case request(Io, {get_until,unicode,Prompt,erl_scan,tokens,[Pos0]}) of
+ parse_erl_exprs(Io, Prompt, Pos0, []).
+
+-spec parse_erl_exprs(IoDevice, Prompt, StartLocation, Options) -> Result when
+ IoDevice :: device(),
+ Prompt :: prompt(),
+ StartLocation :: location(),
+ Options :: erl_scan:options(),
+ Result :: parse_ret().
+
+parse_erl_exprs(Io, Prompt, Pos0, Options) ->
+ case request(Io, {get_until,unicode,Prompt,erl_scan,tokens,[Pos0,Options]}) of
{ok,Toks,EndPos} ->
case erl_parse:parse_exprs(Toks) of
{ok,Exprs} -> {ok,Exprs,EndPos};
@@ -433,10 +487,15 @@ parse_erl_exprs(Io, Prompt, Pos0) ->
Other
end.
--type parse_form_ret() :: {'ok', AbsForm :: erl_parse:abstract_form(), EndLine :: line()}
- | {'eof', EndLine :: line()}
- | {'error', ErrorInfo :: erl_scan:error_info(), ErrorLine :: line()}
- | request_error().
+-type parse_form_ret() :: {'ok',
+ AbsForm :: erl_parse:abstract_form(),
+ EndLocation :: location()}
+ | {'eof', EndLocation :: location()}
+ | {'error',
+ ErrorInfo :: erl_scan:error_info()
+ | erl_parse:error_info(),
+ ErrorLocation :: location()}
+ | server_no_data().
-spec parse_erl_form(Prompt) -> Result when
Prompt :: prompt(),
@@ -453,14 +512,25 @@ parse_erl_form(Prompt) ->
parse_erl_form(Io, Prompt) ->
parse_erl_form(Io, Prompt, 1).
--spec parse_erl_form(IoDevice, Prompt, StartLine) -> Result when
+-spec parse_erl_form(IoDevice, Prompt, StartLocation) -> Result when
IoDevice :: device(),
Prompt :: prompt(),
- StartLine :: line(),
+ StartLocation :: location(),
Result :: parse_form_ret().
parse_erl_form(Io, Prompt, Pos0) ->
- case request(Io, {get_until,unicode,Prompt,erl_scan,tokens,[Pos0]}) of
+ parse_erl_form(Io, Prompt, Pos0, []).
+
+-spec parse_erl_form(IoDevice, Prompt, StartLocation, Options) -> Result when
+ IoDevice :: device(),
+ Prompt :: prompt(),
+ StartLocation :: location(),
+ Options :: erl_scan:options(),
+ Result :: parse_form_ret().
+
+parse_erl_form(Io, Prompt, Pos0, Options) ->
+ Args = [Pos0, Options],
+ case request(Io, {get_until,unicode,Prompt,erl_scan,tokens,Args}) of
{ok,Toks,EndPos} ->
case erl_parse:parse_form(Toks) of
{ok,Exprs} -> {ok,Exprs,EndPos};
diff --git a/lib/stdlib/src/io_lib.erl b/lib/stdlib/src/io_lib.erl
index ab62b72519..5ad505f683 100644
--- a/lib/stdlib/src/io_lib.erl
+++ b/lib/stdlib/src/io_lib.erl
@@ -1,3 +1,4 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
@@ -46,25 +47,28 @@
%% 173 - 176 { - ~ punctuation
%% 177 DEL control
%% 200 - 237 control
-%% 240 - 277 NBSP - � punctuation
-%% 300 - 326 � - � uppercase
-%% 327 � punctuation
-%% 330 - 336 � - � uppercase
-%% 337 - 366 � - � lowercase
-%% 367 � punctuation
-%% 370 - 377 � - � lowercase
+%% 240 - 277 NBSP - ¿ punctuation
+%% 300 - 326 À - Ö uppercase
+%% 327 × punctuation
+%% 330 - 336 Ø - Þ uppercase
+%% 337 - 366 ß - ö lowercase
+%% 367 ÷ punctuation
+%% 370 - 377 ø - ÿ lowercase
%%
%% Many punctuation characters region have special meaning. Must
-%% watch using � \327, very close to x \170
+%% watch using × \327, very close to x \170
-module(io_lib).
-export([fwrite/2,fread/2,fread/3,format/2]).
-export([print/1,print/4,indentation/2]).
--export([write/1,write/2,write/3,nl/0,format_prompt/1]).
+-export([write/1,write/2,write/3,nl/0,format_prompt/1,format_prompt/2]).
-export([write_atom/1,write_string/1,write_string/2,write_unicode_string/1,
- write_unicode_string/2, write_char/1, write_unicode_char/1]).
+ write_unicode_string/2, write_char/1, write_unicode_char/1]).
+
+-export([write_unicode_string_as_latin1/1, write_unicode_string_as_latin1/2,
+ write_unicode_char_as_latin1/1]).
-export([quote_atom/2, char_list/1, unicode_char_list/1,
deep_char_list/1, deep_unicode_char_list/1,
@@ -75,11 +79,14 @@
collect_line/2, collect_line/3, collect_line/4,
get_until/3, get_until/4]).
--export_type([chars/0, continuation/0]).
+-export_type([chars/0, unicode_chars/0, unicode_string/0, continuation/0,
+ fread_error/0]).
%%----------------------------------------------------------------------
-type chars() :: [char() | chars()].
+-type unicode_chars() :: [unicode:unicode_char() | unicode_chars()].
+-type unicode_string() :: [unicode:unicode_char()].
-type depth() :: -1 | non_neg_integer().
-opaque continuation() :: {Format :: string(),
@@ -87,6 +94,16 @@
Nchars :: non_neg_integer(),
Results :: [term()]}.
+-type fread_error() :: 'atom'
+ | 'based'
+ | 'character'
+ | 'float'
+ | 'format'
+ | 'input'
+ | 'integer'
+ | 'string'
+ | 'unsigned'.
+
%%----------------------------------------------------------------------
%% Interface calls to sub-modules.
@@ -107,7 +124,7 @@ fwrite(Format, Args) ->
| {'more', RestFormat :: string(),
Nchars :: non_neg_integer(),
InputStack :: chars()}
- | {'error', What :: term()}.
+ | {'error', What :: fread_error()}.
fread(Chars, Format) ->
io_lib_fread:fread(Chars, Format).
@@ -120,7 +137,7 @@ fread(Chars, Format) ->
| {'done', Result, LeftOverChars :: string()},
Result :: {'ok', InputList :: [term()]}
| 'eof'
- | {'error', What :: term()}.
+ | {'error', What :: fread_error()}.
fread(Cont, Chars, Format) ->
io_lib_fread:fread(Cont, Chars, Format).
@@ -162,27 +179,34 @@ indentation(Chars, Current) ->
%% Format an IO-request prompt (handles formatting errors safely).
-%% Atoms, binaries, and iolists can be used as-is, and will be
-%% printed without any additional quotes.
-%% Note that the output is a deep string, and not an iolist (i.e.,
-%% it may be deep, but never contains binaries, due to the "~s").
+%% Atoms, binaries, and iolists (or unicode:charlist()) can be used
+%% as-is, and will be printed without any additional quotes.
-spec format_prompt(term()) -> chars().
-format_prompt({format,Format,Args}) ->
- format_prompt(Format,Args);
-format_prompt(Prompt)
- when is_list(Prompt); is_atom(Prompt); is_binary(Prompt) ->
- format_prompt("~ts", [Prompt]);
format_prompt(Prompt) ->
- format_prompt("~tp", [Prompt]).
+ format_prompt(Prompt, latin1).
+
+-spec format_prompt(term(), atom()) -> chars().
-format_prompt(Format, Args) ->
+format_prompt({format,Format,Args}, _Encoding) ->
+ do_format_prompt(Format, Args);
+format_prompt(Prompt, Encoding)
+ when is_list(Prompt); is_atom(Prompt); is_binary(Prompt) ->
+ do_format_prompt(add_modifier(Encoding, "s"), [Prompt]);
+format_prompt(Prompt, Encoding) ->
+ do_format_prompt(add_modifier(Encoding, "p"), [Prompt]).
+
+do_format_prompt(Format, Args) ->
case catch io_lib:format(Format, Args) of
{'EXIT',_} -> "???";
List -> List
end.
+add_modifier(latin1, C) ->
+ "~"++C;
+add_modifier(_, C) ->
+ "~t"++C.
%% write(Term)
%% write(Term, Depth)
@@ -253,10 +277,10 @@ write_ref(Ref) ->
write_binary(B, D) when is_integer(D) ->
[$<,$<,write_binary_body(B, D),$>,$>].
-write_binary_body(_B, 1) ->
- "...";
write_binary_body(<<>>, _D) ->
"";
+write_binary_body(_B, 1) ->
+ "...";
write_binary_body(<<X:8>>, _D) ->
[integer_to_list(X)];
write_binary_body(<<X:8,Rest/bitstring>>, D) ->
@@ -294,7 +318,7 @@ quote_atom(Atom, Cs0) ->
case Cs0 of
[C|Cs] when C >= $a, C =< $z ->
not name_chars(Cs);
- [C|Cs] when C >= $�, C =< $�, C =/= $� ->
+ [C|Cs] when C >= $ß, C =< $ÿ, C =/= $÷ ->
not name_chars(Cs);
_ -> true
end
@@ -308,9 +332,9 @@ name_chars([C|Cs]) ->
name_chars([]) -> true.
name_char(C) when C >= $a, C =< $z -> true;
-name_char(C) when C >= $�, C =< $�, C =/= $� -> true;
+name_char(C) when C >= $ß, C =< $ÿ, C =/= $÷ -> true;
name_char(C) when C >= $A, C =< $Z -> true;
-name_char(C) when C >= $�, C =< $�, C =/= $� -> true;
+name_char(C) when C >= $À, C =< $Þ, C =/= $× -> true;
name_char(C) when C >= $0, C =< $9 -> true;
name_char($_) -> true;
name_char($@) -> true;
@@ -330,11 +354,32 @@ write_string(S) ->
write_string(S, Q) ->
[Q|write_string1(latin1, S, Q)].
+%%% There are two functions to write Unicode strings:
+%%% - they both escape control characters < 160;
+%%% - write_unicode_string() never escapes characters >= 160;
+%%% - write_unicode_string_as_latin1() also escapes characters >= 255.
+
+-spec write_unicode_string(UnicodeString) -> unicode_string() when
+ UnicodeString :: unicode_string().
+
write_unicode_string(S) ->
write_unicode_string(S, $"). %"
+-spec write_unicode_string(unicode_string(), char()) -> unicode_string().
+
write_unicode_string(S, Q) ->
- [Q|write_string1(unicode, S, Q)].
+ [Q|write_string1(unicode_as_unicode, S, Q)].
+
+-spec write_unicode_string_as_latin1(UnicodeString) -> string() when
+ UnicodeString :: unicode_string().
+
+write_unicode_string_as_latin1(S) ->
+ write_unicode_string_as_latin1(S, $"). %"
+
+-spec write_unicode_string_as_latin1(unicode_string(), char()) -> string().
+
+write_unicode_string_as_latin1(S, Q) ->
+ [Q|write_string1(unicode_as_latin1, S, Q)].
write_string1(_,[], Q) ->
[Q];
@@ -347,7 +392,11 @@ string_char(_,C, _, Tail) when C >= $\s, C =< $~ ->
[C|Tail];
string_char(latin1,C, _, Tail) when C >= $\240, C =< $\377 ->
[C|Tail];
-string_char(unicode,C, _, Tail) when C >= $\240 ->
+string_char(unicode_as_unicode,C, _, Tail) when C >= $\240 ->
+ [C|Tail];
+string_char(unicode_as_latin1,C, _, Tail) when C >= $\240, C =< $\377 ->
+ [C|Tail];
+string_char(unicode_as_latin1,C, _, Tail) when C >= $\377 ->
"\\x{"++erlang:integer_to_list(C, 16)++"}"++Tail;
string_char(_,$\n, _, Tail) -> [$\\,$n|Tail]; %\n = LF
string_char(_,$\r, _, Tail) -> [$\\,$r|Tail]; %\r = CR
@@ -374,10 +423,22 @@ write_char($\s) -> "$\\s"; %Must special case this.
write_char(C) when is_integer(C), C >= $\000, C =< $\377 ->
[$$|string_char(latin1,C, -1, [])].
-write_unicode_char(Ch) when Ch =< 255 ->
- write_char(Ch);
-write_unicode_char(Uni) ->
- [$$|string_char(unicode,Uni, -1, [])].
+%%% There are two functions to write a Unicode character:
+%%% - they both escape control characters < 160;
+%%% - write_unicode_char() never escapes characters >= 160;
+%%% - write_unicode_char_as_latin1() also escapes characters >= 255.
+
+-spec write_unicode_char(UnicodeChar) -> unicode_string() when
+ UnicodeChar :: unicode:unicode_char().
+
+write_unicode_char(Uni) when is_integer(Uni), Uni >= $\000 ->
+ [$$|string_char(unicode_as_unicode,Uni, -1, [])].
+
+-spec write_unicode_char_as_latin1(UnicodeChar) -> string() when
+ UnicodeChar :: unicode:unicode_char().
+
+write_unicode_char_as_latin1(Uni) when is_integer(Uni), Uni >= $\000 ->
+ [$$|string_char(unicode_as_latin1,Uni, -1, [])].
%% char_list(CharList)
%% deep_char_list(CharList)
@@ -392,7 +453,8 @@ char_list([C|Cs]) when is_integer(C), C >= $\000, C =< $\377 ->
char_list([]) -> true;
char_list(_) -> false. %Everything else is false
--spec unicode_char_list(term()) -> boolean().
+-spec unicode_char_list(Term) -> boolean() when
+ Term :: term().
unicode_char_list([C|Cs]) when is_integer(C), C >= 0, C < 16#D800;
is_integer(C), C > 16#DFFF, C < 16#FFFE;
@@ -417,7 +479,8 @@ deep_char_list([], []) -> true;
deep_char_list(_, _More) -> %Everything else is false
false.
--spec deep_unicode_char_list(term()) -> boolean().
+-spec deep_unicode_char_list(Term) -> boolean() when
+ Term :: term().
deep_unicode_char_list(Cs) ->
deep_unicode_char_list(Cs, []).
@@ -462,7 +525,8 @@ printable_list(_) -> false. %Everything else is false
%% Everything that is not a control character and not invalid unicode
%% will be considered printable.
--spec printable_unicode_list(term()) -> boolean().
+-spec printable_unicode_list(Term) -> boolean() when
+ Term :: term().
printable_unicode_list([C|Cs]) when is_integer(C), C >= $\040, C =< $\176 ->
printable_unicode_list(Cs);
diff --git a/lib/stdlib/src/io_lib_format.erl b/lib/stdlib/src/io_lib_format.erl
index 49a00a4ec7..5680f83ab6 100644
--- a/lib/stdlib/src/io_lib_format.erl
+++ b/lib/stdlib/src/io_lib_format.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -22,7 +22,7 @@
-export([fwrite/2,fwrite_g/1,indentation/2]).
-%% fwrite(Format, ArgList) -> [Char].
+%% fwrite(Format, ArgList) -> [unicode:unicode:char()].
%% Format the arguments in ArgList after string Format. Just generate
%% an error if there is an error in the arguments.
%%
@@ -133,7 +133,7 @@ pcount([{$P,_As,_F,_Ad,_P,_Pad,_Enc}|Cs], Acc) -> pcount(Cs, Acc+1);
pcount([_|Cs], Acc) -> pcount(Cs, Acc);
pcount([], Acc) -> Acc.
-%% build([Control], Pc, Indentation) -> [Char].
+%% build([Control], Pc, Indentation) -> [unicode:unicode_char()].
%% Interpret the control structures. Count the number of print
%% remaining and only calculate indentation when necessary. Must also
%% be smart when calculating indentation for characters in format.
@@ -154,7 +154,7 @@ decr_pc($p, Pc) -> Pc - 1;
decr_pc($P, Pc) -> Pc - 1;
decr_pc(_, Pc) -> Pc.
-%% indentation([Char], Indentation) -> Indentation.
+%% indentation([unicode:unicode_char()], Indentation) -> Indentation.
%% Calculate the indentation of the end of a string given its start
%% indentation. We assume tabs at 8 cols.
@@ -167,19 +167,19 @@ indentation([C|Cs], I) ->
indentation([], I) -> I.
%% control(FormatChar, [Argument], FieldWidth, Adjust, Precision, PadChar,
-%% Indentation) ->
-%% [Char]
+%% Encoding, Indentation) ->
+%% [unicode:unicode_char()]
%% This is the main dispatch function for the various formatting commands.
%% Field widths and precisions have already been calculated.
control($w, [A], F, Adj, P, Pad, _Enc,_I) ->
term(io_lib:write(A, -1), F, Adj, P, Pad);
-control($p, [A], F, Adj, P, Pad, _Enc, I) ->
- print(A, -1, F, Adj, P, Pad, I);
+control($p, [A], F, Adj, P, Pad, Enc, I) ->
+ print(A, -1, F, Adj, P, Pad, Enc, I);
control($W, [A,Depth], F, Adj, P, Pad, _Enc, _I) when is_integer(Depth) ->
term(io_lib:write(A, Depth), F, Adj, P, Pad);
-control($P, [A,Depth], F, Adj, P, Pad, _Enc, I) when is_integer(Depth) ->
- print(A, Depth, F, Adj, P, Pad, I);
+control($P, [A,Depth], F, Adj, P, Pad, Enc, I) when is_integer(Depth) ->
+ print(A, Depth, F, Adj, P, Pad, Enc, I);
control($s, [A], F, Adj, P, Pad, _Enc, _I) when is_atom(A) ->
string(atom_to_list(A), F, Adj, P, Pad);
control($s, [L0], F, Adj, P, Pad, latin1, _I) ->
@@ -187,6 +187,7 @@ control($s, [L0], F, Adj, P, Pad, latin1, _I) ->
string(L, F, Adj, P, Pad);
control($s, [L0], F, Adj, P, Pad, unicode, _I) ->
L = unicode:characters_to_list(L0),
+ true = is_list(L),
uniconv(string(L, F, Adj, P, Pad));
control($e, [A], F, Adj, P, Pad, _Enc, _I) when is_float(A) ->
fwrite_e(A, F, Adj, P, Pad);
@@ -256,13 +257,17 @@ term(T, F, Adj, P0, Pad) ->
adjust(T, chars(Pad, F-L), Adj)
end.
-%% print(Term, Depth, Field, Adjust, Precision, PadChar, Indentation)
+%% print(Term, Depth, Field, Adjust, Precision, PadChar, Encoding,
+%% Indentation)
%% Print a term.
-print(T, D, none, Adj, P, Pad, I) -> print(T, D, 80, Adj, P, Pad, I);
-print(T, D, F, Adj, none, Pad, I) -> print(T, D, F, Adj, I+1, Pad, I);
-print(T, D, F, right, P, _Pad, _I) ->
- io_lib_pretty:print(T, P, F, D).
+print(T, D, none, Adj, P, Pad, E, I) -> print(T, D, 80, Adj, P, Pad, E, I);
+print(T, D, F, Adj, none, Pad, E, I) -> print(T, D, F, Adj, I+1, Pad, E, I);
+print(T, D, F, right, P, _Pad, latin1, _I) ->
+ io_lib_pretty:print(T, P, F, D);
+print(T, D, F, right, P, _Pad, Enc, _I) ->
+ Options = [{column, P}, {line_length, F}, {depth, D}, {encoding, Enc}],
+ io_lib_pretty:print(T, Options).
%% fwrite_e(Float, Field, Adjust, Precision, PadChar)
@@ -608,7 +613,7 @@ prefixed_integer(Int, F, Adj, Base, Pad, Prefix, Lowercase)
term([Prefix|S], F, Adj, none, Pad)
end.
-%% char(Char, Field, Adjust, Precision, PadChar) -> [Char].
+%% char(Char, Field, Adjust, Precision, PadChar) -> [unicode:unicode_char()].
char(C, none, _Adj, none, _Pad) -> [C];
char(C, F, _Adj, none, _Pad) -> chars(C, F);
diff --git a/lib/stdlib/src/io_lib_fread.erl b/lib/stdlib/src/io_lib_fread.erl
index ded1346097..84d4b8bba0 100644
--- a/lib/stdlib/src/io_lib_fread.erl
+++ b/lib/stdlib/src/io_lib_fread.erl
@@ -43,7 +43,7 @@
| {'done', Result, LeftOverChars :: string()},
Result :: {'ok', InputList :: io_lib:chars()}
| 'eof'
- | {'error', What :: term()}.
+ | {'error', What :: io_lib:fread_error()}.
fread([], Chars, Format) ->
%%io:format("FREAD: ~w `~s'~n", [Format,Chars]),
diff --git a/lib/stdlib/src/io_lib_pretty.erl b/lib/stdlib/src/io_lib_pretty.erl
index 169410796b..99ad281a9b 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-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -33,43 +33,76 @@
%% print(Term, Column, LineLength, Depth) -> [Chars]
%% Depth = -1 gives unlimited print depth. Use io_lib:write for atomic terms.
+-spec print(term()) -> io_lib:chars().
+
print(Term) ->
print(Term, 1, 80, -1).
%% print(Term, RecDefFun) -> [Chars]
%% print(Term, Depth, RecDefFun) -> [Chars]
%% RecDefFun = fun(Tag, NoFields) -> [FieldTag] | no
-%% Used by the shell for printing records.
+%% Used by the shell for printing records and for Unicode.
+
+-type rec_print_fun() :: fun((Tag :: atom(), NFields :: non_neg_integer()) ->
+ no | [FieldName :: atom()]).
+-type column() :: integer().
+-type line_length() :: pos_integer().
+-type depth() :: integer().
+-type max_chars() :: integer().
+
+-type chars() :: io_lib:chars().
+-type unicode_chars() :: io_lib:unicode_chars().
+-type option() :: {column, column()}
+ | {line_length, line_length()}
+ | {depth, depth()}
+ | {max_chars, max_chars()}
+ | {record_print_fun, rec_print_fun()}
+ | {encoding, latin1 | utf8 | unicode}.
+-type options() :: [option()].
+
+-spec print(term(), rec_print_fun()) -> chars() | unicode_chars();
+ (term(), options()) -> chars() | unicode_chars().
+
+print(Term, Options) when is_list(Options) ->
+ Col = proplists:get_value(column, Options, 1),
+ Ll = proplists:get_value(line_length, Options, 80),
+ D = proplists:get_value(depth, Options, -1),
+ M = proplists:get_value(max_chars, Options, -1),
+ RecDefFun = proplists:get_value(record_print_fun, Options, no_fun),
+ Encoding = proplists:get_value(encoding, Options, epp:default_encoding()),
+ print(Term, Col, Ll, D, M, RecDefFun, Encoding);
print(Term, RecDefFun) ->
print(Term, -1, RecDefFun).
+-spec print(term(), depth(), rec_print_fun()) -> chars() | unicode_chars().
+
print(Term, Depth, RecDefFun) ->
print(Term, 1, 80, Depth, RecDefFun).
+-spec print(term(), column(), line_length(), depth()) ->
+ chars() | unicode_chars().
+
print(Term, Col, Ll, D) ->
- print(Term, Col, Ll, D, _M=-1, no_fun).
+ print(Term, Col, Ll, D, _M=-1, no_fun, latin1).
+-spec print(term(), column(), line_length(), depth(), rec_print_fun()) ->
+ chars() | unicode_chars().
print(Term, Col, Ll, D, RecDefFun) ->
print(Term, Col, Ll, D, _M=-1, RecDefFun).
-print(_, _, _, 0, _M, _RF) -> "...";
-print(Term, Col, Ll, D, M, RecDefFun) when Col =< 0 ->
- print(Term, 1, Ll, D, M, RecDefFun);
-print(Term, Col, Ll, D, M0, RecDefFun) when is_tuple(Term);
- is_list(Term) ->
- If = {_S, Len} = print_length(Term, D, RecDefFun),
- M = max_cs(M0, Len),
- if
- Len < Ll - Col, Len =< M ->
- write(If);
- true ->
- TInd = while_fail([-1, 4],
- fun(I) -> cind(If, Col, Ll, M, I, 0, 0) end,
- 1),
- pp(If, Col, Ll, M, TInd, indent(Col), 0, 0)
- end;
-print(<<_/bitstring>>=Term, Col, Ll, D, M0, RecDefFun) ->
- If = {_S, Len} = print_length(Term, D, RecDefFun),
+-spec print(term(), column(), line_length(), depth(), max_chars(),
+ rec_print_fun()) -> chars() | unicode_chars().
+
+print(Term, Col, Ll, D, M, RecDefFun) ->
+ print(Term, Col, Ll, D, M, RecDefFun, latin1).
+
+print(_, _, _, 0, _M, _RF, _Enc) -> "...";
+print(Term, Col, Ll, D, M, RecDefFun, Enc) when Col =< 0 ->
+ print(Term, 1, Ll, D, M, RecDefFun, Enc);
+print(Term, Col, Ll, D, M0, RecDefFun, Enc) when is_tuple(Term);
+ is_list(Term);
+ is_bitstring(Term) ->
+ If = {_S, Len} = print_length(Term, D, RecDefFun, Enc),
M = max_cs(M0, Len),
if
Len < Ll - Col, Len =< M ->
@@ -80,7 +113,7 @@ print(<<_/bitstring>>=Term, Col, Ll, D, M0, RecDefFun) ->
1),
pp(If, Col, Ll, M, TInd, indent(Col), 0, 0)
end;
-print(Term, _Col, _Ll, _D, _M, _RF) ->
+print(Term, _Col, _Ll, _D, _M, _RF, _Enc) ->
io_lib:write(Term).
%%%
@@ -294,50 +327,56 @@ write_tail(E, S) ->
%% counted but need to be added later.
%% D =/= 0
-print_length([], _D, _RF) ->
+print_length([], _D, _RF, _Enc) ->
{"[]", 2};
-print_length({}, _D, _RF) ->
+print_length({}, _D, _RF, _Enc) ->
{"{}", 2};
-print_length(List, D, RF) when is_list(List) ->
- case printable_list(List, D) of
+print_length(List, D, RF, Enc) when is_list(List) ->
+ case printable_list(List, D, Enc) of
true ->
- S = io_lib:write_string(List, $"), %"
+ S = write_string(List, Enc),
{S, length(S)};
%% Truncated lists could break some existing code.
% {true, Prefix} ->
- % S = io_lib:write_string(Prefix, $"), %"
+ % S = write_string(Prefix, Enc),
% {[S | "..."], 3 + length(S)};
false ->
- print_length_list(List, D, RF)
+ print_length_list(List, D, RF, Enc)
end;
-print_length(Fun, _D, _RF) when is_function(Fun) ->
+print_length(Fun, _D, _RF, _Enc) when is_function(Fun) ->
S = io_lib:write(Fun),
{S, iolist_size(S)};
-print_length(R, D, RF) when is_atom(element(1, R)),
- is_function(RF) ->
+print_length(R, D, RF, Enc) when is_atom(element(1, R)),
+ is_function(RF) ->
case RF(element(1, R), tuple_size(R) - 1) of
no ->
- print_length_tuple(R, D, RF);
+ print_length_tuple(R, D, RF, Enc);
RDefs ->
- print_length_record(R, D, RF, RDefs)
+ print_length_record(R, D, RF, RDefs, Enc)
end;
-print_length(Tuple, D, RF) when is_tuple(Tuple) ->
- print_length_tuple(Tuple, D, RF);
-print_length(<<>>, _D, _RF) ->
+print_length(Tuple, D, RF, Enc) when is_tuple(Tuple) ->
+ print_length_tuple(Tuple, D, RF, Enc);
+print_length(<<>>, _D, _RF, _Enc) ->
{"<<>>", 4};
-print_length(<<_/bitstring>>, 1, _RF) ->
+print_length(<<_/bitstring>>, 1, _RF, _Enc) ->
{"<<...>>", 7};
-print_length(<<_/bitstring>>=Bin, D, _RF) ->
+print_length(<<_/bitstring>>=Bin, D, _RF, Enc) ->
case bit_size(Bin) rem 8 of
0 ->
D1 = D - 1,
- case printable_bin(Bin, D1) of
- List when is_list(List) ->
- S = io_lib:write_string(List, $"),
+ case printable_bin(Bin, D1, Enc) of
+ {true, List} when is_list(List) ->
+ S = io_lib:write_string(List, $"), %"
{[$<,$<,S,$>,$>], 4 + length(S)};
- {true, Prefix} ->
- S = io_lib:write_string(Prefix, $"),
- {[$<,$<, S | "...>>"], 4 + length(S)};
+ {false, List} when is_list(List) ->
+ S = io_lib:write_unicode_string(List, $"), %"
+ {[$<,$<,S,"/utf8>>"], 9 + length(S)};
+ {true, true, Prefix} ->
+ S = io_lib:write_string(Prefix, $"), %"
+ {[$<,$<, S | "...>>"], 7 + length(S)};
+ {false, true, Prefix} ->
+ S = io_lib:write_unicode_string(Prefix, $"), %"
+ {[$<,$<, S | "/utf8...>>"], 12 + length(S)};
false ->
S = io_lib:write(Bin, D),
{{bin,S}, iolist_size(S)}
@@ -346,51 +385,51 @@ print_length(<<_/bitstring>>=Bin, D, _RF) ->
S = io_lib:write(Bin, D),
{{bin,S}, iolist_size(S)}
end;
-print_length(Term, _D, _RF) ->
+print_length(Term, _D, _RF, _Enc) ->
S = io_lib:write(Term),
{S, iolist_size(S)}.
-print_length_tuple(_Tuple, 1, _RF) ->
+print_length_tuple(_Tuple, 1, _RF, _Enc) ->
{"{...}", 5};
-print_length_tuple(Tuple, D, RF) ->
- L = print_length_list1(tuple_to_list(Tuple), D, RF),
+print_length_tuple(Tuple, D, RF, Enc) ->
+ L = print_length_list1(tuple_to_list(Tuple), D, RF, Enc),
IsTagged = is_atom(element(1, Tuple)) and (tuple_size(Tuple) > 1),
{{tuple,IsTagged,L}, list_length(L, 2)}.
-print_length_record(_Tuple, 1, _RF, _RDefs) ->
+print_length_record(_Tuple, 1, _RF, _RDefs, _Enc) ->
{"{...}", 5};
-print_length_record(Tuple, D, RF, RDefs) ->
+print_length_record(Tuple, D, RF, RDefs, Enc) ->
Name = [$# | io_lib:write_atom(element(1, Tuple))],
NameL = length(Name),
- L = print_length_fields(RDefs, D - 1, tl(tuple_to_list(Tuple)), RF),
+ L = print_length_fields(RDefs, D - 1, tl(tuple_to_list(Tuple)), RF, Enc),
{{record, [{Name,NameL} | L]}, list_length(L, NameL + 2)}.
-print_length_fields([], _D, [], _RF) ->
+print_length_fields([], _D, [], _RF, _Enc) ->
[];
-print_length_fields(_, 1, _, _RF) ->
+print_length_fields(_, 1, _, _RF, _Enc) ->
{dots, 3};
-print_length_fields([Def | Defs], D, [E | Es], RF) ->
- [print_length_field(Def, D - 1, E, RF) |
- print_length_fields(Defs, D - 1, Es, RF)].
+print_length_fields([Def | Defs], D, [E | Es], RF, Enc) ->
+ [print_length_field(Def, D - 1, E, RF, Enc) |
+ print_length_fields(Defs, D - 1, Es, RF, Enc)].
-print_length_field(Def, D, E, RF) ->
+print_length_field(Def, D, E, RF, Enc) ->
Name = io_lib:write_atom(Def),
- {S, L} = print_length(E, D, RF),
+ {S, L} = print_length(E, D, RF, Enc),
NameL = length(Name) + 3,
{{field, Name, NameL, {S, L}}, NameL + L}.
-print_length_list(List, D, RF) ->
- L = print_length_list1(List, D, RF),
+print_length_list(List, D, RF, Enc) ->
+ L = print_length_list1(List, D, RF, Enc),
{{list, L}, list_length(L, 2)}.
-print_length_list1([], _D, _RF) ->
+print_length_list1([], _D, _RF, _Enc) ->
[];
-print_length_list1(_, 1, _RF) ->
+print_length_list1(_, 1, _RF, _Enc) ->
{dots, 3};
-print_length_list1([E | Es], D, RF) ->
- [print_length(E, D - 1, RF) | print_length_list1(Es, D - 1, RF)];
-print_length_list1(E, D, RF) ->
- print_length(E, D - 1, RF).
+print_length_list1([E | Es], D, RF, Enc) ->
+ [print_length(E, D - 1, RF, Enc) | print_length_list1(Es, D - 1, RF, Enc)];
+print_length_list1(E, D, RF, Enc) ->
+ print_length(E, D - 1, RF, Enc).
list_length([], Acc) ->
Acc;
@@ -409,16 +448,16 @@ list_length_tail({_, Len}, Acc) ->
%% ?CHARS printable characters has depth 1.
-define(CHARS, 4).
-printable_list(L, D) when D < 0 ->
- io_lib:printable_list(L);
-printable_list(_L, 1) ->
+printable_list(_L, 1, _Enc) ->
false;
-printable_list(L, _D) ->
- io_lib:printable_list(L).
+printable_list(L, _D, latin1) ->
+ io_lib:printable_list(L);
+printable_list(L, _D, _Uni) ->
+ io_lib:printable_unicode_list(L).
%% Truncated lists could break some existing code.
-% printable_list(L, D) ->
+% printable_list(L, D, Enc) when D >= 0 ->
% Len = ?CHARS * (D - 1),
-% case printable_list1(L, Len) of
+% case printable_list1(L, Len, Enc) of
% all ->
% true;
% N when is_integer(N), Len - N >= D - 1 ->
@@ -428,32 +467,41 @@ printable_list(L, _D) ->
% false
% end.
-printable_bin(Bin, D) when D >= 0, ?CHARS * D =< byte_size(Bin) ->
- printable_bin(Bin, erlang:min(?CHARS * D, byte_size(Bin)), D);
-printable_bin(Bin, D) ->
- printable_bin(Bin, byte_size(Bin), D).
+printable_bin(Bin, D, Enc) when D >= 0, ?CHARS * D =< byte_size(Bin) ->
+ printable_bin(Bin, erlang:min(?CHARS * D, byte_size(Bin)), D, Enc);
+printable_bin(Bin, D, Enc) ->
+ printable_bin(Bin, byte_size(Bin), D, Enc).
-printable_bin(Bin, Len, D) ->
+printable_bin(Bin, Len, D, latin1) ->
N = erlang:min(20, Len),
L = binary_to_list(Bin, 1, N),
case printable_list1(L, N) of
all when N =:= byte_size(Bin) ->
- L;
- all when N =:= Len -> % N < byte_size(Bin)
{true, L};
+ all when N =:= Len -> % N < byte_size(Bin)
+ {true, true, L};
all ->
case printable_bin1(Bin, 1 + N, Len - N) of
0 when byte_size(Bin) =:= Len ->
- binary_to_list(Bin);
+ {true, binary_to_list(Bin)};
NC when D > 0, Len - NC >= D ->
- {true, binary_to_list(Bin, 1, Len - NC)};
+ {true, true, binary_to_list(Bin, 1, Len - NC)};
NC when is_integer(NC) ->
false
end;
NC when is_integer(NC), D > 0, N - NC >= D ->
- {true, binary_to_list(Bin, 1, N - NC)};
+ {true, true, binary_to_list(Bin, 1, N - NC)};
NC when is_integer(NC) ->
false
+ end;
+printable_bin(Bin, Len, D, _Uni) ->
+ case printable_unicode(Bin, Len, []) of
+ {_, <<>>, L} ->
+ {byte_size(Bin) =:= length(L), L};
+ {NC, Bin1, L} when D > 0, Len - NC >= D ->
+ {byte_size(Bin)-byte_size(Bin1) =:= length(L), true, L};
+ {_NC, _Bin, _L} ->
+ false
end.
printable_bin1(_Bin, _Start, 0) ->
@@ -484,6 +532,16 @@ printable_list1([$\e | Cs], N) -> printable_list1(Cs, N - 1);
printable_list1([], _) -> all;
printable_list1(_, N) -> N.
+printable_unicode(<<C/utf8, R/binary>>, I, L) when I > 0 ->
+ printable_unicode(R, I - 1, [C | L]);
+printable_unicode(Bin, I, L) ->
+ {I, Bin, lists:reverse(L)}.
+
+write_string(S, latin1) ->
+ io_lib:write_string(S, $"); %"
+write_string(S, _Uni) ->
+ io_lib:write_unicode_string(S, $"). %"
+
%% Throw 'no_good' if the indentation exceeds half the line length
%% unless there is room for M characters on the line.
diff --git a/lib/stdlib/src/lib.erl b/lib/stdlib/src/lib.erl
index cf4b87d7eb..b2ce2a5a8f 100644
--- a/lib/stdlib/src/lib.erl
+++ b/lib/stdlib/src/lib.erl
@@ -21,8 +21,9 @@
-export([flush_receive/0, error_message/2, progname/0, nonl/1, send/2,
sendw/2, eval_str/1]).
--export([format_exception/6, format_stacktrace/4,
- format_call/4, format_fun/1]).
+-export([format_exception/6, format_exception/7,
+ format_stacktrace/4, format_stacktrace/5,
+ format_call/4, format_call/5, format_fun/1]).
-spec flush_receive() -> 'ok'.
@@ -128,32 +129,49 @@ all_white(_) -> false.
%% as indentation whenever newline has been inserted);
%% Class, Reason and StackTrace are the exception;
%% FormatFun = fun(Term, I) -> iolist() formats terms;
-%% StackFun = fun(Mod, Fun, Arity) -> bool() is used for trimming the
+%% StackFun = fun(Mod, Fun, Arity) -> boolean() is used for trimming the
%% end of the stack (typically calls to erl_eval are skipped).
-format_exception(I, Class, Reason, StackTrace, StackFun, FormatFun)
+format_exception(I, Class, Reason, StackTrace, StackFun, FormatFun) ->
+ format_exception(I, Class, Reason, StackTrace, StackFun, FormatFun,
+ latin1).
+
+%% -> iolist() | unicode:charlist() (no \n at end)
+%% FormatFun = fun(Term, I) -> iolist() | unicode:charlist().
+format_exception(I, Class, Reason, StackTrace, StackFun, FormatFun, Encoding)
when is_integer(I), I >= 1, is_function(StackFun, 3),
is_function(FormatFun, 2) ->
S = n_spaces(I-1),
{Term,Trace1,Trace} = analyze_exception(Class, Reason, StackTrace),
- Expl0 = explain_reason(Term, Class, Trace1, FormatFun, S),
- Expl = io_lib:fwrite(<<"~s~s">>, [exited(Class), Expl0]),
- case format_stacktrace1(S, Trace, FormatFun, StackFun) of
+ Expl0 = explain_reason(Term, Class, Trace1, FormatFun, S, Encoding),
+ FormatString = case Encoding of
+ latin1 -> "~s~s";
+ _ -> "~s~ts"
+ end,
+ Expl = io_lib:fwrite(FormatString, [exited(Class), Expl0]),
+ case format_stacktrace1(S, Trace, FormatFun, StackFun, Encoding) of
[] -> Expl;
Stack -> [Expl, $\n, Stack]
end.
%% -> iolist() (no \n at end)
-format_stacktrace(I, StackTrace, StackFun, FormatFun)
+format_stacktrace(I, StackTrace, StackFun, FormatFun) ->
+ format_stacktrace(I, StackTrace, StackFun, FormatFun, latin1).
+
+%% -> iolist() | unicode:charlist() (no \n at end)
+format_stacktrace(I, StackTrace, StackFun, FormatFun, Encoding)
when is_integer(I), I >= 1, is_function(StackFun, 3),
is_function(FormatFun, 2) ->
S = n_spaces(I-1),
- format_stacktrace1(S, StackTrace, FormatFun, StackFun).
+ format_stacktrace1(S, StackTrace, FormatFun, StackFun, Encoding).
%% -> iolist() (no \n at end)
-format_call(I, ForMForFun, As, FormatFun) when is_integer(I), I >= 1,
- is_list(As),
- is_function(FormatFun, 2) ->
- format_call("", n_spaces(I-1), ForMForFun, As, FormatFun).
+format_call(I, ForMForFun, As, FormatFun) ->
+ format_call(I, ForMForFun, As, FormatFun, latin1).
+
+%% -> iolist() | unicode:charlist() (no \n at end)
+format_call(I, ForMForFun, As, FormatFun, Enc)
+ when is_integer(I), I >= 1, is_list(As), is_function(FormatFun, 2) ->
+ format_call("", n_spaces(I-1), ForMForFun, As, FormatFun, Enc).
%% -> iolist() (no \n at end)
format_fun(Fun) when is_function(Fun) ->
@@ -204,79 +222,80 @@ is_stacktrace(_) ->
false.
%% ERTS exit codes (some of them are also returned by erl_eval):
-explain_reason(badarg, error, [], _PF, _S) ->
+explain_reason(badarg, error, [], _PF, _S, _Enc) ->
<<"bad argument">>;
-explain_reason({badarg,V}, error=Cl, [], PF, S) -> % orelse, andalso
+explain_reason({badarg,V}, error=Cl, [], PF, S, _Enc) -> % orelse, andalso
format_value(V, <<"bad argument: ">>, Cl, PF, S);
-explain_reason(badarith, error, [], _PF, _S) ->
+explain_reason(badarith, error, [], _PF, _S, _Enc) ->
<<"an error occurred when evaluating an arithmetic expression">>;
-explain_reason({badarity,{Fun,As}}, error, [], _PF, _S)
+explain_reason({badarity,{Fun,As}}, error, [], _PF, _S, _Enc)
when is_function(Fun) ->
%% Only the arity is displayed, not the arguments As.
io_lib:fwrite(<<"~s called with ~s">>,
[format_fun(Fun), argss(length(As))]);
-explain_reason({badfun,Term}, error=Cl, [], PF, S) ->
+explain_reason({badfun,Term}, error=Cl, [], PF, S, _Enc) ->
format_value(Term, <<"bad function ">>, Cl, PF, S);
-explain_reason({badmatch,Term}, error=Cl, [], PF, S) ->
- format_value(Term, <<"no match of right hand side value ">>, Cl, PF, S);
-explain_reason({case_clause,V}, error=Cl, [], PF, S) ->
+explain_reason({badmatch,Term}, error=Cl, [], PF, S, _Enc) ->
+ Str = <<"no match of right hand side value ">>,
+ format_value(Term, Str, Cl, PF, S);
+explain_reason({case_clause,V}, error=Cl, [], PF, S, _Enc) ->
%% "there is no case clause with a true guard sequence and a
%% pattern matching..."
format_value(V, <<"no case clause matching ">>, Cl, PF, S);
-explain_reason(function_clause, error, [{F,A}], _PF, _S) ->
+explain_reason(function_clause, error, [{F,A}], _PF, _S, _Enc) ->
%% Shell commands
FAs = io_lib:fwrite(<<"~w/~w">>, [F, A]),
[<<"no function clause matching call to ">> | FAs];
-explain_reason(function_clause, error=Cl, [{M,F,As,Loc}], PF, S) ->
+explain_reason(function_clause, error=Cl, [{M,F,As,Loc}], PF, S, Enc) ->
Str = <<"no function clause matching ">>,
- [format_errstr_call(Str, Cl, {M,F}, As, PF, S),$\s|location(Loc)];
-explain_reason(if_clause, error, [], _PF, _S) ->
+ [format_errstr_call(Str, Cl, {M,F}, As, PF, S, Enc),$\s|location(Loc)];
+explain_reason(if_clause, error, [], _PF, _S, _Enc) ->
<<"no true branch found when evaluating an if expression">>;
-explain_reason(noproc, error, [], _PF, _S) ->
+explain_reason(noproc, error, [], _PF, _S, _Enc) ->
<<"no such process or port">>;
-explain_reason(notalive, error, [], _PF, _S) ->
+explain_reason(notalive, error, [], _PF, _S, _Enc) ->
<<"the node cannot be part of a distributed system">>;
-explain_reason(system_limit, error, [], _PF, _S) ->
+explain_reason(system_limit, error, [], _PF, _S, _Enc) ->
<<"a system limit has been reached">>;
-explain_reason(timeout_value, error, [], _PF, _S) ->
+explain_reason(timeout_value, error, [], _PF, _S, _Enc) ->
<<"bad receive timeout value">>;
-explain_reason({try_clause,V}, error=Cl, [], PF, S) ->
+explain_reason({try_clause,V}, error=Cl, [], PF, S, _Enc) ->
%% "there is no try clause with a true guard sequence and a
%% pattern matching..."
format_value(V, <<"no try clause matching ">>, Cl, PF, S);
-explain_reason(undef, error, [{M,F,A,_}], _PF, _S) ->
+explain_reason(undef, error, [{M,F,A,_}], _PF, _S, _Enc) ->
%% Only the arity is displayed, not the arguments, if there are any.
io_lib:fwrite(<<"undefined function ~s">>,
[mfa_to_string(M, F, n_args(A))]);
-explain_reason({shell_undef,F,A,_}, error, [], _PF, _S) ->
+explain_reason({shell_undef,F,A,_}, error, [], _PF, _S, _Enc) ->
%% Give nicer reports for undefined shell functions
%% (but not when the user actively calls shell_default:F(...)).
io_lib:fwrite(<<"undefined shell command ~s/~w">>, [F, n_args(A)]);
%% Exit codes returned by erl_eval only:
-explain_reason({argument_limit,_Fun}, error, [], _PF, _S) ->
+explain_reason({argument_limit,_Fun}, error, [], _PF, _S, _Enc) ->
io_lib:fwrite(<<"limit of number of arguments to interpreted function"
" exceeded">>, []);
-explain_reason({bad_filter,V}, error=Cl, [], PF, S) ->
+explain_reason({bad_filter,V}, error=Cl, [], PF, S, _Enc) ->
format_value(V, <<"bad filter ">>, Cl, PF, S);
-explain_reason({bad_generator,V}, error=Cl, [], PF, S) ->
+explain_reason({bad_generator,V}, error=Cl, [], PF, S, _Enc) ->
format_value(V, <<"bad generator ">>, Cl, PF, S);
-explain_reason({unbound,V}, error, [], _PF, _S) ->
+explain_reason({unbound,V}, error, [], _PF, _S, _Enc) ->
io_lib:fwrite(<<"variable ~w is unbound">>, [V]);
%% Exit codes local to the shell module (restricted shell):
-explain_reason({restricted_shell_bad_return, V}, exit=Cl, [], PF, S) ->
+explain_reason({restricted_shell_bad_return, V}, exit=Cl, [], PF, S, _Enc) ->
Str = <<"restricted shell module returned bad value ">>,
format_value(V, Str, Cl, PF, S);
explain_reason({restricted_shell_disallowed,{ForMF,As}},
- exit=Cl, [], PF, S) ->
+ exit=Cl, [], PF, S, Enc) ->
%% ForMF can be a fun, but not a shell fun.
Str = <<"restricted shell does not allow ">>,
- format_errstr_call(Str, Cl, ForMF, As, PF, S);
-explain_reason(restricted_shell_started, exit, [], _PF, _S) ->
+ format_errstr_call(Str, Cl, ForMF, As, PF, S, Enc);
+explain_reason(restricted_shell_started, exit, [], _PF, _S, _Enc) ->
<<"restricted shell starts now">>;
-explain_reason(restricted_shell_stopped, exit, [], _PF, _S) ->
+explain_reason(restricted_shell_stopped, exit, [], _PF, _S, _Enc) ->
<<"restricted shell stopped">>;
%% Other exit code:
-explain_reason(Reason, Class, [], PF, S) ->
+explain_reason(Reason, Class, [], PF, S, _Enc) ->
PF(Reason, (iolist_size(S)+1) + exited_size(Class)).
n_args(A) when is_integer(A) ->
@@ -293,28 +312,28 @@ argss(2) ->
argss(I) ->
io_lib:fwrite(<<"~w arguments">>, [I]).
-format_stacktrace1(S0, Stack0, PF, SF) ->
+format_stacktrace1(S0, Stack0, PF, SF, Enc) ->
Stack1 = lists:dropwhile(fun({M,F,A,_}) -> SF(M, F, A)
end, lists:reverse(Stack0)),
S = [" " | S0],
Stack = lists:reverse(Stack1),
- format_stacktrace2(S, Stack, 1, PF).
+ format_stacktrace2(S, Stack, 1, PF, Enc).
-format_stacktrace2(S, [{M,F,A,L}|Fs], N, PF) when is_integer(A) ->
+format_stacktrace2(S, [{M,F,A,L}|Fs], N, PF, Enc) when is_integer(A) ->
[io_lib:fwrite(<<"~s~s ~s ~s">>,
[sep(N, S), origin(N, M, F, A),
mfa_to_string(M, F, A),
location(L)])
- | format_stacktrace2(S, Fs, N + 1, PF)];
-format_stacktrace2(S, [{M,F,As,_}|Fs], N, PF) when is_list(As) ->
+ | format_stacktrace2(S, Fs, N + 1, PF, Enc)];
+format_stacktrace2(S, [{M,F,As,_}|Fs], N, PF, Enc) when is_list(As) ->
A = length(As),
CalledAs = [S,<<" called as ">>],
- C = format_call("", CalledAs, {M,F}, As, PF),
- [io_lib:fwrite(<<"~s~s ~s\n~s~s">>,
+ C = format_call("", CalledAs, {M,F}, As, PF, Enc),
+ [io_lib:fwrite(<<"~s~s ~s\n~s~ts">>,
[sep(N, S), origin(N, M, F, A), mfa_to_string(M, F, A),
CalledAs, C])
- | format_stacktrace2(S, Fs, N + 1, PF)];
-format_stacktrace2(_S, [], _N, _PF) ->
+ | format_stacktrace2(S, Fs, N + 1, PF, Enc)];
+format_stacktrace2(_S, [], _N, _PF, _Enc) ->
"".
location(L) ->
@@ -338,22 +357,22 @@ origin(1, M, F, A) ->
origin(_N, _M, _F, _A) ->
<<"in call from">>.
-format_errstr_call(ErrStr, Class, ForMForFun, As, PF, Pre0) ->
+format_errstr_call(ErrStr, Class, ForMForFun, As, PF, Pre0, Enc) ->
Pre1 = [Pre0 | n_spaces(exited_size(Class))],
- format_call(ErrStr, Pre1, ForMForFun, As, PF).
+ format_call(ErrStr, Pre1, ForMForFun, As, PF, Enc).
-format_call(ErrStr, Pre1, ForMForFun, As, PF) ->
+format_call(ErrStr, Pre1, ForMForFun, As, PF, Enc) ->
Arity = length(As),
[ErrStr |
case is_op(ForMForFun, Arity) of
{yes,Op} ->
- format_op(ErrStr, Pre1, Op, As, PF);
+ format_op(ErrStr, Pre1, Op, As, PF, Enc);
no ->
MFs = mf_to_string(ForMForFun, Arity),
I1 = iolist_size([Pre1,ErrStr|MFs]),
- S1 = pp_arguments(PF, As, I1),
- S2 = pp_arguments(PF, As, iolist_size([Pre1|MFs])),
- Long = count_nl(pp_arguments(PF, [a2345,b2345], I1)) > 0,
+ S1 = pp_arguments(PF, As, I1, Enc),
+ S2 = pp_arguments(PF, As, iolist_size([Pre1|MFs]), Enc),
+ Long = count_nl(pp_arguments(PF, [a2345,b2345], I1, Enc)) > 0,
case Long or (count_nl(S2) < count_nl(S1)) of
true ->
[$\n, Pre1, MFs, S2];
@@ -362,11 +381,11 @@ format_call(ErrStr, Pre1, ForMForFun, As, PF) ->
end
end].
-format_op(ErrStr, Pre, Op, [A1], PF) ->
+format_op(ErrStr, Pre, Op, [A1], PF, _Enc) ->
OpS = io_lib:fwrite(<<"~s ">>, [Op]),
I1 = iolist_size([ErrStr,Pre,OpS]),
[OpS | PF(A1, I1+1)];
-format_op(ErrStr, Pre, Op, [A1, A2], PF) ->
+format_op(ErrStr, Pre, Op, [A1, A2], PF, Enc) ->
I1 = iolist_size([ErrStr,Pre]),
S1 = PF(A1, I1+1),
S2 = PF(A2, I1+1),
@@ -377,33 +396,40 @@ format_op(ErrStr, Pre, Op, [A1, A2], PF) ->
[S1,Pre1,OpS,Pre1|S2];
false ->
OpS2 = io_lib:fwrite(<<" ~s ">>, [Op]),
- S2_2 = PF(A2, iolist_size([ErrStr,Pre,S1|OpS2])+1),
+ Size1 = iolist_size([ErrStr,Pre|OpS2]),
+ {Size2,S1_2} = size(Enc, S1),
+ S2_2 = PF(A2, Size1+Size2+1),
case count_nl(S2) < count_nl(S2_2) of
true ->
- [S1,Pre1,OpS,Pre1|S2];
+ [S1_2,Pre1,OpS,Pre1|S2];
false ->
- [S1,OpS2|S2_2]
+ [S1_2,OpS2|S2_2]
end
end.
-pp_arguments(PF, As, I) ->
- case {As, io_lib:printable_list(As)} of
+pp_arguments(PF, As, I, Enc) ->
+ case {As, printable_list(Enc, As)} of
{[Int | T], true} ->
L = integer_to_list(Int),
Ll = length(L),
A = list_to_atom(lists:duplicate(Ll, $a)),
- S0 = binary_to_list(iolist_to_binary(PF([A | T], I+1))),
- brackets_to_parens([$[,L,string:sub_string(S0, 2+Ll)]);
+ S0 = unicode:characters_to_list(PF([A | T], I+1), Enc),
+ brackets_to_parens([$[,L,string:sub_string(S0, 2+Ll)], Enc);
_ ->
- brackets_to_parens(PF(As, I+1))
+ brackets_to_parens(PF(As, I+1), Enc)
end.
-brackets_to_parens(S) ->
- B = iolist_to_binary(S),
+brackets_to_parens(S, Enc) ->
+ B = unicode:characters_to_binary(S, Enc),
Sz = byte_size(B) - 2,
<<$[,R:Sz/binary,$]>> = B,
[$(,R,$)].
+printable_list(latin1, As) ->
+ io_lib:printable_list(As);
+printable_list(_, As) ->
+ io_lib:printable_unicode_list(As).
+
mfa_to_string(M, F, A) ->
io_lib:fwrite(<<"~s/~w">>, [mf_to_string({M, F}, A), A]).
@@ -472,3 +498,10 @@ exited(exit) ->
<<"exception exit: ">>;
exited(throw) ->
<<"exception throw: ">>.
+
+size(latin1, S) ->
+ {iolist_size(S),S};
+size(_, S0) ->
+ S = unicode:characters_to_list(S0, unicode),
+ true = is_list(S),
+ {length(S),S}.
diff --git a/lib/stdlib/src/log_mf_h.erl b/lib/stdlib/src/log_mf_h.erl
index f7f128dac7..19b555a48c 100644
--- a/lib/stdlib/src/log_mf_h.erl
+++ b/lib/stdlib/src/log_mf_h.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -25,6 +25,8 @@
-export([init/1, handle_event/2, handle_info/2, terminate/2]).
-export([handle_call/2, code_change/3]).
+-export_type([args/0]).
+
%%-----------------------------------------------------------------
-type b() :: non_neg_integer().
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index cddf345c76..9257953071 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -78,89 +78,89 @@ obsolete_1(snmp, N, A) ->
end;
obsolete_1(snmpm, agent_info, 3) ->
- {deprecated, {snmpm, agent_info, 2}, "R16B"};
+ {removed, {snmpm, agent_info, 2}, "R16B"};
obsolete_1(snmpm, update_agent_info, 5) ->
- {deprecated, {snmpm, update_agent_info, 4}, "R16B"};
+ {removed, {snmpm, update_agent_info, 4}, "R16B"};
obsolete_1(snmpm, g, 3) ->
- {deprecated, {snmpm, sync_get, 3}, "R16B"};
+ {removed, {snmpm, sync_get, 3}, "R16B"};
obsolete_1(snmpm, g, 4) ->
- {deprecated, {snmpm, sync_get, [3,4]}, "R16B"};
+ {removed, {snmpm, sync_get, [3,4]}, "R16B"};
obsolete_1(snmpm, g, 5) ->
- {deprecated, {snmpm, sync_get, [4,5]}, "R16B"};
+ {removed, {snmpm, sync_get, [4,5]}, "R16B"};
obsolete_1(snmpm, g, 6) ->
- {deprecated, {snmpm, sync_get, [5,6]}, "R16B"};
+ {removed, {snmpm, sync_get, [5,6]}, "R16B"};
obsolete_1(snmpm, g, 7) ->
- {deprecated, {snmpm, sync_get, 6}, "R16B"};
+ {removed, {snmpm, sync_get, 6}, "R16B"};
obsolete_1(snmpm, ag, 3) ->
- {deprecated, {snmpm, async_get, 3}, "R16B"};
+ {removed, {snmpm, async_get, 3}, "R16B"};
obsolete_1(snmpm, ag, 4) ->
- {deprecated, {snmpm, async_get, [3,4]}, "R16B"};
+ {removed, {snmpm, async_get, [3,4]}, "R16B"};
obsolete_1(snmpm, ag, 5) ->
- {deprecated, {snmpm, async_get, [4,5]}, "R16B"};
+ {removed, {snmpm, async_get, [4,5]}, "R16B"};
obsolete_1(snmpm, ag, 6) ->
- {deprecated, {snmpm, async_get, [5,6]}, "R16B"};
+ {removed, {snmpm, async_get, [5,6]}, "R16B"};
obsolete_1(snmpm, ag, 7) ->
- {deprecated, {snmpm, async_get, 6}, "R16B"};
+ {removed, {snmpm, async_get, 6}, "R16B"};
obsolete_1(snmpm, gn, 3) ->
- {deprecated, {snmpm, sync_get_next, 3}, "R16B"};
+ {removed, {snmpm, sync_get_next, 3}, "R16B"};
obsolete_1(snmpm, gn, 4) ->
- {deprecated, {snmpm, sync_get_next, [3,4]}, "R16B"};
+ {removed, {snmpm, sync_get_next, [3,4]}, "R16B"};
obsolete_1(snmpm, gn, 5) ->
- {deprecated, {snmpm, sync_get_next, [4,5]}, "R16B"};
+ {removed, {snmpm, sync_get_next, [4,5]}, "R16B"};
obsolete_1(snmpm, gn, 6) ->
- {deprecated, {snmpm, sync_get_next, [5,6]}, "R16B"};
+ {removed, {snmpm, sync_get_next, [5,6]}, "R16B"};
obsolete_1(snmpm, gn, 7) ->
- {deprecated, {snmpm, sync_get_next, 6}, "R16B"};
+ {removed, {snmpm, sync_get_next, 6}, "R16B"};
obsolete_1(snmpm, agn, 3) ->
- {deprecated, {snmpm, async_get_next, 3}, "R16B"};
+ {removed, {snmpm, async_get_next, 3}, "R16B"};
obsolete_1(snmpm, agn, 4) ->
- {deprecated, {snmpm, async_get_next, [3,4]}, "R16B"};
+ {removed, {snmpm, async_get_next, [3,4]}, "R16B"};
obsolete_1(snmpm, agn, 5) ->
- {deprecated, {snmpm, async_get_next, [4,5]}, "R16B"};
+ {removed, {snmpm, async_get_next, [4,5]}, "R16B"};
obsolete_1(snmpm, agn, 6) ->
- {deprecated, {snmpm, async_get_next, [5,6]}, "R16B"};
+ {removed, {snmpm, async_get_next, [5,6]}, "R16B"};
obsolete_1(snmpm, agn, 7) ->
- {deprecated, {snmpm, async_get_next, 6}, "R16B"};
+ {removed, {snmpm, async_get_next, 6}, "R16B"};
obsolete_1(snmpm, s, 3) ->
- {deprecated, {snmpm, sync_set, 3}, "R16B"};
+ {removed, {snmpm, sync_set, 3}, "R16B"};
obsolete_1(snmpm, s, 4) ->
- {deprecated, {snmpm, sync_set, [3,4]}, "R16B"};
+ {removed, {snmpm, sync_set, [3,4]}, "R16B"};
obsolete_1(snmpm, s, 5) ->
- {deprecated, {snmpm, sync_set, [4,5]}, "R16B"};
+ {removed, {snmpm, sync_set, [4,5]}, "R16B"};
obsolete_1(snmpm, s, 6) ->
- {deprecated, {snmpm, sync_set, [5,6]}, "R16B"};
+ {removed, {snmpm, sync_set, [5,6]}, "R16B"};
obsolete_1(snmpm, s, 7) ->
- {deprecated, {snmpm, sync_set, 6}, "R16B"};
+ {removed, {snmpm, sync_set, 6}, "R16B"};
obsolete_1(snmpm, as, 3) ->
- {deprecated, {snmpm, async_set, 3}, "R16B"};
+ {removed, {snmpm, async_set, 3}, "R16B"};
obsolete_1(snmpm, as, 4) ->
- {deprecated, {snmpm, async_set, [3,4]}, "R16B"};
+ {removed, {snmpm, async_set, [3,4]}, "R16B"};
obsolete_1(snmpm, as, 5) ->
- {deprecated, {snmpm, async_set, [4,5]}, "R16B"};
+ {removed, {snmpm, async_set, [4,5]}, "R16B"};
obsolete_1(snmpm, as, 6) ->
- {deprecated, {snmpm, async_set, [5,6]}, "R16B"};
+ {removed, {snmpm, async_set, [5,6]}, "R16B"};
obsolete_1(snmpm, as, 7) ->
- {deprecated, {snmpm, async_set, 6}, "R16B"};
+ {removed, {snmpm, async_set, 6}, "R16B"};
obsolete_1(snmpm, gb, 5) ->
- {deprecated, {snmpm, sync_get_bulk, 5}, "R16B"};
+ {removed, {snmpm, sync_get_bulk, 5}, "R16B"};
obsolete_1(snmpm, gb, 6) ->
- {deprecated, {snmpm, sync_get_bulk, [5,6]}, "R16B"};
+ {removed, {snmpm, sync_get_bulk, [5,6]}, "R16B"};
obsolete_1(snmpm, gb, 7) ->
- {deprecated, {snmpm, sync_get_bulk, [6,7]}, "R16B"};
+ {removed, {snmpm, sync_get_bulk, [6,7]}, "R16B"};
obsolete_1(snmpm, gb, 8) ->
- {deprecated, {snmpm, sync_get_bulk, [7,8]}, "R16B"};
+ {removed, {snmpm, sync_get_bulk, [7,8]}, "R16B"};
obsolete_1(snmpm, gb, 9) ->
- {deprecated, {snmpm, sync_get_bulk, 8}, "R16B"};
+ {removed, {snmpm, sync_get_bulk, 8}, "R16B"};
obsolete_1(snmpm, agb, 5) ->
- {deprecated, {snmpm, async_get_bulk, 5}, "R16B"};
+ {removed, {snmpm, async_get_bulk, 5}, "R16B"};
obsolete_1(snmpm, agb, 6) ->
- {deprecated, {snmpm, async_get_bulk, [5,6]}, "R16B"};
+ {removed, {snmpm, async_get_bulk, [5,6]}, "R16B"};
obsolete_1(snmpm, agb, 7) ->
- {deprecated, {snmpm, async_get_bulk, [6,7]}, "R16B"};
+ {removed, {snmpm, async_get_bulk, [6,7]}, "R16B"};
obsolete_1(snmpm, agb, 8) ->
- {deprecated, {snmpm, async_get_bulk, [7,8]}, "R16B"};
+ {removed, {snmpm, async_get_bulk, [7,8]}, "R16B"};
obsolete_1(snmpm, agb, 9) ->
- {deprecated, {snmpm, async_get_bulk, 8}, "R16B"};
+ {removed, {snmpm, async_get_bulk, 8}, "R16B"};
%% *** MEGACO ***
@@ -347,7 +347,7 @@ obsolete_1(docb_xml_check, _, _) ->
obsolete_1(asn1rt, F, _) when F == load_driver; F == unload_driver ->
{deprecated,"deprecated (will be removed in R16A); has no effect as drivers are no longer used."};
obsolete_1(ssl, pid, 1) ->
- {deprecated,"deprecated (will be removed in R17); is no longer needed"};
+ {removed,"was removed in R16; is no longer needed"};
obsolete_1(inviso, _, _) ->
{removed,"the inviso application was removed in R16"};
@@ -359,6 +359,45 @@ obsolete_1(ssh, sign_data, 2) ->
"and public_key:sign/3 instead"};
obsolete_1(ssh, verify_data, 3) ->
{deprecated,"deprecated (will be removed in R16A); use public_key:ssh_decode/1, and public_key:verify/4 instead"};
+
+%% Added in R16
+obsolete_1(wxCalendarCtrl, enableYearChange, _) -> %% wx bug documented?
+ {deprecated,"deprecated function not available in wxWidgets-2.9 and later"};
+obsolete_1(wxDC, computeScaleAndOrigin, 1) ->
+ {deprecated,"deprecated function not available in wxWidgets-2.9 and later"};
+obsolete_1(wxClientDC, new, 0) ->
+ {deprecated,"deprecated function not available in wxWidgets-2.9 and later"};
+obsolete_1(wxPaintDC, new, 0) ->
+ {deprecated,"deprecated function not available in wxWidgets-2.9 and later"};
+obsolete_1(wxWindowDC, new, 0) ->
+ {deprecated,"deprecated function not available in wxWidgets-2.9 and later"};
+obsolete_1(wxGraphicsContext, createLinearGradientBrush, 7) ->
+ {deprecated,"deprecated function not available in wxWidgets-2.9 and later"};
+obsolete_1(wxGraphicsContext, createRadialGradientBrush, 8) ->
+ {deprecated,"deprecated function not available in wxWidgets-2.9 and later"};
+obsolete_1(wxGraphicsRenderer, createLinearGradientBrush, 7) ->
+ {deprecated,"deprecated function not available in wxWidgets-2.9 and later"};
+obsolete_1(wxGraphicsRenderer, createRadialGradientBrush, 8) ->
+ {deprecated,"deprecated function not available in wxWidgets-2.9 and later"};
+obsolete_1(wxGridCellEditor, endEdit, 4) ->
+ {deprecated,"deprecated function not available in wxWidgets-2.9 and later"};
+obsolete_1(wxGridCellEditor, paintBackground, 3) ->
+ {deprecated,"deprecated function not available in wxWidgets-2.9 and later"};
+obsolete_1(wxIdleEvent, canSend, 1) ->
+ {deprecated,"deprecated function not available in wxWidgets-2.9 and later"};
+obsolete_1(wxMDIClientWindow, new, 1) ->
+ {deprecated,"deprecated function not available in wxWidgets-2.9 and later"};
+obsolete_1(wxMDIClientWindow, new, 2) ->
+ {deprecated,"deprecated function not available in wxWidgets-2.9 and later"};
+obsolete_1(wxPostScriptDC, getResolution, 0) ->
+ {deprecated,"deprecated function not available in wxWidgets-2.9 and later"};
+obsolete_1(wxPostScriptDC, setResolution, 1) ->
+ {deprecated,"deprecated function not available in wxWidgets-2.9 and later"};
+obsolete_1(wxCursor, new, 3) ->
+ {deprecated,"deprecated function not available in wxWidgets-2.9 and later"};
+obsolete_1(wxCursor, new, 4) ->
+ {deprecated,"deprecated function not available in wxWidgets-2.9 and later"};
+
obsolete_1(_, _, _) ->
no.
diff --git a/lib/stdlib/src/proc_lib.erl b/lib/stdlib/src/proc_lib.erl
index 02bcbb5a60..4bca4c1e6d 100644
--- a/lib/stdlib/src/proc_lib.erl
+++ b/lib/stdlib/src/proc_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -184,6 +184,17 @@ check_for_monitor(SpawnOpts) ->
false
end.
+spawn_mon(M,F,A) ->
+ Parent = get_my_name(),
+ Ancestors = get_ancestors(),
+ erlang:spawn_monitor(?MODULE, init_p, [Parent,Ancestors,M,F,A]).
+
+spawn_opt_mon(M, F, A, Opts) when is_atom(M), is_atom(F), is_list(A) ->
+ Parent = get_my_name(),
+ Ancestors = get_ancestors(),
+ check_for_monitor(Opts),
+ erlang:spawn_opt(?MODULE, init_p, [Parent,Ancestors,M,F,A], [monitor|Opts]).
+
-spec hibernate(Module, Function, Args) -> no_return() when
Module :: module(),
Function :: atom(),
@@ -270,8 +281,8 @@ start(M, F, A) when is_atom(M), is_atom(F), is_list(A) ->
Ret :: term() | {error, Reason :: term()}.
start(M, F, A, Timeout) when is_atom(M), is_atom(F), is_list(A) ->
- Pid = ?MODULE:spawn(M, F, A),
- sync_wait(Pid, Timeout).
+ PidRef = spawn_mon(M, F, A),
+ sync_wait_mon(PidRef, Timeout).
-spec start(Module, Function, Args, Time, SpawnOpts) -> Ret when
Module :: module(),
@@ -282,8 +293,8 @@ start(M, F, A, Timeout) when is_atom(M), is_atom(F), is_list(A) ->
Ret :: term() | {error, Reason :: term()}.
start(M, F, A, Timeout, SpawnOpts) when is_atom(M), is_atom(F), is_list(A) ->
- Pid = ?MODULE:spawn_opt(M, F, A, SpawnOpts),
- sync_wait(Pid, Timeout).
+ PidRef = spawn_opt_mon(M, F, A, SpawnOpts),
+ sync_wait_mon(PidRef, Timeout).
-spec start_link(Module, Function, Args) -> Ret when
Module :: module(),
@@ -330,6 +341,23 @@ sync_wait(Pid, Timeout) ->
{error, timeout}
end.
+sync_wait_mon({Pid, Ref}, Timeout) ->
+ receive
+ {ack, Pid, Return} ->
+ erlang:demonitor(Ref, [flush]),
+ Return;
+ {'DOWN', Ref, _Type, Pid, Reason} ->
+ {error, Reason};
+ {'EXIT', Pid, Reason} -> %% link as spawn_opt?
+ erlang:demonitor(Ref, [flush]),
+ {error, Reason}
+ after Timeout ->
+ erlang:demonitor(Ref, [flush]),
+ exit(Pid, kill),
+ flush(Pid),
+ {error, timeout}
+ end.
+
-spec flush(pid()) -> 'true'.
flush(Pid) ->
diff --git a/lib/stdlib/src/proplists.erl b/lib/stdlib/src/proplists.erl
index e3eda5d932..204f8e128c 100644
--- a/lib/stdlib/src/proplists.erl
+++ b/lib/stdlib/src/proplists.erl
@@ -51,20 +51,21 @@
-export_type([property/0, proplist/0]).
--type property() :: atom() | tuple().
+-type property() :: atom() | tuple().
-type proplist() :: [property()].
%% ---------------------------------------------------------------------
%% @doc Creates a normal form (minimal) representation of a property. If
-%% <code>P</code> is <code>{Key, true}</code> where <code>Key</code> is
-%% an atom, this returns <code>Key</code>, otherwise the whole term
-%% <code>P</code> is returned.
+%% <code>PropertyIn</code> is <code>{Key, true}</code> where
+%% <code>Key</code> is an atom, this returns <code>Key</code>, otherwise
+%% the whole term <code>PropertyIn</code> is returned.
%%
%% @see property/2
--spec property(Property) -> Property when
- Property :: property().
+-spec property(PropertyIn) -> PropertyOut when
+ PropertyIn :: property(),
+ PropertyOut :: property().
property({Key, true}) when is_atom(Key) ->
Key;
@@ -92,13 +93,14 @@ property(Key, Value) ->
%% ---------------------------------------------------------------------
-%% @doc Unfolds all occurences of atoms in <code>List</code> to tuples
+%% @doc Unfolds all occurences of atoms in <code>ListIn</code> to tuples
%% <code>{Atom, true}</code>.
%%
%% @see compact/1
--spec unfold(List) -> List when
- List :: [term()].
+-spec unfold(ListIn) -> ListOut when
+ ListIn :: [term()],
+ ListOut :: [term()].
unfold([P | Ps]) ->
if is_atom(P) ->
@@ -110,16 +112,17 @@ unfold([]) ->
[].
%% @doc Minimizes the representation of all entries in the list. This is
-%% equivalent to <code>[property(P) || P &lt;- List]</code>.
+%% equivalent to <code>[property(P) || P &lt;- ListIn]</code>.
%%
%% @see unfold/1
%% @see property/1
--spec compact(List) -> List when
- List :: [property()].
+-spec compact(ListIn) -> ListOut when
+ ListIn :: [property()],
+ ListOut :: [property()].
-compact(List) ->
- [property(P) || P <- List].
+compact(ListIn) ->
+ [property(P) || P <- ListIn].
%% ---------------------------------------------------------------------
@@ -199,7 +202,7 @@ is_defined(_Key, []) ->
-spec get_value(Key, List) -> term() when
Key :: term(),
- List :: List::[term()].
+ List :: [term()].
get_value(Key, List) ->
get_value(Key, List, undefined).
@@ -272,9 +275,10 @@ get_all_values(_Key, []) ->
%%
%% @see get_all_values/2
--spec append_values(Key, List) -> List when
+-spec append_values(Key, ListIn) -> ListOut when
Key :: term(),
- List :: [term()].
+ ListIn :: [term()],
+ ListOut :: [term()].
append_values(Key, [P | Ps]) ->
if is_atom(P), P =:= Key ->
@@ -357,7 +361,7 @@ get_keys([], Keys) ->
-spec delete(Key, List) -> List when
Key :: term(),
- List::[term()].
+ List :: [term()].
delete(Key, [P | Ps]) ->
if is_atom(P), P =:= Key ->
@@ -374,7 +378,7 @@ delete(_, []) ->
%% ---------------------------------------------------------------------
%% @doc Substitutes keys of properties. For each entry in
-%% <code>List</code>, if it is associated with some key <code>K1</code>
+%% <code>ListIn</code>, if it is associated with some key <code>K1</code>
%% such that <code>{K1, K2}</code> occurs in <code>Aliases</code>, the
%% key of the entry is changed to <code>Key2</code>. If the same
%% <code>K1</code> occurs more than once in <code>Aliases</code>, only
@@ -388,10 +392,11 @@ delete(_, []) ->
%% @see substitute_negations/2
%% @see normalize/2
--spec substitute_aliases(Aliases, List) -> List when
+-spec substitute_aliases(Aliases, ListIn) -> ListOut when
Aliases :: [{Key, Key}],
Key :: term(),
- List::[term()].
+ ListIn :: [term()],
+ ListOut :: [term()].
substitute_aliases(As, Props) ->
[substitute_aliases_1(As, P) || P <- Props].
@@ -411,13 +416,13 @@ substitute_aliases_1([], P) ->
%% ---------------------------------------------------------------------
%% @doc Substitutes keys of boolean-valued properties and simultaneously
-%% negates their values. For each entry in <code>List</code>, if it is
+%% negates their values. For each entry in <code>ListIn</code>, if it is
%% associated with some key <code>K1</code> such that <code>{K1,
%% K2}</code> occurs in <code>Negations</code>, then if the entry was
%% <code>{K1, true}</code> it will be replaced with <code>{K2,
%% false}</code>, otherwise it will be replaced with <code>{K2,
%% true}</code>, thus changing the name of the option and simultaneously
-%% negating the value given by <code>get_bool(List)</code>. If the same
+%% negating the value given by <code>get_bool(ListIn)</code>. If the same
%% <code>K1</code> occurs more than once in <code>Negations</code>, only
%% the first occurrence is used.
%%
@@ -431,10 +436,11 @@ substitute_aliases_1([], P) ->
%% @see substitute_aliases/2
%% @see normalize/2
--spec substitute_negations(Negations, List) -> List when
+-spec substitute_negations(Negations, ListIn) -> ListOut when
Negations :: [{Key, Key}],
Key :: term(),
- List :: [term()].
+ ListIn :: [term()],
+ ListOut :: [term()].
substitute_negations(As, Props) ->
[substitute_negations_1(As, P) || P <- Props].
@@ -466,11 +472,11 @@ substitute_negations_1([], P) ->
%% @doc Expands particular properties to corresponding sets of
%% properties (or other terms). For each pair <code>{Property,
%% Expansion}</code> in <code>Expansions</code>, if <code>E</code> is
-%% the first entry in <code>List</code> with the same key as
+%% the first entry in <code>ListIn</code> with the same key as
%% <code>Property</code>, and <code>E</code> and <code>Property</code>
%% have equivalent normal forms, then <code>E</code> is replaced with
%% the terms in <code>Expansion</code>, and any following entries with
-%% the same key are deleted from <code>List</code>.
+%% the same key are deleted from <code>ListIn</code>.
%%
%% <p>For example, the following expressions all return <code>[fie, bar,
%% baz, fum]</code>:
@@ -497,9 +503,10 @@ substitute_negations_1([], P) ->
%%
%% @see normalize/2
--spec expand(Expansions, List) -> List when
+-spec expand(Expansions, ListIn) -> ListOut when
Expansions :: [{Property :: property(), Expansion :: [term()]}],
- List :: [term()].
+ ListIn :: [term()],
+ ListOut :: [term()].
expand(Es, Ps) when is_list(Ps) ->
Es1 = [{property(P), V} || {P, V} <- Es],
@@ -599,15 +606,16 @@ flatten([]) ->
%% @see expand/2
%% @see compact/1
--spec normalize(List, Stages) -> List when
- List :: [term()],
+-spec normalize(ListIn, Stages) -> ListOut when
+ ListIn :: [term()],
Stages :: [Operation],
Operation :: {'aliases', Aliases}
| {'negations', Negations}
| {'expand', Expansions},
Aliases :: [{Key, Key}],
Negations :: [{Key, Key}],
- Expansions :: [{Property :: property(), Expansion :: [term()]}].
+ Expansions :: [{Property :: property(), Expansion :: [term()]}],
+ ListOut :: [term()].
normalize(L, [{aliases, As} | Xs]) ->
normalize(substitute_aliases(As, L), Xs);
diff --git a/lib/stdlib/src/qlc.erl b/lib/stdlib/src/qlc.erl
index 2b691e6abf..9b71d0edb8 100644
--- a/lib/stdlib/src/qlc.erl
+++ b/lib/stdlib/src/qlc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -125,7 +125,7 @@
-define(THROWN_ERROR, {?MODULE, throw_error, _, _}).
--export_type([query_handle/0]).
+-export_type([query_cursor/0, query_handle/0]).
%%% A query handle is a tuple {qlc_handle, Handle} where Handle is one
%%% of #qlc_append, #qlc_table, #qlc_sort, and #qlc_lc.
diff --git a/lib/stdlib/src/qlc_pt.erl b/lib/stdlib/src/qlc_pt.erl
index ad25fd559c..d441f38e44 100644
--- a/lib/stdlib/src/qlc_pt.erl
+++ b/lib/stdlib/src/qlc_pt.erl
@@ -31,9 +31,6 @@
%% Also in qlc.erl.
-define(QLC_Q(L1, L2, L3, L4, LC, Os),
{call,L1,{remote,L2,{atom,L3,?APIMOD},{atom,L4,?Q}},[LC | Os]}).
--define(QLC_QQ(L1, L2, L3, L4, L5, L6, LC, Os), % packages...
- {call,L1,{remote,L2,{record_field,L3,{atom,L4,''},
- {atom,L5,?APIMOD}},{atom,L6,?Q}},[LC | Os]}).
-define(IMP_Q(L1, L2, LC, Os), {call,L,{atom,L2,?Q},[LC | Os]}).
%% Also in qlc.erl.
@@ -2475,13 +2472,6 @@ qlcmf(?QLC_Q(L1, L2, L3, L4, LC0, Os0), F, Imp, A0, No0) when length(Os0) < 2 ->
NL = make_lcid(L1, No),
{T, A} = F(NL, LC, A2),
{?QLC_Q(L1, L2, L3, L4, T, Os), A, No + 1};
-qlcmf(?QLC_QQ(L1, L2, L3, L4, L5, L6, LC0, Os0),
- F, Imp, A0, No0) when length(Os0) < 2 ->
- {Os, A1, No1} = qlcmf(Os0, F, Imp, A0, No0),
- {LC, A2, No} = qlcmf(LC0, F, Imp, A1, No1), % nested...
- NL = make_lcid(L1, No),
- {T, A} = F(NL, LC, A2),
- {?QLC_QQ(L1, L2, L3, L4, L5, L6, T, Os), A, No + 1};
qlcmf(?IMP_Q(L1, L2, LC0, Os0), F, Imp=true, A0, No0) when length(Os0) < 2 ->
{Os, A1, No1} = qlcmf(Os0, F, Imp, A0, No0),
{LC, A2, No} = qlcmf(LC0, F, Imp, A1, No1), % nested...
diff --git a/lib/stdlib/src/sets.erl b/lib/stdlib/src/sets.erl
index 3fd6c81e5f..e6f05b71d4 100644
--- a/lib/stdlib/src/sets.erl
+++ b/lib/stdlib/src/sets.erl
@@ -1,7 +1,8 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -17,7 +18,7 @@
%% %CopyrightEnd%
%%
-%% We use the dynamic hashing techniques by Per-�ke Larsson as
+%% We use the dynamic hashing techniques by Per-Åke Larsson as
%% described in "The Design and Implementation of Dynamic Hashing for
%% Sets and Tables in Icon" by Griswold and Townsend. Much of the
%% terminology comes from that paper as well.
diff --git a/lib/stdlib/src/shell.erl b/lib/stdlib/src/shell.erl
index dc450f0ee6..5c929d2f51 100644
--- a/lib/stdlib/src/shell.erl
+++ b/lib/stdlib/src/shell.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -128,7 +128,7 @@ start_restricted(RShMod) when is_atom(RShMod) ->
error_logger:error_report(
lists:flatten(
io_lib:fwrite(
- <<"Restricted shell module ~w not found: ~p\n">>,
+ "Restricted shell module ~w not found: ~"++cs_p() ++"\n",
[RShMod,What]))),
Error
end.
@@ -139,16 +139,6 @@ stop_restricted() ->
application:unset_env(stdlib, restricted_shell),
exit(restricted_shell_stopped).
-default_packages() ->
- [].
-%%% ['erl','erl.lang'].
-
-default_modules() ->
- [].
-%%% [{pdict, 'erl.lang.proc.pdict'},
-%%% {keylist, 'erl.lang.list.keylist'},
-%%% {debug, 'erl.system.debug'}].
-
-spec server(boolean(), boolean()) -> 'terminated'.
server(NoCtrlG, StartSync) ->
@@ -183,16 +173,7 @@ server(StartSync) ->
end
end,
%% Our spawner has fixed the process groups.
- Bs0 = erl_eval:new_bindings(),
- Bs = lists:foldl(fun ({K, V}, D) ->
- erl_eval:add_binding({module,K}, V, D)
- end,
- lists:foldl(fun (P, D) ->
- import_all(P, D)
- end,
- Bs0, default_packages()),
- default_modules()),
- %% io:fwrite("Imported modules: ~p.\n", [erl_eval:bindings(Bs)]),
+ Bs = erl_eval:new_bindings(),
%% Use an Ets table for record definitions. It takes too long to
%% send a huge term to and from the evaluator. Ets makes it
@@ -230,9 +211,10 @@ server(StartSync) ->
ok;
{RShMod2,What2} ->
io:fwrite(
- <<"Warning! Restricted shell module ~w not found: ~p.\n"
- "Only the commands q() and init:stop() will be allowed!\n">>,
- [RShMod2,What2]),
+ ("Warning! Restricted shell module ~w not found: ~"
+ ++cs_p()++".\n"
+ "Only the commands q() and init:stop() will be allowed!\n"),
+ [RShMod2,What2]),
application:set_env(stdlib, restricted_shell, ?MODULE)
end,
@@ -244,7 +226,7 @@ server_loop(N0, Eval_0, Bs00, RT, Ds00, History0, Results0) ->
{Eval_1,Bs0,Ds0,Prompt} = prompt(N, Eval_0, Bs00, RT, Ds00),
{Res,Eval0} = get_command(Prompt, Eval_1, Bs0, RT, Ds0),
case Res of
- {ok,Es0,_EndLine} ->
+ {ok,Es0} ->
case expand_hist(Es0, N) of
{ok,Es} ->
{V,Eval,Bs,Ds} = shell_cmd(Es, Eval0, Bs0, RT, Ds0, cmd),
@@ -263,11 +245,11 @@ server_loop(N0, Eval_0, Bs00, RT, Ds00, History0, Results0) ->
end,
server_loop(N, Eval, Bs, RT, Ds, History, Results);
{error,E} ->
- fwrite_severity(benign, <<"~s">>, [E]),
+ fwrite_severity(benign, <<"~ts">>, [E]),
server_loop(N0, Eval0, Bs0, RT, Ds0, History0, Results0)
end;
- {error,{Line,Mod,What},_EndLine} ->
- fwrite_severity(benign, <<"~w: ~s">>,
+ {error,{Line,Mod,What}} ->
+ fwrite_severity(benign, <<"~w: ~ts">>,
[Line, Mod:format_error(What)]),
server_loop(N0, Eval0, Bs0, RT, Ds0, History0, Results0);
{error,terminated} -> %Io process terminated
@@ -277,20 +259,35 @@ server_loop(N0, Eval_0, Bs00, RT, Ds00, History0, Results0) ->
exit(Eval0, kill),
{_,Eval,_,_} = shell_rep(Eval0, Bs0, RT, Ds0),
server_loop(N0, Eval, Bs0, RT, Ds0, History0, Results0);
- {error,tokens} -> %Most probably unicode > 255
+ {error,tokens} -> %Most probably character > 255
fwrite_severity(benign, <<"~w: Invalid tokens.">>,
[N]),
server_loop(N0, Eval0, Bs0, RT, Ds0, History0, Results0);
- {eof,_EndLine} ->
- fwrite_severity(fatal, <<"Terminating erlang (~w)">>, [node()]),
- halt();
eof ->
fwrite_severity(fatal, <<"Terminating erlang (~w)">>, [node()]),
halt()
end.
get_command(Prompt, Eval, Bs, RT, Ds) ->
- Parse = fun() -> exit(io:parse_erl_exprs(Prompt)) end,
+ Parse =
+ fun() ->
+ exit(
+ case
+ io:scan_erl_exprs(group_leader(), Prompt, 1, [unicode])
+ of
+ {ok,Toks,_EndPos} ->
+ erl_parse:parse_exprs(Toks);
+ {eof,_EndPos} ->
+ eof;
+ {error,ErrorInfo,_EndPos} ->
+ %% Skip the rest of the line:
+ _ = io:get_line(''),
+ {error,ErrorInfo};
+ Else ->
+ Else
+ end
+ )
+ end,
Pid = spawn_link(Parse),
get_command1(Pid, Eval, Bs, RT, Ds).
@@ -337,7 +334,7 @@ get_prompt_func() ->
end.
bad_prompt_func(M) ->
- fwrite_severity(benign, <<"Bad prompt function: ~p">>, [M]).
+ fwrite_severity(benign, "Bad prompt function: ~"++cs_p(), [M]).
default_prompt(N) ->
%% Don't bother flattening the list irrespective of what the
@@ -453,7 +450,8 @@ expand_bin_elements([{bin_element,L,E,Sz,Ts}|Fs], C) ->
no_command(N) ->
throw({error,
- io_lib:fwrite(<<"~s: command not found">>, [erl_pp:expr(N)])}).
+ io_lib:fwrite(<<"~ts: command not found">>,
+ [erl_pp:expr(N, enc())])}).
%% add_cmd(Number, Expressions, Value)
%% get_cmd(Number, CurrentCommand)
@@ -518,7 +516,7 @@ shell_rep(Ev, Bs0, RT, Ds0) ->
{shell_rep,Ev,{value,V,Bs,Ds}} ->
{V,Ev,Bs,Ds};
{shell_rep,Ev,{command_error,{Line,M,Error}}} ->
- fwrite_severity(benign, <<"~w: ~s">>,
+ fwrite_severity(benign, <<"~w: ~ts">>,
[Line, M:format_error(Error)]),
{{'EXIT',Error},Ev,Bs0,Ds0};
{shell_req,Ev,get_cmd} ->
@@ -570,9 +568,10 @@ report_exception(Class, Severity, {Reason,Stacktrace}, RT) ->
I = iolist_size(Tag) + 1,
PF = fun(Term, I1) -> pp(Term, I1, RT) end,
SF = fun(M, _F, _A) -> (M =:= erl_eval) or (M =:= ?MODULE) end,
- io:requests([{put_chars, Tag},
- {put_chars,
- lib:format_exception(I, Class, Reason, Stacktrace, SF, PF)},
+ Enc = encoding(),
+ Str = lib:format_exception(I, Class, Reason, Stacktrace, SF, PF, Enc),
+ io:requests([{put_chars, latin1, Tag},
+ {put_chars, unicode, Str},
nl]).
start_eval(Bs, RT, Ds) ->
@@ -671,7 +670,8 @@ exprs([E0|Es], Bs1, RT, Lf, Ef, Bs0, W) ->
if
Es =:= [] ->
VS = pp(V0, 1, RT),
- [io:requests([{put_chars, VS}, nl]) || W =:= cmd],
+ [io:requests([{put_chars, unicode, VS}, nl]) ||
+ W =:= cmd],
%% Don't send the result back if it will be
%% discarded anyway.
V = if
@@ -753,7 +753,7 @@ used_records(E) ->
{expr, E}.
fwrite_severity(Severity, S, As) ->
- io:fwrite(<<"~s\n">>, [format_severity(Severity, S, As)]).
+ io:fwrite(<<"~ts\n">>, [format_severity(Severity, S, As)]).
format_severity(Severity, S, As) ->
add_severity(Severity, io_lib:fwrite(S, As)).
@@ -958,13 +958,13 @@ local_func(rd, [{atom,_,RecName},RecDef0], Bs, _Shell, RT, _Lf, _Ef) ->
RecDef = expand_value(RecDef0),
RDs = lists:flatten(erl_pp:expr(RecDef)),
Attr = lists:concat(["-record('", RecName, "',", RDs, ")."]),
- {ok, Tokens, _} = erl_scan:string(Attr),
+ {ok, Tokens, _} = erl_scan:string(Attr, 1, [unicode]),
case erl_parse:parse_form(Tokens) of
{ok,AttrForm} ->
[RN] = add_records([AttrForm], Bs, RT),
{value,RN,Bs};
{error,{_Line,M,ErrDesc}} ->
- ErrStr = io_lib:fwrite(<<"~s">>, [M:format_error(ErrDesc)]),
+ ErrStr = io_lib:fwrite(<<"~ts">>, [M:format_error(ErrDesc)]),
exit(lists:flatten(ErrStr))
end;
local_func(rd, [_,_], _Bs, _Shell, _RT, _Lf, _Ef) ->
@@ -988,11 +988,13 @@ local_func(rl, [A], Bs0, _Shell, RT, Lf, Ef) ->
{value,list_records(record_defs(RT, listify(Recs))),Bs};
local_func(rp, [A], Bs0, _Shell, RT, Lf, Ef) ->
{[V],Bs} = expr_list([A], Bs0, Lf, Ef),
- W = columns(),
- io:requests([{put_chars,
- io_lib_pretty:print(V, 1, W, -1, ?CHAR_MAX,
- record_print_fun(RT))},
- nl]),
+ Cs = io_lib_pretty:print(V, ([{column, 1},
+ {line_length, columns()},
+ {depth, -1},
+ {max_chars, ?CHAR_MAX},
+ {record_print_fun, record_print_fun(RT)}]
+ ++ enc())),
+ io:requests([{put_chars, unicode, Cs}, nl]),
{value,ok,Bs};
local_func(rr, [A], Bs0, _Shell, RT, Lf, Ef) ->
{[File],Bs} = expr_list([A], Bs0, Lf, Ef),
@@ -1012,38 +1014,6 @@ local_func(which, [{atom,_,M}], Bs, _Shell, _RT, _Lf, _Ef) ->
end;
local_func(which, [_Other], _Bs, _Shell, _RT, _Lf, _Ef) ->
erlang:raise(error, function_clause, [{shell,which,1}]);
-local_func(import, [M], Bs, _Shell, _RT, _Lf, _Ef) ->
- case erl_parse:package_segments(M) of
- error -> erlang:raise(error, function_clause, [{shell,import,1}]);
- M1 ->
- Mod = packages:concat(M1),
- case packages:is_valid(Mod) of
- true ->
- Key = list_to_atom(packages:last(Mod)),
- Mod1 = list_to_atom(Mod),
- {value,ok,erl_eval:add_binding({module,Key}, Mod1, Bs)};
- false ->
- exit({{bad_module_name, Mod}, [{shell,import,1}]})
- end
- end;
-local_func(import_all, [P], Bs0, _Shell, _RT, _Lf, _Ef) ->
- case erl_parse:package_segments(P) of
- error -> erlang:raise(error, function_clause, [{shell,import_all,1}]);
- P1 ->
- Name = packages:concat(P1),
- case packages:is_valid(Name) of
- true ->
- Bs1 = import_all(Name, Bs0),
- {value,ok,Bs1};
- false ->
- exit({{bad_package_name, Name},
- [{shell,import_all,1}]})
- end
- end;
-local_func(use, [M], Bs, Shell, RT, Lf, Ef) ->
- local_func(import, [M], Bs, Shell, RT, Lf, Ef);
-local_func(use_all, [M], Bs, Shell, RT, Lf, Ef) ->
- local_func(import_all, [M], Bs, Shell, RT, Lf, Ef);
local_func(history, [{integer,_,N}], Bs, _Shell, _RT, _Lf, _Ef) ->
{value,history(N),Bs};
local_func(history, [_Other], _Bs, _Shell, _RT, _Lf, _Ef) ->
@@ -1166,7 +1136,7 @@ add_records(RAs, Bs0, RT) ->
case check_command([], Bs1) of
{error,{_Line,M,ErrDesc}} ->
%% A source file that has not been compiled.
- ErrStr = io_lib:fwrite(<<"~s">>, [M:format_error(ErrDesc)]),
+ ErrStr = io_lib:fwrite(<<"~ts">>, [M:format_error(ErrDesc)]),
exit(lists:flatten(ErrStr));
ok ->
true = ets:insert(RT, Recs),
@@ -1323,15 +1293,6 @@ record_attrs(Forms) ->
%%% End of reading record information from file(s)
-import_all(P, Bs0) ->
- Ms = packages:find_modules(P),
- lists:foldl(fun (M, Bs) ->
- Key = list_to_atom(M),
- M1 = list_to_atom(packages:concat(P, M)),
- erl_eval:add_binding({module,Key}, M1, Bs)
- end,
- Bs0, Ms).
-
shell_req(Shell, Req) ->
Shell ! {shell_req,self(),Req},
receive
@@ -1343,25 +1304,25 @@ list_commands([{{N,command},Es0}, {{N,result}, V} |Ds], RT) ->
VS = pp(V, 4, RT),
Ns = io_lib:fwrite(<<"~w: ">>, [N]),
I = iolist_size(Ns),
- io:requests([{put_chars, Ns},
- {format,<<"~s\n">>,[erl_pp:exprs(Es, I, none)]},
+ io:requests([{put_chars, latin1, Ns},
+ {format,<<"~ts\n">>,[erl_pp:exprs(Es, I, enc())]},
{format,<<"-> ">>,[]},
- {put_chars, VS},
+ {put_chars, unicode, VS},
nl]),
list_commands(Ds, RT);
list_commands([{{N,command},Es0} |Ds], RT) ->
Es = prep_list_commands(Es0),
Ns = io_lib:fwrite(<<"~w: ">>, [N]),
I = iolist_size(Ns),
- io:requests([{put_chars, Ns},
- {format,<<"~s\n">>,[erl_pp:exprs(Es, I, none)]}]),
+ io:requests([{put_chars, latin1, Ns},
+ {format,<<"~ts\n">>,[erl_pp:exprs(Es, I, enc())]}]),
list_commands(Ds, RT);
list_commands([_D|Ds], RT) ->
list_commands(Ds, RT);
list_commands([], _RT) -> ok.
list_bindings([{{module,M},Val}|Bs], RT) ->
- io:fwrite(<<"~p is ~p\n">>, [M,Val]),
+ io:fwrite(<<"~w is ~w\n">>, [M,Val]),
list_bindings(Bs, RT);
list_bindings([{Name,Val}|Bs], RT) ->
case erl_eval:fun_data(Val) of
@@ -1369,13 +1330,13 @@ list_bindings([{Name,Val}|Bs], RT) ->
FCs = expand_value(FCs0), % looks nicer
F = {'fun',0,{clauses,FCs}},
M = {match,0,{var,0,Name},F},
- io:fwrite(<<"~s\n">>, [erl_pp:expr(M)]);
+ io:fwrite(<<"~ts\n">>, [erl_pp:expr(M, enc())]);
false ->
Namel = io_lib:fwrite(<<"~s = ">>, [Name]),
Nl = iolist_size(Namel)+1,
ValS = pp(Val, Nl, RT),
- io:requests([{put_chars, Namel},
- {put_chars, ValS},
+ io:requests([{put_chars, latin1, Namel},
+ {put_chars, unicode, ValS},
nl])
end,
list_bindings(Bs, RT);
@@ -1384,7 +1345,7 @@ list_bindings([], _RT) ->
list_records(Records) ->
lists:foreach(fun({_Name,Attr}) ->
- io:fwrite(<<"~s">>, [erl_pp:attribute(Attr)])
+ io:fwrite(<<"~ts">>, [erl_pp:attribute(Attr, enc())])
end, Records).
record_defs(RT, Names) ->
@@ -1427,8 +1388,20 @@ get_history_and_results() ->
{History, erlang:min(Results, History)}.
pp(V, I, RT) ->
- io_lib_pretty:print(V, I, columns(), ?LINEMAX, ?CHAR_MAX,
- record_print_fun(RT)).
+ pp(V, I, RT, enc()).
+
+pp(V, I, RT, Enc) ->
+ io_lib_pretty:print(V, ([{column, I}, {line_length, columns()},
+ {depth, ?LINEMAX}, {max_chars, ?CHAR_MAX},
+ {record_print_fun, record_print_fun(RT)}]
+ ++ Enc)).
+
+%% Control sequence 'p' possibly with Unicode translation modifier
+cs_p() ->
+ case encoding() of
+ latin1 -> "p";
+ unicode -> "tp"
+ end.
columns() ->
case io:columns() of
@@ -1436,9 +1409,20 @@ columns() ->
_ -> 80
end.
+encoding() ->
+ [{encoding, Encoding}] = enc(),
+ Encoding.
+
+enc() ->
+ case lists:keyfind(encoding, 1, io:getopts()) of
+ false -> [{encoding,latin1}]; % should never happen
+ Enc -> [Enc]
+ end.
+
garb(Shell) ->
erlang:garbage_collect(Shell),
catch erlang:garbage_collect(whereis(user)),
+ catch erlang:garbage_collect(whereis(group)),
catch erlang:garbage_collect(group_leader()),
erlang:garbage_collect().
@@ -1458,7 +1442,8 @@ check_env(V) ->
ok;
{ok, Val} ->
Txt = io_lib:fwrite(
- <<"Invalid value of STDLIB configuration parameter ~p: ~p\n">>,
+ ("Invalid value of STDLIB configuration parameter ~w: ~"
+ ++cs_p()++"\n"),
[V, Val]),
error_logger:info_report(lists:flatten(Txt))
end.
diff --git a/lib/stdlib/src/string.erl b/lib/stdlib/src/string.erl
index fc029a582f..03f0a19f14 100644
--- a/lib/stdlib/src/string.erl
+++ b/lib/stdlib/src/string.erl
@@ -1,3 +1,4 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
@@ -257,7 +258,7 @@ chars(C, N, Tail) when N > 0 ->
chars(C, 0, Tail) when is_integer(C) ->
Tail.
-%% Torbj�rn's bit.
+%% Torbjörn's bit.
%%% COPIES %%%
diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl
index 7d3c5a0e21..9f93747c3e 100644
--- a/lib/stdlib/src/supervisor.erl
+++ b/lib/stdlib/src/supervisor.erl
@@ -104,7 +104,9 @@
%%% SupName = {local, atom()} | {global, atom()}.
%%% ---------------------------------------------------
--type startlink_err() :: {'already_started', pid()} | 'shutdown' | term().
+-type startlink_err() :: {'already_started', pid()}
+ | {'shutdown', term()}
+ | term().
-type startlink_ret() :: {'ok', pid()} | 'ignore' | {'error', startlink_err()}.
-spec start_link(Module, Args) -> startlink_ret() when
@@ -221,8 +223,10 @@ cast(Supervisor, Req) ->
-type init_sup_name() :: sup_name() | 'self'.
--type stop_rsn() :: 'shutdown' | {'bad_return', {module(),'init', term()}}
- | {'bad_start_spec', term()} | {'start_spec', term()}
+-type stop_rsn() :: {'shutdown', term()}
+ | {'bad_return', {module(),'init', term()}}
+ | {'bad_start_spec', term()}
+ | {'start_spec', term()}
| {'supervisor_data', term()}.
-spec init({init_sup_name(), module(), [term()]}) ->
@@ -253,9 +257,9 @@ init_children(State, StartSpec) ->
case start_children(Children, SupName) of
{ok, NChildren} ->
{ok, State#state{children = NChildren}};
- {error, NChildren} ->
+ {error, NChildren, Reason} ->
terminate_children(NChildren, SupName),
- {stop, shutdown}
+ {stop, {shutdown, Reason}}
end;
Error ->
{stop, {start_spec, Error}}
@@ -275,9 +279,9 @@ init_dynamic(_State, StartSpec) ->
%% Func: start_children/2
%% Args: Children = [child_rec()] in start order
%% SupName = {local, atom()} | {global, atom()} | {pid(), Mod}
-%% Purpose: Start all children. The new list contains #child's
+%% Purpose: Start all children. The new list contains #child's
%% with pids.
-%% Returns: {ok, NChildren} | {error, NChildren}
+%% Returns: {ok, NChildren} | {error, NChildren, Reason}
%% NChildren = [child_rec()] in termination order (reversed
%% start order)
%%-----------------------------------------------------------------
@@ -293,7 +297,8 @@ start_children([Child|Chs], NChildren, SupName) ->
start_children(Chs, [Child#child{pid = Pid}|NChildren], SupName);
{error, Reason} ->
report_error(start_error, Reason, Child, SupName),
- {error, lists:reverse(Chs) ++ [Child | NChildren]}
+ {error, lists:reverse(Chs) ++ [Child | NChildren],
+ {failed_to_start_child,Child#child.name,Reason}}
end;
start_children([], NChildren, _SupName) ->
{ok, NChildren}.
@@ -793,7 +798,7 @@ restart(rest_for_one, Child, State) ->
case start_children(ChAfter2, State#state.name) of
{ok, ChAfter3} ->
{ok, State#state{children = ChAfter3 ++ ChBefore}};
- {error, ChAfter3} ->
+ {error, ChAfter3, _Reason} ->
NChild = Child#child{pid=restarting(Child#child.pid)},
NState = State#state{children = ChAfter3 ++ ChBefore},
{try_again, replace_child(NChild,NState)}
@@ -804,7 +809,7 @@ restart(one_for_all, Child, State) ->
case start_children(Children2, State#state.name) of
{ok, NChs} ->
{ok, State#state{children = NChs}};
- {error, NChs} ->
+ {error, NChs, _Reason} ->
NChild = Child#child{pid=restarting(Child#child.pid)},
NState = State#state{children = NChs},
{try_again, replace_child(NChild,NState)}
diff --git a/lib/stdlib/src/sys.erl b/lib/stdlib/src/sys.erl
index f34201604c..2d6287814e 100644
--- a/lib/stdlib/src/sys.erl
+++ b/lib/stdlib/src/sys.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -32,12 +32,25 @@
%% Types
%%-----------------------------------------------------------------
+-export_type([dbg_opt/0]).
+
-type name() :: pid() | atom() | {'global', atom()}.
-type system_event() :: {'in', Msg :: _}
| {'in', Msg :: _, From :: _}
| {'out', Msg :: _, To :: _}
| term().
--opaque dbg_opt() :: list().
+-opaque dbg_opt() :: {'trace', 'true'}
+ | {'log',
+ {N :: non_neg_integer(),
+ [{Event :: system_event(),
+ FuncState :: _,
+ FormFunc :: dbg_fun()}]}}
+ | {'statistics', {file:date_time(),
+ {'reductions', non_neg_integer()},
+ MessagesIn :: non_neg_integer(),
+ MessagesOut :: non_neg_integer()}}
+ | {'log_to_file', file:io_device()}
+ | {Func :: dbg_fun(), FuncState :: term()}.
-type dbg_fun() :: fun((FuncState :: _,
Event :: system_event(),
ProcState :: _) -> 'done' | (NewFuncState :: _)).
@@ -45,24 +58,22 @@
%%-----------------------------------------------------------------
%% System messages
%%-----------------------------------------------------------------
--spec suspend(Name) -> Void when
- Name :: name(),
- Void :: term().
+-spec suspend(Name) -> 'ok' when
+ Name :: name().
suspend(Name) -> send_system_msg(Name, suspend).
--spec suspend(Name, Timeout) -> Void when
+
+-spec suspend(Name, Timeout) -> 'ok' when
Name :: name(),
- Timeout :: timeout(),
- Void :: term().
+ Timeout :: timeout().
suspend(Name, Timeout) -> send_system_msg(Name, suspend, Timeout).
--spec resume(Name) -> Void when
- Name :: name(),
- Void :: term().
+-spec resume(Name) -> 'ok' when
+ Name :: name().
resume(Name) -> send_system_msg(Name, resume).
--spec resume(Name, Timeout) -> Void when
+
+-spec resume(Name, Timeout) -> 'ok' when
Name :: name(),
- Timeout :: timeout(),
- Void :: term().
+ Timeout :: timeout().
resume(Name, Timeout) -> send_system_msg(Name, resume, Timeout).
-spec get_status(Name) -> Status when
@@ -71,9 +82,10 @@ resume(Name, Timeout) -> send_system_msg(Name, resume, Timeout).
SItem :: (PDict :: [{Key :: term(), Value :: term()}])
| (SysState :: 'running' | 'suspended')
| (Parent :: pid())
- | (Dbg :: dbg_opt())
+ | (Dbg :: [dbg_opt()])
| (Misc :: term()).
get_status(Name) -> send_system_msg(Name, get_status).
+
-spec get_status(Name, Timeout) -> Status when
Name :: name(),
Timeout :: timeout(),
@@ -81,7 +93,7 @@ get_status(Name) -> send_system_msg(Name, get_status).
SItem :: (PDict :: [{Key :: term(), Value :: term()}])
| (SysState :: 'running' | 'suspended')
| (Parent :: pid())
- | (Dbg :: dbg_opt())
+ | (Dbg :: [dbg_opt()])
| (Misc :: term()).
get_status(Name, Timeout) -> send_system_msg(Name, get_status, Timeout).
@@ -93,6 +105,7 @@ get_status(Name, Timeout) -> send_system_msg(Name, get_status, Timeout).
Reason :: term().
change_code(Name, Mod, Vsn, Extra) ->
send_system_msg(Name, {change_code, Mod, Vsn, Extra}).
+
-spec change_code(Name, Module, OldVsn, Extra, Timeout) ->
'ok' | {error, Reason} when
Name :: name(),
@@ -189,35 +202,33 @@ no_debug(Name) -> send_system_msg(Name, {debug, no_debug}).
Timeout :: timeout().
no_debug(Name, Timeout) -> send_system_msg(Name, {debug, no_debug}, Timeout).
--spec install(Name, FuncSpec) -> Void when
+-spec install(Name, FuncSpec) -> 'ok' when
Name :: name(),
FuncSpec :: {Func, FuncState},
Func :: dbg_fun(),
- FuncState :: term(),
- Void :: term().
+ FuncState :: term().
install(Name, {Func, FuncState}) ->
send_system_msg(Name, {debug, {install, {Func, FuncState}}}).
--spec install(Name, FuncSpec, Timeout) -> Void when
+
+-spec install(Name, FuncSpec, Timeout) -> 'ok' when
Name :: name(),
FuncSpec :: {Func, FuncState},
Func :: dbg_fun(),
FuncState :: term(),
- Timeout :: timeout(),
- Void :: term().
+ Timeout :: timeout().
install(Name, {Func, FuncState}, Timeout) ->
send_system_msg(Name, {debug, {install, {Func, FuncState}}}, Timeout).
--spec remove(Name, Func) -> Void when
+-spec remove(Name, Func) -> 'ok' when
Name :: name(),
- Func :: dbg_fun(),
- Void :: term().
+ Func :: dbg_fun().
remove(Name, Func) ->
send_system_msg(Name, {debug, {remove, Func}}).
--spec remove(Name, Func, Timeout) -> Void when
+
+-spec remove(Name, Func, Timeout) -> 'ok' when
Name :: name(),
Func :: dbg_fun(),
- Timeout :: timeout(),
- Void :: term().
+ Timeout :: timeout().
remove(Name, Func, Timeout) ->
send_system_msg(Name, {debug, {remove, Func}}, Timeout).
@@ -243,18 +254,13 @@ mfa(Name, {change_code, Mod, Vsn, Extra}) ->
{sys, change_code, [Name, Mod, Vsn, Extra]};
mfa(Name, Atom) ->
{sys, Atom, [Name]}.
+
mfa(Name, Req, Timeout) ->
{M, F, A} = mfa(Name, Req),
{M, F, A ++ [Timeout]}.
%%-----------------------------------------------------------------
%% Func: handle_system_msg/6
-%% Args: Msg ::= term()
-%% From ::= {pid(),Ref} but don't count on that
-%% Parent ::= pid()
-%% Module ::= atom()
-%% Debug ::= [debug_opts()]
-%% Misc ::= term()
%% Purpose: Used by a process module that wishes to take care of
%% system messages. The process receives a {system, From,
%% Msg} message, and passes the Msg to this function.
@@ -266,14 +272,14 @@ mfa(Name, Req, Timeout) ->
%% The Module must export system_continue/3, system_terminate/4
%% and format_status/2 for status information.
%%-----------------------------------------------------------------
--spec handle_system_msg(Msg, From, Parent, Module, Debug, Misc) -> Void when
+-spec handle_system_msg(Msg, From, Parent, Module, Debug, Misc) ->
+ no_return() when
Msg :: term(),
From :: {pid(), Tag :: _},
Parent :: pid(),
Module :: module(),
Debug :: [dbg_opt()],
- Misc :: term(),
- Void :: term().
+ Misc :: term().
handle_system_msg(Msg, From, Parent, Module, Debug, Misc) ->
handle_system_msg(running, Msg, From, Parent, Module, Debug, Misc, false).
@@ -292,10 +298,6 @@ handle_system_msg(SysState, Msg, From, Parent, Mod, Debug, Misc, Hib) ->
%%-----------------------------------------------------------------
%% Func: handle_debug/4
-%% Args: Debug ::= [debug_opts()]
-%% Func ::= {M,F} | fun() arity 3
-%% State ::= term()
-%% Event ::= {in, Msg} | {in, Msg, From} | {out, Msg, To} | term()
%% Purpose: Called by a process that wishes to debug an event.
%% Func is a formatting function, called as Func(Device, Event).
%% Returns: [debug_opts()]
@@ -451,6 +453,7 @@ print_event(Dev, {Event, State, FormFunc}) ->
FormFunc(Dev, Event, State).
init_stat() -> {erlang:localtime(), process_info(self(), reductions), 0, 0}.
+
get_stat({Time, {reductions, Reds}, In, Out}) ->
{reductions, Reds2} = process_info(self(), reductions),
[{start_time, Time}, {current_time, erlang:localtime()},
@@ -490,9 +493,8 @@ get_debug2(Item, Debug, Default) ->
_ -> Default
end.
--spec print_log(Debug) -> Void when
- Debug :: [dbg_opt()],
- Void :: term().
+-spec print_log(Debug) -> 'ok' when
+ Debug :: [dbg_opt()].
print_log(Debug) ->
{_N, Logs} = get_debug(log, Debug, {0, []}),
lists:foreach(fun print_event/1,
@@ -509,8 +511,6 @@ close_log_file(Debug) ->
%%-----------------------------------------------------------------
%% Func: debug_options/1
-%% Args: [trace|log|{log,N}|statistics|{log_to_file, FileName}|
-%% {install, {Func, FuncState}}]
%% Purpose: Initiate a debug structure. Called by a process that
%% wishes to initiate the debug structure without the
%% system messages.
@@ -519,7 +519,11 @@ close_log_file(Debug) ->
-spec debug_options(Options) -> [dbg_opt()] when
Options :: [Opt],
- Opt :: 'trace' | 'log' | 'statistics' | {'log_to_file', FileName}
+ Opt :: 'trace'
+ | 'log'
+ | {'log', pos_integer()}
+ | 'statistics'
+ | {'log_to_file', FileName}
| {'install', FuncSpec},
FileName :: file:name(),
FuncSpec :: {Func, FuncState},
@@ -527,6 +531,7 @@ close_log_file(Debug) ->
FuncState :: term().
debug_options(Options) ->
debug_options(Options, []).
+
debug_options([trace | T], Debug) ->
debug_options(T, install_debug(trace, true, Debug));
debug_options([log | T], Debug) ->
diff --git a/lib/stdlib/src/win32reg.erl b/lib/stdlib/src/win32reg.erl
index 598e77ffdc..48a7e262be 100644
--- a/lib/stdlib/src/win32reg.erl
+++ b/lib/stdlib/src/win32reg.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -25,6 +25,8 @@
expand/1,
format_error/1]).
+-export_type([reg_handle/0]).
+
%% Key handles (always open).
-define(hkey_classes_root, 16#80000000).
-define(hkey_current_user, 16#80000001).
diff --git a/lib/stdlib/test/Makefile b/lib/stdlib/test/Makefile
index 29b8e28d3a..6aa09d7bd0 100644
--- a/lib/stdlib/test/Makefile
+++ b/lib/stdlib/test/Makefile
@@ -23,7 +23,6 @@ MODULES= \
dummy_via \
edlin_expand_SUITE \
epp_SUITE \
- erl_eval_helper \
erl_eval_SUITE \
erl_expand_records_SUITE \
erl_internal_SUITE \
diff --git a/lib/stdlib/test/base64_SUITE.erl b/lib/stdlib/test/base64_SUITE.erl
index c64a961ffa..b28df94221 100644
--- a/lib/stdlib/test/base64_SUITE.erl
+++ b/lib/stdlib/test/base64_SUITE.erl
@@ -1,7 +1,8 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -20,7 +21,6 @@
-module(base64_SUITE).
-include_lib("common_test/include/ct.hrl").
--include("test_server_line.hrl").
%% Test server specific exports
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
@@ -33,7 +33,7 @@
mime_decode_to_string/1, roundtrip/1]).
init_per_testcase(_, Config) ->
- Dog = test_server:timetrap(?t:minutes(2)),
+ Dog = test_server:timetrap(?t:minutes(4)),
NewConfig = lists:keydelete(watchdog, 1, Config),
[{watchdog, Dog} | NewConfig].
@@ -180,7 +180,7 @@ mime_decode(Config) when is_list(Config) ->
<<"o">> = base64:mime_decode(<<"b=w=====">>),
%% Test misc white space and illegals with embedded padding
<<"one">> = base64:mime_decode(<<" b~2=\r\n5()l===">>),
- <<"on">> = base64:mime_decode(<<"\tb =2\"�4=�= ==">>),
+ <<"on">> = base64:mime_decode(<<"\tb =2\"¤4=¤= ==">>),
<<"o">> = base64:mime_decode(<<"\nb=w=====">>),
%% Two pads
<<"Aladdin:open sesame">> =
@@ -189,7 +189,7 @@ mime_decode(Config) when is_list(Config) ->
<<"Hello World!!">> = base64:mime_decode(<<"SGVsb)(G8gV29ybGQ=h IQ= =">>),
%% No pad
<<"Aladdin:open sesam">> =
- base64:mime_decode("QWxhZGRpbjpvcG�\")(VuIHNlc2Ft"),
+ base64:mime_decode("QWxhZGRpbjpvcG¤\")(VuIHNlc2Ft"),
%% Encoded base 64 strings may be divided by non base 64 chars.
%% In this cases whitespaces.
<<"0123456789!@#0^&*();:<>,. []{}">> =
@@ -223,7 +223,7 @@ mime_decode_to_string(Config) when is_list(Config) ->
"o" = base64:mime_decode_to_string(<<"b=w=====">>),
%% Test misc white space and illegals with embedded padding
"one" = base64:mime_decode_to_string(<<" b~2=\r\n5()l===">>),
- "on" = base64:mime_decode_to_string(<<"\tb =2\"�4=�= ==">>),
+ "on" = base64:mime_decode_to_string(<<"\tb =2\"¤4=¤= ==">>),
"o" = base64:mime_decode_to_string(<<"\nb=w=====">>),
%% Two pads
"Aladdin:open sesame" =
@@ -232,7 +232,7 @@ mime_decode_to_string(Config) when is_list(Config) ->
"Hello World!!" = base64:mime_decode_to_string(<<"SGVsb)(G8gV29ybGQ=h IQ= =">>),
%% No pad
"Aladdin:open sesam" =
- base64:mime_decode_to_string("QWxhZGRpbjpvcG�\")(VuIHNlc2Ft"),
+ base64:mime_decode_to_string("QWxhZGRpbjpvcG¤\")(VuIHNlc2Ft"),
%% Encoded base 64 strings may be divided by non base 64 chars.
%% In this cases whitespaces.
"0123456789!@#0^&*();:<>,. []{}" =
diff --git a/lib/stdlib/test/binary_module_SUITE.erl b/lib/stdlib/test/binary_module_SUITE.erl
index bac59a3107..9b6f628aa9 100644
--- a/lib/stdlib/test/binary_module_SUITE.erl
+++ b/lib/stdlib/test/binary_module_SUITE.erl
@@ -1,7 +1,8 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -1331,9 +1332,9 @@ one_random_number(N) ->
one_random(N) ->
M = ((N - 1) rem 68) + 1,
element(M,{$a,$b,$c,$d,$e,$f,$g,$h,$i,$j,$k,$l,$m,$n,$o,$p,$q,$r,$s,$t,
- $u,$v,$w,$x,$y,$z,$�,$�,$�,$A,$B,$C,$D,$E,$F,$G,$H,
- $I,$J,$K,$L,$M,$N,$O,$P,$Q,$R,$S,$T,$U,$V,$W,$X,$Y,$Z,$�,
- $�,$�,$0,$1,$2,$3,$4,$5,$6,$7,$8,$9}).
+ $u,$v,$w,$x,$y,$z,$å,$ä,$ö,$A,$B,$C,$D,$E,$F,$G,$H,
+ $I,$J,$K,$L,$M,$N,$O,$P,$Q,$R,$S,$T,$U,$V,$W,$X,$Y,$Z,$Å,
+ $Ä,$Ö,$0,$1,$2,$3,$4,$5,$6,$7,$8,$9}).
random_number({Min,Max}) -> % Min and Max are *length* of number in
% decimal positions
diff --git a/lib/stdlib/test/dict_SUITE.erl b/lib/stdlib/test/dict_SUITE.erl
index c46fc47b34..df9c769c67 100644
--- a/lib/stdlib/test/dict_SUITE.erl
+++ b/lib/stdlib/test/dict_SUITE.erl
@@ -53,7 +53,7 @@ end_per_group(_GroupName, Config) ->
init_per_testcase(_Case, Config) ->
- ?line Dog = ?t:timetrap(?t:minutes(5)),
+ Dog = ?t:timetrap(?t:minutes(5)),
[{watchdog,Dog}|Config].
end_per_testcase(_Case, Config) ->
@@ -65,22 +65,22 @@ create(Config) when is_list(Config) ->
test_all(fun create_1/1).
create_1(M) ->
- ?line D0 = M:empty(),
- ?line [] = M:to_list(D0),
- ?line 0 = M:size(D0),
+ D0 = M(empty, []),
+ [] = M(to_list, D0),
+ 0 = M(size, D0),
D0.
store(Config) when is_list(Config) ->
test_all([{0,132},{253,258},{510,514}], fun store_1/2).
store_1(List, M) ->
- ?line D0 = M:from_list(List),
+ D0 = M(from_list, List),
%% Make sure that we get the same result by inserting
%% elements one at the time.
- ?line D1 = foldl(fun({K,V}, Dict) -> M:enter(K, V, Dict) end,
- M:empty(), List),
- ?line true = M:equal(D0, D1),
+ D1 = foldl(fun({K,V}, Dict) -> M(enter, {K,V,Dict}) end,
+ M(empty, []), List),
+ true = M(equal, {D0,D1}),
D0.
%%%
@@ -98,7 +98,7 @@ dict_mods() ->
[Orddict,Dict,Gb].
test_all(Tester) ->
- ?line Pids = [spawn_tester(M, Tester) || M <- dict_mods()],
+ Pids = [spawn_tester(M, Tester) || M <- dict_mods()],
collect_all(Pids, []).
spawn_tester(M, Tester) ->
@@ -106,7 +106,7 @@ spawn_tester(M, Tester) ->
spawn_link(fun() ->
random:seed(1, 2, 42),
S = Tester(M),
- Res = {M:size(S),lists:sort(M:to_list(S))},
+ Res = {M(size, S),lists:sort(M(to_list, S))},
Parent ! {result,self(),Res}
end).
diff --git a/lib/stdlib/test/dict_test_lib.erl b/lib/stdlib/test/dict_test_lib.erl
index 92a75dad89..7167014310 100644
--- a/lib/stdlib/test/dict_test_lib.erl
+++ b/lib/stdlib/test/dict_test_lib.erl
@@ -17,67 +17,48 @@
%% %CopyrightEnd%
%%
--module(dict_test_lib, [Mod,Equal]).
+-module(dict_test_lib).
--export([module/0,equal/2,empty/0,size/1,to_list/1,from_list/1,
- enter/3,delete/2,lookup/2]).
+-export([new/2]).
-module() ->
- Mod.
-
-equal(X, Y) ->
- Equal(X, Y).
+new(Mod, Eq) ->
+ fun (enter, {K,V,D}) -> enter(Mod, K, V, D);
+ (empty, []) -> empty(Mod);
+ (equal, {D1,D2}) -> Eq(D1, D2);
+ (from_list, L) -> from_list(Mod, L);
+ (module, []) -> Mod;
+ (size, D) -> Mod:size(D);
+ (to_list, D) -> to_list(Mod, D)
+ end.
-empty() ->
+empty(Mod) ->
case erlang:function_exported(Mod, new, 0) of
false -> Mod:empty();
true -> Mod:new()
end.
-size(S) ->
- Mod:size(S).
-
-to_list(S) ->
- Mod:to_list(S).
+to_list(Mod, D) ->
+ Mod:to_list(D).
-from_list(S) ->
+from_list(Mod, L) ->
case erlang:function_exported(Mod, from_orddict, 1) of
false ->
- Mod:from_list(S);
+ Mod:from_list(L);
true ->
%% The gb_trees module has no from_list/1 function.
%%
%% The keys in S are not unique. To make sure
%% that we pick the same key/value pairs as
%% dict/orddict, first convert the list to an orddict.
- Orddict = orddict:from_list(S),
+ Orddict = orddict:from_list(L),
Mod:from_orddict(Orddict)
end.
%% Store new value into dictionary or update previous value in dictionary.
-enter(Key, Val, Dict) ->
+enter(Mod, Key, Val, Dict) ->
case erlang:function_exported(Mod, store, 3) of
false ->
Mod:enter(Key, Val, Dict);
true ->
Mod:store(Key, Val, Dict)
end.
-
-%% Delete an EXISTING key.
-delete(Key, Dict) ->
- case erlang:function_exported(Mod, delete, 2) of
- true -> Mod:delete(Key, Dict);
- false -> Mod:erase(Key, Dict)
- end.
-
-%% -> none | {value,Value}
-lookup(Key, Dict) ->
- case erlang:function_exported(Mod, lookup, 2) of
- false ->
- case Mod:find(Key, Dict) of
- error -> none;
- {ok,Value} -> {value,Value}
- end;
- true ->
- Mod:lookup(Key, Dict)
- end.
diff --git a/lib/stdlib/test/digraph_SUITE.erl b/lib/stdlib/test/digraph_SUITE.erl
index 1d1326d60e..ed01b32a59 100644
--- a/lib/stdlib/test/digraph_SUITE.erl
+++ b/lib/stdlib/test/digraph_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -400,7 +400,7 @@ sane1(G) ->
lists:foreach(
fun(V) ->
InEs = digraph:in_edges(G, V),
- %% Nu har man *alla* inkanter f�r V
+ %% *All* in-edoges of V
lists:foreach(
fun(E) ->
case digraph:edge(G, E) of
diff --git a/lib/stdlib/test/epp_SUITE.erl b/lib/stdlib/test/epp_SUITE.erl
index f79414db49..606bbbcbb2 100644
--- a/lib/stdlib/test/epp_SUITE.erl
+++ b/lib/stdlib/test/epp_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -25,7 +25,7 @@
variable_1/1, otp_4870/1, otp_4871/1, otp_5362/1,
pmod/1, not_circular/1, skip_header/1, otp_6277/1, otp_7702/1,
otp_8130/1, overload_mac/1, otp_8388/1, otp_8470/1, otp_8503/1,
- otp_8562/1, otp_8665/1, otp_8911/1]).
+ otp_8562/1, otp_8665/1, otp_8911/1, otp_10302/1]).
-export([epp_parse_erl_form/2]).
@@ -67,7 +67,7 @@ all() ->
{group, variable}, otp_4870, otp_4871, otp_5362, pmod,
not_circular, skip_header, otp_6277, otp_7702, otp_8130,
overload_mac, otp_8388, otp_8470, otp_8503, otp_8562,
- otp_8665, otp_8911].
+ otp_8665, otp_8911, otp_10302].
groups() ->
[{upcase_mac, [], [upcase_mac_1, upcase_mac_2]},
@@ -582,12 +582,13 @@ otp_8130(suite) ->
otp_8130(Config) when is_list(Config) ->
true = os:putenv("epp_inc1", "stdlib"),
Ts = [{otp_8130_1,
- %% The scanner handles UNICODE in a special way. Hopefully
- %% temporarily.
<<"-define(M(A), ??A). "
"t() -> "
- " \"{ 34 , [ $1 , 2730 ] , \\\"34\\\" , X . a , 2730 }\" = "
- " ?M({34,\"1\\x{aaa}\",\"34\",X.a,$\\x{aaa}}), ok. ">>,
+ " L = \"{ 34 , \\\"1\\\\x{AAA}\\\" , \\\"34\\\" , X . a , $\\\\x{AAA} }\", "
+ " R = ?M({34,\"1\\x{aaa}\",\"34\",X.a,$\\x{aaa}}),"
+ " Lt = erl_scan:string(L, 1, [unicode]),"
+ " Rt = erl_scan:string(R, 1, [unicode]),"
+ " Lt = Rt, ok. ">>,
ok},
{otp_8130_2,
@@ -1236,6 +1237,13 @@ otp_8911(doc) ->
otp_8911(suite) ->
[];
otp_8911(Config) when is_list(Config) ->
+ case test_server:is_cover() of
+ true ->
+ {skip, "Testing cover, so can not run when cover is already running"};
+ false ->
+ do_otp_8911(Config)
+ end.
+do_otp_8911(Config) ->
?line {ok, CWD} = file:get_cwd(),
?line ok = file:set_cwd(?config(priv_dir, Config)),
@@ -1277,6 +1285,75 @@ otp_8665(Config) when is_list(Config) ->
?line [] = compile(Config, Cs),
ok.
+otp_10302(doc) ->
+ "OTP-10302. Unicode characters scanner/parser.";
+otp_10302(suite) ->
+ [];
+otp_10302(Config) when is_list(Config) ->
+ %% Two messages (one too many). Keeps otp_4871 happy.
+ Cs = [{otp_8562,
+ <<"%% coding: utf-8\n \n \x{E4}">>,
+ {errors,[{3,epp,cannot_parse},
+ {3,file_io_server,invalid_unicode}],[]}}
+ ],
+ [] = compile(Config, Cs),
+ Dir = ?config(priv_dir, Config),
+ File = filename:join(Dir, "otp_10302.erl"),
+ utf8 = encoding("coding: utf-8", File),
+ utf8 = encoding("coding: UTF-8", File),
+ latin1 = encoding("coding: Latin-1", File),
+ latin1 = encoding("coding: latin-1", File),
+ none = encoding_com("coding: utf-8", File),
+ none = encoding_com("\n\n%% coding: utf-8", File),
+ none = encoding_nocom("\n\n coding: utf-8", File),
+ utf8 = encoding_com("\n%% coding: utf-8", File),
+ utf8 = encoding_nocom("\n coding: utf-8", File),
+ none = encoding("coding: \nutf-8", File),
+ latin1 = encoding("Encoding : latin-1", File),
+ utf8 = encoding("ccoding: UTF-8", File),
+ utf8 = encoding("coding= utf-8", File),
+ utf8 = encoding_com(" %% coding= utf-8", File),
+ utf8 = encoding("coding = utf-8", File),
+ none = encoding("coding: utf-16 coding: utf-8", File), %first is bad
+ none = encoding("Coding: utf-8", File), %capital c
+ utf8 = encoding("-*- coding: utf-8 -*-", File),
+ utf8 = encoding("-*-coding= utf-8-*-", File),
+ utf8 = encoding("codingcoding= utf-8", File),
+ ok = prefix("coding: utf-8", File, utf8),
+
+ "coding: latin-1" = epp:encoding_to_string(latin1),
+ "coding: utf-8" = epp:encoding_to_string(utf8),
+ true = lists:member(epp:default_encoding(), [latin1, utf8]),
+
+ ok.
+
+prefix(S, File, Enc) ->
+ prefix(0, S, File, Enc).
+
+prefix(100, _S, _File, _) ->
+ ok;
+prefix(N, S, File, Enc) ->
+ Enc = encoding(lists:duplicate(N, $\s) ++ S, File),
+ prefix(N+1, S, File, Enc).
+
+encoding(Enc, File) ->
+ E = encoding_com("%% " ++ Enc, File),
+ none = encoding_com(Enc, File),
+ E = encoding_nocom(Enc, File).
+
+encoding_com(Enc, File) ->
+ ok = file:write_file(File, Enc),
+ {ok, Fd} = file:open(File, [read]),
+ E = epp:set_encoding(Fd),
+ ok = file:close(Fd),
+ E = epp:read_encoding(File).
+
+encoding_nocom(Enc, File) ->
+ ok = file:write_file(File, Enc),
+ {ok, Fd} = file:open(File, [read]),
+ ok = file:close(Fd),
+ epp:read_encoding(File, [{in_comment_only, false}]).
+
check(Config, Tests) ->
eval_tests(Config, fun check_test/2, Tests).
diff --git a/lib/stdlib/test/erl_eval_SUITE.erl b/lib/stdlib/test/erl_eval_SUITE.erl
index 47792d1052..04d49770cb 100644
--- a/lib/stdlib/test/erl_eval_SUITE.erl
+++ b/lib/stdlib/test/erl_eval_SUITE.erl
@@ -1160,24 +1160,6 @@ do_funs(LFH, EFH) ->
concat(["begin F = fun(F, N) -> [", M,
":count_down(F,N) || X <-[1]] end, F(F,2) end."]),
[[[0]]], ['F'], LFH, EFH),
-
- %% Tests for a bug found by the Dialyzer - used to crash.
- case test_server:is_native(erl_eval) of
- true ->
- %% Parameterized modules are not supported by HiPE.
- ok;
- false ->
- check(fun() -> Pmod = erl_eval_helper:new(42), Pmod:add(5) end,
- "begin Pmod = erl_eval_helper:new(42), Pmod:add(5) end.",
- 47,
- ['Pmod'], LFH, EFH),
- check(fun() -> Pmod = erl_eval_helper:new(42),
- B = Pmod:add(7), B end,
- "begin Pmod = erl_eval_helper:new(42), "
- "B = Pmod:add(7), B end.",
- 49,
- ['B','Pmod'], LFH, EFH)
- end,
ok.
count_down(F, N) when N > 0 ->
diff --git a/lib/stdlib/test/erl_expand_records_SUITE.erl b/lib/stdlib/test/erl_expand_records_SUITE.erl
index e248934e10..94b4397a9c 100644
--- a/lib/stdlib/test/erl_expand_records_SUITE.erl
+++ b/lib/stdlib/test/erl_expand_records_SUITE.erl
@@ -35,7 +35,7 @@
init_per_group/2,end_per_group/2,
init_per_testcase/2, end_per_testcase/2]).
--export([abstract_module/1, attributes/1, expr/1, guard/1,
+-export([attributes/1, expr/1, guard/1,
init/1, pattern/1, strict/1, update/1,
otp_5915/1, otp_7931/1, otp_5990/1,
otp_7078/1, otp_7101/1]).
@@ -55,7 +55,7 @@ end_per_testcase(_Case, _Config) ->
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [abstract_module, attributes, expr, guard, init,
+ [attributes, expr, guard, init,
pattern, strict, update, {group, tickets}].
groups() ->
@@ -75,40 +75,12 @@ end_per_group(_GroupName, Config) ->
Config.
-abstract_module(doc) ->
- "Compile an abstract module.";
-abstract_module(suite) -> [];
-abstract_module(Config) when is_list(Config) ->
- %% erl_expand_records does not handle abstract modules. But anyway...
- File = filename("param.erl", Config),
- Beam = filename("param.beam", Config),
- Test = <<"-module(param, [A, B]).
-
- -export([args/1]).
-
- args(C) ->
- X = local(C),
- Z = new(A, B),
- {X, Z}.
-
- local(C) ->
- module_info(C).
- ">>,
-
- ?line ok = file:write_file(File, Test),
- ?line {ok, param} = compile:file(File, [{outdir,?privdir}]),
-
- ?line ok = file:delete(File),
- ?line ok = file:delete(Beam),
- ok.
-
attributes(doc) ->
"Import module and functions.";
attributes(suite) -> [];
attributes(Config) when is_list(Config) ->
Ts = [
- <<"-import(erl_expand_records_SUITE).
- -import(lists, [append/2, reverse/1]).
+ <<"-import(lists, [append/2, reverse/1]).
-record(r, {a,b}).
@@ -158,12 +130,12 @@ expr(Config) when is_list(Config) ->
2 = fun(X) -> X end(One + One),
3 = fun exprec_test:f/1(3),
4 = exprec_test:f(4),
- 5 = ''.f(5),
+ 5 = f(5),
L = receive
{a,message,L0} ->
L0
end,
- case catch a.b.c:foo(bar) of
+ case catch a:foo(bar) of
{'EXIT', _} -> ok
end,
_ = receive %Suppress warning.
@@ -197,7 +169,7 @@ guard(suite) -> [];
guard(Config) when is_list(Config) ->
File = filename("guard.erl", Config),
Beam = filename("guard.beam", Config),
- Test = <<"-module(guard, [A, B]).
+ Test = <<"-module(guard).
-export([t/1]).
@@ -263,8 +235,7 @@ pattern(doc) ->
pattern(suite) -> [];
pattern(Config) when is_list(Config) ->
Ts = [
- <<"-import(erl_expand_records_SUITE).
- -import(lists, [append/2, reverse/1]).
+ <<"-import(lists, [append/2, reverse/1]).
-record(r, {a,b}).
@@ -292,10 +263,10 @@ pattern(Config) when is_list(Config) ->
21 = t(#r{a = #r{}}),
22 = t(2),
23 = t(#r{a = #r{}, b = b}),
- 24 = t(a.b.c),
+ 24 = t(abc),
ok.
- t(a.b.c) ->
+ t(abc) ->
24;
t($a) ->
2;
diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl
index 90a37f6441..564f27a512 100644
--- a/lib/stdlib/test/erl_lint_SUITE.erl
+++ b/lib/stdlib/test/erl_lint_SUITE.erl
@@ -1732,7 +1732,7 @@ otp_5362(Config) when is_list(Config) ->
{otp_5362_2,
<<"-export([inline/0]).
- -import(lists.foo, [a/1,b/1]). % b/1 is not used
+ -import(lists, [a/1,b/1]). % b/1 is not used
-compile([{inline,{inl,7}}]). % undefined
-compile([{inline,[{inl,17}]}]). % undefined
@@ -1764,7 +1764,7 @@ otp_5362(Config) when is_list(Config) ->
{6,erl_lint,{bad_inline,{inl,17}}},
{11,erl_lint,{undefined_function,{fipp,0}}},
{22,erl_lint,{bad_nowarn_unused_function,{and_not_used,2}}}],
- [{3,erl_lint,{unused_import,{{b,1},'lists.foo'}}},
+ [{3,erl_lint,{unused_import,{{b,1},lists}}},
{9,erl_lint,{unused_function,{foop,0}}},
{19,erl_lint,{unused_function,{not_used,0}}},
{23,erl_lint,{unused_function,{and_not_used,1}}}]}},
@@ -2187,27 +2187,9 @@ otp_5878(Config) when is_list(Config) ->
?line [] = run(Config, Ts),
Abstr = <<"-module(lint_test, [A, B]).
-
- -export([args/1]).
-
- -record(r, {a = A, b = THIS}). % A and THIS are unbound
-
- %% param:args(compile,param:new(1,2)).
-
- args(C) ->
- X = local(C),
- Z = new(A, B),
- F = fun(THIS) -> {x, A} end, % THIS unused and shadowed
- {X, Z, THIS, F, #r{}}.
-
- local(C) ->
- module_info(C).
">>,
- ?line {error,[{5,erl_lint,{unbound_var,'A'}},
- {5,erl_lint,{unbound_var,'THIS'}}],
- [{12,erl_lint,{unused_var,'THIS'}},
- {12,erl_lint,{shadowed_var,'THIS','fun'}}]}
- = run_test2(Config, Abstr, [warn_unused_record]),
+ {errors,[{1,erl_lint,pmod_unsupported}],[]} =
+ run_test2(Config, Abstr, [warn_unused_record]),
QLC1 = <<"-module(lint_test).
-include_lib(\"stdlib/include/qlc.hrl\").
diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl
index 64853ca078..db416b03b0 100644
--- a/lib/stdlib/test/erl_pp_SUITE.erl
+++ b/lib/stdlib/test/erl_pp_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -40,7 +40,7 @@
init_per_testcase/2, end_per_testcase/2]).
-export([ func/1, call/1, recs/1, try_catch/1, if_then/1,
- receive_after/1, bits/1, head_tail/1, package/1,
+ receive_after/1, bits/1, head_tail/1,
cond1/1, block/1, case1/1, ops/1, messages/1,
old_mnemosyne_syntax/1,
import_export/1, misc_attrs/1,
@@ -48,7 +48,8 @@
neg_indent/1,
otp_6321/1, otp_6911/1, otp_6914/1, otp_8150/1, otp_8238/1,
- otp_8473/1, otp_8522/1, otp_8567/1, otp_8664/1, otp_9147/1]).
+ otp_8473/1, otp_8522/1, otp_8567/1, otp_8664/1, otp_9147/1,
+ otp_10302/1]).
%% Internal export.
-export([ehook/6]).
@@ -74,12 +75,12 @@ all() ->
groups() ->
[{expr, [],
[func, call, recs, try_catch, if_then, receive_after,
- bits, head_tail, package, cond1, block, case1, ops,
+ bits, head_tail, cond1, block, case1, ops,
messages, old_mnemosyne_syntax]},
{attributes, [], [misc_attrs, import_export]},
{tickets, [],
[otp_6321, otp_6911, otp_6914, otp_8150, otp_8238,
- otp_8473, otp_8522, otp_8567, otp_8664, otp_9147]}].
+ otp_8473, otp_8522, otp_8567, otp_8664, otp_9147, otp_10302]}].
init_per_suite(Config) ->
Config.
@@ -438,9 +439,6 @@ bits(Config) when is_list(Config) ->
?line ok = pp_expr(<<"<<{a,b}/binary>>">>),
?line ok = pp_expr(<<"<<{foo:bar(),b}/binary>>">>),
?line ok = pp_expr(<<"<<(foo:bar()):(foo:bar())/binary>>">>),
- ?line ok = pp_expr(<<"<<(foo.bar)/binary>>">>),
- ?line ok = pp_expr(<<"<<(foo.bar):all/binary>>">>),
- ?line ok = pp_expr(<<"<<(foo.bar):(foo.bar)/binary>>">>),
ok.
head_tail(suite) ->
@@ -462,17 +460,6 @@ head_tail(Config) when is_list(Config) ->
?line compile(Config, Ts),
ok.
-package(suite) ->
- [];
-package(Config) when is_list(Config) ->
- Ts = [{package_1,
- <<"t() -> a.b:foo().">>},
- {package_2,
- <<"t() -> .lists:sort([]).">>}
- ],
- ?line compile(Config, Ts),
- ok.
-
cond1(suite) ->
[];
cond1(Config) when is_list(Config) ->
@@ -614,13 +601,11 @@ misc_attrs(suite) ->
[];
misc_attrs(Config) when is_list(Config) ->
?line ok = pp_forms(<<"-module(m). ">>),
- ?line ok = pp_forms(<<"-module(m.p, [A,B]). ">>),
?line ok = pp_forms(<<"-module(m, [Aafjlksfjdlsjflsdfjlsdjflkdsfjlk,"
"Blsjfdlslfjsdf]). ">>),
?line ok = pp_forms(<<"-export([]). ">>),
?line ok = pp_forms(<<"-export([foo/2, bar/0]). ">>),
?line ok = pp_forms(<<"-export([bar/0]). ">>),
- ?line ok = pp_forms(<<"-import(.lists). ">>),
?line ok = pp_forms(<<"-import(lists, []). ">>),
?line ok = pp_forms(<<"-import(lists, [map/2]). ">>),
?line ok = pp_forms(<<"-import(lists, [map/2, foreach/2]). ">>),
@@ -634,8 +619,12 @@ misc_attrs(Config) when is_list(Config) ->
hook(suite) ->
[];
hook(Config) when is_list(Config) ->
+ F = fun(H) -> H end,
+ do_hook(F).
+
+do_hook(HookFun) ->
Lc = parse_expr(binary_to_list(<<"[X || X <- [1,2,3]].">>)),
- H = fun hook/4,
+ H = HookFun(fun hook/4),
Expr = {call,0,{atom,0,fff},[{foo,Lc},{foo,Lc},{foo,Lc}]},
EChars = lists:flatten(erl_pp:expr(Expr, 0, H)),
Call = {call,0,{atom,0,foo},[Lc]},
@@ -692,7 +681,7 @@ hook(Config) when is_list(Config) ->
GChars2 = erl_pp:guard(G2),
?line true = GChars =:= lists:flatten(GChars2),
- EH = {?MODULE, ehook, [foo,bar]},
+ EH = HookFun({?MODULE, ehook, [foo,bar]}),
XEChars = erl_pp:expr(Expr, -1, EH),
?line true = remove_indentation(EChars) =:= lists:flatten(XEChars),
XEChars2 = erl_pp:expr(Expr, EH),
@@ -1068,6 +1057,43 @@ otp_9147(Config) when is_list(Config) ->
string:tokens(binary_to_list(Bin), "\n")),
ok.
+otp_10302(doc) ->
+ "OTP-10302. Unicode characters scanner/parser.";
+otp_10302(suite) -> [];
+otp_10302(Config) when is_list(Config) ->
+ Ts = [{uni_1,
+ <<"t() -> <<(<<\"abc\\x{aaa}\">>):3/binary>>.">>}
+ ],
+ compile(Config, Ts),
+ ok = pp_expr(<<"$\\x{aaa}">>),
+ ok = pp_expr(<<"\"1\\x{aaa}\"">>),
+ ok = pp_expr(<<"<<<<\"hej\">>/binary>>">>),
+ ok = pp_expr(<<"<< <<\"1\\x{aaa}\">>/binary>>">>),
+
+ U = [{encoding,unicode}],
+
+ do_hook(fun(H) -> [{hook,H}] end),
+ do_hook(fun(H) -> [{hook,H}]++U end),
+
+ ok = pp_expr(<<"$\\x{aaa}">>, [{hook,fun hook/4}]),
+
+ Opts = [{hook, fun unicode_hook/4},{encoding,unicode}],
+ Lc = parse_expr("[X || X <- [\"\x{400}\",\"\xFF\"]]."),
+ Expr = {call,0,{atom,0,fff},[{foo,{foo,Lc}},{foo,{foo,Lc}}]},
+ EChars = lists:flatten(erl_pp:expr(Expr, 0, Opts)),
+ Call = {call,0,{atom,0,foo},[{call,0,{atom,0,foo},[Lc]}]},
+ Expr2 = {call,0,{atom,0,fff},[Call,Call]},
+ EChars2 = erl_pp:exprs([Expr2], U),
+ EChars = lists:flatten(EChars2),
+ [$\x{400},$\x{400}] = [C || C <- EChars, C > 255],
+
+ ok = pp_forms(<<"function() -> {\"\x{400}\",$\x{400}}. "/utf8>>, U),
+ ok = pp_forms("function() -> {\"\x{400}\",$\x{400}}. ", []),
+ ok.
+
+unicode_hook({foo,E}, I, P, H) ->
+ erl_pp:expr({call,0,{atom,0,foo},[E]}, I, P, H).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
compile(Config, Tests) ->
@@ -1137,9 +1163,11 @@ flat_expr(Expr) ->
pp_forms(Bin) ->
pp_forms(Bin, none).
-pp_forms(Bin, Hook) ->
- PP1 = (catch parse_and_pp_forms(binary_to_list(Bin), Hook)),
- PP2 = (catch parse_and_pp_forms(PP1, Hook)),
+pp_forms(Bin, Options) when is_binary(Bin) ->
+ pp_forms(to_list(Bin, Options), Options);
+pp_forms(List, Options) when is_list(List) ->
+ PP1 = (catch parse_and_pp_forms(List, Options)),
+ PP2 = (catch parse_and_pp_forms(PP1, Options)),
case PP1 =:= PP2 of % same line numbers
true ->
test_max_line(PP1);
@@ -1147,8 +1175,8 @@ pp_forms(Bin, Hook) ->
not_ok
end.
-parse_and_pp_forms(String, Hook) ->
- lists:append(lists:map(fun(AF) -> erl_pp:form(AF, Hook)
+parse_and_pp_forms(String, Options) ->
+ lists:append(lists:map(fun(AF) -> erl_pp:form(AF, Options)
end, parse_forms(String))).
parse_forms(Chars) ->
@@ -1158,7 +1186,7 @@ parse_forms(Chars) ->
parse_forms2([], _Cont, _Line, Forms) ->
lists:reverse(Forms);
parse_forms2(String, Cont0, Line, Forms) ->
- case erl_scan:tokens(Cont0, String, Line) of
+ case erl_scan:tokens(Cont0, String, Line, [unicode]) of
{done, {ok, Tokens, EndLine}, Chars} ->
{ok, Form} = erl_parse:parse_form(Tokens),
parse_forms2(Chars, [], EndLine, [Form | Forms]);
@@ -1174,10 +1202,12 @@ pp_expr(Bin) ->
pp_expr(Bin, none).
%% Final dot is added.
-pp_expr(Bin, Hook) ->
- PP1 = (catch parse_and_pp_expr(binary_to_list(Bin), 0, Hook)),
- PPneg = (catch parse_and_pp_expr(binary_to_list(Bin), -1, Hook)),
- PP2 = (catch parse_and_pp_expr(PPneg, 0, Hook)),
+pp_expr(Bin, Options) when is_binary(Bin) ->
+ pp_expr(to_list(Bin, Options), Options);
+pp_expr(List, Options) when is_list(List) ->
+ PP1 = (catch parse_and_pp_expr(List, 0, Options)),
+ PPneg = (catch parse_and_pp_expr(List, -1, Options)),
+ PP2 = (catch parse_and_pp_expr(PPneg, 0, Options)),
if
PP1 =:= PP2 -> % same line numbers
case
@@ -1192,15 +1222,24 @@ pp_expr(Bin, Hook) ->
not_ok
end.
-parse_and_pp_expr(String, Indent, Hook) ->
+parse_and_pp_expr(String, Indent, Options) ->
StringDot = lists:flatten(String) ++ ".",
- erl_pp:expr(parse_expr(StringDot), Indent, Hook).
+ erl_pp:expr(parse_expr(StringDot), Indent, Options).
parse_expr(Chars) ->
- {ok, Tokens, _} = erl_scan:string(Chars),
+ {ok, Tokens, _} = erl_scan:string(Chars, 1, [unicode]),
{ok, [Expr]} = erl_parse:parse_exprs(Tokens),
Expr.
+to_list(Bin, Options) when is_list(Options) ->
+ case proplists:get_value(encoding, Options) of
+ unicode -> unicode:characters_to_list(Bin);
+ encoding -> binary_to_list(Bin);
+ undefined -> binary_to_list(Bin)
+ end;
+to_list(Bin, _Hook) ->
+ binary_to_list(Bin).
+
test_new_line(String) ->
case string:chr(String, $\n) of
0 -> ok;
diff --git a/lib/stdlib/test/erl_scan_SUITE.erl b/lib/stdlib/test/erl_scan_SUITE.erl
index 4298b2c701..34e1b99abe 100644
--- a/lib/stdlib/test/erl_scan_SUITE.erl
+++ b/lib/stdlib/test/erl_scan_SUITE.erl
@@ -1,7 +1,8 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -20,7 +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]).
--export([ error_1/1, error_2/1, iso88591/1, otp_7810/1]).
+-export([ error_1/1, error_2/1, iso88591/1, otp_7810/1, otp_10302/1]).
-import(lists, [nth/2,flatten/1]).
-import(io_lib, [print/1]).
@@ -59,7 +60,7 @@ end_per_testcase(_Case, Config) ->
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [{group, error}, iso88591, otp_7810].
+ [{group, error}, iso88591, otp_7810, otp_10302].
groups() ->
[{error, [], [error_1, error_2]}].
@@ -131,10 +132,10 @@ iso88591(Config) when is_list(Config) ->
?line ok =
case catch begin
%% Some atom and variable names
- V1s = [$�,$�,$�,$�],
- V2s = [$N,$�,$r],
- A1s = [$h,$�,$r],
- A2s = [$�,$r,$e],
+ V1s = [$Á,$á,$é,$ë],
+ V2s = [$N,$ä,$r],
+ A1s = [$h,$ä,$r],
+ A2s = [$ö,$r,$e],
%% Test parsing atom and variable characters.
{ok,Ts1,_} = erl_scan:string(V1s ++ " " ++ V2s ++
"\327" ++
@@ -214,8 +215,8 @@ atoms() ->
?line test_string("'a b'", [{atom,1,'a b'}]),
?line test_string("a", [{atom,1,a}]),
?line test_string("a@2", [{atom,1,a@2}]),
- ?line test_string([39,65,200,39], [{atom,1,'A�'}]),
- ?line test_string("�rlig �sten", [{atom,1,�rlig},{atom,1,�sten}]),
+ ?line test_string([39,65,200,39], [{atom,1,'AÈ'}]),
+ ?line test_string("ärlig östen", [{atom,1,ärlig},{atom,1,östen}]),
?line {ok,[{atom,_,'$a'}],{1,6}} =
erl_scan:string("'$\\a'", {1,1}),
?line test("'$\\a'"),
@@ -289,7 +290,7 @@ errors() ->
?line {error,{1,erl_scan,{string,$","str"}},1} = %"
erl_scan:string("\"str"), %"
?line {error,{1,erl_scan,char},1} = erl_scan:string("$"),
- ?line test_string([34,65,200,34], [{string,1,"A�"}]),
+ ?line test_string([34,65,200,34], [{string,1,"AÈ"}]),
?line test_string("\\", [{'\\',1}]),
?line {'EXIT',_} =
(catch {foo, erl_scan:string('$\\a', {1,1})}), % type error
@@ -354,7 +355,7 @@ dots() ->
{".\n", {ok,[{dot,1}],2}},
{".%", {ok,[{dot,1}],1}},
{".\210",{ok,[{dot,1}],1}},
- {".% �h",{ok,[{dot,1}],1}},
+ {".% öh",{ok,[{dot,1}],1}},
{".%\n", {ok,[{dot,1}],2}},
{".$", {error,{1,erl_scan,char},1}},
{".$\\", {error,{1,erl_scan,char},1}},
@@ -369,7 +370,7 @@ dots() ->
?line [{column,1},{length,1},{line,1},{text,"."}] =
erl_scan:token_info(T2, [column, length, line, text]),
?line {ok,[{dot,_}=T3],{1,6}} =
- erl_scan:string(".% �h", {1,1}, text),
+ erl_scan:string(".% öh", {1,1}, text),
?line [{column,1},{length,1},{line,1},{text,"."}] =
erl_scan:token_info(T3, [column, length, line, text]),
?line {error,{{1,2},erl_scan,char},{1,3}} =
@@ -472,11 +473,11 @@ chars() ->
variables() ->
- ?line test_string(" \237_Aou�eiy��", [{var,1,'_Aou�eiy��'}]),
+ ?line test_string(" \237_Aouåeiyäö", [{var,1,'_Aouåeiyäö'}]),
?line test_string("A_b_c@", [{var,1,'A_b_c@'}]),
?line test_string("V@2", [{var,1,'V@2'}]),
- ?line test_string("ABD�", [{var,1,'ABD�'}]),
- ?line test_string("�rlig �sten", [{var,1,'�rlig'},{var,1,'�sten'}]),
+ ?line test_string("ABDÀ", [{var,1,'ABDÀ'}]),
+ ?line test_string("Ärlig Östen", [{var,1,'Ärlig'},{var,1,'Östen'}]),
ok.
eof() ->
@@ -823,7 +824,7 @@ unicode() ->
?line {ok,[{char,1,1}],1} = erl_scan:string([$$,$\\,$^,1089]),
?line {error,{1,erl_scan,Error},1} = erl_scan:string("\"qa\x{aaa}"),
- ?line "unterminated string starting with \"qa\\x{AAA}\"" =
+ ?line "unterminated string starting with \"qa"++[2730]++"\"" =
erl_scan:format_error(Error),
?line {error,{{1,1},erl_scan,_},{1,11}} =
erl_scan:string("\"qa\\x{aaa}",{1,1}),
@@ -887,9 +888,10 @@ unicode() ->
{char,_,$d},{']',_}],{1,8}} = erl_scan:string(Str1, {1,1}),
?line test(Str1),
Comment = "%% "++[1089],
- ?line {ok,[{comment,1,[$%,$%,$\s,1089]}],1} =
+ %% Returned a comment In R15B03:
+ {error,{1,erl_scan,{illegal,character}},1} =
erl_scan:string(Comment, 1, return),
- ?line {ok,[{comment,_,[$%,$%,$\s,1089]}],{1,5}} =
+ {error,{{1,1},erl_scan,{illegal,character}},{1,5}} =
erl_scan:string(Comment, {1,1}, return),
ok.
@@ -958,6 +960,182 @@ more_chars() ->
erl_scan:string("$\\xg", {1,1}),
ok.
+otp_10302(doc) ->
+ "OTP-10302. Unicode characters scanner/parser.";
+otp_10302(suite) ->
+ [];
+otp_10302(Config) when is_list(Config) ->
+ %% From unicode():
+ {error,{1,erl_scan,{illegal,atom}},1} =
+ erl_scan:string("'a"++[1089]++"b'", 1, unicode),
+ {error,{{1,1},erl_scan,{illegal,atom}},{1,12}} =
+ erl_scan:string("'qa\\x{aaa}'",{1,1},unicode),
+
+ {ok,[{char,1,1089}],1} = erl_scan:string([$$,1089], 1, unicode),
+ {ok,[{char,1,1089}],1} = erl_scan:string([$$,$\\,1089],1,unicode),
+
+ Qs = "$\\x{aaa}",
+ {ok,[{char,1,2730}],1} = erl_scan:string(Qs,1,unicode),
+ {ok,[Q2],{1,9}} = erl_scan:string(Qs,{1,1},[unicode,text]),
+ [{category,char},{column,1},{length,8},
+ {line,1},{symbol,16#aaa},{text,Qs}] =
+ erl_scan:token_info(Q2),
+
+ Tags = [category, column, length, line, symbol, text],
+
+ U1 = "\"\\x{aaa}\"",
+ {ok,[T1],{1,10}} = erl_scan:string(U1, {1,1}, [unicode,text]),
+ [{category,string},{column,1},{length,9},{line,1},
+ {symbol,[16#aaa]},{text,U1}] = erl_scan:token_info(T1, Tags),
+
+ U2 = "\"\\x41\\x{fff}\\x42\"",
+ {ok,[{string,1,[65,4095,66]}],1} = erl_scan:string(U2, 1, unicode),
+
+ U3 = "\"a\n\\x{fff}\n\"",
+ {ok,[{string,1,[97,10,4095,10]}],3} = erl_scan:string(U3, 1,unicode),
+
+ U4 = "\"\\^\n\\x{aaa}\\^\n\"",
+ {ok,[{string,1,[10,2730,10]}],3} = erl_scan:string(U4, 1,[unicode]),
+
+ Str1 = "\"ab" ++ [1089] ++ "cd\"",
+ {ok,[{string,1,[97,98,1089,99,100]}],1} =
+ erl_scan:string(Str1,1,unicode),
+ {ok,[{string,{1,1},[97,98,1089,99,100]}],{1,8}} =
+ erl_scan:string(Str1, {1,1},unicode),
+
+ OK1 = 16#D800-1,
+ OK2 = 16#DFFF+1,
+ OK3 = 16#FFFE-1,
+ OK4 = 16#FFFF+1,
+ OKL = [OK1,OK2,OK3,OK4],
+
+ Illegal1 = 16#D800,
+ Illegal2 = 16#DFFF,
+ Illegal3 = 16#FFFE,
+ Illegal4 = 16#FFFF,
+ IllegalL = [Illegal1,Illegal2,Illegal3,Illegal4],
+
+ [{ok,[{comment,1,[$%,$%,$\s,OK]}],1} =
+ erl_scan:string("%% "++[OK], 1, [unicode,return]) ||
+ OK <- OKL],
+ {ok,[{comment,_,[$%,$%,$\s,OK1]}],{1,5}} =
+ erl_scan:string("%% "++[OK1], {1,1}, [unicode,return]),
+ [{error,{1,erl_scan,{illegal,character}},1} =
+ erl_scan:string("%% "++[Illegal], 1, [unicode,return]) ||
+ Illegal <- IllegalL],
+ {error,{{1,1},erl_scan,{illegal,character}},{1,5}} =
+ erl_scan:string("%% "++[Illegal1], {1,1}, [unicode,return]),
+
+ [{ok,[],1} = erl_scan:string("%% "++[OK], 1, [unicode]) ||
+ OK <- OKL],
+ {ok,[],{1,5}} = erl_scan:string("%% "++[OK1], {1,1}, [unicode]),
+ [{error,{1,erl_scan,{illegal,character}},1} =
+ erl_scan:string("%% "++[Illegal], 1, [unicode]) ||
+ Illegal <- IllegalL],
+ {error,{{1,1},erl_scan,{illegal,character}},{1,5}} =
+ erl_scan:string("%% "++[Illegal1], {1,1}, [unicode]),
+
+ [{ok,[{string,{1,1},[OK]}],{1,4}} =
+ erl_scan:string("\""++[OK]++"\"",{1,1},unicode) ||
+ OK <- OKL],
+ [{error,{{1,2},erl_scan,{illegal,character}},{1,3}} =
+ erl_scan:string("\""++[OK]++"\"",{1,1},unicode) ||
+ OK <- IllegalL],
+
+ [{error,{{1,1},erl_scan,{illegal,character}},{1,2}} =
+ erl_scan:string([Illegal],{1,1},unicode) ||
+ Illegal <- IllegalL],
+
+ {ok,[{char,{1,1},OK1}],{1,3}} =
+ erl_scan:string([$$,OK1],{1,1},unicode),
+ {error,{{1,1},erl_scan,{illegal,character}},{1,2}} =
+ erl_scan:string([$$,Illegal1],{1,1},unicode),
+
+ {ok,[{char,{1,1},OK1}],{1,4}} =
+ erl_scan:string([$$,$\\,OK1],{1,1},unicode),
+ {error,{{1,1},erl_scan,{illegal,character}},{1,4}} =
+ erl_scan:string([$$,$\\,Illegal1],{1,1},unicode),
+
+ {ok,[{string,{1,1},[55295]}],{1,5}} =
+ erl_scan:string("\"\\"++[OK1]++"\"",{1,1},unicode),
+ {error,{{1,2},erl_scan,{illegal,character}},{1,4}} =
+ erl_scan:string("\"\\"++[Illegal1]++"\"",{1,1},unicode),
+
+ {ok,[{char,{1,1},OK1}],{1,10}} =
+ erl_scan:string("$\\x{D7FF}",{1,1},unicode),
+ {error,{{1,1},erl_scan,{illegal,character}},{1,10}} =
+ erl_scan:string("$\\x{D800}",{1,1},unicode),
+
+ %% Not erl_scan, but erl_parse.
+ {integer,0,1} = erl_parse:abstract(1),
+ Float = 3.14, {float,0,Float} = erl_parse:abstract(Float),
+ {nil,0} = erl_parse:abstract([]),
+ {bin,0,
+ [{bin_element,0,{integer,0,1},default,default},
+ {bin_element,0,{integer,0,2},default,default}]} =
+ erl_parse:abstract(<<1,2>>),
+ {cons,0,{tuple,0,[{atom,0,a}]},{atom,0,b}} =
+ erl_parse:abstract([{a} | b]),
+ {string,0,"str"} = erl_parse:abstract("str"),
+ {cons,0,
+ {integer,0,$a},
+ {cons,0,{integer,0,1024},{string,0,"c"}}} =
+ erl_parse:abstract("a"++[1024]++"c"),
+
+ Line = 17,
+ {integer,Line,1} = erl_parse:abstract(1, Line),
+ Float = 3.14, {float,Line,Float} = erl_parse:abstract(Float, Line),
+ {nil,Line} = erl_parse:abstract([], Line),
+ {bin,Line,
+ [{bin_element,Line,{integer,Line,1},default,default},
+ {bin_element,Line,{integer,Line,2},default,default}]} =
+ erl_parse:abstract(<<1,2>>, Line),
+ {cons,Line,{tuple,Line,[{atom,Line,a}]},{atom,Line,b}} =
+ erl_parse:abstract([{a} | b], Line),
+ {string,Line,"str"} = erl_parse:abstract("str", Line),
+ {cons,Line,
+ {integer,Line,$a},
+ {cons,Line,{integer,Line,1024},{string,Line,"c"}}} =
+ erl_parse:abstract("a"++[1024]++"c", Line),
+
+ Opts1 = [{line,17}],
+ {integer,Line,1} = erl_parse:abstract(1, Opts1),
+ Float = 3.14, {float,Line,Float} = erl_parse:abstract(Float, Opts1),
+ {nil,Line} = erl_parse:abstract([], Opts1),
+ {bin,Line,
+ [{bin_element,Line,{integer,Line,1},default,default},
+ {bin_element,Line,{integer,Line,2},default,default}]} =
+ erl_parse:abstract(<<1,2>>, Opts1),
+ {cons,Line,{tuple,Line,[{atom,Line,a}]},{atom,Line,b}} =
+ erl_parse:abstract([{a} | b], Opts1),
+ {string,Line,"str"} = erl_parse:abstract("str", Opts1),
+ {cons,Line,
+ {integer,Line,$a},
+ {cons,Line,{integer,Line,1024},{string,Line,"c"}}} =
+ erl_parse:abstract("a"++[1024]++"c", Opts1),
+
+ [begin
+ {integer,Line,1} = erl_parse:abstract(1, Opts2),
+ Float = 3.14, {float,Line,Float} = erl_parse:abstract(Float, Opts2),
+ {nil,Line} = erl_parse:abstract([], Opts2),
+ {bin,Line,
+ [{bin_element,Line,{integer,Line,1},default,default},
+ {bin_element,Line,{integer,Line,2},default,default}]} =
+ erl_parse:abstract(<<1,2>>, Opts2),
+ {cons,Line,{tuple,Line,[{atom,Line,a}]},{atom,Line,b}} =
+ erl_parse:abstract([{a} | b], Opts2),
+ {string,Line,"str"} = erl_parse:abstract("str", Opts2),
+ {string,Line,[97,1024,99]} =
+ erl_parse:abstract("a"++[1024]++"c", Opts2)
+ end || Opts2 <- [[{encoding,unicode},{line,Line}],
+ [{encoding,utf8},{line,Line}]]],
+
+ {cons,0,
+ {integer,0,97},
+ {cons,0,{integer,0,1024},{string,0,"c"}}} =
+ erl_parse:abstract("a"++[1024]++"c", [{encoding,latin1}]),
+ ok.
+
test_string(String, Expected) ->
{ok, Expected, _End} = erl_scan:string(String),
test(String).
diff --git a/lib/stdlib/test/escript_SUITE.erl b/lib/stdlib/test/escript_SUITE.erl
index 5b592c65cc..3749d594f2 100644
--- a/lib/stdlib/test/escript_SUITE.erl
+++ b/lib/stdlib/test/escript_SUITE.erl
@@ -26,6 +26,7 @@
errors/1,
strange_name/1,
emulator_flags/1,
+ emulator_flags_no_shebang/1,
module_script/1,
beam_script/1,
archive_script/1,
@@ -34,7 +35,8 @@
create_and_extract/1,
foldl/1,
overflow/1,
- verify_sections/3
+ verify_sections/3,
+ unicode/1
]).
-include_lib("test_server/include/test_server.hrl").
@@ -44,9 +46,10 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[basic, errors, strange_name, emulator_flags,
+ emulator_flags_no_shebang,
module_script, beam_script, archive_script, epp,
create_and_extract, foldl, overflow,
- archive_script_file_access].
+ archive_script_file_access, unicode].
groups() ->
[].
@@ -149,6 +152,21 @@ emulator_flags(Config) when is_list(Config) ->
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+emulator_flags_no_shebang(Config) when is_list(Config) ->
+ Data = ?config(data_dir, Config),
+ Dir = filename:absname(Data), %Get rid of trailing slash.
+ %% Need run_with_opts, to always use "escript" explicitly
+ ?line run_with_opts(Dir, "", "emulator_flags_no_shebang -arg1 arg2 arg3",
+ [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
+ "nostick:[{nostick,[]}]\n"
+ "mnesia:[{mnesia,[\"dir\",\"a/directory\"]},{mnesia,[\"debug\",\"verbose\"]}]\n"
+ "ERL_FLAGS=false\n"
+ "unknown:[]\n"
+ "ExitCode:0">>]),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Pick the source code from the emulator_flags script
%% Generate a new escript with a module header
@@ -810,6 +828,8 @@ normalize_sections(Sections) ->
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
foldl(Config) when is_list(Config) ->
{NewFile, _FileInfo,
_EmuArg, _Source,
@@ -887,6 +907,20 @@ emulate_escript_foldl(Fun, Acc, File) ->
{error, Reason}
end.
+unicode(Config) when is_list(Config) ->
+ Data = ?config(data_dir, Config),
+ Dir = filename:absname(Data), %Get rid of trailing slash.
+ run(Dir, "unicode1",
+ [<<"escript: exception error: an error occurred when evaluating"
+ " an arithmetic expression\n in operator '/'/2\n "
+ "called as <<170>> / <<170>>\nExitCode:127">>]),
+ run(Dir, "unicode2",
+ [<<"escript: exception error: an error occurred when evaluating"
+ " an arithmetic expression\n in operator '/'/2\n "
+ "called as <<\"\xaa\">> / <<\"\xaa\">>\nExitCode:127">>]),
+ run(Dir, "unicode3", [<<"ExitCode:0">>]),
+ ok.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
overflow(Config) when is_list(Config) ->
diff --git a/lib/stdlib/test/escript_SUITE_data/emulator_flags_no_shebang b/lib/stdlib/test/escript_SUITE_data/emulator_flags_no_shebang
new file mode 100644
index 0000000000..47d843ebe1
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/emulator_flags_no_shebang
@@ -0,0 +1,10 @@
+%% -*- erlang -*-
+%%! -nostick -mnesia dir a/directory -mnesia debug verbose
+
+main(MainArgs) ->
+ io:format("main:~p\n",[MainArgs]),
+ ErlArgs = init:get_arguments(),
+ io:format("nostick:~p\n",[[E || E <- ErlArgs, element(1, E) =:= nostick]]),
+ io:format("mnesia:~p\n", [[E || E <- ErlArgs, element(1, E) =:= mnesia]]),
+ 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/escript_SUITE_data/unicode1 b/lib/stdlib/test/escript_SUITE_data/unicode1
new file mode 100755
index 0000000000..a77574625e
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/unicode1
@@ -0,0 +1,14 @@
+#!/usr/bin/env escript
+%% -*- erlang -*-
+
+-export([main/1]).
+
+main(_) ->
+ ok = io:setopts([{encoding,unicode}]),
+ _D = erlang:system_flag(backtrace_depth, 0),
+ A = <<"\x{aa}">>,
+ S = lists:flatten(io_lib:format("~p/~p.", [A, A])),
+ {ok, Ts, _} = erl_scan:string(S, 1, [unicode]),
+ {ok, Es} = erl_parse:parse_exprs(Ts),
+ B = erl_eval:new_bindings(),
+ erl_eval:exprs(Es, B).
diff --git a/lib/stdlib/test/escript_SUITE_data/unicode2 b/lib/stdlib/test/escript_SUITE_data/unicode2
new file mode 100755
index 0000000000..495188f6f0
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/unicode2
@@ -0,0 +1,14 @@
+#!/usr/bin/env escript
+%% -*- erlang -*-
+
+-export([main/1]).
+
+main(_) ->
+ ok = io:setopts([{encoding,latin1}]),
+ _D = erlang:system_flag(backtrace_depth, 0),
+ A = <<"\x{aa}">>,
+ S = lists:flatten(io_lib:format("~p/~p.", [A, A])),
+ {ok, Ts, _} = erl_scan:string(S, 1, [unicode]),
+ {ok, Es} = erl_parse:parse_exprs(Ts),
+ B = erl_eval:new_bindings(),
+ erl_eval:exprs(Es, B).
diff --git a/lib/stdlib/test/escript_SUITE_data/unicode3 b/lib/stdlib/test/escript_SUITE_data/unicode3
new file mode 100755
index 0000000000..944487dcae
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/unicode3
@@ -0,0 +1,13 @@
+#!/usr/bin/env escript
+%% -*- erlang; coding: utf-8 -*-
+
+-export([main/1]).
+
+main(_) ->
+ ok = io:setopts([{encoding,unicode}]),
+ Bin1 = <<"örn_Ѐ שלום-שלום+של 日本語">>,
+
+ L = [246,114,110,95,1024,32,1513,1500,1493,1501,45,1513,1500,1493,
+ 1501,43,1513,1500,32,26085,26412,35486],
+ L = unicode:characters_to_list(Bin1, utf8),
+ ok.
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index d5c1c5276e..dc17e5d33c 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -2170,20 +2170,29 @@ heir_do(Opts) ->
?line undefined = ets:info(foo),
%% When heir dies and pid reused before founder dies
- NextPidIx = erts_debug:get_internal_state(next_pid),
- {Founder4,MrefF4} = my_spawn_monitor(fun()->heir_founder(Master,"The dying heir",Opts)end),
- {Heir4,MrefH4} = my_spawn_monitor(fun()->heir_heir(Founder4)end),
- Founder4 ! {go, Heir4},
- ?line {'DOWN', MrefH4, process, Heir4, normal} = receive_any(),
- erts_debug:set_internal_state(next_pid, NextPidIx),
- {Heir4,MrefH4_B} = spawn_monitor_with_pid(Heir4,
- fun()-> ?line die_please = receive_any() end),
- Founder4 ! die_please,
- ?line {'DOWN', MrefF4, process, Founder4, normal} = receive_any(),
- Heir4 ! die_please,
- ?line {'DOWN', MrefH4_B, process, Heir4, normal} = receive_any(),
- ?line undefined = ets:info(foo),
-
+ repeat_while(fun() ->
+ NextPidIx = erts_debug:get_internal_state(next_pid),
+ {Founder4,MrefF4} = my_spawn_monitor(fun()->heir_founder(Master,"The dying heir",Opts)end),
+ {Heir4,MrefH4} = my_spawn_monitor(fun()->heir_heir(Founder4)end),
+ Founder4 ! {go, Heir4},
+ ?line {'DOWN', MrefH4, process, Heir4, normal} = receive_any(),
+ erts_debug:set_internal_state(next_pid, NextPidIx),
+ DoppelGanger = spawn_monitor_with_pid(Heir4,
+ fun()-> ?line die_please = receive_any() end),
+ Founder4 ! die_please,
+ ?line {'DOWN', MrefF4, process, Founder4, normal} = receive_any(),
+ case DoppelGanger of
+ {Heir4,MrefH4_B} ->
+ Heir4 ! die_please,
+ ?line {'DOWN', MrefH4_B, process, Heir4, normal} = receive_any(),
+ ?line undefined = ets:info(foo),
+ false;
+ failed ->
+ io:format("Failed to spawn process with pid ~p\n", [Heir4]),
+ true % try again
+ end
+ end),
+
?line verify_etsmem(EtsMem).
heir_founder(Master, HeirData, Opts) ->
@@ -5787,25 +5796,20 @@ receive_any_spinning(Loops, N, Tries) when N>0 ->
spawn_monitor_with_pid(Pid, Fun) when is_pid(Pid) ->
- spawn_monitor_with_pid(Pid, Fun, 1, 10).
+ spawn_monitor_with_pid(Pid, Fun, 10).
-spawn_monitor_with_pid(Pid, Fun, N, M) when N > M*10 ->
- spawn_monitor_with_pid(Pid, Fun, N, M*10);
-spawn_monitor_with_pid(Pid, Fun, N, M) ->
- ?line false = is_process_alive(Pid),
+spawn_monitor_with_pid(_, _, 0) ->
+ failed;
+spawn_monitor_with_pid(Pid, Fun, N) ->
case my_spawn(fun()-> case self() of
Pid -> Fun();
_ -> die
end
end) of
- Pid ->
+ Pid ->
{Pid, erlang:monitor(process, Pid)};
Other ->
- case N rem M of
- 0 -> io:format("Failed ~p times to get pid ~p (current = ~p)\n",[N,Pid,Other]);
- _ -> ok
- end,
- spawn_monitor_with_pid(Pid,Fun,N+1,M)
+ spawn_monitor_with_pid(Pid,Fun,N-1)
end.
diff --git a/lib/stdlib/test/gen_server_SUITE.erl b/lib/stdlib/test/gen_server_SUITE.erl
index 2abb01ba24..dffeadb423 100644
--- a/lib/stdlib/test/gen_server_SUITE.erl
+++ b/lib/stdlib/test/gen_server_SUITE.erl
@@ -1046,8 +1046,9 @@ call_with_huge_message_queue(Config) when is_list(Config) ->
io:format("Time for empty message queue: ~p", [Time]),
io:format("Time for huge message queue: ~p", [NewTime]),
+ IsCover = test_server:is_cover(),
case (NewTime+1) / (Time+1) of
- Q when Q < 10 ->
+ Q when Q < 10; IsCover ->
ok;
Q ->
io:format("Q = ~p", [Q]),
diff --git a/lib/stdlib/test/id_transform_SUITE.erl b/lib/stdlib/test/id_transform_SUITE.erl
index 233b0d0a78..ee97ffe7b3 100644
--- a/lib/stdlib/test/id_transform_SUITE.erl
+++ b/lib/stdlib/test/id_transform_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -61,7 +61,7 @@ id_transform(Config) when is_list(Config) ->
?line {module,erl_id_trans}=code:load_binary(erl_id_trans,File,Bin),
?line case test_server:purify_is_running() of
false ->
- Dog = ?t:timetrap(?t:hours(1)),
+ Dog = ct:timetrap(?t:hours(1)),
?line Res = run_in_test_suite(),
?t:timetrap_cancel(Dog),
Res;
diff --git a/lib/stdlib/test/io_SUITE.erl b/lib/stdlib/test/io_SUITE.erl
index bb02a879c2..521d7255ea 100644
--- a/lib/stdlib/test/io_SUITE.erl
+++ b/lib/stdlib/test/io_SUITE.erl
@@ -1,7 +1,8 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -27,7 +28,8 @@
otp_6282/1, otp_6354/1, otp_6495/1, otp_6517/1, otp_6502/1,
manpage/1, otp_6708/1, otp_7084/1, otp_7421/1,
io_lib_collect_line_3_wb/1, cr_whitespace_in_string/1,
- io_fread_newlines/1, otp_8989/1, io_lib_fread_literal/1]).
+ io_fread_newlines/1, otp_8989/1, io_lib_fread_literal/1,
+ io_lib_print_binary_depth_one/1, otp_10302/1]).
%-define(debug, true).
@@ -62,7 +64,8 @@ all() ->
otp_6282, otp_6354, otp_6495, otp_6517, otp_6502,
manpage, otp_6708, otp_7084, otp_7421,
io_lib_collect_line_3_wb, cr_whitespace_in_string,
- io_fread_newlines, otp_8989, io_lib_fread_literal].
+ io_fread_newlines, otp_8989, io_lib_fread_literal,
+ io_lib_print_binary_depth_one, otp_10302].
groups() ->
[].
@@ -892,7 +895,7 @@ otp_6354(Config) when is_list(Config) ->
?line "\"\\b\\t\\n\\v\\f\\r\\e\250\"" =
p([8,9,10,11,12,13,27,168], 1, 40, -1),
% ?line "\"\\b\\t\\n\"\n \"\\v\\f\\r\"\n \"\\e\250\"" =
- ?line "\"\\b\\t\\n\\v\\f\\r\\e�\"" =
+ ?line "\"\\b\\t\\n\\v\\f\\r\\e¨\"" =
p([8,9,10,11,12,13,27,168], 1, 10, -1),
?line "\"\\b\\t\\n\\v\\f\\r\\e\250\"" =
p([8,9,10,11,12,13,27,168], 1, 40, 100),
@@ -2021,3 +2024,55 @@ io_lib_fread_literal(Suite) when is_list(Suite) ->
?line {done,{error,{fread,input}},_} = io_lib:fread(C2, eof, " d"),
?line {done,{ok,[]},[]} = io_lib:fread(C2, "d\n", " d"),
ok.
+
+io_lib_print_binary_depth_one(doc) ->
+ "Test binaries printed with a depth of one behave correctly";
+io_lib_print_binary_depth_one(Suite) when is_list(Suite) ->
+ ?line "<<>>" = fmt("~W", [<<>>, 1]),
+ ?line "<<>>" = fmt("~P", [<<>>, 1]),
+ ?line "<<...>>" = fmt("~W", [<<1>>, 1]),
+ ?line "<<...>>" = fmt("~P", [<<1>>, 1]),
+ ?line "<<...>>" = fmt("~W", [<<1:7>>, 1]),
+ ?line "<<...>>" = fmt("~P", [<<1:7>>, 1]),
+ ok.
+
+otp_10302(doc) ->
+ "OTP-10302. Unicode";
+otp_10302(Suite) when is_list(Suite) ->
+ "\"\x{400}\"" = pretty("\x{400}", -1),
+ "<<\"\x{400}\"/utf8>>" = pretty(<<"\x{400}"/utf8>>, -1),
+
+ "<<\"\x{400}foo\"/utf8>>" = pretty(<<"\x{400}foo"/utf8>>, 2),
+ "<<\"äppl\"/utf8>>" = pretty(<<"äppl"/utf8>>, 2),
+ "<<\"äppl\"/utf8...>>" = pretty(<<"äpple"/utf8>>, 2),
+ "<<\"apel\">>" = pretty(<<"apel">>, 2),
+ "<<\"apel\"...>>" = pretty(<<"apelsin">>, 2),
+ "<<228,112,112,108>>" = fmt("~tp", [<<"äppl">>]),
+ "<<228,...>>" = fmt("~tP", [<<"äppl">>, 2]),
+
+ Chars = lists:seq(0, 512), % just a few...
+ [] = [C || C <- Chars, S <- io_lib:write_unicode_char_as_latin1(C),
+ not is_latin1(S)],
+ L1 = [S || C <- Chars, S <- io_lib:write_unicode_char(C),
+ not is_latin1(S)],
+ L1 = lists:seq(256, 512),
+
+ [] = [C || C <- Chars, S <- io_lib:write_unicode_string_as_latin1([C]),
+ not is_latin1(S)],
+ L2 = [S || C <- Chars, S <- io_lib:write_unicode_string([C]),
+ not is_latin1(S)],
+ L2 = lists:seq(256, 512),
+
+ ok.
+
+pretty(Term, Depth) when is_integer(Depth) ->
+ Opts = [{column, 1}, {line_length, 20},
+ {depth, Depth}, {max_chars, 60},
+ {encoding, unicode}],
+ pretty(Term, Opts);
+pretty(Term, Opts) when is_list(Opts) ->
+ R = io_lib_pretty:print(Term, Opts),
+ lists:flatten(io_lib:format("~ts", [R])).
+
+is_latin1(S) ->
+ S >= 0 andalso S =< 255.
diff --git a/lib/stdlib/test/io_proto_SUITE.erl b/lib/stdlib/test/io_proto_SUITE.erl
index 661d57c85b..299daf0e42 100644
--- a/lib/stdlib/test/io_proto_SUITE.erl
+++ b/lib/stdlib/test/io_proto_SUITE.erl
@@ -96,7 +96,8 @@ groups() ->
[].
init_per_suite(Config) ->
- Config.
+ DefShell = get_default_shell(),
+ [{default_shell,DefShell}|Config].
end_per_suite(_Config) ->
ok.
@@ -124,20 +125,25 @@ unicode_prompt(doc) ->
["Test that an Unicode prompt does not crash the shell"];
unicode_prompt(Config) when is_list(Config) ->
?line PA = filename:dirname(code:which(?MODULE)),
- ?line rtnode([{putline,""},
- {putline, "2."},
- {getline, "2"},
- {putline, "shell:prompt_func({io_proto_SUITE,uprompt})."},
- {getline, "default"},
- {putline, "io:get_line('')."},
- {putline, "hej"},
- {getline, "\"hej\\n\""},
- {putline, "io:setopts([{binary,true}])."},
- {getline, "ok"},
- {putline, "io:get_line('')."},
- {putline, "hej"},
- {getline, "<<\"hej\\n\">>"}
- ],[],[],"-pa \""++ PA++"\""),
+ case proplists:get_value(default_shell,Config) of
+ old ->
+ ok;
+ new ->
+ ?line rtnode([{putline,""},
+ {putline, "2."},
+ {getline, "2"},
+ {putline, "shell:prompt_func({io_proto_SUITE,uprompt})."},
+ {getline, "default"},
+ {putline, "io:get_line('')."},
+ {putline, "hej"},
+ {getline, "\"hej\\n\""},
+ {putline, "io:setopts([{binary,true}])."},
+ {getline, "ok"},
+ {putline, "io:get_line('')."},
+ {putline, "hej"},
+ {getline, "<<\"hej\\n\">>"}
+ ],[],[],"-pa \""++ PA++"\"")
+ end,
%% And one with oldshell
?line rtnode([{putline,""},
{putline, "2."},
@@ -234,21 +240,26 @@ setopts_getopts(Config) when is_list(Config) ->
lists:sort(io:getopts(RFile)),
?line eof = io:get_line(RFile,''),
?line file:close(RFile),
- %% So, lets test another node with new interactive shell
- ?line rtnode([{putline,""},
- {putline, "2."},
- {getline, "2"},
- {putline, "lists:keyfind(binary,1,io:getopts())."},
- {getline, "{binary,false}"},
- {putline, "io:get_line('')."},
- {putline, "hej"},
- {getline, "\"hej\\n\""},
- {putline, "io:setopts([{binary,true}])."},
- {getline, "ok"},
- {putline, "io:get_line('')."},
- {putline, "hej"},
- {getline, "<<\"hej\\n\">>"}
- ],[]),
+ case proplists:get_value(default_shell,Config) of
+ old ->
+ ok;
+ new ->
+ %% So, lets test another node with new interactive shell
+ ?line rtnode([{putline,""},
+ {putline, "2."},
+ {getline, "2"},
+ {putline, "lists:keyfind(binary,1,io:getopts())."},
+ {getline, "{binary,false}"},
+ {putline, "io:get_line('')."},
+ {putline, "hej"},
+ {getline, "\"hej\\n\""},
+ {putline, "io:setopts([{binary,true}])."},
+ {getline, "ok"},
+ {putline, "io:get_line('')."},
+ {putline, "hej"},
+ {getline, "<<\"hej\\n\">>"}
+ ],[])
+ end,
%% And one with oldshell
?line rtnode([{putline,""},
{putline, "2."},
@@ -433,21 +444,27 @@ unicode_options(Config) when is_list(Config) ->
end,
?line [ ok = CannotWriteFile(F,FailDir) || F <- AllNoBom ],
- %% OK, time for the group_leaders...
- ?line rtnode([{putline,""},
- {putline, "2."},
- {getline, "2"},
- {putline, "lists:keyfind(encoding,1,io:getopts())."},
- {getline, "{encoding,latin1}"},
- {putline, "io:format(\"~ts~n\",[[1024]])."},
- {getline, "\\x{400}"},
- {putline, "io:setopts([unicode])."},
- {getline, "ok"},
- {putline, "io:format(\"~ts~n\",[[1024]])."},
- {getline,
- binary_to_list(unicode:characters_to_binary(
- [1024],unicode,utf8))}
- ],[],"LC_CTYPE=\""++get_lc_ctype()++"\"; export LC_CTYPE; "),
+ case proplists:get_value(default_shell,Config) of
+ old ->
+ ok;
+ new ->
+ %% OK, time for the group_leaders...
+ ?line rtnode([{putline,""},
+ {putline, "2."},
+ {getline, "2"},
+ {putline, "lists:keyfind(encoding,1,io:getopts())."},
+ {getline, "{encoding,latin1}"},
+ {putline, "io:format(\"~ts~n\",[[1024]])."},
+ {getline, "\\x{400}"},
+ {putline, "io:setopts([unicode])."},
+ {getline, "ok"},
+ {putline, "io:format(\"~ts~n\",[[1024]])."},
+ {getline,
+ binary_to_list(unicode:characters_to_binary(
+ [1024],unicode,utf8))}
+ ],[],"LC_CTYPE=\""++get_lc_ctype()++"\"; "
+ "export LC_CTYPE; ")
+ end,
?line rtnode([{putline,""},
{putline, "2."},
{getline_re, ".*2."},
@@ -680,23 +697,28 @@ binary_options(Config) when is_list(Config) ->
?line file:close(F3),
%% OK, time for the group_leaders...
%% io:format(standard_error,"Hmmm:~w~n",["<<\""++binary_to_list(<<"\345\344\366"/utf8>>)++"\\n\">>"]),
- ?line rtnode([{putline,""},
- {putline, "2."},
- {getline, "2"},
- {putline, "lists:keyfind(binary,1,io:getopts())."},
- {getline, "{binary,false}"},
- {putline, "io:get_line('')."},
- {putline, "hej"},
- {getline, "\"hej\\n\""},
- {putline, "io:setopts([{binary,true},unicode])."},
- {getline, "ok"},
- {putline, "io:get_line('')."},
- {putline, "hej"},
- {getline, "<<\"hej\\n\">>"},
- {putline, "io:get_line('')."},
- {putline, binary_to_list(<<"\345\344\366"/utf8>>)},
- {getline, "<<\""++binary_to_list(unicode:characters_to_binary(<<"\345\344\366"/utf8>>,latin1,utf8))++"\\n\">>"}
- ],[]),
+ case proplists:get_value(default_shell,Config) of
+ old ->
+ ok;
+ new ->
+ ?line rtnode([{putline,""},
+ {putline, "2."},
+ {getline, "2"},
+ {putline, "lists:keyfind(binary,1,io:getopts())."},
+ {getline, "{binary,false}"},
+ {putline, "io:get_line('')."},
+ {putline, "hej"},
+ {getline, "\"hej\\n\""},
+ {putline, "io:setopts([{binary,true},unicode])."},
+ {getline, "ok"},
+ {putline, "io:get_line('')."},
+ {putline, "hej"},
+ {getline, "<<\"hej\\n\">>"},
+ {putline, "io:get_line('')."},
+ {putline, binary_to_list(<<"\345\344\366"/utf8>>)},
+ {getline, "<<\""++binary_to_list(unicode:characters_to_binary(<<"\345\344\366"/utf8>>,latin1,utf8))++"\\n\">>"}
+ ],[])
+ end,
%% And one with oldshell
?line rtnode([{putline,""},
{putline, "2."},
@@ -714,7 +736,7 @@ binary_options(Config) when is_list(Config) ->
{getline_re, ".*<<\"hej\\\\n\">>"},
{putline, "io:get_line('')."},
{putline, binary_to_list(<<"\345\344\366"/utf8>>)},
- {getline_re, ".*<<\""++binary_to_list(unicode:characters_to_binary(<<"\345\344\366"/utf8>>,latin1,utf8))++"\\\\n\">>"}
+ {getline_re, ".*<<\""++binary_to_list(<<"\345\344\366"/utf8>>)++"\\\\n\"/utf8>>"}
],[],[],"-oldshell"),
ok.
@@ -1146,9 +1168,11 @@ read_modes_gl(suite) ->
read_modes_gl(doc) ->
["Test various modes when reading from the group leade from another machine"];
read_modes_gl(Config) when is_list(Config) ->
- case get_progs() of
- {error,Reason} ->
+ case {get_progs(),proplists:get_value(default_shell,Config)} of
+ {{error,Reason},_} ->
{skipped,Reason};
+ {_,old} ->
+ {skipper,"No new shell"};
_ ->
read_modes_gl_1(Config,answering_machine1)
end.
@@ -1754,6 +1778,17 @@ get_data_within(Port, Timeout, Acc) ->
timeout
end.
+get_default_shell() ->
+ try
+ rtnode([{putline,""},
+ {putline, "whereis(user_drv)."},
+ {getline, "undefined"}],[]),
+ old
+ catch E:R ->
+ ?dbg({E,R}),
+ new
+ end.
+
%%
%% Test I/O-server
%%
diff --git a/lib/stdlib/test/proc_lib_SUITE.erl b/lib/stdlib/test/proc_lib_SUITE.erl
index c95089117c..8dca69bac4 100644
--- a/lib/stdlib/test/proc_lib_SUITE.erl
+++ b/lib/stdlib/test/proc_lib_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -28,7 +28,7 @@
crash/1, sync_start_nolink/1, sync_start_link/1,
spawn_opt/1, sp1/0, sp2/0, sp3/1, sp4/2, sp5/1,
hibernate/1]).
--export([ otp_6345/1]).
+-export([ otp_6345/1, init_dont_hang/1]).
-export([hib_loop/1, awaken/1]).
@@ -36,7 +36,7 @@
handle_event/2, handle_call/2, handle_info/2,
terminate/2]).
--export([otp_6345_init/1]).
+-export([otp_6345_init/1, init_dont_hang_init/1]).
-ifdef(STANDALONE).
@@ -52,7 +52,7 @@ all() ->
{group, tickets}].
groups() ->
- [{tickets, [], [otp_6345]},
+ [{tickets, [], [otp_6345, init_dont_hang]},
{sync_start, [], [sync_start_nolink, sync_start_link]}].
init_per_suite(Config) ->
@@ -343,6 +343,29 @@ otp_6345_loop() ->
otp_6345_loop()
end.
+%% OTP-9803
+init_dont_hang(suite) ->
+ [];
+init_dont_hang(doc) ->
+ ["Check that proc_lib:start don't hang if spawned process crashes before proc_lib:init_ack/2"];
+init_dont_hang(Config) when is_list(Config) ->
+ %% Start should behave as start_link
+ process_flag(trap_exit, true),
+ StartLinkRes = proc_lib:start_link(?MODULE, init_dont_hang_init, [self()]),
+ try
+ StartLinkRes = proc_lib:start(?MODULE, init_dont_hang_init, [self()], 1000),
+ StartLinkRes = proc_lib:start(?MODULE, init_dont_hang_init, [self()], 1000, []),
+ ok
+ catch _:Error ->
+ io:format("Error ~p /= ~p ~n",[erlang:get_stacktrace(), StartLinkRes]),
+ exit(Error)
+ end.
+
+init_dont_hang_init(Parent) ->
+ 1 = 2.
+
+
+
%%-----------------------------------------------------------------
%% The error_logger handler used.
%%-----------------------------------------------------------------
diff --git a/lib/stdlib/test/qlc_SUITE.erl b/lib/stdlib/test/qlc_SUITE.erl
index e3090e4a47..cac8309bd9 100644
--- a/lib/stdlib/test/qlc_SUITE.erl
+++ b/lib/stdlib/test/qlc_SUITE.erl
@@ -6062,21 +6062,6 @@ otp_6673(Config) when is_list(Config) ->
],
?line run(Config, Ts_RT),
- %% Ulf Wiger provided a patch that makes QLC work with packages:
- Dir = filename:join(?privdir, "p"),
- ?line ok = filelib:ensure_dir(filename:join(Dir, ".")),
- File = filename:join(Dir, "p.erl"),
- ?line ok = file:write_file(File,
- <<"-module(p.p).\n"
- "-export([q/0]).\n"
- "-include_lib(\"stdlib/include/qlc.hrl\").\n"
- "q() ->\n"
- " .qlc:q([X || X <- [1,2]]).">>),
- ?line {ok, 'p.p'} = compile:file(File, [{outdir,Dir}]),
- ?line code:purge('p.p'),
- ?line {module, 'p.p'} = code:load_abs(filename:rootname(File), 'p.p'),
- ?line [1,2] = qlc:e(p.p:q()),
-
ok.
otp_6964(doc) ->
diff --git a/lib/stdlib/test/re_SUITE.erl b/lib/stdlib/test/re_SUITE.erl
index 8ee0a13f4c..500f5fadb9 100644
--- a/lib/stdlib/test/re_SUITE.erl
+++ b/lib/stdlib/test/re_SUITE.erl
@@ -1,3 +1,4 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
@@ -291,10 +292,10 @@ global_capture(Config) when is_list(Config) ->
?line match = re:run("ABCabcdABCabcdA","a(?<FOO>bcd)",[global,{capture,none,index}]),
?line match = re:run("ABCabcdABCabcdA","a(?<FOO>bcd)",[global,{capture,none,binary}]),
?line match = re:run("ABCabcdABCabcdA","a(?<FOO>bcd)",[global,{capture,none,list}]),
- ?line {match,[[<<195,133,98,99,100>>,<<"bcd">>],[<<"abcd">>,<<"bcd">>]]} = re:run("ABC�bcdABCabcdA",".(?<FOO>bcd)",[global,{capture,all,binary},unicode]),
- ?line {match,[["�bcd","bcd"],["abcd","bcd"]]} = re:run(<<"ABC",8#303,8#205,"bcdABCabcdA">>,".(?<FOO>bcd)",[global,{capture,all,list},unicode]),
- ?line {match,[["�bcd","bcd"],["abcd","bcd"]]} = re:run("ABC�bcdABCabcdA",".(?<FOO>bcd)",[global,{capture,all,list},unicode]),
- ?line {match,[[{3,5},{5,3}],[{11,4},{12,3}]]} = re:run("ABC�bcdABCabcdA",".(?<FOO>bcd)",[global,{capture,all,index},unicode]),
+ ?line {match,[[<<195,133,98,99,100>>,<<"bcd">>],[<<"abcd">>,<<"bcd">>]]} = re:run("ABCÅbcdABCabcdA",".(?<FOO>bcd)",[global,{capture,all,binary},unicode]),
+ ?line {match,[["Åbcd","bcd"],["abcd","bcd"]]} = re:run(<<"ABC",8#303,8#205,"bcdABCabcdA">>,".(?<FOO>bcd)",[global,{capture,all,list},unicode]),
+ ?line {match,[["Åbcd","bcd"],["abcd","bcd"]]} = re:run("ABCÅbcdABCabcdA",".(?<FOO>bcd)",[global,{capture,all,list},unicode]),
+ ?line {match,[[{3,5},{5,3}],[{11,4},{12,3}]]} = re:run("ABCÅbcdABCabcdA",".(?<FOO>bcd)",[global,{capture,all,index},unicode]),
?t:timetrap_cancel(Dog),
ok.
@@ -314,17 +315,17 @@ replace_return(Config) when is_list(Config) ->
Dog = ?t:timetrap(?t:minutes(3)),
?line {'EXIT',{badarg,_}} = (catch re:replace("na","(a","")),
?line <<"nasse">> = re:replace(<<"nisse">>,"i","a",[{return,binary}]),
- ?line <<"ABC�XABCXA">> = re:replace("ABC\305abcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,binary}]),
+ ?line <<"ABCÅXABCXA">> = re:replace("ABC\305abcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,binary}]),
- ?line [<<"ABC�">>,
+ ?line [<<"ABCÅ">>,
<<"X">>,
<<"ABC">>,
<<"X">> |
<<"A">> ] =
- re:replace("ABC�abcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,iodata}]),
- ?line "ABC�XABCXA" = re:replace("ABC�abcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,list},unicode]),
- ?line <<65,66,67,195,133,88,65,66,67,88,65>> = re:replace("ABC�abcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,binary},unicode]),
- ?line <<65,66,67,195,133,88,65,66,67,97,98,99,100,65>> = re:replace("ABC�abcdABCabcdA","a(?<FOO>bcd)","X",[{return,binary},unicode]),
+ re:replace("ABCÅabcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,iodata}]),
+ ?line "ABCÅXABCXA" = re:replace("ABCÅabcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,list},unicode]),
+ ?line <<65,66,67,195,133,88,65,66,67,88,65>> = re:replace("ABCÅabcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,binary},unicode]),
+ ?line <<65,66,67,195,133,88,65,66,67,97,98,99,100,65>> = re:replace("ABCÅabcdABCabcdA","a(?<FOO>bcd)","X",[{return,binary},unicode]),
?line <<"iXk">> = re:replace("abcdefghijk","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\9X",[{return,binary}]),
?line <<"jXk">> = re:replace("abcdefghijk","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\10X",[{return,binary}]),
?line <<"Xk">> = re:replace("abcdefghijk","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\11X",[{return,binary}]),
diff --git a/lib/stdlib/test/re_testoutput1_replacement_test.erl b/lib/stdlib/test/re_testoutput1_replacement_test.erl
index 69cb140e0d..8f8d8762ad 100644
--- a/lib/stdlib/test/re_testoutput1_replacement_test.erl
+++ b/lib/stdlib/test/re_testoutput1_replacement_test.erl
@@ -1,7 +1,8 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -274,10 +275,10 @@ run() ->
?line <<"dthing">> = iolist_to_binary(re:replace("dthing","^[^]cde]","y\\1I&MoqRPG&GQa\\1l",[global])),
?line <<"ething">> = iolist_to_binary(re:replace("ething","^[^]cde]","AsxwUn\\1GqkWNdgRJk",[])),
?line <<"ething">> = iolist_to_binary(re:replace("ething","^[^]cde]","AsxwUn\\1GqkWNdgRJk",[global])),
-?line <<"RornKmOnaFr�tWgtW">> = iolist_to_binary(re:replace("�","^\\�","R\\1o\\1r\\1nKmOnaFr&tWgtW",[])),
-?line <<"RornKmOnaFr�tWgtW">> = iolist_to_binary(re:replace("�","^\\�","R\\1o\\1r\\1nKmOnaFr&tWgtW",[global])),
-?line <<"ufbmbfOYuK�wf�E�dx">> = iolist_to_binary(re:replace("�","^�","ufbmbfOYuK&wf&E&\\1dx",[])),
-?line <<"ufbmbfOYuK�wf�E�dx">> = iolist_to_binary(re:replace("�","^�","ufbmbfOYuK&wf&E&\\1dx",[global])),
+?line <<"RornKmOnaFrtWgtW">> = iolist_to_binary(re:replace("","^\\","R\\1o\\1r\\1nKmOnaFr&tWgtW",[])),
+?line <<"RornKmOnaFrtWgtW">> = iolist_to_binary(re:replace("","^\\","R\\1o\\1r\\1nKmOnaFr&tWgtW",[global])),
+?line <<"ufbmbfOYuKÿwfÿEÿdx">> = iolist_to_binary(re:replace("ÿ","^ÿ","ufbmbfOYuK&wf&E&\\1dx",[])),
+?line <<"ufbmbfOYuKÿwfÿEÿdx">> = iolist_to_binary(re:replace("ÿ","^ÿ","ufbmbfOYuK&wf&E&\\1dx",[global])),
?line <<"oAdJme0jw">> = iolist_to_binary(re:replace("0","^[0-9]+$","oAdJme\\1&jw",[])),
?line <<"oAdJme0jw">> = iolist_to_binary(re:replace("0","^[0-9]+$","oAdJme\\1&jw",[global])),
?line <<"1aoKN">> = iolist_to_binary(re:replace("1","^[0-9]+$","&aoKN",[])),
@@ -14972,10 +14973,10 @@ def">> = iolist_to_binary(re:replace("abc
def","abc$","M",[global])),
?line <<"abcWCabcSYXGPjRugTabcVGabcSX">> = iolist_to_binary(re:replace("abcS","(abc)\\123","\\1WC&YXGPjRugT\\1VG&X",[])),
?line <<"abcWCabcSYXGPjRugTabcVGabcSX">> = iolist_to_binary(re:replace("abcS","(abc)\\123","\\1WC&YXGPjRugT\\1VG&X",[global])),
-?line <<"fabc�Uabc�UmiqabceCsabcabc�">> = iolist_to_binary(re:replace("abc�","(abc)\\223","f&U&Umiq\\1eCs\\1&",[])),
-?line <<"fabc�Uabc�UmiqabceCsabcabc�">> = iolist_to_binary(re:replace("abc�","(abc)\\223","f&U&Umiq\\1eCs\\1&",[global])),
-?line <<"JRFabcxnbabc�Vkabc�fWigQMuaY">> = iolist_to_binary(re:replace("abc�","(abc)\\323","JRF\\1xnb&Vk&fWigQMuaY",[])),
-?line <<"JRFabcxnbabc�Vkabc�fWigQMuaY">> = iolist_to_binary(re:replace("abc�","(abc)\\323","JRF\\1xnb&Vk&fWigQMuaY",[global])),
+?line <<"fabc“Uabc“UmiqabceCsabcabc“">> = iolist_to_binary(re:replace("abc“","(abc)\\223","f&U&Umiq\\1eCs\\1&",[])),
+?line <<"fabc“Uabc“UmiqabceCsabcabc“">> = iolist_to_binary(re:replace("abc“","(abc)\\223","f&U&Umiq\\1eCs\\1&",[global])),
+?line <<"JRFabcxnbabcÓVkabcÓfWigQMuaY">> = iolist_to_binary(re:replace("abcÓ","(abc)\\323","JRF\\1xnb&Vk&fWigQMuaY",[])),
+?line <<"JRFabcxnbabcÓVkabcÓfWigQMuaY">> = iolist_to_binary(re:replace("abcÓ","(abc)\\323","JRF\\1xnb&Vk&fWigQMuaY",[global])),
?line <<"vgabc@QQ">> = iolist_to_binary(re:replace("abc@","(abc)\\100","vg&QQ",[])),
?line <<"vgabc@QQ">> = iolist_to_binary(re:replace("abc@","(abc)\\100","vg&QQ",[global])),
?line <<"abc@OkvNytabc@abcabc@a">> = iolist_to_binary(re:replace("abc@","(abc)\\100","&OkvNyt&\\1&a",[])),
@@ -18343,24 +18344,24 @@ xb","(?!^)x","\\1tysI\\1v\\1BVwx\\1FOWG\\1&C",[multiline,
?line <<"cY">> = iolist_to_binary(re:replace("M","\\M","cY\\1",[global])),
?line <<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","(a+)*b","yWOTIFhIX\\1H",[])),
?line <<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","(a+)*b","yWOTIFhIX\\1H",[global])),
-?line <<"NREGularsRREGularWEYrVRr">> = iolist_to_binary(re:replace("REGular","(?i)reg(?:ul(?:[a�]|ae)r|ex)","N&\\1sR&WEYrVRr",[])),
-?line <<"NREGularsRREGularWEYrVRr">> = iolist_to_binary(re:replace("REGular","(?i)reg(?:ul(?:[a�]|ae)r|ex)","N&\\1sR&WEYrVRr",[global])),
-?line <<"G">> = iolist_to_binary(re:replace("regulaer","(?i)reg(?:ul(?:[a�]|ae)r|ex)","G",[])),
-?line <<"G">> = iolist_to_binary(re:replace("regulaer","(?i)reg(?:ul(?:[a�]|ae)r|ex)","G",[global])),
-?line <<"PSsXtwlmy">> = iolist_to_binary(re:replace("Regex","(?i)reg(?:ul(?:[a�]|ae)r|ex)","PSsXtwlmy",[])),
-?line <<"PSsXtwlmy">> = iolist_to_binary(re:replace("Regex","(?i)reg(?:ul(?:[a�]|ae)r|ex)","PSsXtwlmy",[global])),
-?line <<"regul�rmiYTi">> = iolist_to_binary(re:replace("regul�r","(?i)reg(?:ul(?:[a�]|ae)r|ex)","&miYTi\\1\\1",[])),
-?line <<"regul�rmiYTi">> = iolist_to_binary(re:replace("regul�r","(?i)reg(?:ul(?:[a�]|ae)r|ex)","&miYTi\\1\\1",[global])),
-?line <<"W�����rxh�����yUoaLOIegmSA">> = iolist_to_binary(re:replace("�����","����[�-��-�]+","W&rxh&yUoaL\\1OIegmS\\1A",[])),
-?line <<"W�����rxh�����yUoaLOIegmSA">> = iolist_to_binary(re:replace("�����","����[�-��-�]+","W&rxh&yUoaL\\1OIegmS\\1A",[global])),
-?line <<"F�����gnWPyHeh�����tXTQ">> = iolist_to_binary(re:replace("�����","����[�-��-�]+","F&gnWPyHe\\1h&tXTQ",[])),
-?line <<"F�����gnWPyHeh�����tXTQ">> = iolist_to_binary(re:replace("�����","����[�-��-�]+","F&gnWPyHe\\1h&tXTQ",[global])),
-?line <<"sHerHnAhAdx">> = iolist_to_binary(re:replace("�����","����[�-��-�]+","sHer\\1HnA\\1h\\1Adx",[])),
-?line <<"sHerHnAhAdx">> = iolist_to_binary(re:replace("�����","����[�-��-�]+","sHer\\1HnA\\1h\\1Adx",[global])),
-?line <<"trobAQoU�����n">> = iolist_to_binary(re:replace("�����","����[�-��-�]+","tr\\1obAQoU&n",[])),
-?line <<"trobAQoU�����n">> = iolist_to_binary(re:replace("�����","����[�-��-�]+","tr\\1obAQoU&n",[global])),
-?line <<"�XAZSd">> = iolist_to_binary(re:replace("�XAZXB","(?<=Z)X.","Sd",[])),
-?line <<"�XAZSd">> = iolist_to_binary(re:replace("�XAZXB","(?<=Z)X.","Sd",[global])),
+?line <<"NREGularsRREGularWEYrVRr">> = iolist_to_binary(re:replace("REGular","(?i)reg(?:ul(?:[aä]|ae)r|ex)","N&\\1sR&WEYrVRr",[])),
+?line <<"NREGularsRREGularWEYrVRr">> = iolist_to_binary(re:replace("REGular","(?i)reg(?:ul(?:[aä]|ae)r|ex)","N&\\1sR&WEYrVRr",[global])),
+?line <<"G">> = iolist_to_binary(re:replace("regulaer","(?i)reg(?:ul(?:[aä]|ae)r|ex)","G",[])),
+?line <<"G">> = iolist_to_binary(re:replace("regulaer","(?i)reg(?:ul(?:[aä]|ae)r|ex)","G",[global])),
+?line <<"PSsXtwlmy">> = iolist_to_binary(re:replace("Regex","(?i)reg(?:ul(?:[aä]|ae)r|ex)","PSsXtwlmy",[])),
+?line <<"PSsXtwlmy">> = iolist_to_binary(re:replace("Regex","(?i)reg(?:ul(?:[aä]|ae)r|ex)","PSsXtwlmy",[global])),
+?line <<"regulärmiYTi">> = iolist_to_binary(re:replace("regulär","(?i)reg(?:ul(?:[aä]|ae)r|ex)","&miYTi\\1\\1",[])),
+?line <<"regulärmiYTi">> = iolist_to_binary(re:replace("regulär","(?i)reg(?:ul(?:[aä]|ae)r|ex)","&miYTi\\1\\1",[global])),
+?line <<"WÅæåäàrxhÅæåäàyUoaLOIegmSA">> = iolist_to_binary(re:replace("Åæåäà","Åæåä[à-ÿÀ-ß]+","W&rxh&yUoaL\\1OIegmS\\1A",[])),
+?line <<"WÅæåäàrxhÅæåäàyUoaLOIegmSA">> = iolist_to_binary(re:replace("Åæåäà","Åæåä[à-ÿÀ-ß]+","W&rxh&yUoaL\\1OIegmS\\1A",[global])),
+?line <<"FÅæåäÿgnWPyHehÅæåäÿtXTQ">> = iolist_to_binary(re:replace("Åæåäÿ","Åæåä[à-ÿÀ-ß]+","F&gnWPyHe\\1h&tXTQ",[])),
+?line <<"FÅæåäÿgnWPyHehÅæåäÿtXTQ">> = iolist_to_binary(re:replace("Åæåäÿ","Åæåä[à-ÿÀ-ß]+","F&gnWPyHe\\1h&tXTQ",[global])),
+?line <<"sHerHnAhAdx">> = iolist_to_binary(re:replace("ÅæåäÀ","Åæåä[à-ÿÀ-ß]+","sHer\\1HnA\\1h\\1Adx",[])),
+?line <<"sHerHnAhAdx">> = iolist_to_binary(re:replace("ÅæåäÀ","Åæåä[à-ÿÀ-ß]+","sHer\\1HnA\\1h\\1Adx",[global])),
+?line <<"trobAQoUÅæåäßn">> = iolist_to_binary(re:replace("Åæåäß","Åæåä[à-ÿÀ-ß]+","tr\\1obAQoU&n",[])),
+?line <<"trobAQoUÅæåäßn">> = iolist_to_binary(re:replace("Åæåäß","Åæåä[à-ÿÀ-ß]+","tr\\1obAQoU&n",[global])),
+?line <<"„XAZSd">> = iolist_to_binary(re:replace("„XAZXB","(?<=Z)X.","Sd",[])),
+?line <<"„XAZSd">> = iolist_to_binary(re:replace("„XAZXB","(?<=Z)X.","Sd",[global])),
?line <<"A">> = iolist_to_binary(re:replace("ab cd defg","ab cd (?x) de fg","\\1A\\1",[])),
?line <<"A">> = iolist_to_binary(re:replace("ab cd defg","ab cd (?x) de fg","\\1A\\1",[global])),
?line <<"fab cddefgLdtKCtPab cddefgxvVUHDah">> = iolist_to_binary(re:replace("ab cddefg","ab cd(?x) de fg","f&LdtKC\\1\\1tP&xvVUHDah",[])),
diff --git a/lib/stdlib/test/re_testoutput1_split_test.erl b/lib/stdlib/test/re_testoutput1_split_test.erl
index e86a04b008..4fc85b95c0 100644
--- a/lib/stdlib/test/re_testoutput1_split_test.erl
+++ b/lib/stdlib/test/re_testoutput1_split_test.erl
@@ -1,7 +1,8 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -524,14 +525,14 @@ run() ->
?line <<"ething">> = iolist_to_binary(join(re:split("ething","^[^]cde]",[{parts,
2}]))),
?line <<"ething">> = iolist_to_binary(join(re:split("ething","^[^]cde]",[]))),
-?line <<"">> = iolist_to_binary(join(re:split("�","^\\�",[trim]))),
-?line <<":">> = iolist_to_binary(join(re:split("�","^\\�",[{parts,
+?line <<"">> = iolist_to_binary(join(re:split("","^\\",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("","^\\",[{parts,
2}]))),
-?line <<":">> = iolist_to_binary(join(re:split("�","^\\�",[]))),
-?line <<"">> = iolist_to_binary(join(re:split("�","^�",[trim]))),
-?line <<":">> = iolist_to_binary(join(re:split("�","^�",[{parts,
+?line <<":">> = iolist_to_binary(join(re:split("","^\\",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("ÿ","^ÿ",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ÿ","^ÿ",[{parts,
2}]))),
-?line <<":">> = iolist_to_binary(join(re:split("�","^�",[]))),
+?line <<":">> = iolist_to_binary(join(re:split("ÿ","^ÿ",[]))),
?line <<"">> = iolist_to_binary(join(re:split("0","^[0-9]+$",[trim]))),
?line <<":">> = iolist_to_binary(join(re:split("0","^[0-9]+$",[{parts,
2}]))),
@@ -22879,14 +22880,14 @@ def","abc$",[]))),
?line <<":abc:">> = iolist_to_binary(join(re:split("abcS","(abc)\\123",[{parts,
2}]))),
?line <<":abc:">> = iolist_to_binary(join(re:split("abcS","(abc)\\123",[]))),
-?line <<":abc">> = iolist_to_binary(join(re:split("abc�","(abc)\\223",[trim]))),
-?line <<":abc:">> = iolist_to_binary(join(re:split("abc�","(abc)\\223",[{parts,
+?line <<":abc">> = iolist_to_binary(join(re:split("abc“","(abc)\\223",[trim]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abc“","(abc)\\223",[{parts,
2}]))),
-?line <<":abc:">> = iolist_to_binary(join(re:split("abc�","(abc)\\223",[]))),
-?line <<":abc">> = iolist_to_binary(join(re:split("abc�","(abc)\\323",[trim]))),
-?line <<":abc:">> = iolist_to_binary(join(re:split("abc�","(abc)\\323",[{parts,
+?line <<":abc:">> = iolist_to_binary(join(re:split("abc“","(abc)\\223",[]))),
+?line <<":abc">> = iolist_to_binary(join(re:split("abcÓ","(abc)\\323",[trim]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abcÓ","(abc)\\323",[{parts,
2}]))),
-?line <<":abc:">> = iolist_to_binary(join(re:split("abc�","(abc)\\323",[]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abcÓ","(abc)\\323",[]))),
?line <<":abc">> = iolist_to_binary(join(re:split("abc@","(abc)\\100",[trim]))),
?line <<":abc:">> = iolist_to_binary(join(re:split("abc@","(abc)\\100",[{parts,
2}]))),
@@ -28929,42 +28930,42 @@ xb","(?!^)x",[multiline]))),
?line <<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","(a+)*b",[{parts,
2}]))),
?line <<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","(a+)*b",[]))),
-?line <<"">> = iolist_to_binary(join(re:split("REGular","(?i)reg(?:ul(?:[a�]|ae)r|ex)",[trim]))),
-?line <<":">> = iolist_to_binary(join(re:split("REGular","(?i)reg(?:ul(?:[a�]|ae)r|ex)",[{parts,
+?line <<"">> = iolist_to_binary(join(re:split("REGular","(?i)reg(?:ul(?:[aä]|ae)r|ex)",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("REGular","(?i)reg(?:ul(?:[aä]|ae)r|ex)",[{parts,
2}]))),
-?line <<":">> = iolist_to_binary(join(re:split("REGular","(?i)reg(?:ul(?:[a�]|ae)r|ex)",[]))),
-?line <<"">> = iolist_to_binary(join(re:split("regulaer","(?i)reg(?:ul(?:[a�]|ae)r|ex)",[trim]))),
-?line <<":">> = iolist_to_binary(join(re:split("regulaer","(?i)reg(?:ul(?:[a�]|ae)r|ex)",[{parts,
+?line <<":">> = iolist_to_binary(join(re:split("REGular","(?i)reg(?:ul(?:[aä]|ae)r|ex)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("regulaer","(?i)reg(?:ul(?:[aä]|ae)r|ex)",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("regulaer","(?i)reg(?:ul(?:[aä]|ae)r|ex)",[{parts,
2}]))),
-?line <<":">> = iolist_to_binary(join(re:split("regulaer","(?i)reg(?:ul(?:[a�]|ae)r|ex)",[]))),
-?line <<"">> = iolist_to_binary(join(re:split("Regex","(?i)reg(?:ul(?:[a�]|ae)r|ex)",[trim]))),
-?line <<":">> = iolist_to_binary(join(re:split("Regex","(?i)reg(?:ul(?:[a�]|ae)r|ex)",[{parts,
+?line <<":">> = iolist_to_binary(join(re:split("regulaer","(?i)reg(?:ul(?:[aä]|ae)r|ex)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("Regex","(?i)reg(?:ul(?:[aä]|ae)r|ex)",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("Regex","(?i)reg(?:ul(?:[aä]|ae)r|ex)",[{parts,
2}]))),
-?line <<":">> = iolist_to_binary(join(re:split("Regex","(?i)reg(?:ul(?:[a�]|ae)r|ex)",[]))),
-?line <<"">> = iolist_to_binary(join(re:split("regul�r","(?i)reg(?:ul(?:[a�]|ae)r|ex)",[trim]))),
-?line <<":">> = iolist_to_binary(join(re:split("regul�r","(?i)reg(?:ul(?:[a�]|ae)r|ex)",[{parts,
+?line <<":">> = iolist_to_binary(join(re:split("Regex","(?i)reg(?:ul(?:[aä]|ae)r|ex)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("regulär","(?i)reg(?:ul(?:[aä]|ae)r|ex)",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("regulär","(?i)reg(?:ul(?:[aä]|ae)r|ex)",[{parts,
2}]))),
-?line <<":">> = iolist_to_binary(join(re:split("regul�r","(?i)reg(?:ul(?:[a�]|ae)r|ex)",[]))),
-?line <<"">> = iolist_to_binary(join(re:split("�����","����[�-��-�]+",[trim]))),
-?line <<":">> = iolist_to_binary(join(re:split("�����","����[�-��-�]+",[{parts,
+?line <<":">> = iolist_to_binary(join(re:split("regulär","(?i)reg(?:ul(?:[aä]|ae)r|ex)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("Åæåäà","Åæåä[à-ÿÀ-ß]+",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("Åæåäà","Åæåä[à-ÿÀ-ß]+",[{parts,
2}]))),
-?line <<":">> = iolist_to_binary(join(re:split("�����","����[�-��-�]+",[]))),
-?line <<"">> = iolist_to_binary(join(re:split("�����","����[�-��-�]+",[trim]))),
-?line <<":">> = iolist_to_binary(join(re:split("�����","����[�-��-�]+",[{parts,
+?line <<":">> = iolist_to_binary(join(re:split("Åæåäà","Åæåä[à-ÿÀ-ß]+",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("Åæåäÿ","Åæåä[à-ÿÀ-ß]+",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("Åæåäÿ","Åæåä[à-ÿÀ-ß]+",[{parts,
2}]))),
-?line <<":">> = iolist_to_binary(join(re:split("�����","����[�-��-�]+",[]))),
-?line <<"">> = iolist_to_binary(join(re:split("�����","����[�-��-�]+",[trim]))),
-?line <<":">> = iolist_to_binary(join(re:split("�����","����[�-��-�]+",[{parts,
+?line <<":">> = iolist_to_binary(join(re:split("Åæåäÿ","Åæåä[à-ÿÀ-ß]+",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("ÅæåäÀ","Åæåä[à-ÿÀ-ß]+",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ÅæåäÀ","Åæåä[à-ÿÀ-ß]+",[{parts,
2}]))),
-?line <<":">> = iolist_to_binary(join(re:split("�����","����[�-��-�]+",[]))),
-?line <<"">> = iolist_to_binary(join(re:split("�����","����[�-��-�]+",[trim]))),
-?line <<":">> = iolist_to_binary(join(re:split("�����","����[�-��-�]+",[{parts,
+?line <<":">> = iolist_to_binary(join(re:split("ÅæåäÀ","Åæåä[à-ÿÀ-ß]+",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("Åæåäß","Åæåä[à-ÿÀ-ß]+",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("Åæåäß","Åæåä[à-ÿÀ-ß]+",[{parts,
2}]))),
-?line <<":">> = iolist_to_binary(join(re:split("�����","����[�-��-�]+",[]))),
-?line <<"�XAZ">> = iolist_to_binary(join(re:split("�XAZXB","(?<=Z)X.",[trim]))),
-?line <<"�XAZ:">> = iolist_to_binary(join(re:split("�XAZXB","(?<=Z)X.",[{parts,
+?line <<":">> = iolist_to_binary(join(re:split("Åæåäß","Åæåä[à-ÿÀ-ß]+",[]))),
+?line <<"„XAZ">> = iolist_to_binary(join(re:split("„XAZXB","(?<=Z)X.",[trim]))),
+?line <<"„XAZ:">> = iolist_to_binary(join(re:split("„XAZXB","(?<=Z)X.",[{parts,
2}]))),
-?line <<"�XAZ:">> = iolist_to_binary(join(re:split("�XAZXB","(?<=Z)X.",[]))),
+?line <<"„XAZ:">> = iolist_to_binary(join(re:split("„XAZXB","(?<=Z)X.",[]))),
?line <<"">> = iolist_to_binary(join(re:split("ab cd defg","ab cd (?x) de fg",[trim]))),
?line <<":">> = iolist_to_binary(join(re:split("ab cd defg","ab cd (?x) de fg",[{parts,
2}]))),
diff --git a/lib/stdlib/test/sets_SUITE.erl b/lib/stdlib/test/sets_SUITE.erl
index f284276bd7..e2bcdd18ce 100644
--- a/lib/stdlib/test/sets_SUITE.erl
+++ b/lib/stdlib/test/sets_SUITE.erl
@@ -35,7 +35,7 @@
-import(lists, [foldl/3,reverse/1]).
init_per_testcase(_Case, Config) ->
- ?line Dog = ?t:timetrap(?t:minutes(5)),
+ Dog = ?t:timetrap(?t:minutes(5)),
[{watchdog,Dog}|Config].
end_per_testcase(_Case, Config) ->
@@ -70,65 +70,65 @@ create(Config) when is_list(Config) ->
test_all(fun create_1/1).
create_1(M) ->
- ?line S0 = M:empty(),
- ?line [] = M:to_list(S0),
- ?line 0 = M:size(S0),
- ?line true = M:is_empty(S0),
+ S0 = M(empty, []),
+ [] = M(to_list, S0),
+ 0 = M(size, S0),
+ true = M(is_empty, S0),
E = make_ref(),
- ?line One = M:singleton(E),
- ?line 1 = M:size(One),
- ?line false = M:is_empty(One),
- [E] = M:to_list(One),
+ One = M(singleton, E),
+ 1 = M(size, One),
+ false = M(is_empty, One),
+ [E] = M(to_list, One),
S0.
add_element(Config) when is_list(Config) ->
test_all([{0,132},{253,258},{510,514}], fun add_element_1/2).
add_element_1(List, M) ->
- ?line S = M:from_list(List),
- ?line SortedSet = lists:usort(List),
- ?line SortedSet = lists:sort(M:to_list(S)),
+ S = M(from_list, List),
+ SortedSet = lists:usort(List),
+ SortedSet = lists:sort(M(to_list, S)),
%% Make sure that we get the same result by inserting
%% elements one at the time.
- ?line S2 = foldl(fun(El, Set) -> M:add_element(El, Set) end,
- M:empty(), List),
- ?line true = M:equal(S, S2),
+ S2 = foldl(fun(El, Set) -> M(add_element, {El,Set}) end,
+ M(empty, []), List),
+ true = M(equal, {S,S2}),
%% Insert elements, randomly delete inserted elements,
%% and re-inserted all deleted elements at the end.
- ?line S3 = add_element_del(List, M, M:empty(), [], []),
- ?line true = M:equal(S2, S3),
- ?line true = M:equal(S, S3),
+ S3 = add_element_del(List, M, M(empty, []), [], []),
+ true = M(equal, {S2,S3}),
+ true = M(equal, {S,S3}),
S.
add_element_del([H|T], M, S, Del, []) ->
- add_element_del(T, M, M:add_element(H, S), Del, [H]);
+ add_element_del(T, M, M(add_element, {H,S}), Del, [H]);
add_element_del([H|T], M, S0, Del, Inserted) ->
- S1 = M:add_element(H, S0),
+ S1 = M(add_element, {H,S0}),
case random:uniform(3) of
1 ->
OldEl = lists:nth(random:uniform(length(Inserted)), Inserted),
- S = M:del_element(OldEl, S1),
+ S = M(del_element, {OldEl,S1}),
add_element_del(T, M, S, [OldEl|Del], [H|Inserted]);
_ ->
add_element_del(T, M, S1, Del, [H|Inserted])
end;
add_element_del([], M, S, Del, _) ->
- M:union(S, M:from_list(Del)).
+ M(union, {S,M(from_list, Del)}).
del_element(Config) when is_list(Config) ->
test_all([{0,132},{253,258},{510,514},{1022,1026}], fun del_element_1/2).
del_element_1(List, M) ->
- ?line S0 = M:from_list(List),
- ?line Empty = foldl(fun(El, Set) -> M:del_element(El, Set) end, S0, List),
- ?line Empty = M:empty(),
- ?line M:is_empty(Empty),
- ?line S1 = foldl(fun(El, Set) ->
- M:add_element(El, Set)
- end, S0, reverse(List)),
- ?line true = M:equal(S0, S1),
+ S0 = M(from_list, List),
+ Empty = foldl(fun(El, Set) -> M(del_element, {El,Set}) end, S0, List),
+ Empty = M(empty, []),
+ true = M(is_empty, Empty),
+ S1 = foldl(fun(El, Set) ->
+ M(add_element, {El,Set})
+ end, S0, reverse(List)),
+ true = M(equal, {S0,S1}),
S1.
subtract(Config) when is_list(Config) ->
@@ -138,23 +138,23 @@ subtract(Config) when is_list(Config) ->
test_all([{2,69},{126,130},{253,258},511,512,{1023,1030}], fun subtract_1/2).
subtract_empty(M) ->
- ?line Empty = M:empty(),
- ?line true = M:is_empty(M:subtract(Empty, Empty)),
- M:subtract(Empty, Empty).
+ Empty = M(empty, []),
+ true = M(is_empty, M(subtract, {Empty,Empty})),
+ M(subtract, {Empty,Empty}).
subtract_1(List, M) ->
- ?line S0 = M:from_list(List),
- ?line Empty = M:empty(),
+ S0 = M(from_list, List),
+ Empty = M(empty, []),
%% Trivial cases.
- ?line true = M:is_empty(M:subtract(Empty, S0)),
- ?line true = M:equal(S0, M:subtract(S0, Empty)),
+ true = M(is_empty, M(subtract, {Empty,S0})),
+ true = M(equal, {S0,M(subtract, {S0,Empty})}),
%% Not so trivial.
- ?line subtract_check(List, mutate_some(remove_some(List, 0.4)), M),
- ?line subtract_check(List, rnd_list(length(List) div 2 + 5), M),
- ?line subtract_check(List, rnd_list(length(List) div 7 + 9), M),
- ?line subtract_check(List, mutate_some(List), M).
+ subtract_check(List, mutate_some(remove_some(List, 0.4)), M),
+ subtract_check(List, rnd_list(length(List) div 2 + 5), M),
+ subtract_check(List, rnd_list(length(List) div 7 + 9), M),
+ subtract_check(List, mutate_some(List), M).
subtract_check(A, B, M) ->
one_subtract_check(B, A, M),
@@ -163,12 +163,12 @@ subtract_check(A, B, M) ->
one_subtract_check(A, B, M) ->
ASorted = lists:usort(A),
BSorted = lists:usort(B),
- ASet = M:from_list(A),
- BSet = M:from_list(B),
- DiffSet = M:subtract(ASet, BSet),
+ ASet = M(from_list, A),
+ BSet = M(from_list, B),
+ DiffSet = M(subtract, {ASet,BSet}),
Diff = ASorted -- BSorted,
- true = M:equal(DiffSet, M:from_list(Diff)),
- Diff = lists:sort(M:to_list(DiffSet)),
+ true = M(equal, {DiffSet,M(from_list, Diff)}),
+ Diff = lists:sort(M(to_list, DiffSet)),
DiffSet.
intersection(Config) when is_list(Config) ->
@@ -176,60 +176,60 @@ intersection(Config) when is_list(Config) ->
test_all([{1,65},{126,130},{253,259},{499,513},{1023,1025}], fun intersection_1/2).
intersection_1(List, M) ->
- ?line S0 = M:from_list(List),
+ S0 = M(from_list, List),
%% Intersection with self.
- ?line true = M:equal(S0, M:intersection(S0, S0)),
- ?line true = M:equal(S0, M:intersection([S0,S0])),
- ?line true = M:equal(S0, M:intersection([S0,S0,S0])),
- ?line true = M:equal(S0, M:intersection([S0])),
+ true = M(equal, {S0,M(intersection, {S0,S0})}),
+ true = M(equal, {S0,M(intersection, [S0,S0])}),
+ true = M(equal, {S0,M(intersection, [S0,S0,S0])}),
+ true = M(equal, {S0,M(intersection, [S0])}),
%% Intersection with empty.
- ?line Empty = M:empty(),
- ?line true = M:equal(Empty, M:intersection(S0, Empty)),
- ?line true = M:equal(Empty, M:intersection([S0,Empty,S0,Empty])),
+ Empty = M(empty, []),
+ true = M(equal, {Empty,M(intersection, {S0,Empty})}),
+ true = M(equal, {Empty,M(intersection, [S0,Empty,S0,Empty])}),
%% The intersection of no sets is undefined.
- ?line {'EXIT',_} = (catch M:intersection([])),
+ {'EXIT',_} = (catch M(intersection, [])),
%% Disjoint sets.
- ?line Disjoint = [{El} || El <- List],
- ?line DisjointSet = M:from_list(Disjoint),
- ?line M:is_empty(M:intersection(S0, DisjointSet)),
+ Disjoint = [{El} || El <- List],
+ DisjointSet = M(from_list, Disjoint),
+ true = M(is_empty, M(intersection, {S0,DisjointSet})),
%% Disjoint, different sizes.
- ?line M:is_empty(M:intersection(S0, M:from_list(remove_some(Disjoint, 0.3)))),
- ?line M:is_empty(M:intersection(S0, M:from_list(remove_some(Disjoint, 0.7)))),
- ?line M:is_empty(M:intersection(S0, M:from_list(remove_some(Disjoint, 0.9)))),
- ?line M:is_empty(M:intersection(M:from_list(remove_some(List, 0.3)), DisjointSet)),
- ?line M:is_empty(M:intersection(M:from_list(remove_some(List, 0.5)), DisjointSet)),
- ?line M:is_empty(M:intersection(M:from_list(remove_some(List, 0.9)), DisjointSet)),
+ [begin
+ SomeRemoved = M(from_list, remove_some(Disjoint, HowMuch)),
+ true = M(is_empty, M(intersection, {S0,SomeRemoved})),
+ MoreRemoved = M(from_list, remove_some(List, HowMuch)),
+ true = M(is_empty, M(intersection, {MoreRemoved,DisjointSet}))
+ end || HowMuch <- [0.3,0.5,0.7,0.9]],
%% Partial overlap (one or more elements in result set).
%% The sets have almost the same size. (Almost because a duplicated
%% element in the original list could be mutated and not mutated
%% at the same time.)
- ?line PartialOverlap = mutate_some(List, []),
- ?line IntersectionSet = check_intersection(List, PartialOverlap, M),
- ?line false = M:is_empty(IntersectionSet),
+ PartialOverlap = mutate_some(List, []),
+ IntersectionSet = check_intersection(List, PartialOverlap, M),
+ false = M(is_empty, IntersectionSet),
%% Partial overlap, different set sizes. (Intersection possibly empty.)
- ?line check_intersection(List, remove_some(PartialOverlap, 0.1), M),
- ?line check_intersection(List, remove_some(PartialOverlap, 0.3), M),
- ?line check_intersection(List, remove_some(PartialOverlap, 0.5), M),
- ?line check_intersection(List, remove_some(PartialOverlap, 0.7), M),
- ?line check_intersection(List, remove_some(PartialOverlap, 0.9), M),
+ check_intersection(List, remove_some(PartialOverlap, 0.1), M),
+ check_intersection(List, remove_some(PartialOverlap, 0.3), M),
+ check_intersection(List, remove_some(PartialOverlap, 0.5), M),
+ check_intersection(List, remove_some(PartialOverlap, 0.7), M),
+ check_intersection(List, remove_some(PartialOverlap, 0.9), M),
IntersectionSet.
check_intersection(Orig, Mutated, M) ->
- OrigSet = M:from_list(Orig),
- MutatedSet = M:from_list(Mutated),
+ OrigSet = M(from_list, Orig),
+ MutatedSet = M(from_list, Mutated),
Intersection = [El || El <- Mutated, not is_tuple(El)],
SortedIntersection = lists:usort(Intersection),
- IntersectionSet = M:intersection(OrigSet, MutatedSet),
- true = M:equal(IntersectionSet, M:from_list(SortedIntersection)),
- SortedIntersection = lists:sort(M:to_list(IntersectionSet)),
+ IntersectionSet = M(intersection, {OrigSet,MutatedSet}),
+ true = M(equal, {IntersectionSet,M(from_list, SortedIntersection)}),
+ SortedIntersection = lists:sort(M(to_list, IntersectionSet)),
IntersectionSet.
@@ -239,63 +239,63 @@ union(Config) when is_list(Config) ->
test_all([{1,71},{125,129},{254,259},{510,513},{1023,1025}], fun union_1/2).
union_1(List, M) ->
- ?line S = M:from_list(List),
+ S = M(from_list, List),
%% Union with self and empty.
- ?line Empty = M:empty(),
- ?line true = M:equal(S, M:union(S, S)),
- ?line true = M:equal(S, M:union([S,S])),
- ?line true = M:equal(S, M:union([S,S,Empty])),
- ?line true = M:equal(S, M:union([S,Empty,S])),
- ?line true = M:equal(S, M:union(S, Empty)),
- ?line true = M:equal(S, M:union([S])),
- ?line true = M:is_empty(M:union([])),
+ Empty = M(empty, []),
+ true = M(equal, {S,M(union, {S,S})}),
+ true = M(equal, {S,M(union, [S,S])}),
+ true = M(equal, {S,M(union, [S,S,Empty])}),
+ true = M(equal, {S,M(union, [S,Empty,S])}),
+ true = M(equal, {S,M(union, {S,Empty})}),
+ true = M(equal, {S,M(union, [S])}),
+ true = M(is_empty, M(union, [])),
%% Partial overlap.
- ?line check_union(List, remove_some(mutate_some(List), 0.9), M),
- ?line check_union(List, remove_some(mutate_some(List), 0.7), M),
- ?line check_union(List, remove_some(mutate_some(List), 0.5), M),
- ?line check_union(List, remove_some(mutate_some(List), 0.3), M),
- ?line check_union(List, remove_some(mutate_some(List), 0.1), M),
-
- ?line check_union(List, mutate_some(remove_some(List, 0.9)), M),
- ?line check_union(List, mutate_some(remove_some(List, 0.7)), M),
- ?line check_union(List, mutate_some(remove_some(List, 0.5)), M),
- ?line check_union(List, mutate_some(remove_some(List, 0.3)), M),
- ?line check_union(List, mutate_some(remove_some(List, 0.1)), M).
+ check_union(List, remove_some(mutate_some(List), 0.9), M),
+ check_union(List, remove_some(mutate_some(List), 0.7), M),
+ check_union(List, remove_some(mutate_some(List), 0.5), M),
+ check_union(List, remove_some(mutate_some(List), 0.3), M),
+ check_union(List, remove_some(mutate_some(List), 0.1), M),
+
+ check_union(List, mutate_some(remove_some(List, 0.9)), M),
+ check_union(List, mutate_some(remove_some(List, 0.7)), M),
+ check_union(List, mutate_some(remove_some(List, 0.5)), M),
+ check_union(List, mutate_some(remove_some(List, 0.3)), M),
+ check_union(List, mutate_some(remove_some(List, 0.1)), M).
check_union(Orig, Other, M) ->
- OrigSet = M:from_list(Orig),
- OtherSet = M:from_list(Other),
+ OrigSet = M(from_list, Orig),
+ OtherSet = M(from_list, Other),
Union = Orig++Other,
SortedUnion = lists:usort(Union),
- UnionSet = M:union(OrigSet, OtherSet),
- SortedUnion = lists:sort(M:to_list(UnionSet)),
- M:equal(UnionSet, M:from_list(Union)),
+ UnionSet = M(union, {OrigSet,OtherSet}),
+ SortedUnion = lists:sort(M(to_list, UnionSet)),
+ M(equal, {UnionSet,M(from_list, Union)}),
UnionSet.
is_subset(Config) when is_list(Config) ->
test_all([{1,132},{253,270},{299,311}], fun is_subset_1/2).
is_subset_1(List, M) ->
- ?line S = M:from_list(List),
- ?line Empty = M:empty(),
+ S = M(from_list, List),
+ Empty = M(empty, []),
%% Subset of empty and self.
- ?line true = M:is_subset(Empty, Empty),
- ?line true = M:is_subset(Empty, S),
- ?line false = M:is_subset(S, Empty),
- ?line true = M:is_subset(S, S),
+ true = M(is_subset, {Empty,Empty}),
+ true = M(is_subset, {Empty,S}),
+ false = M(is_subset, {S,Empty}),
+ true = M(is_subset, {S,S}),
%% Other cases.
- Res = [?line false = M:is_subset(M:singleton(make_ref()), S),
- ?line true = M:is_subset(M:singleton(hd(List)), S),
- ?line true = check_subset(remove_some(List, 0.1), List, M),
- ?line true = check_subset(remove_some(List, 0.5), List, M),
- ?line true = check_subset(remove_some(List, 0.9), List, M),
- ?line check_subset(mutate_some(List), List, M),
- ?line check_subset(rnd_list(length(List) div 2 + 5), List, M),
- ?line subtract_check(List, rnd_list(length(List) div 7 + 9), M)
+ Res = [false = M(is_subset, {M(singleton, make_ref()),S}),
+ true = M(is_subset, {M(singleton, hd(List)),S}),
+ true = check_subset(remove_some(List, 0.1), List, M),
+ true = check_subset(remove_some(List, 0.5), List, M),
+ true = check_subset(remove_some(List, 0.9), List, M),
+ check_subset(mutate_some(List), List, M),
+ check_subset(rnd_list(length(List) div 2 + 5), List, M),
+ subtract_check(List, rnd_list(length(List) div 7 + 9), M)
],
res_to_set(Res, M, 0, []).
@@ -304,12 +304,12 @@ check_subset(X, Y, M) ->
check_one_subset(X, Y, M).
check_one_subset(X, Y, M) ->
- XSet = M:from_list(X),
- YSet = M:from_list(Y),
+ XSet = M(from_list, X),
+ YSet = M(from_list, Y),
SortedX = lists:usort(X),
SortedY = lists:usort(Y),
IsSubSet = length(SortedY--SortedX) =:= length(SortedY) - length(SortedX),
- IsSubSet = M:is_subset(XSet, YSet),
+ IsSubSet = M(is_subset, {XSet,YSet}),
IsSubSet.
%% Encode all test results as a set to return.
@@ -317,54 +317,54 @@ res_to_set([true|T], M, I, Acc) ->
res_to_set(T, M, I+1, [I|Acc]);
res_to_set([_|T], M, I, Acc) ->
res_to_set(T, M, I+1, Acc);
-res_to_set([], M, _, Acc) -> M:from_list(Acc).
+res_to_set([], M, _, Acc) -> M(from_list, Acc).
is_set(Config) when is_list(Config) ->
%% is_set/1 is tested in the other test cases when its argument
%% is a set. Here test some arguments that makes it return false.
- ?line false = gb_sets:is_set([a,b]),
- ?line false = gb_sets:is_set({a,very,bad,tuple}),
+ false = gb_sets:is_set([a,b]),
+ false = gb_sets:is_set({a,very,bad,tuple}),
- ?line false = sets:is_set([a,b]),
- ?line false = sets:is_set({a,very,bad,tuple}),
+ false = sets:is_set([a,b]),
+ false = sets:is_set({a,very,bad,tuple}),
- ?line false = ordsets:is_set([b,a]),
- ?line false = ordsets:is_set({bad,tuple}),
+ false = ordsets:is_set([b,a]),
+ false = ordsets:is_set({bad,tuple}),
%% Now test values that are known to be bad for all set representations.
test_all(fun is_set_1/1).
is_set_1(M) ->
- ?line false = M:is_set(self()),
- ?line false = M:is_set(blurf),
- ?line false = M:is_set(make_ref()),
- ?line false = M:is_set(<<1,2,3>>),
- ?line false = M:is_set(42),
- ?line false = M:is_set(math:pi()),
- ?line false = M:is_set({}),
- M:empty().
+ false = M(is_set, self()),
+ false = M(is_set, blurf),
+ false = M(is_set, make_ref()),
+ false = M(is_set, <<1,2,3>>),
+ false = M(is_set, 42),
+ false = M(is_set, math:pi()),
+ false = M(is_set, {}),
+ M(empty, []).
fold(Config) when is_list(Config) ->
test_all([{0,71},{125,129},{254,259},{510,513},{1023,1025},{9999,10001}],
fun fold_1/2).
fold_1(List, M) ->
- ?line S = M:from_list(List),
- ?line L = M:fold(fun(E, A) -> [E|A] end, [], S),
- ?line true = lists:sort(L) =:= lists:usort(List),
- M:empty().
+ S = M(from_list, List),
+ L = M(fold, {fun(E, A) -> [E|A] end,[],S}),
+ true = lists:sort(L) =:= lists:usort(List),
+ M(empty, []).
filter(Config) when is_list(Config) ->
test_all([{0,69},{126,130},{254,259},{510,513},{1023,1025},{7999,8000}],
fun filter_1/2).
filter_1(List, M) ->
- ?line S = M:from_list(List),
+ S = M(from_list, List),
IsNumber = fun(X) -> is_number(X) end,
- ?line M:equal(M:from_list(lists:filter(IsNumber, List)),
- M:filter(IsNumber, S)),
- ?line M:filter(fun(X) -> is_atom(X) end, S).
+ M(equal, {M(from_list, lists:filter(IsNumber, List)),
+ M(filter, {IsNumber,S})}),
+ M(filter, {fun(X) -> is_atom(X) end,S}).
%%%
%%% Test specifics for gb_sets.
@@ -375,26 +375,26 @@ take_smallest(Config) when is_list(Config) ->
fun take_smallest_1/2).
take_smallest_1(List, M) ->
- case M:module() of
+ case M(module, []) of
gb_sets -> take_smallest_2(List, M);
_ -> ok
end,
- M:empty().
+ M(empty, []).
take_smallest_2(List0, M) ->
- ?line List = lists:usort(List0),
- ?line S = M:from_list(List0),
+ List = lists:usort(List0),
+ S = M(from_list, List0),
take_smallest_3(S, List, M).
take_smallest_3(S0, List0, M) ->
- case M:is_empty(S0) of
+ case M(is_empty, S0) of
true -> ok;
false ->
- ?line Smallest = hd(List0),
- ?line Smallest = gb_sets:smallest(S0),
- ?line {Smallest,S} = gb_sets:take_smallest(S0),
- ?line List = tl(List0),
- ?line true = gb_sets:to_list(S) =:= List,
+ Smallest = hd(List0),
+ Smallest = gb_sets:smallest(S0),
+ {Smallest,S} = gb_sets:take_smallest(S0),
+ List = tl(List0),
+ true = gb_sets:to_list(S) =:= List,
take_smallest_3(S, List, M)
end.
@@ -403,26 +403,26 @@ take_largest(Config) when is_list(Config) ->
fun take_largest_1/2).
take_largest_1(List, M) ->
- case M:module() of
+ case M(module, []) of
gb_sets -> take_largest_2(List, M);
_ -> ok
end,
- M:empty().
+ M(empty, []).
take_largest_2(List0, M) ->
- ?line List = reverse(lists:usort(List0)),
- ?line S = M:from_list(List0),
+ List = reverse(lists:usort(List0)),
+ S = M(from_list, List0),
take_largest_3(S, List, M).
take_largest_3(S0, List0, M) ->
- case M:is_empty(S0) of
+ case M(is_empty, S0) of
true -> ok;
false ->
- ?line Largest = hd(List0),
- ?line Largest = gb_sets:largest(S0),
- ?line {Largest,S} = gb_sets:take_largest(S0),
- ?line List = tl(List0),
- ?line true = gb_sets:to_list(S) =:= reverse(List),
+ Largest = hd(List0),
+ Largest = gb_sets:largest(S0),
+ {Largest,S} = gb_sets:take_largest(S0),
+ List = tl(List0),
+ true = gb_sets:to_list(S) =:= reverse(List),
take_largest_3(S, List, M)
end.
@@ -441,23 +441,23 @@ sets_mods() ->
[Ordsets,Sets,Gb].
test_all(Tester) ->
- ?line Res = [begin
- random:seed(1, 2, 42),
- S = Tester(M),
- {M:size(S),lists:sort(M:to_list(S))}
- end || M <- sets_mods()],
- ?line all_same(Res).
+ Res = [begin
+ random:seed(1, 2, 42),
+ S = Tester(M),
+ {M(size, S),lists:sort(M(to_list, S))}
+ end || M <- sets_mods()],
+ all_same(Res).
test_all([{Low,High}|T], Tester) ->
test_all(lists:seq(Low, High)++T, Tester);
test_all([Sz|T], Tester) when is_integer(Sz) ->
List = rnd_list(Sz),
- ?line Res = [begin
+ Res = [begin
random:seed(19, 2, Sz),
S = Tester(List, M),
- {M:size(S),lists:sort(M:to_list(S))}
+ {M(size, S),lists:sort(M(to_list, S))}
end || M <- sets_mods()],
- ?line all_same(Res),
+ all_same(Res),
test_all(T, Tester);
test_all([], _) -> ok.
diff --git a/lib/stdlib/test/sets_test_lib.erl b/lib/stdlib/test/sets_test_lib.erl
index bdfb0d59d2..fd4ec2bac3 100644
--- a/lib/stdlib/test/sets_test_lib.erl
+++ b/lib/stdlib/test/sets_test_lib.erl
@@ -17,91 +17,89 @@
%% %CopyrightEnd%
%%
--module(sets_test_lib, [Mod,Equal]).
-
--export([module/0,equal/2,empty/0,from_list/1,to_list/1,singleton/1,
- add_element/2,del_element/2,size/1,is_empty/1,is_set/1,
- intersection/1,intersection/2,subtract/2,
- union/1,union/2,is_subset/2,fold/3,filter/2]).
-
-module() ->
- Mod.
-
-equal(X, Y) ->
- Equal(X, Y).
-
-empty() ->
- Mod:new().
-
-from_list(L) ->
- Mod:from_list(L).
-
-to_list(S) ->
- Mod:to_list(S).
+-module(sets_test_lib).
+
+-export([new/2]).
+
+new(Mod, Eq) ->
+ fun (add_element, {El,S}) -> add_element(Mod, El, S);
+ (del_element, {El,S}) -> del_element(Mod, El, S);
+ (empty, []) -> Mod:new();
+ (equal, {S1,S2}) -> Eq(S1, S2);
+ (filter, {F,S}) -> filter(Mod, F, S);
+ (fold, {F,A,S}) -> fold(Mod, F, A, S);
+ (from_list, L) -> Mod:from_list(L);
+ (intersection, {S1,S2}) -> intersection(Mod, Eq, S1, S2);
+ (intersection, Ss) -> intersection(Mod, Eq, Ss);
+ (is_empty, S) -> is_empty(Mod, S);
+ (is_set, S) -> Mod:is_set(S);
+ (is_subset, {S,Set}) -> is_subset(Mod, Eq, S, Set);
+ (module, []) -> Mod;
+ (singleton, E) -> singleton(Mod, E);
+ (size, S) -> Mod:size(S);
+ (subtract, {S1,S2}) -> subtract(Mod, S1, S2);
+ (to_list, S) -> Mod:to_list(S);
+ (union, {S1,S2}) -> union(Mod, Eq, S1, S2);
+ (union, Ss) -> union(Mod, Eq, Ss)
+ end.
-singleton(E) ->
+singleton(Mod, E) ->
case erlang:function_exported(Mod, singleton, 1) of
true -> Mod:singleton(E);
- false -> from_list([E])
+ false -> Mod:from_list([E])
end.
-add_element(El, S0) ->
+add_element(Mod, El, S0) ->
S = Mod:add_element(El, S0),
true = Mod:is_element(El, S),
- false = is_empty(S),
+ false = is_empty(Mod, S),
true = Mod:is_set(S),
S.
-del_element(El, S0) ->
+del_element(Mod, El, S0) ->
S = Mod:del_element(El, S0),
false = Mod:is_element(El, S),
true = Mod:is_set(S),
S.
-size(S) ->
- Mod:size(S).
-
-is_empty(S) ->
+is_empty(Mod, S) ->
true = Mod:is_set(S),
case erlang:function_exported(Mod, is_empty, 1) of
true -> Mod:is_empty(S);
false -> Mod:size(S) == 0
end.
-is_set(S) ->
- Mod:is_set(S).
-
-intersection(S1, S2) ->
+intersection(Mod, Equal, S1, S2) ->
S = Mod:intersection(S1, S2),
true = Equal(S, Mod:intersection(S2, S1)),
- Disjoint = is_empty(S),
+ Disjoint = is_empty(Mod, S),
Disjoint = Mod:is_disjoint(S1, S2),
Disjoint = Mod:is_disjoint(S2, S1),
S.
-intersection(Ss) ->
+intersection(Mod, Equal, Ss) ->
S = Mod:intersection(Ss),
true = Equal(S, Mod:intersection(lists:reverse(Ss))),
S.
-subtract(S1, S2) ->
+subtract(Mod, S1, S2) ->
S = Mod:subtract(S1, S2),
true = Mod:is_set(S),
true = Mod:size(S) =< Mod:size(S1),
S.
-union(S1, S2) ->
+union(Mod, Equal, S1, S2) ->
S = Mod:union(S1, S2),
true = Equal(S, Mod:union(S2, S1)),
true = Mod:is_set(S),
S.
-union(Ss) ->
+union(Mod, Equal, Ss) ->
S = Mod:union(Ss),
true = Equal(S, Mod:union(lists:reverse(Ss))),
S.
-is_subset(S, Set) ->
+is_subset(Mod, Equal, S, Set) ->
case Mod:is_subset(S, Set) of
false -> false;
true ->
@@ -115,10 +113,10 @@ is_subset(S, Set) ->
true
end.
-fold(F, A, S) ->
+fold(Mod, F, A, S) ->
true = Mod:is_set(S),
Mod:fold(F, A, S).
-filter(F, S) ->
+filter(Mod, F, S) ->
true = Mod:is_set(S),
Mod:filter(F, S).
diff --git a/lib/stdlib/test/shell_SUITE.erl b/lib/stdlib/test/shell_SUITE.erl
index d49416c150..f22df96697 100644
--- a/lib/stdlib/test/shell_SUITE.erl
+++ b/lib/stdlib/test/shell_SUITE.erl
@@ -28,8 +28,8 @@
refman_bit_syntax/1,
progex_bit_syntax/1, progex_records/1,
progex_lc/1, progex_funs/1,
- otp_5990/1, otp_6166/1, otp_6554/1, otp_6785/1,
- otp_7184/1, otp_7232/1, otp_8393/1]).
+ otp_5990/1, otp_6166/1, otp_6554/1,
+ otp_7184/1, otp_7232/1, otp_8393/1, otp_10302/1]).
-export([ start_restricted_from_shell/1,
start_restricted_on_command_line/1,restricted_local/1]).
@@ -92,8 +92,8 @@ groups() ->
[progex_bit_syntax, progex_records, progex_lc,
progex_funs]},
{tickets, [],
- [otp_5990, otp_6166, otp_6554, otp_6785, otp_7184,
- otp_7232, otp_8393]}].
+ [otp_5990, otp_6166, otp_6554, otp_7184,
+ otp_7232, otp_8393, otp_10302]}].
init_per_suite(Config) ->
Config.
@@ -108,7 +108,7 @@ end_per_group(_GroupName, Config) ->
Config.
--record(state, {bin, reply, leader}).
+-record(state, {bin, reply, leader, unic = latin1}).
start_restricted_from_shell(doc) ->
@@ -374,15 +374,18 @@ records(Config) when is_list(Config) ->
MS = ?MODULE_STRING,
RR1 = "rr(" ++ MS ++ "). #state{}.",
?line "[state]\n"
- "#state{bin = undefined,reply = undefined,leader = undefined}.\n" =
+ "#state{bin = undefined,reply = undefined,leader = undefined,\n"
+ " unic = latin1}.\n" =
t(RR1),
RR2 = "rr(" ++ MS ++ ",[state]). #state{}.",
?line "[state]\n"
- "#state{bin = undefined,reply = undefined,leader = undefined}.\n" =
+ "#state{bin = undefined,reply = undefined,leader = undefined,\n"
+ " unic = latin1}.\n" =
t(RR2),
RR3 = "rr(" ++ MS ++ ",'_'). #state{}.",
?line "[state]\n"
- "#state{bin = undefined,reply = undefined,leader = undefined}.\n" =
+ "#state{bin = undefined,reply = undefined,leader = undefined,\n"
+ " unic = latin1}.\n" =
t(RR3),
RR4 = "rr(" ++ MS ++ ", '_', {d,test1}).",
?line [[state]] = scan(RR4),
@@ -2540,19 +2543,6 @@ otp_6554(Config) when is_list(Config) ->
ok.
-otp_6785(doc) ->
- "OTP-6785. Parameterized modules.";
-otp_6785(suite) -> [];
-otp_6785(Config) when is_list(Config) ->
- MFile = filename:join(?config(priv_dir, Config), "parameterized.erl"),
- Contents = <<"-module(parameterized, [A]). "
- "-export([test/0]). "
- "test() -> A. ">>,
- ?line ok = compile_file(Config, MFile, Contents, []),
- ?line (parameterized:new(adsf)):test(),
- file:delete(MFile),
- ok.
-
otp_7184(doc) ->
"OTP-7184. Propagate exit signals from dying evaluator process.";
otp_7184(suite) -> [];
@@ -2748,6 +2738,143 @@ prompt_err(B) ->
S = string:strip(S2, both, $"),
string:strip(S, right, $.).
+otp_10302(doc) ->
+ "OTP-10302. Unicode.";
+otp_10302(suite) -> [];
+otp_10302(Config) when is_list(Config) ->
+ Test1 =
+ <<"begin
+ io:setopts([{encoding,utf8}]),
+ [1024] = \"\\x{400}\",
+ rd(rec, {a = \"\\x{400}\"}),
+ ok = rl(rec)
+ end.">>,
+ "-record(rec,{a = \"\x{400}\"}).\nok.\n" = t(Test1),
+
+ Test3 =
+ <<"io:setopts([{encoding,utf8}]).
+ rd(rec, {a = \"\\x{400}\"}).
+ ok = rp(#rec{}).">>,
+ "ok.\nrec\n#rec{a = \"\x{400}\"}.\nok.\n" = t(Test3),
+
+ Test4 =
+ <<"io:setopts([{encoding,utf8}]).
+ A = [1024] = \"\\x{400}\".
+ b().
+ h().">>,
+
+ "ok.\n\"\x{400}\"\nA = \"\x{400}\".\nok.\n"
+ "1: io:setopts([{encoding,utf8}])\n-> ok.\n"
+ "2: A = [1024] = \"\x{400}\"\n-> \"\x{400}\"\n"
+ "3: b()\n-> ok.\nok.\n" = t(Test4),
+
+ Test5 =
+ <<"begin
+ io:setopts([{encoding,utf8}]),
+ results(0),
+ A = [1024] = \"\\x{400}\",
+ b(),
+ h()
+ end.">>,
+ "A = \"\x{400}\".\nok.\n" = t(Test5),
+
+ %% One $" is "lost":
+ true =
+ "\x{400}\": command not found" =:=
+ prompt_err({<<"io:setopts([{encoding,utf8}]). v(\"\x{400}\")."/utf8>>,
+ unicode}),
+
+ "ok.\ndefault\n* Bad prompt function: \"\x{400}\".\n" =
+ t({<<"io:setopts([{encoding,utf8}]). "
+ "shell:prompt_func(\"\x{400}\")."/utf8>>,
+ unicode}),
+ _ = shell:prompt_func(default),
+
+ %% Test lib:format_exception() (cf. OTP-6554)
+ Test6 =
+ <<"begin
+ A = <<\"\\xaa\">>,
+ S = lists:flatten(io_lib:format(\"~p/~p.\", [A, A])),
+ {ok, Ts, _} = erl_scan:string(S, 1, [unicode]),
+ {ok, Es} = erl_parse:parse_exprs(Ts),
+ B = erl_eval:new_bindings(),
+ erl_eval:exprs(Es, B)
+ end.">>,
+
+ "** exception error: an error occurred when evaluating"
+ " an arithmetic expression\n in operator '/'/2\n"
+ " called as <<\"\xaa\">> / <<\"\xaa\">>.\n" = t(Test6),
+ Test7 =
+ <<"io:setopts([{encoding,utf8}]).
+ A = <<\"\\xaa\">>,
+ S = lists:flatten(io_lib:format(\"~p/~p.\", [A, A])),
+ {ok, Ts, _} = erl_scan:string(S, 1, [unicode]),
+ {ok, Es} = erl_parse:parse_exprs(Ts),
+ B = erl_eval:new_bindings(),
+ erl_eval:exprs(Es, B).">>,
+
+ "ok.\n** exception error: an error occurred when evaluating"
+ " an arithmetic expression\n in operator '/'/2\n"
+ " called as <<170>> / <<170>>.\n" = t(Test7),
+ Test8 =
+ <<"begin
+ A = [1089],
+ S = lists:flatten(io_lib:format(\"~tp/~tp.\", [A, A])),
+ {ok, Ts, _} = erl_scan:string(S, 1, [unicode]),
+ {ok, Es} = erl_parse:parse_exprs(Ts),
+ B = erl_eval:new_bindings(),
+ erl_eval:exprs(Es, B)
+ end.">>,
+ "** exception error: an error occurred when evaluating"
+ " an arithmetic expression\n in operator '/'/2\n"
+ " called as [1089] / [1089].\n" = t(Test8),
+ Test9 =
+ <<"io:setopts([{encoding,utf8}]).
+ A = [1089],
+ S = lists:flatten(io_lib:format(\"~tp/~tp.\", [A, A])),
+ {ok, Ts, _} = erl_scan:string(S, 1, [unicode]),
+ {ok, Es} = erl_parse:parse_exprs(Ts),
+ B = erl_eval:new_bindings(),
+ erl_eval:exprs(Es, B).">>,
+
+ "ok.\n** exception error: an error occurred when evaluating"
+ " an arithmetic expression\n in operator '/'/2\n"
+ " called as \"\x{441}\" / \"\x{441}\".\n" = t(Test9),
+ Test10 =
+ <<"A = {\"1\\xaa\",
+ $\\xaa,
+ << <<\"hi\">>/binary >>,
+ <<\"1\xaa\">>},
+ fun(a) -> true end(A).">>,
+ "** exception error: no function clause matching \n"
+ " erl_eval:'-inside-an-interpreted-fun-'"
+ "({\"1\xc2\xaa\",170,<<\"hi\">>,\n "
+ " <<\"1\xc2\xaa\">>}) .\n" = t(Test10),
+ Test11 =
+ <<"io:setopts([{encoding,utf8}]).
+ A = {\"1\\xaa\",
+ $\\xaa,
+ << <<\"hi\">>/binary >>,
+ <<\"1\xaa\">>},
+ fun(a) -> true end(A).">>,
+
+ "ok.\n** exception error: no function clause matching \n"
+ " erl_eval:'-inside-an-interpreted-fun-'"
+ "({\"1\xaa\",170,<<\"hi\">>,\n "
+ " <<\"1\xaa\"/utf8>>}) .\n" = t(Test11),
+ Test12 = <<"fun(a, b) -> false end(65, [1089]).">>,
+ "** exception error: no function clause matching \n"
+ " erl_eval:'-inside-an-interpreted-fun-'(65,[1089])"
+ " .\n" = t(Test12),
+ Test13 =
+ <<"io:setopts([{encoding,utf8}]).
+ fun(a, b) -> false end(65, [1089]).">>,
+ "ok.\n** exception error: no function clause matching \n"
+ " erl_eval:'-inside-an-interpreted-fun-'(65,\"\x{441}\")"
+ " .\n" = t(Test13),
+
+ ok.
+
scan(B) ->
F = fun(Ts) ->
case erl_parse:parse_term(Ts) of
@@ -2761,7 +2888,7 @@ scan(B) ->
scan(t(B), F).
scan(S0, F) ->
- case erl_scan:tokens([], S0, 1) of
+ case erl_scan:tokens([], S0, 1, [unicode]) of
{done,{ok,Ts,_},S} ->
[F(Ts) | scan(S, F)];
_Else ->
@@ -2769,29 +2896,36 @@ scan(S0, F) ->
end.
t({Node,Bin}) when is_atom(Node),is_binary(Bin) ->
- t0(Bin, fun() -> start_new_shell(Node) end);
+ t0({Bin,latin1}, fun() -> start_new_shell(Node) end);
t(Bin) when is_binary(Bin) ->
- t0(Bin, fun() -> start_new_shell() end);
+ t0({Bin,latin1}, fun() -> start_new_shell() end);
+t({Bin,Enc}) when is_binary(Bin), is_atom(Enc) ->
+ t0({Bin,Enc}, fun() -> start_new_shell() end);
t(L) ->
t(list_to_binary(L)).
-t0(Bin, F) ->
+t0({Bin,Enc}, F) ->
%% Spawn a process so that io_request messages do not interfer.
P = self(),
- C = spawn(fun() -> t1(P, Bin, F) end),
+ C = spawn(fun() -> t1(P, {Bin, Enc}, F) end),
receive {C, R} -> R end.
-t1(Parent, Bin, F) ->
- %% io:format("*** Testing ~s~n", [binary_to_list(Bin)]),
- S = #state{bin = Bin, reply = [], leader = group_leader()},
+t1(Parent, {Bin,Enc}, F) ->
+ io:format("*** Testing ~s~n", [binary_to_list(Bin)]),
+ S = #state{bin = Bin, unic = Enc, reply = [], leader = group_leader()},
group_leader(self(), self()),
_Shell = F(),
try
server_loop(S)
catch exit:R -> Parent ! {self(), R};
- throw:{?MODULE,LoopReply} ->
+ throw:{?MODULE,LoopReply,latin1} ->
L0 = binary_to_list(list_to_binary(LoopReply)),
[$\n | L1] = lists:dropwhile(fun(X) -> X =/= $\n end, L0),
+ Parent ! {self(), dotify(L1)};
+ throw:{?MODULE,LoopReply,_Uni} ->
+ Tmp = unicode:characters_to_binary(LoopReply),
+ L0 = unicode:characters_to_list(Tmp),
+ [$\n | L1] = lists:dropwhile(fun(X) -> X =/= $\n end, L0),
Parent ! {self(), dotify(L1)}
after group_leader(S#state.leader, self())
end.
@@ -2835,7 +2969,7 @@ do_io_request(Req, From, S, ReplyAs) ->
case io_requests([Req], [], S) of
{_Status,{eof,_},S1} ->
io_reply(From, ReplyAs, {error,terminated}),
- throw({?MODULE,S1#state.reply});
+ throw({?MODULE,S1#state.reply,S1#state.unic});
{_Status,Reply,S1} ->
io_reply(From, ReplyAs, Reply),
S1
@@ -2858,13 +2992,34 @@ io_requests([], [Rs|Cont], S) ->
io_requests([], [], S) ->
{ok,ok,S}.
+io_request({setopts, Opts}, S) ->
+ #state{unic = OldEnc, bin = Bin} = S,
+ NewEnc = case proplists:get_value(encoding, Opts) of
+ undefined -> OldEnc;
+ utf8 -> unicode;
+ New -> New
+ end,
+ NewBin = case {OldEnc, NewEnc} of
+ {E, E} -> Bin;
+ {latin1, _} ->
+ unicode:characters_to_binary(Bin, latin1, unicode);
+ {_, latin1} ->
+ unicode:characters_to_binary(Bin, unicode, latin1);
+ {_, _} -> Bin
+ end,
+ {ok, ok, S#state{unic = NewEnc, bin = NewBin}};
+io_request(getopts, S) ->
+ {ok,[{encoding,S#state.unic}],S};
io_request({get_geometry,columns}, S) ->
{ok,80,S};
io_request({get_geometry,rows}, S) ->
{ok,24,S};
io_request({put_chars,Chars}, S) ->
{ok,ok,S#state{reply = [S#state.reply | Chars]}};
-io_request({put_chars,_,Chars}, S) ->
+io_request({put_chars,latin1,Chars}, S) ->
+ {ok,ok,S#state{reply = [S#state.reply | Chars]}};
+io_request({put_chars,unicode,Chars0}, S) ->
+ Chars = unicode:characters_to_list(Chars0),
{ok,ok,S#state{reply = [S#state.reply | Chars]}};
io_request({put_chars,Mod,Func,Args}, S) ->
case catch apply(Mod, Func, Args) of
@@ -2890,9 +3045,12 @@ get_until_loop(M, F, As, S, {more,Cont}, Enc) ->
0 ->
get_until_loop(M, F, As, S,
catch apply(M, F, [Cont,eof|As]), Enc);
+ _ when S#state.unic =:= latin1 ->
+ get_until_loop(M, F, As, S#state{bin = <<>>},
+ catch apply(M, F, [Cont,binary_to_list(Bin)|As]), Enc);
_ ->
get_until_loop(M, F, As, S#state{bin = <<>>},
- catch apply(M, F, [Cont,binary_to_list(Bin)|As]), Enc)
+ catch apply(M, F, [Cont,unicode:characters_to_list(Bin)|As]), Enc)
end;
get_until_loop(_M, _F, _As, S, {done,Res,Buf}, Enc) ->
{ok,Res,S#state{bin = buf2bin(Buf, Enc)}};
@@ -2903,6 +3061,8 @@ buf2bin(eof,_) ->
<<>>;
buf2bin(Buf,latin1) ->
list_to_binary(Buf);
+buf2bin(Buf,utf8) ->
+ unicode:characters_to_binary(Buf,unicode,unicode);
buf2bin(Buf,unicode) ->
unicode:characters_to_binary(Buf,unicode,unicode).
diff --git a/lib/stdlib/test/stdlib.cover b/lib/stdlib/test/stdlib.cover
index 61f4f064b9..e71be880cb 100644
--- a/lib/stdlib/test/stdlib.cover
+++ b/lib/stdlib/test/stdlib.cover
@@ -1,17 +1,2 @@
%% -*- erlang -*-
{incl_app,stdlib,details}.
-
-{excl_mods,stdlib,
- [erl_parse,
- erl_eval,
- ets,
- filename,
- gen_event,
- gen_server,
- gen,
- lists,
- io,
- io_lib,
- io_lib_format,
- io_lib_pretty,
- proc_lib]}.
diff --git a/lib/stdlib/test/string_SUITE.erl b/lib/stdlib/test/string_SUITE.erl
index 6969c095a0..96e653985f 100644
--- a/lib/stdlib/test/string_SUITE.erl
+++ b/lib/stdlib/test/string_SUITE.erl
@@ -1,7 +1,8 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -473,8 +474,8 @@ to_upper_to_lower(suite) ->
to_upper_to_lower(doc) ->
[];
to_upper_to_lower(Config) when is_list(Config) ->
- ?line "1234ABCDEF���=" = string:to_upper("1234abcdef���="),
- ?line "����������abc()" = string:to_lower("����������abc()"),
+ ?line "1234ABCDEFÅÄÖ=" = string:to_upper("1234abcdefåäö="),
+ ?line "éèíúùòóåäöabc()" = string:to_lower("ÉÈÍÚÙÒÓÅÄÖabc()"),
?line All = lists:seq(0, 255),
?line UC = string:to_upper(All),
diff --git a/lib/stdlib/test/supervisor_SUITE.erl b/lib/stdlib/test/supervisor_SUITE.erl
index 767ae3d62c..569c66959e 100644
--- a/lib/stdlib/test/supervisor_SUITE.erl
+++ b/lib/stdlib/test/supervisor_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -46,6 +46,7 @@
temporary_normal/1,
permanent_shutdown/1, transient_shutdown/1,
temporary_shutdown/1,
+ faulty_application_shutdown/1,
permanent_abnormal/1, transient_abnormal/1,
temporary_abnormal/1, temporary_bystander/1]).
@@ -98,7 +99,8 @@ groups() ->
{normal_termination, [],
[permanent_normal, transient_normal, temporary_normal]},
{shutdown_termination, [],
- [permanent_shutdown, transient_shutdown, temporary_shutdown]},
+ [permanent_shutdown, transient_shutdown, temporary_shutdown,
+ faulty_application_shutdown]},
{abnormal_termination, [],
[permanent_abnormal, transient_abnormal,
temporary_abnormal]},
@@ -659,6 +661,39 @@ temporary_shutdown(Config) when is_list(Config) ->
[0,0,0,0] = get_child_counts(sup_test).
%%-------------------------------------------------------------------------
+%% Faulty application should shutdown and pass on errors
+faulty_application_shutdown(Config) when is_list(Config) ->
+
+ %% Set some paths
+ AppDir = filename:join(?config(data_dir, Config), "app_faulty"),
+ EbinDir = filename:join(AppDir, "ebin"),
+
+ %% Start faulty app
+ code:add_patha(EbinDir),
+
+ %% {error,
+ %% {{shutdown,
+ %% {failed_to_start_child,
+ %% app_faulty,
+ %% {undef,
+ %% [{an_undefined_module_with,an_undefined_function,[argument1,argument2],
+ %% []},
+ %% {app_faulty_server,init,1,
+ %% [{file,"app_faulty/src/app_faulty_server.erl"},{line,16}]},
+ %% {gen_server,init_it,6,
+ %% [{file,"gen_server.erl"},{line,304}]},
+ %% {proc_lib,init_p_do_apply,3,
+ %% [{file,"proc_lib.erl"},{line,227}]}]}}},
+ %% {app_faulty,start,[normal,[]]}}}
+
+ {error, Error} = application:start(app_faulty),
+ {{shutdown, {failed_to_start_child,app_faulty,{undef, CallStack}}},
+ {app_faulty,start,_}} = Error,
+ [{an_undefined_module_with,an_undefined_function,_,_}|_] = CallStack,
+ ok = application:unload(app_faulty),
+ ok.
+
+%%-------------------------------------------------------------------------
%% A permanent child should always be restarted.
permanent_abnormal(Config) when is_list(Config) ->
{ok, SupPid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
diff --git a/lib/stdlib/test/supervisor_SUITE_data/Makefile.src b/lib/stdlib/test/supervisor_SUITE_data/Makefile.src
new file mode 100644
index 0000000000..dbc5729f47
--- /dev/null
+++ b/lib/stdlib/test/supervisor_SUITE_data/Makefile.src
@@ -0,0 +1,15 @@
+EFLAGS=+debug_info
+
+APP_FAULTY= \
+ app_faulty/ebin/app_faulty_sup.@EMULATOR@ \
+ app_faulty/ebin/app_faulty_server.@EMULATOR@ \
+ app_faulty/ebin/app_faulty.@EMULATOR@ \
+
+all: $(APP_FAULTY)
+
+app_faulty/ebin/app_faulty_server.@EMULATOR@: app_faulty/src/app_faulty_server.erl
+ erlc $(EFLAGS) -oapp_faulty/ebin app_faulty/src/app_faulty_server.erl
+app_faulty/ebin/app_faulty_sup.@EMULATOR@: app_faulty/src/app_faulty_sup.erl
+ erlc $(EFLAGS) -oapp_faulty/ebin app_faulty/src/app_faulty_sup.erl
+app_faulty/ebin/app_faulty.@EMULATOR@: app_faulty/src/app_faulty.erl
+ erlc $(EFLAGS) -oapp_faulty/ebin app_faulty/src/app_faulty.erl
diff --git a/lib/stdlib/test/supervisor_SUITE_data/app_faulty/ebin/app_faulty.app b/lib/stdlib/test/supervisor_SUITE_data/app_faulty/ebin/app_faulty.app
new file mode 100644
index 0000000000..d4ab07e485
--- /dev/null
+++ b/lib/stdlib/test/supervisor_SUITE_data/app_faulty/ebin/app_faulty.app
@@ -0,0 +1,10 @@
+{application, app_faulty,
+ [{description, "very simple example faulty application"},
+ {id, "app_faulty"},
+ {vsn, "1.0"},
+ {modules, [app_faulty, app_faulty_sup, app_faulty_server]},
+ {registered, [app_faulty]},
+ {applications, [kernel, stdlib]},
+ {env, [{var,val1}]},
+ {mod, {app_faulty, []}}
+ ]}.
diff --git a/lib/stdlib/test/supervisor_SUITE_data/app_faulty/src/app_faulty.erl b/lib/stdlib/test/supervisor_SUITE_data/app_faulty/src/app_faulty.erl
new file mode 100644
index 0000000000..c65b411cd6
--- /dev/null
+++ b/lib/stdlib/test/supervisor_SUITE_data/app_faulty/src/app_faulty.erl
@@ -0,0 +1,17 @@
+-module(app_faulty).
+
+-behaviour(application).
+
+%% Application callbacks
+-export([start/2, stop/1]).
+
+start(_Type, _StartArgs) ->
+ case app_faulty_sup:start_link() of
+ {ok, Pid} ->
+ {ok, Pid};
+ Error ->
+ Error
+ end.
+
+stop(_State) ->
+ ok.
diff --git a/lib/stdlib/test/supervisor_SUITE_data/app_faulty/src/app_faulty_server.erl b/lib/stdlib/test/supervisor_SUITE_data/app_faulty/src/app_faulty_server.erl
new file mode 100644
index 0000000000..6628f92210
--- /dev/null
+++ b/lib/stdlib/test/supervisor_SUITE_data/app_faulty/src/app_faulty_server.erl
@@ -0,0 +1,32 @@
+-module(app_faulty_server).
+
+-behaviour(gen_server).
+
+%% API
+-export([start_link/0]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+start_link() ->
+ gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
+
+init([]) ->
+ an_undefined_module_with:an_undefined_function(argument1, argument2),
+ {ok, []}.
+
+handle_call(_Request, _From, State) ->
+ {reply, ok, State}.
+
+handle_cast(_Msg, State) ->
+ {noreply, State}.
+
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
diff --git a/lib/stdlib/test/supervisor_SUITE_data/app_faulty/src/app_faulty_sup.erl b/lib/stdlib/test/supervisor_SUITE_data/app_faulty/src/app_faulty_sup.erl
new file mode 100644
index 0000000000..8115a88809
--- /dev/null
+++ b/lib/stdlib/test/supervisor_SUITE_data/app_faulty/src/app_faulty_sup.erl
@@ -0,0 +1,17 @@
+-module(app_faulty_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/0]).
+
+%% Supervisor callbacks
+-export([init/1]).
+
+start_link() ->
+ supervisor:start_link(?MODULE, []).
+
+init([]) ->
+ AChild = {app_faulty,{app_faulty_server,start_link,[]},
+ permanent,2000,worker,[app_faulty_server]},
+ {ok,{{one_for_all,0,1}, [AChild]}}.
diff --git a/lib/syntax_tools/src/Makefile b/lib/syntax_tools/src/Makefile
index dca5e78be9..2aa6591c77 100644
--- a/lib/syntax_tools/src/Makefile
+++ b/lib/syntax_tools/src/Makefile
@@ -62,17 +62,17 @@ distclean: clean
realclean: clean
$(EBIN)/%.$(EMULATOR):%.erl
- erlc -W $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
+ $(erlc_verbose)erlc -W $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
# ----------------------------------------------------
# Special Build Targets
# ----------------------------------------------------
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
# ----------------------------------------------------
# Release Target
diff --git a/lib/syntax_tools/src/epp_dodger.erl b/lib/syntax_tools/src/epp_dodger.erl
index b3ced34c14..70395848a1 100644
--- a/lib/syntax_tools/src/epp_dodger.erl
+++ b/lib/syntax_tools/src/epp_dodger.erl
@@ -186,6 +186,7 @@ quick_parse_file(File, Options) ->
parse_file(File, Parser, Options) ->
case file:open(File, [read]) of
{ok, Dev} ->
+ _ = epp:set_encoding(Dev),
try Parser(Dev, 1, Options)
after ok = file:close(Dev)
end;
@@ -400,7 +401,7 @@ quick_parse_form(Dev, L0, Options) ->
parse_form(Dev, L0, Parser, Options) ->
NoFail = proplists:get_bool(no_fail, Options),
Opt = #opt{clever = proplists:get_bool(clever, Options)},
- case io:scan_erl_form(Dev, "", L0) of
+ case io:scan_erl_form(Dev, "", L0, [unicode]) of
{ok, Ts, L1} ->
case catch {ok, Parser(Ts, Opt)} of
{'EXIT', Term} ->
@@ -419,6 +420,7 @@ parse_form(Dev, L0, Parser, Options) ->
{ok, F, L1}
end;
{error, _IoErr, _L1} = Err -> Err;
+ {error, _Reason} -> {eof, L0}; % This is probably encoding problem
{eof, _L1} = Eof -> Eof
end.
diff --git a/lib/syntax_tools/src/erl_comment_scan.erl b/lib/syntax_tools/src/erl_comment_scan.erl
index b833e1c069..a70e7ba413 100644
--- a/lib/syntax_tools/src/erl_comment_scan.erl
+++ b/lib/syntax_tools/src/erl_comment_scan.erl
@@ -72,7 +72,17 @@ file(Name) ->
{ok, V} ->
case V of
{ok, B} ->
- string(binary_to_list(B));
+ Enc = case epp:read_encoding(Name) of
+ none -> epp:default_encoding();
+ Enc0 -> Enc0
+ end,
+ case catch unicode:characters_to_list(B, Enc) of
+ String when is_list(String) ->
+ string(String);
+ R ->
+ error_read_file(Name1),
+ exit(R)
+ end;
{error, E} ->
error_read_file(Name1),
exit({read, E})
diff --git a/lib/syntax_tools/src/erl_prettypr.erl b/lib/syntax_tools/src/erl_prettypr.erl
index f4bbf975c3..1a55a5e71c 100644
--- a/lib/syntax_tools/src/erl_prettypr.erl
+++ b/lib/syntax_tools/src/erl_prettypr.erl
@@ -60,7 +60,9 @@
hook = ?NOHOOK :: hook(),
paper = ?PAPER :: integer(),
ribbon = ?RIBBON :: integer(),
- user = ?NOUSER :: term()}).
+ user = ?NOUSER :: term(),
+ encoding = epp:default_encoding() :: epp:source_encoding()}).
+
-type context() :: #ctxt{}.
%% =====================================================================
@@ -231,6 +233,8 @@ format(Node) ->
%% <dt>{user, term()}</dt>
%% <dd>User-specific data for use in hook functions. The default
%% value is `undefined'.</dd>
+%% <dt>{encoding, epp:source_encoding()}</dt>
+%% <dd>Specifies the encoding of the generated file.</dd>
%% </dl>
%%
%% A hook function (cf. the {@link hook()} type) is passed the current
@@ -342,7 +346,9 @@ layout(Node, Options) ->
#ctxt{hook = proplists:get_value(hook, Options, ?NOHOOK),
paper = proplists:get_value(paper, Options, ?PAPER),
ribbon = proplists:get_value(ribbon, Options, ?RIBBON),
- user = proplists:get_value(user, Options)}).
+ user = proplists:get_value(user, Options),
+ encoding = proplists:get_value(encoding, Options,
+ epp:default_encoding())}).
lay(Node, Ctxt) ->
case erl_syntax:get_ann(Node) of
@@ -445,10 +451,10 @@ lay_2(Node, Ctxt) ->
text(tidy_float(erl_syntax:float_literal(Node)));
char ->
- text(erl_syntax:char_literal(Node));
+ text(erl_syntax:char_literal(Node, Ctxt#ctxt.encoding));
string ->
- lay_string(erl_syntax:string_literal(Node), Ctxt);
+ lay_string(erl_syntax:string_literal(Node, Ctxt#ctxt.encoding), Ctxt);
nil ->
text("[]");
@@ -639,10 +645,6 @@ lay_2(Node, Ctxt) ->
set_prec(Ctxt, PrecR)),
beside(D1, beside(text(":"), D2));
- qualified_name ->
- Ss = erl_syntax:qualified_name_segments(Node),
- lay_qualified_name(Ss, Ctxt);
-
%%
%% The rest is in alphabetical order
%%
@@ -966,26 +968,6 @@ maybe_parentheses(D, Prec, Ctxt) ->
D
end.
-lay_qualified_name([S | Ss1] = Ss, Ctxt) ->
- case erl_syntax:type(S) of
- atom ->
- case erl_syntax:atom_value(S) of
- '' ->
- beside(text("."),
- lay_qualified_name_1(Ss1, Ctxt));
- _ ->
- lay_qualified_name_1(Ss, Ctxt)
- end;
- _ ->
- lay_qualified_name_1(Ss, Ctxt)
- end.
-
-lay_qualified_name_1([S], Ctxt) ->
- lay(S, Ctxt);
-lay_qualified_name_1([S | Ss], Ctxt) ->
- beside(lay(S, Ctxt), beside(text("."),
- lay_qualified_name_1(Ss, Ctxt))).
-
lay_string(S, Ctxt) ->
%% S includes leading/trailing double-quote characters. The segment
%% width is 2/3 of the ribbon width - this seems to work well.
diff --git a/lib/syntax_tools/src/erl_syntax.erl b/lib/syntax_tools/src/erl_syntax.erl
index 151f04b03b..f7420030c3 100644
--- a/lib/syntax_tools/src/erl_syntax.erl
+++ b/lib/syntax_tools/src/erl_syntax.erl
@@ -161,6 +161,7 @@
is_char/2,
char_value/1,
char_literal/1,
+ char_literal/2,
clause/2,
clause/3,
clause_body/1,
@@ -234,8 +235,6 @@
prefix_expr/2,
prefix_expr_argument/1,
prefix_expr_operator/1,
- qualified_name/1,
- qualified_name_segments/1,
query_expr/1,
query_expr_body/1,
receive_expr/1,
@@ -271,6 +270,7 @@
is_string/2,
string_value/1,
string_literal/1,
+ string_literal/2,
text/1,
text_string/1,
try_expr/2,
@@ -449,7 +449,6 @@
%% <td>parentheses</td>
%% <td>prefix_expr</td>
%% </tr><tr>
-%% <td>qualified_name</td>
%% <td>query_expr</td>
%% <td>receive_expr</td>
%% <td>record_access</td>
@@ -514,7 +513,6 @@
%% @see operator/1
%% @see parentheses/1
%% @see prefix_expr/2
-%% @see qualified_name/1
%% @see query_expr/1
%% @see receive_expr/3
%% @see record_access/3
@@ -584,11 +582,7 @@ type(Node) ->
{record, _, _, _, _} -> record_expr;
{record, _, _, _} -> record_expr;
{record_field, _, _, _, _} -> record_access;
- {record_field, _, _, _} ->
- case is_qualified_name(Node) of
- true -> qualified_name;
- false -> record_access
- end;
+ {record_field, _, _, _} -> record_access;
{record_index, _, _, _} -> record_index_expr;
{remote, _, _, _} -> module_qualifier;
{rule, _, _, _, _} -> rule;
@@ -1628,6 +1622,7 @@ float_literal(Node) ->
%%
%% @see char_value/1
%% @see char_literal/1
+%% @see char_literal/2
%% @see is_char/2
%% type(Node) = char
@@ -1687,13 +1682,34 @@ char_value(Node) ->
%% =====================================================================
%% @doc Returns the literal string represented by a `char'
%% node. This includes the leading "`$'" character.
+%% Characters beyond 255 will be escaped.
%%
%% @see char/1
-spec char_literal(syntaxTree()) -> nonempty_string().
char_literal(Node) ->
- io_lib:write_char(char_value(Node)).
+ char_literal(Node, latin1).
+
+
+%% =====================================================================
+%% @doc Returns the literal string represented by a `char'
+%% node. This includes the leading "`$'" character.
+%% Depending on the encoding a character beyond 255 will be escaped
+%% ('latin1') or copied as is ('utf8').
+%%
+%% @see char/1
+
+-type encoding() :: 'utf8' | 'unicode' | 'latin1'.
+
+-spec char_literal(syntaxTree(), encoding()) -> nonempty_string().
+
+char_literal(Node, unicode) ->
+ io_lib:write_unicode_char(char_value(Node));
+char_literal(Node, utf8) ->
+ io_lib:write_unicode_char(char_value(Node));
+char_literal(Node, latin1) ->
+ io_lib:write_unicode_char_as_latin1(char_value(Node)).
%% =====================================================================
@@ -1708,6 +1724,7 @@ char_literal(Node) ->
%%
%% @see string_value/1
%% @see string_literal/1
+%% @see string_literal/2
%% @see is_string/2
%% @see char/1
@@ -1768,13 +1785,32 @@ string_value(Node) ->
%% =====================================================================
%% @doc Returns the literal string represented by a `string'
%% node. This includes surrounding double-quote characters.
+%% Characters beyond 255 will be escaped.
%%
%% @see string/1
-spec string_literal(syntaxTree()) -> nonempty_string().
string_literal(Node) ->
- io_lib:write_string(string_value(Node)).
+ string_literal(Node, latin1).
+
+
+%% =====================================================================
+%% @doc Returns the literal string represented by a `string'
+%% node. This includes surrounding double-quote characters.
+%% Depending on the encoding characters beyond 255 will be escaped
+%% ('latin1') or copied as is ('utf8').
+%%
+%% @see string/1
+
+-spec string_literal(syntaxTree(), encoding()) -> nonempty_string().
+
+string_literal(Node, utf8) ->
+ io_lib:write_unicode_string(string_value(Node));
+string_literal(Node, unicode) ->
+ io_lib:write_unicode_string(string_value(Node));
+string_literal(Node, latin1) ->
+ io_lib:write_unicode_string_as_latin1(string_value(Node)).
%% =====================================================================
@@ -3003,9 +3039,6 @@ revert_module_name(A) ->
case type(A) of
atom ->
{ok, concrete(A)};
- qualified_name ->
- Ss = qualified_name_segments(A),
- {ok, [concrete(S) || S <- Ss]};
_ ->
error
end.
@@ -3051,11 +3084,7 @@ attribute_arguments(Node) ->
M0 ->
{M0, none}
end,
- M2 = if is_list(M1) ->
- qualified_name([atom(A) || A <- M1]);
- true ->
- atom(M1)
- end,
+ M2 = atom(M1),
M = set_pos(M2, Pos),
if Vs == none -> [M];
true -> [M, set_pos(list(Vs), Pos)]
@@ -3065,20 +3094,11 @@ attribute_arguments(Node) ->
list(unfold_function_names(Data, Pos)),
Pos)];
import ->
- case Data of
- {Module, Imports} ->
- [if is_list(Module) ->
- qualified_name([atom(A)
- || A <- Module]);
- true ->
- set_pos(atom(Module), Pos)
- end,
- set_pos(
- list(unfold_function_names(Imports, Pos)),
- Pos)];
- _ ->
- [qualified_name([atom(A) || A <- Data])]
- end;
+ {Module, Imports} = Data,
+ [set_pos(atom(Module), Pos),
+ set_pos(
+ list(unfold_function_names(Imports, Pos)),
+ Pos)];
file ->
{File, Line} = Data,
[set_pos(string(File), Pos),
@@ -3210,53 +3230,6 @@ module_qualifier_body(Node) ->
%% =====================================================================
-%% @doc Creates an abstract qualified name. The result represents
-%% "<code><em>S1</em>.<em>S2</em>. ... .<em>Sn</em></code>", if
-%% `Segments' is `[S1, S2, ..., Sn]'.
-%%
-%% @see qualified_name_segments/1
-
-%% type(Node) = qualified_name
-%% data(Node) = [syntaxTree()]
-%%
-%% `erl_parse' representation:
-%%
-%% {record_field, Pos, Node, Node}
-%%
-%% Node = {atom, Pos, Value} | {record_field, Pos, Node, Node}
-%%
-%% Note that if not all leaf subnodes are (abstract) atoms, then Node
-%% represents a Mnemosyne query record field access ('record_access');
-%% see type/1 for details.
-
--spec qualified_name([syntaxTree()]) -> syntaxTree().
-
-qualified_name(Segments) ->
- tree(qualified_name, Segments).
-
-revert_qualified_name(Node) ->
- Pos = get_pos(Node),
- fold_qualified_name(qualified_name_segments(Node), Pos).
-
-
-%% =====================================================================
-%% @doc Returns the list of name segments of a
-%% `qualified_name' node.
-%%
-%% @see qualified_name/1
-
--spec qualified_name_segments(syntaxTree()) -> [syntaxTree()].
-
-qualified_name_segments(Node) ->
- case unwrap(Node) of
- {record_field, _, _, _} = Node1 ->
- unfold_qualified_name(Node1);
- Node1 ->
- data(Node1)
- end.
-
-
-%% =====================================================================
%% @doc Creates an abstract function definition. If `Clauses'
%% is `[C1, ..., Cn]', the result represents
%% "<code><em>Name</em> <em>C1</em>; ...; <em>Name</em>
@@ -6068,8 +6041,6 @@ revert_root(Node) ->
revert_parentheses(Node);
prefix_expr ->
revert_prefix_expr(Node);
- qualified_name ->
- revert_qualified_name(Node);
query_expr ->
revert_query_expr(Node);
receive_expr ->
@@ -6312,8 +6283,6 @@ subtrees(T) ->
prefix_expr ->
[[prefix_expr_operator(T)],
[prefix_expr_argument(T)]];
- qualified_name ->
- [qualified_name_segments(T)];
query_expr ->
[[query_expr_body(T)]];
receive_expr ->
@@ -6444,7 +6413,6 @@ make_tree(match_expr, [[P], [E]]) -> match_expr(P, E);
make_tree(module_qualifier, [[M], [N]]) -> module_qualifier(M, N);
make_tree(parentheses, [[E]]) -> parentheses(E);
make_tree(prefix_expr, [[F], [A]]) -> prefix_expr(F, A);
-make_tree(qualified_name, [S]) -> qualified_name(S);
make_tree(query_expr, [[B]]) -> query_expr(B);
make_tree(receive_expr, [C]) -> receive_expr(C);
make_tree(receive_expr, [C, [E], A]) -> receive_expr(C, E, A);
@@ -6788,32 +6756,6 @@ fold_variable_names(Vs) ->
unfold_variable_names(Vs, Pos) ->
[set_pos(variable(V), Pos) || V <- Vs].
-%% Support functions for qualified names ("foo.bar.baz",
-%% "erl.lang.lists", etc.). The representation overlaps with the weird
-%% "Mnesia query record access" operators. The '.' operator is left
-%% associative, so folding should nest on the left.
-
-is_qualified_name({record_field, _, L, R}) ->
- is_qualified_name(L) andalso is_qualified_name(R);
-is_qualified_name({atom, _, _}) -> true;
-is_qualified_name(_) -> false.
-
-unfold_qualified_name(Node) ->
- lists:reverse(unfold_qualified_name(Node, [])).
-
-unfold_qualified_name({record_field, _, L, R}, Ss) ->
- unfold_qualified_name(R, unfold_qualified_name(L, Ss));
-unfold_qualified_name(S, Ss) -> [S | Ss].
-
-fold_qualified_name([S | Ss], Pos) ->
- fold_qualified_name(Ss, Pos, {atom, Pos, atom_value(S)}).
-
-fold_qualified_name([S | Ss], Pos, Ack) ->
- fold_qualified_name(Ss, Pos, {record_field, Pos, Ack,
- {atom, Pos, atom_value(S)}});
-fold_qualified_name([], _Pos, Ack) ->
- Ack.
-
%% Support functions for transforming lists of record field definitions.
%%
%% There is no unique representation for field definitions in the
diff --git a/lib/syntax_tools/src/erl_syntax_lib.erl b/lib/syntax_tools/src/erl_syntax_lib.erl
index 36cd35f15d..2c94ac776d 100644
--- a/lib/syntax_tools/src/erl_syntax_lib.erl
+++ b/lib/syntax_tools/src/erl_syntax_lib.erl
@@ -2223,11 +2223,6 @@ module_name_to_atom(M) ->
case erl_syntax:type(M) of
atom ->
erl_syntax:atom_value(M);
- qualified_name ->
- list_to_atom(packages:concat(
- [erl_syntax:atom_value(A)
- || A <- erl_syntax:qualified_name_segments(M)])
- );
_ ->
throw(syntax_error)
end.
diff --git a/lib/syntax_tools/src/erl_tidy.erl b/lib/syntax_tools/src/erl_tidy.erl
index 59cf6c0a92..e9a88caff3 100644
--- a/lib/syntax_tools/src/erl_tidy.erl
+++ b/lib/syntax_tools/src/erl_tidy.erl
@@ -375,6 +375,8 @@ write_module(Tree, Name, Opts) ->
end,
filename(filename:join(Dir, Name1))
end,
+ Encoding = [{encoding,Enc} || Enc <- [epp:read_encoding(Name)],
+ Enc =/= none],
case proplists:get_bool(backups, Opts) of
true ->
backup_file(File, Opts);
@@ -382,9 +384,9 @@ write_module(Tree, Name, Opts) ->
ok
end,
Printer = proplists:get_value(printer, Opts),
- FD = open_output_file(File),
+ FD = open_output_file(File, Encoding),
verbose("writing to file `~s'.", [File], Opts),
- V = (catch {ok, output(FD, Printer, Tree, Opts)}),
+ V = (catch {ok, output(FD, Printer, Tree, Opts++Encoding)}),
ok = file:close(FD),
case V of
{ok, _} ->
@@ -432,8 +434,9 @@ file_type(Name, Links) ->
throw(R)
end.
-open_output_file(FName) ->
- case catch file:open(FName, [write]) of
+open_output_file(FName, Options) ->
+io:format("Options ~p~n", [Options]),
+ case catch file:open(FName, [write]++Options) of
{ok, FD} ->
FD;
{error, R} ->
diff --git a/lib/syntax_tools/src/igor.erl b/lib/syntax_tools/src/igor.erl
index 37e561cbbe..8abc3f41cb 100644
--- a/lib/syntax_tools/src/igor.erl
+++ b/lib/syntax_tools/src/igor.erl
@@ -341,10 +341,12 @@ merge(Name, Files) ->
merge(Name, Files, Opts) ->
Opts1 = Opts ++ ?DEFAULT_MERGE_OPTS,
- {Tree, Stubs} = merge_files(Name, Files, Opts1),
+ {Sources, Enc} = merge_files1(Files, Opts1),
+ {Tree, Stubs} = merge_sources(Name, Sources, Opts1),
Dir = proplists:get_value(dir, Opts1, ""),
Filename = proplists:get_value(outfile, Opts1, Name),
- File = write_module(Tree, Filename, Dir, Opts1),
+ Encoding = [{encoding, Enc} || Enc =/= none],
+ File = write_module(Tree, Filename, Dir, Encoding ++ Opts1),
[File | maybe_create_stubs(Stubs, Opts1)].
@@ -459,16 +461,21 @@ merge_files(Name, Files, Options) ->
-spec merge_files(atom(), erl_syntax:forms(), [file:filename()], [option()]) ->
{erl_syntax:syntaxTree(), [stubDescriptor()]}.
-merge_files(_, _Trees, [], _) ->
+merge_files(Name, Trees, Files, Opts) ->
+ {Sources, _Encoding} = merge_files1(Files, Opts),
+ merge_sources(Name, Trees ++ Sources, Opts).
+
+merge_files1([], _) ->
report_error("no files to merge."),
exit(badarg);
-merge_files(Name, Trees, Files, Opts) ->
+merge_files1(Files, Opts) ->
Opts1 = Opts ++ [{includes, ?DEFAULT_INCLUDES},
{macros, ?DEFAULT_MACROS},
{preprocess, false},
comments],
- Sources = [read_module(F, Opts1) || F <- Files],
- merge_sources(Name, Trees ++ Sources, Opts1).
+ SourceEncodings = [read_module(F, Opts1) || F <- Files],
+ {Sources, [Encoding | _]} = lists:unzip(SourceEncodings),
+ {Sources, Encoding}.
%% =====================================================================
@@ -2512,7 +2519,11 @@ rename(Files, Renamings, Opts) ->
lists:flatmap(fun (F) -> rename_file(F, Dict, Opts1) end, Files).
rename_file(File, Dict, Opts) ->
- S = read_module(File, Opts),
+ {S, Enc} = read_module(File, Opts),
+ %% Try to avoid *two* coding: comments:
+ Encoding = [{encoding, Enc} ||
+ Enc =/= none,
+ not proplists:get_bool(comments, Opts)],
M = get_module_info(S),
Name = M#module.name,
Name1 = case dict:find(Name, Dict) of
@@ -2526,10 +2537,10 @@ rename_file(File, Dict, Opts) ->
Opts1 = [no_headers,
{export, [Name]},
{static, [Name]},
- {redirect, dict:to_list(Dict1)}] ++ Opts,
+ {redirect, dict:to_list(Dict1)}] ++ Encoding ++ Opts,
{Tree, Stubs} = merge_sources(Name1, [S], Opts1),
Dir = filename:dirname(filename(File)),
- File1 = write_module(Tree, Name1, Dir, Opts),
+ File1 = write_module(Tree, Name1, Dir, Opts++Encoding),
%% We create the stub file in the same directory as the source file
%% and the target file.
@@ -2648,7 +2659,7 @@ error_text(D, Name) ->
{L, M, E} when is_integer(L), is_atom(M) ->
case catch M:format_error(E) of
S when is_list(S) ->
- io_lib:fwrite("`~w', line ~w: ~s.",
+ io_lib:fwrite("`~w', line ~w: ~ts.",
[Name, L, S]);
_ ->
error_text_1(D, Name)
@@ -2706,7 +2717,17 @@ open_output_file(FName) ->
exit(R)
end.
-%% read_module(Name, Options) -> syntaxTree()
+output_encoding(FD, Opts) ->
+ case proplists:get_value(encoding, Opts) of
+ undefined ->
+ ok = io:setopts(FD, [{encoding, epp:default_encoding()}]);
+ Encoding ->
+ ok = io:setopts(FD, [{encoding, Encoding}]),
+ EncS = epp:encoding_to_string(Encoding),
+ ok = io:fwrite(FD, <<"%% ~s\n">>, [EncS])
+ end.
+
+%% read_module(Name, Options) -> {syntaxTree(), epp:source_encoding()}
%%
%% This also tries to locate the real source file, if "Name" does not
%% point directly to a particular file.
@@ -2729,20 +2750,21 @@ read_module(Name, Options) ->
read_module_1(Name, Options) ->
verbose("reading module `~s'.", [filename(Name)], Options),
- Forms = read_module_2(Name, Options),
+ {Forms, Enc} = read_module_2(Name, Options),
case proplists:get_bool(comments, Options) of
false ->
- Forms;
+ {Forms, Enc};
true ->
Comments = erl_comment_scan:file(Name),
- erl_recomment:recomment_forms(Forms, Comments)
+ {erl_recomment:recomment_forms(Forms, Comments), Enc}
end.
read_module_2(Name, Options) ->
case read_module_3(Name, Options) of
{ok, Forms} ->
check_forms(Forms, Name),
- Forms;
+ Enc = epp:read_encoding(Name),
+ {Forms, Enc};
{error, _} = Error ->
error_read_file(Name),
exit(Error)
@@ -2772,7 +2794,7 @@ check_forms([F | Fs], File) ->
_ ->
"unknown error"
end,
- report_error("in file `~s' at line ~w:\n ~s",
+ report_error("in file `~s' at line ~w:\n ~ts",
[filename(File), erl_syntax:get_pos(F), S]),
exit(error);
_ ->
@@ -2847,6 +2869,7 @@ write_module(Tree, Name, Dir, Opts) ->
end,
Printer = proplists:get_value(printer, Opts),
FD = open_output_file(File),
+ ok = output_encoding(FD, Opts),
verbose("writing to file `~s'.", [File], Opts),
V = (catch {ok, output(FD, Printer, Tree, Opts)}),
ok = file:close(FD),
diff --git a/lib/test_server/doc/src/notes.xml b/lib/test_server/doc/src/notes.xml
index 3b109193a0..6a9add044a 100644
--- a/lib/test_server/doc/src/notes.xml
+++ b/lib/test_server/doc/src/notes.xml
@@ -32,6 +32,47 @@
<file>notes.xml</file>
</header>
+<section><title>Test_Server 3.5.3</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ test_server_h will now recognize info_reports written by
+ ct connection handlers (according to the description in
+ cth_conn_log) and ignore them as they will be completely
+ handled by by ct_conn_log_h.</p>
+ <p>
+ Earlier test_server_h would print a tag (testcase name)
+ before forwarding the report to error_logger_tty_h. This
+ would cause lots of tags in the log with no info report
+ following (since error_logger_tty_h did not handle them).</p>
+ <p>
+ Own Id: OTP-10571</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Known Bugs and Problems</title>
+ <list>
+ <item>
+ <p>
+ Restore Config data if lost when test case fails.</p>
+ <p>
+ Own Id: OTP-10070 Aux Id: kunagi-175 [86] </p>
+ </item>
+ <item>
+ <p>
+ IO server error in test_server.</p>
+ <p>
+ Own Id: OTP-10125 Aux Id: OTP-10101, kunagi-177 [88] </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Test_Server 3.5.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/test_server/doc/src/test_server.xml b/lib/test_server/doc/src/test_server.xml
index 5bfa42c36f..841cbfbe91 100644
--- a/lib/test_server/doc/src/test_server.xml
+++ b/lib/test_server/doc/src/test_server.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2007</year>
- <year>2011</year>
+ <year>2012</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -529,6 +529,18 @@ Only valid for peer nodes. Note that slave nodes always
analogy with <c>os:getenv/1</c>), which removes the
environment variable. Only valid for peer nodes. Not
available on VxWorks.</item>
+ <tag><c>{start_cover, false}</c></tag>
+ <item>By default the test server will start cover on all nodes
+ when the test is run with code coverage analysis. To make
+ sure cover is not started on a new node, set this option to
+ <c>false</c>. This can be necessary if the connection to
+ the node at some point will be broken but the node is
+ expected to stay alive. The reason is that a remote cover
+ node can not continue to run without its main node. Another
+ solution would be to explicitly stop cover on the node
+ before breaking the connection, but in some situations (if
+ old code resides in one or more processes) this is not
+ possible.</item>
</taglist>
</desc>
</func>
diff --git a/lib/test_server/doc/src/test_server_ctrl.xml b/lib/test_server/doc/src/test_server_ctrl.xml
index 41bc0bcc75..af96f1fe7e 100644
--- a/lib/test_server/doc/src/test_server_ctrl.xml
+++ b/lib/test_server/doc/src/test_server_ctrl.xml
@@ -427,11 +427,21 @@ Optional, if not given the test server controller node
<p>A <c>CoverFile</c> can have the following entries:</p>
<code type="none">
{exclude, all | ExcludeModuleList}.
-{include, IncludeModuleList}. </code>
+{include, IncludeModuleList}.
+{cross, CrossCoverInfo}.</code>
<p>Note that each line must end with a full
stop. <c>ExcludeModuleList</c> and <c>IncludeModuleList</c>
are lists of atoms, where each atom is a module name.
</p>
+
+ <p><c>CrossCoverInfo</c> is used when collecting cover data
+ over multiple tests. Modules listed here are compiled, but
+ they will not be analysed when the test is finished. See
+ <seealso
+ marker="#cross_cover_analyse-2">cross_cover_analyse/2</seealso>
+ for more information about the cross cover mechanism and the
+ format of <c>CrossCoverInfo</c>.
+ </p>
<p>If both an <c>Application</c> and a <c>CoverFile</c> is
given, all modules in the application are cover compiled,
except for the modules listed in <c>ExcludeModuleList</c>. The
@@ -467,30 +477,71 @@ Optional, if not given the test server controller node
</desc>
</func>
<func>
- <name>cross_cover_analyse(Level) -> ok</name>
- <fsummary>Analyse cover data collected from all tests</fsummary>
+ <name>cross_cover_analyse(Level, Tests) -> ok</name>
+ <fsummary>Analyse cover data collected from multiple tests</fsummary>
<type>
<v>Level = details | overview</v>
+ <v>Tests = [{Tag,LogDir}]</v>
+ <v>Tag = atom()</v>
+ <d>Test identifier.</d>
+ <v>LogDir = string()</v>
+ <d>Log directory for the test identified by <c>Tag</c>. This
+ can either be the <c>run.&lt;timestamp&gt;</c> directory or
+ the parent directory of this (in which case the latest
+ <c>run.&lt;timestamp&gt;</c> directory is chosen.</d>
</type>
<desc>
- <p>Analyse cover data collected from all tests. The modules
- analysed are the ones listed in the cross cover file
- <c>cross.cover</c> in the current directory of the test
- server.</p>
- <p>The modules listed in the <c>cross.cover</c> file are
- modules that are heavily used by other applications than the
- one they belong to. This function should be run after all
- tests are completed, and the result will be stored in a file
- called cross_cover.html in the run.&lt;timestamp&gt;
- directory of the application the modules belong to.
- </p>
- <p>The <c>cross.cover</c> file contains elements like this:</p>
- <pre>
-{App,Modules}. </pre>
- <p>where <c>App</c> can be an application name or the atom
- <c>all</c>. The application (or all applications) will cover
- compile the listed <c>Modules</c>.
- </p>
+ <p>Analyse cover data collected from multiple tests. The modules
+ analysed are the ones listed in <c>cross</c> statements in
+ the cover files. These are modules that are heavily used by
+ other tests than the one where they belong or are explicitly
+ tested. They should then be listed as cross modules in the
+ cover file for the test where they are used but do not
+ belong. Se example below.</p>
+ <p>This function should be run after all tests are completed,
+ and the result will be stored in a file called
+ <c>cross_cover.html</c> in the <c>run.&lt;timestamp&gt;</c>
+ directory of the test the modules belong to.</p>
+ <p>Note that the function can be executed on any node, and it
+ does not require <c>test_server_ctrl</c> to be started first.</p>
+ <p>The <c>cross</c> statement in the cover file must be like this:</p>
+ <code type="none">
+{cross,[{Tag,Modules}]}.</code>
+ <p>where <c>Tag</c> is the same as <c>Tag</c> in the
+ <c>Tests</c> parameter to this function and <c>Modules</c> is a
+ list of module names (atoms).</p>
+ <p><em>Example:</em></p>
+ <p>If the module <c>m1</c> belongs to system <c>s1</c> but is
+ heavily used also in the tests for another system <c>s2</c>,
+ then the cover files for the two systems' tests could be like
+ this:</p>
+<code type="none">
+s1.cover:
+ {include,[m1]}.
+
+s2.cover:
+ {include,[....]}. % modules belonging to system s2
+ {cross,[{s1,[m1]}]}.</code>
+ <p>When the tests for both <c>s1</c> and <c>s2</c> are completed, run</p>
+<code type="none">
+test_server_ctrl:cross_cover_analyse(Level,[{s1,S1LogDir},{s2,S2LogDir}])
+</code>
+
+ <p>and the accumulated cover data for <c>m1</c> will be written to
+ <c>S1LogDir/[run.&lt;timestamp&gt;/]cross_cover.html</c>.</p>
+ <p>Note that the <c>m1</c> module will also be presented in the
+ normal coverage log for <c>s1</c> (due to the include statement in
+ <c>s1.cover</c>), but that only includes the coverage achieved by the
+ <c>s1</c> test itself.</p>
+ <p>The Tag in the <c>cross</c> statement in the cover file has
+ no other purpose than mapping the list of modules
+ (<c>[m1]</c> in the example above) to the correct log
+ directory where it should be included in the
+ <c>cross_cover.html</c> file (<c>S1LogDir</c> in the example
+ above). I.e. the value of <c>Tag</c> has no meaning, it
+ could be <c>foo</c> as well as <c>s1</c> above, as long as
+ the same <c>Tag</c> is used in the cover file and in the
+ call to this function.</p>
</desc>
</func>
<func>
diff --git a/lib/test_server/doc/src/ts.xml b/lib/test_server/doc/src/ts.xml
index 4a2c536e96..82ba3a5017 100644
--- a/lib/test_server/doc/src/ts.xml
+++ b/lib/test_server/doc/src/ts.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2007</year>
- <year>2011</year>
+ <year>2012</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -450,7 +450,7 @@ This option is mandatory for remote targets
<desc>
<p>Analyse cover data collected from all tests.
</p>
- <p>See test_server_ctrl:cross_cover_analyse/1
+ <p>See test_server_ctrl:cross_cover_analyse/2
</p>
</desc>
</func>
diff --git a/lib/test_server/src/Makefile b/lib/test_server/src/Makefile
index bb0b4e55b8..43a03f4e1d 100644
--- a/lib/test_server/src/Makefile
+++ b/lib/test_server/src/Makefile
@@ -40,6 +40,8 @@ RELSYSDIR = $(RELEASE_PATH)/lib/test_server-$(VSN)
# ----------------------------------------------------
MODULES= test_server_ctrl \
+ test_server_gl \
+ test_server_io \
test_server_node \
test_server \
test_server_sup \
@@ -67,7 +69,6 @@ INTERNAL_HRL_FILES = test_server_internal.hrl
TS_HRL_FILES= ts.hrl
C_FILES =
AUTOCONF_FILES = configure.in conf_vars.in
-COVER_FILES = cross.cover
PROGRAMS = configure config.sub config.guess install-sh
CONFIG = ts.config ts.unix.config ts.win32.config
@@ -111,10 +112,10 @@ configure: configure.in
# Special Build Targets
# ----------------------------------------------------
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
# ----------------------------------------------------
# Release Target
@@ -135,7 +136,7 @@ release_tests_spec: opt
$(INSTALL_DATA) $(ERL_FILES) $(TS_ERL_FILES) \
$(HRL_FILES) $(INTERNAL_HRL_FILES) $(TS_HRL_FILES) \
$(TS_TARGET_FILES) \
- $(AUTOCONF_FILES) $(C_FILES) $(COVER_FILES) $(CONFIG) \
+ $(AUTOCONF_FILES) $(C_FILES) $(CONFIG) \
"$(RELEASE_PATH)/test_server"
$(INSTALL_SCRIPT) $(PROGRAMS) "$(RELEASE_PATH)/test_server"
diff --git a/lib/test_server/src/erl2html2.erl b/lib/test_server/src/erl2html2.erl
index 6891e87e48..1729257809 100644
--- a/lib/test_server/src/erl2html2.erl
+++ b/lib/test_server/src/erl2html2.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -18,19 +18,9 @@
%%
%%%------------------------------------------------------------------
-%%% Purpose:Convert Erlang files to html. (Pretty faaast... :-)
+%%% Purpose:Convert Erlang files to html.
%%%------------------------------------------------------------------
-%--------------------------------------------------------------------
-% Some stats (Sparc5@110Mhz):
-% 4109 lines (erl_parse.erl): 3.00 secs
-% 1847 lines (application_controller.erl): 0.57 secs
-% 3160 lines (test_server.erl): 1.00 secs
-% 1199 lines (ts_estone.erl): 0.35 secs
-%
-% Avg: ~4.5e-4s/line, or ~0.45s/1000 lines, or ~2200 lines/sec.
-%--------------------------------------------------------------------
-
-module(erl2html2).
-export([convert/2, convert/3]).
@@ -44,142 +34,172 @@ convert(File, Dest) ->
%%
%% FIXME: The colours should *really* be set with
%% stylesheets...
+ Encoding = encoding(File),
Header = ["<!DOCTYPE HTML PUBLIC "
"\"-//W3C//DTD HTML 3.2 Final//EN\">\n"
"<!-- autogenerated by '"++atom_to_list(?MODULE)++"'. -->\n"
"<html>\n"
- "<head><title>", File, "</title></head>\n\n"
+ "<head>\n"
+ "<meta http-equiv=\"Content-Type\" content=\"text/html;"
+ "charset=",
+ Encoding,"\"/>\n"
+ "<title>", File, "</title>\n"
+ "</head>\n\n"
"<body bgcolor=\"white\" text=\"black\""
" link=\"blue\" vlink=\"purple\" alink=\"red\">\n"],
convert(File, Dest, Header).
-
+
+
convert(File, Dest, Header) ->
- case file:read_file(File) of
- {ok, Bin} ->
- Code=binary_to_list(Bin),
- statistics(runtime),
- {Html1, Lines} = root(Code, [], 1),
- Html = [Header,
- "<pre>\n", Html1, "</pre>\n",
- footer(Lines),"</body>\n</html>\n"],
- file:write_file(Dest, Html);
- {error, Reason} ->
- {error, Reason}
+ %% statistics(runtime),
+ case parse_file(File) of
+ {ok,Functions} ->
+ %% {_, Time1} = statistics(runtime),
+ %% io:format("Parsed file in ~.2f Seconds.~n",[Time1/1000]),
+ case file:open(File,[raw,{read_ahead,10000}]) of
+ {ok,SFd} ->
+ case file:open(Dest,[write,raw]) of
+ {ok,DFd} ->
+ file:write(DFd,[Header,"<pre>\n"]),
+ _Lines = build_html(SFd,DFd,Functions),
+ file:write(DFd,["</pre>\n",footer(),
+ "</body>\n</html>\n"]),
+ %% {_, Time2} = statistics(runtime),
+ %% io:format("Converted ~p lines in ~.2f Seconds.~n",
+ %% [_Lines, Time2/1000]),
+ file:close(SFd),
+ file:close(DFd),
+ ok;
+ Error ->
+ Error
+ end;
+ Error ->
+ Error
+ end;
+ Error ->
+ Error
end.
-root([], Res, Line) ->
- {Res, Line};
-root([Char0|Code], Res, Line0) ->
- Char = [Char0],
- case Char of
- "-" ->
- {Match, Line1, NewCode0, AttName} =
- read_to_char(Line0+1, Code, [], [$(, $.]),
- {_, Line2, NewCode, Stuff} = read_to_char(Line1, NewCode0, [], $\n),
- NewRes = [Res,linenum(Line0),"-<b>",AttName,
- "</b>",Match, Stuff, "\n"],
- root(NewCode, NewRes, Line2);
- "%" ->
- {_, Line, NewCode, Stuff} = read_to_char(Line0+1, Code, [], $\n),
- NewRes = [Res,linenum(Line0),"<i>%",Stuff,"</i>\n"],
- root(NewCode, NewRes, Line);
- "\n" ->
- root(Code, [Res,linenum(Line0), "\n"], Line0+1);
- " " ->
- {_, Line, NewCode, Stuff} = read_to_char(Line0+1, Code, [], $\n),
- root(NewCode, [Res,linenum(Line0)," ",Stuff, "\n"],
- Line);
- "\t" ->
- {_, Line, NewCode, Stuff} = read_to_char(Line0+1, Code, [], $\n),
- root(NewCode, [Res,linenum(Line0),"\t",Stuff, "\n"],
- Line);
- [Chr|_] when Chr>96, Chr<123 ->
- %% Assumed to be function/clause start.
- %% FIXME: This will trivially generate non-unique anchors
- %% (one for each clause) --- which is illegal HTML.
- {_, Line1, NewCode0, FName0} = read_to_char(Line0+1, Code, [], $(),
- {_, Line2, NewCode, Stuff} =
- read_to_char(Line1,NewCode0, [], $\n),
- FuncName = [[Chr],FName0],
- NewRes=[Res,"<a name=",FuncName,">",
- linenum(Line0),"<b>",FuncName,"</b></a>",
- "(",Stuff, "\n"],
- root(NewCode, NewRes, Line2);
- Chr ->
- {_, Line, NewCode, Stuff} = read_to_char(Line0+1, Code, [], $\n),
- root(NewCode, [Res,linenum(Line0),Chr,Stuff, "\n"],
- Line)
+%%%-----------------------------------------------------------------
+%%% Parse the input file to get the line numbers for all function
+%%% definitions. This will be used when creating link targets for each
+%%% function in build_html/5.
+%%%
+%%% All function clauses are also marked in order to allow
+%%% possibly_enhance/2 to write these in bold.
+parse_file(File) ->
+ case epp:open(File, [], []) of
+ {ok,Epp} ->
+ Forms = parse_file(Epp,File,false),
+ epp:close(Epp),
+ {ok,Forms};
+ {error,E} ->
+ {error,E}
end.
-read_to_char(Line0, [], Res, _Chr) ->
- {nomatch, Line0, [], Res};
-read_to_char(Line0, [Char|Code], Res, Chr) ->
- case Char of
- Chr -> {Char, Line0, Code, Res};
- _ when is_list(Chr) ->
- case lists:member(Char,Chr) of
- true ->
- {Char, Line0, Code, Res};
- false ->
- {Line,NewCode,NewRes} = maybe_convert(Line0,Code,Res,Char),
- read_to_char(Line, NewCode, NewRes, Chr)
+
+parse_file(Epp,File,InCorrectFile) ->
+ case epp:parse_erl_form(Epp) of
+ {ok,Form} ->
+ case Form of
+ {attribute,_,file,{File,_}} ->
+ parse_file(Epp,File,true);
+ {attribute,_,file,{_OtherFile,_}} ->
+ parse_file(Epp,File,false);
+ {function,L,F,A,[_|C]} when InCorrectFile ->
+ Clauses = [{clause,CL} || {clause,CL,_,_,_} <- C],
+ [{atom_to_list(F),A,L} | Clauses] ++
+ parse_file(Epp,File,true);
+ _ ->
+ parse_file(Epp,File,InCorrectFile)
end;
- _ ->
- {Line,NewCode,NewRes} = maybe_convert(Line0,Code,Res,Char),
- read_to_char(Line,NewCode, NewRes, Chr)
+ {error,_E} ->
+ parse_file(Epp,File,InCorrectFile);
+ {eof,_Location} ->
+ []
end.
-maybe_convert(Line0,Code,Res,Chr) ->
- case Chr of
- %% Quoted stuff should not have the highlighting like normal code
- %% FIXME: unbalanced quotes (e.g. in comments) will cause trouble with
- %% highlighting and line numbering in the rest of the module.
- $" ->
- {_, Line1, NewCode, Stuff0} = read_to_char(Line0, Code, [], $"),
- {Line2,Stuff} = add_linenumbers(Line1,lists:flatten(Stuff0),[]),
- {Line2,NewCode,[Res,$",Stuff,$"]};
- %% These chars have meaning in HTML, and *must* *not* be
- %% written as themselves.
- $& ->
- {Line0, Code, [Res,"&amp;"]};
- $< ->
- {Line0, Code, [Res,"&lt;"]};
- $> ->
- {Line0, Code, [Res,"&gt;"]};
- %% Everything else is simply copied.
- OtherChr ->
- {Line0, Code, [Res,OtherChr]}
- end.
+%%%-----------------------------------------------------------------
+%%% Add a link target for each line and one for each function definition.
+build_html(SFd,DFd,Functions) ->
+ build_html(SFd,DFd,file:read_line(SFd),1,Functions,false).
-add_linenumbers(Line,[Chr|Chrs],Res) ->
- case Chr of
- $\n -> add_linenumbers(Line+1,Chrs,[Res,$\n,linenum(Line)]);
- _ -> add_linenumbers(Line,Chrs,[Res,Chr])
- end;
-add_linenumbers(Line,[],Res) ->
- {Line,Res}.
-
-%% Make nicely indented line numbers.
-linenum(Line) ->
- Num = integer_to_list(Line),
- A = case Line rem 10 of
- 0 -> "<a name=\"" ++ Num ++"\"></a>";
- _ -> []
- end,
+build_html(SFd,DFd,{ok,Str},L,[{F,A,L}|Functions],_IsFuncDef) ->
+ FALink = http_uri:encode(F++"-"++integer_to_list(A)),
+ file:write(DFd,["<a name=\"",FALink,"\"/>"]),
+ build_html(SFd,DFd,{ok,Str},L,Functions,true);
+build_html(SFd,DFd,{ok,Str},L,[{clause,L}|Functions],_IsFuncDef) ->
+ build_html(SFd,DFd,{ok,Str},L,Functions,true);
+build_html(SFd,DFd,{ok,Str},L,Functions,IsFuncDef) ->
+ LStr = line_number(L),
+ Str1 = line(Str,IsFuncDef),
+ file:write(DFd,[LStr,Str1]),
+ build_html(SFd,DFd,file:read_line(SFd),L+1,Functions,false);
+build_html(_SFd,_DFd,eof,L,_Functions,_IsFuncDef) ->
+ L.
+
+line_number(L) ->
+ LStr = integer_to_list(L),
Pred =
- case length(Num) of
+ case length(LStr) of
Length when Length < 5 ->
lists:duplicate(5-Length,$\s);
_ ->
[]
end,
- [A,Pred,integer_to_list(Line),":"].
+ ["<a name=\"",LStr,"\"/>",Pred,LStr,": "].
+
+line(Str,IsFuncDef) ->
+ Str1 = htmlize(Str),
+ possibly_enhance(Str1,IsFuncDef).
-footer(_Lines) ->
+%%%-----------------------------------------------------------------
+%%% Substitute special characters that should not appear in HTML
+htmlize([$<|Str]) ->
+ [$&,$l,$t,$;|htmlize(Str)];
+htmlize([$>|Str]) ->
+ [$&,$g,$t,$;|htmlize(Str)];
+htmlize([$&|Str]) ->
+ [$&,$a,$m,$p,$;|htmlize(Str)];
+htmlize([$"|Str]) ->
+ [$&,$q,$u,$o,$t,$;|htmlize(Str)];
+htmlize([Ch|Str]) ->
+ [Ch|htmlize(Str)];
+htmlize([]) ->
+ [].
+
+%%%-----------------------------------------------------------------
+%%% Write comments in italic and function definitions in bold.
+possibly_enhance(Str,true) ->
+ case lists:splitwith(fun($() -> false; (_) -> true end, Str) of
+ {_,[]} -> Str;
+ {F,A} -> ["<b>",F,"</b>",A]
+ end;
+possibly_enhance([$%|_]=Str,_) ->
+ ["<i>",Str--"\n","</i>","\n"];
+possibly_enhance([$-|_]=Str,_) ->
+ possibly_enhance(Str,true);
+possibly_enhance(Str,false) ->
+ Str.
+
+%%%-----------------------------------------------------------------
+%%% End of the file
+footer() ->
"".
-%% {_, Time} = statistics(runtime),
-%% io:format("Converted ~p lines in ~.2f Seconds.~n",
-%% [Lines, Time/1000]),
-%% S = "<i>The transformation of this file (~p lines) took ~.2f seconds</i>",
-%% F = lists:flatten(io_lib:format(S, [Lines, Time/1000])),
-%% ["<hr size=1>",F,"<br>\n"].
+
+%%%-----------------------------------------------------------------
+%%% Read encoding from source file
+encoding(File) ->
+ Encoding =
+ case epp:read_encoding(File) of
+ none ->
+ epp:default_encoding();
+ E ->
+ E
+ end,
+ html_encoding(Encoding).
+
+html_encoding(latin1) ->
+ "iso-8859-1";
+html_encoding(utf8) ->
+ "utf-8".
diff --git a/lib/test_server/src/test_server.app.src b/lib/test_server/src/test_server.app.src
index faf7db835e..26330f9695 100644
--- a/lib/test_server/src/test_server.app.src
+++ b/lib/test_server/src/test_server.app.src
@@ -24,6 +24,7 @@
test_server_ctrl,
test_server,
test_server_h,
+ test_server_io,
test_server_node,
test_server_sup
]},
diff --git a/lib/test_server/src/test_server.erl b/lib/test_server/src/test_server.erl
index 8beed9bd3e..37cd8fac99 100644
--- a/lib/test_server/src/test_server.erl
+++ b/lib/test_server/src/test_server.erl
@@ -20,15 +20,12 @@
-define(DEFAULT_TIMETRAP_SECS, 60).
-%%% START %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--export([start/1,start/2]).
-
%%% TEST_SERVER_CTRL INTERFACE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-export([run_test_case_apply/1,init_target_info/0,init_purify/0]).
--export([cover_compile/1,cover_analyse/2]).
+-export([cover_compile/1,cover_analyse/3]).
%%% TEST_SERVER_SUP INTERFACE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--export([get_loc/1]).
+-export([get_loc/1,set_tc_state/1]).
%%% TEST SUITE INTERFACE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-export([lookup_config/2]).
@@ -60,49 +57,9 @@
-export([]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--record(state,{controller,jobs=[]}).
-
-include("test_server_internal.hrl").
-include_lib("kernel/include/file.hrl").
--define(pl2a(M), test_server_sup:package_atom(M)).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% **** START *** CODE FOR REMOTE TARGET ONLY ***
-%%
-%% test_server
-%% This process is started only if the test is to be run on a remote target
-%% The process is then started on target
-%% A socket connection is established with the test_server_ctrl process
-%% on host, and information about target is sent to host.
-start([ControllerHost]) when is_atom(ControllerHost) ->
- start(atom_to_list(ControllerHost));
-start(ControllerHost) when is_list(ControllerHost) ->
- start(ControllerHost,?MAIN_PORT).
-start(ControllerHost,ControllerPort) ->
- S = self(),
- Pid = spawn(fun() -> init(ControllerHost,ControllerPort,S) end),
- receive {Pid,started} -> {ok,Pid};
- {Pid,Error} -> Error
- end.
-
-init(Host,Port,Starter) ->
- global:register_name(?MODULE,self()),
- process_flag(trap_exit,true),
- test_server_sup:cleanup_crash_dumps(),
- case gen_tcp:connect(Host,Port, [binary,
- {reuseaddr,true},
- {packet,2}]) of
- {ok,MainSock} ->
- Starter ! {self(),started},
- request(MainSock,{target_info,init_target_info()}),
- loop(#state{controller={Host,MainSock}});
- Error ->
- Starter ! {self(),{error,
- {could_not_contact_controller,Error}}}
- end.
-
init_target_info() ->
[$.|Emu] = code:objfile_extension(),
{_, OTPRel} = init:script_id(),
@@ -118,171 +75,10 @@ init_target_info() ->
username=test_server_sup:get_username(),
cookie=atom_to_list(erlang:get_cookie())}.
-
-loop(#state{controller={_,MainSock}} = State) ->
- receive
- {tcp, MainSock, <<1,Request/binary>>} ->
- State1 = decode_main(binary_to_term(Request),State),
- loop(State1);
- {tcp_closed, MainSock} ->
- gen_tcp:close(MainSock),
- halt();
- {'EXIT',Pid,Reason} ->
- case lists:keysearch(Pid,1,State#state.jobs) of
- {value,{Pid,Name}} ->
- case Reason of
- normal -> ignore;
- _other -> request(MainSock,{job_proc_killed,Name,Reason})
- end,
- NewJobs = lists:keydelete(Pid,1,State#state.jobs),
- loop(State#state{jobs = NewJobs});
- false ->
- loop(State)
- end
- end.
-
-%% Decode request on main socket
-decode_main({job,Port,Name},#state{controller={Host,_},jobs=Jobs}=State) ->
- S = self(),
- NewJob = spawn_link(fun() -> job(Host,Port,S) end),
- receive {NewJob,started} -> State#state{jobs=[{NewJob,Name}|Jobs]};
- {NewJob,_Error} -> State
- end.
-
init_purify() ->
purify_new_leaks().
-%% Temporary job process on target
-%% This process will live while all test cases in the job are executed.
-%% A socket connection is established with the job process on host.
-job(Host,Port,Starter) ->
- process_flag(trap_exit,true),
- init_purify(),
- case gen_tcp:connect(Host,Port, [binary,
- {reuseaddr,true},
- {packet,4},
- {active,false}]) of
- {ok,JobSock} ->
- Starter ! {self(),started},
- job(JobSock);
- Error ->
- Starter ! {self(),{error,
- {could_not_contact_controller,Error}}}
- end.
-
-job(JobSock) ->
- JobDir = get_jobdir(),
- ok = file:make_dir(JobDir),
- ok = file:make_dir(filename:join(JobDir,?priv_dir)),
- put(test_server_job_sock,JobSock),
- put(test_server_job_dir,JobDir),
- {ok,Cwd} = file:get_cwd(),
- job_loop(JobSock),
- ok = file:set_cwd(Cwd),
- send_privdir(JobDir,JobSock), % also recursively removes jobdir
- ok.
-
-
-get_jobdir() ->
- Now = now(),
- {{Y,M,D},{H,Mi,S}} = calendar:now_to_local_time(Now),
- Basename = io_lib:format("~w-~2.2.0w-~2.2.0w_~2.2.0w.~2.2.0w.~2.2.0w_~w",
- [Y,M,D,H,Mi,S,element(3,Now)]),
- %% if target has a file master, don't use prim_file to look up cwd
- case lists:keymember(master,1,init:get_arguments()) of
- true ->
- {ok,Cwd} = file:get_cwd(),
- Cwd ++ "/" ++ Basename;
- false ->
- filename:absname(Basename)
- end.
-
-send_privdir(JobDir,JobSock) ->
- LocalPrivDir = filename:join(JobDir,?priv_dir),
- case file:list_dir(LocalPrivDir) of
- {ok,List} when List/=[] ->
- Tarfile0 = ?priv_dir ++ ".tar.gz",
- Tarfile = filename:join(JobDir,Tarfile0),
- {ok,Tar} = erl_tar:open(Tarfile,[write,compressed,cooked]),
- ok = erl_tar:add(Tar,LocalPrivDir,?priv_dir,[]),
- ok = erl_tar:close(Tar),
- {ok,TarBin} = file:read_file(Tarfile),
- file:delete(Tarfile),
- ok = del_dir(JobDir),
- request(JobSock,{{privdir,Tarfile0},TarBin});
- _ ->
- ok = del_dir(JobDir),
- request(JobSock,{privdir,empty_priv_dir})
- end.
-
-del_dir(Dir) ->
- case file:read_file_info(Dir) of
- {ok,#file_info{type=directory}} ->
- {ok,Cont} = file:list_dir(Dir),
- lists:foreach(fun(F) -> del_dir(filename:join(Dir,F)) end, Cont),
- ok = file:del_dir(Dir);
- {ok,#file_info{}} ->
- ok = file:delete(Dir);
- _r ->
- %% This might be a symlink - let's try to delete it!
- catch file:delete(Dir),
- ok
- end.
-
-%%
-%% Receive and decode request on job socket
-%%
-job_loop(JobSock) ->
- Request = recv(JobSock),
- case decode_job(Request) of
- ok -> job_loop(JobSock);
- {stop,R} -> R
- end.
-
-decode_job({{beam,Mod,Which},Beam}) ->
- % FIXME, shared directory structure on host and target required,
- % "Library beams" are not loaded from HOST... /Patrik
- code:add_patha(filename:dirname(Which)),
- % End of Patriks uglyness...
- {module,Mod} = code:load_binary(Mod,Which,Beam),
- ok;
-decode_job({{datadir,Tarfile0},Archive}) ->
- JobDir = get(test_server_job_dir),
- Tarfile = filename:join(JobDir,Tarfile0),
- ok = file:write_file(Tarfile,Archive),
- % Cooked is temporary removed/broken
- % ok = erl_tar:extract(Tarfile,[compressed,{cwd,JobDir},cooked]),
- ok = erl_tar:extract(Tarfile,[compressed,{cwd,JobDir}]),
- ok = file:delete(Tarfile),
- ok;
-decode_job({test_case,Case}) ->
- Result = run_test_case_apply(Case),
- JobSock = get(test_server_job_sock),
- request(JobSock,{test_case_result,Result}),
- case test_server_sup:tar_crash_dumps() of
- {error,no_crash_dumps} -> request(JobSock,{crash_dumps,no_crash_dumps});
- {ok,TarFile} ->
- {ok,TarBin} = file:read_file(TarFile),
- file:delete(TarFile),
- request(JobSock,{{crash_dumps,filename:basename(TarFile)},TarBin})
- end,
- ok;
-decode_job({sync_apply,{M,F,A}}) ->
- R = apply(M,F,A),
- request(get(test_server_job_sock),{sync_result,R}),
- ok;
-decode_job(job_done) ->
- {stop,stopped}.
-
-%%
-%% **** STOP *** CODE FOR REMOTE TARGET ONLY ***
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
-
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% cover_compile({App,Include,Exclude,Cross}) ->
%% {ok,AnalyseModules} | {error,Reason}
@@ -299,7 +95,8 @@ decode_job(job_done) ->
%% is found, else {error,application_not_found}.
cover_compile({none,_Exclude,Include,Cross}) ->
- CompileMods = Include++Cross,
+ CrossMods = lists:flatmap(fun({_,M}) -> M end,Cross),
+ CompileMods = Include++CrossMods,
case length(CompileMods) of
0 ->
io:fwrite("WARNING: No modules to cover compile!\n\n",[]),
@@ -313,7 +110,8 @@ cover_compile({none,_Exclude,Include,Cross}) ->
{ok,Include}
end;
cover_compile({App,all,Include,Cross}) ->
- CompileMods = Include++Cross,
+ CrossMods = lists:flatmap(fun({_,M}) -> M end,Cross),
+ CompileMods = Include++CrossMods,
case length(CompileMods) of
0 ->
io:fwrite("WARNING: No modules to cover compile!\n\n",[]),
@@ -331,9 +129,10 @@ cover_compile({App,all,Include,Cross}) ->
{ok,Include}
end;
cover_compile({App,Exclude,Include,Cross}) ->
+ CrossMods = lists:flatmap(fun({_,M}) -> M end,Cross),
case code:lib_dir(App) of
{error,bad_name} ->
- case Include++Cross of
+ case Include++CrossMods of
[] ->
io:format("\nWARNING: Can't find lib_dir for \'~w\'\n"
"Not cover compiling!\n\n",[App]),
@@ -354,7 +153,7 @@ cover_compile({App,Exclude,Include,Cross}) ->
WC = filename:join(EbinDir,"*.beam"),
AllMods = module_names(filelib:wildcard(WC)),
AnalyseMods = (AllMods ++ Include) -- Exclude,
- CompileMods = AnalyseMods ++ Cross,
+ CompileMods = AnalyseMods ++ CrossMods,
case length(CompileMods) of
0 ->
io:fwrite("WARNING: No modules to cover compile!\n\n",[]),
@@ -377,9 +176,7 @@ module_names(Beams) ->
do_cover_compile(Modules) ->
do_cover_compile1(lists:usort(Modules)). % remove duplicates
-do_cover_compile1([Dont|Rest]) when Dont=:=cover;
- Dont=:=test_server;
- Dont=:=test_server_ctrl ->
+do_cover_compile1([Dont|Rest]) when Dont=:=cover ->
do_cover_compile1(Rest);
do_cover_compile1([M|Rest]) ->
case {code:is_sticky(M),code:is_loaded(M)} of
@@ -416,7 +213,7 @@ do_cover_compile1([]) ->
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% cover_analyse(Analyse,Modules) -> [{M,{Cov,NotCov,Details}}]
+%% cover_analyse(Analyse,Modules,Stop) -> [{M,{Cov,NotCov,Details}}]
%%
%% Analyse = {details,Dir} | details | {overview,void()} | overview
%% Modules = [atom()], the modules to analyse
@@ -432,8 +229,19 @@ do_cover_compile1([]) ->
%%
%% Also, if a Dir exists, cover data will be exported to a file called
%% all.coverdata in that directory.
-cover_analyse(Analyse,Modules) ->
- io:fwrite("Cover analysing...\n",[]),
+%%
+%% Finally, if Stop==true, then cover will be stopped after the
+%% analysis is completed. Stopping cover causes the original (non
+%% cover compiled) modules to be loaded back in. If a process at this
+%% point is still running old code of any of the cover compiled
+%% modules, meaning that is has not done any fully qualified function
+%% call after the cover compilation, the process will now be
+%% killed. To avoid this scenario, it is possible to set Stop=false,
+%% which means that the modules will stay cover compiled. Note that
+%% this is only recommended if the erlang node is being terminated
+%% after the test is completed.
+cover_analyse(Analyse,Modules,Stop) ->
+ print(stdout, "Cover analysing...\n", []),
DetailsFun =
case Analyse of
{details,Dir} ->
@@ -483,9 +291,15 @@ cover_analyse(Analyse,Modules) ->
{M,Err}
end
end, Modules),
- Sticky = unstick_all_sticky(node()),
- cover:stop(),
- stick_all_sticky(node(),Sticky),
+
+ case Stop of
+ true ->
+ Sticky = unstick_all_sticky(node()),
+ cover:stop(),
+ stick_all_sticky(node(),Sticky);
+ false ->
+ ok
+ end,
R.
pmap(Fun,List) ->
@@ -502,7 +316,27 @@ pmap(Fun,List) ->
end
end, Pids).
+
+do_cover_for_node(Node,CoverFunc) ->
+ do_cover_for_node(Node,CoverFunc,true).
+do_cover_for_node(Node,CoverFunc,StickUnstick) ->
+ %% In case a slave node is starting another slave node! I.e. this
+ %% function is executed on a slave node - then the cover function
+ %% must be executed on the master node. This is for instance the
+ %% case in test_server's own tests.
+ MainCoverNode = cover:get_main_node(),
+ Sticky =
+ if StickUnstick -> unstick_all_sticky(MainCoverNode,Node);
+ true -> ok
+ end,
+ rpc:call(MainCoverNode,cover,CoverFunc,[Node]),
+ if StickUnstick -> stick_all_sticky(Node,Sticky);
+ true -> ok
+ end.
+
unstick_all_sticky(Node) ->
+ unstick_all_sticky(node(),Node).
+unstick_all_sticky(MainCoverNode,Node) ->
lists:filter(
fun(M) ->
case code:is_sticky(M) of
@@ -513,7 +347,7 @@ unstick_all_sticky(Node) ->
false
end
end,
- cover:modules()).
+ rpc:call(MainCoverNode,cover,modules,[])).
stick_all_sticky(Node,Sticky) ->
lists:foreach(
@@ -524,7 +358,7 @@ stick_all_sticky(Node,Sticky) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% run_test_case_apply(Mod,Func,Args,Name,RunInit,TimetrapData,RejectIoReqs) ->
+%% run_test_case_apply(Mod,Func,Args,Name,RunInit,TimetrapData) ->
%% {Time,Value,Loc,Opts,Comment} | {died,Reason,unknown,Comment}
%%
%% Time = float() (seconds)
@@ -538,7 +372,6 @@ stick_all_sticky(Node,Sticky) ->
%% it possible to capture all it's output from io:format/2, etc.
%%
%% The job process then sits down and waits for news from the case process.
-%% This might be io requests (which are redirected to the log files).
%%
%% Returns a tuple with the time spent (in seconds) in the test case,
%% the return value from the test case or an {'EXIT',Reason} if the case
@@ -559,12 +392,9 @@ stick_all_sticky(Node,Sticky) ->
%% ScaleTimetrap indicates if test_server should attemp to automatically
%% compensate timetraps for runtime delays introduced by e.g. tools like
%% cover.
-%%
-%% RejectIoReqs (bool) is information about whether printouts to stdout
-%% should be visible in the minor log file or not.
run_test_case_apply({CaseNum,Mod,Func,Args,Name,
- RunInit,TimetrapData,RejectIoReqs}) ->
+ RunInit,TimetrapData}) ->
purify_format("Test case #~w ~w:~w/1", [CaseNum, Mod, Func]),
case os:getenv("TS_RUN_VALGRIND") of
false ->
@@ -576,40 +406,29 @@ run_test_case_apply({CaseNum,Mod,Func,Args,Name,
test_server_h:testcase({Mod,Func,1}),
ProcBef = erlang:system_info(process_count),
Result = run_test_case_apply(Mod, Func, Args, Name, RunInit,
- TimetrapData, RejectIoReqs),
+ TimetrapData),
ProcAft = erlang:system_info(process_count),
purify_new_leaks(),
DetFail = get(test_server_detected_fail),
{Result,DetFail,ProcBef,ProcAft}.
-run_test_case_apply(Mod, Func, Args, Name, RunInit, TimetrapData, RejectIoReqs) ->
- case get(test_server_job_dir) of
- undefined ->
- %% i'm a local target
- do_run_test_case_apply(Mod, Func, Args, Name, RunInit,
- TimetrapData, RejectIoReqs);
- JobDir ->
- %% i'm a remote target
- case Args of
- [Config] when is_list(Config) ->
- {value,{data_dir,HostDataDir}} =
- lists:keysearch(data_dir, 1, Config),
- DataBase = filename:basename(HostDataDir),
- TargetDataDir = filename:join(JobDir, DataBase),
- Config1 = lists:keyreplace(data_dir, 1, Config,
- {data_dir,TargetDataDir}),
- TargetPrivDir = filename:join(JobDir, ?priv_dir),
- Config2 = lists:keyreplace(priv_dir, 1, Config1,
- {priv_dir,TargetPrivDir}),
- do_run_test_case_apply(Mod, Func, [Config2], Name, RunInit,
- TimetrapData, RejectIoReqs);
- _other ->
- do_run_test_case_apply(Mod, Func, Args, Name, RunInit,
- TimetrapData, RejectIoReqs)
- end
- end.
-do_run_test_case_apply(Mod, Func, Args, Name, RunInit,
- TimetrapData, RejectIoReqs) ->
+-type tc_status() :: 'starting' | 'running' | 'init_per_testcase' |
+ 'end_per_testcase' | {'framework',atom(),atom()} |
+ 'tc'.
+-record(st,
+ {
+ ref :: reference(),
+ pid :: pid(),
+ mf :: {atom(),atom()},
+ status :: tc_status() | 'undefined',
+ ret_val :: term(),
+ comment :: list(char()),
+ timeout :: non_neg_integer() | 'infinity',
+ config :: list() | 'undefined',
+ end_conf_pid :: pid() | 'undefined'
+ }).
+
+run_test_case_apply(Mod, Func, Args, Name, RunInit, TimetrapData) ->
{ok,Cwd} = file:get_cwd(),
Args2Print = case Args of
[Args1] when is_list(Args1) ->
@@ -624,9 +443,6 @@ do_run_test_case_apply(Mod, Func, Args, Name, RunInit,
TCCallback = get(test_server_testcase_callback),
LogOpts = get(test_server_logopts),
Ref = make_ref(),
- OldGLeader = group_leader(),
- %% Set ourself to group leader for the spawned process
- group_leader(self(),self()),
Pid =
spawn_link(
fun() ->
@@ -634,10 +450,10 @@ do_run_test_case_apply(Mod, Func, Args, Name, RunInit,
RunInit, TimetrapData,
LogOpts, TCCallback)
end),
- group_leader(OldGLeader, self()),
put(test_server_detected_fail, []),
- run_test_case_msgloop(Ref, Pid, false, RejectIoReqs, false, "",
- undefined, starting).
+ St = #st{ref=Ref,pid=Pid,mf={Mod,Func},status=starting,ret_val=[],
+ comment="",timeout=infinity,config=hd(Args)},
+ run_test_case_msgloop(St).
%% Ugly bug (pre R5A):
%% If this process (group leader of the test case) terminates before
@@ -648,32 +464,23 @@ do_run_test_case_apply(Mod, Func, Args, Name, RunInit,
%% A test case is known to have failed if it returns {'EXIT', _} tuple,
%% or sends a message {failed, File, Line} to it's group_leader
%%
-run_test_case_msgloop(Ref, Pid, CaptureStdout, RejectIoReqs, Terminate,
- Comment, CurrConf, Status) ->
- %% NOTE: Keep job_proxy_msgloop/0 up to date when changes
- %% are made in this function!
- {Timeout,ReturnValue} =
- case Terminate of
- {true, ReturnVal} ->
- %% stop any timetrap timers for the test case
- %% that have been started by this process
- timetrap_cancel_all(Pid, false),
- {20, ReturnVal};
- false ->
- {infinity, should_never_appear}
- end,
+run_test_case_msgloop(#st{ref=Ref,pid=Pid,end_conf_pid=EndConfPid0}=St0) ->
receive
- {test_case_initialized,Pid} ->
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,
- Comment,CurrConf,running);
- Abort = {abort_current_testcase,_,_} when Status == starting ->
+ {set_tc_state=Tag,From,{Status,Config0}} ->
+ Config = case Config0 of
+ unknown -> St0#st.config;
+ _ -> Config0
+ end,
+ St = St0#st{status=Status,config=Config},
+ From ! {self(),Tag,ok},
+ run_test_case_msgloop(St);
+ {abort_current_testcase,_,_}=Abort when St0#st.status =:= starting ->
%% we're in init phase, must must postpone this operation
%% until test case execution is in progress (or FW:init_tc
%% gets killed)
self() ! Abort,
erlang:yield(),
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,
- Comment,CurrConf,Status);
+ run_test_case_msgloop(St0);
{abort_current_testcase,Reason,From} ->
Line = case is_process_alive(Pid) of
true -> get_loc(Pid);
@@ -683,142 +490,49 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, RejectIoReqs, Terminate,
exit(Pid,{testcase_aborted,Reason,Line}),
erlang:yield(),
From ! {self(),abort_current_testcase,ok},
- NewComment =
- receive
- {'DOWN', Mon, process, Pid, _} ->
- Comment
- after 10000 ->
- %% Pid is probably trapping exits, hit it harder...
- exit(Pid, kill),
- %% here's the only place we know Reason, so we save
- %% it as a comment, potentially replacing user data
- Error = lists:flatten(io_lib:format("Aborted: ~p",
- [Reason])),
- Error1 = lists:flatten([string:strip(S,left) ||
+ St = receive
+ {'DOWN', Mon, process, Pid, _} ->
+ St0
+ after 10000 ->
+ %% Pid is probably trapping exits, hit it harder...
+ exit(Pid, kill),
+ %% here's the only place we know Reason, so we save
+ %% it as a comment, potentially replacing user data
+ Error = lists:flatten(io_lib:format("Aborted: ~p",
+ [Reason])),
+ Error1 = lists:flatten([string:strip(S,left) ||
S <- string:tokens(Error,
[$\n])]),
- if length(Error1) > 63 ->
- string:substr(Error1,1,60) ++ "...";
- true ->
- Error1
- end
- end,
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,
- NewComment,CurrConf,Status);
- {permit_io,FromPid} ->
- put({permit_io,FromPid},true),
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,
- Comment,CurrConf,Status);
- {io_request,From,ReplyAs,{put_chars,io_lib,Func,[Format,Args]}}
- when is_list(Format) ->
- Msg = (catch io_lib:Func(Format,Args)),
- run_test_case_msgloop_io(From,ReplyAs,CaptureStdout,RejectIoReqs,
- Msg,From,Func),
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,
- Comment,CurrConf,Status);
- {io_request,From,ReplyAs,{put_chars,io_lib,Func,[Format,Args]}}
- when is_atom(Format) ->
- Msg = (catch io_lib:Func(Format,Args)),
- run_test_case_msgloop_io(From,ReplyAs,CaptureStdout,RejectIoReqs,
- Msg,From,Func),
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,
- Comment,CurrConf,Status);
- {io_request,From,ReplyAs,{put_chars,Bytes}} ->
- run_test_case_msgloop_io(From,ReplyAs,CaptureStdout,RejectIoReqs,
- Bytes,From,put_chars),
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,
- Comment,CurrConf,Status);
- {io_request,From,ReplyAs,{put_chars,unicode,io_lib,Func,[Format,Args]}}
- when is_list(Format) ->
- Msg = unicode_to_latin1(catch io_lib:Func(Format,Args)),
- run_test_case_msgloop_io(From,ReplyAs,CaptureStdout,RejectIoReqs,
- Msg,From,Func),
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,
- Comment,CurrConf,Status);
- {io_request,From,ReplyAs,{put_chars,latin1,io_lib,Func,[Format,Args]}}
- when is_list(Format) ->
- Msg = (catch io_lib:Func(Format,Args)),
- run_test_case_msgloop_io(From,ReplyAs,CaptureStdout,RejectIoReqs,
- Msg,From,Func),
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,
- Comment,CurrConf,Status);
- {io_request,From,ReplyAs,{put_chars,unicode,io_lib,Func,[Format,Args]}}
- when is_atom(Format) ->
- Msg = unicode_to_latin1(catch io_lib:Func(Format,Args)),
- run_test_case_msgloop_io(From,ReplyAs,CaptureStdout,RejectIoReqs,
- Msg,From,Func),
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,
- Comment,CurrConf,Status);
- {io_request,From,ReplyAs,{put_chars,latin1,io_lib,Func,[Format,Args]}}
- when is_atom(Format) ->
- Msg = (catch io_lib:Func(Format,Args)),
- run_test_case_msgloop_io(From,ReplyAs,CaptureStdout,RejectIoReqs,
- Msg,From,Func),
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,
- Comment,CurrConf,Status);
- {io_request,From,ReplyAs,{put_chars,unicode,Bytes}} ->
- run_test_case_msgloop_io(From,ReplyAs,CaptureStdout,RejectIoReqs,
- unicode_to_latin1(Bytes),From,put_chars),
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,
- Comment,CurrConf,Status);
- {io_request,From,ReplyAs,{put_chars,latin1,Bytes}} ->
- run_test_case_msgloop_io(From,ReplyAs,CaptureStdout,RejectIoReqs,
- Bytes,From,put_chars),
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,
- Comment,CurrConf,Status);
- IoReq when element(1, IoReq) == io_request ->
- %% something else, just pass it on
- group_leader() ! IoReq,
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,
- Comment,CurrConf,Status);
- {structured_io,ClientPid,Msg} ->
- output(Msg, ClientPid),
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,
- Comment,CurrConf,Status);
- {capture,NewCapture} ->
- run_test_case_msgloop(Ref,Pid,NewCapture,RejectIoReqs,Terminate,
- Comment,CurrConf,Status);
+ Comment = if length(Error1) > 63 ->
+ string:substr(Error1,1,60) ++ "...";
+ true ->
+ Error1
+ end,
+ St0#st{comment=Comment}
+ end,
+ run_test_case_msgloop(St);
{sync_apply,From,MFA} ->
sync_local_or_remote_apply(false,From,MFA),
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,
- Comment,CurrConf,Status);
+ run_test_case_msgloop(St0);
{sync_apply_proxy,Proxy,From,MFA} ->
sync_local_or_remote_apply(Proxy,From,MFA),
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,
- Comment,CurrConf,Status);
- {printout,Detail,Format,Args} ->
- print(Detail,Format,Args),
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,
- Comment,CurrConf,Status);
- {comment,NewComment} ->
- NewComment1 = test_server_ctrl:to_string(NewComment),
- NewComment2 = test_server_sup:framework_call(format_comment,
- [NewComment1],
- NewComment1),
- Terminate1 =
- case Terminate of
- {true,{Time,Value,Loc,Opts,_OldComment}} ->
- {true,{Time,Value,mod_loc(Loc),Opts,NewComment2}};
- Other ->
- Other
- end,
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate1,
- NewComment2,CurrConf,Status);
+ run_test_case_msgloop(St0);
+ {comment,NewComment0} ->
+ NewComment1 = test_server_ctrl:to_string(NewComment0),
+ NewComment = test_server_sup:framework_call(format_comment,
+ [NewComment1],
+ NewComment1),
+ run_test_case_msgloop(St0#st{comment=NewComment});
{read_comment,From} ->
- From ! {self(),read_comment,Comment},
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,
- Comment,CurrConf,Status);
- {set_curr_conf,From,NewCurrConf} ->
- From ! {self(),set_curr_conf,ok},
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,
- Comment,NewCurrConf,Status);
- {make_priv_dir,From} when CurrConf == undefined ->
- From ! {self(),make_priv_dir,{error,no_priv_dir_in_config}},
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,
- Comment,CurrConf,Status);
+ From ! {self(),read_comment,St0#st.comment},
+ run_test_case_msgloop(St0);
{make_priv_dir,From} ->
+ Config = case St0#st.config of
+ undefined -> [];
+ Config0 -> Config0
+ end,
Result =
- case proplists:get_value(priv_dir, element(2, CurrConf)) of
+ case proplists:get_value(priv_dir, Config) of
undefined ->
{error,no_priv_dir_in_config};
PrivDir ->
@@ -832,212 +546,63 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, RejectIoReqs, Terminate,
end
end,
From ! {self(),make_priv_dir,Result},
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,Terminate,
- Comment,CurrConf,Status);
+ run_test_case_msgloop(St0);
{'EXIT',Pid,{Ref,Time,Value,Loc,Opts}} ->
- RetVal = {Time/1000000,Value,mod_loc(Loc),Opts,Comment},
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,
- {true,RetVal},Comment,undefined,Status);
+ RetVal = {Time/1000000,Value,Loc,Opts},
+ St = setup_termination(RetVal, St0#st{config=undefined}),
+ run_test_case_msgloop(St);
{'EXIT',Pid,Reason} ->
- case Reason of
- {timetrap_timeout,TVal,Loc} ->
- %% convert Loc to form that can be formatted
- case mod_loc(Loc) of
- {FwMod,FwFunc,framework} ->
- %% timout during framework call
- spawn_fw_call(FwMod,FwFunc,CurrConf,Pid,
- {framework_error,{timetrap,TVal}},
- unknown,self()),
- run_test_case_msgloop(Ref,Pid,
- CaptureStdout,RejectIoReqs,
- Terminate,Comment,
- undefined,Status);
- Loc1 ->
- %% call end_per_testcase on a separate process,
- %% only so that the user has a chance to
- %% clean up after init_per_testcase, even after
- %% a timetrap timeout
- NewCurrConf =
- case CurrConf of
- {{Mod,Func},Conf} ->
- EndConfPid =
- call_end_conf(
- Mod,Func,Pid,
- {timetrap_timeout,TVal},
- Loc1,[{tc_status,
- {failed,
- timetrap_timeout}}|Conf],
- TVal),
- {EndConfPid,{Mod,Func},Conf};
- _ ->
- {Mod,Func} = get_mf(Loc1),
- %% The framework functions mustn't
- %% execute on this group leader process
- %% or io will cause deadlock, so we
- %% spawn a dedicated process for the
- %% operation and let the group leader
- %% go back to handle io.
- spawn_fw_call(Mod,Func,CurrConf,Pid,
- {timetrap_timeout,TVal},
- Loc1,self()),
- undefined
- end,
- run_test_case_msgloop(Ref,Pid,
- CaptureStdout,RejectIoReqs,
- Terminate,Comment,
- NewCurrConf,Status)
- end;
- {timetrap_timeout,TVal,Loc,InitOrEnd} ->
- case mod_loc(Loc) of
- {FwMod,FwFunc,framework} ->
- %% timout during framework call
- spawn_fw_call(FwMod,FwFunc,CurrConf,Pid,
- {framework_error,{timetrap,TVal}},
- unknown,self());
- Loc1 ->
- {Mod,_Func} = get_mf(Loc1),
- spawn_fw_call(Mod,InitOrEnd,CurrConf,Pid,
- {timetrap_timeout,TVal},
- Loc1,self())
- end,
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,
- Terminate,Comment,CurrConf,Status);
- {testcase_aborted,ErrorMsg={user_timetrap_error,_},AbortLoc} ->
- %% user timetrap function caused exit
- %% during start of test case
- {Mod,Func} = get_mf(mod_loc(AbortLoc)),
- spawn_fw_call(Mod,Func,CurrConf,Pid,
- ErrorMsg,unknown,self()),
- run_test_case_msgloop(Ref,Pid,
- CaptureStdout,RejectIoReqs,
- Terminate,Comment,
- undefined,Status);
- {testcase_aborted,AbortReason,AbortLoc} ->
- ErrorMsg = {testcase_aborted,AbortReason},
- case mod_loc(AbortLoc) of
- {FwMod,FwFunc,framework} ->
- %% abort during framework call
- spawn_fw_call(FwMod,FwFunc,CurrConf,Pid,
- {framework_error,ErrorMsg},
- unknown,self()),
- run_test_case_msgloop(Ref,Pid,
- CaptureStdout,RejectIoReqs,
- Terminate,Comment,
- undefined,Status);
- Loc1 ->
- %% call end_per_testcase on a separate process,
- %% only so that the user has a chance to clean up
- %% after init_per_testcase, even after abortion
- NewCurrConf =
- case CurrConf of
- {{Mod,Func},Conf} ->
- TVal =
- case lists:keysearch(default_timeout,
- 1,
- Conf) of
- {value,{default_timeout,Tmo}} ->
- Tmo;
- _ ->
- ?DEFAULT_TIMETRAP_SECS*1000
- end,
- EndConfPid =
- call_end_conf(
- Mod,Func,Pid,
- ErrorMsg,Loc1,
- [{tc_status,
- {failed,ErrorMsg}}|Conf],TVal),
- {EndConfPid,{Mod,Func},Conf};
- _ ->
- {Mod,Func} = get_mf(Loc1),
- spawn_fw_call(Mod,Func,CurrConf,Pid,
- ErrorMsg,Loc1,self()),
- undefined
- end,
- run_test_case_msgloop(Ref,Pid,
- CaptureStdout,RejectIoReqs,
- Terminate,Comment,
- NewCurrConf,Status)
- end;
- killed ->
- %% result of an exit(TestCase,kill) call, which is the
- %% only way to abort a testcase process that traps exits
- %% (see abort_current_testcase)
- {Mod,Func} = case CurrConf of
- {MF,_} -> MF;
- _ -> {undefined,undefined}
- end,
- spawn_fw_call(Mod,Func,CurrConf,Pid,
- testcase_aborted_or_killed,
- unknown,self()),
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,
- Terminate,Comment,CurrConf,Status);
- {fw_error,{FwMod,FwFunc,FwError}} ->
- spawn_fw_call(FwMod,FwFunc,CurrConf,Pid,
- {framework_error,FwError},
- unknown,self()),
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,
- Terminate,Comment,CurrConf,Status);
- _Other ->
- %% the testcase has terminated because of Reason (e.g. an exit
- %% because a linked process failed)
- {Mod,Func} = case CurrConf of
- {MF,_} -> MF;
- _ -> {undefined,undefined}
- end,
- spawn_fw_call(Mod,Func,CurrConf,Pid,
- Reason,unknown,self()),
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,
- Terminate,Comment,CurrConf,Status)
- end;
- {EndConfPid,{call_end_conf,Data,_Result}} ->
+ St = handle_tc_exit(Reason, St0),
+ run_test_case_msgloop(St);
+ {EndConfPid0,{call_end_conf,Data,_Result}} ->
+ #st{mf={Mod,Func},config=CurrConf} = St0,
case CurrConf of
- {EndConfPid,{Mod,Func},_Conf} ->
+ _ when is_list(CurrConf) ->
{_Mod,_Func,TCPid,TCExitReason,Loc} = Data,
spawn_fw_call(Mod,Func,CurrConf,TCPid,
TCExitReason,Loc,self()),
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,
- Terminate,Comment,undefined,Status);
+ St = St0#st{config=undefined,end_conf_pid=undefined},
+ run_test_case_msgloop(St);
_ ->
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,
- Terminate,Comment,CurrConf,Status)
+ run_test_case_msgloop(St0)
end;
{_FwCallPid,fw_notify_done,{T,Value,Loc,Opts,AddToComment}} ->
%% the framework has been notified, we're finished
- RetVal =
- case AddToComment of
- undefined ->
- {T,Value,Loc,Opts,Comment};
- _ ->
- Comment1 =
- if Comment == "" ->
- AddToComment;
- true ->
- Comment ++
- test_server_ctrl:xhtml("<br>",
- "<br />") ++
- AddToComment
- end,
- {T,Value,Loc,Opts,Comment1}
- end,
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,
- {true,RetVal},Comment,undefined,Status);
+ RetVal = {T,Value,Loc,Opts},
+ Comment0 = St0#st.comment,
+ Comment = case AddToComment of
+ undefined ->
+ Comment0;
+ _ ->
+ if Comment0 =:= "" ->
+ AddToComment;
+ true ->
+ Comment0 ++
+ test_server_ctrl:xhtml("<br>",
+ "<br />") ++
+ AddToComment
+ end
+ end,
+ St = setup_termination(RetVal, St0#st{comment=Comment,
+ config=undefined}),
+ run_test_case_msgloop(St);
{'EXIT',_FwCallPid,{fw_notify_done,Func,Error}} ->
%% a framework function failed
CB = os:getenv("TEST_SERVER_FRAMEWORK"),
Loc = case CB of
FW when FW =:= false; FW =:= "undefined" ->
- {test_server,Func};
+ [{test_server,Func}];
_ ->
- {list_to_atom(CB),Func}
+ [{list_to_atom(CB),Func}]
end,
- RetVal = {died,{framework_error,Loc,Error},Loc,"Framework error"},
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,
- {true,RetVal},Comment,undefined,Status);
+ RetVal = {died,{framework_error,Loc,Error},Loc},
+ St = setup_termination(RetVal, St0#st{comment="Framework error",
+ config=undefined}),
+ run_test_case_msgloop(St);
{failed,File,Line} ->
put(test_server_detected_fail,
[{File, Line}| get(test_server_detected_fail)]),
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,
- Terminate,Comment,CurrConf,Status);
+ run_test_case_msgloop(St0);
{user_timetrap,Pid,_TrapTime,StartTime,E={user_timetrap_error,_},_} ->
case update_user_timetraps(Pid, StartTime) of
@@ -1046,8 +611,7 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, RejectIoReqs, Terminate,
ignore ->
ok
end,
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,
- Terminate,Comment,CurrConf,Status);
+ run_test_case_msgloop(St0);
{user_timetrap,Pid,TrapTime,StartTime,ElapsedTime,Scale} ->
%% a user timetrap is triggered, ignore it if new
%% timetrap has been started since
@@ -1062,71 +626,117 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, RejectIoReqs, Terminate,
ignore ->
ok
end,
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,
- Terminate,Comment,CurrConf,Status);
+ run_test_case_msgloop(St0);
{timetrap_cancel_one,Handle,_From} ->
timetrap_cancel_one(Handle, false),
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,
- Terminate,Comment,CurrConf,Status);
+ run_test_case_msgloop(St0);
{timetrap_cancel_all,TCPid,_From} ->
timetrap_cancel_all(TCPid, false),
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,
- Terminate,Comment,CurrConf,Status);
- {get_timetrap_info,TCPid,From} ->
+ run_test_case_msgloop(St0);
+ {get_timetrap_info,From,TCPid} ->
Info = get_timetrap_info(TCPid, false),
From ! {self(),get_timetrap_info,Info},
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,
- Terminate,Comment,CurrConf,Status);
+ run_test_case_msgloop(St0);
_Other when not is_tuple(_Other) ->
%% ignore anything not generated by test server
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,
- Terminate,Comment,CurrConf,Status);
+ run_test_case_msgloop(St0);
_Other when element(1, _Other) /= 'EXIT',
element(1, _Other) /= started,
element(1, _Other) /= finished,
element(1, _Other) /= print ->
%% ignore anything not generated by test server
- run_test_case_msgloop(Ref,Pid,CaptureStdout,RejectIoReqs,
- Terminate,Comment,CurrConf,Status)
- after Timeout ->
- ReturnValue
+ run_test_case_msgloop(St0)
+ after St0#st.timeout ->
+ #st{ret_val=RetVal,comment=Comment} = St0,
+ erlang:append_element(RetVal, Comment)
end.
-run_test_case_msgloop_io(From,ReplyAs,CaptureStdout,RejectIoReqs,
- Msg,From,Func) ->
- case Msg of
- {'EXIT',_} ->
- From ! {io_reply,ReplyAs,{error,Func}};
- _ ->
- From ! {io_reply,ReplyAs,ok}
- end,
- Proceed = if RejectIoReqs -> get({permit_io,From});
- true -> true
- end,
- if Proceed ->
- if CaptureStdout /= false ->
- CaptureStdout ! {captured,Msg};
- true ->
- ok
- end,
- output({minor,Msg},From);
- true ->
- ok
- end.
+setup_termination(RetVal, #st{pid=Pid}=St) ->
+ timetrap_cancel_all(Pid, false),
+ St#st{ret_val=RetVal,timeout=20}.
+
+set_tc_state(State) ->
+ set_tc_state(State,unknown).
+set_tc_state(State, Config) ->
+ tc_supervisor_req(set_tc_state, {State,Config}).
+
+handle_tc_exit(killed, St) ->
+ %% probably the result of an exit(TestCase,kill) call, which is the
+ %% only way to abort a testcase process that traps exits
+ %% (see abort_current_testcase).
+ #st{config=Config,mf={Mod,Func},pid=Pid} = St,
+ Msg = testcase_aborted_or_killed,
+ spawn_fw_call(Mod, Func, Config, Pid, Msg, unknown, self()),
+ St;
+handle_tc_exit({testcase_aborted,{user_timetrap_error,_}=Msg,_}, St) ->
+ #st{config=Config,mf={Mod,Func},pid=Pid} = St,
+ spawn_fw_call(Mod, Func, Config, Pid, Msg, unknown, self()),
+ St;
+handle_tc_exit(Reason, #st{status={framework,FwMod,FwFunc},
+ config=Config,pid=Pid}=St) ->
+ R = case Reason of
+ {timetrap_timeout,TVal,_} ->
+ {timetrap,TVal};
+ {testcase_aborted=E,AbortReason,_} ->
+ {E,AbortReason};
+ {fw_error,{FwMod,FwFunc,FwError}} ->
+ FwError;
+ Other ->
+ Other
+ end,
+ Error = {framework_error,R},
+ spawn_fw_call(FwMod, FwFunc, Config, Pid, Error, unknown, self()),
+ St;
+handle_tc_exit(Reason, #st{status=tc,config=Config0,mf={Mod,Func},pid=Pid}=St)
+ when is_list(Config0) ->
+ {R,Loc1,F} = case Reason of
+ {timetrap_timeout=E,TVal,Loc0} ->
+ {{E,TVal},Loc0,E};
+ {testcase_aborted=E,AbortReason,Loc0} ->
+ Msg = {E,AbortReason},
+ {Msg,Loc0,Msg};
+ Other ->
+ {Other,unknown,Other}
+ end,
+ Timeout = end_conf_timeout(Reason, St),
+ Config = [{tc_status,{failed,F}}|Config0],
+ EndConfPid = call_end_conf(Mod, Func, Pid, R, Loc1, Config, Timeout),
+ St#st{end_conf_pid=EndConfPid};
+handle_tc_exit(Reason, #st{config=Config,mf={Mod,Func0},pid=Pid,
+ status=Status}=St) ->
+ {R,Loc1} = case Reason of
+ {timetrap_timeout=E,TVal,Loc0} ->
+ {{E,TVal},Loc0};
+ {testcase_aborted=E,AbortReason,Loc0} ->
+ {{E,AbortReason},Loc0};
+ Other ->
+ {Other,unknown}
+ end,
+ Func = case Status of
+ init_per_testcase=F -> {F,Func0};
+ end_per_testcase=F -> {F,Func0};
+ _ -> Func0
+ end,
+ spawn_fw_call(Mod, Func, Config, Pid, R, Loc1, self()),
+ St.
-output(Msg,Sender) ->
- local_or_remote_apply({test_server_ctrl,output,[Msg,Sender]}).
+end_conf_timeout({timetrap_timeout,Timeout,_}, _) ->
+ Timeout;
+end_conf_timeout(_, #st{config=Config}) when is_list(Config) ->
+ proplists:get_value(default_timeout, Config, ?DEFAULT_TIMETRAP_SECS*1000);
+end_conf_timeout(_, _) ->
+ ?DEFAULT_TIMETRAP_SECS*1000.
call_end_conf(Mod,Func,TCPid,TCExitReason,Loc,Conf,TVal) ->
- %% Starter is also the group leader process
Starter = self(),
Data = {Mod,Func,TCPid,TCExitReason,Loc},
EndConfProc =
fun() ->
- group_leader(Starter, self()),
+ process_flag(trap_exit,true), % to catch timetraps
Supervisor = self(),
EndConfApply =
fun() ->
+ timetrap(TVal),
case catch apply(Mod,end_per_testcase,[Func,Conf]) of
{'EXIT',Why} ->
timer:sleep(1),
@@ -1145,29 +755,26 @@ call_end_conf(Mod,Func,TCPid,TCExitReason,Loc,Conf,TVal) ->
{Pid,end_conf} ->
Starter ! {self(),{call_end_conf,Data,ok}};
{'EXIT',Pid,Reason} ->
- Starter ! {self(),{call_end_conf,Data,{error,Reason}}}
- after TVal ->
- exit(Pid, kill),
group_leader() ! {printout,12,
"WARNING! ~p:end_per_testcase(~p, ~p)"
- " failed!\n\tReason: timetrap timeout"
- " after ~w ms!\n", [Mod,Func,Conf,TVal]},
- Starter ! {self(),{call_end_conf,Data,{error,timeout}}}
+ " failed!\n\tReason: ~p\n",
+ [Mod,Func,Conf,Reason]},
+ Starter ! {self(),{call_end_conf,Data,{error,Reason}}};
+ {'EXIT',_OtherPid,Reason} ->
+ %% Probably the parent - not much to do about that
+ exit(Reason)
end
end,
spawn_link(EndConfProc).
-spawn_fw_call(Mod,{init_per_testcase,Func},_,Pid,{timetrap_timeout,TVal}=Why,
+spawn_fw_call(Mod,{init_per_testcase,Func},CurrConf,Pid,{timetrap_timeout,TVal}=Why,
Loc,SendTo) ->
FwCall =
fun() ->
- %% set group leader so that printouts/comments
- %% from the framework get printed in the logs
- group_leader(SendTo, self()),
Skip = {skip,{failed,{Mod,init_per_testcase,Why}}},
%% if init_per_testcase fails, the test case
%% should be skipped
- case catch do_end_tc_call(Mod,Func, Loc, {Pid,Skip,[[]]}, Why) of
+ case catch do_end_tc_call(Mod,Func, {Pid,Skip,[CurrConf]}, Why) of
{'EXIT',FwEndTCErr} ->
exit({fw_notify_done,end_tc,FwEndTCErr});
_ ->
@@ -1181,22 +788,10 @@ spawn_fw_call(Mod,{init_per_testcase,Func},_,Pid,{timetrap_timeout,TVal}=Why,
spawn_fw_call(Mod,{end_per_testcase,Func},EndConf,Pid,
{timetrap_timeout,TVal}=Why,_Loc,SendTo) ->
- %%! This is a temporary fix that keeps Test Server alive during
- %%! execution of a parallel test case group, when sometimes
- %%! this clause gets called with EndConf == undefined. See OTP-9594
- %%! for more info.
- EndConf1 = if EndConf == undefined ->
- [{tc_status,{failed,{Mod,end_per_testcase,Why}}}];
- true ->
- EndConf
- end,
FwCall =
fun() ->
- %% set group leader so that printouts/comments
- %% from the framework get printed in the logs
- group_leader(SendTo, self()),
{RetVal,Report} =
- case proplists:get_value(tc_status, EndConf1) of
+ case proplists:get_value(tc_status, EndConf) of
undefined ->
E = {failed,{Mod,end_per_testcase,Why}},
{E,E};
@@ -1210,9 +805,9 @@ spawn_fw_call(Mod,{end_per_testcase,Func},EndConf,Pid,
"WARNING! ~p:end_per_testcase(~p, ~p)"
" failed!\n\tReason: timetrap timeout"
" after ~w ms!\n", [Mod,Func,EndConf,TVal]},
- FailLoc = proplists:get_value(tc_fail_loc, EndConf1),
- case catch do_end_tc_call(Mod,Func, FailLoc,
- {Pid,Report,[EndConf1]}, Why) of
+ FailLoc = proplists:get_value(tc_fail_loc, EndConf),
+ case catch do_end_tc_call(Mod,Func,
+ {Pid,Report,[EndConf]}, Why) of
{'EXIT',FwEndTCErr} ->
exit({fw_notify_done,end_tc,FwEndTCErr});
_ ->
@@ -1230,9 +825,6 @@ spawn_fw_call(Mod,{end_per_testcase,Func},EndConf,Pid,
spawn_fw_call(FwMod,FwFunc,_,_Pid,{framework_error,FwError},_,SendTo) ->
FwCall =
fun() ->
- %% set group leader so that printouts/comments
- %% from the framework get printed in the logs
- group_leader(SendTo, self()),
test_server_sup:framework_call(report, [framework_error,
{{FwMod,FwFunc},
FwError}]),
@@ -1249,17 +841,9 @@ spawn_fw_call(FwMod,FwFunc,_,_Pid,{framework_error,FwError},_,SendTo) ->
spawn_link(FwCall);
spawn_fw_call(Mod,Func,CurrConf,Pid,Error,Loc,SendTo) ->
- {Mod1,Func1} =
- case {Mod,Func,CurrConf} of
- {undefined,undefined,{{M,F},_}} -> {M,F};
- _ -> {Mod,Func}
- end,
FwCall =
fun() ->
- %% set group leader so that printouts/comments
- %% from the framework get printed in the logs
- group_leader(SendTo, self()),
- case catch fw_error_notify(Mod1,Func1,[],
+ case catch fw_error_notify(Mod,Func,[],
Error,Loc) of
{'EXIT',FwErrorNotifyErr} ->
exit({fw_notify_done,error_notification,
@@ -1267,8 +851,8 @@ spawn_fw_call(Mod,Func,CurrConf,Pid,Error,Loc,SendTo) ->
_ ->
ok
end,
- Conf = [{tc_status,{failed,timetrap_timeout}}],
- case catch do_end_tc_call(Mod1,Func1, Loc,
+ Conf = [{tc_status,{failed,timetrap_timeout}}|CurrConf],
+ case catch do_end_tc_call(Mod,Func,
{Pid,Error,[Conf]},Error) of
{'EXIT',FwEndTCErr} ->
exit({fw_notify_done,end_tc,FwEndTCErr});
@@ -1333,83 +917,73 @@ run_test_case_eval(Mod, Func, Args0, Name, Ref, RunInit,
TimetrapData, LogOpts, TCCallback) ->
put(test_server_multiply_timetraps, TimetrapData),
put(test_server_logopts, LogOpts),
- FWInitResult = test_server_sup:framework_call(init_tc,[?pl2a(Mod),Func,Args0],
+ Where = [{Mod,Func}],
+ put(test_server_loc, Where),
+ FWInitResult = test_server_sup:framework_call(init_tc,[Mod,Func,Args0],
{ok,Args0}),
- group_leader() ! {test_case_initialized,self()},
+ set_tc_state(running),
{{Time,Value},Loc,Opts} =
case FWInitResult of
{ok,Args} ->
run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback);
Error = {error,_Reason} ->
- Where = {Mod,Func},
- NewResult = do_end_tc_call(Mod,Func, Where, {Error,Args0},
+ NewResult = do_end_tc_call(Mod,Func, {Error,Args0},
{skip,{failed,Error}}),
{{0,NewResult},Where,[]};
{fail,Reason} ->
Conf = [{tc_status,{failed,Reason}} | hd(Args0)],
- Where = {Mod,Func},
fw_error_notify(Mod, Func, Conf, Reason),
- NewResult = do_end_tc_call(Mod,Func, Where, {{error,Reason},[Conf]},
+ NewResult = do_end_tc_call(Mod,Func, {{error,Reason},[Conf]},
{fail,Reason}),
{{0,NewResult},Where,[]};
Skip = {skip,_Reason} ->
- Where = {Mod,Func},
- NewResult = do_end_tc_call(Mod,Func, Where, {Skip,Args0}, Skip),
+ NewResult = do_end_tc_call(Mod,Func, {Skip,Args0}, Skip),
{{0,NewResult},Where,[]};
{auto_skip,Reason} ->
- Where = {Mod,Func},
- NewResult = do_end_tc_call(Mod,Func, Where, {{skip,Reason},Args0},
+ NewResult = do_end_tc_call(Mod,Func, {{skip,Reason},Args0},
{skip,Reason}),
{{0,NewResult},Where,[]}
end,
exit({Ref,Time,Value,Loc,Opts}).
run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback) ->
- %% save current state in controller loop
- sync_send(group_leader(),set_curr_conf,{{Mod,Func},hd(Args)},
- 5000, fun() -> exit(no_answer_from_group_leader) end),
case RunInit of
run_init ->
- put(test_server_init_or_end_conf,{init_per_testcase,Func}),
- put(test_server_loc, {Mod,{init_per_testcase,Func}}),
+ set_tc_state(init_per_testcase, hd(Args)),
ensure_timetrap(Args),
case init_per_testcase(Mod, Func, Args) of
Skip = {skip,Reason} ->
Line = get_loc(),
- Conf = [{tc_status,{skipped,Reason}}],
- NewRes = do_end_tc_call(Mod,Func, Line, {Skip,[Conf]}, Skip),
+ Conf = [{tc_status,{skipped,Reason}}|hd(Args)],
+ NewRes = do_end_tc_call(Mod,Func, {Skip,[Conf]}, Skip),
{{0,NewRes},Line,[]};
{skip_and_save,Reason,SaveCfg} ->
Line = get_loc(),
- Conf = [{tc_status,{skipped,Reason}},{save_config,SaveCfg}],
- NewRes = do_end_tc_call(Mod,Func, Line, {{skip,Reason},[Conf]},
+ Conf = [{tc_status,{skipped,Reason}},{save_config,SaveCfg}|hd(Args)],
+ NewRes = do_end_tc_call(Mod,Func, {{skip,Reason},[Conf]},
{skip,Reason}),
{{0,NewRes},Line,[]};
FailTC = {fail,Reason} -> % user fails the testcase
EndConf = [{tc_status,{failed,Reason}} | hd(Args)],
fw_error_notify(Mod, Func, EndConf, Reason),
- NewRes = do_end_tc_call(Mod,Func, {Mod,Func},
+ NewRes = do_end_tc_call(Mod,Func,
{{error,Reason},[EndConf]},
FailTC),
- {{0,NewRes},{Mod,Func},[]};
+ {{0,NewRes},[{Mod,Func}],[]};
{ok,NewConf} ->
- put(test_server_init_or_end_conf,undefined),
%% call user callback function if defined
NewConf1 = user_callback(TCCallback, Mod, Func, init, NewConf),
%% save current state in controller loop
- sync_send(group_leader(),set_curr_conf,{{Mod,Func},NewConf1},
- 5000, fun() -> exit(no_answer_from_group_leader) end),
- put(test_server_loc, {Mod,Func}),
+ set_tc_state(tc, NewConf1),
%% execute the test case
{{T,Return},Loc} = {ts_tc(Mod, Func, [NewConf1]),get_loc()},
{EndConf,TSReturn,FWReturn} =
case Return of
{E,TCError} when E=='EXIT' ; E==failed ->
- ModLoc = mod_loc(Loc),
fw_error_notify(Mod, Func, NewConf1,
- TCError, ModLoc),
+ TCError, Loc),
{[{tc_status,{failed,TCError}},
- {tc_fail_loc,ModLoc}|NewConf1],
+ {tc_fail_loc,Loc}|NewConf1],
Return,{error,TCError}};
SaveCfg={save_config,_} ->
{[{tc_status,ok},SaveCfg|NewConf1],Return,ok};
@@ -1426,8 +1000,6 @@ run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback) ->
%% call user callback function if defined
EndConf1 = user_callback(TCCallback, Mod, Func, 'end', EndConf),
%% update current state in controller loop
- sync_send(group_leader(),set_curr_conf,EndConf1, 5000,
- fun() -> exit(no_answer_from_group_leader) end),
{FWReturn1,TSReturn1,EndConf2} =
case end_per_testcase(Mod, Func, EndConf1) of
SaveCfg1={save_config,_} ->
@@ -1447,24 +1019,21 @@ run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback) ->
{FWReturn,TSReturn,EndConf1}
end,
%% clear current state in controller loop
- sync_send(group_leader(),set_curr_conf,undefined,
- 5000, fun() -> exit(no_answer_from_group_leader) end),
- put(test_server_init_or_end_conf,undefined),
- case do_end_tc_call(Mod,Func, Loc,
+ case do_end_tc_call(Mod,Func,
{FWReturn1,[EndConf2]}, TSReturn1) of
{failed,Reason} = NewReturn ->
fw_error_notify(Mod,Func,EndConf2, Reason),
- {{T,NewReturn},{Mod,Func},[]};
+ {{T,NewReturn},[{Mod,Func}],[]};
NewReturn ->
{{T,NewReturn},Loc,[]}
end
end;
skip_init ->
+ set_tc_state(running, hd(Args)),
%% call user callback function if defined
Args1 = user_callback(TCCallback, Mod, Func, init, Args),
ensure_timetrap(Args1),
%% ts_tc does a catch
- put(test_server_loc, {Mod,Func}),
%% if this is a named conf group, the test case (init or end conf)
%% should be called with the name as the first argument
Args2 = if Name == undefined -> Args1;
@@ -1475,47 +1044,16 @@ run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback) ->
%% call user callback function if defined
Return1 = user_callback(TCCallback, Mod, Func, 'end', Return),
{Return2,Opts} = process_return_val([Return1], Mod, Func,
- Args1, {Mod,Func}, Return1),
+ Args1, [{Mod,Func}], Return1),
{{T,Return2},Loc,Opts}
end.
-do_end_tc_call(M,F, Loc, Res, Return) ->
- IsSuite = case lists:reverse(atom_to_list(M)) of
- [$E,$T,$I,$U,$S,$_|_] -> true;
- _ -> false
- end,
+do_end_tc_call(Mod, Func, Res, Return) ->
FwMod = os:getenv("TEST_SERVER_FRAMEWORK"),
- {Mod,Func} =
- if FwMod == M ; FwMod == "undefined"; FwMod == false ->
- {M,F};
- (not IsSuite) and is_list(Loc) and (length(Loc)>1) ->
- %% If failure in other module (M) than suite, try locate
- %% suite name in Loc list and call end_tc with Suite:TestCase
- %% instead of M:F.
- GetSuite = fun(S,TC) ->
- case lists:reverse(atom_to_list(S)) of
- [$E,$T,$I,$U,$S,$_|_] -> [{S,TC}];
- _ -> []
- end
- end,
- case lists:flatmap(fun({S,TC,_}) -> GetSuite(S,TC);
- ({{S,TC},_}) -> GetSuite(S,TC);
- ({S,TC}) -> GetSuite(S,TC);
- (_) -> []
- end, Loc) of
- [] ->
- {M,F};
- [FoundSuite|_] ->
- FoundSuite
- end;
- true ->
- {M,F}
- end,
-
Ref = make_ref(),
if FwMod == "ct_framework" ; FwMod == "undefined"; FwMod == false ->
case test_server_sup:framework_call(
- end_tc, [?pl2a(Mod),Func,Res, Return], ok) of
+ end_tc, [Mod,Func,Res, Return], ok) of
{fail,FWReason} ->
{failed,FWReason};
ok ->
@@ -1530,7 +1068,7 @@ do_end_tc_call(M,F, Loc, Res, Return) ->
end;
true ->
case test_server_sup:framework_call(FwMod, end_tc,
- [?pl2a(Mod),Func,Res], Ref) of
+ [Mod,Func,Res], Ref) of
{fail,FWReason} ->
{failed,FWReason};
_Else ->
@@ -1553,7 +1091,7 @@ process_return_val([Return], M,F,A, Loc, Final) when is_list(Return) ->
true -> % must be return value from end conf case
process_return_val1(Return, M,F,A, Loc, Final, []);
false -> % must be Config value from init conf case
- case do_end_tc_call(M, F, Loc, {ok,A}, Return) of
+ case do_end_tc_call(M, F, {ok,A}, Return) of
{failed, FWReason} = Failed ->
fw_error_notify(M,F,A, FWReason),
{Failed, []};
@@ -1569,9 +1107,9 @@ process_return_val(Return, M,F,A, Loc, Final) ->
process_return_val1([Failed={E,TCError}|_], M,F,A=[Args], Loc, _, SaveOpts)
when E=='EXIT';
E==failed ->
- fw_error_notify(M,F,A, TCError, mod_loc(Loc)),
- case do_end_tc_call(M,F, Loc, {{error,TCError},
- [[{tc_status,{failed,TCError}}|Args]]},
+ fw_error_notify(M,F,A, TCError, Loc),
+ case do_end_tc_call(M,F, {{error,TCError},
+ [[{tc_status,{failed,TCError}}|Args]]},
Failed) of
{failed,FWReason} ->
{{failed,FWReason},SaveOpts};
@@ -1589,8 +1127,8 @@ process_return_val1([RetVal={Tag,_}|Opts], M,F,A, Loc, _, SaveOpts) when Tag==sk
process_return_val1(Opts, M,F,A, Loc, RetVal, SaveOpts);
process_return_val1([_|Opts], M,F,A, Loc, Final, SaveOpts) ->
process_return_val1(Opts, M,F,A, Loc, Final, SaveOpts);
-process_return_val1([], M,F,A, Loc, Final, SaveOpts) ->
- case do_end_tc_call(M,F, Loc, {Final,A}, Final) of
+process_return_val1([], M,F,A, _Loc, Final, SaveOpts) ->
+ case do_end_tc_call(M,F, {Final,A}, Final) of
{failed,FWReason} ->
{{failed,FWReason},SaveOpts};
NewReturn ->
@@ -1656,7 +1194,7 @@ do_init_per_testcase(Mod, Args) ->
throw:Other ->
set_loc(erlang:get_stacktrace()),
Line = get_loc(),
- FormattedLoc = test_server_sup:format_loc(mod_loc(Line)),
+ FormattedLoc = test_server_sup:format_loc(Line),
group_leader() ! {printout,12,
"ERROR! init_per_testcase thrown!\n"
"\tLocation: ~s\n\tReason: ~p\n",
@@ -1667,7 +1205,7 @@ do_init_per_testcase(Mod, Args) ->
Reason = {Reason0,Stk},
set_loc(Stk),
Line = get_loc(),
- FormattedLoc = test_server_sup:format_loc(mod_loc(Line)),
+ FormattedLoc = test_server_sup:format_loc(Line),
group_leader() ! {printout,12,
"ERROR! init_per_testcase crashed!\n"
"\tLocation: ~s\n\tReason: ~p\n",
@@ -1690,8 +1228,7 @@ end_per_testcase(Mod, Func, Conf) ->
end.
do_end_per_testcase(Mod,EndFunc,Func,Conf) ->
- put(test_server_init_or_end_conf,{EndFunc,Func}),
- put(test_server_loc, {Mod,{EndFunc,Func}}),
+ set_tc_state(end_per_testcase, Conf),
try Mod:EndFunc(Func, Conf) of
{save_config,_}=SaveCfg ->
SaveCfg;
@@ -1715,8 +1252,7 @@ do_end_per_testcase(Mod,EndFunc,Func,Conf) ->
"Reason: ~p\n"
"Line: ~s\n",
[EndFunc, Other,
- test_server_sup:format_loc(
- mod_loc(get_loc()))]},
+ test_server_sup:format_loc(get_loc())]},
{failed,{Mod,end_per_testcase,Other}};
Class:Reason ->
Stk = erlang:get_stacktrace(),
@@ -1738,8 +1274,7 @@ do_end_per_testcase(Mod,EndFunc,Func,Conf) ->
"Reason: ~p\n"
"Line: ~s\n",
[EndFunc, Reason,
- test_server_sup:format_loc(
- mod_loc(get_loc()))]},
+ test_server_sup:format_loc(get_loc())]},
{failed,{Mod,end_per_testcase,Why}}
end.
@@ -1752,73 +1287,26 @@ get_loc(Pid) ->
lists:foreach(fun({Key,Val}) -> put(Key, Val) end, Dict),
Stk = [rewrite_loc_item(Loc) || Loc <- Stk0],
case get(test_server_loc) of
- undefined ->
- put(test_server_loc, Stk);
- {Suite,Case} ->
+ [{Suite,Case}] ->
%% location info unknown, check if {Suite,Case,Line}
%% is available in stacktrace. and if so, use stacktrace
- %% instead of currect test_server_loc
+ %% instead of current test_server_loc
case [match || {S,C,_L} <- Stk, S == Suite, C == Case] of
[match|_] -> put(test_server_loc, Stk);
_ -> ok
end;
_ ->
- ok
+ put(test_server_loc, Stk)
end,
get_loc().
-%% find the latest known Suite:Testcase
-get_mf(MFs) ->
- get_mf(MFs, {undefined,undefined}).
-
-get_mf([MF|MFs], _Found) when is_tuple(MF) ->
- ModFunc = {Mod,_} = case MF of
- {M,F,_} -> {M,F};
- MF -> MF
- end,
- case is_suite(Mod) of
- true -> ModFunc;
- false -> get_mf(MFs, ModFunc)
- end;
-get_mf(_, Found) ->
- Found.
-
-is_suite(Mod) ->
- case lists:reverse(atom_to_list(Mod)) of
- "ETIUS" ++ _ -> true;
- _ -> false
- end.
-
-mod_loc(Loc) ->
- %% handle diff line num versions
- case Loc of
- [{{_M,_F},_L}|_] ->
- [begin if L /= 0 -> {?pl2a(M),F,L};
- true -> {?pl2a(M),F} end end || {{M,F},L} <- Loc];
- [{_M,_F}|_] ->
- [{?pl2a(M),F} || {M,F} <- Loc];
- {{M,F},0} ->
- [{?pl2a(M),F}];
- {{M,F},L} ->
- [{?pl2a(M),F,L}];
- {M,ForL} ->
- [{?pl2a(M),ForL}];
- {M,F,0} ->
- [{M,F}];
- [{M,F,0}|Stack] ->
- [{M,F}|Stack];
- _ ->
- Loc
- end.
-
-
fw_error_notify(Mod, Func, Args, Error) ->
test_server_sup:framework_call(error_notification,
- [?pl2a(Mod),Func,[Args],
+ [Mod,Func,[Args],
{Error,unknown}]).
fw_error_notify(Mod, Func, Args, Error, Loc) ->
test_server_sup:framework_call(error_notification,
- [?pl2a(Mod),Func,[Args],
+ [Mod,Func,[Args],
{Error,Loc}]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1833,10 +1321,10 @@ fw_error_notify(Mod, Func, Args, Error, Loc) ->
%% is directed to console, major and/or minor log files.
print(Detail,Format,Args) ->
- local_or_remote_apply({test_server_ctrl,print,[Detail,Format,Args]}).
+ test_server_ctrl:print(Detail, Format, Args).
print(Detail,Format,Args,Printer) ->
- local_or_remote_apply({test_server_ctrl,print,[Detail,Format,Args,Printer]}).
+ test_server_ctrl:print(Detail, Format, Args, Printer).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% print_timsteamp(Detail,Leader) -> ok
@@ -1846,7 +1334,7 @@ print(Detail,Format,Args,Printer) ->
%% log files.
print_timestamp(Detail,Leader) ->
- local_or_remote_apply({test_server_ctrl,print_timestamp,[Detail,Leader]}).
+ test_server_ctrl:print_timestamp(Detail, Leader).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1894,7 +1382,12 @@ ts_tc(M, F, A) ->
{Elapsed, Result}.
set_loc(Stk) ->
- Loc = [rewrite_loc_item(I) || {_,_,_,_}=I <- Stk],
+ Loc = case [rewrite_loc_item(I) || {_,_,_,_}=I <- Stk] of
+ [{M,F,0}|Stack] ->
+ [{M,F}|Stack];
+ Other ->
+ Other
+ end,
put(test_server_loc, Loc).
rewrite_loc_item({M,F,_,Loc}) ->
@@ -1908,16 +1401,6 @@ rewrite_loc_item({M,F,_,Loc}) ->
%% Note: Some of these functions have been moved to test_server_sup %%
%% in an attempt to keep this modules small (yeah, right!) %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-unicode_to_latin1(Chars) when is_list(Chars); is_binary(Chars) ->
- lists:flatten(
- [ case X of
- High when High > 255 ->
- io_lib:format("\\{~.8B}",[X]);
- Low ->
- Low
- end || X <- unicode:characters_to_list(Chars,unicode) ]);
-unicode_to_latin1(Garbage) ->
- Garbage.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% format(Format) -> IoLibReturn
@@ -2170,24 +1653,19 @@ continue(Pid) when is_pid(Pid) ->
%%
%% Returns the amount to scale timetraps with.
+%% {X, fun() -> check() end} <- multiply scale with X if Fun() is true
timetrap_scale_factor() ->
- F0 = case test_server:purify_is_running() of
- true -> 5;
- false -> 1
- end,
- F1 = case {is_debug(), has_lock_checking()} of
- {true,_} -> 6 * F0;
- {false,true} -> 2 * F0;
- {false,false} -> F0
- end,
- F = case has_superfluous_schedulers() of
- true -> 3*F1;
- false -> F1
- end,
- case test_server:is_cover() of
- true -> 10 * F;
- false -> F
- end.
+ timetrap_scale_factor([
+ { 2, fun() -> has_lock_checking() end},
+ { 3, fun() -> has_superfluous_schedulers() end},
+ { 5, fun() -> purify_is_running() end},
+ { 6, fun() -> is_debug() end},
+ {10, fun() -> is_cover() end}
+ ]).
+
+timetrap_scale_factor(Scales) ->
+ %% The fun in {S, Fun} a filter input to the list comprehension
+ lists:foldl(fun(S,O) -> O*S end, 1, [ S || {S,F} <- Scales, F()]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -2515,11 +1993,7 @@ get_timetrap_info(TCPid, SendToServer) ->
[I|_] ->
I;
[] when SendToServer == true ->
- MsgLooper = group_leader(),
- MsgLooper ! {get_timetrap_info,TCPid,self()},
- receive
- {MsgLooper,get_timetrap_info,I} -> I
- end;
+ tc_supervisor_req({get_timetrap_info,TCPid});
[] ->
undefined
end
@@ -2538,17 +2012,29 @@ hours(N) -> trunc(N * 1000 * 60 * 60).
minutes(N) -> trunc(N * 1000 * 60).
seconds(N) -> trunc(N * 1000).
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% sync_send(Pid,Tag,Msg,Timeout,DoAfter) -> Result
+%% tc_supervisor_req(Tag) -> Result
+%% tc_supervisor_req(Tag, Msg) -> Result
%%
-sync_send(Pid,Tag,Msg,Timeout,DoAfter) ->
+
+tc_supervisor_req(Tag) ->
+ Pid = test_server_gl:get_tc_supervisor(group_leader()),
+ Pid ! {Tag,self()},
+ receive
+ {Pid,Tag,Result} ->
+ Result
+ after 5000 ->
+ error(no_answer_from_tc_supervisor)
+ end.
+
+tc_supervisor_req(Tag, Msg) ->
+ Pid = test_server_gl:get_tc_supervisor(group_leader()),
Pid ! {Tag,self(),Msg},
receive
{Pid,Tag,Result} ->
Result
- after Timeout ->
- DoAfter()
+ after 5000 ->
+ error(no_answer_from_tc_supervisor)
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -2708,9 +2194,9 @@ start_node(Name, Type, Options) ->
%% Cannot run cover on shielded node or on a node started
%% by a shielded node.
- Cover = case is_cover() of
+ Cover = case is_cover(Node) of
true ->
- not is_shielded(Name) andalso same_version(Node);
+ proplists:get_value(start_cover,Options,true);
false ->
false
end,
@@ -2718,9 +2204,7 @@ start_node(Name, Type, Options) ->
net_adm:ping(Node),
case Cover of
true ->
- Sticky = unstick_all_sticky(Node),
- cover:start(Node),
- stick_all_sticky(Node,Sticky);
+ do_cover_for_node(Node,start);
_ ->
ok
end,
@@ -2748,7 +2232,20 @@ wait_for_node(Slave) ->
group_leader() ! {sync_apply,
self(),
{test_server_ctrl,wait_for_node,[Slave]}},
- receive {sync_result,R} -> R end.
+ Result = receive {sync_result,R} -> R end,
+ case Result of
+ ok ->
+ net_adm:ping(Slave),
+ case is_cover(Slave) of
+ true ->
+ do_cover_for_node(Slave,start);
+ _ ->
+ ok
+ end;
+ _ ->
+ ok
+ end,
+ Result.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -2757,14 +2254,9 @@ wait_for_node(Slave) ->
%% Kills a (remote) node.
%% Also inform test_server_ctrl so it can clean up!
stop_node(Slave) ->
- Nocover = is_shielded(Slave) orelse not same_version(Slave),
- case is_cover() of
- true when not Nocover ->
- Sticky = unstick_all_sticky(Slave),
- cover:stop(Slave),
- stick_all_sticky(Slave,Sticky);
- _ ->
- ok
+ Cover = is_cover(Slave),
+ if Cover -> do_cover_for_node(Slave,flush,false);
+ true -> ok
end,
group_leader() ! {sync_apply,self(),{test_server_ctrl,stop_node,[Slave]}},
Result = receive {sync_result,R} -> R end,
@@ -2776,10 +2268,15 @@ stop_node(Slave) ->
{nodedown, Slave} ->
format(minor, "Stopped slave node: ~p", [Slave]),
format(major, "=node_stop ~p", [Slave]),
+ if Cover -> do_cover_for_node(Slave,stop,false);
+ true -> ok
+ end,
true
after 30000 ->
format("=== WARNING: Node ~p does not seem to terminate.",
[Slave]),
+ erlang:monitor_node(Slave, false),
+ receive {nodedown, Slave} -> ok after 0 -> ok end,
false
end;
{error, _Reason} ->
@@ -2791,9 +2288,27 @@ stop_node(Slave) ->
[Slave]),
case net_adm:ping(Slave)of
pong ->
+ erlang:monitor_node(Slave, true),
slave:stop(Slave),
- true;
+ receive
+ {nodedown, Slave} ->
+ format(minor, "Stopped slave node: ~p", [Slave]),
+ format(major, "=node_stop ~p", [Slave]),
+ if Cover -> do_cover_for_node(Slave,stop,false);
+ true -> ok
+ end,
+ true
+ after 30000 ->
+ format("=== WARNING: Node ~p does not seem to terminate.",
+ [Slave]),
+ erlang:monitor_node(Slave, false),
+ receive {nodedown, Slave} -> ok after 0 -> ok end,
+ false
+ end;
pang ->
+ if Cover -> do_cover_for_node(Slave,stop,false);
+ true -> ok
+ end,
false
end
end.
@@ -2880,6 +2395,14 @@ same_version(Name) ->
OtherVersion = rpc:call(Name, erlang, system_info, [version]),
ThisVersion =:= OtherVersion.
+is_cover(Name) ->
+ case is_cover() of
+ true ->
+ not is_shielded(Name) andalso same_version(Name);
+ false ->
+ false
+ end.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% temp_name(Stem) -> string()
%% Stem = string()
@@ -2943,13 +2466,7 @@ comment(String) ->
%% Read the current comment string stored in
%% state during test case execution.
read_comment() ->
- MsgLooper = group_leader(),
- MsgLooper ! {read_comment,self()},
- receive
- {MsgLooper,read_comment,Comment} -> Comment
- after
- 5000 -> ""
- end.
+ tc_supervisor_req(read_comment).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% make_priv_dir() -> ok
@@ -2957,13 +2474,7 @@ read_comment() ->
%% Order test server to create the private directory
%% for the current test case.
make_priv_dir() ->
- MsgLooper = group_leader(),
- group_leader() ! {make_priv_dir,self()},
- receive
- {MsgLooper,make_priv_dir,Result} -> Result
- after
- 5000 -> error
- end.
+ tc_supervisor_req(make_priv_dir).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% os_type() -> OsType
@@ -2971,7 +2482,7 @@ make_priv_dir() ->
%% Returns the OsType of the target node. OsType is
%% the same as returned from os:type()
os_type() ->
- test_server_ctrl:get_target_os_type().
+ os:type().
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -3090,47 +2601,9 @@ purify_format(Format, Args) ->
%%
%% Generic send functions for communication with host
%%
-sync_local_or_remote_apply(Proxy,From,{M,F,A} = MFA) ->
- case get(test_server_job_sock) of
- undefined ->
- %% i'm a local target
- Result = apply(M,F,A),
- if is_pid(Proxy) -> Proxy ! {sync_result_proxy,From,Result};
- true -> From ! {sync_result,Result}
- end;
- JobSock ->
- %% i'm a remote target
- request(JobSock,{sync_apply,MFA}),
- {sync_result,Result} = recv(JobSock),
- if is_pid(Proxy) -> Proxy ! {sync_result_proxy,From,Result};
- true -> From ! {sync_result,Result}
- end
- end.
-local_or_remote_apply({M,F,A} = MFA) ->
- case get(test_server_job_sock) of
- undefined ->
- %% i'm a local target
- apply(M,F,A),
- ok;
- JobSock ->
- %% i'm a remote target
- request(JobSock,{apply,MFA}),
- ok
- end.
-
-request(Sock,Request) ->
- gen_tcp:send(Sock,<<1,(term_to_binary(Request))/binary>>).
-
-%%
-%% Generic receive function for communication with host
-%%
-recv(Sock) ->
- case gen_tcp:recv(Sock,0) of
- {error,closed} ->
- gen_tcp:close(Sock),
- exit(connection_lost);
- {ok,<<1,Request/binary>>} ->
- binary_to_term(Request);
- {ok,<<0,B/binary>>} ->
- B
+sync_local_or_remote_apply(Proxy, From, {M,F,A}) ->
+ %% i'm a local target
+ Result = apply(M, F, A),
+ if is_pid(Proxy) -> Proxy ! {sync_result_proxy,From,Result};
+ true -> From ! {sync_result,Result}
end.
diff --git a/lib/test_server/src/test_server_ctrl.erl b/lib/test_server/src/test_server_ctrl.erl
index 88d86285d5..c5c57426b4 100644
--- a/lib/test_server/src/test_server_ctrl.erl
+++ b/lib/test_server/src/test_server_ctrl.erl
@@ -34,118 +34,6 @@
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% ARCHITECTURE
-%%
-%% The Erlang Test Server can be run on the target machine (local target)
-%% or towards a remote target. The execution flow is mainly the same in
-%% both cases, but with a remote target the test cases are (obviously)
-%% executed on the target machine. Host and target communicates over
-%% socket connections because the host should not be introduced as an
-%% additional node in the distributed erlang system in which the test
-%% cases are run.
-%%
-%%
-%% Local Target:
-%% =============
-%%
-%% -----
-%% | | test_server_ctrl ({global,test_server})
-%% ----- (test_server_ctrl.erl)
-%% |
-%% |
-%% -----
-%% | | JobProc
-%% ----- (test_server_ctrl.erl and test_server.erl)
-%% |
-%% |
-%% -----
-%% | | CaseProc
-%% ----- (test_server.erl)
-%%
-%%
-%%
-%% test_server_ctrl is the main process in the system. It is a registered
-%% process, and it will always be alive when testing is ongoing.
-%% test_server_ctrl initiates testing and monitors JobProc(s).
-%%
-%% When target is local, and Test Server is *not* being used by a framework
-%% application (where it might cause duplicate name problems in a distributed
-%% test environment), the process is globally registered as 'test_server'
-%% to be able to simulate the {global,test_server} process on a remote target.
-%%
-%% JobProc is spawned for each 'job' added to the test_server_ctrl.
-%% A job can mean one test case, one test suite or one spec.
-%% JobProc creates and writes logs and presents results from testing.
-%% JobProc is the group leader for CaseProc.
-%%
-%% CaseProc is spawned for each test case. It runs the test case and
-%% sends results and any other information to its group leader - JobProc.
-%%
-%%
-%%
-%% Remote Target:
-%% ==============
-%%
-%% HOST TARGET
-%%
-%% ----- MainSock -----
-%% test_server_ctrl | |- - - - - - -| | {global,test_server}
-%% (test_server_ctrl.erl) ----- ----- (test_server.erl)
-%% | |
-%% | |
-%% ----- JobSock -----
-%% JobProcH | |- - - - - - -| | JobProcT
-%% (test_server_ctrl.erl) ----- ----- (test_server.erl)
-%% |
-%% |
-%% -----
-%% | | CaseProc
-%% ----- (test_server.erl)
-%%
-%%
-%%
-%%
-%% A separate test_server process only exists when target is remote. It
-%% is then the main process on target. It is started when test_server_ctrl
-%% is started, and a socket connection is established between
-%% test_server_ctrl and test_server. The following information can be sent
-%% over MainSock:
-%%
-%% HOST TARGET
-%% -> {target_info, TargetInfo} (during initiation)
-%% <- {job_proc_killed,Name,Reason} (if a JobProcT dies unexpectedly)
-%% -> {job,Port,Name} (to start a new JobProcT)
-%%
-%%
-%% When target is remote, JobProc is split into to processes: JobProcH
-%% executing on Host and JobProcT executing on Target. (The two processes
-%% execute the same code as JobProc does when target is local.) JobProcH
-%% and JobProcT communicates over a socket connection. The following
-%% information can be sent over JobSock:
-%%
-%% HOST TARGET
-%% -> {test_case, Case} To start a new test case
-%% -> {beam,Mod} .beam file as binary to be loaded
-%% on target, e.g. a test suite
-%% -> {datadir,Tarfile} Content of the datadir for a test suite
-%% <- {apply,MFA} MFA to be applied on host, ignore return;
-%% (apply is used for printing information in
-%% log or console)
-%% <- {sync_apply,MFA} MFA to be applied on host, wait for return
-%% (used for starting and stopping slave nodes)
-%% -> {sync_apply,MFA} MFA to be applied on target, wait for return
-%% (used for cover compiling and analysing)
-%% <-> {sync_result,Result} Return value from sync_apply
-%% <- {test_case_result,Result} When a test case is finished
-%% <- {crash_dumps,Tarfile} When a test case is finished
-%% -> job_done When a job is finished
-%% <- {privdir,Privdir} When a job is finished
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
-
%%% SUPERVISOR INTERFACE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-export([start/0, start/1, start_link/1, stop/0]).
@@ -165,19 +53,17 @@
-export([reject_io_reqs/1, get_levels/0, set_levels/3]).
-export([multiply_timetraps/1, scale_timetraps/1, get_timetrap_parameters/0]).
-export([create_priv_dir/1]).
--export([cover/2, cover/3, cover/7,
- cross_cover_analyse/1, cross_cover_analyse/2, trc/1, stop_trace/0]).
+-export([cover/2, cover/3, cover/8, cross_cover_analyse/2, trc/1, stop_trace/0]).
-export([testcase_callback/1]).
-export([set_random_seed/1]).
-export([kill_slavenodes/0]).
%%% TEST_SERVER INTERFACE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--export([output/2, print/2, print/3, print/4, print_timestamp/2]).
+-export([print/2, print/3, print/4, print_timestamp/2]).
-export([start_node/3, stop_node/1, wait_for_node/1, is_release_available/1]).
-export([format/1, format/2, format/3, to_string/1]).
-export([get_target_info/0]).
-export([get_hosts/0]).
--export([get_target_os_type/0]).
-export([node_started/1]).
%%% DEBUGGER INTERFACE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -201,16 +87,18 @@
-define(data_dir_suffix, "_data/").
-define(suitelog_name, "suite.log").
-define(coverlog_name, "cover.html").
+-define(raw_coverlog_name, "cover.log").
-define(cross_coverlog_name, "cross_cover.html").
+-define(raw_cross_coverlog_name, "cross_cover.log").
+-define(cross_cover_info, "cross_cover.info").
-define(cover_total, "total_cover.log").
+-define(unexpected_io_log, "unexpected_io.log").
-define(last_file, "last_name").
-define(last_link, "last_link").
-define(last_test, "last_test").
-define(html_ext, ".html").
--define(cross_cover_file, "cross.cover").
-define(now, erlang:now()).
--define(pl2a(M), test_server_sup:package_atom(M)).
-define(void_fun, fun() -> ok end).
-define(mod_result(X), if X == skip -> skipped;
X == auto_skip -> skipped;
@@ -462,8 +350,7 @@ wait_finish() ->
ok.
abort_current_testcase(Reason) ->
- controller_call({abort_current_testcase,Reason}),
- ok.
+ controller_call({abort_current_testcase,Reason}).
abort() ->
OldTrap = process_flag(trap_exit, true),
@@ -520,9 +407,11 @@ cover(App, Analyse) when is_atom(App) ->
cover(CoverFile, Analyse) ->
cover(none, CoverFile, Analyse).
cover(App, CoverFile, Analyse) ->
- controller_call({cover,{App,CoverFile},Analyse}).
-cover(App, CoverFile, Exclude, Include, Cross, Export, Analyse) ->
- controller_call({cover,{App,{CoverFile,Exclude,Include,Cross,Export}},Analyse}).
+ controller_call({cover,{App,CoverFile},Analyse,true}).
+cover(App, CoverFile, Exclude, Include, Cross, Export, Analyse, Stop) ->
+ controller_call({cover,
+ {App,{CoverFile,Exclude,Include,Cross,Export}},
+ Analyse,Stop}).
testcase_callback(ModFunc) ->
controller_call({testcase_callback,ModFunc}).
@@ -536,20 +425,6 @@ kill_slavenodes() ->
get_hosts() ->
get(test_server_hosts).
-get_target_os_type() ->
- case whereis(?MODULE) of
- undefined ->
- %% This is probably called on the target node
- os:type();
- Pid when Pid =:= self() ->
- os:type();
- _pid ->
- %% This is called on the controller, e.g. from a
- %% specification clause of a test case
- #target_info{os_type=OsType} = controller_call(get_target_info),
- OsType
- end.
-
%%--------------------------------------------------------------------
add_job(Name, TopCase) ->
@@ -605,7 +480,7 @@ controller_call(Arg, Timeout) ->
%% Mode 'lazy' ignores (and resets to []) any jobs in the state file
%%
-init([Param]) ->
+init([_]) ->
case os:getenv("TEST_SERVER_CALL_TRACE") of
false ->
ok;
@@ -631,104 +506,14 @@ init([Param]) ->
test_server_sup:cleanup_crash_dumps(),
State = #state{jobs=[],finish=false},
put(test_server_free_targets,[]),
- case contact_main_target(Param) of
- {ok,TI} ->
- ets:new(slave_tab, [named_table,set,public,{keypos,2}]),
- set_hosts([TI#target_info.host]),
- {ok,State#state{target_info=TI}};
- {error,Reason} ->
- {stop,Reason}
- end.
-
-
-%% If the test is to be run at a remote target, this function sets up
-%% a socket communication with the target.
-contact_main_target(local) ->
- %% When used by a general framework, global registration of
- %% test_server should not be required.
- case get_fw_mod(undefined) of
- undefined ->
- %% Local target! The global test_server process implemented by
- %% test_server.erl will not be started, so we simulate it by
- %% globally registering this process instead.
- global:sync(),
- case global:whereis_name(test_server) of
- undefined ->
- global:register_name(test_server, self());
- Pid ->
- case node() of
- N when N == node(Pid) ->
- io:format(user, "Warning: test_server already running!\n", []),
- global:re_register_name(test_server,self());
- _ ->
- ok
- end
- end;
- _ ->
- ok
- end,
- TI = test_server:init_target_info(),
+ TI0 = test_server:init_target_info(),
TargetHost = test_server_sup:hoststr(),
- {ok,TI#target_info{where=local,
- host=TargetHost,
- naming=naming(),
- master=TargetHost}};
-
-contact_main_target(ParameterFile) ->
- case read_parameters(ParameterFile) of
- {ok,Par} ->
- case test_server_node:start_remote_main_target(Par) of
- {ok,TI} ->
- {ok,TI};
- {error,Error} ->
- {error,{could_not_start_main_target,Error}}
- end;
- {error,Error} ->
- {error,{could_not_read_parameterfile,Error}}
- end.
-
-read_parameters(File) ->
- case file:consult(File) of
- {ok,Data} ->
- read_parameters(lists:flatten(Data), #par{naming=naming()});
- Error ->
- Error
- end.
-read_parameters([{type,Type}|Data], Par) -> % mandatory
- read_parameters(Data, Par#par{type=Type});
-read_parameters([{target,Target}|Data], Par) -> % mandatory
- read_parameters(Data, Par#par{target=cast_to_list(Target)});
-read_parameters([{slavetargets,SlaveTargets}|Data], Par) ->
- read_parameters(Data, Par#par{slave_targets=SlaveTargets});
-read_parameters([{longnames,Bool}|Data], Par) ->
- Naming = if Bool->"-name"; true->"-sname" end,
- read_parameters(Data, Par#par{naming=Naming});
-read_parameters([{master,{Node,Cookie}}|Data], Par) ->
- read_parameters(Data, Par#par{master=cast_to_list(Node),
- cookie=cast_to_list(Cookie)});
-read_parameters([Other|_Data], _Par) ->
- {error,{illegal_parameter,Other}};
-read_parameters([], Par) when Par#par.type==undefined ->
- {error, {missing_mandatory_parameter,type}};
-read_parameters([], Par) when Par#par.target==undefined ->
- {error, {missing_mandatory_parameter,target}};
-read_parameters([], Par0) ->
- Par =
- case {Par0#par.type, Par0#par.master} of
- {ose, undefined} ->
- %% Use this node as master and bootserver for target
- %% and slave nodes
- Par0#par{master = atom_to_list(node()),
- cookie = atom_to_list(erlang:get_cookie())};
- {ose, _Master} ->
- %% Master for target and slave nodes was defined in parameterfile
- Par0;
- _ ->
- %% Use target as master for slave nodes,
- %% (No master is used for target)
- Par0#par{master="test_server@" ++ Par0#par.target}
- end,
- {ok,Par}.
+ TI = TI0#target_info{host=TargetHost,
+ naming=naming(),
+ master=TargetHost},
+ ets:new(slave_tab, [named_table,set,public,{keypos,2}]),
+ set_hosts([TI#target_info.host]),
+ {ok,State#state{target_info=TI}}.
naming() ->
case lists:member($., test_server_sup:hoststr()) of
@@ -795,7 +580,7 @@ handle_call({add_job,Dir,Name,TopCase,Skip}, _From, State) ->
ExtraTools =
case State#state.cover of
false -> [];
- {App,Analyse} -> [{cover,App,Analyse}]
+ {App,Analyse,Stop} -> [{cover,App,Analyse,Stop}]
end,
ExtraTools1 =
case State#state.random_seed of
@@ -1051,13 +836,13 @@ handle_call(stop_trace, _From, State) ->
{reply,R,State#state{trc=false}};
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% handle_call({cover,App,Analyse}, _, State) -> ok | {error,Reason}
+%% handle_call({cover,App,Analyse,Stop}, _, State) -> ok | {error,Reason}
%%
%% All modules inn application App are cover compiled
%% Analyse indicates on which level the coverage should be analysed
-handle_call({cover,App,Analyse}, _From, State) ->
- {reply,ok,State#state{cover={App,Analyse}}};
+handle_call({cover,App,Analyse,Stop}, _From, State) ->
+ {reply,ok,State#state{cover={App,Analyse,Stop}}};
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% handle_call({create_priv_dir,Value}, _, State) -> ok | {error,Reason}
@@ -1209,25 +994,17 @@ handle_cast({node_started,Node}, State) ->
%% Pid = pid()
%% Reason = term()
%%
-%% Handles exit messages from linked processes. Only test suites and
-%% possibly a target client are expected to be linked.
-%% When a test suite terminates, it is removed from the job queue.
-%% If a target client terminates it means that we lost contact with
-%% target. The test_server_ctrl process is terminated, and teminate/2
-%% will do the cleanup
+%% Handles exit messages from linked processes. Only test suites are
+%% expected to be linked. When a test suite terminates, it is removed
+%% from the job queue. If a target client terminates it means that we
+%% lost contact with target. The test_server_ctrl process is
+%% terminated, and teminate/2 will do the cleanup
handle_info({'EXIT',Pid,Reason}, State) ->
case lists:keysearch(Pid,2,State#state.jobs) of
false ->
- TI = State#state.target_info,
- case TI#target_info.target_client of
- Pid ->
- %% The target client died - lost contact with target
- {stop,{lost_contact_with_target,Reason},State};
- _other ->
- %% not our problem
- {noreply,State}
- end;
+ %% not our problem
+ {noreply,State};
{value,{Name,_}} ->
NewJobs = lists:keydelete(Pid, 2, State#state.jobs),
case Reason of
@@ -1302,14 +1079,8 @@ handle_info({tcp_closed,Sock}, State=#state{trc=Sock}) ->
%%! Maybe print something???
{noreply,State#state{trc=false}};
handle_info({tcp_closed,Sock}, State) ->
- case test_server_node:nodedown(Sock,State#state.target_info) of
- target_died ->
- %% terminate/2 will do the cleanup
- {stop,target_died,State};
- _ ->
- {noreply,State}
- end;
-
+ test_server_node:nodedown(Sock, State#state.target_info),
+ {noreply,State};
handle_info(_, State) ->
%% dummy; accept all, do nothing.
{noreply, State}.
@@ -1370,24 +1141,22 @@ kill_all_jobs([]) ->
spawn_tester(Mod, Func, Args, Dir, Name, Levels, RejectIoReqs,
CreatePrivDir, TCCallback, ExtraTools) ->
- spawn_link(
- fun() -> init_tester(Mod, Func, Args, Dir, Name, Levels, RejectIoReqs,
+ spawn_link(fun() ->
+ init_tester(Mod, Func, Args, Dir, Name, Levels, RejectIoReqs,
CreatePrivDir, TCCallback, ExtraTools)
end).
-init_tester(Mod, Func, Args, Dir, Name, {SumLev,MajLev,MinLev}, RejectIoReqs,
- CreatePrivDir, TCCallback, ExtraTools) ->
+init_tester(Mod, Func, Args, Dir, Name, {_,_,MinLev}=Levels,
+ RejectIoReqs, CreatePrivDir, TCCallback, ExtraTools) ->
process_flag(trap_exit, true),
+ test_server_io:start_link(),
put(test_server_name, Name),
put(test_server_dir, Dir),
put(test_server_total_time, 0),
put(test_server_ok, 0),
put(test_server_failed, 0),
put(test_server_skipped, {0,0}),
- put(test_server_summary_level, SumLev),
- put(test_server_major_level, MajLev),
put(test_server_minor_level, MinLev),
- put(test_server_reject_io_reqs, RejectIoReqs),
put(test_server_create_priv_dir, CreatePrivDir),
put(test_server_random_seed, proplists:get_value(random_seed, ExtraTools)),
put(test_server_testcase_callback, TCCallback),
@@ -1403,24 +1172,30 @@ init_tester(Mod, Func, Args, Dir, Name, {SumLev,MajLev,MinLev}, RejectIoReqs,
put(test_server_framework_name, list_to_atom(FWName))
end
end,
+
%% before first print, read and set logging options
LogOpts = test_server_sup:framework_call(get_logopts, [], []),
put(test_server_logopts, LogOpts),
- put(test_server_log_nl, not lists:member(no_nl, LogOpts)),
+
StartedExtraTools = start_extra_tools(ExtraTools),
+
+ test_server_io:set_job_name(Name),
+ test_server_io:set_gl_props([{levels,Levels},
+ {auto_nl,not lists:member(no_nl, LogOpts)},
+ {reject_io_reqs,RejectIoReqs}]),
+ group_leader(test_server_io:get_gl(true), self()),
{TimeMy,Result} = ts_tc(Mod, Func, Args),
- put(test_server_common_io_handler, undefined),
+ set_io_buffering(undefined),
+ test_server_io:set_job_name(undefined),
catch stop_extra_tools(StartedExtraTools),
case Result of
{'EXIT',test_suites_done} ->
- print(25, "DONE, normal exit", []);
+ ok;
{'EXIT',_Pid,Reason} ->
print(1, "EXIT, reason ~p", [Reason]);
{'EXIT',Reason} ->
report_severe_error(Reason),
- print(1, "EXIT, reason ~p", [Reason]);
- _Other ->
- print(25, "DONE", [])
+ print(1, "EXIT, reason ~p", [Reason])
end,
Time = TimeMy/1000000,
SuccessStr =
@@ -1439,7 +1214,8 @@ init_tester(Mod, Func, Args, Dir, Name, {SumLev,MajLev,MinLev}, RejectIoReqs,
"<tr><td></td><td><b>TOTAL</b></td><td></td><td></td><td></td>"
"<td>~.3fs</td><td><b>~s</b></td><td>~p Ok, ~p Failed~s of ~p</td></tr>\n"
"</tfoot>\n",
- [Time,SuccessStr,OkN,FailedN,SkipStr,OkN+FailedN+SkippedN]).
+ [Time,SuccessStr,OkN,FailedN,SkipStr,OkN+FailedN+SkippedN]),
+ test_server_io:stop().
report_severe_error(Reason) ->
test_server_sup:framework_call(report, [severe_error,Reason]).
@@ -1460,11 +1236,11 @@ elapsed_time(Before, After) ->
start_extra_tools(ExtraTools) ->
start_extra_tools(ExtraTools, []).
-start_extra_tools([{cover,App,Analyse} | ExtraTools], Started) ->
+start_extra_tools([{cover,App,Analyse,Stop} | ExtraTools], Started) ->
case cover_compile(App) of
{ok,AnalyseMods} ->
start_extra_tools(ExtraTools,
- [{cover,App,Analyse,AnalyseMods}|Started]);
+ [{cover,App,Analyse,AnalyseMods,Stop}|Started]);
{error,_} ->
start_extra_tools(ExtraTools, Started)
end;
@@ -1483,8 +1259,8 @@ stop_extra_tools(ExtraTools) ->
end,
stop_extra_tools(ExtraTools, TestDir).
-stop_extra_tools([{cover,App,Analyse,AnalyseMods}|ExtraTools], TestDir) ->
- cover_analyse(App, Analyse, AnalyseMods, TestDir),
+stop_extra_tools([{cover,App,Analyse,AnalyseMods,Stop}|ExtraTools], TestDir) ->
+ cover_analyse(App, Analyse, AnalyseMods, Stop, TestDir),
stop_extra_tools(ExtraTools, TestDir);
%%stop_extra_tools([_ | ExtraTools], TestDir) ->
%% stop_extra_tools(ExtraTools, TestDir);
@@ -1816,8 +1592,9 @@ do_test_cases(TopCases, SkipCases,
print(html,
"<p><ul>\n"
"<li><a href=\"~s\">Full textual log</a></li>\n"
- "<li><a href=\"~s\">Coverage log</a></li>\n</ul></p>\n",
- [?suitelog_name,?coverlog_name]),
+ "<li><a href=\"~s\">Coverage log</a></li>\n"
+ "<li><a href=\"~s\">Unexpected I/O log</a></li>\n</ul></p>\n",
+ [?suitelog_name,?coverlog_name,?unexpected_io_log]),
print(html,
"<p>~s</p>\n" ++
xhtml("<table bgcolor=\"white\" border=\"3\" cellpadding=\"5\">",
@@ -1902,10 +1679,16 @@ start_log_file() ->
put(test_server_log_dir_base,TestDir1),
MajorName = filename:join(TestDir1, ?suitelog_name),
HtmlName = MajorName ++ ?html_ext,
+ UnexpectedName = filename:join(TestDir1, ?unexpected_io_log),
{ok,Major} = file:open(MajorName, [write]),
{ok,Html} = file:open(HtmlName, [write]),
+ {ok,Unexpected} = file:open(UnexpectedName, [write]),
+ test_server_io:set_fd(major, Major),
+ test_server_io:set_fd(html, Html),
+ test_server_io:set_fd(unexpected_io, Unexpected),
put(test_server_major_fd,Major),
put(test_server_html_fd,Html),
+ put(test_server_unexpected_io, Unexpected),
make_html_link(filename:absname(?last_test ++ ?html_ext),
HtmlName, filename:basename(Dir)),
@@ -1916,7 +1699,7 @@ start_log_file() ->
PrivDir = filename:join(TestDir1, ?priv_dir),
ok = file:make_dir(PrivDir),
put(test_server_priv_dir,PrivDir++"/"),
- print_timestamp(13,"Suite started at "),
+ print_timestamp(major, "Suite started at "),
LogInfo = [{topdir,Dir},{rundir,lists:flatten(TestDir1)}],
test_server_sup:framework_call(report, [loginfo,LogInfo]),
@@ -1958,13 +1741,14 @@ make_html_link(LinkName, Target, Explanation) ->
%% Some header info will also be inserted into the log file.
start_minor_log_file(Mod, Func) ->
+ MFA = {Mod,Func,1},
LogDir = get(test_server_log_dir_base),
Name0 = lists:flatten(io_lib:format("~s.~s~s", [Mod,Func,?html_ext])),
Name = downcase(Name0),
AbsName = filename:join(LogDir, Name),
case file:read_file_info(AbsName) of
{error,_} -> %% normal case, unique name
- start_minor_log_file1(Mod, Func, LogDir, AbsName);
+ start_minor_log_file1(Mod, Func, LogDir, AbsName, MFA);
{ok,_} -> %% special case, duplicate names
{_,S,Us} = now(),
Name1_0 =
@@ -1973,14 +1757,15 @@ start_minor_log_file(Mod, Func) ->
?html_ext])),
Name1 = downcase(Name1_0),
AbsName1 = filename:join(LogDir, Name1),
- start_minor_log_file1(Mod, Func, LogDir, AbsName1)
+ start_minor_log_file1(Mod, Func, LogDir, AbsName1, MFA)
end.
-start_minor_log_file1(Mod, Func, LogDir, AbsName) ->
+start_minor_log_file1(Mod, Func, LogDir, AbsName, MFA) ->
{ok,Fd} = file:open(AbsName, [write]),
Lev = get(test_server_minor_level)+1000, %% far down in the minor levels
put(test_server_minor_fd, Fd),
-
+ test_server_gl:set_minor_fd(group_leader(), Fd, MFA),
+
TestDescr = io_lib:format("Test ~p:~p result", [Mod,Func]),
{Header,Footer} =
case test_server_sup:framework_call(get_html_wrapper,
@@ -2013,7 +1798,7 @@ start_minor_log_file1(Mod, Func, LogDir, AbsName) ->
lists:member(no_src, get(test_server_logopts))} of
{true,false} ->
print(Lev, "<a href=\"~s#~s\">source code for ~p:~p/1</a>\n",
- [SrcListing,Func,Mod,Func]);
+ [SrcListing,atom_to_list(Func)++"-1",Mod,Func]);
_ -> ok
end,
@@ -2028,6 +1813,7 @@ start_minor_log_file1(Mod, Func, LogDir, AbsName) ->
AbsName.
stop_minor_log_file() ->
+ test_server_gl:unset_minor_fd(group_leader()),
Fd = get(test_server_minor_fd),
Footer = get(test_server_minor_footer),
io:fwrite(Fd, "</pre>\n" ++ Footer, []),
@@ -2303,9 +2089,7 @@ do_add_end_per_suite_and_skip(LastMod, LastRef, Mod, FwMod) ->
%% Runs the specified tests, then displays/logs the summary.
run_test_cases(TestSpec, Config, TimetrapData) ->
-
- maybe_open_job_sock(),
-
+ test_server:init_purify(),
case lists:member(no_src, get(test_server_logopts)) of
true ->
ok;
@@ -2315,8 +2099,6 @@ run_test_cases(TestSpec, Config, TimetrapData) ->
run_test_cases_loop(TestSpec, [Config], TimetrapData, [], []),
- maybe_get_privdir(),
-
{AllSkippedN,UserSkipN,AutoSkipN,SkipStr} =
case get(test_server_skipped) of
{0,0} -> {0,0,0,""};
@@ -2335,41 +2117,6 @@ run_test_cases(TestSpec, Config, TimetrapData) ->
print(major, "=auto_skipped ~p", [AutoSkipN]),
exit(test_suites_done).
-%% If the test is run at a remote target, this function sets up a socket
-%% communication with the target for handling this particular job.
-maybe_open_job_sock() ->
- TI = get_target_info(),
- case TI#target_info.where of
- local ->
- %% local target
- test_server:init_purify();
- MainSock ->
- %% remote target
- {ok,LSock} = gen_tcp:listen(0, [binary,
- {reuseaddr,true},
- {packet,4},
- {active,false}]),
- {ok,Port} = inet:port(LSock),
- request(MainSock, {job,Port,get(test_server_name)}),
- case gen_tcp:accept(LSock, ?ACCEPT_TIMEOUT) of
- {ok,Sock} -> put(test_server_ctrl_job_sock, Sock);
- {error,Reason} -> exit({no_contact,Reason})
- end
- end.
-
-%% If the test is run at a remote target, this function waits for a
-%% tar packet containing the privdir created by the test case.
-maybe_get_privdir() ->
- case get(test_server_ctrl_job_sock) of
- undefined ->
- %% local target
- ok;
- Sock ->
- %% remote target
- request(Sock, job_done),
- gen_tcp:close(Sock)
- end.
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% run_test_cases_loop(TestCases, Config, TimetrapData, Mode, Status) -> ok
@@ -2448,27 +2195,38 @@ maybe_get_privdir() ->
%% reason, the Mode argument specifies if a parallel group is currently
%% being executed.
%%
-%% A parallel test case process will always set the dictionary value
-%% 'test_server_common_io_handler' to the pid of the main (starting)
-%% process. With this value set, the print/3 function will send print
-%% messages to the main process instead of writing the data to file
-%% (only true for printouts to common log files).
+%% The low-level mechanism for buffering IO for the common log files
+%% is handled by the test_server_io module. Buffering is turned on by
+%% test_server_io:start_transaction/0 and off by calling
+%% test_server_io:end_transaction/0. The buffered data for the transaction
+%% can printed by calling test_server_io:print_buffered/1.
+%%
+%% This module is responsible for turning on IO buffering and to later
+%% test_server_io:print_buffered/1 to print the data. To help with this,
+%% two variables in the process dictionary are used:
+%% 'test_server_common_io_handler' and 'test_server_queued_io'. The values
+%% are set to as follwing:
+%%
+%% Value Meaning
+%% ----- -------
+%% undefined No parallel test cases running
+%% {tc,Pid} Running test cases in a top-level parallel group
+%% {Ref,Pid} Running sequential test case inside a parallel group
+%%
+%% FIXME: The Pid is no longer used.
%%
%% If a conf group nested under a parallel group in the test
%% specification should be started, the 'test_server_common_io_handler'
-%% value gets set also on the main process. This causes all printouts
-%% to common files - both from parallel test cases and from cases
-%% executed by the main process - to all end up as messages in the
-%% inbox of the main process.
+%% value gets set also on the main process.
%%
%% During execution of a parallel group (or of a group nested under a
%% parallel group), *any* new test case being started gets registered
%% in a list saved in the dictionary with 'test_server_queued_io' as key.
%% When the top level parallel group is finished (only then can we be
%% sure all parallel test cases have finished and "reported in"), the
-%% list of test cases is traversed in order and printout messages from
-%% each process - including the main process - are handled in turn. See
-%% handle_test_case_io_and_status/0 for details.
+%% list of test cases is traversed in order and test_server_io:print_buffered/1
+%% can be called for each test case. See handle_test_case_io_and_status/0
+%% for details.
%%
%% To be able to handle nested conf groups with different properties,
%% the Mode argument specifies a list of {Ref,Properties} tuples.
@@ -2521,7 +2279,7 @@ run_test_cases_loop([{auto_skip_case,{Type,Ref,Case,Comment},SkipMode}|Cases],
set_io_buffering(undefined),
{Mod,Func} = skip_case(auto, Ref, 0, Case, Comment, false, SkipMode),
test_server_sup:framework_call(report, [tc_auto_skip,
- {?pl2a(Mod),Func,Comment}]),
+ {Mod,Func,Comment}]),
run_test_cases_loop(Cases, Config, TimetrapData, ParentMode,
delete_status(Ref, Status));
_ ->
@@ -2530,7 +2288,7 @@ run_test_cases_loop([{auto_skip_case,{Type,Ref,Case,Comment},SkipMode}|Cases],
wait_for_cases(Ref),
{Mod,Func} = skip_case(auto, Ref, 0, Case, Comment, true, SkipMode),
test_server_sup:framework_call(report, [tc_auto_skip,
- {?pl2a(Mod),Func,Comment}]),
+ {Mod,Func,Comment}]),
case CurrIOHandler of
{Ref,_} ->
%% current_io_handler was set by start conf of this
@@ -2547,7 +2305,7 @@ run_test_cases_loop([{auto_skip_case,{Type,Ref,Case,Comment},SkipMode}|Cases],
%% this is a skipped end conf for a non-parallel group that's not
%% nested under a parallel group
{Mod,Func} = skip_case(auto, Ref, 0, Case, Comment, false, SkipMode),
- test_server_sup:framework_call(report, [tc_auto_skip,{?pl2a(Mod),Func,Comment}]),
+ test_server_sup:framework_call(report, [tc_auto_skip,{Mod,Func,Comment}]),
%% Check if this group is auto skipped because of error in the init conf.
%% If so, check if the parent group is a sequence, and if it is, skip
@@ -2578,7 +2336,7 @@ run_test_cases_loop([{auto_skip_case,{Type,Ref,Case,Comment},SkipMode}|Cases],
%% this is a skipped end conf for a non-parallel group nested under
%% a parallel group (io buffering is active)
{Mod,Func} = skip_case(auto, Ref, 0, Case, Comment, true, SkipMode),
- test_server_sup:framework_call(report, [tc_auto_skip,{?pl2a(Mod),Func,Comment}]),
+ test_server_sup:framework_call(report, [tc_auto_skip,{Mod,Func,Comment}]),
case CurrIOHandler of
{Ref,_} ->
%% current_io_handler was set by start conf of this
@@ -2594,7 +2352,7 @@ run_test_cases_loop([{auto_skip_case,{Type,Ref,Case,Comment},SkipMode}|Cases],
%% this is a skipped start conf for a group which is not nested
%% under a parallel group
{Mod,Func} = skip_case(auto, Ref, 0, Case, Comment, false, SkipMode),
- test_server_sup:framework_call(report, [tc_auto_skip,{?pl2a(Mod),Func,Comment}]),
+ test_server_sup:framework_call(report, [tc_auto_skip,{Mod,Func,Comment}]),
run_test_cases_loop(Cases, Config, TimetrapData, [conf(Ref,[])|Mode], Status);
{_,Ref0} when is_reference(Ref0) ->
%% this is a skipped start conf for a group nested under a parallel group
@@ -2605,22 +2363,21 @@ run_test_cases_loop([{auto_skip_case,{Type,Ref,Case,Comment},SkipMode}|Cases],
ok
end,
{Mod,Func} = skip_case(auto, Ref, 0, Case, Comment, true, SkipMode),
- test_server_sup:framework_call(report, [tc_auto_skip,{?pl2a(Mod),Func,Comment}]),
+ test_server_sup:framework_call(report, [tc_auto_skip,{Mod,Func,Comment}]),
run_test_cases_loop(Cases, Config, TimetrapData, [conf(Ref,[])|Mode], Status)
end;
run_test_cases_loop([{auto_skip_case,{Case,Comment},SkipMode}|Cases],
Config, TimetrapData, Mode, Status) ->
- {Mod,Func} = skip_case(auto, undefined, get(test_server_case_num)+1, Case, Comment,
- (undefined /= get(test_server_common_io_handler)), SkipMode),
- test_server_sup:framework_call(report, [tc_auto_skip,{?pl2a(Mod),Func,Comment}]),
+ {Mod,Func} = skip_case(auto, undefined, get(test_server_case_num)+1,
+ Case, Comment, is_io_buffered(), SkipMode),
+ test_server_sup:framework_call(report, [tc_auto_skip,{Mod,Func,Comment}]),
run_test_cases_loop(Cases, Config, TimetrapData, Mode,
update_status(skipped, Mod, Func, Status));
run_test_cases_loop([{skip_case,{conf,Ref,Case,Comment}}|Cases0],
Config, TimetrapData, Mode, Status) ->
- {Mod,Func} = skip_case(user, Ref, 0, Case, Comment,
- (undefined /= get(test_server_common_io_handler))),
+ {Mod,Func} = skip_case(user, Ref, 0, Case, Comment, is_io_buffered()),
{Cases,Config1} =
case curr_ref(Mode) of
Ref ->
@@ -2630,15 +2387,15 @@ run_test_cases_loop([{skip_case,{conf,Ref,Case,Comment}}|Cases0],
%% skipped start conf
{skip_cases_upto(Ref, Cases0, Comment, conf, Mode),Config}
end,
- test_server_sup:framework_call(report, [tc_user_skip,{?pl2a(Mod),Func,Comment}]),
+ test_server_sup:framework_call(report, [tc_user_skip,{Mod,Func,Comment}]),
run_test_cases_loop(Cases, Config1, TimetrapData, Mode,
update_status(skipped, Mod, Func, Status));
run_test_cases_loop([{skip_case,{Case,Comment}}|Cases],
Config, TimetrapData, Mode, Status) ->
- {Mod,Func} = skip_case(user, undefined, get(test_server_case_num)+1, Case, Comment,
- (undefined /= get(test_server_common_io_handler))),
- test_server_sup:framework_call(report, [tc_user_skip,{?pl2a(Mod),Func,Comment}]),
+ {Mod,Func} = skip_case(user, undefined, get(test_server_case_num)+1,
+ Case, Comment, is_io_buffered()),
+ test_server_sup:framework_call(report, [tc_user_skip,{Mod,Func,Comment}]),
run_test_cases_loop(Cases, Config, TimetrapData, Mode,
update_status(skipped, Mod, Func, Status));
@@ -2874,7 +2631,7 @@ run_test_cases_loop([{conf,Ref,Props,{Mod,Func}}|_Cases]=Cs0,
end,
CurrMode = curr_mode(Ref, Mode0, Mode),
- ConfCaseResult = run_test_case(Ref, 0, Mod, Func, [ActualCfg], skip_init, target,
+ ConfCaseResult = run_test_case(Ref, 0, Mod, Func, [ActualCfg], skip_init,
TimetrapData, CurrMode),
case ConfCaseResult of
@@ -2908,6 +2665,7 @@ run_test_cases_loop([{conf,Ref,Props,{Mod,Func}}|_Cases]=Cs0,
exit(framework_error);
{_,Fail,_} when element(1,Fail) == 'EXIT';
element(1,Fail) == timetrap_timeout;
+ element(1,Fail) == user_timetrap_error;
element(1,Fail) == failed ->
{Cases2,Config1,Status3} =
if StartConf ->
@@ -2927,14 +2685,6 @@ run_test_cases_loop([{conf,Ref,Props,{Mod,Func}}|_Cases]=Cs0,
set_io_buffering(IOHandler),
stop_minor_log_file(),
run_test_cases_loop(Cases2, Config1, TimetrapData, Mode, Status3);
- {died,Why,_} when Func == init_per_suite ->
- print(minor, "~n*** Unexpected exit during init_per_suite.~n", []),
- Reason = {failed,{Mod,init_per_suite,Why}},
- Cases2 = skip_cases_upto(Ref, Cases, Reason, conf, CurrMode),
- set_io_buffering(IOHandler),
- stop_minor_log_file(),
- run_test_cases_loop(Cases2, Config, TimetrapData, Mode,
- delete_status(Ref, Status2));
{_,{Skip,Reason},_} when StartConf and ((Skip==skip) or (Skip==skipped)) ->
ReportAbortRepeat(skipped),
print(minor, "~n*** ~p skipped.~n"
@@ -3005,7 +2755,7 @@ run_test_cases_loop([{conf,Ref,Props,{Mod,Func}}|_Cases]=Cs0,
end;
run_test_cases_loop([{make,Ref,{Mod,Func,Args}}|Cases0], Config, TimetrapData, Mode, Status) ->
- case run_test_case(Ref, 0, Mod, Func, Args, skip_init, host, TimetrapData) of
+ case run_test_case(Ref, 0, Mod, Func, Args, skip_init, TimetrapData) of
{_,Why={'EXIT',_},_} ->
print(minor, "~n*** ~p failed.~n"
" Skipping all cases.", [Func]),
@@ -3036,23 +2786,21 @@ run_test_cases_loop([{Mod,Case}|Cases], Config, TimetrapData, Mode, Status) ->
run_test_cases_loop([{Mod,Func,Args}|Cases], Config, TimetrapData, Mode, Status) ->
Num = put(test_server_case_num, get(test_server_case_num)+1),
+
%% check the current execution mode and save info about the case if
%% detected that printouts to common log files is handled later
- case check_prop(parallel, Mode) of
+
+ case check_prop(parallel, Mode) =:= false andalso is_io_buffered() of
+ true ->
+ %% sequential test case nested in a parallel group;
+ %% io is buffered, so we must queue this test case
+ queue_test_case_io(undefined, self(), Num+1, Mod, Func);
false ->
- case get(test_server_common_io_handler) of
- undefined ->
- %% io printouts are written to straight to file
- ok;
- _ ->
- %% io messages are buffered, put test case in queue
- queue_test_case_io(undefined, self(), Num+1, Mod, Func)
- end;
- _ ->
ok
end,
+
case run_test_case(undefined, Num+1, Mod, Func, Args,
- run_init, target, TimetrapData, Mode) of
+ run_init, TimetrapData, Mode) of
%% callback to framework module failed, exit immediately
{_,{framework_error,{FwMod,FwFunc},Reason},_} ->
print(minor, "~n*** ~p failed in ~p. Reason: ~p~n", [FwMod,FwFunc,Reason]),
@@ -3099,8 +2847,8 @@ run_test_cases_loop([{Mod,Func,Args}|Cases], Config, TimetrapData, Mode, Status)
%% the test case is being executed in parallel with the main process (and
%% other test cases) and Pid is the dedicated process executing the case
Pid ->
- %% io from Pid will be buffered in the main process inbox and handled
- %% later, so we have to save info about the case
+ %% io from Pid will be buffered by the test_server_io process and
+ %% handled later, so we have to save info about the case
queue_test_case_io(undefined, Pid, Num+1, Mod, Func),
run_test_cases_loop(Cases, Config, TimetrapData, Mode, Status)
end;
@@ -3207,11 +2955,17 @@ get_data_dir(Mod, Suite) ->
non_existing ->
print(12, "The module ~p is not loaded", [Mod]),
[];
+ cover_compiled ->
+ MainCoverNode = cover:get_main_node(),
+ {file,File} = rpc:call(MainCoverNode,cover,is_compiled,[UseMod]),
+ do_get_data_dir(UseMod,File);
FullPath ->
- filename:dirname(FullPath) ++ "/" ++ cast_to_list(UseMod) ++
- ?data_dir_suffix
+ do_get_data_dir(UseMod,FullPath)
end.
+do_get_data_dir(Mod,File) ->
+ filename:dirname(File) ++ "/" ++ cast_to_list(Mod) ++ ?data_dir_suffix.
+
print_conf_time(0) ->
ok;
print_conf_time(ConfTime) ->
@@ -3355,7 +3109,9 @@ skip_case(Type, Ref, CaseNum, Case, Comment, SendSync, Mode) ->
if SendSync ->
queue_test_case_io(Ref, self(), CaseNum, Mod, Func),
self() ! {started,Ref,self(),CaseNum,Mod,Func},
+ test_server_io:start_transaction(),
skip_case1(Type, CaseNum, Mod, Func, Comment, Mode),
+ test_server_io:end_transaction(),
self() ! {finished,Ref,self(),CaseNum,Mod,Func,skipped,{0,skipped,[]}};
not SendSync ->
skip_case1(Type, CaseNum, Mod, Func, Comment, Mode)
@@ -3496,13 +3252,20 @@ modify_cases_upto1(Ref, CopyOp, [C|T], Orig, Alt) ->
%%
%% Save info about current process (always the main process) buffering
%% io printout messages from parallel test case processes (*and* possibly
-%% also the main process). If the value is the default 'undefined',
-%% io is not buffered but printed directly to file (see print/3).
+%% also the main process).
set_io_buffering(IOHandler) ->
put(test_server_common_io_handler, IOHandler).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% is_io_buffered() -> true|false
+%%
+%% Test whether is being buffered.
+
+is_io_buffered() ->
+ get(test_server_common_io_handler) =/= undefined.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% queue_test_case_io(Pid, Num, Mod, Func) -> ok
%%
%% Save info about test case that gets its io buffered. This can
@@ -3549,7 +3312,7 @@ wait_and_resend(Ref, [{_,CurrPid,CaseNum,Mod,Func}|Ps] = Cases, Ok,Skip,Fail) ->
receive
{finished,_Ref,CurrPid,CaseNum,Mod,Func,Result,_RetVal} = Msg ->
%% resend message to main process so that it can be used
- %% to handle buffered io messages later
+ %% to test_server_io:print_buffered/1 later
self() ! Msg,
MF = {Mod,Func},
{Ok1,Skip1,Fail1} =
@@ -3580,16 +3343,18 @@ rm_cases_upto(Ref, [_|Ps]) ->
%%
%% Each parallel test case process prints to its own minor log file during
%% execution. The common log files (major, html etc) must however be
-%% written to sequentially. The test case processes send print requests
-%% to the main (starting) process (the same process executing
-%% run_test_cases_loop/4), which handles these requests in the same
-%% order that the test case processes were started.
-%%
-%% An io session is always started with a {started,Ref,Pid,Num,Mod,Func}
-%% message and terminated with {finished,Ref,Pid,Num,Mod,Func,Result,RetVal}.
-%% The result shipped with the finished message from a parallel process
-%% is used to update status data of the current test run. An 'EXIT'
-%% message from each parallel test case process (after finishing and
+%% written to sequentially. This is handled by calling
+%% test_server_io:start_transaction/0 to tell the test_server_io process
+%% to buffer all print requests.
+%%
+%% An io session is always started with a
+%% {started,Ref,Pid,Num,Mod,Func} message (and
+%% test_server_io:start_transaction/0 will be called) and terminated
+%% with {finished,Ref,Pid,Num,Mod,Func,Result,RetVal} (and
+%% test_server_io:end_transaction/0 will be called). The result
+%% shipped with the finished message from a parallel process is used
+%% to update status data of the current test run. An 'EXIT' message
+%% from each parallel test case process (after finishing and
%% terminating) is also received and handled here.
%%
%% During execution of a parallel group, any cases (conf or normal)
@@ -3598,13 +3363,13 @@ rm_cases_upto(Ref, [_|Ps]) ->
%% correct sequence. This function handles also the print messages
%% generated by nested group cases that have been executed sequentially
%% by the main process (note that these cases do not generate 'EXIT'
-%% messages, only 'start', 'print' and 'finished' messages).
+%% messages, only 'start' and 'finished' messages).
%%
%% See the header comment for run_test_cases_loop/4 for more
%% info about IO handling.
%%
%% Note: It is important that the type of messages handled here
-%% do not get consumated by test_server:run_test_case_msgloop/5
+%% do not get consumed by test_server:run_test_case_msgloop/5
%% during the test case execution (e.g. in the catch clause of
%% the receive)!
@@ -3631,7 +3396,7 @@ handle_test_case_io_and_status() ->
%% Handle cases (without Ref) that belong to the top parallel group (i.e. when Refs = [])
handle_io_and_exit_loop([], [{undefined,CurrPid,CaseNum,Mod,Func}|Ps] = Cases, Ok,Skip,Fail) ->
- %% retreive the start message for the current io session (= testcase)
+ %% retrieve the start message for the current io session (= testcase)
receive
{started,_,CurrPid,CaseNum,Mod,Func} ->
{Ok1,Skip1,Fail1} =
@@ -3671,11 +3436,18 @@ handle_io_and_exit_loop(_, [], Ok,Skip,Fail) ->
handle_io_and_exits(Main, CurrPid, CaseNum, Mod, Func, Cases) ->
receive
+ {abort_current_testcase=Tag,_Reason,From} ->
+ %% If a parallel group is executing, there is no unique
+ %% current test case, so we must generate an error.
+ From ! {self(),Tag,{error,parallel_group}},
+ handle_io_and_exits(Main, CurrPid, CaseNum, Mod, Func, Cases);
%% end of io session from test case executed by main process
{finished,_,Main,CaseNum,Mod,Func,Result,_RetVal} ->
+ test_server_io:print_buffered(CurrPid),
{Result,{Mod,Func}};
%% end of io session from test case executed by parallel process
{finished,_,CurrPid,CaseNum,Mod,Func,Result,RetVal} ->
+ test_server_io:print_buffered(CurrPid),
case Result of
ok ->
put(test_server_ok, get(test_server_ok)+1);
@@ -3688,13 +3460,9 @@ handle_io_and_exits(Main, CurrPid, CaseNum, Mod, Func, Cases) ->
end,
{Result,{Mod,Func}};
- %% print to common log file
- {print,CurrPid,Detail,Msg} ->
- output({Detail,Msg}, internal),
- handle_io_and_exits(Main, CurrPid, CaseNum, Mod, Func, Cases);
-
%% unexpected termination of test case process
{'EXIT',TCPid,Reason} when Reason /= normal ->
+ test_server_io:print_buffered(CurrPid),
{value,{_,_,Num,M,F}} = lists:keysearch(TCPid, 2, Cases),
print(1, "Error! Process for test case #~p (~p:~p) died! Reason: ~p",
[Num, M, F, Reason]),
@@ -3726,59 +3494,52 @@ handle_io_and_exits(Main, CurrPid, CaseNum, Mod, Func, Cases) ->
%% RetVal is the result of executing the test case. It contains info
%% about the execution time and the return value of the test case function.
-run_test_case(Ref, Num, Mod, Func, Args, RunInit, Where, TimetrapData) ->
+run_test_case(Ref, Num, Mod, Func, Args, RunInit, TimetrapData) ->
file:set_cwd(filename:dirname(get(test_server_dir))),
- run_test_case1(Ref, Num, Mod, Func, Args, RunInit, Where,
- TimetrapData, [], [], self()).
+ run_test_case1(Ref, Num, Mod, Func, Args, RunInit,
+ TimetrapData, [], self()).
-run_test_case(Ref, Num, Mod, Func, Args, skip_init, Where, TimetrapData, Mode) ->
+run_test_case(Ref, Num, Mod, Func, Args, skip_init, TimetrapData, Mode) ->
%% a conf case is always executed by the main process
- run_test_case1(Ref, Num, Mod, Func, Args, skip_init, Where,
- TimetrapData, [], Mode, self());
+ run_test_case1(Ref, Num, Mod, Func, Args, skip_init,
+ TimetrapData, Mode, self());
-run_test_case(Ref, Num, Mod, Func, Args, RunInit, Where, TimetrapData, Mode) ->
+run_test_case(Ref, Num, Mod, Func, Args, RunInit, TimetrapData, Mode) ->
file:set_cwd(filename:dirname(get(test_server_dir))),
+ Main = self(),
case check_prop(parallel, Mode) of
false ->
%% this is a sequential test case
- run_test_case1(Ref, Num, Mod, Func, Args, RunInit, Where,
- TimetrapData, [], Mode, self());
+ run_test_case1(Ref, Num, Mod, Func, Args, RunInit,
+ TimetrapData, Mode, Main);
_Ref ->
%% this a parallel test case, spawn the new process
- Main = self(),
- {dictionary,State} = process_info(self(), dictionary),
- spawn_link(fun() ->
- run_test_case1(Ref, Num, Mod, Func, Args, RunInit, Where,
- TimetrapData, State, Mode, Main)
- end)
+ Dictionary = get(),
+ {dictionary,Dictionary} = process_info(self(), dictionary),
+ spawn_link(
+ fun() ->
+ process_flag(trap_exit, true),
+ [put(Key, Val) || {Key,Val} <- Dictionary],
+ set_io_buffering({tc,Main}),
+ run_test_case1(Ref, Num, Mod, Func, Args, RunInit,
+ TimetrapData, Mode, Main)
+ end)
end.
-run_test_case1(Ref, Num, Mod, Func, Args, RunInit, Where,
- TimetrapData, State, Mode, Main) ->
- %% if this runs on a parallel test case process,
- %% copy the dictionary from the main process
- do_if_parallel(Main, fun() -> process_flag(trap_exit, true) end, ok),
- CopyDict = fun() -> lists:foreach(fun({Key,Val}) ->
- put(Key, Val)
- end, State)
- end,
- do_if_parallel(Main, CopyDict, ok),
- do_if_parallel(Main, fun() ->
- put(test_server_common_io_handler, {tc,Main})
- end, ok),
+run_test_case1(Ref, Num, Mod, Func, Args, RunInit,
+ TimetrapData, Mode, Main) ->
+ group_leader(test_server_io:get_gl(Main == self()), self()),
+
%% if io is being buffered, send start io session message
%% (no matter if case runs on parallel or main process)
- case get(test_server_common_io_handler) of
- undefined -> ok;
- _ -> Main ! {started,Ref,self(),Num,Mod,Func}
+ case is_io_buffered() of
+ false -> ok;
+ true ->
+ test_server_io:start_transaction(),
+ Main ! {started,Ref,self(),Num,Mod,Func}
end,
TSDir = get(test_server_dir),
- case Where of
- target ->
- maybe_send_beam_and_datadir(Mod);
- host ->
- ok
- end,
+
print(major, "=case ~p:~p", [Mod, Func]),
MinorName = start_minor_log_file(Mod, Func),
print(minor, "<a name=\"top\"></a>", [], internal_raw),
@@ -3812,7 +3573,7 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit, Where,
end,
test_server_sup:framework_call(report,
- [tc_start,{{?pl2a(Mod),Func},MinorName}]),
+ [tc_start,{{Mod,Func},MinorName}]),
print_props((RunInit==skip_init), get_props(Mode)),
GroupName = case get_name(Mode) of
@@ -3830,13 +3591,12 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit, Where,
[num2str(Num),fw_name(Mod),GroupName,MinorBase,Func,
MinorBase,MinorBase]),
- do_if_parallel(Main, ok, fun erlang:yield/0),
+ do_unless_parallel(Main, fun erlang:yield/0),
- RejectIoReqs = get(test_server_reject_io_reqs),
%% run the test case
{Result,DetectedFail,ProcsBefore,ProcsAfter} =
run_test_case_apply(Num, Mod, Func, [UpdatedArgs], get_name(Mode),
- RunInit, Where, TimetrapData, RejectIoReqs),
+ RunInit, TimetrapData),
{Time,RetVal,Loc,Opts,Comment} =
case Result of
Normal={_Time,_RetVal,_Loc,_Opts,_Comment} -> Normal;
@@ -3848,7 +3608,7 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit, Where,
print_timestamp(minor, "Ended at "),
print(major, "=ended ~s", [lists:flatten(timestamp_get(""))]),
- do_if_parallel(Main, ok, fun() -> file:set_cwd(filename:dirname(TSDir)) end),
+ do_unless_parallel(Main, fun() -> file:set_cwd(filename:dirname(TSDir)) end),
%% call the appropriate progress function clause to print the results to log
Status =
@@ -3953,14 +3713,17 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit, Where,
true ->
ok
end,
- check_new_crash_dumps(Where),
+ test_server_sup:check_new_crash_dumps(),
%% if io is being buffered, send finished message
%% (no matter if case runs on parallel or main process)
- case get(test_server_common_io_handler) of
- undefined -> ok;
- _ -> Main ! {finished,Ref,self(),Num,Mod,Func,
- ?mod_result(Status),{Time,RetVal,Opts}}
+ case is_io_buffered() of
+ false ->
+ ok;
+ true ->
+ test_server_io:end_transaction(),
+ Main ! {finished,Ref,self(),Num,Mod,Func,
+ ?mod_result(Status),{Time,RetVal,Opts}}
end,
{Time,RetVal,Opts}.
@@ -3968,126 +3731,16 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit, Where,
%%--------------------------------------------------------------------
%% various help functions
-%% Call If() if we're on parallel process, or
-%% call Else() if we're on main process
-do_if_parallel(Pid, If, Else) ->
+%% Call Action if we are running on the main process (not parallel).
+do_unless_parallel(Main, Action) when is_function(Action, 0) ->
case self() of
- Pid ->
- if is_function(Else) -> Else();
- true -> Else
- end;
- _ ->
- if is_function(If) -> If();
- true -> If
- end
+ Main -> Action();
+ _ -> ok
end.
num2str(0) -> "";
num2str(N) -> integer_to_list(N).
-%% If remote target, this function sends the test suite (if not already sent)
-%% and the content of datadir til target.
-maybe_send_beam_and_datadir(Mod) ->
- case get(test_server_ctrl_job_sock) of
- undefined ->
- %% local target
- ok;
- JobSock ->
- %% remote target
- case get(test_server_downloaded_suites) of
- undefined ->
- send_beam_and_datadir(Mod, JobSock),
- put(test_server_downloaded_suites, [Mod]);
- Suites ->
- case lists:member(Mod, Suites) of
- false ->
- send_beam_and_datadir(Mod, JobSock),
- put(test_server_downloaded_suites, [Mod|Suites]);
- true ->
- ok
- end
- end
- end.
-
-send_beam_and_datadir(Mod, JobSock) ->
- case code:which(Mod) of
- non_existing ->
- io:format("** WARNING: Suite ~w could not be found on host\n",
- [Mod]);
- BeamFile ->
- send_beam(JobSock, Mod, BeamFile)
- end,
- DataDir = get_data_dir(Mod),
- case file:read_file_info(DataDir) of
- {ok,_I} ->
- {ok,All} = file:list_dir(DataDir),
- AddTarFiles =
- case controller_call(get_target_info) of
- #target_info{os_family=ose} ->
- ObjExt = code:objfile_extension(),
- Wc = filename:join(DataDir, "*" ++ ObjExt),
- ModsInDatadir = filelib:wildcard(Wc),
- SendBeamFun = fun(X) -> send_beam(JobSock, X) end,
- lists:foreach(SendBeamFun, ModsInDatadir),
- %% No need to send C code or makefiles since
- %% no compilation can be done on target anyway.
- %% Compiled C code must exist on target.
- %% Beam files are already sent as binaries.
- %% Erlang source are sent in case the test case
- %% is to compile it.
- Filter = fun("Makefile") -> false;
- ("Makefile.src") -> false;
- (Y) ->
- case filename:extension(Y) of
- ".c" -> false;
- ObjExt -> false;
- _ -> true
- end
- end,
- lists:filter(Filter, All);
- _ ->
- All
- end,
- Tarfile = "data_dir.tar.gz",
- {ok,Tar} = erl_tar:open(Tarfile, [write,compressed]),
- ShortDataDir = filename:basename(DataDir),
- AddTarFun =
- fun(File) ->
- Long = filename:join(DataDir, File),
- Short = filename:join(ShortDataDir, File),
- ok = erl_tar:add(Tar, Long, Short, [])
- end,
- lists:foreach(AddTarFun, AddTarFiles),
- ok = erl_tar:close(Tar),
- {ok,TarBin} = file:read_file(Tarfile),
- file:delete(Tarfile),
- request(JobSock, {{datadir,Tarfile}, TarBin});
- {error,_R} ->
- ok
- end.
-
-send_beam(JobSock, BeamFile) ->
- Mod=filename:rootname(filename:basename(BeamFile), code:objfile_extension()),
- send_beam(JobSock, list_to_atom(Mod), BeamFile).
-send_beam(JobSock, Mod, BeamFile) ->
- {ok,BeamBin} = file:read_file(BeamFile),
- request(JobSock, {{beam,Mod,BeamFile}, BeamBin}).
-
-check_new_crash_dumps(Where) ->
- case Where of
- target ->
- case get(test_server_ctrl_job_sock) of
- undefined ->
- ok;
- Socket ->
- read_job_sock_loop(Socket)
- end;
- _ ->
- ok
- end,
- test_server_sup:check_new_crash_dumps().
-
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% progress(Result, CaseNum, Mod, Func, Location, Reason, Time,
%% Comment, TimeFormat) -> Result
@@ -4105,7 +3758,7 @@ progress(skip, CaseNum, Mod, Func, Loc, Reason, Time,
print(major, "=result skipped", []),
print(1, "*** SKIPPED *** ~s",
[get_info_str(Func, CaseNum, get(test_server_cases))]),
- test_server_sup:framework_call(report, [tc_done,{?pl2a(Mod),Func,
+ test_server_sup:framework_call(report, [tc_done,{Mod,Func,
{skipped,Reason1}}]),
ReasonStr = reason_to_string(Reason1),
ReasonStr1 = lists:flatten([string:strip(S,left) ||
@@ -4136,7 +3789,7 @@ progress(failed, CaseNum, Mod, Func, Loc, timetrap_timeout, T,
print(1, "*** FAILED *** ~s",
[get_info_str(Func, CaseNum, get(test_server_cases))]),
test_server_sup:framework_call(report,
- [tc_done,{?pl2a(Mod),Func,
+ [tc_done,{Mod,Func,
{failed,timetrap_timeout}}]),
FormatLastLoc = test_server_sup:format_loc(get_last_loc(Loc)),
ErrorReason = io_lib:format("{timetrap_timeout,~s}", [FormatLastLoc]),
@@ -4162,7 +3815,7 @@ progress(failed, CaseNum, Mod, Func, Loc, {testcase_aborted,Reason}, _T,
print(1, "*** FAILED *** ~s",
[get_info_str(Func, CaseNum, get(test_server_cases))]),
test_server_sup:framework_call(report,
- [tc_done,{?pl2a(Mod),Func,
+ [tc_done,{Mod,Func,
{failed,testcase_aborted}}]),
FormatLastLoc = test_server_sup:format_loc(get_last_loc(Loc)),
ErrorReason = io_lib:format("{testcase_aborted,~s}", [FormatLastLoc]),
@@ -4187,7 +3840,7 @@ progress(failed, CaseNum, Mod, Func, unknown, Reason, Time,
print(major, "=result failed: ~p, ~p", [Reason,unknown]),
print(1, "*** FAILED *** ~s",
[get_info_str(Func, CaseNum, get(test_server_cases))]),
- test_server_sup:framework_call(report, [tc_done,{?pl2a(Mod),Func,
+ test_server_sup:framework_call(report, [tc_done,{Mod,Func,
{failed,Reason}}]),
TimeStr = io_lib:format(if is_float(Time) -> "~.3fs";
true -> "~w"
@@ -4223,7 +3876,7 @@ progress(failed, CaseNum, Mod, Func, Loc, Reason, Time,
print(major, "=result failed: ~p, ~p", [Reason,Loc]),
print(1, "*** FAILED *** ~s",
[get_info_str(Func, CaseNum, get(test_server_cases))]),
- test_server_sup:framework_call(report, [tc_done,{?pl2a(Mod),Func,
+ test_server_sup:framework_call(report, [tc_done,{Mod,Func,
{failed,Reason}}]),
TimeStr = io_lib:format(if is_float(Time) -> "~.3fs";
true -> "~w"
@@ -4248,7 +3901,7 @@ progress(failed, CaseNum, Mod, Func, Loc, Reason, Time,
progress(ok, _CaseNum, Mod, Func, _Loc, RetVal, Time,
Comment0, {St0,St1}) ->
print(minor, "successfully completed test case", []),
- test_server_sup:framework_call(report, [tc_done,{?pl2a(Mod),Func,ok}]),
+ test_server_sup:framework_call(report, [tc_done,{Mod,Func,ok}]),
Comment =
case RetVal of
{comment,RetComment} ->
@@ -4455,11 +4108,10 @@ do_format_exception(Reason={Error,Stack}) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% run_test_case_apply(CaseNum, Mod, Func, Args, Name, RunInit,
-%% Where, TimetrapData, RejectIoReqs) ->
+%% TimetrapData) ->
%% {{Time,RetVal,Loc,Opts,Comment},DetectedFail,ProcessesBefore,ProcessesAfter} |
%% {{died,Reason,unknown,Comment},DetectedFail,ProcessesBefore,ProcessesAfter}
%% Name = atom()
-%% Where = target | host
%% Time = float() (seconds)
%% RetVal = term()
%% Loc = term()
@@ -4474,23 +4126,10 @@ do_format_exception(Reason={Error,Stack}) ->
%% sent over socket to target, and test_server runs the case and sends the
%% result back over the socket. Else test_server runs the case directly on host.
-run_test_case_apply(CaseNum, Mod, Func, Args, Name, RunInit, host,
- TimetrapData, RejectIoReqs) ->
+run_test_case_apply(CaseNum, Mod, Func, Args, Name, RunInit,
+ TimetrapData) ->
test_server:run_test_case_apply({CaseNum,Mod,Func,Args,Name,RunInit,
- TimetrapData,RejectIoReqs});
-run_test_case_apply(CaseNum, Mod, Func, Args, Name, RunInit, target,
- TimetrapData, RejectIoReqs) ->
- case get(test_server_ctrl_job_sock) of
- undefined ->
- %% local target
- test_server:run_test_case_apply({CaseNum,Mod,Func,Args,Name,RunInit,
- TimetrapData,RejectIoReqs});
- JobSock ->
- %% remote target
- request(JobSock, {test_case,{CaseNum,Mod,Func,Args,Name,RunInit,
- TimetrapData,RejectIoReqs}}),
- read_job_sock_loop(JobSock)
- end.
+ TimetrapData}).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% print(Detail, Format, Args) -> ok
@@ -4500,16 +4139,6 @@ run_test_case_apply(CaseNum, Mod, Func, Args, Name, RunInit, target,
%%
%% Just like io:format, except that depending on the Detail value, the output
%% is directed to console, major and/or minor log files.
-%%
-%% To handle printouts to common (not minor) log files from parallel test
-%% case processes, the test_server_common_io_handler value is checked. If
-%% set, the data is sent to the main controlling process. Note that test
-%% cases that belong to a conf group nested under a parallel group will also
-%% get its io data sent to main rather than immediately printed out, even
-%% if the test cases are executed by the same, main, process (ie the main
-%% process sends messages to itself then).
-%%
-%% Buffered io is handled by the handle_test_case_io_and_status/0 function.
print(Detail, Format) ->
print(Detail, Format, []).
@@ -4522,19 +4151,7 @@ print(Detail, Format, Args, Printer) ->
print_or_buffer(Detail, Msg, Printer).
print_or_buffer(Detail, Msg, Printer) ->
- case get(test_server_minor_level) of
- _ when Detail == minor ->
- output({Detail,Msg}, Printer);
- MinLevel when is_number(Detail), Detail >= MinLevel ->
- output({Detail,Msg}, Printer);
- _ -> % Detail < Minor | major | html
- case get(test_server_common_io_handler) of
- undefined ->
- output({Detail,Msg}, Printer);
- {_,MainPid} ->
- MainPid ! {print,self(),Detail,Msg}
- end
- end.
+ test_server_gl:print(group_leader(), Detail, Msg, Printer).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% print_timestamp(Detail, Leader) -> ok
@@ -4598,107 +4215,6 @@ format(Detail, Format, Args) ->
print_or_buffer(Detail, Str, self()).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% output({Level,Message}, Sender) -> ok
-%% Level = integer() | minor | major | html
-%% Message = string() | [integer()]
-%% Sender = string() | internal
-%%
-%% Outputs the message on the channels indicated by Level. If Level is an
-%% atom, only the corresponding channel receives the output. When Level is
-%% an integer console, major and/or minor log file will receive output
-%% depending on the user set thresholds (see get_levels/0, set_levels/3)
-%%
-%% When printing on the console, the message is prefixed with the test
-%% suite's name. In case a name is not set (yet), Sender is used.
-%%
-%% When not outputting to the console, and the Sender is 'internal',
-%% the message is prefixed with "=== ", so that it will be apparent that
-%% the message comes from the test server and not the test suite itself.
-
-output({Level,Msg}, Sender) when is_integer(Level) ->
- SumLev = get(test_server_summary_level),
- if Level =< SumLev ->
- output_to_fd(stdout, Msg, Sender);
- true ->
- ok
- end,
- MajLev = get(test_server_major_level),
- if Level =< MajLev ->
- output_to_fd(get(test_server_major_fd), Msg, Sender);
- true ->
- ok
- end,
- MinLev = get(test_server_minor_level),
- if Level >= MinLev ->
- output_to_fd(get(test_server_minor_fd), Msg, Sender);
- true ->
- ok
- end;
-output({minor,Bytes}, Sender) when is_list(Bytes) ->
- output_to_fd(get(test_server_minor_fd), Bytes, Sender);
-output({major,Bytes}, Sender) when is_list(Bytes) ->
- output_to_fd(get(test_server_major_fd), Bytes, Sender);
-output({minor,Bytes}, Sender) when is_binary(Bytes) ->
- output_to_fd(get(test_server_minor_fd),binary_to_list(Bytes), Sender);
-output({major,Bytes}, Sender) when is_binary(Bytes) ->
- output_to_fd(get(test_server_major_fd),binary_to_list(Bytes), Sender);
-output({html,Msg}, _Sender) ->
- case get(test_server_html_fd) of
- undefined ->
- ok;
- Fd ->
- io:put_chars(Fd,Msg),
- case file:position(Fd, {cur, 0}) of
- {ok, Pos} ->
- %% We are writing to a seekable file. Finalise so
- %% we get complete valid (and viewable) HTML code.
- %% Then rewind to overwrite the finalising code.
- io:put_chars(Fd, "\n</table>\n"),
- case get(test_server_html_footer) of
- undefined ->
- io:put_chars(Fd, "</body>\n</html>\n");
- Footer ->
- io:put_chars(Fd, Footer)
- end,
- file:position(Fd, Pos);
- {error, epipe} ->
- %% The file is not seekable. We cannot erase what
- %% we've already written --- so the reader will
- %% have to wait until we're done.
- ok
- end
- end;
-output({minor,Data}, Sender) ->
- output_to_fd(get(test_server_minor_fd),
- lists:flatten(io_lib:format(
- "Unexpected output: ~p~n", [Data])),Sender);
-output({major,Data}, Sender) ->
- output_to_fd(get(test_server_major_fd),
- lists:flatten(io_lib:format(
- "Unexpected output: ~p~n", [Data])),Sender).
-
-output_to_fd(stdout, Msg, Sender) ->
- Name =
- case get(test_server_name) of
- undefined -> Sender;
- Other -> Other
- end,
- io:format("Testing ~s: ~s\n", [Name, lists:flatten(Msg)]);
-output_to_fd(undefined, _Msg, _Sender) ->
- ok;
-output_to_fd(Fd, Msg=[$=|_], internal) ->
- io:put_chars(Fd, [Msg,"\n"]);
-
-output_to_fd(Fd, Msg, internal) ->
- io:put_chars(Fd, [$=,$=,$=,$ , Msg, "\n"]);
-
-output_to_fd(Fd, Msg, _Sender) ->
- case get(test_server_log_nl) of
- false -> io:put_chars(Fd, Msg);
- _ -> io:put_chars(Fd, [Msg,"\n"])
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% xhtml(BasicHtml, XHtml) -> BasicHtml | XHtml
%%
xhtml(HTML, XHTML) ->
@@ -5032,7 +4548,7 @@ collect_case_invoke(Mod, Case, MFA, St) ->
end;
_ ->
Suite = test_server_sup:framework_call(get_suite,
- [?pl2a(Mod),Case],
+ [Mod,Case],
[]),
collect_subcases(Mod, Case, MFA, St, Suite)
end.
@@ -5210,7 +4726,7 @@ get_target_info() ->
%% Called by test_server. See test_server:start_node/3 for details
start_node(Name, Type, Options) ->
- T = 10 * ?ACCEPT_TIMEOUT, % give some extra time
+ T = 10 * ?ACCEPT_TIMEOUT * test_server:timetrap_scale_factor(),
format(minor, "Attempt to start ~w node ~p with options ~p",
[Type, Name, Options]),
case controller_call({start_node,Name,Type,Options}, T) of
@@ -5255,7 +4771,8 @@ start_node(Name, Type, Options) ->
%% when the new node has contacted test_server_ctrl again
wait_for_node(Slave) ->
- case catch controller_call({wait_for_node,Slave},10000) of
+ T = 10000 * test_server:timetrap_scale_factor(),
+ case catch controller_call({wait_for_node,Slave},T) of
{'EXIT',{timeout,_}} -> {error,timeout};
ok -> ok
end.
@@ -5279,60 +4796,6 @@ stop_node(Slave) ->
controller_call({stop_node,Slave}).
-%%--------------------------------------------------------------------
-%% Functions handling target communication over socket
-
-%% Generic send function for communication with target
-request(Sock,Request) ->
- gen_tcp:send(Sock,<<1,(term_to_binary(Request))/binary>>).
-
-%% Receive and decode request on job specific socket
-%% Used when test is running on a remote target
-read_job_sock_loop(Sock) ->
- case gen_tcp:recv(Sock,0) of
- {error,Reason} ->
- gen_tcp:close(Sock),
- exit({controller,connection_lost,Reason});
- {ok,<<1,Request/binary>>} ->
- case decode(binary_to_term(Request)) of
- ok ->
- read_job_sock_loop(Sock);
- {stop,Result} ->
- Result
- end
- end.
-
-decode({apply,{M,F,A}}) ->
- apply(M,F,A),
- ok;
-decode({sync_apply,{M,F,A}}) ->
- R = apply(M,F,A),
- request(get(test_server_ctrl_job_sock),{sync_result,R}),
- ok;
-decode({sync_result,Result}) ->
- {stop,Result};
-decode({test_case_result,Result}) ->
- {stop,Result};
-decode({privdir,empty_priv_dir}) ->
- {stop,ok};
-decode({{privdir,PrivDirTar},TarBin}) ->
- Root = get(test_server_log_dir_base),
- unpack_tar(Root,PrivDirTar,TarBin),
- {stop,ok};
-decode({crash_dumps,no_crash_dumps}) ->
- {stop,ok};
-decode({{crash_dumps,CrashDumpTar},TarBin}) ->
- Dir = test_server_sup:crash_dump_dir(),
- unpack_tar(Dir,CrashDumpTar,TarBin),
- {stop,ok}.
-
-unpack_tar(Dir,TarFileName0,TarBin) ->
- TarFileName = filename:join(Dir,TarFileName0),
- ok = file:write_file(TarFileName,TarBin),
- ok = erl_tar:extract(TarFileName,[compressed,{cwd,Dir}]),
- ok = file:delete(TarFileName).
-
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% DEBUGGER INTERFACE %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -5437,33 +4900,52 @@ pinfo(P) ->
%% - it does not belong to the application, but is listed in the
%% {include,List} part of the App.cover file
%% - it does not belong to the application, but is listed in the
-%% cross.cover file (in the test_server application) under 'all'
-%% or under the tested application.
-%%
-%% The modules listed in the cross.cover file are modules that are
-%% hevily used by other applications than the one they belong
-%% to. After all tests are completed, these modules can be analysed
-%% with coverage data from all tests - see cross_cover_analyse/1. The
-%% result is stored in a file called cross_cover.html in the
-%% run.<timestamp> directory of the application the modules belong
-%% to.
-%%
-%% For example, the lists module is listed in cross.cover to be
-%% included in all tests. lists belongs to the stdlib
-%% application. cross_cover_analyse/1 will create a file named
-%% cross_cover.html under the newest stdlib.logs/run.xxx directory,
-%% where the coverage result for the lists module from all tests is
-%% presented.
-%%
-%% The lists module is also presented in the normal coverage log
-%% for stdlib, but that only includes the coverage achieved by
-%% the stdlib tests themselves.
-%%
-%% The Cross cover file cross.cover contains elements like this:
-%% {App,Modules}.
-%% where App can be an application name or the atom all. The
-%% application (or all applications) shall cover compile the listed
-%% Modules.
+%% {cross,[{Tag,List}]} part of the App.cover file
+%%
+%% The modules listed in the 'cross' part of the cover file are
+%% modules that are heavily used by other tests than the one where
+%% they are explicitly tested. They should then be listed as 'cross'
+%% in the cover file for the test where they are used but do not
+%% belong.
+%%
+%% After all tests are completed, the these modules can be analysed
+%% with coverage data from all tests where they are compiled - see
+%% cross_cover_analyse/2. The result is stored in a file called
+%% cross_cover.html in the run.<timestamp> directory of the
+%% test the modules belong to.
+%%
+%% Example:
+%% If the module m1 belongs to system s1 but is heavily used also in
+%% the tests for another system s2, then the cover files for the two
+%% systems could be like this:
+%%
+%% s1.cover:
+%% {include,[m1]}.
+%%
+%% s2.cover:
+%% {include,[....]}. % modules belonging to system s2
+%% {cross,[{s1,[m1]}]}.
+%%
+%% When the tests for both s1 and s2 are completed, run
+%% cross_cover_analyse(Level,[{s1,S1LogDir},{s2,S2LogDir}]), and
+%% the accumulated cover data for m1 will be written to
+%% S1LogDir/[run.<timestamp>/]cross_cover.html
+%%
+%% S1LogDir and S2LogDir are either the run.<timestamp> directories
+%% for the two tests, or the parent directory of these, in which case
+%% the latest run.<timestamp> directory will be chosen.
+%%
+%% Note that the m1 module will also be presented in the normal
+%% coverage log for s1 (due to the include statement in s1.cover), but
+%% that only includes the coverage achieved by the s1 test itself.
+%%
+%% The Tag in the 'cross' statement in the cover file has no other
+%% purpose than mapping the list of modules ([m1] in the example
+%% above) to the correct log directory where it should be included in
+%% the cross_cover.html file (S1LogDir in the example above).
+%% I.e. the value of the Tag has no meaning, it could be foo as well
+%% as s1 above, as long as the same Tag is used in the cover file and
+%% in the call to cross_cover_analyse/2.
%% Cover compilation
@@ -5472,62 +4954,68 @@ cover_compile({App,{_File,Exclude,Include,Cross,_Export}}) ->
cover_compile1({App,Exclude,Include,Cross});
cover_compile({App,CoverFile}) ->
- Cross = get_cross_modules(App),
- {Exclude,Include} = read_cover_file(CoverFile),
+ {Exclude,Include,Cross} = read_cover_file(CoverFile),
cover_compile1({App,Exclude,Include,Cross}).
cover_compile1(What) ->
- case get(test_server_ctrl_job_sock) of
- undefined ->
- %% local target
- test_server:cover_compile(What);
- JobSock ->
- %% remote target
- request(JobSock, {sync_apply,{test_server,cover_compile,[What]}}),
- read_job_sock_loop(JobSock)
- end.
-
+ test_server:cover_compile(What).
%% Read the coverfile for an application and return a list of modules
%% that are members of the application but shall not be compiled
%% (Exclude), and a list of modules that are not members of the
%% application but shall be compiled (Include).
read_cover_file(none) ->
- {[],[]};
+ {[],[],[]};
read_cover_file(CoverFile) ->
case file:consult(CoverFile) of
{ok,List} ->
- case check_cover_file(List, [], []) of
- {ok,Exclude,Include} -> {Exclude,Include};
+ case check_cover_file(List, [], [], []) of
+ {ok,Exclude,Include,Cross} -> {Exclude,Include,Cross};
error ->
io:fwrite("Faulty format of CoverFile ~p\n", [CoverFile]),
- {[],[]}
+ {[],[],[]}
end;
{error,Reason} ->
io:fwrite("Can't read CoverFile ~p\nReason: ~p\n",
[CoverFile,Reason]),
- {[],[]}
+ {[],[],[]}
end.
-check_cover_file([{exclude,all}|Rest], _, Include) ->
- check_cover_file(Rest, all, Include);
-check_cover_file([{exclude,Exclude}|Rest], _, Include) ->
+check_cover_file([{exclude,all}|Rest], _, Include, Cross) ->
+ check_cover_file(Rest, all, Include, Cross);
+check_cover_file([{exclude,Exclude}|Rest], _, Include, Cross) ->
case lists:all(fun(M) -> is_atom(M) end, Exclude) of
true ->
- check_cover_file(Rest, Exclude, Include);
+ check_cover_file(Rest, Exclude, Include, Cross);
false ->
error
end;
-check_cover_file([{include,Include}|Rest], Exclude, _) ->
+check_cover_file([{include,Include}|Rest], Exclude, _, Cross) ->
case lists:all(fun(M) -> is_atom(M) end, Include) of
true ->
- check_cover_file(Rest, Exclude, Include);
+ check_cover_file(Rest, Exclude, Include, Cross);
+ false ->
+ error
+ end;
+check_cover_file([{cross,Cross}|Rest], Exclude, Include, _) ->
+ case check_cross(Cross) of
+ true ->
+ check_cover_file(Rest, Exclude, Include, Cross);
false ->
error
end;
-check_cover_file([], Exclude, Include) ->
- {ok,Exclude,Include}.
+check_cover_file([], Exclude, Include, Cross) ->
+ {ok,Exclude,Include,Cross}.
+check_cross([{Tag,Modules}|Rest]) ->
+ case lists:all(fun(M) -> is_atom(M) end, [Tag|Modules]) of
+ true ->
+ check_cross(Rest);
+ false ->
+ false
+ end;
+check_cross([]) ->
+ true.
%% Cover analysis, per application
@@ -5538,7 +5026,7 @@ check_cover_file([], Exclude, Include) ->
%%
%% This per application analysis writes the file cover.html in the
%% application's run.<timestamp> directory.
-cover_analyse({App,CoverInfo}, Analyse, AnalyseMods, TestDir) ->
+cover_analyse({App,CoverInfo}, Analyse, AnalyseMods, Stop, TestDir) ->
write_default_cross_coverlog(TestDir),
{ok,CoverLog} = file:open(filename:join(TestDir, ?coverlog_name), [write]),
@@ -5548,16 +5036,17 @@ cover_analyse({App,CoverInfo}, Analyse, AnalyseMods, TestDir) ->
"<p><a href=\"~s\">Coverdata collected over all tests</a></p>",
[?cross_coverlog_name]),
- {CoverFile,_Included,Excluded} =
+ {CoverFile,_Included,Excluded,Cross} =
case CoverInfo of
- {File,Excl,Incl,_Cross,Export} ->
+ {File,Excl,Incl,Cr,Export} ->
cover:export(Export),
- {File,Incl,Excl};
+ {File,Incl,Excl,Cr};
File ->
- {Excl,Incl} = read_cover_file(File),
- {File,Incl,Excl}
+ {Excl,Incl,Cr} = read_cover_file(File),
+ {File,Incl,Excl,Cr}
end,
io:fwrite(CoverLog, "<p>CoverFile: <code>~p</code>\n", [CoverFile]),
+ write_cross_cover_info(TestDir,Cross),
case length(cover:imported_modules()) of
Imps when Imps > 0 ->
@@ -5569,7 +5058,9 @@ cover_analyse({App,CoverInfo}, Analyse, AnalyseMods, TestDir) ->
io:fwrite(CoverLog, "<p>Excluded module(s): <code>~p</code>\n", [Excluded]),
- Coverage = cover_analyse(Analyse, AnalyseMods),
+ Coverage = cover_analyse(Analyse, AnalyseMods, Stop),
+ file:write_file(filename:join(TestDir,?raw_coverlog_name),
+ term_to_binary(Coverage)),
case lists:filter(fun({_M,{_,_,_}}) -> false;
(_) -> true
@@ -5586,32 +5077,27 @@ cover_analyse({App,CoverInfo}, Analyse, AnalyseMods, TestDir) ->
file:write_file(filename:join(TestDir, ?cover_total),
term_to_binary(TotPercent)).
-cover_analyse(Analyse, AnalyseMods) ->
+cover_analyse(Analyse, AnalyseMods, Stop) ->
TestDir = get(test_server_log_dir_base),
- case get(test_server_ctrl_job_sock) of
- undefined ->
- %% local target
- test_server:cover_analyse({Analyse,TestDir}, AnalyseMods);
- JobSock ->
- %% remote target
- request(JobSock, {sync_apply,{test_server,
- cover_analyse,
- [Analyse,AnalyseMods]}}),
- read_job_sock_loop(JobSock)
- end.
+ test_server:cover_analyse({Analyse,TestDir}, AnalyseMods, Stop).
-%% Cover analysis, cross application
+%% Cover analysis - accumulated over multiple tests
%% This can be executed on any node after all tests are finished.
-%% The node's current directory must be the same as when the tests
-%% were run.
-cross_cover_analyse(Analyse) ->
- cross_cover_analyse(Analyse, undefined).
-
-cross_cover_analyse(Analyse, CrossModules) ->
- CoverdataFiles = get_coverdata_files(),
+%% Analyse = overview | details
+%% TagDirs = [{Tag,Dir}]
+%% Tag = atom(), identifier
+%% Dir = string(), the log directory for Tag, it can be a
+%% run.<timestamp> directory or the parent directory of
+%% such (in which case the latest run.<timestamp> directory
+%% is used)
+cross_cover_analyse(Analyse, TagDirs0) ->
+ TagDirs = get_latest_run_dirs(TagDirs0),
+ TagMods = get_all_cross_info(TagDirs,[]),
+ TagDirMods = add_cross_modules(TagMods,TagDirs),
+ CoverdataFiles = get_coverdata_files(TagDirMods),
lists:foreach(fun(CDF) -> cover:import(CDF) end, CoverdataFiles),
- io:fwrite("Cover analysing... ", []),
+ io:fwrite("Cover analysing...\n", []),
DetailsFun =
case Analyse of
details ->
@@ -5619,100 +5105,111 @@ cross_cover_analyse(Analyse, CrossModules) ->
OutFile = filename:join(Dir,
atom_to_list(M) ++
".CROSS_COVER.html"),
- cover:analyse_to_file(M, OutFile, [html]),
- {file,OutFile}
+ case cover:analyse_to_file(M, OutFile, [html]) of
+ {ok,_} ->
+ {file,OutFile};
+ Error ->
+ Error
+ end
end;
_ ->
fun(_,_) -> undefined end
end,
- SortedModules =
- case CrossModules of
- undefined ->
- sort_modules([Mod || Mod <- get_all_cross_modules(),
- lists:member(Mod, cover:imported_modules())], []);
- _ ->
- sort_modules(CrossModules, [])
- end,
- Coverage = analyse_apps(SortedModules, DetailsFun, []),
+ Coverage = analyse_tests(TagDirMods, DetailsFun, []),
cover:stop(),
- write_cross_cover_logs(Coverage).
+ write_cross_cover_logs(Coverage,TagDirMods).
-%% For each application from which there are modules listed in the
-%% cross.cover, write a cross cover log (cross_cover.html).
-write_cross_cover_logs([{App,Coverage}|T]) ->
- case last_test_for_app(App) of
- false ->
- ok;
- Dir ->
+write_cross_cover_info(_Dir,[]) ->
+ ok;
+write_cross_cover_info(Dir,Cross) ->
+ {ok,Fd} = file:open(filename:join(Dir,?cross_cover_info),[write]),
+ lists:foreach(fun(C) -> io:format(Fd,"~p.~n",[C]) end, Cross),
+ file:close(Fd).
+
+%% For each test from which there are cross cover analysed
+%% modules, write a cross cover log (cross_cover.html).
+write_cross_cover_logs([{Tag,Coverage}|T],TagDirMods) ->
+ case lists:keyfind(Tag,1,TagDirMods) of
+ {_,Dir,Mods} when Mods=/=[] ->
+ file:write_file(filename:join(Dir,?raw_cross_coverlog_name),
+ term_to_binary(Coverage)),
CoverLogName = filename:join(Dir,?cross_coverlog_name),
{ok,CoverLog} = file:open(CoverLogName, [write]),
write_coverlog_header(CoverLog),
io:fwrite(CoverLog,
"<h1>Coverage results for \'~w\' from all tests</h1>\n",
- [App]),
+ [Tag]),
write_cover_result_table(CoverLog, Coverage),
- io:fwrite("Written file ~p\n", [CoverLogName])
+ io:fwrite("Written file ~p\n", [CoverLogName]);
+ _ ->
+ ok
end,
- write_cross_cover_logs(T);
-write_cross_cover_logs([]) ->
+ write_cross_cover_logs(T,TagDirMods);
+write_cross_cover_logs([],_) ->
io:fwrite("done\n", []).
-%% Find all exported coverdata files. First find all the latest
-%% run.<timestamp> directories, and the check if there is a file named
-%% all.coverdata.
-get_coverdata_files() ->
- PossibleFiles = [last_coverdata_file(Dir) ||
- Dir <- filelib:wildcard([$*|?logdir_ext]),
- filelib:is_dir(Dir)],
- [File || File <- PossibleFiles, filelib:is_file(File)].
-
-last_coverdata_file(Dir) ->
- LastDir = last_test(filelib:wildcard(filename:join(Dir,"run.[1-2]*")),false),
- filename:join(LastDir,"all.coverdata").
-
-
-%% Find the latest run.<timestamp> directory for the given application.
-last_test_for_app(App) ->
- AppLogDir = atom_to_list(App)++?logdir_ext,
- last_test(filelib:wildcard(filename:join(AppLogDir,"run.[1-2]*")),false).
-
-last_test([Run|Rest], false) ->
- last_test(Rest, Run);
-last_test([Run|Rest], Latest) when Run > Latest ->
- last_test(Rest, Run);
-last_test([_|Rest], Latest) ->
- last_test(Rest, Latest);
-last_test([], Latest) ->
+%% Get the latest run.<timestamp> directories
+get_latest_run_dirs([{Tag,Dir}|Rest]) ->
+ [{Tag,get_latest_run_dir(Dir)} | get_latest_run_dirs(Rest)];
+get_latest_run_dirs([]) ->
+ [].
+
+get_latest_run_dir(Dir) ->
+ case filelib:wildcard(filename:join(Dir,"run.[1-2]*")) of
+ [] ->
+ Dir;
+ [H|T] ->
+ get_latest_dir(T,H)
+ end.
+
+get_latest_dir([H|T],Latest) when H>Latest ->
+ get_latest_dir(T,H);
+get_latest_dir([_|T],Latest) ->
+ get_latest_dir(T,Latest);
+get_latest_dir([],Latest) ->
Latest.
-%% Sort modules according to the application they belong to.
-%% Return [{App,LastTestDir,ModuleList}]
-sort_modules([M|Modules], Acc) ->
- App = get_app(M),
- Acc1 =
- case lists:keysearch(App, 1, Acc) of
- {value,{App,LastTest,List}} ->
- lists:keyreplace(App, 1, Acc, {App,LastTest,[M|List]});
+get_all_cross_info([{_Tag,Dir}|Rest],Acc) ->
+ case file:consult(filename:join(Dir,?cross_cover_info)) of
+ {ok,TagMods} ->
+ get_all_cross_info(Rest,TagMods++Acc);
+ _ ->
+ get_all_cross_info(Rest,Acc)
+ end;
+get_all_cross_info([],Acc) ->
+ Acc.
+
+%% Associate the cross cover modules with their log directories
+add_cross_modules(TagMods,TagDirs)->
+ do_add_cross_modules(TagMods,[{Tag,Dir,[]} || {Tag,Dir} <- TagDirs]).
+do_add_cross_modules([{Tag,Mods1}|TagMods],TagDirMods)->
+ NewTagDirMods =
+ case lists:keytake(Tag,1,TagDirMods) of
+ {value,{Tag,Dir,Mods},Rest} ->
+ [{Tag,Dir,lists:umerge(lists:sort(Mods1),Mods)}|Rest];
false ->
- [{App,last_test_for_app(App),[M]}|Acc]
+ TagDirMods
end,
- sort_modules(Modules, Acc1);
-sort_modules([], Acc) ->
- Acc.
+ do_add_cross_modules(TagMods,NewTagDirMods);
+do_add_cross_modules([],TagDirMods) ->
+ %% Just to get the modules in the same order as in the normal cover log
+ [{Tag,Dir,lists:reverse(Mods)} || {Tag,Dir,Mods} <- TagDirMods].
-get_app(Module) ->
- Beam = code:which(Module),
- AppDir = filename:basename(filename:dirname(filename:dirname(Beam))),
- [AppStr|_] = string:tokens(AppDir,"-"),
- list_to_atom(AppStr).
+%% Find all exported coverdata files.
+get_coverdata_files(TagDirMods) ->
+ lists:flatmap(
+ fun({_,LatestDir,_}) ->
+ filelib:wildcard(filename:join(LatestDir,"all.coverdata"))
+ end,
+ TagDirMods).
-%% For each application, analyse all modules
+%% For each test, analyse all modules
%% Used for cross cover analysis.
-analyse_apps([{App,LastTest,Modules}|T], DetailsFun, Acc) ->
+analyse_tests([{Tag,LastTest,Modules}|T], DetailsFun, Acc) ->
Cov = analyse_modules(LastTest, Modules, DetailsFun, []),
- analyse_apps(T, DetailsFun, [{App,Cov}|Acc]);
-analyse_apps([], _DetailsFun, Acc) ->
+ analyse_tests(T, DetailsFun, [{Tag,Cov}|Acc]);
+analyse_tests([], _DetailsFun, Acc) ->
Acc.
%% Analyse each module
@@ -5725,27 +5222,6 @@ analyse_modules(_Dir, [], _DetailsFun, Acc) ->
Acc.
-%% Read the cross cover file (cross.cover)
-get_all_cross_modules() ->
- get_cross_modules(all).
-get_cross_modules(App) ->
- case file:consult(?cross_cover_file) of
- {ok,List} ->
- get_cross_modules(App, List, []);
- _X ->
- []
- end.
-
-get_cross_modules(App, [{_To,Modules}|T], Acc) when App==all->
- get_cross_modules(App, T, Acc ++ Modules);
-get_cross_modules(App, [{To,Modules}|T], Acc) when To==App; To==all->
- get_cross_modules(App, T, Acc ++ Modules);
-get_cross_modules(App, [_H|T], Acc) ->
- get_cross_modules(App, T, Acc);
-get_cross_modules(_App, [], Acc) ->
- Acc.
-
-
%% Support functions for writing the cover logs (both cross and normal)
write_coverlog_header(CoverLog) ->
case catch
diff --git a/lib/test_server/src/test_server_gl.erl b/lib/test_server/src/test_server_gl.erl
new file mode 100644
index 0000000000..d32c7c07dc
--- /dev/null
+++ b/lib/test_server/src/test_server_gl.erl
@@ -0,0 +1,293 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% This module implements group leader processes for test cases.
+%% Each group leader process handles output to the minor log file for
+%% a test case, and calls test_server_io to handle output to the common
+%% log files. The group leader processes are created and destroyed
+%% 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,
+ get_tc_supervisor/1,print/4,set_props/2]).
+
+-export([init/1,handle_call/3,handle_cast/2,handle_info/2,terminate/2]).
+
+-record(st, {tc_supervisor :: 'none'|pid(), %Test case supervisor
+ tc :: mfa(), %Current test case MFA
+ minor :: 'none'|pid(), %Minor fd
+ minor_monitor, %Monitor ref for minor fd
+ capture :: 'none'|pid(), %Capture output
+ reject_io :: boolean(), %Reject I/O requests...
+ permit_io, %... and exceptions
+ auto_nl=true :: boolean(), %Automatically add NL
+ levels %{Stdout,Major,Minor}
+ }).
+
+%% start_link()
+%% 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
+ {ok,Pid} ->
+ {ok,Pid};
+ Other ->
+ Other
+ end.
+
+
+%% stop(Pid)
+%% Stop a group leader process. Only to be called by
+%% the test_server_io process.
+
+stop(GL) ->
+ gen_server:cast(GL, stop).
+
+
+%% set_minor_fd(GL, Fd, MFA)
+%% GL = Pid for the group leader process
+%% Fd = file descriptor for the minor log file
+%% MFA = {M,F,A} for the test case owning the minor log file
+%%
+%% Register the file descriptor for the minor log file. Subsequent
+%% IO directed to the minor log file will be written to this file.
+%% Also register the currently executing process at the testcase
+%% supervisor corresponding to this group leader process.
+
+set_minor_fd(GL, Fd, MFA) ->
+ req(GL, {set_minor_fd,Fd,MFA,self()}).
+
+
+%% unset_minor_fd(GL, Fd, MFA)
+%% GL = Pid for the group leader process
+%%
+%% Unregister the file descriptor for minor log file (typically
+%% because the test case has ended the minor log file is about
+%% to be closed). Subsequent IO (for example, by a process spawned
+%% by the testcase process) will go to the unexpected_io log file.
+
+unset_minor_fd(GL) ->
+ req(GL, unset_minor_fd).
+
+
+%% get_tc_supervisor(GL)
+%% GL = Pid for the group leader process
+%%
+%% Return the Pid for the process that supervises the test case
+%% that has this group leader.
+
+get_tc_supervisor(GL) ->
+ req(GL, get_tc_supervisor).
+
+
+%% print(GL, Detail, Format, Args) -> ok
+%% GL = Pid for the group leader process
+%% Detail = integer() | minor | major | html | stdout
+%% Msg = iodata()
+%% Printer = internal | pid()
+%%
+%% Print a message to one of the log files. If Detail is an integer,
+%% it will be compared to the levels (set by set_props/2) to
+%% determine which log file(s) that are to receive the output. If
+%% Detail is an atom, the value of the atom will directly determine
+%% which log file to use. IO to the minor log file will be handled
+%% directly by this group leader process (printing to the file set by
+%% set_minor_fd/3), and all other IO will be handled by calling
+%% test_server_io:print/3.
+
+print(GL, Detail, Msg, Printer) ->
+ req(GL, {print,Detail,Msg,Printer}).
+
+
+%% set_props(GL, [PropertyTuple])
+%% GL = Pid for the group leader process
+%% PropertyTuple = {levels,{Show,Major,Minor}} |
+%% {auto_nl,boolean()} |
+%% {reject_io_reqs,boolean()}
+%%
+%% Set properties for this group leader process.
+
+set_props(GL, PropList) ->
+ req(GL, {set_props,PropList}).
+
+%%% Internal functions.
+
+init([]) ->
+ {ok,#st{tc_supervisor=none,
+ minor=none,
+ minor_monitor=none,
+ capture=none,
+ reject_io=false,
+ permit_io=gb_sets:empty(),
+ auto_nl=true,
+ levels={1,19,10}
+ }}.
+
+req(GL, Req) ->
+ gen_server:call(GL, Req, infinity).
+
+handle_call(get_tc_supervisor, _From, #st{tc_supervisor=Pid}=St) ->
+ {reply,Pid,St};
+handle_call({set_minor_fd,Fd,MFA,Supervisor}, _From, St) ->
+ Ref = erlang:monitor(process, Fd),
+ {reply,ok,St#st{tc=MFA,minor=Fd,minor_monitor=Ref,
+ tc_supervisor=Supervisor}};
+handle_call(unset_minor_fd, _From, St) ->
+ {reply,ok,St#st{minor=none,tc_supervisor=none}};
+handle_call({set_props,PropList}, _From, St) ->
+ {reply,ok,do_set_props(PropList, St)};
+handle_call({print,Detail,Msg,Printer}, {From,_}, St) ->
+ output(Detail, Msg, Printer, From, St),
+ {reply,ok,St}.
+
+handle_cast(stop, St) ->
+ {stop,normal,St}.
+
+handle_info({'DOWN',Ref,process,_,_}, #st{minor_monitor=Ref}=St) ->
+ {noreply,St#st{minor=none,minor_monitor=none}};
+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) ->
+ Cap = case Cap0 of
+ false -> none;
+ Pid when is_pid(Cap0) -> Pid
+ end,
+ {noreply,St#st{capture=Cap}};
+handle_info({io_request,From,ReplyAs,Req}=IoReq, St) ->
+ try io_req(Req, From, St) of
+ passthrough ->
+ group_leader() ! IoReq;
+ Data ->
+ case is_io_permitted(From, St) of
+ false ->
+ ok;
+ true ->
+ case St of
+ #st{capture=none} ->
+ ok;
+ #st{capture=CapturePid} ->
+ CapturePid ! {captured,Data}
+ end,
+ output(minor, Data, From, From, St)
+ end,
+ From ! {io_reply,ReplyAs,ok}
+ catch
+ _:_ ->
+ {io_reply,ReplyAs,{error,arguments}}
+ end,
+ {noreply,St};
+handle_info({structured_io,ClientPid,{Detail,Str}}, St) ->
+ output(Detail, Str, ClientPid, ClientPid, St),
+ {noreply,St};
+handle_info({printout,Detail,Format,Args}, St) ->
+ Str = io_lib:format(Format, Args),
+ output(Detail, Str, internal, none, St),
+ {noreply,St};
+handle_info(Msg, #st{tc_supervisor=Pid}=St) when is_pid(Pid) ->
+ %% The process overseeing the testcase process also used to be
+ %% the group leader; thus, it is widely expected that it can be
+ %% reached by sending a message to the group leader. Therefore
+ %% we'll need to forward any non-recognized messaged to the test
+ %% case supervisor.
+ Pid ! Msg,
+ {noreply,St};
+handle_info(_Msg, #st{}=St) ->
+ %% There is no known supervisor process. Ignore this message.
+ {noreply,St}.
+
+terminate(_, _) ->
+ ok.
+
+do_set_props([{levels,Levels}|Ps], St) ->
+ do_set_props(Ps, St#st{levels=Levels});
+do_set_props([{auto_nl,AutoNL}|Ps], St) ->
+ do_set_props(Ps, St#st{auto_nl=AutoNL});
+do_set_props([{reject_io_reqs,Bool}|Ps], St) ->
+ do_set_props(Ps, St#st{reject_io=Bool});
+do_set_props([], St) -> St.
+
+io_req({put_chars,Enc,Bytes}, _, _) when Enc =:= latin1; Enc =:= unicode ->
+ to_latin1(Enc, Bytes);
+io_req({put_chars,Encoding,Mod,Func,[Format,Args]}, _, _) ->
+ Str = Mod:Func(Format, Args),
+ to_latin1(Encoding, Str);
+io_req(_, _, _) -> passthrough.
+
+to_latin1(unicode, Str) ->
+ [if C > 255 ->
+ io_lib:format("\\{~.8B}", [C]);
+ true ->
+ C
+ end || C <- unicode:characters_to_list(Str, unicode)];
+to_latin1(latin1, Str) -> Str.
+
+output(Level, Str, Sender, From, St) when is_integer(Level) ->
+ case selected_by_level(Level, stdout, St) of
+ true -> output(stdout, Str, Sender, From, St);
+ false -> ok
+ end,
+ case selected_by_level(Level, major, St) of
+ true -> output(major, Str, Sender, From, St);
+ false -> ok
+ end,
+ case selected_by_level(Level, minor, St) of
+ true -> output(minor, Str, Sender, From, St);
+ false -> ok
+ end;
+output(stdout, Str, _Sender, From, St) ->
+ output_to_file(stdout, Str, From, St);
+output(html, Str, _Sender, From, St) ->
+ output_to_file(html, Str, From, St);
+output(Level, Str, Sender, From, St) when is_atom(Level) ->
+ output_to_file(Level, dress_output(Str, Sender, St), From, St).
+
+output_to_file(minor, Data0, From, #st{tc={M,F,A},minor=none}) ->
+ Data = [io_lib:format("=== ~p:~p/~p\n", [M,F,A]),Data0],
+ test_server_io:print(From, unexpected_io, Data),
+ ok;
+output_to_file(minor, Data, From, #st{minor=Fd}) ->
+ try
+ io:put_chars(Fd, Data)
+ catch
+ _:_ ->
+ test_server_io:print(From, unexpected_io, Data)
+ end;
+output_to_file(Detail, Data, From, _) ->
+ test_server_io:print(From, Detail, Data).
+
+is_io_permitted(From, #st{reject_io=true,permit_io=P}) ->
+ gb_sets:is_member(From, P);
+is_io_permitted(_, #st{reject_io=false}) -> true.
+
+selected_by_level(Level, stdout, #st{levels={Stdout,_,_}}) ->
+ Level =< Stdout;
+selected_by_level(Level, major, #st{levels={_,Major,_}}) ->
+ Level =< Major;
+selected_by_level(Level, minor, #st{levels={_,_,Minor}}) ->
+ Level >= Minor.
+
+dress_output([$=|_]=Str, internal, _) ->
+ [Str,$\n];
+dress_output(Str, internal, _) ->
+ ["=== ",Str,$\n];
+dress_output(Str, _, #st{auto_nl=AutoNL}) ->
+ case AutoNL of
+ true -> [Str,$\n];
+ false -> Str
+ end.
diff --git a/lib/test_server/src/test_server_h.erl b/lib/test_server/src/test_server_h.erl
index fdeee59326..78daba855d 100644
--- a/lib/test_server/src/test_server_h.erl
+++ b/lib/test_server/src/test_server_h.erl
@@ -131,6 +131,11 @@ report_receiver(warning_msg, _) -> kernel;
report_receiver(warning_report, _) -> kernel;
report_receiver(info, _) -> kernel;
report_receiver(info_msg, _) -> kernel;
+report_receiver(info_report,Tuple)
+ when is_tuple(Tuple) andalso
+ (element(1,Tuple)==ct_connection orelse
+ element(1,Tuple)==conn_log) ->
+ none;
report_receiver(info_report, _) -> kernel;
report_receiver(_, _) -> none.
diff --git a/lib/test_server/src/test_server_internal.hrl b/lib/test_server/src/test_server_internal.hrl
index b58b42805e..d204c35293 100644
--- a/lib/test_server/src/test_server_internal.hrl
+++ b/lib/test_server/src/test_server_internal.hrl
@@ -24,8 +24,7 @@
%% Target information generated by test_server:init_target_info/0 and
%% test_server_ctrl:contact_main_target/2
%% Once initiated, this information will never change!!
--record(target_info, {where, % local | Socket
- os_family, % atom(); win32 | unix
+-record(target_info, {os_family, % atom(); win32 | unix
os_type, % result of os:type()
host, % string(); the name of the target machine
version, % string()
@@ -43,7 +42,6 @@
% itself is master for slave nodes
%% The following are only used for remote targets
- target_client, % reference to a client talking to target
slave_targets=[]}).% list() of atom(); all available
% targets for starting slavenodes
diff --git a/lib/test_server/src/test_server_io.erl b/lib/test_server/src/test_server_io.erl
new file mode 100644
index 0000000000..777b377201
--- /dev/null
+++ b/lib/test_server/src/test_server_io.erl
@@ -0,0 +1,319 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% This module implements a process with the registered name 'test_server_io',
+%% which has two main responsibilities:
+%%
+%% * Manage group leader processes (see the test_server_gl module)
+%% for test cases. A group_leader process is obtained by calling
+%% get_gl/1. Group leader processes will be kept alive as along as
+%% the 'test_server_io' process is alive.
+%%
+%% * Handle output to the common log files (stdout, major, html,
+%% unexpected_io).
+%%
+
+-module(test_server_io).
+-export([start_link/0,stop/0,get_gl/1,set_fd/2,
+ start_transaction/0,end_transaction/0,print_buffered/1,print/3,
+ set_footer/1,set_job_name/1,set_gl_props/1]).
+
+-export([init/1,handle_call/3,handle_info/2,terminate/2]).
+
+-record(st, {fds, %Singleton fds (gb_tree)
+ shared_gl :: pid(), %Shared group leader
+ gls, %Group leaders (gb_set)
+ io_buffering=false, %I/O buffering
+ buffered, %Buffered I/O requests
+ html_footer, %HTML footer
+ job_name, %Name of current job.
+ gl_props, %Properties for GL.
+ stopping
+ }).
+
+start_link() ->
+ case gen_server:start_link({local,?MODULE}, ?MODULE, [], []) of
+ {ok,Pid} ->
+ {ok,Pid};
+ Other ->
+ Other
+ end.
+
+stop() ->
+ OldGL = group_leader(),
+ group_leader(self(), self()),
+ req(stop),
+ group_leader(OldGL, self()),
+ ok.
+
+%% get_gl(Shared) -> Pid
+%% Shared = boolean()
+%% Pid = pid()
+%%
+%% Return a group leader (a process using the test_server_gl module).
+%% If Shared is true, the shared group leader is returned (suitable for
+%% running sequential test cases), otherwise a new group leader process
+%% is spawned. Group leader processes will live until the
+%% 'test_server_io' process is stopped.
+
+get_gl(Shared) when is_boolean(Shared) ->
+ req({get_gl,Shared}).
+
+%% set_fd(Tag, Fd) -> ok.
+%% Tag = major | html | unexpected_io
+%% Fd = a file descriptor (as returned by file:open/2)
+%%
+%% Associate a file descriptor with the given Tag. This
+%% Tag can later be used in when calling to print/3.
+
+set_fd(Tag, Fd) ->
+ req({set_fd,Tag,Fd}).
+
+%% start_transaction()
+%%
+%% Subsequent calls to print/3 from the process executing start_transaction/0
+%% will cause the messages to be buffered instead of printed directly.
+
+start_transaction() ->
+ req({start_transaction,self()}).
+
+%% end_transaction()
+%%
+%% End the transaction started by start_transaction/0. Subsequent calls to
+%% print/3 will cause the message to be printed directly.
+
+end_transaction() ->
+ req({end_transaction,self()}).
+
+%% print(From, Tag, Msg)
+%% From = pid()
+%% Tag = stdout, or any tag that has been registered using set_fd/2
+%% Msg = string or iolist
+%%
+%% Either print Msg to the file identified by Tag, or buffer the message
+%% start_transaction/0 has been called from the process From.
+%%
+%% NOTE: The tags have various special meanings. For example, 'html'
+%% is assumed to be a HTML file.
+
+print(From, Tag, Msg) ->
+ req({print,From,Tag,Msg}).
+
+%% print_buffered(Pid)
+%% Pid = pid()
+%%
+%% Print all messages buffered in the *first* transaction buffered for Pid.
+%% (If start_transaction/0 and end_transaction/0 has been called N times,
+%% print_buffered/1 must be called N times to print all transactions.)
+
+print_buffered(Pid) ->
+ req({print_buffered,Pid}).
+
+%% set_footer(IoData)
+%%
+%% Set a footer for the file associated with the 'html' tag.
+%% It will be used by print/3 to print a footer for the HTML file.
+
+set_footer(Footer) ->
+ req({set_footer,Footer}).
+
+%% set_job_name(Name)
+%% Set a name for the currently running job. The name will be used
+%% when printing to 'stdout'.
+%%
+set_job_name(Name) ->
+ req({set_job_name,Name}).
+
+%% set_gl_props(PropList)
+%% Set properties for group leader processes. When a group_leader process
+%% is created, test_server_gl:set_props(PropList) will be called.
+
+set_gl_props(PropList) ->
+ req({set_gl_props,PropList}).
+
+
+%%% Internal functions.
+
+init([]) ->
+ process_flag(trap_exit, true),
+ Empty = gb_trees:empty(),
+ {ok,Shared} = test_server_gl:start_link(),
+ {ok,#st{fds=Empty,shared_gl=Shared,gls=gb_sets:empty(),
+ io_buffering=gb_sets:empty(),
+ buffered=Empty,
+ html_footer="</body>\n</html>\n",
+ job_name="<name not set>",
+ gl_props=[]}}.
+
+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(),
+ 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) ->
+ {reply,Shared,St};
+handle_call({set_fd,Tag,Fd}, _From, #st{fds=Fds0}=St) ->
+ Fds = gb_trees:enter(Tag, Fd, Fds0),
+ {reply,ok,St#st{fds=Fds}};
+handle_call({start_transaction,Pid}, _From, #st{io_buffering=Buffer0,
+ buffered=Buf0}=St) ->
+ Buf = case gb_trees:is_defined(Pid, Buf0) of
+ false -> gb_trees:insert(Pid, queue:new(), Buf0);
+ true -> Buf0
+ end,
+ Buffer = gb_sets:add(Pid, Buffer0),
+ {reply,ok,St#st{io_buffering=Buffer,buffered=Buf}};
+handle_call({print,From,Tag,Str}, _From, St0) ->
+ St = output(From, Tag, Str, St0),
+ {reply,ok,St};
+handle_call({end_transaction,Pid}, _From, #st{io_buffering=Buffer0,
+ buffered=Buffered0}=St0) ->
+ Q0 = gb_trees:get(Pid, Buffered0),
+ Q = queue:in(eot, Q0),
+ Buffered = gb_trees:update(Pid, Q, Buffered0),
+ Buffer = gb_sets:delete_any(Pid, Buffer0),
+ St = St0#st{io_buffering=Buffer,buffered=Buffered},
+ {reply,ok,St};
+handle_call({print_buffered,Pid}, _From, #st{buffered=Buffered0}=St0) ->
+ Q0 = gb_trees:get(Pid, Buffered0),
+ Q = do_print_buffered(Q0, St0),
+ Buffered = gb_trees:update(Pid, Q, Buffered0),
+ St = St0#st{buffered=Buffered},
+ {reply,ok,St};
+handle_call({set_footer,Footer}, _From, St) ->
+ {reply,ok,St#st{html_footer=Footer}};
+handle_call({set_job_name,Name}, _From, St) ->
+ {reply,ok,St#st{job_name=Name}};
+handle_call({set_gl_props,Props}, _From, #st{shared_gl=Shared}=St) ->
+ test_server_gl:set_props(Shared, Props),
+ {reply,ok,St#st{gl_props=Props}};
+handle_call(stop, From, #st{shared_gl=SGL,gls=Gls0}=St0) ->
+ St = St0#st{gls=gb_sets:insert(SGL, Gls0),stopping=From},
+ gc(St),
+ %% Give the users of the surviving group leaders some
+ %% time to finish.
+ erlang:send_after(2000, self(), stop_group_leaders),
+ {noreply,St}.
+
+handle_info({'EXIT',Pid,normal}, #st{gls=Gls0,stopping=From}=St) ->
+ Gls = gb_sets:delete_any(Pid, Gls0),
+ case gb_sets:is_empty(Gls) andalso stopping =/= undefined of
+ true ->
+ %% No more group leaders left.
+ gen_server:reply(From, ok),
+ {stop,normal,St#st{gls=Gls,stopping=undefined}};
+ false ->
+ %% Wait for more group leaders to finish.
+ {noreply,St#st{gls=Gls}}
+ end;
+handle_info({'EXIT',_Pid,Reason}, _St) ->
+ exit(Reason);
+handle_info(stop_group_leaders, #st{gls=Gls}=St) ->
+ %% Stop the remaining group leaders.
+ [test_server_gl:stop(GL) || GL <- gb_sets:to_list(Gls)],
+ erlang:send_after(2000, self(), kill_group_leaders),
+ {noreply,St};
+handle_info(kill_group_leaders, #st{gls=Gls,stopping=From}=St) ->
+ [exit(GL, kill) || GL <- gb_sets:to_list(Gls)],
+ gen_server:reply(From, ok),
+ {stop,normal,St};
+handle_info(Other, St) ->
+ io:format("Ignoring: ~p\n", [Other]),
+ {noreply,St}.
+
+terminate(_, _) ->
+ ok.
+
+output(From, Tag, Str, #st{io_buffering=Buffered,buffered=Buf0}=St) ->
+ case gb_sets:is_member(From, Buffered) of
+ false ->
+ do_output(Tag, Str, St),
+ St;
+ true ->
+ Q0 = gb_trees:get(From, Buf0),
+ Q = queue:in({Tag,Str}, Q0),
+ Buf = gb_trees:update(From, Q, Buf0),
+ St#st{buffered=Buf}
+ end.
+
+do_output(stdout, Str, #st{job_name=undefined}) ->
+ io:put_chars(Str);
+do_output(stdout, Str0, #st{job_name=Name}) ->
+ Str = io_lib:format("Testing ~s: ~s\n", [Name,Str0]),
+ io:put_chars(Str);
+do_output(Tag, Str, #st{fds=Fds}=St) ->
+ case gb_trees:lookup(Tag, Fds) of
+ none ->
+ S = io_lib:format("\n*** ERROR: ~p, line ~p: No known '~p' log file\n",
+ [?MODULE,?LINE,Tag]),
+ do_output(stdout, [S,Str], St);
+ {value,Fd} ->
+ try
+ io:put_chars(Fd, Str),
+ case Tag of
+ html -> finalise_table(Fd, St);
+ _ -> ok
+ end
+ catch _:Error ->
+ S = io_lib:format("\n*** ERROR: ~p, line ~p: Error writing to "
+ "log file '~p': ~p\n",
+ [?MODULE,?LINE,Tag,Error]),
+ do_output(stdout, [S,Str], St)
+ end
+ end.
+
+finalise_table(Fd, #st{html_footer=Footer}) ->
+ case file:position(Fd, {cur,0}) of
+ {ok,Pos} ->
+ %% We are writing to a seekable file. Finalise so
+ %% we get complete valid (and viewable) HTML code.
+ %% Then rewind to overwrite the finalising code.
+ io:put_chars(Fd, ["\n</table>\n",Footer]),
+ file:position(Fd, Pos);
+ {error,epipe} ->
+ %% The file is not seekable. We cannot erase what
+ %% we've already written --- so the reader will
+ %% have to wait until we're done.
+ ok
+ end.
+
+do_print_buffered(Q0, St) ->
+ Item = queue:get(Q0),
+ Q = queue:drop(Q0),
+ case Item of
+ eot ->
+ Q;
+ {Tag,Str} ->
+ do_output(Tag, Str, St),
+ do_print_buffered(Q, St)
+ end.
+
+gc(#st{gls=Gls0}) ->
+ InUse0 = [begin
+ case process_info(P, group_leader) of
+ {group_leader,GL} -> GL;
+ undefined -> undefined
+ end
+ end || P <- processes()],
+ InUse = ordsets:from_list(InUse0),
+ Gls = gb_sets:to_list(Gls0),
+ NotUsed = ordsets:subtract(Gls, InUse),
+ [test_server_gl:stop(Pid) || Pid <- NotUsed],
+ ok.
diff --git a/lib/test_server/src/test_server_node.erl b/lib/test_server/src/test_server_node.erl
index 17c02dfbe5..b307d93c7d 100644
--- a/lib/test_server/src/test_server_node.erl
+++ b/lib/test_server/src/test_server_node.erl
@@ -26,7 +26,7 @@
%% Test Controller interface
-export([is_release_available/1]).
--export([start_remote_main_target/1,stop/1]).
+-export([stop/1]).
-export([start_tracer_node/2,trace_nodes/2,stop_tracer_node/1]).
-export([start_node/5, stop_node/2]).
-export([kill_nodes/1, nodedown/2]).
@@ -57,79 +57,8 @@ is_release_available(Rel) ->
false
end.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%% Start main target node on remote host
-%%% The target node must not know the controller node via erlang distribution.
-start_remote_main_target(Parameters) ->
- #par{type=TargetType,
- target=TargetHost,
- naming=Naming,
- master=MasterNode,
- cookie=MasterCookie,
- slave_targets=SlaveTargets} = Parameters,
-
- lists:foreach(fun(T) -> maybe_reboot_target({TargetType,T}) end,
- [list_to_atom(TargetHost)|SlaveTargets]),
-
- Cmd0 = get_main_target_start_command(TargetType,TargetHost,Naming,
- MasterNode,MasterCookie),
- Cmd =
- case os:getenv("TEST_SERVER_FRAMEWORK") of
- FW when FW =:= false; FW =:= "undefined" -> Cmd0;
- FW -> Cmd0 ++ " -env TEST_SERVER_FRAMEWORK " ++ FW
- end,
-
- {ok,LSock} = gen_tcp:listen(?MAIN_PORT,[binary,{reuseaddr,true},{packet,2}]),
- case start_target(TargetType,TargetHost,Cmd) of
- {ok,TargetClient,AcceptTimeout} ->
- case gen_tcp:accept(LSock,AcceptTimeout) of
- {ok,Sock} ->
- gen_tcp:close(LSock),
- receive
- {tcp,Sock,Bin} when is_binary(Bin) ->
- case unpack(Bin) of
- error ->
- gen_tcp:close(Sock),
- close_target_client(TargetClient),
- {error,bad_message};
- {ok,{target_info,TI}} ->
- put(test_server_free_targets,SlaveTargets),
- {ok, TI#target_info{where=Sock,
- host=TargetHost,
- naming=Naming,
- master=MasterNode,
- target_client=TargetClient,
- slave_targets=SlaveTargets}}
- end;
- {tcp_closed,Sock} ->
- gen_tcp:close(Sock),
- close_target_client(TargetClient),
- {error,could_not_contact_target}
- after AcceptTimeout ->
- gen_tcp:close(Sock),
- close_target_client(TargetClient),
- {error,timeout}
- end;
- Error ->
- %%! maybe something like kill_target(...)???
- gen_tcp:close(LSock),
- close_target_client(TargetClient),
- {error,{could_not_contact_target,Error}}
- end;
- Error ->
- gen_tcp:close(LSock),
- {error,{could_not_start_target,Error}}
- end.
-
stop(TI) ->
- kill_nodes(TI),
- case TI#target_info.where of
- local -> % there is no remote target to stop
- ok;
- Sock -> % stop remote target
- gen_tcp:close(Sock),
- close_target_client(TI#target_info.target_client)
- end.
+ kill_nodes(TI).
nodedown(Sock, TI) ->
Match = #slave_info{name='$1',socket=Sock,client='$2',_='_'},
@@ -146,14 +75,8 @@ nodedown(Sock, TI) ->
false -> ok
end,
slave_died;
- [] ->
- case TI#target_info.where of
- Sock ->
- %% test_server_ctrl will do the cleanup
- target_died;
- _ ->
- ignore
- end
+ [] ->
+ ok
end.
@@ -167,10 +90,7 @@ start_tracer_node(TraceFile,TI) ->
Match = #slave_info{name='$1',_='_'},
SlaveNodes = lists:map(fun([N]) -> [" ",N] end,
ets:match(slave_tab,Match)),
- TargetNode = case TI#target_info.where of
- local -> node();
- _ -> "test_server@" ++ TI#target_info.host
- end,
+ TargetNode = node(),
Cookie = TI#target_info.cookie,
{ok,LSock} = gen_tcp:listen(0,[binary,{reuseaddr,true},{packet,2}]),
{ok,TracePort} = inet:port(LSock),
@@ -424,10 +344,12 @@ start_node_peer(SlaveName, OptList, From, TI) ->
%% Bad environment can cause open port to fail. If this happens,
%% we ignore it and let the testcase handle the situation...
catch open_port({spawn, Cmd}, [stream|Opts]),
+
+ Tmo = 60000 * test_server:timetrap_scale_factor(),
case start_node_get_option_value(wait, OptList, true) of
true ->
- Ret = wait_for_node_started(LSock,60000,undefined,Cleanup,TI,self()),
+ Ret = wait_for_node_started(LSock,Tmo,undefined,Cleanup,TI,self()),
case {Ret,FailOnError} of
{{{ok, Node}, Warning},_} ->
gen_server:reply(From,{{ok,Node},HostStr,Cmd,[],Warning});
@@ -443,7 +365,7 @@ start_node_peer(SlaveName, OptList, From, TI) ->
Self = self(),
spawn_link(
fun() ->
- wait_for_node_started(LSock,60000,undefined,
+ wait_for_node_started(LSock,Tmo,undefined,
Cleanup,TI,Self),
receive after infinity -> ok end
end),
@@ -469,129 +391,29 @@ start_node_slave(SlaveName, OptList, From, TI) ->
Ret =
case start_which_node(OptList) of
{error,Reason} -> {{error,Reason},undefined,undefined};
- Host0 -> do_start_node_slave(Host0,SlaveName,Args,Prog,Cleanup,TI)
+ Host0 -> do_start_node_slave(Host0,SlaveName,Args,Prog,Cleanup)
end,
gen_server:reply(From,Ret).
-do_start_node_slave(Host0, SlaveName, Args, Prog, Cleanup, TI) ->
- case TI#target_info.where of
- local ->
- Host =
- case Host0 of
- local -> test_server_sup:hoststr();
- _ -> cast_to_list(Host0)
- end,
- Cmd = Prog ++ " " ++ Args,
- %% Can use slave.erl here because I'm both controller and target
- %% so I will ping the new node anyway
- case slave:start(Host, SlaveName, Args, no_link, Prog) of
- {ok,Nodename} ->
- case Cleanup of
- true -> ets:insert(slave_tab,#slave_info{name=Nodename});
- false -> ok
- end,
- {{ok,Nodename}, Host, Cmd, [], []};
- Ret ->
- {Ret, Host, Cmd}
- end;
-
- _Sock ->
- %% Cannot use slave.erl here because I'm only controller, and will
- %% not ping the new node. Only target shall contact the new node!!
- no_contact_start_slave(Host0,SlaveName,Args,Prog,Cleanup,TI)
- end.
-
-
-
-no_contact_start_slave(Host, Name, Args0, Prog, Cleanup,TI) ->
- Args1 = case string:str(Args0,"-setcookie") of
- 0 -> "-setcookie " ++ TI#target_info.cookie ++ " " ++ Args0;
- _ -> Args0
+do_start_node_slave(Host0, SlaveName, Args, Prog, Cleanup) ->
+ Host =
+ case Host0 of
+ local -> test_server_sup:hoststr();
+ _ -> cast_to_list(Host0)
+ end,
+ Cmd = Prog ++ " " ++ Args,
+ %% Can use slave.erl here because I'm both controller and target
+ %% so I will ping the new node anyway
+ case slave:start(Host, SlaveName, Args, no_link, Prog) of
+ {ok,Nodename} ->
+ case Cleanup of
+ true -> ets:insert(slave_tab,#slave_info{name=Nodename});
+ false -> ok
end,
- Args = TI#target_info.naming ++ " " ++ cast_to_list(Name) ++ " " ++ Args1,
- case Host of
- local ->
- case get(test_server_free_targets) of
- [] ->
- io:format("Starting slave ~p on HOST~n", [Name]),
- TargetType = test_server_sup:get_os_family(),
- Cmd0 = get_slave_node_start_command(TargetType,
- Prog,
- TI#target_info.master),
- Cmd = Cmd0 ++ " " ++ Args,
- do_no_contact_start_slave(TargetType,
- test_server_sup:hoststr(),
- Cmd, Cleanup,TI, false);
- [H|T] ->
- TargetType = TI#target_info.os_family,
- Cmd0 = get_slave_node_start_command(TargetType,
- Prog,
- TI#target_info.master),
- Cmd = Cmd0 ++ " " ++ Args,
- case do_no_contact_start_slave(TargetType,H,Cmd,Cleanup,
- TI,true) of
- {error,remove} ->
- io:format("Cannot start node on ~p, "
- "removing from slave "
- "target list.", [H]),
- put(test_server_free_targets,T),
- no_contact_start_slave(Host,Name,Args,Prog,
- Cleanup,TI);
- {error,keep} ->
- %% H is added to the END OF THE LIST
- %% in order to avoid the same target to
- %% be selected each time
- put(test_server_free_targets,T++[H]),
- no_contact_start_slave(Host,Name,Args,Prog,
- Cleanup,TI);
- R ->
- put(test_server_free_targets,T),
- R
- end
- end;
- _ ->
- TargetType = TI#target_info.os_family,
- Cmd0 = get_slave_node_start_command(TargetType,
- Prog,
- TI#target_info.master),
- Cmd = Cmd0 ++ " " ++ Args,
- do_no_contact_start_slave(TargetType, Host, Cmd, Cleanup, TI, false)
- end.
-
-do_no_contact_start_slave(TargetType,Host0,Cmd0,Cleanup,TI,Retry) ->
- %% Must use TargetType instead of TI#target_info.os_familiy here
- %% because if there were no free_targets we will be starting the
- %% slave node on host which might have a different os_familiy
- Host = cast_to_list(Host0),
- {ok,LSock} = gen_tcp:listen(0,[binary,
- {reuseaddr,true},
- {packet,2}]),
- {ok,WaitPort} = inet:port(LSock),
- Cmd = lists:concat([Cmd0, " -s ", ?MODULE, " node_started ",
- test_server_sup:hoststr(), " ", WaitPort]),
-
- case start_target(TargetType,Host,Cmd) of
- {ok,Client,AcceptTimeout} ->
- case wait_for_node_started(LSock,AcceptTimeout,
- Client,Cleanup,TI,self()) of
- {error,_}=WaitError ->
- if Retry ->
- case maybe_reboot_target(Client) of
- {error,_} -> {error,remove};
- ok -> {error,keep}
- end;
- true ->
- {WaitError,Host,Cmd}
- end;
- {Ok,Warning} ->
- {Ok,Host,Cmd,[],Warning}
- end;
- StartError ->
- gen_tcp:close(LSock),
- if Retry -> {error,remove};
- true -> {{error,{could_not_start_target,StartError}},Host,Cmd}
- end
+ {{ok,Nodename}, Host, Cmd, [], []};
+ Ret ->
+ {Ret, Host, Cmd}
end.
@@ -775,40 +597,10 @@ kill_node(SI,TI) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Platform specific code
-start_target(unix,TargetHost,Cmd0) ->
- Cmd =
- case test_server_sup:hoststr() of
- TargetHost -> Cmd0;
- _ -> lists:concat(["rsh ",TargetHost, " ", Cmd0])
- end,
- open_port({spawn, Cmd}, [stream]),
- {ok,undefined,?ACCEPT_TIMEOUT}.
-
-maybe_reboot_target(_) ->
- {error, cannot_reboot_target}.
-
close_target_client(undefined) ->
ok.
-
-%%
-%% Command for starting main target
-%%
-get_main_target_start_command(unix,_TargetHost,Naming,
- _MasterNode,_MasterCookie) ->
- Prog = pick_erl_program(default),
- Prog ++ " " ++ Naming ++ " test_server" ++
- " -boot start_sasl -sasl errlog_type error"
- " -s test_server start " ++ test_server_sup:hoststr().
-
-%%
-%% Command for starting slave nodes
-%%
-get_slave_node_start_command(unix, Prog, MasterNode) ->
- cast_to_list(Prog) ++ " -detached -master " ++ MasterNode.
-
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% cast_to_list(X) -> string()
%%% X = list() | atom() | void()
diff --git a/lib/test_server/src/test_server_sup.erl b/lib/test_server/src/test_server_sup.erl
index 4a27c1ebae..a6d426887e 100644
--- a/lib/test_server/src/test_server_sup.erl
+++ b/lib/test_server/src/test_server_sup.erl
@@ -28,7 +28,7 @@
get_username/0, get_os_family/0,
hostatom/0, hostatom/1, hoststr/0, hoststr/1,
framework_call/2,framework_call/3,framework_call/4,
- format_loc/1, package_str/1, package_atom/1,
+ format_loc/1,
call_trace/1]).
-include("test_server_internal.hrl").
-define(crash_dump_tar,"crash_dumps.tar.gz").
@@ -64,13 +64,7 @@ timetrap(Timeout0, ReportTVal, Scale, Pid) ->
true -> ReportTVal end,
MFLs = test_server:get_loc(Pid),
Mon = erlang:monitor(process, Pid),
- Trap =
- case get(test_server_init_or_end_conf) of
- undefined ->
- {timetrap_timeout,TimeToReport,MFLs};
- InitOrEnd ->
- {timetrap_timeout,TimeToReport,MFLs,InitOrEnd}
- end,
+ Trap = {timetrap_timeout,TimeToReport,MFLs},
exit(Pid, Trap),
receive
{'DOWN', Mon, process, Pid, _} ->
@@ -518,8 +512,18 @@ framework_call(Callback,Func,Args,DefaultReturn) ->
end,
case erlang:function_exported(Mod,Func,length(Args)) of
true ->
- put(test_server_loc, {Mod,Func,framework}),
EH = fun(Reason) -> exit({fw_error,{Mod,Func,Reason}}) end,
+ SetTcState = case Func of
+ end_tc -> true;
+ init_tc -> true;
+ _ -> false
+ end,
+ case SetTcState of
+ true ->
+ test_server:set_tc_state({framework,Mod,Func});
+ false ->
+ ok
+ end,
try apply(Mod,Func,Args) of
Result ->
Result
@@ -549,19 +553,7 @@ format_loc([{Mod,Func,Line}|Rest]) ->
format_loc([{Mod,LineOrFunc}]) ->
format_loc({Mod,LineOrFunc});
format_loc({Mod,Func}) when is_atom(Func) ->
- io_lib:format("{~s,~w}",[package_str(Mod),Func]);
-format_loc({Mod,Line}) when is_integer(Line) ->
- %% ?line macro is used
- ModStr = package_str(Mod),
- case {lists:member(no_src, get(test_server_logopts)),
- lists:reverse(ModStr)} of
- {false,[$E,$T,$I,$U,$S,$_|_]} ->
- io_lib:format("{~s,<a href=\"~s~s#~w\">~w</a>}",
- [ModStr,downcase(ModStr),?src_listing_ext,
- round_to_10(Line),Line]);
- _ ->
- io_lib:format("{~s,~w}",[ModStr,Line])
- end;
+ io_lib:format("{~w,~w}",[Mod,Func]);
format_loc(Loc) ->
io_lib:format("~p",[Loc]).
@@ -570,22 +562,17 @@ format_loc1([{Mod,Func,Line}]) ->
format_loc1([{Mod,Func,Line}|Rest]) ->
[" ",format_loc1({Mod,Func,Line}),",\n"|format_loc1(Rest)];
format_loc1({Mod,Func,Line}) ->
- ModStr = package_str(Mod),
+ ModStr = atom_to_list(Mod),
case {lists:member(no_src, get(test_server_logopts)),
lists:reverse(ModStr)} of
{false,[$E,$T,$I,$U,$S,$_|_]} ->
- io_lib:format("{~s,~w,<a href=\"~s~s#~w\">~w</a>}",
- [ModStr,Func,downcase(ModStr),?src_listing_ext,
- round_to_10(Line),Line]);
+ io_lib:format("{~w,~w,<a href=\"~s~s#~w\">~w</a>}",
+ [Mod,Func,downcase(ModStr),?src_listing_ext,
+ Line,Line]);
_ ->
- io_lib:format("{~s,~w,~w}",[ModStr,Func,Line])
+ io_lib:format("{~w,~w,~w}",[Mod,Func,Line])
end.
-round_to_10(N) when (N rem 10) == 0 ->
- N;
-round_to_10(N) ->
- trunc(N/10)*10.
-
downcase(S) -> downcase(S, []).
downcase([Uc|Rest], Result) when $A =< Uc, Uc =< $Z ->
downcase(Rest, [Uc-$A+$a|Result]);
@@ -594,22 +581,6 @@ downcase([C|Rest], Result) ->
downcase([], Result) ->
lists:reverse(Result).
-package_str(Mod) when is_atom(Mod) ->
- atom_to_list(Mod);
-package_str(Mod) when is_list(Mod), is_atom(hd(Mod)) ->
- %% convert [s1,s2] -> "s1.s2"
- [_|M] = lists:flatten(["."++atom_to_list(S) || S <- Mod]),
- M;
-package_str(Mod) when is_list(Mod) ->
- Mod.
-
-package_atom(Mod) when is_atom(Mod) ->
- Mod;
-package_atom(Mod) when is_list(Mod), is_atom(hd(Mod)) ->
- list_to_atom(package_str(Mod));
-package_atom(Mod) when is_list(Mod) ->
- list_to_atom(Mod).
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% call_trace(TraceSpecFile) -> ok
%%
diff --git a/lib/test_server/src/ts.erl b/lib/test_server/src/ts.erl
index db16b6ecd2..cfd7161dbd 100644
--- a/lib/test_server/src/ts.erl
+++ b/lib/test_server/src/ts.erl
@@ -160,8 +160,8 @@ help(installed) ->
" the given run options\n",
" ts:cross_cover_analyse(Level)\n"
" - Used after ts:run with option cover or \n"
- " cover_details. Analyses modules specified in\n"
- " cross.cover.\n"
+ " cover_details. Analyses modules specified with\n"
+ " a 'cross' statement in the cover spec file.\n"
" Level can be 'overview' or 'details'.\n",
" ts:compile_testcases()~n"
" ts:compile_testcases(Apps)~n"
@@ -259,14 +259,43 @@ run(List, Opts) when is_list(List), is_list(Opts) ->
run(Testspec, Config) when is_atom(Testspec), is_list(Config) ->
Options=check_test_get_opts(Testspec, Config),
File=atom_to_list(Testspec),
- Spec = case code:lib_dir(Testspec) of
- {error, bad_name} when Testspec /= emulator,
- Testspec /= system,
- Testspec /= epmd ->
- create_skip_spec(Testspec, tests(Testspec));
- _ ->
- File++".spec"
- end,
+ WhatToDo =
+ case Testspec of
+ %% Known to exist but fails generic tests below
+ emulator -> test;
+ system -> test;
+ erl_interface -> test;
+ epmd -> test;
+ _ ->
+ case code:lib_dir(Testspec) of
+ {error,bad_name} ->
+ %% Application does not exist
+ skip;
+ Path ->
+ case file:read_file_info(filename:join(Path,"ebin")) of
+ {ok,#file_info{type=directory}} ->
+ %% Erlang application is built
+ test;
+ _ ->
+ case filelib:wildcard(
+ filename:join([Path,"priv","*.jar"])) of
+ [] ->
+ %% The application is not built
+ skip;
+ [_|_] ->
+ %% Java application is built
+ test
+ end
+ end
+ end
+ end,
+ Spec =
+ case WhatToDo of
+ skip ->
+ create_skip_spec(Testspec, tests(Testspec));
+ test ->
+ File++".spec"
+ end,
run_test(File, [{spec,[Spec]}], Options);
%% Runs one module in a spec (interactive)
run(Testspec, Mod) when is_atom(Testspec), is_atom(Mod) ->
@@ -498,8 +527,35 @@ estone(Opts) when is_list(Opts) -> run(emulator,estone_SUITE,Opts).
cross_cover_analyse([Level]) ->
cross_cover_analyse(Level);
cross_cover_analyse(Level) ->
- test_server_ctrl:cross_cover_analyse(Level).
-
+ Apps = get_last_app_tests(),
+ test_server_ctrl:cross_cover_analyse(Level,Apps).
+
+get_last_app_tests() ->
+ AllTests = filelib:wildcard(filename:join(["*","*_test.logs"])),
+ {ok,RE} = re:compile("^[^/]*/[^\.]*\.(.*)_test\.logs$"),
+ get_last_app_tests(AllTests,RE,[]).
+
+get_last_app_tests([Dir|Dirs],RE,Acc) ->
+ NewAcc =
+ case re:run(Dir,RE,[{capture,all,list}]) of
+ {match,[Dir,AppStr]} ->
+ App = list_to_atom(AppStr),
+ case lists:keytake(App,1,Acc) of
+ {value,{App,LastDir},Rest} ->
+ if Dir > LastDir ->
+ [{App,Dir}|Rest];
+ true ->
+ Acc
+ end;
+ false ->
+ [{App,Dir} | Acc]
+ end;
+ _ ->
+ Acc
+ end,
+ get_last_app_tests(Dirs,RE,NewAcc);
+get_last_app_tests([],_,Acc) ->
+ Acc.
%%% Implementation.
diff --git a/lib/test_server/src/ts_run.erl b/lib/test_server/src/ts_run.erl
index f4d5b3e3b1..741dd483f5 100644
--- a/lib/test_server/src/ts_run.erl
+++ b/lib/test_server/src/ts_run.erl
@@ -368,7 +368,7 @@ make_common_test_args(Args0, Options0, _Vars) ->
io:format("No cover file found for ~p~n",[App]),
[];
{value,{cover,_App,File,_Analyse}} ->
- [{cover,to_list(File)}];
+ [{cover,to_list(File)},{cover_stop,false}];
false ->
[]
end,
@@ -380,13 +380,7 @@ make_common_test_args(Args0, Options0, _Vars) ->
[{logdir,"../test_server"}]
end,
- TimeTrap = case test_server:timetrap_scale_factor() of
- 1 ->
- [];
- Scale ->
- [{multiply_timetraps, Scale},
- {scale_timetraps, true}]
- end,
+ TimeTrap = [{scale_timetraps, true}],
{ConfigPath,
Options} = case {os:getenv("TEST_CONFIG_PATH"),
diff --git a/lib/test_server/test/Makefile b/lib/test_server/test/Makefile
index afe5aff196..afccc28662 100644
--- a/lib/test_server/test/Makefile
+++ b/lib/test_server/test/Makefile
@@ -26,8 +26,8 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
MODULES= \
test_server_SUITE \
- test_server_line_SUITE \
- test_server_test_lib
+ test_server_test_lib \
+ erl2html2_SUITE
ERL_FILES= $(MODULES:%=%.erl)
@@ -65,7 +65,6 @@ make_emakefile:
>> $(EMAKEFILE)
tests debug opt: make_emakefile
- cd ../src && $(MAKE) ../ebin/test_server_line.beam
erl $(ERL_MAKE_FLAGS) -make
clean:
diff --git a/lib/test_server/test/erl2html2_SUITE.erl b/lib/test_server/test/erl2html2_SUITE.erl
new file mode 100644
index 0000000000..96175413a1
--- /dev/null
+++ b/lib/test_server/test/erl2html2_SUITE.erl
@@ -0,0 +1,254 @@
+%%%-------------------------------------------------------------------
+%%% @author Siri Hansen <[email protected]>
+%%% @copyright (C) 2012, Siri Hansen
+%%% @doc
+%%%
+%%% @end
+%%% Created : 15 Nov 2012 by Siri Hansen <[email protected]>
+%%%-------------------------------------------------------------------
+-module(erl2html2_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+
+-define(HEADER,
+ ["<!DOCTYPE HTML PUBLIC",
+ "\"-//W3C//DTD HTML 3.2 Final//EN\">\n",
+ "<!-- autogenerated by 'erl2html2' -->\n",
+ "<html>\n",
+ "<head><title>Module ", Src, "</title>\n",
+ "<meta http-equiv=\"cache-control\" ",
+ "content=\"no-cache\">\n",
+ "</head>\n",
+ "<body bgcolor=\"white\" text=\"black\" ",
+ "link=\"blue\" vlink=\"purple\" alink=\"red\">\n"]).
+
+%%--------------------------------------------------------------------
+%% @spec suite() -> Info
+%% Info = [tuple()]
+%% @end
+%%--------------------------------------------------------------------
+suite() ->
+ [{timetrap,{seconds,30}},
+ {ct_hooks,[ts_install_cth,test_server_test_lib]}].
+
+%%--------------------------------------------------------------------
+%% @spec init_per_suite(Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% @spec end_per_suite(Config0) -> void() | {save_config,Config1}
+%% Config0 = Config1 = [tuple()]
+%% @end
+%%--------------------------------------------------------------------
+end_per_suite(_Config) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% @spec init_per_group(GroupName, Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%% GroupName = atom()
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+init_per_group(_GroupName, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% @spec end_per_group(GroupName, Config0) ->
+%% void() | {save_config,Config1}
+%% GroupName = atom()
+%% Config0 = Config1 = [tuple()]
+%% @end
+%%--------------------------------------------------------------------
+end_per_group(_GroupName, _Config) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% @spec init_per_testcase(TestCase, Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%% TestCase = atom()
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% @spec end_per_testcase(TestCase, Config0) ->
+%% void() | {save_config,Config1} | {fail,Reason}
+%% TestCase = atom()
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+end_per_testcase(_TestCase, _Config) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% @spec groups() -> [Group]
+%% Group = {GroupName,Properties,GroupsAndTestCases}
+%% GroupName = atom()
+%% Properties = [parallel | sequence | Shuffle | {RepeatType,N}]
+%% GroupsAndTestCases = [Group | {group,GroupName} | TestCase]
+%% TestCase = atom()
+%% Shuffle = shuffle | {shuffle,{integer(),integer(),integer()}}
+%% RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail |
+%% repeat_until_any_ok | repeat_until_any_fail
+%% N = integer() | forever
+%% @end
+%%--------------------------------------------------------------------
+groups() ->
+ [].
+
+%%--------------------------------------------------------------------
+%% @spec all() -> GroupsAndTestCases | {skip,Reason}
+%% GroupsAndTestCases = [{group,GroupName} | TestCase]
+%% GroupName = atom()
+%% TestCase = atom()
+%% Reason = term()
+%% @end
+%%--------------------------------------------------------------------
+all() ->
+ [m1].
+
+%%--------------------------------------------------------------------
+%% @spec TestCase() -> Info
+%% Info = [tuple()]
+%% @end
+%%--------------------------------------------------------------------
+m1() ->
+ [].
+
+%%--------------------------------------------------------------------
+%% @spec TestCase(Config0) ->
+%% ok | exit() | {skip,Reason} | {comment,Comment} |
+%% {save_config,Config1} | {skip_and_save,Reason,Config1}
+%% Config0 = Config1 = [tuple()]
+%% Reason = term()
+%% Comment = term()
+%% @end
+%%--------------------------------------------------------------------
+m1(Config) ->
+ {Src,Dst} = convert_module("m1",Config),
+ {true,L} = check_line_numbers(Src,Dst),
+ ok = check_link_targets(Src,Dst,L,[{baz,0}]),
+ ok.
+
+convert_module(Mod,Config) ->
+ DataDir = ?config(data_dir,Config),
+ PrivDir = ?config(priv_dir,Config),
+ Src = filename:join(DataDir,Mod++".erl"),
+ Dst = filename:join(PrivDir,Mod++".erl.html"),
+ io:format("<a href=\"~s\">~s</a>\n",[Src,filename:basename(Src)]),
+ ok = erl2html2:convert(Src, Dst, "<html><body>"),
+ io:format("<a href=\"~s\">~s</a>\n",[Dst,filename:basename(Dst)]),
+ {Src,Dst}.
+
+%% Check that there are the same number of lines in each file, and
+%% that all line numbers are displayed in the dst file.
+check_line_numbers(Src,Dst) ->
+ {ok,SFd} = file:open(Src,[read]),
+ {ok,DFd} = file:open(Dst,[read]),
+ {ok,SN} = count_src_lines(SFd,0),
+ ok = file:close(SFd),
+ {ok,DN} = read_dst_line_numbers(DFd),
+ ok = file:close(DFd),
+ {SN == DN,SN}.
+
+count_src_lines(Fd,N) ->
+ case io:get_line(Fd,"") of
+ eof ->
+ {ok,N};
+ {error,Reason} ->
+ {error,Reason,N};
+ _Line ->
+ count_src_lines(Fd,N+1)
+ end.
+
+read_dst_line_numbers(Fd) ->
+ "<html><body><pre>\n" = io:get_line(Fd,""),
+ read_dst_line_numbers(Fd,0).
+read_dst_line_numbers(Fd,Last) when is_integer(Last) ->
+ case io:get_line(Fd,"") of
+ eof ->
+ {ok,Last};
+ {error,Reason} ->
+ {error,Reason,Last};
+ "</pre>"++_ ->
+ {ok,Last};
+ "</body>"++_ ->
+ {ok,Last};
+ Line ->
+ %% erlang:display(Line),
+ Num = check_line_number(Last,Line,Line),
+ read_dst_line_numbers(Fd,Num)
+ end.
+
+check_line_number(Last,Line,OrigLine) ->
+ case Line of
+ "<a name="++_ ->
+ [$>|Rest] = lists:dropwhile(fun($>) -> false; (_) -> true end,Line),
+ check_line_number(Last,Rest,OrigLine);
+ _ ->
+ [N |_] = string:tokens(Line,":"),
+% erlang:display(N),
+ Num =
+ try list_to_integer(string:strip(N))
+ catch _:_ -> ct:fail({no_line_number_after,Last,OrigLine})
+ end,
+ if Num == Last+1 ->
+ Num;
+ true ->
+ ct:fail({unexpected_integer,Num,Last})
+ end
+ end.
+
+
+%% Check that there is one link target for each line and one for each
+%% function.
+%% The test module has -compile(export_all), so all functions are
+%% found by listing the exported ones.
+check_link_targets(Src,Dst,L,RmFncs) ->
+ Mod = list_to_atom(filename:basename(filename:rootname(Src))),
+ Exports = Mod:module_info(exports)--[{module_info,0},{module_info,1}|RmFncs],
+ {ok,{[],L},_} = xmerl_sax_parser:file(Dst,
+ [{event_fun,fun sax_event/3},
+ {event_state,{Exports,0}}]),
+ ok.
+
+sax_event(Event,_Loc,State) ->
+ sax_event(Event,State).
+
+sax_event({startElement,_Uri,"a",_QN,Attrs},{Exports,PrevLine}) ->
+ {_,_,"name",Name} = lists:keyfind("name",3,Attrs),
+ case catch list_to_integer(Name) of
+ Line when is_integer(Line) ->
+ case PrevLine + 1 of
+ Line ->
+% erlang:display({found_line,Line}),
+ {Exports,Line};
+ Other ->
+ ct:fail({unexpected_line_number_target,Other})
+ end;
+ {'EXIT',_} ->
+ {match,[FStr,AStr]} =
+ re:run(Name,"^(.*)-([0-9]+)$",[{capture,all_but_first,list}]),
+ F = list_to_atom(http_uri:decode(FStr)),
+ A = list_to_integer(AStr),
+% erlang:display({found_fnc,F,A}),
+ A = proplists:get_value(F,Exports),
+ {lists:delete({F,A},Exports),PrevLine}
+ end;
+sax_event(_,State) ->
+ State.
diff --git a/lib/test_server/test/erl2html2_SUITE_data/Makefile.src b/lib/test_server/test/erl2html2_SUITE_data/Makefile.src
new file mode 100644
index 0000000000..942ac0584b
--- /dev/null
+++ b/lib/test_server/test/erl2html2_SUITE_data/Makefile.src
@@ -0,0 +1,2 @@
+all:
+ erlc -Iinclude m1.erl \ No newline at end of file
diff --git a/lib/test_server/test/erl2html2_SUITE_data/header1.hrl b/lib/test_server/test/erl2html2_SUITE_data/header1.hrl
new file mode 100644
index 0000000000..53d1b79ac5
--- /dev/null
+++ b/lib/test_server/test/erl2html2_SUITE_data/header1.hrl
@@ -0,0 +1,4 @@
+baz() ->
+ ok.
+
+-define(MACRO_DEFINING_A_FUNCTION,quux() -> ok).
diff --git a/lib/test_server/test/erl2html2_SUITE_data/include/header2.hrl b/lib/test_server/test/erl2html2_SUITE_data/include/header2.hrl
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/test_server/test/erl2html2_SUITE_data/include/header2.hrl
diff --git a/lib/test_server/test/erl2html2_SUITE_data/m1.erl b/lib/test_server/test/erl2html2_SUITE_data/m1.erl
new file mode 100644
index 0000000000..156f1d0a51
--- /dev/null
+++ b/lib/test_server/test/erl2html2_SUITE_data/m1.erl
@@ -0,0 +1,46 @@
+%% Comment with <html> code &amp; </html>
+%% and also some "quotes" and 'single quotes'
+
+-module(m1).
+
+-compile(export_all).
+
+-include("header1.hrl").
+-include("header2.hrl").
+
+-define(MACRO1,value).
+
+%%% Comment
+foo(x) ->
+ %% Comment
+ ok_x;
+foo(y) ->
+ %% Second clause
+ ok_y.
+
+'quoted_foo'() ->
+ ok.
+
+'quoted_foo_with_"_and_/'() ->
+ ok.
+
+'quoted_foo_with_(_and_)'() ->
+ ok.
+
+'quoted_foo_with_<_and_>'() ->
+ ok.
+
+bar() ->
+ do_something(),
+ok. % indentation error, OTP-9710
+
+%% Function inside macro definition
+?MACRO_DEFINING_A_FUNCTION.
+
+%% Two function one one line
+quuux() -> ok. quuuux() -> ok.
+
+%% do_something/0 does something
+do_something() ->
+ ?MACRO1.
+%% comments after last line
diff --git a/lib/test_server/test/test_server.cover b/lib/test_server/test/test_server.cover
index c16212567e..052415377d 100644
--- a/lib/test_server/test/test_server.cover
+++ b/lib/test_server/test/test_server.cover
@@ -1,21 +1 @@
{incl_app,test_server,details}.
-
-{excl_mods, test_server, [test_server,
- test_server_ctrl,
- ts_selftest]}.
-
-%% Using incl_mods list here because the test_server might not find
-%% lib_dir for test_server - and so it will not find which modules to
-%% compile.
-{incl_mods, test_server, [erl2html2,
- test_server_node,
- test_server_sup,
- ts,
- ts_autoconf_win32,
- ts_erl_config,
- ts_install,
- ts_lib,
- ts_make,
- ts_run
- ]}.
-
diff --git a/lib/test_server/test/test_server_SUITE.erl b/lib/test_server/test/test_server_SUITE.erl
index a8532b08ab..fb82a87fd0 100644
--- a/lib/test_server/test/test_server_SUITE.erl
+++ b/lib/test_server/test/test_server_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -79,7 +79,8 @@ groups() ->
all() ->
[test_server_SUITE, test_server_parallel01_SUITE,
test_server_conf02_SUITE, test_server_conf01_SUITE,
- test_server_skip_SUITE, test_server_shuffle01_SUITE].
+ test_server_skip_SUITE, test_server_shuffle01_SUITE,
+ test_server_break_SUITE, test_server_cover_SUITE].
%%--------------------------------------------------------------------
@@ -92,45 +93,113 @@ test_server_SUITE(Config) ->
% rpc:call(Node,dbg, tracer,[]),
% rpc:call(Node,dbg, p,[all,c]),
% rpc:call(Node,dbg, tpl,[test_server_ctrl,x]),
- run_test_server_tests("test_server_SUITE", 39, 1, 31,
- 20, 9, 1, 11, 2, 26, Config).
+ run_test_server_tests("test_server_SUITE",
+ [{test_server_SUITE,skip_case7,"SKIPPED!"}],
+ 38, 1, 30, 19, 9, 1, 11, 2, 25, Config).
test_server_parallel01_SUITE(Config) ->
- run_test_server_tests("test_server_parallel01_SUITE", 37, 0, 19,
- 19, 0, 0, 0, 0, 37, Config).
+ run_test_server_tests("test_server_parallel01_SUITE", [],
+ 37, 0, 19, 19, 0, 0, 0, 0, 37, Config).
test_server_shuffle01_SUITE(Config) ->
- run_test_server_tests("test_server_shuffle01_SUITE", 130, 0, 0,
- 76, 0, 0, 0, 0, 130, Config).
+ run_test_server_tests("test_server_shuffle01_SUITE", [],
+ 130, 0, 0, 76, 0, 0, 0, 0, 130, Config).
test_server_skip_SUITE(Config) ->
- run_test_server_tests("test_server_skip_SUITE", 3, 0, 1,
- 0, 0, 1, 3, 0, 0, Config).
+ run_test_server_tests("test_server_skip_SUITE", [],
+ 3, 0, 1, 0, 0, 1, 3, 0, 0, Config).
test_server_conf01_SUITE(Config) ->
- run_test_server_tests("test_server_conf01_SUITE", 24, 0, 12,
- 12, 0, 0, 0, 0, 24, Config).
+ run_test_server_tests("test_server_conf01_SUITE", [],
+ 24, 0, 12, 12, 0, 0, 0, 0, 24, Config).
test_server_conf02_SUITE(Config) ->
- run_test_server_tests("test_server_conf02_SUITE", 26, 0, 12,
- 12, 0, 0, 0, 0, 26, Config).
+ run_test_server_tests("test_server_conf02_SUITE", [],
+ 26, 0, 12, 12, 0, 0, 0, 0, 26, Config).
+test_server_break_SUITE(Config) ->
+ run_test_server_tests("test_server_break_SUITE", [],
+ 8, 2, 6, 4, 0, 0, 0, 2, 6, Config).
-run_test_server_tests(SuiteName, NCases, NFail, NExpected, NSucc,
+test_server_cover_SUITE(Config) ->
+ case test_server:is_cover() of
+ true ->
+ {skip, "Cover already running"};
+ false ->
+ PrivDir = ?config(priv_dir,Config),
+
+ %% Test suite has two test cases
+ %% tc1 calls cover_helper:foo/0
+ %% tc2 calls cover_helper:bar/0
+ %% Each function in cover_helper is one line.
+ %%
+ %% First test run skips tc2, so only cover_helper:foo/0 is executed.
+ %% Cover file specifies to include cover_helper in this test run.
+ CoverFile1 = filename:join(PrivDir,"t1.cover"),
+ CoverSpec1 = {include,[cover_helper]},
+ file:write_file(CoverFile1,io_lib:format("~p.~n",[CoverSpec1])),
+ run_test_server_tests("test_server_cover_SUITE",
+ [{test_server_cover_SUITE,tc2,"SKIPPED!"}],
+ 4, 0, 2, 1, 1, 0, 1, 0, 3,
+ CoverFile1, Config),
+
+ %% Next test run skips tc1, so only cover_helper:bar/0 is executed.
+ %% Cover file specifies cross compilation of cover_helper
+ CoverFile2 = filename:join(PrivDir,"t2.cover"),
+ CoverSpec2 = {cross,[{t1,[cover_helper]}]},
+ file:write_file(CoverFile2,io_lib:format("~p.~n",[CoverSpec2])),
+ run_test_server_tests("test_server_cover_SUITE",
+ [{test_server_cover_SUITE,tc1,"SKIPPED!"}],
+ 4, 0, 2, 1, 1, 0, 1, 0, 3, CoverFile2, Config),
+
+ %% Cross cover analyse
+ WorkDir = ?config(work_dir,Config),
+ WC = filename:join([WorkDir,"test_server_cover_SUITE.logs","run.*"]),
+ [D2,D1|_] = lists:reverse(lists:sort(filelib:wildcard(WC))),
+ TagDirs = [{t1,D1},{t2,D2}],
+ test_server_ctrl:cross_cover_analyse(details,TagDirs),
+
+ %% Check that cover log shows only what is really included
+ %% in the test and cross cover log show the accumulated
+ %% result.
+ {ok,Cover1} = file:read_file(filename:join(D1,"cover.log")),
+ [{cover_helper,{1,1,_}}] = binary_to_term(Cover1),
+ {ok,Cover2} = file:read_file(filename:join(D2,"cover.log")),
+ [] = binary_to_term(Cover2),
+ {ok,Cross} = file:read_file(filename:join(D1,"cross_cover.log")),
+ [{cover_helper,{2,0,_}}] = binary_to_term(Cross),
+ ok
+ end.
+
+
+run_test_server_tests(SuiteName, Skip, NCases, NFail, NExpected, NSucc,
NUsrSkip, NAutoSkip,
NActualSkip, NActualFail, NActualSucc, Config) ->
+ run_test_server_tests(SuiteName, Skip, NCases, NFail, NExpected, NSucc,
+ NUsrSkip, NAutoSkip,
+ NActualSkip, NActualFail, NActualSucc, false, Config).
- ct:log("See test case log files under:~n~p~n",
- [filename:join([proplists:get_value(priv_dir, Config),
- SuiteName++".logs"])]),
+run_test_server_tests(SuiteName, Skip, NCases, NFail, NExpected, NSucc,
+ NUsrSkip, NAutoSkip,
+ NActualSkip, NActualFail, NActualSucc, Cover, Config) ->
+
+ WorkDir = proplists:get_value(work_dir, Config),
+ ct:log("<a href=\"file://~s\">Test case log files</a>\n",
+ [filename:join(WorkDir, SuiteName++".logs")]),
Node = proplists:get_value(node, Config),
{ok,_Pid} = rpc:call(Node,test_server_ctrl, start, []),
+ case Cover of
+ false ->
+ ok;
+ _ ->
+ rpc:call(Node,test_server_ctrl,cover,[Cover,details])
+ end,
rpc:call(Node,
test_server_ctrl,add_dir_with_skip,
[SuiteName,
[proplists:get_value(data_dir,Config)],SuiteName,
- [{test_server_SUITE,skip_case7,"SKIPPED!"}]]),
+ Skip]),
until(fun() ->
rpc:call(Node,test_server_ctrl,jobs,[]) =:= []
@@ -138,17 +207,18 @@ run_test_server_tests(SuiteName, NCases, NFail, NExpected, NSucc,
rpc:call(Node,test_server_ctrl, stop, []),
- {ok,#suite{ n_cases = NCases,
- n_cases_failed = NFail,
- n_cases_expected = NExpected,
- n_cases_succ = NSucc,
- n_cases_user_skip = NUsrSkip,
- n_cases_auto_skip = NAutoSkip,
- cases = Cases }} = Data =
- test_server_test_lib:parse_suite(
- hd(filelib:wildcard(
- filename:join([proplists:get_value(priv_dir, Config),
- SuiteName++".logs","run*","suite.log"])))),
+ {ok,Data} = test_server_test_lib:parse_suite(
+ lists:last(
+ lists:sort(
+ filelib:wildcard(
+ filename:join([WorkDir,SuiteName++".logs",
+ "run*","suite.log"]))))),
+ check([{"Number of cases",NCases,Data#suite.n_cases},
+ {"Number failed",NFail,Data#suite.n_cases_failed},
+ {"Number expected",NExpected,Data#suite.n_cases_expected},
+ {"Number successful",NSucc,Data#suite.n_cases_succ},
+ {"Number user skipped",NUsrSkip,Data#suite.n_cases_user_skip},
+ {"Number auto skipped",NAutoSkip,Data#suite.n_cases_auto_skip}], ok),
{NActualSkip,NActualFail,NActualSucc} =
lists:foldl(fun(#tc{ result = skip },{S,F,Su}) ->
{S+1,F,Su};
@@ -156,9 +226,18 @@ run_test_server_tests(SuiteName, NCases, NFail, NExpected, NSucc,
{S,F,Su+1};
(#tc{ result = failed },{S,F,Su}) ->
{S,F+1,Su}
- end,{0,0,0},Cases),
+ end,{0,0,0},Data#suite.cases),
Data.
+check([{Str,Same,Same}|T], Status) ->
+ io:format("~s: ~p\n", [Str,Same]),
+ check(T, Status);
+check([{Str,Expected,Actual}|T], _) ->
+ io:format("~s: expected ~p, actual ~p\n", [Str,Expected,Actual]),
+ check(T, error);
+check([], ok) -> ok;
+check([], error) -> ?t:fail().
+
until(Fun) ->
case Fun() of
true ->
diff --git a/lib/test_server/test/test_server_SUITE_data/Makefile.src b/lib/test_server/test/test_server_SUITE_data/Makefile.src
index 332b855df6..c770627f04 100644
--- a/lib/test_server/test/test_server_SUITE_data/Makefile.src
+++ b/lib/test_server/test/test_server_SUITE_data/Makefile.src
@@ -4,4 +4,7 @@ all:
erlc test_server_conf01_SUITE.erl
erlc test_server_shuffle01_SUITE.erl
erlc test_server_conf02_SUITE.erl
- erlc test_server_skip_SUITE.erl \ No newline at end of file
+ erlc test_server_skip_SUITE.erl
+ erlc test_server_break_SUITE.erl
+ erlc test_server_cover_SUITE.erl
+ erlc +debug_info test_server_cover_SUITE_data/cover_helper.erl \ No newline at end of file
diff --git a/lib/test_server/test/test_server_SUITE_data/test_server_SUITE.erl b/lib/test_server/test/test_server_SUITE_data/test_server_SUITE.erl
index dfcdff0c3e..fc2adcd651 100644
--- a/lib/test_server/test/test_server_SUITE_data/test_server_SUITE.erl
+++ b/lib/test_server/test/test_server_SUITE_data/test_server_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -34,7 +34,7 @@
do_times/1, do_times_mfa/1, do_times_fun/1,
skip_cases/1, skip_case1/1, skip_case2/1, skip_case3/1,
skip_case4/1, skip_case5/1, skip_case6/1, skip_case7/1,
- skip_case8/1, skip_case9/1, undefined_functions/1,
+ skip_case8/1, skip_case9/1,
conf_init/1, check_new_conf/1, conf_cleanup/1,
check_old_conf/1, conf_init_fail/1, start_stop_node/1,
cleanup_nodes_init/1, check_survive_nodes/1, cleanup_nodes_fin/1,
@@ -47,7 +47,7 @@ all(suite) ->
[config, comment, timetrap, timetrap_cancel, multiply_timetrap,
init_per_s, init_per_tc, end_per_tc,
timeconv, msgs, capture, timecall, do_times, skip_cases,
- undefined_functions, commercial,
+ commercial,
{conf, conf_init, [check_new_conf], conf_cleanup},
check_old_conf,
{conf, conf_init_fail,[conf_member_skip],conf_cleanup_skip},
@@ -386,50 +386,6 @@ skip_case9(Config) when is_list(Config) ->
%% returning {skip, Reason} from init_per_testcase/2 for this case.
?t:fail("This case should have been Skipped by init_per_testcase/2").
-undefined_functions(suite) -> [];
-undefined_functions(doc) -> ["Check for calls to undefined functions in"
- " test_server."
- "Skip if cover is running"];
-undefined_functions(Config) when is_list(Config) ->
- case whereis(cover_server) of
- Pid when is_pid(Pid) ->
- {skip,"Cover is running"};
- undefined ->
- undefined_functions()
- end.
-
-undefined_functions() ->
- TestServerDir = filename:dirname(code:which(test_server)),
- Res = xref:d(TestServerDir),
-
- {value,{unused,Unused}} = lists:keysearch(unused, 1, Res),
- case Unused of
- [] -> ok;
- _ ->
- lists:foreach(fun (MFA) ->
- io:format("~s unused", [format_mfa(MFA)])
- end, Unused)
- end,
-
- {value,{undefined,Undef0}} = lists:keysearch(undefined, 1, Res),
- Undef = [U || U <- Undef0, not unresolved(U)],
- case Undef of
- [] -> ok;
- _ ->
- lists:foreach(fun ({MFA1,MFA2}) ->
- io:format("~s calls undefined ~s",
- [format_mfa(MFA1),format_mfa(MFA2)])
- end, Undef),
- ?t:fail({length(Undef),undefined_functions_in_otp})
- end,
- ok.
-
-unresolved({_,{_,'$F_EXPR',_}}) -> true;
-unresolved(_) -> false.
-
-format_mfa({M,F,A}) ->
- lists:flatten(io_lib:format("~s:~s/~p", [M,F,A])).
-
conf_init(doc) -> ["Test successful conf case: Change Config parameter"];
conf_init(Config) when is_list(Config) ->
[{conf_init_var,1389}|Config].
@@ -477,7 +433,7 @@ start_stop_node(Config) when is_list(Config) ->
?t:comment("WARNING: Node started with {wait,false}"
" is up faster than expected...");
false ->
- wait_for_node(Node4,0),
+ test_server:wait_for_node(Node4),
true = lists:member(Node4,nodes())
end,
@@ -494,16 +450,6 @@ start_stop_node(Config) when is_list(Config) ->
ok.
-
-wait_for_node(Node,Acc) ->
- case net_adm:ping(Node) of
- pang ->
- timer:sleep(100),
- wait_for_node(Node,Acc+100);
- pong ->
- Acc
- end.
-
cleanup_nodes_init(doc) -> ["Test that nodes are terminated when test case"
" is finished unless {cleanup,false} is given."];
cleanup_nodes_init(Config) when is_list(Config) ->
diff --git a/lib/test_server/test/test_server_SUITE_data/test_server_break_SUITE.erl b/lib/test_server/test/test_server_SUITE_data/test_server_break_SUITE.erl
new file mode 100644
index 0000000000..d9f009679a
--- /dev/null
+++ b/lib/test_server/test/test_server_SUITE_data/test_server_break_SUITE.erl
@@ -0,0 +1,148 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(test_server_break_SUITE).
+
+-export([all/1, init_per_suite/1, end_per_suite/1]).
+-export([init_per_testcase/2, end_per_testcase/2]).
+-export([break_in_init_tc/1,
+ break_in_tc/1,
+ break_in_end_tc/1,
+ break_in_end_tc_after_fail/1,
+ break_in_end_tc_after_abort/1,
+ check_all_breaks/1]).
+
+-include_lib("test_server/include/test_server.hrl").
+
+all(suite) ->
+ [break_in_init_tc,
+ break_in_tc,
+ break_in_end_tc,
+ break_in_end_tc_after_fail,
+ break_in_end_tc_after_abort,
+ check_all_breaks]. %must be the last test - checks result of previous tests
+
+init_per_suite(Config) ->
+ spawn(fun break_and_continue_sup/0),
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_testcase(Case,Config) when Case==break_in_init_tc ->
+ Config1 = init_timetrap(500,Config),
+ break_and_check(Case),
+ Config1;
+init_per_testcase(Case,Config) when Case==check_all_breaks ->
+ init_timetrap({seconds,20},Config);
+init_per_testcase(_Case,Config) ->
+ init_timetrap(500,Config).
+
+init_timetrap(T,Config) ->
+ Dog = ?t:timetrap(T),
+ [{watchdog, Dog}|Config].
+
+end_per_testcase(Case,Config) when Case==break_in_end_tc;
+ Case==break_in_end_tc_after_fail;
+ Case==break_in_end_tc_after_abort ->
+ break_and_check(Case),
+ cancel_timetrap(Config);
+end_per_testcase(_Case,Config) ->
+ cancel_timetrap(Config).
+
+cancel_timetrap(Config) ->
+ Dog=?config(watchdog, Config),
+ ?t:timetrap_cancel(Dog),
+ ok.
+
+
+%%%-----------------------------------------------------------------
+%%% Test cases
+
+break_in_init_tc(Config) when is_list(Config) ->
+ ok.
+
+break_in_tc(Config) when is_list(Config) ->
+ break_and_check(break_in_tc),
+ ok.
+
+break_in_end_tc(Config) when is_list(Config) ->
+ ok.
+
+break_in_end_tc_after_fail(Config) when is_list(Config) ->
+ ?t:fail(test_case_should_fail).
+
+break_in_end_tc_after_abort(Config) when is_list(Config) ->
+ ?t:adjusted_sleep(2000). % will cause a timetrap timeout
+
+%% This test case checks that all breaks in previous test cases was
+%% also continued, and that the break lasted as long as expected.
+%% The reason for this is that some of the breaks above are in
+%% end_per_testcase, and failures there will only produce a warning,
+%% not an error - so this is to catch the error for real.
+check_all_breaks(Config) when is_list(Config) ->
+ break_and_continue_sup ! {done,self()},
+ receive {Breaks,Continued} ->
+ check_all_breaks(Breaks,Continued)
+ end.
+%%%-----------------------------------------------------------------
+%%% Internal functions
+
+
+check_all_breaks([{From,Case,T,Start}|Breaks],[{From,End}|Continued]) ->
+ Diff = timer:now_diff(End,Start),
+ DiffSec = round(Diff/1000000),
+ TSec = round(T/1000000),
+ if DiffSec==TSec ->
+ ?t:format("Break in ~p successfully continued after ~p second(s)~n",
+ [Case,DiffSec]),
+ check_all_breaks(Breaks,Continued);
+ true ->
+ ?t:format("Faulty duration of break in ~p: continued after ~p second(s)~n",
+ [Case,DiffSec]),
+ ?t:fail({faulty_diff,Case,DiffSec,TSec})
+ end;
+check_all_breaks([],[]) ->
+ ok;
+check_all_breaks(Breaks,Continued) ->
+ %% This is probably a case of a missing continue - i.e. a break
+ %% has been started, but it was never continued.
+ ?t:fail({no_match_in_breaks_and_continued,Breaks,Continued}).
+
+break_and_check(Case) ->
+ break_and_continue_sup ! {break,Case,1000,self()},
+ ?t:break(atom_to_list(Case)),
+ break_and_continue_sup ! {continued,self()},
+ ok.
+
+break_and_continue_sup() ->
+ register(break_and_continue_sup,self()),
+ break_and_continue_loop([],[]).
+
+break_and_continue_loop(Breaks,Continued) ->
+ receive
+ {break,Case,T,From} ->
+ Start = now(),
+ {RealT,_} = timer:tc(?t,adjusted_sleep,[T]),
+ ?t:continue(),
+ break_and_continue_loop([{From,Case,RealT,Start}|Breaks],Continued);
+ {continued,From} ->
+ break_and_continue_loop(Breaks,[{From,now()}|Continued]);
+ {done,From} ->
+ From ! {lists:reverse(Breaks),lists:reverse(Continued)}
+ end.
diff --git a/lib/test_server/test/test_server_SUITE_data/test_server_cover_SUITE.erl b/lib/test_server/test/test_server_SUITE_data/test_server_cover_SUITE.erl
new file mode 100644
index 0000000000..b1ae70a302
--- /dev/null
+++ b/lib/test_server/test/test_server_SUITE_data/test_server_cover_SUITE.erl
@@ -0,0 +1,58 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(test_server_cover_SUITE).
+
+-export([all/1, init_per_suite/1, end_per_suite/1]).
+-export([init_per_testcase/2, end_per_testcase/2]).
+-export([tc1/1, tc2/1]).
+
+-include_lib("test_server/include/test_server.hrl").
+
+all(suite) ->
+ [tc1,tc2].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_testcase(_Case,Config) ->
+ Dog = ?t:timetrap({minutes,10}),
+ [{watchdog, Dog}|Config].
+
+end_per_testcase(_Case,Config) ->
+ Dog=?config(watchdog, Config),
+ ?t:timetrap_cancel(Dog),
+ ok.
+
+
+%%%-----------------------------------------------------------------
+%%% Test cases
+tc1(Config) when is_list(Config) ->
+ cover_helper:foo(),
+ ok.
+
+tc2(Config) when is_list(Config) ->
+ cover_helper:bar(),
+ ok.
+
+%%%-----------------------------------------------------------------
+%%% Internal functions
+
diff --git a/lib/test_server/test/test_server_SUITE_data/test_server_cover_SUITE_data/cover_helper.erl b/lib/test_server/test/test_server_SUITE_data/test_server_cover_SUITE_data/cover_helper.erl
new file mode 100644
index 0000000000..6c74eb4e8a
--- /dev/null
+++ b/lib/test_server/test/test_server_SUITE_data/test_server_cover_SUITE_data/cover_helper.erl
@@ -0,0 +1,4 @@
+-module(cover_helper).
+-compile(export_all).
+foo() -> ok.
+bar() -> ok.
diff --git a/lib/test_server/test/test_server_line_SUITE.erl b/lib/test_server/test/test_server_line_SUITE.erl
deleted file mode 100644
index 0aba54f6b5..0000000000
--- a/lib/test_server/test/test_server_line_SUITE.erl
+++ /dev/null
@@ -1,131 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%%------------------------------------------------------------------
-%%% Test Server self test.
-%%%------------------------------------------------------------------
--module(test_server_line_SUITE).
--include_lib("test_server/include/test_server.hrl").
-
--export([all/0,suite/0]).
--export([init_per_suite/1,end_per_suite/1,
- init_per_testcase/2, end_per_testcase/2]).
--export([parse_transform/1, lines/1]).
-
-suite() ->
- [{ct_hooks,[ts_install_cth]},
- {doc,["Test of parse transform for collection line numbers"]}].
-
-all() -> [parse_transform,lines].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_testcase(_Case, Config) ->
- ?line test_server_line:clear(),
- Dog = ?t:timetrap(?t:minutes(2)),
- [{watchdog, Dog}|Config].
-
-end_per_testcase(_Case, Config) ->
- ?line test_server_line:clear(),
- Dog=?config(watchdog, Config),
- ?t:timetrap_cancel(Dog),
- ok.
-
-parse_transform(suite) -> [];
-parse_transform(doc) -> [];
-parse_transform(Config) when is_list(Config) ->
- ?line DataDir = ?config(data_dir,Config),
- code:add_pathz(DataDir),
-
- ?line ok = parse_transform_test:excluded(),
- ?line [] = test_server_line:get_lines(),
-
- ?line test_server_line:clear(),
- ?line ok = parse_transform_test:func(),
-
- ?line [{parse_transform_test,func4,58},
- {parse_transform_test,func,49},
- {parse_transform_test,func3,56},
- {parse_transform_test,func,39},
- {parse_transform_test,func2,54},
- {parse_transform_test,func,36},
- {parse_transform_test,func1,52},
- {parse_transform_test,func,35}] = test_server_line:get_lines(),
-
- code:del_path(DataDir),
- ok.
-
-lines(suite) -> [];
-lines(doc) -> ["Test parse transform for collection line numbers"];
-lines(Config) when is_list(Config) ->
- ?line L0 = [{mod,func,1},{mod,func,2},{mod,func,3},
- {m,f,4},{m,f,5},{m,f,6},
- {mo,fu,7},{mo,fu,8},{mo,fu,9}],
- ?line LL = string:copies(L0, 1000),
- ?line T1 = erlang:now(),
- ?line lists:foreach(fun ({M,F,L}) ->
- test_server_line:'$test_server_line'(M, F, L)
- end, LL),
- ?line T2 = erlang:now(),
- ?line Long = test_server_line:get_lines(),
- ?line test_server_line:clear(),
-
- ?line T3 = erlang:now(),
- ?line lists:foreach(fun ({M,F,L}) ->
- test_server_line:'$test_server_lineQ'(M, F, L)
- end, LL),
- ?line T4 = erlang:now(),
- ?line LongQ = test_server_line:get_lines(),
-
- ?line io:format("'$test_server_line': ~f~n'$test_server_lineQ': ~f~n",
- [timer:now_diff(T2, T1)/1000, timer:now_diff(T4, T3)/1000]),
- ?line io:format("'$test_server_line' result long:~p~n", [Long]),
- ?line io:format("'$test_server_lineQ' result long:~p~n", [LongQ]),
-
- if Long =:= LongQ ->
- ?line ok;
- true ->
- ?line ?t:fail("The two methods did not produce same result for"
- " long lists of lines")
- end,
-
- ?line test_server_line:clear(),
- ?line lists:foreach(fun ({M,F,L}) ->
- test_server_line:'$test_server_line'(M, F, L)
- end, L0),
- ?line Short = test_server_line:get_lines(),
- ?line test_server_line:clear(),
- ?line lists:foreach(fun ({M,F,L}) ->
- test_server_line:'$test_server_lineQ'(M, F, L)
- end, L0),
- ?line ShortQ = test_server_line:get_lines(),
-
- ?line io:format("'$test_server_line' result short:~p~n", [Short]),
- ?line io:format("'$test_server_lineQ' result short:~p~n", [ShortQ]),
-
- if Short =:= ShortQ ->
- ?line ok;
- true ->
- ?line ?t:fail("The two methods did not produce same result for"
- " shot lists of lines\n")
- end.
diff --git a/lib/test_server/test/test_server_line_SUITE_data/Makefile.src b/lib/test_server/test/test_server_line_SUITE_data/Makefile.src
deleted file mode 100644
index a077648934..0000000000
--- a/lib/test_server/test/test_server_line_SUITE_data/Makefile.src
+++ /dev/null
@@ -1,6 +0,0 @@
-EFLAGS=+debug_info -pa ../../test_server -I../../test_server
-
-all: parse_transform_test.@EMULATOR@
-
-parse_transform_test.@EMULATOR@: parse_transform_test.erl
- erlc $(EFLAGS) parse_transform_test.erl
diff --git a/lib/test_server/test/test_server_test_lib.erl b/lib/test_server/test/test_server_test_lib.erl
index 5ca24f3df7..d466aa0110 100644
--- a/lib/test_server/test/test_server_test_lib.erl
+++ b/lib/test_server/test/test_server_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -54,9 +54,13 @@ start_slave(Config,_Level) ->
ok
end,
DataDir = proplists:get_value(data_dir, Config),
- PrivDir = proplists:get_value(priv_dir, Config),
+ %% We would normally use priv_dir for temporary data,
+ %% but the pathnames gets too long on Windows.
+ %% Until the run-time system can support long pathnames,
+ %% use the data dir.
+ WorkDir = DataDir,
- %% PrivDir as well as directory of Test Server suites
+ %% WorkDir as well as directory of Test Server suites
%% have to be in code path on Test Server node.
[_ | Parts] = lists:reverse(filename:split(DataDir)),
TSDir = filename:join(lists:reverse(Parts)),
@@ -64,7 +68,7 @@ start_slave(Config,_Level) ->
undefined -> [];
Ds -> Ds
end,
- PathDirs = [PrivDir,TSDir | AddPathDirs],
+ PathDirs = [WorkDir,TSDir | AddPathDirs],
[true = rpc:call(Node, code, add_patha, [D]) || D <- PathDirs],
io:format("Dirs added to code path (on ~w):~n",
[Node]),
@@ -73,15 +77,27 @@ start_slave(Config,_Level) ->
true = rpc:call(Node, os, putenv,
["TEST_SERVER_FRAMEWORK", "undefined"]),
- ok = rpc:call(Node, file, set_cwd, [PrivDir]),
- [{node,Node} | Config]
+ ok = rpc:call(Node, file, set_cwd, [WorkDir]),
+ [{node,Node}, {work_dir,WorkDir} | Config]
end.
post_end_per_testcase(_TC, Config, Return, State) ->
Node = proplists:get_value(node, Config),
- cover:stop(Node),
+ Cover = test_server:is_cover(),
+ if Cover-> cover:flush(Node);
+ true -> ok
+ end,
+ erlang:monitor_node(Node, true),
slave:stop(Node),
-
+ receive
+ {nodedown, Node} ->
+ if Cover -> cover:stop(Node);
+ true -> ok
+ end
+ after 5000 ->
+ erlang:monitor_node(Node, false),
+ receive {nodedown, Node} -> ok after 0 -> ok end %flush
+ end,
{Return, State}.
%% Parse an .suite log file
diff --git a/lib/test_server/vsn.mk b/lib/test_server/vsn.mk
index aecf595f3f..b956ebb2b3 100644
--- a/lib/test_server/vsn.mk
+++ b/lib/test_server/vsn.mk
@@ -1 +1 @@
-TEST_SERVER_VSN = 3.5.2
+TEST_SERVER_VSN = 3.5.3
diff --git a/lib/toolbar/src/Makefile b/lib/toolbar/src/Makefile
index 102970a59a..a24846976b 100644
--- a/lib/toolbar/src/Makefile
+++ b/lib/toolbar/src/Makefile
@@ -71,10 +71,10 @@ clean:
rm -f errs core *~
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
docs:
diff --git a/lib/tools/c_src/Makefile.in b/lib/tools/c_src/Makefile.in
index 0382d3228d..aea5686ae9 100644
--- a/lib/tools/c_src/Makefile.in
+++ b/lib/tools/c_src/Makefile.in
@@ -17,6 +17,7 @@
# %CopyrightEnd%
#
+include $(ERL_TOP)/make/output.mk
include $(ERL_TOP)/make/target.mk
include $(ERL_TOP)/erts/include/internal/$(TARGET)/ethread.mk
@@ -150,7 +151,7 @@ _create_dirs := $(shell mkdir -p $(CREATE_DIRS))
all: $(PROGS) $(DRIVERS)
$(ERTS_LIB):
- cd $(ERL_TOP)/erts/lib_src && $(MAKE) $(TYPE)
+ $(make_verbose)cd $(ERL_TOP)/erts/lib_src && $(MAKE) $(TYPE)
docs:
@@ -167,7 +168,7 @@ clean:
#
$(EMEM_OBJ_DIR)/%.o: %.c
- $(CC) $(EMEM_CFLAGS) -o $@ -c $<
+ $(V_CC) $(EMEM_CFLAGS) -o $@ -c $<
#
# Driver targets
@@ -178,7 +179,7 @@ $(EMEM_OBJ_DIR)/%.o: %.c
#
$(BIN_DIR)/emem$(TYPEMARKER)@EXEEXT@: $(EMEM_OBJS) $(ERTS_LIB)
- $(PRE_LD) $(LD) $(EMEM_LDFLAGS) -o $@ $(EMEM_OBJS) $(EMEM_LIBS)
+ $(ld_verbose)$(PRE_LD) $(LD) $(EMEM_LDFLAGS) -o $@ $(EMEM_OBJS) $(EMEM_LIBS)
#
# Release targets
@@ -221,7 +222,8 @@ SED_DEPEND=sed '$(SED_REPL_OBJ_DIR);$(SED_REPL_TT_DIR);$(SED_REPL_TARGET);$(SED_
DEPEND_MK=depend.mk
dep depend:
- @echo "Generating dependency file $(DEPEND_MK)..."
+ [ $(v_p) == 0 ] && echo " GEN "$(DEPEND_MK)
+ $(V_colon)@echo "Generating dependency file $(DEPEND_MK)..."
@echo "# Generated dependency rules." > $(DEPEND_MK);
@echo "# Do *not* edit this file; instead, run 'make depend'." \
>> $(DEPEND_MK);
diff --git a/lib/tools/doc/src/cover.xml b/lib/tools/doc/src/cover.xml
index 683acc025d..a2444ec947 100644
--- a/lib/tools/doc/src/cover.xml
+++ b/lib/tools/doc/src/cover.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2001</year>
- <year>2011</year>
+ <year>2012</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -104,6 +104,13 @@
remove nodes. The same Cover compiled code will be loaded on each
node, and analysis will collect and sum up coverage data results
from all nodes.</p>
+ <p>To only collect data from remote nodes without stopping
+ <c>cover</c> on those nodes, use <c>cover:flush/1</c></p>
+ <p>If the connection to a remote node goes down, the main node
+ will mark it as lost. If the node comes back it will be added
+ again. If the remote node was alive during the disconnected
+ periode, cover data from before and during this periode will be
+ included in the analysis.</p>
</description>
<funcs>
<func>
@@ -477,6 +484,17 @@
remote nodes is fetched and stored on the main node.</p>
</desc>
</func>
+ <func>
+ <name>flush(Nodes) -> ok | {error,not_main_node}</name>
+ <fsummary>Collect cover data from remote nodes.</fsummary>
+ <type>
+ <v>Nodes = [atom()]</v>
+ </type>
+ <desc>
+ <p>Fetch data from the Cover database on the remote nodes and
+ stored on the main node.</p>
+ </desc>
+ </func>
</funcs>
<section>
diff --git a/lib/tools/doc/src/xref.xml b/lib/tools/doc/src/xref.xml
index 17de66bb22..9706ae6746 100644
--- a/lib/tools/doc/src/xref.xml
+++ b/lib/tools/doc/src/xref.xml
@@ -1453,7 +1453,7 @@ Evaluates a predefined analysis.
Note however that the code path will be traversed once for
each used <seealso marker="#library_module">library module</seealso> while setting up module data.
On the other hand, if there are only a few modules that are
- used by not analyzed, using <c>code_path</c> may be faster
+ used but not analyzed, using <c>code_path</c> may be faster
than setting the library path to <c>code:get_path()</c>.
</p>
<p>If the library path is set to <c>code_path</c>, the set of
diff --git a/lib/tools/emacs/erlang-pkg.el b/lib/tools/emacs/erlang-pkg.el
new file mode 100644
index 0000000000..decc696e21
--- /dev/null
+++ b/lib/tools/emacs/erlang-pkg.el
@@ -0,0 +1,3 @@
+(define-package "erlang" "2.7.0"
+ "Erlang major mode"
+ '((flymake-mode "0.4.6")))
diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el
index aae118f3db..2967acf310 100644
--- a/lib/tools/emacs/erlang.el
+++ b/lib/tools/emacs/erlang.el
@@ -1,4 +1,10 @@
-;; erlang.el --- Major modes for editing and running Erlang
+;;; erlang.el --- Major modes for editing and running Erlang
+
+;; Copyright (C) 2004 Free Software Foundation, Inc.
+;; Author: Anders Lindgren
+;; Keywords: erlang, languages, processes
+;; Date: 2011-12-11
+
;; %CopyrightBegin%
;;
;; Copyright Ericsson AB 1996-2012. All Rights Reserved.
@@ -15,10 +21,7 @@
;; under the License.
;;
;; %CopyrightEnd%
-;;
-;; Copyright (C) 2004 Free Software Foundation, Inc.
-;; Author: Anders Lindgren
-;; Keywords: erlang, languages, processes
+;;
;; Lars Thors�n's modifications of 2000-06-07 included.
;; The original version of this package was written by Robert Virding.
@@ -994,6 +997,22 @@ behaviour.")
1 'font-lock-function-name-face t))
"Font lock keyword highlighting a function header.")
+(defface erlang-font-lock-exported-function-name-face
+ '((default (:inherit font-lock-function-name-face)))
+ "Face used for highlighting exported functions.")
+
+(defvar erlang-font-lock-exported-function-name-face
+ 'erlang-font-lock-exported-function-name-face)
+
+(defvar erlang-inhibit-exported-function-name-face nil
+ "Inhibit separate face for exported functions")
+
+(defvar erlang-font-lock-keywords-exported-function-header
+ (list
+ (list #'erlang-match-next-exported-function
+ 1 'erlang-font-lock-exported-function-name-face t))
+ "Font lock keyword highlighting an exported function header.")
+
(defvar erlang-font-lock-keywords-int-bifs
(list
(list (concat erlang-int-bif-regexp "\\s-*(")
@@ -1129,7 +1148,8 @@ There exists three levels of Font Lock keywords for Erlang:
`erlang-font-lock-keywords-1' - Function headers and reserved keywords.
`erlang-font-lock-keywords-2' - Bifs, guards and `single quotes'.
`erlang-font-lock-keywords-3' - Variables, macros and records.
- `erlang-font-lock-keywords-4' - Function names, Funs, LCs (not Atoms)
+ `erlang-font-lock-keywords-4' - Exported functions, Function names,
+ Funs, LCs (not Atoms).
To use a specific level, please set the variable
`font-lock-maximum-decoration' to the appropriate level. Note that the
@@ -1171,6 +1191,7 @@ Example:
(defvar erlang-font-lock-keywords-4
(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
@@ -3659,6 +3680,38 @@ In the future the list may contain more elements."
str)
(store-match-data md))))
+(defun erlang-match-next-exported-function (max)
+ "Returns non-nil if there is an exported function in the current
+buffer between point and MAX."
+ (block nil
+ (while (and (not erlang-inhibit-exported-function-name-face)
+ (erlang-match-next-function max))
+ (when (erlang-last-match-exported-p)
+ (return (match-data))))))
+
+(defun erlang-match-next-function (max)
+ "Searches forward in current buffer for the next erlang function,
+bounded by position MAX."
+ (re-search-forward erlang-defun-prompt-regexp max 'move-point))
+
+(defun erlang-last-match-exported-p ()
+ "Returns non-nil if match-data describes the name and arity of an
+exported function."
+ (save-excursion
+ (save-match-data
+ (goto-char (match-beginning 1))
+ (erlang-function-exported-p
+ (erlang-remove-quotes (erlang-get-function-name))
+ (erlang-get-function-arity)))))
+
+(defun erlang-function-exported-p (name arity)
+ "Returns non-nil if function of name and arity is exported in current buffer."
+ (save-excursion
+ (let* ((old-match-data (match-data))
+ (exports (erlang-get-export)))
+ (store-match-data old-match-data)
+ (member (cons name arity) exports))))
+
;;; Check module name
diff --git a/lib/tools/emacs/vsn.mk b/lib/tools/emacs/vsn.mk
index f33ea8b519..a495da3453 100644
--- a/lib/tools/emacs/vsn.mk
+++ b/lib/tools/emacs/vsn.mk
@@ -1,3 +1,2 @@
-EMACS_VSN = 2.4.13
-
+EMACS_VSN = 2.7.0
diff --git a/lib/tools/src/Makefile b/lib/tools/src/Makefile
index abe1389771..bdd0cdce25 100644
--- a/lib/tools/src/Makefile
+++ b/lib/tools/src/Makefile
@@ -94,10 +94,10 @@ docs:
# ----------------------------------------------------
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
# ----------------------------------------------------
# Release Target
diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl
index e21bd1b88c..ab29d156aa 100644
--- a/lib/tools/src/cover.erl
+++ b/lib/tools/src/cover.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -26,12 +26,17 @@
%% ARCHITECTURE
%% The coverage tool consists of one process on each node involved in
%% coverage analysis. The process is registered as 'cover_server'
-%% (?SERVER). All cover_servers in the distributed system are linked
-%% together. The cover_server on the 'main' node is in charge, and it
-%% traps exits so it can detect nodedown or process crashes on the
-%% remote nodes. This process is implemented by the functions
-%% init_main/1 and main_process_loop/1. The cover_server on the remote
-%% nodes are implemented by the functions init_remote/2 and
+%% (?SERVER). The cover_server on the 'main' node is in charge, and
+%% it monitors the cover_servers on all remote nodes. When it gets a
+%% 'DOWN' message for another cover_server, it marks the node as
+%% 'lost'. If a nodeup is received for a lost node the main node
+%% ensures that the cover compiled modules are loaded again. If the
+%% remote node was alive during the disconnected periode, cover data
+%% for this periode will also be included in the analysis.
+%%
+%% The cover_server process on the main node is implemented by the
+%% functions init_main/1 and main_process_loop/1. The cover_server on
+%% the remote nodes are implemented by the functions init_remote/2 and
%% remote_process_loop/1.
%%
%% TABLES
@@ -81,15 +86,17 @@
export/1, export/2, import/1,
modules/0, imported/0, imported_modules/0, which_nodes/0, is_compiled/1,
reset/1, reset/0,
+ flush/1,
stop/0, stop/1]).
--export([remote_start/1]).
+-export([remote_start/1,get_main_node/0]).
%-export([bump/5]).
-export([transform/4]). % for test purposes
-record(main_state, {compiled=[], % [{Module,File}]
imported=[], % [{Module,File,ImportFile}]
stopper, % undefined | pid()
- nodes=[]}). % [Node]
+ nodes=[], % [Node]
+ lost_nodes=[]}). % [Node]
-record(remote_state, {compiled=[], % [{Module,File}]
main_node}). % atom()
@@ -497,6 +504,19 @@ stop(Node) when is_atom(Node) ->
stop(Nodes) ->
call({stop,remove_myself(Nodes,[])}).
+%% flush(Nodes) -> ok | {error,not_main_node}
+%% Nodes = [Node] | Node
+%% Node = atom()
+%% Error = {not_cover_compiled,Module}
+flush(Node) when is_atom(Node) ->
+ flush([Node]);
+flush(Nodes) ->
+ call({flush,remove_myself(Nodes,[])}).
+
+%% Used by test_server only. Not documented.
+get_main_node() ->
+ call(get_main_node).
+
%% bump(Module, Function, Arity, Clause, Line)
%% Module = Function = atom()
%% Arity = Clause = Line = integer()
@@ -541,7 +561,10 @@ remote_call(Node,Request) ->
Return =
receive
{'DOWN', Ref, _Type, _Object, _Info} ->
- {error,node_dead};
+ case Request of
+ {remote,stop} -> ok;
+ _ -> {error,node_dead}
+ end;
{?SERVER,Reply} ->
Reply
end,
@@ -569,40 +592,14 @@ init_main(Starter) ->
ets:new(?BINARY_TABLE, [set, named_table]),
ets:new(?COLLECTION_TABLE, [set, public, named_table]),
ets:new(?COLLECTION_CLAUSE_TABLE, [set, public, named_table]),
- process_flag(trap_exit,true),
+ net_kernel:monitor_nodes(true),
Starter ! {?SERVER,started},
main_process_loop(#main_state{}).
main_process_loop(State) ->
receive
{From, {start_nodes,Nodes}} ->
- ThisNode = node(),
- StartedNodes =
- lists:foldl(
- fun(Node,Acc) ->
- case rpc:call(Node,cover,remote_start,[ThisNode]) of
- {ok,RPid} ->
- link(RPid),
- [Node|Acc];
- Error ->
- io:format("Could not start cover on ~w: ~p\n",
- [Node,Error]),
- Acc
- end
- end,
- [],
- Nodes),
-
- %% In case some of the compiled modules have been unloaded they
- %% should not be loaded on the new node.
- {_LoadedModules,Compiled} =
- get_compiled_still_loaded(State#main_state.nodes,
- State#main_state.compiled),
- remote_load_compiled(StartedNodes,Compiled),
-
- State1 =
- State#main_state{nodes = State#main_state.nodes ++ StartedNodes,
- compiled = Compiled},
+ {StartedNodes,State1} = do_start_nodes(Nodes, State),
reply(From, {ok,StartedNodes}),
main_process_loop(State1);
@@ -707,8 +704,15 @@ main_process_loop(State) ->
{From, {stop,Nodes}} ->
remote_collect('_',Nodes,true),
reply(From, ok),
- State1 = State#main_state{nodes=State#main_state.nodes--Nodes},
- main_process_loop(State1);
+ Nodes1 = State#main_state.nodes--Nodes,
+ LostNodes1 = State#main_state.lost_nodes--Nodes,
+ main_process_loop(State#main_state{nodes=Nodes1,
+ lost_nodes=LostNodes1});
+
+ {From, {flush,Nodes}} ->
+ remote_collect('_',Nodes,false),
+ reply(From, ok),
+ main_process_loop(State);
{From, stop} ->
lists:foreach(
@@ -788,14 +792,37 @@ main_process_loop(State) ->
end,
main_process_loop(S);
- {'EXIT',Pid,_Reason} ->
- %% Exit is trapped on the main node only, so this will only happen
- %% there. I assume that I'm only linked to cover_servers on remote
- %% nodes, so this must be one of them crashing.
- %% Remove node from list!
- State1 = State#main_state{nodes=State#main_state.nodes--[node(Pid)]},
+ {'DOWN', _MRef, process, {?SERVER,Node}, _Info} ->
+ %% A remote cover_server is down, mark as lost
+ {Nodes,Lost} =
+ case lists:member(Node,State#main_state.nodes) of
+ true ->
+ N = State#main_state.nodes--[Node],
+ L = [Node|State#main_state.lost_nodes],
+ {N,L};
+ false -> % node stopped
+ {State#main_state.nodes,State#main_state.lost_nodes}
+ end,
+ main_process_loop(State#main_state{nodes=Nodes,lost_nodes=Lost});
+
+ {nodeup,Node} ->
+ State1 =
+ case lists:member(Node,State#main_state.lost_nodes) of
+ true ->
+ sync_compiled(Node,State);
+ false ->
+ State
+ end,
main_process_loop(State1);
+
+ {nodedown,_} ->
+ %% Will be taken care of when 'DOWN' message arrives
+ main_process_loop(State);
+ {From, get_main_node} ->
+ reply(From, node()),
+ main_process_loop(State);
+
get_status ->
io:format("~p~n",[State]),
main_process_loop(State)
@@ -850,7 +877,16 @@ remote_process_loop(State) ->
{remote,stop} ->
reload_originals(State#remote_state.compiled),
unregister(?SERVER),
- remote_reply(State#remote_state.main_node, ok);
+ ok; % not replying since 'DOWN' message will be received anyway
+
+ {remote,get_compiled} ->
+ remote_reply(State#remote_state.main_node,
+ State#remote_state.compiled),
+ remote_process_loop(State);
+
+ {From, get_main_node} ->
+ remote_reply(From, State#remote_state.main_node),
+ remote_process_loop(State);
get_status ->
io:format("~p~n",[State]),
@@ -961,6 +997,36 @@ unload([]) ->
%%%--Handling of remote nodes--------------------------------------------
+do_start_nodes(Nodes, State) ->
+ ThisNode = node(),
+ StartedNodes =
+ lists:foldl(
+ fun(Node,Acc) ->
+ case rpc:call(Node,cover,remote_start,[ThisNode]) of
+ {ok,_RPid} ->
+ erlang:monitor(process,{?SERVER,Node}),
+ [Node|Acc];
+ Error ->
+ io:format("Could not start cover on ~w: ~p\n",
+ [Node,Error]),
+ Acc
+ end
+ end,
+ [],
+ Nodes),
+
+ %% In case some of the compiled modules have been unloaded they
+ %% should not be loaded on the new node.
+ {_LoadedModules,Compiled} =
+ get_compiled_still_loaded(State#main_state.nodes,
+ State#main_state.compiled),
+ remote_load_compiled(StartedNodes,Compiled),
+
+ State1 =
+ State#main_state{nodes = State#main_state.nodes ++ StartedNodes,
+ compiled = Compiled},
+ {StartedNodes, State1}.
+
%% start the cover_server on a remote node
remote_start(MainNode) ->
case whereis(?SERVER) of
@@ -984,6 +1050,30 @@ remote_start(MainNode) ->
{error,{already_started,Pid}}
end.
+%% If a lost node comes back, ensure that main and remote node has the
+%% same cover compiled modules. Note that no action is taken if the
+%% same {Mod,File} eksists on both, i.e. code change is not handled!
+sync_compiled(Node,State) ->
+ #main_state{compiled=Compiled0,nodes=Nodes,lost_nodes=Lost}=State,
+ State1 =
+ case remote_call(Node,{remote,get_compiled}) of
+ {error,node_dead} ->
+ {_,S} = do_start_nodes([Node],State),
+ S;
+ {error,_} ->
+ State;
+ RemoteCompiled ->
+ {_,Compiled} = get_compiled_still_loaded(Nodes,Compiled0),
+ Unload = [UM || {UM,_}=U <- RemoteCompiled,
+ false == lists:member(U,Compiled)],
+ remote_unload([Node],Unload),
+ Load = [L || L <- Compiled,
+ false == lists:member(L,RemoteCompiled)],
+ remote_load_compiled([Node],Load),
+ State#main_state{compiled=Compiled, nodes=[Node|Nodes]}
+ end,
+ State1#main_state{lost_nodes=Lost--[Node]}.
+
%% Load a set of cover compiled modules on remote nodes,
%% We do it ?MAX_MODS modules at a time so that we don't
%% run out of memory on the cover_server node.
@@ -1094,7 +1184,6 @@ remove_myself([Node|Nodes],Acc) ->
remove_myself(Nodes,[Node|Acc]);
remove_myself([],Acc) ->
Acc.
-
%%%--Handling of modules state data--------------------------------------
@@ -2007,30 +2096,40 @@ do_analyse_to_file(Module, OutFile, ErlFile, HTML) ->
case file:open(OutFile, [write]) of
{ok, OutFd} ->
if HTML ->
- io:format(OutFd,
- "<html>\n"
- "<head><title>~s</title></head>"
- "<body bgcolor=white text=black>\n"
- "<pre>\n",
- [OutFile]);
+ Encoding = encoding(ErlFile),
+ Header =
+ ["<!DOCTYPE HTML PUBLIC "
+ "\"-//W3C//DTD HTML 3.2 Final//EN\">\n"
+ "<html>\n"
+ "<head>\n"
+ "<meta http-equiv=\"Content-Type\""
+ " content=\"text/html; charset=",
+ Encoding,"\"/>\n"
+ "<title>",OutFile,"</title>\n"
+ "</head>"
+ "<body style='background-color: white;"
+ " color: black'>\n"
+ "<pre>\n"],
+ file:write(OutFd,Header);
true -> ok
end,
%% Write some initial information to the output file
{{Y,Mo,D},{H,Mi,S}} = calendar:local_time(),
- io:format(OutFd, "File generated from ~s by COVER "
- "~p-~s-~s at ~s:~s:~s~n",
- [ErlFile,
- Y,
- string:right(integer_to_list(Mo), 2, $0),
- string:right(integer_to_list(D), 2, $0),
- string:right(integer_to_list(H), 2, $0),
- string:right(integer_to_list(Mi), 2, $0),
- string:right(integer_to_list(S), 2, $0)]),
- io:format(OutFd, "~n"
- "**************************************"
- "**************************************"
- "~n~n", []),
+ Timestamp =
+ io_lib:format("~p-~s-~s at ~s:~s:~s",
+ [Y,
+ string:right(integer_to_list(Mo), 2, $0),
+ string:right(integer_to_list(D), 2, $0),
+ string:right(integer_to_list(H), 2, $0),
+ string:right(integer_to_list(Mi), 2, $0),
+ string:right(integer_to_list(S), 2, $0)]),
+ file:write(OutFd,
+ ["File generated from ",ErlFile," by COVER ",
+ Timestamp,"\n\n"
+ "**************************************"
+ "**************************************"
+ "\n\n"]),
print_lines(Module, InFd, OutFd, 1, HTML),
@@ -2254,7 +2353,13 @@ do_reset2([]) ->
do_clear(Module) ->
ets:match_delete(?COVER_CLAUSE_TABLE, {Module,'_'}),
ets:match_delete(?COVER_TABLE, {#bump{module=Module},'_'}),
- ets:match_delete(?COLLECTION_TABLE, {#bump{module=Module},'_'}).
+ case lists:member(?COLLECTION_TABLE, ets:all()) of
+ true ->
+ %% We're on the main node
+ ets:match_delete(?COLLECTION_TABLE, {#bump{module=Module},'_'});
+ false ->
+ ok
+ end.
not_loaded(Module, unloaded, State) ->
do_clear(Module),
@@ -2307,7 +2412,7 @@ pmap(Fun, [E | Rest], Pids, Limit, Cnt, Acc) when Cnt < Limit ->
pmap(Fun, Rest, Pids ++ [Pid], Limit, Cnt + 1, Acc);
pmap(Fun, List, [Pid | Pids], Limit, Cnt, Acc) ->
receive
- {'DOWN', _Ref, process, _, _} ->
+ {'DOWN', _Ref, process, X, _} when is_pid(X) ->
pmap(Fun, List, [Pid | Pids], Limit, Cnt - 1, Acc);
{res, Pid, Res} ->
pmap(Fun, List, Pids, Limit, Cnt, [Res | Acc])
@@ -2316,6 +2421,23 @@ pmap(_Fun, [], [], _Limit, 0, Acc) ->
lists:reverse(Acc);
pmap(Fun, [], [], Limit, Cnt, Acc) ->
receive
- {'DOWN', _Ref, process, _, _} ->
+ {'DOWN', _Ref, process, X, _} when is_pid(X) ->
pmap(Fun, [], [], Limit, Cnt - 1, Acc)
end.
+
+%%%-----------------------------------------------------------------
+%%% Read encoding from source file
+encoding(File) ->
+ Encoding =
+ case epp:read_encoding(File) of
+ none ->
+ epp:default_encoding();
+ E ->
+ E
+ end,
+ html_encoding(Encoding).
+
+html_encoding(latin1) ->
+ "iso-8859-1";
+html_encoding(utf8) ->
+ "utf-8".
diff --git a/lib/tools/src/lcnt.erl b/lib/tools/src/lcnt.erl
index 989a661b75..70d62307c8 100644
--- a/lib/tools/src/lcnt.erl
+++ b/lib/tools/src/lcnt.erl
@@ -1,7 +1,8 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2012. All Rights Reserved.
%%
%% The 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/tools/src/tools.app.src b/lib/tools/src/tools.app.src
index 94998fb763..553c5eb96b 100644
--- a/lib/tools/src/tools.app.src
+++ b/lib/tools/src/tools.app.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
%%
%% The 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/tools/test/cover_SUITE.erl b/lib/tools/test/cover_SUITE.erl
index c2c708d806..57260a3869 100644
--- a/lib/tools/test/cover_SUITE.erl
+++ b/lib/tools/test/cover_SUITE.erl
@@ -23,7 +23,9 @@
init_per_group/2,end_per_group/2]).
-export([start/1, compile/1, analyse/1, misc/1, stop/1,
- distribution/1, export_import/1,
+ distribution/1, reconnect/1, die_and_reconnect/1,
+ dont_reconnect_after_stop/1, stop_node_after_disconnect/1,
+ export_import/1,
otp_5031/1, eif/1, otp_5305/1, otp_5418/1, otp_6115/1, otp_7095/1,
otp_8188/1, otp_8270/1, otp_8273/1, otp_8340/1]).
@@ -45,7 +47,9 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
case whereis(cover_server) of
undefined ->
- [start, compile, analyse, misc, stop, distribution,
+ [start, compile, analyse, misc, stop,
+ distribution, reconnect, die_and_reconnect,
+ dont_reconnect_after_stop, stop_node_after_disconnect,
export_import, otp_5031, eif, otp_5305, otp_5418,
otp_6115, otp_7095, otp_8188, otp_8270, otp_8273,
otp_8340];
@@ -85,8 +89,11 @@ init_per_testcase(TC, Config) when TC =:= misc;
init_per_testcase(_TestCase, Config) ->
Config.
-end_per_testcase(_TestCase, _Config) ->
- %cover:stop(),
+end_per_testcase(TestCase, _Config) ->
+ case lists:member(TestCase,[start,compile,analyse,misc]) of
+ true -> ok;
+ false -> cover:stop()
+ end,
ok.
start(suite) -> [];
@@ -326,14 +333,16 @@ distribution(Config) when is_list(Config) ->
?line {ok,N1} = ?t:start_node(cover_SUITE_distribution1,slave,[]),
?line {ok,N2} = ?t:start_node(cover_SUITE_distribution2,slave,[]),
?line {ok,N3} = ?t:start_node(cover_SUITE_distribution3,slave,[]),
+ ?line {ok,N4} = ?t:start_node(cover_SUITE_distribution4,slave,[]),
%% Check that an already compiled module is loaded on new nodes
?line {ok,f} = cover:compile(f),
- ?line {ok,[_,_,_]} = cover:start(nodes()),
+ ?line {ok,[_,_,_,_]} = cover:start(nodes()),
?line cover_compiled = code:which(f),
?line cover_compiled = rpc:call(N1,code,which,[f]),
?line cover_compiled = rpc:call(N2,code,which,[f]),
?line cover_compiled = rpc:call(N3,code,which,[f]),
+ ?line cover_compiled = rpc:call(N4,code,which,[f]),
%% Check that a node cannot be started twice
?line {ok,[]} = cover:start(N2),
@@ -351,6 +360,7 @@ distribution(Config) when is_list(Config) ->
?line cover_compiled = rpc:call(N1,code,which,[v]),
?line cover_compiled = rpc:call(N2,code,which,[v]),
?line cover_compiled = rpc:call(N3,code,which,[v]),
+ ?line cover_compiled = rpc:call(N4,code,which,[v]),
%% this is lost when the node is killed
?line rpc:call(N3,f,f2,[]),
@@ -385,6 +395,18 @@ distribution(Config) when is_list(Config) ->
%% reset on the remote node(s))
?line check_f_calls(1,1),
+ %% Another checn that data is not fetched twice, i.e. when flushed
+ %% then analyse should not add the same data again.
+ ?line rpc:call(N4,f,f2,[]),
+ ?line ok = cover:flush(N4),
+ ?line check_f_calls(1,2),
+
+ %% Check that flush collects data so calls are not lost if node is killed
+ ?line rpc:call(N4,f,f2,[]),
+ ?line ok = cover:flush(N4),
+ ?line rpc:call(N4,erlang,halt,[]),
+ ?line check_f_calls(1,3),
+
%% Check that stop() unloads on all nodes
?line ok = cover:stop(),
?line timer:sleep(100), %% Give nodes time to unload on slow machines.
@@ -393,20 +415,205 @@ distribution(Config) when is_list(Config) ->
?line true = is_unloaded(LocalBeam),
?line true = is_unloaded(N2Beam),
- %% Check that cover_server on remote node dies if main node dies
+ %% Check that cover_server on remote node does not die if main node dies
?line {ok,[N1]} = cover:start(N1),
- ?line true = is_pid(rpc:call(N1,erlang,whereis,[cover_server])),
+ ?line true = is_pid(N1Server = rpc:call(N1,erlang,whereis,[cover_server])),
?line exit(whereis(cover_server),kill),
- ?line timer:sleep(10),
- ?line undefined = rpc:call(N1,erlang,whereis,[cover_server]),
-
+ ?line timer:sleep(100),
+ ?line N1Server = rpc:call(N1,erlang,whereis,[cover_server]),
+
%% Cleanup
?line Files = lsfiles(),
?line remove(files(Files, ".beam")),
?line ?t:stop_node(N1),
?line ?t:stop_node(N2).
-
+%% Test that a lost node is reconnected
+reconnect(Config) ->
+ DataDir = ?config(data_dir, Config),
+ ok = file:set_cwd(DataDir),
+
+ {ok,a} = compile:file(a),
+ {ok,b} = compile:file(b),
+ {ok,f} = compile:file(f),
+
+ {ok,N1} = ?t:start_node(cover_SUITE_reconnect,peer,
+ [{args," -pa " ++ DataDir},{start_cover,false}]),
+ {ok,a} = cover:compile(a),
+ {ok,f} = cover:compile(f),
+ {ok,[N1]} = cover:start(nodes()),
+
+ %% Some calls to check later
+ rpc:call(N1,f,f1,[]),
+ cover:flush(N1),
+ rpc:call(N1,f,f1,[]),
+
+ %% This will cause a call to f:f2() when nodes()==[] on N1
+ rpc:cast(N1,f,call_f2_when_isolated,[]),
+
+ %% Disconnect and check that node is removed from main cover node
+ net_kernel:disconnect(N1),
+ timer:sleep(500), % allow some to detect disconnect and for f:f2() call
+ [] = cover:which_nodes(),
+
+ %% Do some add one module (b) and remove one module (a)
+ code:purge(a),
+ {module,a} = code:load_file(a),
+ {ok,b} = cover:compile(b),
+ cover_compiled = code:which(b),
+
+ [] = cover:which_nodes(),
+ check_f_calls(1,0), % only the first call - before the flush
+
+ %% Reconnect the node and check that b and f are cover compiled but not a
+ net_kernel:connect_node(N1),
+ timer:sleep(100),
+ [N1] = cover:which_nodes(), % we are reconnected
+ cover_compiled = rpc:call(N1,code,which,[b]),
+ cover_compiled = rpc:call(N1,code,which,[f]),
+ ABeam = rpc:call(N1,code,which,[a]),
+ false = (cover_compiled==ABeam),
+
+ %% Ensure that we have:
+ %% * one f1 call from before the flush,
+ %% * one f1 call from after the flush but before disconnect
+ %% * one f2 call when disconnected
+ check_f_calls(2,1),
+
+ cover:stop(),
+ ?t:stop_node(N1),
+ ok.
+
+%% Test that a lost node is reconnected - also if it has been dead
+die_and_reconnect(Config) ->
+ DataDir = ?config(data_dir, Config),
+ ok = file:set_cwd(DataDir),
+
+ {ok,f} = compile:file(f),
+
+ NodeName = cover_SUITE_die_and_reconnect,
+ {ok,N1} = ?t:start_node(NodeName,peer,
+ [{args," -pa " ++ DataDir},{start_cover,false}]),
+ %% {ok,a} = cover:compile(a),
+ {ok,f} = cover:compile(f),
+ {ok,[N1]} = cover:start(nodes()),
+
+ %% Some calls to check later
+ rpc:call(N1,f,f1,[]),
+ cover:flush(N1),
+ rpc:call(N1,f,f1,[]),
+
+ %% Kill the node
+ rpc:call(N1,erlang,halt,[]),
+ [] = cover:which_nodes(),
+
+ check_f_calls(1,0), % only the first call - before the flush
+
+ %% Restart the node and check that cover reconnects
+ {ok,N1} = ?t:start_node(NodeName,peer,
+ [{args," -pa " ++ DataDir},{start_cover,false}]),
+ timer:sleep(100),
+ [N1] = cover:which_nodes(), % we are reconnected
+ cover_compiled = rpc:call(N1,code,which,[f]),
+
+ %% One more call...
+ rpc:call(N1,f,f1,[]),
+
+ %% Ensure that no more calls are counted
+ check_f_calls(2,0),
+
+ cover:stop(),
+ ?t:stop_node(N1),
+ ok.
+
+%% Test that a stopped node is not marked as lost, i.e. that it is not
+%% reconnected if it is restarted (OTP-10638)
+dont_reconnect_after_stop(Config) ->
+ DataDir = ?config(data_dir, Config),
+ ok = file:set_cwd(DataDir),
+
+ {ok,f} = compile:file(f),
+
+ NodeName = cover_SUITE_dont_reconnect_after_stop,
+ {ok,N1} = ?t:start_node(NodeName,peer,
+ [{args," -pa " ++ DataDir},{start_cover,false}]),
+ {ok,f} = cover:compile(f),
+ {ok,[N1]} = cover:start(nodes()),
+
+ %% A call to check later
+ rpc:call(N1,f,f1,[]),
+
+ %% Stop cover on the node, then terminate the node
+ cover:stop(N1),
+ rpc:call(N1,erlang,halt,[]),
+ [] = cover:which_nodes(),
+
+ check_f_calls(1,0),
+
+ %% Restart the node and check that cover does not reconnect
+ {ok,N1} = ?t:start_node(NodeName,peer,
+ [{args," -pa " ++ DataDir},{start_cover,false}]),
+ timer:sleep(300),
+ [] = cover:which_nodes(),
+ Beam = rpc:call(N1,code,which,[f]),
+ false = (Beam==cover_compiled),
+
+ %% One more call...
+ rpc:call(N1,f,f1,[]),
+ cover:flush(N1),
+
+ %% Ensure that the last call is not counted
+ check_f_calls(1,0),
+
+ cover:stop(),
+ ?t:stop_node(N1),
+ ok.
+
+%% Test that a node which is stopped while it is marked as lost is not
+%% reconnected if it is restarted (OTP-10638)
+stop_node_after_disconnect(Config) ->
+ DataDir = ?config(data_dir, Config),
+ ok = file:set_cwd(DataDir),
+
+ {ok,f} = compile:file(f),
+
+ NodeName = cover_SUITE_stop_node_after_disconnect,
+ {ok,N1} = ?t:start_node(NodeName,peer,
+ [{args," -pa " ++ DataDir},{start_cover,false}]),
+ {ok,f} = cover:compile(f),
+ {ok,[N1]} = cover:start(nodes()),
+
+ %% A call to check later
+ rpc:call(N1,f,f1,[]),
+
+ %% Flush the node, then terminate the node to make it marked as lost
+ cover:flush(N1),
+ rpc:call(N1,erlang,halt,[]),
+
+ check_f_calls(1,0),
+
+ %% Stop cover on node
+ cover:stop(N1),
+
+ %% Restart the node and check that cover does not reconnect
+ {ok,N1} = ?t:start_node(NodeName,peer,
+ [{args," -pa " ++ DataDir},{start_cover,false}]),
+ timer:sleep(300),
+ [] = cover:which_nodes(),
+ Beam = rpc:call(N1,code,which,[f]),
+ false = (Beam==cover_compiled),
+
+ %% One more call...
+ rpc:call(N1,f,f1,[]),
+ cover:flush(N1),
+
+ %% Ensure that the last call is not counted
+ check_f_calls(1,0),
+
+ cover:stop(),
+ ?t:stop_node(N1),
+ ok.
+
export_import(suite) -> [];
export_import(Config) when is_list(Config) ->
?line DataDir = ?config(data_dir, Config),
@@ -795,7 +1002,7 @@ otp_8270(Config) when is_list(Config) ->
ok.
otp_8273(doc) ->
- ["OTP-8270. Bug."];
+ ["OTP-8273. Bug."];
otp_8273(suite) -> [];
otp_8273(Config) when is_list(Config) ->
Test = <<"-module(t).
@@ -1238,4 +1445,4 @@ is_unloaded(What) ->
end.
check_f_calls(F1,F2) ->
- {ok,[{{f,f1,0},F1},{{f,f2,0},F2}]} = cover:analyse(f,calls,function).
+ {ok,[{{f,f1,0},F1},{{f,f2,0},F2}|_]} = cover:analyse(f,calls,function).
diff --git a/lib/tools/test/cover_SUITE_data/f.erl b/lib/tools/test/cover_SUITE_data/f.erl
index 1ef8bbdb49..ce2963014a 100644
--- a/lib/tools/test/cover_SUITE_data/f.erl
+++ b/lib/tools/test/cover_SUITE_data/f.erl
@@ -1,5 +1,5 @@
-module(f).
--export([f1/0,f2/0]).
+-export([f1/0,f2/0,call_f2_when_isolated/0]).
f1() ->
f1_line1,
@@ -8,3 +8,12 @@ f1() ->
f2() ->
f2_line1,
f2_line2.
+
+call_f2_when_isolated() ->
+ case nodes() of
+ [] ->
+ f2();
+ _ ->
+ timer:sleep(100),
+ call_f2_when_isolated()
+ end.
diff --git a/lib/tools/test/cprof_SUITE.erl b/lib/tools/test/cprof_SUITE.erl
index ce5cf66a14..93caee0c8f 100644
--- a/lib/tools/test/cprof_SUITE.erl
+++ b/lib/tools/test/cprof_SUITE.erl
@@ -230,10 +230,10 @@ on_load_test(Config) ->
%%
?line N4 = cprof:restart(),
?line {ok,Module} = c:c(File, [{outdir,Priv}]),
- ?line L = Module:seq(1, M, fun succ/1),
- ?line Lr = Module:seq_r(1, M, fun succ/1),
- ?line L = seq(1, M, fun succ/1),
- ?line Lr = seq_r(1, M, fun succ/1),
+ ?line L = Module:seq(1, M, fun (I) -> succ(I) end),
+ ?line Lr = Module:seq_r(1, M, fun (I) -> succ(I) end),
+ ?line L = seq(1, M, fun (I) -> succ(I) end),
+ ?line Lr = seq_r(1, M, fun (I) -> succ(I) end),
?line N2 = cprof:pause(),
?line {Module,0,[]} = cprof:analyse(Module),
?line M_1 = M - 1,
@@ -265,10 +265,10 @@ modules_test(Config) ->
?line M2__1 = M2 + 1,
?line erlang:yield(),
?line N = cprof:start(),
- ?line L = Module:seq(1, M, fun succ/1),
- ?line Lr = Module:seq_r(1, M, fun succ/1),
- ?line L = seq(1, M, fun succ/1),
- ?line Lr = seq_r(1, M, fun succ/1),
+ ?line L = Module:seq(1, M, fun (I) -> succ(I) end),
+ ?line Lr = Module:seq_r(1, M, fun (I) -> succ(I) end),
+ ?line L = seq(1, M, fun (I) -> succ(I) end),
+ ?line Lr = seq_r(1, M, fun (I) -> succ(I) end),
?line N = cprof:pause(),
?line Lr = lists:reverse(L),
?line M_1 = M - 1,
diff --git a/lib/tools/test/xref_SUITE.erl b/lib/tools/test/xref_SUITE.erl
index fd3e111d8d..dc06678b8e 100644
--- a/lib/tools/test/xref_SUITE.erl
+++ b/lib/tools/test/xref_SUITE.erl
@@ -1,3 +1,4 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
@@ -46,7 +47,7 @@
-export([
add/1, default/1, info/1, lib/1, read/1, read2/1, remove/1,
replace/1, update/1, deprecated/1, trycatch/1,
- abstract_modules/1, fun_mfa/1, fun_mfa_r14/1,
+ fun_mfa/1, fun_mfa_r14/1,
fun_mfa_vars/1, qlc/1]).
-export([
@@ -82,7 +83,7 @@ groups() ->
modules]},
{files, [],
[add, default, info, lib, read, read2, remove, replace,
- update, deprecated, trycatch, abstract_modules, fun_mfa,
+ update, deprecated, trycatch, fun_mfa,
fun_mfa_r14, fun_mfa_vars, qlc]},
{analyses, [],
[analyze, basic, md, q, variables, unused_locals]},
@@ -1668,64 +1669,6 @@ trycatch(Conf) when is_list(Conf) ->
ok.
-abstract_modules(suite) -> [];
-abstract_modules(doc) -> ["OTP-5520: Abstract (parameterized) modules."];
-abstract_modules(Conf) when is_list(Conf) ->
- Dir = ?copydir,
- File = fname(Dir, "absmod.erl"),
- MFile = fname(Dir, "absmod"),
- Beam = fname(Dir, "absmod.beam"),
- Test = <<"-module(param, [A, B]).
-
- -export([args/1]).
-
- args(C) ->
- X = local(C),
- Y = THIS:new(), % undef
- Z = new(A, B),
- {X, Y, Z}.
-
- local(C) ->
- module_info(C).
- ">>,
-
- ?line ok = file:write_file(File, Test),
-
- %% The compiler will no longer allow us to have a mismatch between
- %% the module name and the output file, so we must use a trick.
- ?line {ok, param, BeamCode} = compile:file(File, [binary,debug_info]),
- ?line ok = file:write_file(Beam, BeamCode),
-
- ?line {ok, _} = xref:start(s),
- ?line {ok, param} = xref:add_module(s, MFile, {warnings,false}),
- A = param,
- ?line {ok, [{{{A,args,1},{'$M_EXPR',new,0}},[7]},
- {{{A,args,1},{A,local,1}},[6]},
- {{{A,args,1},{A,new,2}},[8]},
- {{{A,local,1},{A,module_info,1}},[12]},
- {{{param,new,2},{param,instance,2}},[0]}]} =
- xref:q(s, "(Lin) E"),
- ?line {ok,[{param,args,1},
- {param,instance,2},
- {param,local,1},
- {param,module_info,1},
- {param,new,2}]} = xref:q(s, "F"),
-
- ?line ok = check_state(s),
- ?line xref:stop(s),
-
- ?line {ok, _} = xref:start(s, {xref_mode, modules}),
- ?line {ok, param} = xref:add_module(s, MFile),
- ?line {ok,[{param,args,1},
- {param,instance,2},
- {param,new,2}]} = xref:q(s, "X"),
- ?line ok = check_state(s),
- ?line xref:stop(s),
-
- ?line ok = file:delete(File),
- ?line ok = file:delete(Beam),
- ok.
-
fun_mfa(suite) -> [];
fun_mfa(doc) -> ["OTP-5653: fun M:F/A."];
fun_mfa(Conf) when is_list(Conf) ->
@@ -2521,7 +2464,7 @@ otp_10192(doc) ->
otp_10192(Conf) when is_list(Conf) ->
PrivDir = ?privdir,
{ok, _Pid} = xref:start(s),
- Dir = filename:join(PrivDir, "�"),
+ Dir = filename:join(PrivDir, "ä"),
ok = file:make_dir(Dir),
{ok, []} = xref:add_directory(s, Dir),
xref:stop(s),
diff --git a/lib/tv/src/Makefile b/lib/tv/src/Makefile
index da1713e156..3d680c1eaf 100644
--- a/lib/tv/src/Makefile
+++ b/lib/tv/src/Makefile
@@ -109,10 +109,10 @@ clean:
rm -f errs core *~
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
docs:
diff --git a/lib/typer/src/Makefile b/lib/typer/src/Makefile
index 1f94d8fdc8..13af466755 100644
--- a/lib/typer/src/Makefile
+++ b/lib/typer/src/Makefile
@@ -82,13 +82,13 @@ clean:
# ----------------------------------------------------
$(EBIN)/typer.$(EMULATOR): typer.erl ../vsn.mk Makefile
- erlc -W $(ERL_COMPILE_FLAGS) -DVSN="\"v$(VSN)\"" -o$(EBIN) typer.erl
+ $(erlc_verbose)erlc -W $(ERL_COMPILE_FLAGS) -DVSN="\"v$(VSN)\"" -o$(EBIN) typer.erl
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
# ---------------------------------------------------------------------
# dependencies
diff --git a/lib/webtool/src/Makefile b/lib/webtool/src/Makefile
index 783ffad79a..f28c777240 100644
--- a/lib/webtool/src/Makefile
+++ b/lib/webtool/src/Makefile
@@ -76,10 +76,10 @@ docs:
# ----------------------------------------------------
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
# ----------------------------------------------------
# Release Target
diff --git a/lib/wx/.gitignore b/lib/wx/.gitignore
index 0fa427bfe5..960c76a779 100644
--- a/lib/wx/.gitignore
+++ b/lib/wx/.gitignore
@@ -1,4 +1,5 @@
test_log_*
wx_test_case_info
-api_gen/gl_man?
-doc/html/* \ No newline at end of file
+doc/html/*
+%% Don't delete links to man src when git clean -dfX
+%% api_gen/gl_man?
diff --git a/lib/wx/aclocal.m4 b/lib/wx/aclocal.m4
index b1cf1fe404..918e30a886 100644
--- a/lib/wx/aclocal.m4
+++ b/lib/wx/aclocal.m4
@@ -740,11 +740,16 @@ dnl Try to find POSIX threads
dnl The usual pthread lib...
AC_CHECK_LIB(pthread, pthread_create, THR_LIBS="-lpthread")
-dnl FreeBSD has pthreads in special c library, c_r...
+dnl Very old versions of FreeBSD have pthreads in special c library, c_r...
if test "x$THR_LIBS" = "x"; then
AC_CHECK_LIB(c_r, pthread_create, THR_LIBS="-lc_r")
fi
+dnl QNX has pthreads in standard C library
+ if test "x$THR_LIBS" = "x"; then
+ AC_CHECK_FUNC(pthread_create, THR_LIBS="none_needed")
+ fi
+
dnl On ofs1 the '-pthread' switch should be used
if test "x$THR_LIBS" = "x"; then
AC_MSG_CHECKING([if the '-pthread' switch can be used])
@@ -765,6 +770,9 @@ dnl On ofs1 the '-pthread' switch should be used
if test "x$THR_LIBS" != "x"; then
THR_DEFS="$THR_DEFS -D_THREAD_SAFE -D_REENTRANT -DPOSIX_THREADS"
THR_LIB_NAME=pthread
+ if test "x$THR_LIBS" = "xnone_needed"; then
+ THR_LIBS=
+ fi
case $host_os in
solaris*)
THR_DEFS="$THR_DEFS -D_POSIX_PTHREAD_SEMANTICS" ;;
@@ -1841,6 +1849,31 @@ case $erl_gethrvtime in
esac
])dnl
+dnl ----------------------------------------------------------------------
+dnl
+dnl LM_TRY_ENABLE_CFLAG
+dnl
+dnl
+dnl Tries a CFLAG and sees if it can be enabled without compiler errors
+dnl $1: textual cflag to add
+dnl $2: variable to store the modified CFLAG in
+dnl Usage example LM_TRY_ENABLE_CFLAG([-Werror=return-type], [CFLAGS])
+dnl
+dnl
+AC_DEFUN([LM_TRY_ENABLE_CFLAG], [
+ AC_MSG_CHECKING([if we can add $1 to $2 (via CFLAGS)])
+ saved_CFLAGS=$CFLAGS;
+ CFLAGS="$1 $$2";
+ AC_TRY_COMPILE([],[return 0;],can_enable_flag=true,can_enable_flag=false)
+ CFLAGS=$saved_CFLAGS;
+ if test "X$can_enable_flag" = "Xtrue"; then
+ AC_MSG_RESULT([yes])
+ AS_VAR_SET($2, "$1 $$2")
+ else
+ AC_MSG_RESULT([no])
+ fi
+])
+
dnl ERL_TRY_LINK_JAVA(CLASSES, FUNCTION-BODY
dnl [ACTION_IF_FOUND [, ACTION-IF-NOT-FOUND]])
dnl Freely inspired by AC_TRY_LINK. (Maybe better to create a
diff --git a/lib/wx/api_gen/gen_util.erl b/lib/wx/api_gen/gen_util.erl
index 4638d4c7ea..2ba1c6e16f 100644
--- a/lib/wx/api_gen/gen_util.erl
+++ b/lib/wx/api_gen/gen_util.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -49,8 +49,10 @@ get_taylor_made(Str, Name) ->
[dotall, {capture, all_but_first, list}]).
open_write(File) ->
+ open_write(File, []).
+open_write(File, Opts) ->
%% io:format("Generating ~s~n",[File]),
- {ok, Fd} = file:open(File++".temp", [write]),
+ {ok, Fd} = file:open(File++".temp", [write|Opts]),
put(current_file, {Fd,File}).
@@ -187,6 +189,8 @@ replace_and_remove([$| | R], Acc) ->
replace_and_remove(R, ["|"|Acc]);
replace_and_remove([$* | R], Acc) ->
replace_and_remove(R, ["*"|Acc]);
+replace_and_remove([$+ | R], Acc) ->
+ replace_and_remove(R, ["+"|Acc]);
replace_and_remove([$& | R], Acc) ->
replace_and_remove(R, [$&|Acc]);
replace_and_remove([$<,$< | R], Acc) ->
@@ -221,7 +225,7 @@ erl_copyright() ->
w("%%~n",[]),
w("%% %CopyrightBegin%~n",[]),
w("%%~n",[]),
- w("%% Copyright Ericsson AB ~p-2012. All Rights Reserved.~n",
+ w("%% Copyright Ericsson AB ~p-2013. All Rights Reserved.~n",
[StartYear]),
w("%%~n",[]),
w("%% The contents of this file are subject to the Erlang Public License,~n",[]),
@@ -241,7 +245,7 @@ c_copyright() ->
w("/*~n",[]),
w(" * %CopyrightBegin%~n",[]),
w(" *~n",[]),
- w(" * Copyright Ericsson AB 2008-2012. All Rights Reserved.~n",[]),
+ w(" * Copyright Ericsson AB 2008-2013. All Rights Reserved.~n",[]),
w(" *~n",[]),
w(" * The contents of this file are subject to the Erlang Public License,~n",[]),
w(" * Version 1.1, (the \"License\"); you may not use this file except in~n",[]),
diff --git a/lib/wx/api_gen/gl_gen.erl b/lib/wx/api_gen/gl_gen.erl
index 331ba32ba4..ea967c958f 100644
--- a/lib/wx/api_gen/gl_gen.erl
+++ b/lib/wx/api_gen/gl_gen.erl
@@ -185,11 +185,11 @@ parse_define([#xmlElement{name=name,content=[#xmlText{value="WINGDIAPI"++_}]}|_]
throw(skip);
parse_define([#xmlElement{name=name,content=[#xmlText{value=Name}]}|R], Def, Os) ->
parse_define(R, Def#def{name=Name}, Os);
-parse_define([#xmlElement{name=initializer,content=[#xmlText{value=V}]}|_],Def,_Os) ->
- Val0 = string:strip(V),
- try
+parse_define([#xmlElement{name=initializer,content=Contents}|_R],Def,_Os) ->
+ Val0 = extract_def2(Contents),
+ try
case Val0 of
- "0x" ++ Val1 ->
+ "0x" ++ Val1 ->
_ = http_util:hexlist_to_integer(Val1),
Def#def{val=Val1, type=hex};
_ ->
@@ -207,6 +207,23 @@ parse_define([_|R], D, Opts) ->
parse_define([], D, _Opts) ->
D.
+extract_def2([#xmlText{value=Val}|R]) ->
+ strip_comment(string:strip(Val)) ++ extract_def2(R);
+extract_def2([#xmlElement{content=Cs}|R]) ->
+ extract_def2(Cs) ++ extract_def2(R);
+extract_def2([]) -> [].
+
+strip_comment("/*" ++ Rest) ->
+ strip_comment_until_end(Rest);
+strip_comment("//" ++ _) -> [];
+strip_comment([H|R]) -> [H | strip_comment(R)];
+strip_comment([]) -> [].
+
+strip_comment_until_end("*/" ++ Rest) ->
+ strip_comment(Rest);
+strip_comment_until_end([_|R]) ->
+ strip_comment_until_end(R).
+
parse_func(Xml, Opts) ->
{Func,_} = foldl(fun(X,Acc) -> parse_func(X,Acc,Opts) end, {#func{},1}, Xml),
put(current_func, Func#func.name),
diff --git a/lib/wx/api_gen/gl_gen_erl.erl b/lib/wx/api_gen/gl_gen_erl.erl
index 25f89e4ad4..446521098e 100644
--- a/lib/wx/api_gen/gl_gen_erl.erl
+++ b/lib/wx/api_gen/gl_gen_erl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -31,7 +31,7 @@
-import(lists, [foldl/3,foldr/3,reverse/1, keysearch/3, map/2, filter/2, max/1]).
-import(gen_util, [lowercase/1, lowercase_all/1, uppercase/1, uppercase_all/1,
- open_write/1, close/0, erl_copyright/0, w/2,
+ open_write/1, open_write/2, close/0, erl_copyright/0, w/2,
args/3, args/4, strip_name/2]).
gl_defines(Defs) ->
@@ -90,7 +90,8 @@ types() ->
].
gl_api(Fs) ->
- open_write("../src/gen/gl.erl"),
+ open_write("../src/gen/gl.erl", [{encoding,utf8}]),
+ w("%% -*- coding: utf-8 -*-~n~n", []),
erl_copyright(),
w("~n%% OPENGL API~n~n", []),
w("%% This file is generated DO NOT EDIT~n~n", []),
@@ -148,7 +149,8 @@ gl_api(Fs) ->
ok.
glu_api(Fs) ->
- open_write("../src/gen/glu.erl"),
+ open_write("../src/gen/glu.erl", [{encoding,utf8}]),
+ w("%% -*- coding: utf-8 -*-~n~n", []),
erl_copyright(),
w("~n%% OPENGL UTILITY API~n~n", []),
w("%% This file is generated DO NOT EDIT~n~n", []),
@@ -330,7 +332,7 @@ format_doc([{constant, Const}|Rest], Count) ->
w("`?~s'", [Const]),
format_doc(Rest, Count-length(Const)-8);
format_doc([{emphasis, Const}|Rest], Count) ->
- w("`~s'", [Const]),
+ w("`~ts'", [Const]),
format_doc(Rest, Count-length(Const)-7);
format_doc([{function, Func}|Rest], Count) ->
case Func of
@@ -377,7 +379,7 @@ format_doc([{fenced, Open, Close, Eq}|Rest], Count) ->
format_doc(Rest, Count);
format_doc([{code, Code}|Rest], Count) ->
- w("``~s''", [Code]),
+ w("``~ts''", [Code]),
format_doc(Rest, Count-length(Code)-7);
format_doc([para|Rest], _Count) ->
@@ -387,10 +389,10 @@ format_doc([break|Rest], _Count) ->
w("<br />~n%% ", []),
format_doc(Rest, ?LINE_LEN);
format_doc([{purpose, Purpose}, para | Doc], _Count) ->
- w("%% @doc ~s~n%%~n%% ", [uppercase(Purpose)]),
+ w("%% @doc ~ts~n%%~n%% ", [uppercase(Purpose)]),
format_doc(Doc, ?LINE_LEN);
format_doc([{purpose, Purpose} | Doc], _Count) ->
- w("%% @doc ~s~n%%~n%% ", [Purpose]),
+ w("%% @doc ~ts~n%%~n%% ", [Purpose]),
format_doc(Doc, ?LINE_LEN);
format_doc([listentry|Rest], _Count) ->
w("~n%%~n%% ", []),
@@ -398,11 +400,11 @@ format_doc([listentry|Rest], _Count) ->
format_doc([Str|Rest], Count) ->
case length(Str) of
Len when Len < Count ->
- w("~s", [Str]),
+ w("~ts", [Str]),
format_doc(Rest, Count-Len);
_ ->
{Str1, Str2} = split(Str, Count, []),
- w("~s~n%% ", [Str1]),
+ w("~ts~n%% ", [Str1]),
format_doc([Str2|Rest], ?LINE_LEN)
end;
format_doc([], _) -> ok.
diff --git a/lib/wx/api_gen/gl_scan_doc.erl b/lib/wx/api_gen/gl_scan_doc.erl
index fc7b7cf275..80b4826a30 100644
--- a/lib/wx/api_gen/gl_scan_doc.erl
+++ b/lib/wx/api_gen/gl_scan_doc.erl
@@ -2,7 +2,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -56,8 +56,10 @@ gen_output({characters, String0}, #state{gen_output=true, type=Type, str=Str} =
mi -> case hd(Str) of
"/" -> String;
"*" -> String;
+ [215] -> String;
"+" -> String;
"-" -> String;
+ "=" -> String;
{fenced,_,_} -> String;
_ ->
[$ |String]
@@ -268,7 +270,9 @@ fix_str([$<|Str]) ->
fix_str([$>|Str]) ->
[$&,$g,$t,$;|fix_str(Str)];
fix_str("&times;"++Str) ->
- [$*|fix_str(Str)];
+ [215|fix_str(Str)];
+%% fix_str([215|Str]) ->
+%% [$*|fix_str(Str)];
fix_str("&Prime;"++Str) ->
[$"|fix_str(Str)];
fix_str("&CenterDot;"++Str) ->
@@ -277,10 +281,12 @@ fix_str("&af;"++Str) ->
fix_str(Str);
fix_str("&it;"++Str) ->
[$ |fix_str(Str)];
+fix_str("&nbsp;"++Str) ->
+ [$ |fix_str(Str)];
fix_str([$&|Str]) ->
[$&,$a,$m,$p,$; |fix_str(Str)];
-fix_str([C|Str]) when C > 255 ->
- fix_str(Str);
+%% fix_str([C|Str]) when C > 255 ->
+%% fix_str(Str);
fix_str([C|Str]) ->
[C|fix_str(Str)];
fix_str([]) -> [].
diff --git a/lib/wx/api_gen/wx_extra/wxPrintout.erl b/lib/wx/api_gen/wx_extra/wxPrintout.erl
index be8f2e2fa5..1dfd86ec62 100644
--- a/lib/wx/api_gen/wx_extra/wxPrintout.erl
+++ b/lib/wx/api_gen/wx_extra/wxPrintout.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -40,7 +40,8 @@ new(Title, OnPrintPage) ->
%% <pre>OnBeginDocument(This,StartPage,EndPage) -> boolean() </pre>
%% <pre>OnEndDocument(This) -> term() </pre>
%% <pre>HasPage(This,Page)} -> boolean() </pre>
-%% <pre>GetPageInfo(This) -> {MinPage:.integer(), MaxPage::integer(), PageFrom::integer(), PageTo::integer()} </pre>
+%% <pre>GetPageInfo(This) -> {MinPage::integer(), MaxPage::integer(),
+%% PageFrom::integer(), PageTo::integer()} </pre>
%% The <b>This</b> argument is the wxPrintout object reference to this object
%% <br /> NOTE: The callbacks may not call other processes.
new(Title, OnPrintPage, Opts) when is_list(Title), is_function(OnPrintPage), is_list(Opts) ->
diff --git a/lib/wx/api_gen/wx_gen.erl b/lib/wx/api_gen/wx_gen.erl
index 7f85151d03..2eb9d9d33d 100644
--- a/lib/wx/api_gen/wx_gen.erl
+++ b/lib/wx/api_gen/wx_gen.erl
@@ -103,7 +103,12 @@ mangle_info({class,CN,P,O,FL}) ->
Event = get_value(event,O, false),
Acc = get_value(acc, O, []),
{Fs,Fopts} = foldr(fun(FWO={F,FO},{Fl,Fopt}) when is_list(FO) ->
- {[F|Fl],[FWO|Fopt]};
+ Opt = case F of
+ {Name, ArgLen} when is_integer(ArgLen) ->
+ {Name, FO};
+ _ -> FWO
+ end,
+ {[F|Fl],[Opt|Fopt]};
(F,{Fl,Fopt}) ->
{[F|Fl], Fopt}
end, {[],[]}, FL),
@@ -421,22 +426,30 @@ select_member(Several, #class{name=Class,file=Orig}, Defs0, Opts) ->
parse_member(Data,MType,Virtual,Opts = #hs{fopt=Fopts}) ->
Parse = fun(Con,A) -> parse_member2(Con,Opts,A) end,
- Method = #method{name=MName,params=PS0} =
+ Method = #method{name=MName,params=PS0} =
foldl(Parse, #method{method_type=MType, virtual=Virtual}, Data),
%% Skip motif name's if it's last and optional
PS2 = case PS0 of %% Backward order..
- [#param{name="name",def=Def,type=#type{name="wxString"}}|PS1]
- when Def =/= none ->
+ [#param{name="name",def=Def,type=#type{name="wxString"}}|PS1]
+ when Def =/= none ->
PS1;
_ ->
PS0
end,
Sz = length(PS2),
- PS = map(fun(P=#param{name=PName}) ->
+ PS = map(fun(P=#param{name=PName}) ->
patch_param(MName,{Sz,PName},P,Fopts)
end, PS2),
- Alias = find_erl_alias_name(MName,PS,Fopts),
- Method#method{params=PS, alias=Alias}.
+ Alias = find_erl_alias_name(MName,PS,Fopts),
+ FOpts = case gb_trees:lookup(MName, Fopts) of
+ {value, FuncO} when is_list(FuncO) ->
+ case lists:keyfind({func,Sz}, 1, FuncO) of
+ false -> FuncO;
+ {_, FuncNO} -> FuncNO
+ end;
+ _ -> []
+ end,
+ Method#method{params=PS, alias=Alias, opts=FOpts}.
find_erl_alias_name(MName,Ps,Fopts) ->
case gb_trees:lookup(MName, Fopts) of
@@ -527,7 +540,7 @@ add_param2(P=#param{name=Name},#hs{fopt=FOpt},M0=#method{name=MName,params=Ps})
M0#method{params=[Patched|Ps]}
end.
-patch_param(Method, Name, P, Opt) ->
+patch_param(Method, Name, P, Opt) ->
case gb_trees:lookup(Method,Opt) of
none -> P;
{value,NoArg} when is_integer(NoArg) -> P;
@@ -560,11 +573,14 @@ handle_param_opt(both, P) -> P#param{in=both};
handle_param_opt({def,Def},P) -> P#param{def=Def};
handle_param_opt({type,Type}, P=#param{type=T}) -> P#param{type=T#type{name=Type}};
handle_param_opt({single,Opt}, P=#param{type=T}) -> P#param{type=T#type{single=Opt}};
+handle_param_opt({base,Enum={enum,Type}}, P=#param{type=T}) -> P#param{type=T#type{base=Enum, name=Type}};
handle_param_opt({base,Opt}, P=#param{type=T}) -> P#param{type=T#type{base=Opt}};
handle_param_opt({c_only,Opt},P) -> P#param{where=c, alt=Opt};
-handle_param_opt({ref, pointer}, P=#param{type=T}) ->
+handle_param_opt({ref, pointer}, P=#param{type=T}) ->
P#param{type=T#type{by_val=false,ref={pointer, 1}}};
-handle_param_opt({mod,Mods}, P=#param{type=T=#type{mod=Mods0}}) ->
+handle_param_opt({by_val, true}, P=#param{type=T}) ->
+ P#param{type=T#type{by_val=true}};
+handle_param_opt({mod,Mods}, P=#param{type=T=#type{mod=Mods0}}) ->
P#param{type=T#type{mod=Mods++Mods0}}.
get_opt(Opt, Method, Sz, Opts) ->
@@ -654,6 +670,12 @@ extract_type_info(#xmlElement{name=ref,attributes=As,content=[#xmlText{value=V}]
{value, #xmlAttribute{value = Kind}} = keysearch(kindref,#xmlAttribute.name,As),
{reverse(foldl(fun extract_type_info2/2, [], string:tokens(V, " "))) ++ Acc,
{Kind,Refid}};
+extract_type_info(#xmlElement{name=ref,attributes=As,content=[#xmlText{value=V}]},
+ {Acc,_}) ->
+ {value, #xmlAttribute{value = Refid}} = keysearch(refid,#xmlAttribute.name,As),
+ {value, #xmlAttribute{value = Kind}} = keysearch(kindref,#xmlAttribute.name,As),
+ {reverse(foldl(fun extract_type_info2/2, [], string:tokens(V, " "))) ++ Acc,
+ {Kind,Refid}};
extract_type_info(What,Acc) ->
?error({parse_error,What,Acc}).
@@ -704,11 +726,9 @@ parse_type2([N="wxTextPos"|R],Info,Opts,T) -> %%long
parse_type2(R,Info,Opts,T#type{name=N,base=int});
parse_type2([N="wxPrintQuality"|R],Info,Opts,T) ->
parse_type2(R,Info,Opts,T#type{name=N,base=int});
-parse_type2([N="wxPaperSize"|R],Info,Opts,T) ->
- parse_type2(R,Info,Opts,T#type{name=N,base=int});
parse_type2(["wxDataFormat"|_R],_Info,_Opts,T) ->
%% Hack Hack
- T#type{name="wxDataFormatId",base=int};
+ T#type{name="wxDataFormatId",base={enum,"wxDataFormatId"}};
parse_type2([N="wxArrayInt"|R],Info,Opts,T) ->
parse_type2(R,Info,Opts,T#type{name=N,base=int,single=array});
parse_type2([N="wxArrayDouble"|R],Info,Opts,T) ->
@@ -1251,7 +1271,7 @@ parse_enums([File|Files], Parsed) ->
case gb_sets:is_member(File,Parsed) of
false ->
FileName = filename:join(["wx_xml",File ++ "_8h.xml"]),
-%% io:format("Parse Enums in ~s ~n", [FileName]),
+ %%io:format("Parse Enums in ~s ~n", [FileName]),
case xmerl_scan:file(FileName, [{space, normalize}]) of
{error, enoent} ->
parse_enums(Files, gb_sets:add(File,Parsed));
@@ -1318,41 +1338,37 @@ extract_enum2([], N, _Id, Acc) ->
extract_enum3([#xmlElement{name=name,content=[#xmlText{value=Name}]}|R], Id, Acc) ->
case lists:keymember(Name, 1, Acc) of
- true -> %% Doxygen double includes some defs.
+ true -> %% Doxygen double includes some defs.
{Acc,Id};
false ->
case Id of
- This = {Str,Num} ->
+ This = {Str,Num} ->
extract_enum3(R, {Str, Num+1}, [{Name,This}|Acc]);
Val ->
extract_enum3(R, Val+1, [{Name,Val}|Acc])
end
end;
-extract_enum3([#xmlElement{name=initializer,
- content=Cs=[#xmlText{}|_]}|_],_Id,[{Name,_}|Acc]) ->
-
- String = lists:append([string:strip(C#xmlText.value) || C <- Cs]),
-
+extract_enum3([#xmlElement{name=initializer,content=Cs}|_],_Id,[{Name,_}|Acc]) ->
+ String = extract_def2(Cs),
Val0 = gen_util:tokens(String,"<& "),
-
- try
+ try
case Val0 of
- ["0x" ++ Val1] ->
+ ["0x" ++ Val1] ->
Val = http_util:hexlist_to_integer(Val1),
{[{Name, Val}|Acc], Val+1};
- [Single] ->
- Val = list_to_integer(Single),
- {[{Name, Val}|Acc], Val+1};
["1", "<<", Shift] ->
Val = 1 bsl list_to_integer(Shift),
{[{Name, Val}|Acc], Val+1};
- [_Str, "+", _What] ->
- Val = lists:append(Val0),
- {[{Name, {Val, 0}}|Acc], {Val,1}};
- _What ->
- %% io:format("~p Name ~p ~p~n",[?LINE, Name, Val0]),
- throw(below)
+ [Str, "+", What] ->
+ Val = list_to_integer(What),
+ {[{Name, {Str, Val}}|Acc], {Str,Val+1}};
+ [Single] ->
+ Val = list_to_integer(Single),
+ {[{Name, Val}|Acc], Val+1};
+ _ ->
+ %% io:format("~p Name ~p ~p ~p~n",[?LINE, Name, Val0, String]),
+ throw(below)
end
catch _:_ ->
{[{Name,{String,0}}|Acc], {String,1}}
@@ -1372,7 +1388,7 @@ extract_defs(Defs, File) ->
end.
extract_defs2(#xmlElement{name=memberdef,content=C},{Acc,Skip}) ->
- try
+ try
Res = {Name,_} = extract_def(C,undefined,Skip),
case gb_sets:is_member(Name,Skip) orelse lists:keymember(Name, 1, Acc) of
true -> {Acc,Skip};
@@ -1380,30 +1396,31 @@ extract_defs2(#xmlElement{name=memberdef,content=C},{Acc,Skip}) ->
end
catch throw:SkipName -> {Acc, gb_sets:add(SkipName,Skip)}
end.
-
+
extract_def([#xmlElement{name=name,content=[#xmlText{value=Name}]}|R], _N, Skip) ->
case Name of
"wxUSE" ++ _ ->
throw(Name);
"wx" ++ _ ->
extract_def(R, Name, Skip);
- _ ->
+ _ ->
throw(Name)
end;
extract_def([#xmlElement{name=param}|_],Name,_) ->
throw(Name);
-extract_def([#xmlElement{name=initializer,content=[#xmlText{value=Val0}]}|_],N,Skip) ->
+extract_def([#xmlElement{name=initializer,content=Cs}|_R],N,Skip) ->
+ Val0 = extract_def2(Cs),
case Val0 of
"0x" ++ Val1 -> {N, http_util:hexlist_to_integer(Val1)};
_ ->
try
Val = list_to_integer(Val0),
{N, Val}
- catch _:_ ->
+ catch _:_ ->
case def_is_ok(Val0, Skip) of
false ->
throw(N);
- NVal when is_integer(NVal) ->
+ NVal when is_integer(NVal) ->
{N, NVal};
NVal ->
{N, {NVal,0}}
@@ -1414,7 +1431,24 @@ extract_def([_|R],N,Skip) ->
extract_def(R,N,Skip);
extract_def(_,N,_) ->
throw(N).
-
+
+extract_def2([#xmlText{value=Val}|R]) ->
+ strip_comment(string:strip(Val)) ++ extract_def2(R);
+extract_def2([#xmlElement{content=Cs}|R]) ->
+ extract_def2(Cs) ++ extract_def2(R);
+extract_def2([]) -> [].
+
+strip_comment("/*" ++ Rest) ->
+ strip_comment_until_end(Rest);
+strip_comment("//" ++ _) -> [];
+strip_comment([H|R]) -> [H | strip_comment(R)];
+strip_comment([]) -> [].
+
+strip_comment_until_end("*/" ++ Rest) ->
+ strip_comment(Rest);
+strip_comment_until_end([_|R]) ->
+ strip_comment_until_end(R).
+
def_is_ok(Name, Skip) ->
Toks = gen_util:tokens(Name,"()| \\:"),
R = def_is_ok(Toks, Skip, []),
diff --git a/lib/wx/api_gen/wx_gen.hrl b/lib/wx/api_gen/wx_gen.hrl
index 426e3adfae..89577b9707 100644
--- a/lib/wx/api_gen/wx_gen.hrl
+++ b/lib/wx/api_gen/wx_gen.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -44,7 +44,8 @@
doc, % Extra documentation
virtual, % Is virtual?
pre_hook = [], % Pre hook before call in c-code
- post_hook = [] % Post hook after call in c-code
+ post_hook = [], % Post hook after call in c-code
+ opts = [] % Options
}
).
diff --git a/lib/wx/api_gen/wx_gen_cpp.erl b/lib/wx/api_gen/wx_gen_cpp.erl
index 2209e4a53b..293c97507e 100644
--- a/lib/wx/api_gen/wx_gen_cpp.erl
+++ b/lib/wx/api_gen/wx_gen_cpp.erl
@@ -118,12 +118,18 @@ gen_constructors(#class{name=Class, methods=Ms0}) ->
gen_constructor(_Class, #method{where=merged_c}) -> ok;
gen_constructor(_Class, #method{where=erl_no_opt}) -> ok;
-gen_constructor(Class, _M=#method{params=Ps}) ->
+gen_constructor(Class, _M=#method{params=Ps, opts=FOpts}) ->
Gen1 = fun(#param{name=N, type=T}) -> gen_type(T,1) ++ N end,
Gen2 = fun(#param{name=N, type=T}) -> gen_type(T,2) ++ N end,
CallA = fun(#param{name=N}) -> N end,
HaveMergedType = fun(#param{type={merged,_,_,_,_,_,_}}) -> true; (_) -> false end,
?WTC("gen_constructor"),
+ Endif = case lists:keysearch(deprecated, 1, FOpts) of
+ {value, {deprecated, IfDef}} ->
+ w("#if ~s~n", [IfDef]),
+ true;
+ _ -> false
+ end,
case lists:any(HaveMergedType, Ps) of
false ->
w(" E~s(~s) : ~s(~s) {};~n",
@@ -133,7 +139,9 @@ gen_constructor(Class, _M=#method{params=Ps}) ->
[Class,args(Gen1,",",Ps),Class,args(CallA,",",Ps)]),
w(" E~s(~s) : ~s(~s) {};~n",
[Class,args(Gen2,",",Ps),Class,args(CallA,",",Ps)])
- end.
+ end,
+ Endif andalso w("#endif~n", []),
+ ok.
gen_type(#type{name=Type, ref={pointer,1}, mod=Mod},_) ->
mods(Mod) ++ to_string(Type) ++ " * ";
@@ -162,6 +170,14 @@ gen_funcs(Defs) ->
w("#include \"wxe_macros.h\"~n"),
w("#include \"wxe_derived_dest.h\"~n~n"),
+ w("#if !wxCHECK_VERSION(2,9,0)~n", []),
+ [w("#define ~p int~n", [Enum]) ||
+ Enum <- [wxPenJoin, wxPenCap, wxImageResizeQuality, %%wxBitmapType,
+ wxPolygonFillMode, wxMappingMode, wxRasterOperationMode,
+ wxFloodFillStyle
+ ]],
+ w("#endif~n",[]),
+
w("void WxeApp::wxe_dispatch(wxeCommand& Ecmd)~n{~n"),
w(" char * bp = Ecmd.buffer;~n"),
w(" wxeMemEnv *memenv = getMemEnv(Ecmd.port);~n"),
@@ -292,10 +308,16 @@ gen_method(CName, M=#method{name=N,params=[Ps],method_type=destructor,id=MethodI
ignore
end,
M;
-gen_method(CName, M=#method{name=N,params=Ps0,type=T,method_type=MT,id=MethodId}) ->
+gen_method(CName, M=#method{name=N,params=Ps0,type=T,method_type=MT,id=MethodId, opts=FOpts}) ->
put(current_func, N),
put(bin_count,-1),
?WTC("gen_method"),
+ Endif = case lists:keysearch(deprecated, 1, FOpts) of
+ {value, {deprecated, IfDef}} ->
+ w("#if ~s~n", [IfDef]),
+ true;
+ _ -> false
+ end,
w("case ~s: { // ~s::~s~n", [wx_gen_erl:get_unique_name(MethodId),CName,N]),
Ps1 = declare_variables(void, Ps0),
{Ps2,Align} = decode_arguments(Ps1),
@@ -314,6 +336,7 @@ gen_method(CName, M=#method{name=N,params=Ps0,type=T,method_type=MT,id=MethodId
free_args(),
build_return_vals(T,Ps3),
w(" break;~n}~n", []),
+ Endif andalso w("#endif~n", []),
erase(current_func),
M.
@@ -746,7 +769,7 @@ return_res1(#type{name=Type,ref={pointer,_}, base={term,_}}) ->
{Type ++ " * Result = (" ++ Type ++ "*)", ""};
return_res1(#type{name=Type,ref={pointer,_}}) ->
{Type ++ " * Result = (" ++ Type ++ "*)", ""};
-return_res1(#type{name=Type,single=true,ref=reference}) ->
+return_res1(#type{name=Type,single=true,by_val=false,ref=reference}) ->
{Type ++ " * Result = &", ""};
return_res1(#type{name=Type,single=true,by_val=true})
when is_atom(Type) ->
@@ -758,7 +781,7 @@ return_res1(#type{name=Type,base={class,_},single=list,ref=reference}) ->
return_res1(#type{name=Type,base={comp,_,_},single=array,by_val=true}) ->
{Type ++ " Result = ", ""};
return_res1(#type{name=Type,single=true,by_val=true, base={class, _}}) ->
- %% Memory leak !!!!!! XXXX BUGBUG FIXME or doument!!
+ %% Temporary memory leak !!!!!!
case Type of
"wxImage" -> ok;
"wxFont" -> ok;
@@ -769,7 +792,6 @@ return_res1(#type{name=Type,single=true,by_val=true, base={class, _}}) ->
io:format("~s::~s Building return value of temp ~s~n",
[get(current_class),get(current_func),Type])
end,
- %% #class{id=Id} = get({class,Type}),
{Type ++ " * Result = new " ++ Type ++ "(", "); newPtr((void *) Result,"
++ "3, memenv);"};
return_res1(#type{base={enum,_Type},single=true,by_val=true}) ->
@@ -794,15 +816,14 @@ call_arg(#param{where=c, alt={length,Alt}}) when is_list(Alt) ->
call_arg(#param{where=c, alt={size,Id}}) when is_integer(Id) ->
%% It's a binary
"Ecmd.bin["++ integer_to_list(Id) ++ "]->size";
-call_arg(#param{name=N,def=Def,type=#type{name=Type,by_val=true,single=true,base=Base}})
+call_arg(#param{name=N,def=Def,type=#type{by_val=true,single=true,base=Base}})
when Base =:= int; Base =:= long; Base =:= float; Base =:= double; Base =:= bool ->
case Def of
- none -> "(" ++ to_string(Type) ++ ") *" ++ N;
+ none -> "*" ++ N;
_ -> N
end;
-
-call_arg(#param{name=N,type=#type{base={enum,Type}, by_val=true,single=true}}) ->
- "(" ++ enum_type(Type) ++") " ++ N;
+call_arg(#param{name=N,type=#type{base={enum,_Type}, by_val=true,single=true}}) ->
+ N;
call_arg(#param{name=N,type=#type{base={class,_},by_val=true,single=true}}) -> "*" ++ N;
call_arg(#param{name=N,type=#type{base={class,_},ref=reference,single=true}}) -> "*" ++ N;
call_arg(#param{name=N,type=#type{base=eventType}}) ->
@@ -823,8 +844,8 @@ call_arg(#param{name=N,type={merged,_,#type{base={class,_},single=true,
ref=Ref},_,_,_,_}})
when ByVal =:= true; Ref =:= reference ->
"*" ++ N;
-call_arg(#param{def=Def, type=void}) when Def =/= none -> Def;
-call_arg(#param{def=Def, type=voidp}) when Def =/= none -> Def;
+call_arg(#param{def=Def, type=void}) when Def =/= none -> Def;
+call_arg(#param{def=Def, type=voidp}) when Def =/= none -> "(void **) " ++ Def;
call_arg(#param{name=N,type=#type{base={ref,_},by_val=true,single=true}}) -> N;
call_arg(#param{name=N,type={merged,_,_,_,_,_,_}}) -> N.
@@ -932,10 +953,18 @@ build_ret(Name,_,#type{base={enum,_Type},single=true}) ->
w(" rt.addInt(~s);~n",[Name]);
build_ret(Name,_,#type{base={comp,_,{record, _}},single=true}) ->
w(" rt.add(~s);~n", [Name]);
+build_ret(Name,{ret,_},#type{base={comp,_,_},single=true, by_val=true}) ->
+ w(" rt.add(~s);~n",[Name]);
build_ret(Name,{ret,_},#type{base={comp,_,_},single=true, ref=reference}) ->
w(" rt.add((*~s));~n",[Name]);
build_ret(Name,_,#type{base={comp,_,_},single=true}) ->
w(" rt.add(~s);~n",[Name]);
+build_ret(Name = "ev->m_scanCode",_,#type{base=bool,single=true,by_val=true}) ->
+ %% Hardcoded workaround for 2.9 and later
+ w("#if !wxCHECK_VERSION(2,9,0)~n", []),
+ w(" rt.addBool(~s);~n",[Name]),
+ w("#else~n rt.addBool(false);~n",[]),
+ w("#endif~n",[]);
build_ret(Name,_,#type{base=bool,single=true,by_val=true}) ->
w(" rt.addBool(~s);~n",[Name]);
build_ret(Name,{arg, both},#type{base=int,single=true,mod=M}) ->
diff --git a/lib/wx/api_gen/wx_gen_erl.erl b/lib/wx/api_gen/wx_gen_erl.erl
index a8f23575f3..a999a869e6 100644
--- a/lib/wx/api_gen/wx_gen_erl.erl
+++ b/lib/wx/api_gen/wx_gen_erl.erl
@@ -70,8 +70,7 @@ gen_class1(C=#class{name=Name,parent="static",methods=Ms,options=_Opts}) ->
Exp = fun(M) -> gen_export(C,M) end,
ExportList = lists:usort(lists:append(lists:map(Exp,reverse(Ms)))),
- w("-export([~s]).~n~n", [args(fun(EF) -> EF end, ",", ExportList, 60)]),
-
+ w("-export([~s]).~n~n", [args(fun({EF,_}) -> EF end, ",", ExportList, 60)]),
Gen = fun(M) -> gen_method(Name,M) end,
NewMs = lists:map(Gen,reverse(Ms)),
@@ -134,7 +133,7 @@ gen_class1(C=#class{name=Name,parent=Parent,methods=Ms,options=Opts}) ->
w("-include(\"wxe.hrl\").~n",[]),
Exp = fun(M) -> gen_export(C,M) end,
ExportList = lists:usort(lists:append(lists:map(Exp,reverse(Ms)))),
- w("-export([~s]).~n~n", [args(fun(EF) -> EF end, ",", ExportList, 60)]),
+ w("-export([~s]).~n~n", [args(fun({EF,_}) -> EF end, ",", ExportList, 60)]),
w("%% inherited exports~n",[]),
Done0 = ["Destroy", "New", "Create", "destroy", "new", "create"],
Done = gb_sets:from_list(Done0 ++ [M|| #method{name=M} <- lists:append(Ms)]),
@@ -143,6 +142,10 @@ gen_class1(C=#class{name=Name,parent=Parent,methods=Ms,options=Opts}) ->
lists:usort(["parent_class/1"|InExported]),
60)]),
w("-export_type([~s/0]).~n", [Name]),
+ case lists:filter(fun({_F,Depr}) -> Depr end, ExportList) of
+ [] -> ok;
+ Depr -> w("-deprecated([~s]).~n~n", [args(fun({EF,_}) -> EF end, ",", Depr, 60)])
+ end,
w("%% @hidden~n", []),
parents_check(Parents),
w("-type ~s() :: wx:wx_object().~n", [Name]),
@@ -218,33 +221,40 @@ gen_export(#class{name=Class,abstract=Abs},Ms0) ->
case Res of
[] -> [];
[M=#method{where=taylormade}|_] ->
- [taylormade_export(Class, M)];
+ [deprecated(M, taylormade_export(Class, M))];
Ms ->
- GetF = fun(#method{method_type=constructor,where=W,params=Ps}) ->
+ GetF = fun(M=#method{method_type=constructor,where=W,params=Ps}) ->
{Args,Opts} = split_optional(Ps),
OptLen = case Opts of
[] -> 0;
_ when W =:= erl_no_opt -> 0;
_ -> 1
end,
- "new/" ++ integer_to_list(length(Args)+OptLen);
- (#method{method_type=destructor}) ->
+ deprecated(M, "new" ++ "/" ++ integer_to_list(length(Args)+OptLen));
+ (M=#method{method_type=destructor}) ->
case Abs of
true -> [];
- _ -> "destroy/1"
+ _ -> deprecated(M, "destroy/1")
end;
- (#method{name=N,alias=A,where=W, params=Ps}) ->
+ (M=#method{name=N,alias=A,where=W, params=Ps}) ->
{Args,Opts} = split_optional(Ps),
OptLen = case Opts of
[] -> 0;
_ when W =:= erl_no_opt -> 0;
_ -> 1
end,
- erl_func_name(N,A) ++ "/" ++ integer_to_list(length(Args) + OptLen)
+ deprecated(M, erl_func_name(N,A) ++ "/" ++ integer_to_list(length(Args) + OptLen))
end,
lists:map(GetF, Ms)
end.
+deprecated(#method{opts=FOpts}, FA) ->
+ case lists:keysearch(deprecated, 1, FOpts) of
+ {value, {deprecated, _}} ->
+ {FA,true};
+ _ ->
+ {FA,false}
+ end.
gen_method(Class,Ms0) ->
RemoveC = fun(#method{where=merged_c}) -> false;(_Other) -> true end,
@@ -832,15 +842,20 @@ doc_enum(_,Ps) ->
[doc_enum_type(Type,Name) || #param{name=Name, type=#type{base={enum,Type}}} <- Ps].
doc_enum_type(Type, Name) ->
- {Enum0, #enum{vals=Vals}} = wx_gen:get_enum(Type),
- Enum = case Enum0 of {_, E} -> E; E -> E end,
- Consts = get(consts),
- Format = fun({N,_What}) ->
- #const{name=N} = gb_trees:get(N, Consts),
- "?" ++ enum_name(N)
- end,
- Vs = args(Format, " | ", Vals),
- {uppercase(Enum),Name, Vs}.
+ try
+ {Enum0, #enum{vals=Vals}} = wx_gen:get_enum(Type),
+ Enum = case Enum0 of {_, E} -> E; E -> E end,
+ Consts = get(consts),
+ Format = fun({N,_What}) ->
+ #const{name=N} = gb_trees:get(N, Consts),
+ "?" ++ enum_name(N)
+ end,
+ Vs = args(Format, " | ", Vals),
+ {uppercase(Enum),Name, Vs}
+ catch _:_ ->
+ io:format("Warning missing enum type ~p~n", [Type]),
+ {uppercase(Type),Name,"integer"}
+ end.
doc_enum_desc([]) -> ok;
doc_enum_desc([{_Enum,Name,Vs}|R]) ->
@@ -1014,11 +1029,23 @@ align(64, 1, Str) -> {"0:32," ++ Str,0};
align(Sz, W, Str) -> align(Sz, W rem 2, Str).
enum_name(Name) ->
+ case enum_split(Name) of
+ {undefined, _} -> Name;
+ {_C, ErlName} -> ErlName
+ end.
+
+enum_split(Name) ->
case string:tokens(Name, ":") of
- [Name] -> Name;
- [C,N] -> C ++ "_" ++ N
+ [Name] -> {undefined, Name};
+ [C,N] -> {C, enum_name(C,N)}
end.
+enum_name(undefined, Name) -> Name;
+enum_name(Enum, Name) -> Enum ++ "_" ++ Name.
+
+enum_name_c(undefined, Name) -> Name;
+enum_name_c(Enum, Name) -> Enum ++ "::" ++ Name.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
gen_enums_ints() ->
@@ -1058,6 +1085,14 @@ build_enum_ints(#enum{from=From, vals=Vals},Done) ->
w("% From class ~s::~s~n",[Class, Name])
end,
+ Consts = get(consts),
+ Ignore = fun(Name) ->
+ case gb_trees:lookup(Name, Consts) of
+ {value, Const} -> Const;
+ none -> true
+ end
+ end,
+
Format = fun(#const{name="wxEVT_" ++ _}) ->
ignore; %% Ignore event macros they are not valid in our event model
(#const{name=Name,val=Value,is_const=true}) when is_number(Value) ->
@@ -1065,44 +1100,57 @@ build_enum_ints(#enum{from=From, vals=Vals},Done) ->
(#const{name=Name,val=Value,is_const=false}) when is_number(Value) ->
w("-define(~s, wxe_util:get_const(~s)).~n", [enum_name(Name),enum_name(Name)]);
(#const{name=Name,val={Str,0}}) ->
+ {EnumClass, EnumName} = enum_split(Name),
case string:tokens(Str, " |()") of
[Token] ->
- w("-define(~s, ~s).~n", [enum_name(Name),const_value(Token)]);
+ w("-define(~s, ~s).~n", [EnumName,const_value(Token, EnumClass, Ignore)]);
Tokens ->
- Def = args(fun(T) -> const_value(T) end, " bor ", Tokens),
- w("-define(~s, (~s)).~n", [enum_name(Name),Def])
+ Def = args(fun(T) -> const_value(T, EnumClass, Ignore) end, " bor ", Tokens),
+ w("-define(~s, (~s)).~n", [EnumName, Def])
end;
(#const{name=Name,val={Str,N}}) ->
+ {EnumClass, EnumName} = enum_split(Name),
case string:tokens(Str, " |()") of
[Token] ->
- w("-define(~s, (?~s+~p)).~n", [enum_name(Name),Token,N])
+ w("-define(~s, (~s+~p)).~n", [EnumName,const_value(Token, EnumClass, Ignore),N])
end
end,
- Consts = get(consts),
+
Write = fun({Name,_What}, Skip) ->
- case gb_sets:is_member(Name,Skip) of
- true ->
- Skip;
- false ->
- case gb_trees:lookup(Name, Consts) of
- {value, Const} ->
- Format(Const),
- gb_sets:add(Name,Skip);
- none -> Skip
- end
+ case gb_sets:is_member(Name,Skip) orelse Ignore(Name) of
+ true -> Skip;
+ Const ->
+ try Format(Const)
+ catch {unknown_value, _Error} ->
+ %% io:format("Const ~s uses unknown define ~p ignoring~n", [Name, _Error]),
+ ok
+ end,
+ gb_sets:add(Name,Skip)
end
end,
lists:foldl(Write, Done, Vals).
-const_value(V) when is_integer(V) -> integer_to_list(V);
-const_value(V = "16#" ++ IntList) ->
+const_value(V,_,_) when is_integer(V) -> integer_to_list(V);
+const_value(V = "16#" ++ IntList,_,_) ->
_ = http_util:hexlist_to_integer(IntList), %% ASSERT
V;
-const_value(V0) ->
+const_value(V0, EnumClass, Ignore) ->
try
_ = list_to_integer(V0),
V0
- catch _:_ -> [$?|V0]
+ catch _:_ ->
+ EEnum = enum_name(EnumClass, V0),
+ CEnum = enum_name_c(EnumClass, V0),
+ case Ignore(CEnum) of
+ true when CEnum == V0 ->
+ throw({unknown_value, EEnum});
+ true ->
+ case Ignore(V0) of
+ true -> throw({unknown_value, EEnum});
+ _ -> [$?|V0]
+ end;
+ _ -> [$?|EEnum]
+ end
end.
gen_event_recs() ->
diff --git a/lib/wx/api_gen/wxapi.conf b/lib/wx/api_gen/wxapi.conf
index 1f6225ce60..94142ff6ba 100644
--- a/lib/wx/api_gen/wxapi.conf
+++ b/lib/wx/api_gen/wxapi.conf
@@ -148,7 +148,8 @@
{class, wxTopLevelWindowGTK, wxWindow,
[{alias, [{wxTopLevelWindowGTK, wxTopLevelWindow}]}],
- ['GetIcon','GetIcons','GetTitle','IsActive','Iconize',
+ [{'GetIcon', [{return, {by_val, true}}]},
+ 'GetIcons','GetTitle','IsActive','Iconize',
'IsFullScreen','IsIconized','IsMaximized','Maximize',
'RequestUserAttention','SetIcon','SetIcons',
'CenterOnScreen', 'CentreOnScreen',
@@ -279,8 +280,11 @@
{class, wxGridCellEditor, root, [],
['Create',
'IsCreated', 'SetSize', 'Show',
- 'PaintBackground', 'BeginEdit', 'EndEdit', 'Reset', 'StartingKey',
- 'StartingClick', 'HandleReturn'
+ {'PaintBackground', [{deprecated, "!wxCHECK_VERSION(2,9,0)"}]},
+ 'BeginEdit',
+ {'EndEdit', [{deprecated, "!wxCHECK_VERSION(2,9,0)"}]},
+ 'Reset', 'StartingKey',
+ 'StartingClick', 'HandleReturn'
%'Destroy','Clone','~wxGridCellEditor',
]}.
@@ -319,17 +323,25 @@
{class, wxDC, object,
[{skip, [{'DrawEllipse',5},{'DrawRectangle',5},
{'DrawRoundedRectangle',6},{'SetClippingRegion',5}]}],
- [{'Blit',7},'CalcBoundingBox','Clear','ComputeScaleAndOrigin',{'CrossHair',1},
+ [{{'Blit',7},[{"rop", [{base, {enum, "wxRasterOperationMode"}}]}]},
+ 'CalcBoundingBox','Clear',
+ {'ComputeScaleAndOrigin',[{deprecated, "!wxCHECK_VERSION(2,9,0)"}]},
+ {'CrossHair',1},
'DestroyClippingRegion','DeviceToLogicalX','DeviceToLogicalXRel',
'DeviceToLogicalY','DeviceToLogicalYRel',{'DrawArc',3},{'DrawBitmap',3},
{'DrawCheckMark',1},{'DrawCircle',2},'DrawEllipse',{'DrawEllipticArc',4},
{'DrawIcon',2},{'DrawLabel',4},{'DrawLine',2},
{'DrawLines', [{"n",{c_only,{length,"points"}}}]},
- {'DrawPolygon', [{"n",{c_only,{length,"points"}}}]}, %'DrawPolyPolygon',
+ {'DrawPolygon', [{"n",{c_only,{length,"points"}}},
+ {"fillStyle", [{base, {enum, "wxPolygonFillMode"}}]}
+ ]},
+ %%'DrawPolyPolygon',
{'DrawPoint',1},'DrawRectangle',
{'DrawRotatedText',3}, 'DrawRoundedRectangle',%'DrawSpline',
{'DrawText',2},
- 'EndDoc','EndPage',{'FloodFill',3},'GetBackground','GetBackgroundMode',
+ 'EndDoc','EndPage',
+ {{'FloodFill',3},[{"style", [{base, {enum, "wxFloodFillStyle"}}]}]},
+ 'GetBackground','GetBackgroundMode',
'GetBrush','GetCharHeight','GetCharWidth',{'GetClippingBox',[{"rect", skip_member}]},
'GetFont','GetLayoutDirection','GetLogicalFunction','GetMapMode','GetMultiLineTextExtent',
{'GetPartialTextExtents', [{"widths", out}]},
@@ -340,21 +352,33 @@
'LogicalToDeviceX','LogicalToDeviceXRel','LogicalToDeviceY','LogicalToDeviceYRel',
'MaxX','MaxY','MinX','MinY','IsOk','ResetBoundingBox','SetAxisOrientation',
'SetBackground','SetBackgroundMode','SetBrush','SetClippingRegion','SetDeviceOrigin',
- 'SetFont','SetLayoutDirection','SetLogicalFunction','SetMapMode', 'SetPalette',
+ 'SetFont','SetLayoutDirection',
+ {'SetLogicalFunction', [{"function", [{base, {enum, "wxRasterOperationMode"}}]}]},
+ {'SetMapMode', [{"mode", [{base, {enum, "wxMappingMode"}}]}]},
+ 'SetPalette',
'SetPen','SetTextBackground','SetTextForeground','SetUserScale','StartDoc','StartPage']}.
{class,wxMirrorDC, wxDC, [], ['wxMirrorDC', '~wxMirrorDC']}.
{class,wxScreenDC, wxDC, [], ['wxScreenDC', '~wxScreenDC']}.
-{class,wxPostScriptDC,wxDC,[],['wxPostScriptDC','~wxPostScriptDC','SetResolution','GetResolution']}.
-{class,wxWindowDC, wxDC, [], ['wxWindowDC', '~wxWindowDC']}.
-{class,wxClientDC,wxWindowDC,[],['wxClientDC', '~wxClientDC']}.
-{class,wxPaintDC, wxWindowDC, [], ['wxPaintDC', '~wxPaintDC']}.
+{class,wxPostScriptDC,wxDC,[],
+ ['wxPostScriptDC','~wxPostScriptDC',
+ {'SetResolution', [{deprecated, "!wxCHECK_VERSION(2,9,0)"}]},
+ {'GetResolution', [{deprecated, "!wxCHECK_VERSION(2,9,0)"}]}]}.
+{class,wxWindowDC, wxDC, [],
+ [{'wxWindowDC', [{{func, 0}, [{deprecated, "!wxCHECK_VERSION(2,9,0)"}]}]},
+ '~wxWindowDC']}.
+{class,wxClientDC,wxWindowDC,[],
+ [{'wxClientDC', [{{func, 0}, [{deprecated, "!wxCHECK_VERSION(2,9,0)"}]}]},
+ '~wxClientDC']}.
+{class,wxPaintDC, wxWindowDC, [],
+ [{'wxPaintDC', [{{func, 0}, [{deprecated, "!wxCHECK_VERSION(2,9,0)"}]}]},
+ '~wxPaintDC']}.
%%{class,wxPrinterDC, wxDC, [], ['wxPrinterDC','GetPaperRect']}. Not in GTK
{class,wxMemoryDC, wxDC, [], ['wxMemoryDC', '~wxMemoryDC','SelectObject','SelectObjectAsSource']}.
{class,wxBufferedDC,wxMemoryDC,[],['wxBufferedDC','~wxBufferedDC','Init']}.
{class,wxBufferedPaintDC,wxBufferedDC,[],['wxBufferedPaintDC', '~wxBufferedPaintDC']}.
%% Only a typedef!
-%%{class,wxAutoBufferedPaintDC,wxBufferedPaintDC,[],['wxAutoBufferedPaintDC']}.
+%%{class,wxAutoBufferedPaintDC,wxBufferedPaintDC,[],['wxAutoBufferedPaintDC']}.
{class, wxGraphicsObject, object, [{ifdef, wxUSE_GRAPHICS_CONTEXT}],
['~wxGraphicsObject', 'GetRenderer','IsNull']}.
@@ -362,13 +386,17 @@
[{ifdef, wxUSE_GRAPHICS_CONTEXT}, {skip, [{'StrokeLines',4}]}],
['~wxGraphicsContext',
'Create', %%CreateFromNative CreateFromNativeWindow
- 'CreatePen','CreateBrush','CreateRadialGradientBrush',
- 'CreateLinearGradientBrush','CreateFont','CreateMatrix',
+ 'CreatePen','CreateBrush',
+ {'CreateRadialGradientBrush', [{deprecated, "!wxCHECK_VERSION(2,9,0)"}]},
+ {'CreateLinearGradientBrush', [{deprecated, "!wxCHECK_VERSION(2,9,0)"}]},
+ 'CreateFont','CreateMatrix',
'CreatePath','Clip','ResetClip',
'DrawBitmap','DrawEllipse','DrawIcon',
- {'DrawLines', [{"n",{c_only,{length,"points"}}}, {"points", {single,array}}]},
- 'DrawPath',
- 'DrawRectangle','DrawRoundedRectangle','DrawText','FillPath',
+ {'DrawLines', [{"n",{c_only,{length,"points"}}}, {"points", {single,array}},
+ {"fillStyle", [{base, {enum, "wxPolygonFillMode"}}]}]},
+ {'DrawPath',[{"fillStyle", [{base, {enum, "wxPolygonFillMode"}}]}]},
+ 'DrawRectangle','DrawRoundedRectangle','DrawText',
+ {'FillPath',[{"fillStyle", [{base, {enum, "wxPolygonFillMode"}}]}]},
'StrokePath', %% 'GetNativeContext',
{'GetPartialTextExtents', [{"widths", out}]},
'GetTextExtent','Rotate','Scale','Translate',
@@ -383,15 +411,18 @@
{class, wxGraphicsPath, wxGraphicsObject, [{ifdef, wxUSE_GRAPHICS_CONTEXT}],
['MoveToPoint','AddArc','AddArcToPoint','AddCircle','AddCurveToPoint',
'AddEllipse','AddLineToPoint','AddPath','AddQuadCurveToPoint',
- 'AddRectangle','AddRoundedRectangle','CloseSubpath','Contains',
- 'GetBox','GetCurrentPoint','Transform'
+ 'AddRectangle','AddRoundedRectangle','CloseSubpath',
+ {'Contains', [{"fillStyle", [{base, {enum, "wxPolygonFillMode"}}]}]},
+ 'GetBox','GetCurrentPoint','Transform'
%'GetNativePath','UnGetNativePath'
]}.
{class, wxGraphicsRenderer, object, [{ifdef, wxUSE_GRAPHICS_CONTEXT}],
['GetDefaultRenderer','CreateContext',
%%'CreateContextFromNativeContext', 'CreateContextFromNativeWindow',
'CreatePen','CreateBrush',
- 'CreateLinearGradientBrush','CreateRadialGradientBrush','CreateFont',
+ {'CreateLinearGradientBrush', [{deprecated, "!wxCHECK_VERSION(2,9,0)"}]},
+ {'CreateRadialGradientBrush', [{deprecated, "!wxCHECK_VERSION(2,9,0)"}]},
+ 'CreateFont',
'CreateMatrix','CreatePath']}.
{class, wxGraphicsPen, wxGraphicsObject,[{ifdef, wxUSE_GRAPHICS_CONTEXT}], []}.
@@ -501,10 +532,12 @@
'CopyFromBitmap','~wxIcon']}.
{class, wxIconBundle, root, [],
- ['wxIconBundle','~wxIconBundle','AddIcon','GetIcon']}.
+ ['wxIconBundle','~wxIconBundle','AddIcon',
+ {'GetIcon', [{return, {by_val, true}}]}]}.
{class, wxCursor, wxBitmap,[],
- [{'wxCursor',[{"bits",[in,{base,binary},{single,true}]},
+ [{'wxCursor',[{{func, 5}, [{deprecated, "!wxCHECK_VERSION(2,9,0)"}]},
+ {"bits",[in,{base,binary},{single,true}]},
{"maskBits",nowhere},{"fg",nowhere},{"bg",nowhere}]},
'~wxCursor','Ok']}.
@@ -549,16 +582,22 @@
{'GetAlpha',[{{0,return},{base,{binary,"(This->GetWidth()*This->GetHeight())"}}}]},
'GetBlue',
{'GetData', [{return,{base,{binary,"(This->GetWidth()*This->GetHeight()*3)"}}}]},
- 'GetGreen', 'GetImageCount', %'GetHandlers',
+ 'GetGreen',
+ {'GetImageCount', [{"type", [{base, {enum, "wxBitmapType"}}]}]},
+ %%'GetHandlers',
'GetHeight','GetMaskBlue','GetMaskGreen',
'GetMaskRed','GetOrFindMaskColour','GetPalette',
'GetRed','GetSubImage', 'GetWidth',%%':HSVValue', 'HSVtoRGB',
'HasAlpha','HasMask','GetOption','GetOptionInt','HasOption',
'InitAlpha','InitStandardHandlers',%'InsertHandler',
'IsTransparent', 'LoadFile','Ok',%%RGBValue 'RGBtoHSV',
- 'RemoveHandler','Mirror','Replace','Rescale','Resize',
+ 'RemoveHandler','Mirror','Replace',
+ {'Rescale', [{"quality", [{base, {enum, "wxImageResizeQuality"}}]}]},
+ 'Resize',
'Rotate', 'RotateHue',
- 'Rotate90','SaveFile','Scale','Size',
+ 'Rotate90','SaveFile',
+ {'Scale', [{"quality", [{base, {enum, "wxImageResizeQuality"}}]}]},
+ 'Size',
{'SetAlpha', [{{2,"alpha"},[in,{base,binary}, {def, none}]},
{{2,pre_hook},
[{c, "if(!static_data) {"
@@ -576,15 +615,20 @@
'SetRGB']}.
{class, wxBrush, object, [],
- ['wxBrush','~wxBrush','GetColour','GetStipple','GetStyle',
+ ['wxBrush','~wxBrush',
+ {'GetColour', [{return, {by_val, true}}]},
+ 'GetStipple','GetStyle',
'IsHatch','IsOk','SetColour','SetStipple','SetStyle']}.
{class, wxPen, object, [],
- ['wxPen','~wxPen','GetCap','GetColour',
+ ['wxPen','~wxPen','GetCap',
+ {'GetColour', [{return, {by_val, true}}]},
%%'GetDashes', %'GetStipple',
- 'GetJoin', 'GetStyle','GetWidth','IsOk','SetCap','SetColour',
+ 'GetJoin', 'GetStyle','GetWidth','IsOk',
+ {'SetCap', [{"capStyle", [{base, {enum, "wxPenCap"}}]}]},
+ 'SetColour',
%%'SetDashes', %'SetStipple',
- 'SetJoin', 'SetStyle','SetWidth']}.
+ {'SetJoin', [{"joinStyle", [{base, {enum, "wxPenJoin"}}]}]}, 'SetStyle','SetWidth']}.
{enum, wxRegionContain, "wx"}.
@@ -683,8 +727,11 @@
['wxButton','~wxButton','Create',%'GetLabel',
'GetDefaultSize', 'SetDefault','SetLabel']}.
{class, wxBitmapButton, wxButton, [],
- ['wxBitmapButton','~wxBitmapButton','Create','GetBitmapDisabled',
- 'GetBitmapFocus','GetBitmapLabel','GetBitmapSelected',
+ ['wxBitmapButton','~wxBitmapButton','Create',
+ {'GetBitmapDisabled', [{return, {by_val, true}}]},
+ {'GetBitmapFocus', [{return, {by_val, true}}]},
+ {'GetBitmapLabel', [{return, {by_val, true}}]},
+ {'GetBitmapSelected', [{return, {by_val, true}}]},
'SetBitmapDisabled','SetBitmapFocus','SetBitmapLabel','SetBitmapSelected']}.
{class, wxToggleButton, wxControl, [],
['wxToggleButton','~wxToggleButton','Create','GetValue','SetValue']}.
@@ -693,8 +740,10 @@
{class, wxDateTime, root, [ignore], []}. %% Only for ifdefs and enums
{class, wxCalendarCtrl, wxControl, [],
- ['wxCalendarCtrl','Create','~wxCalendarCtrl','SetDate','GetDate',
- 'EnableYearChange','EnableMonthChange','EnableHolidayDisplay',
+ ['wxCalendarCtrl','Create','~wxCalendarCtrl','SetDate',
+ {'GetDate', [{return, {by_val, true}}]},
+ {'EnableYearChange', [{deprecated, "!wxCHECK_VERSION(2,9,0)"}]}, %% Temp bug in wx I assume
+ 'EnableMonthChange','EnableHolidayDisplay',
'SetHeaderColours','GetHeaderColourFg','GetHeaderColourBg',
'SetHighlightColours','GetHighlightColourFg','GetHighlightColourBg',
'SetHolidayColours','GetHolidayColourFg','GetHolidayColourBg',
@@ -816,8 +865,9 @@
{enum, wxTextAttrAlignment, "wxTEXT_ALIGNMENT_"}.
{class, wxTextAttr, root, [],
- ['wxTextAttr','GetAlignment','GetBackgroundColour','GetFont','GetLeftIndent',
- 'GetLeftSubIndent','GetRightIndent','GetTabs','GetTextColour',
+ ['wxTextAttr','GetAlignment','GetBackgroundColour',
+ {'GetFont', [{return, {by_val, true}}]},
+ 'GetLeftIndent','GetLeftSubIndent','GetRightIndent','GetTabs','GetTextColour',
'HasBackgroundColour','HasFont','HasTextColour','GetFlags','IsDefault',
'SetAlignment','SetBackgroundColour','SetFlags','SetFont','SetLeftIndent',
'SetRightIndent','SetTabs','SetTextColour']}.
@@ -1233,7 +1283,8 @@
{class, wxMDIParentFrame, wxFrame, [],
[
- 'wxMDIParentFrame', '~wxMDIParentFrame', 'ActivateNext', 'ActivatePrevious',
+ 'wxMDIParentFrame',
+ '~wxMDIParentFrame', 'ActivateNext', 'ActivatePrevious',
'ArrangeIcons', 'Cascade', 'Create',
%%'GetClientSize', 'GetToolBar', 'SetToolBar', defined in parent
'GetActiveChild', 'GetClientWindow',
@@ -1244,8 +1295,9 @@
{class, wxMDIChildFrame, wxFrame, [],
['wxMDIChildFrame','~wxMDIChildFrame','Activate','Create','Maximize','Restore']}.
-{class, wxMDIClientWindow, wxWindow, [],
- ['wxMDIClientWindow','~wxMDIClientWindow','CreateClient']}.
+{class, wxMDIClientWindow, wxWindow, [],
+ [{'wxMDIClientWindow', [{{func, 2}, [{deprecated, "!wxCHECK_VERSION(2,9,0)"}]}]},
+ '~wxMDIClientWindow','CreateClient']}.
{class, wxLayoutAlgorithm, object, [],
['wxLayoutAlgorithm', '~wxLayoutAlgorithm',
@@ -1310,12 +1362,7 @@
[wxEVT_LEFT_DOWN,wxEVT_LEFT_UP,wxEVT_MIDDLE_DOWN,wxEVT_MIDDLE_UP,
wxEVT_RIGHT_DOWN,wxEVT_RIGHT_UP,wxEVT_MOTION,wxEVT_ENTER_WINDOW,
wxEVT_LEAVE_WINDOW,wxEVT_LEFT_DCLICK,wxEVT_MIDDLE_DCLICK,
- wxEVT_RIGHT_DCLICK,wxEVT_MOUSEWHEEL,
- wxEVT_NC_LEFT_DOWN,wxEVT_NC_LEFT_UP,
- wxEVT_NC_MIDDLE_DOWN,wxEVT_NC_MIDDLE_UP,wxEVT_NC_RIGHT_DOWN,
- wxEVT_NC_RIGHT_UP,wxEVT_NC_MOTION,wxEVT_NC_ENTER_WINDOW,
- wxEVT_NC_LEAVE_WINDOW,wxEVT_NC_LEFT_DCLICK,wxEVT_NC_MIDDLE_DCLICK,
- wxEVT_NC_RIGHT_DCLICK]}],
+ wxEVT_RIGHT_DCLICK,wxEVT_MOUSEWHEEL]}],
['AltDown','Button','ButtonDClick','ButtonDown','ButtonUp','CmdDown','ControlDown',
'Dragging', 'Entering', 'GetButton', 'GetPosition', 'GetLogicalPosition',
'GetLinesPerAction', 'GetWheelRotation', 'GetWheelDelta', 'GetX', 'GetY',
@@ -1345,8 +1392,8 @@
['GetSize']}.
{class, wxMoveEvent, wxEvent, [{event,[wxEVT_MOVE]}],
['GetPosition']}.
-{class, wxPaintEvent, wxEvent, [{event,[wxEVT_PAINT,wxEVT_PAINT_ICON]}],[]}.
-{class, wxNcPaintEvent, wxEvent, [{event,[wxEVT_NC_PAINT]}],[]}.
+{class, wxPaintEvent, wxEvent, [{event,[wxEVT_PAINT]}],[]}.
+%%{class, wxNcPaintEvent, wxEvent, [{event,[wxEVT_NC_PAINT]}],[]}.
{class, wxEraseEvent, wxEvent,
[{acc, [{m_dc, "GetDC()"}]},
{event, [wxEVT_ERASE_BACKGROUND]}],
@@ -1415,7 +1462,8 @@
['GetPosition','SetPosition']}.
{enum, wxIdleMode, "wxIDLE_"}.
{class, wxIdleEvent, wxEvent, [{event,[wxEVT_IDLE]}],
- ['CanSend','GetMode','RequestMore','MoreRequested','SetMode']}.
+ [{'CanSend', [{deprecated, "!wxCHECK_VERSION(2,9,0)"}]},
+ 'GetMode','RequestMore','MoreRequested','SetMode']}.
{class, wxGridEvent, wxNotifyEvent,
[{acc, [{m_row, "GetRow()"}, {m_col, "GetCol()"}, {m_x, "GetPosition().x"},{m_y, "GetPosition().y"},
{m_selecting, "Selecting()"},{m_control,"ControlDown()"},
@@ -1634,7 +1682,7 @@
'StyleSetFont', 'StyleSetFontAttr', 'StyleSetCharacterSet', 'StyleSetFontEncoding',
'CmdKeyExecute',
'SetMargins', {'GetSelection', [{"startPos", [out]}, {"endPos",[out]}]},
- 'PointFromPosition', 'ScrollToLine', 'ScrollToColumn', 'SendMsg',
+ 'PointFromPosition', 'ScrollToLine', 'ScrollToColumn', %% 'SendMsg',
'SetVScrollBar', 'SetHScrollBar', 'GetLastKeydownProcessed', 'SetLastKeydownProcessed',
'SaveFile', 'LoadFile', 'DoDragOver', 'DoDropText', 'GetUseAntiAliasing',
{'AddTextRaw', [{"text", [in, {base, binary}]}]},
diff --git a/lib/wx/c_src/Makefile.in b/lib/wx/c_src/Makefile.in
index 1497ac4d16..1d17076d23 100644
--- a/lib/wx/c_src/Makefile.in
+++ b/lib/wx/c_src/Makefile.in
@@ -71,8 +71,7 @@ WX_OBJECTS = $(GENERAL_O) $(GENERATED_O) $(RC_FILE)
OBJECTS = $(WX_OBJECTS) $(GL_OBJECTS)
-TARGET_APIS = wxe_driver erl_gl
-TARGET_DIR = ../priv
+TARGET_DIR = ../priv/$(SYS_TYPE)
# -O2 -funroll-loops -ffast-math -fomit-frame-pointer
@@ -121,7 +120,7 @@ debug:
clean:
rm -f $(OBJECTS)
- rm -f ../priv/$(TARGET_DIR)/$(TARGET_API)$(SO_EXT)
+ rm -f $(TARGET_DIR)/*$(SO_EXT)
rm -f *~ erl_crash.dump
complete_clean:
diff --git a/lib/wx/c_src/gen/wxe_derived_dest.h b/lib/wx/c_src/gen/wxe_derived_dest.h
index 6b7a5378cb..5fdce27d4b 100644
--- a/lib/wx/c_src/gen/wxe_derived_dest.h
+++ b/lib/wx/c_src/gen/wxe_derived_dest.h
@@ -94,19 +94,25 @@ class EwxPostScriptDC : public wxPostScriptDC {
class EwxWindowDC : public wxWindowDC {
public: ~EwxWindowDC() {((WxeApp *)wxTheApp)->clearPtr(this);};
EwxWindowDC(wxWindow * win) : wxWindowDC(win) {};
+#if !wxCHECK_VERSION(2,9,0)
EwxWindowDC() : wxWindowDC() {};
+#endif
};
class EwxClientDC : public wxClientDC {
public: ~EwxClientDC() {((WxeApp *)wxTheApp)->clearPtr(this);};
EwxClientDC(wxWindow * win) : wxClientDC(win) {};
+#if !wxCHECK_VERSION(2,9,0)
EwxClientDC() : wxClientDC() {};
+#endif
};
class EwxPaintDC : public wxPaintDC {
public: ~EwxPaintDC() {((WxeApp *)wxTheApp)->clearPtr(this);};
EwxPaintDC(wxWindow * win) : wxPaintDC(win) {};
+#if !wxCHECK_VERSION(2,9,0)
EwxPaintDC() : wxPaintDC() {};
+#endif
};
class EwxMemoryDC : public wxMemoryDC {
@@ -182,7 +188,9 @@ class EwxIcon : public wxIcon {
class EwxCursor : public wxCursor {
public: ~EwxCursor() {((WxeApp *)wxTheApp)->clearPtr(this);};
+#if !wxCHECK_VERSION(2,9,0)
EwxCursor(const char * bits,int width,int height,int hotSpotX,int hotSpotY) : wxCursor(bits,width,height,hotSpotX,hotSpotY) {};
+#endif
EwxCursor(int cursorId) : wxCursor(cursorId) {};
EwxCursor(const wxImage& image) : wxCursor(image) {};
EwxCursor() : wxCursor() {};
@@ -286,7 +294,7 @@ class EwxStdDialogButtonSizer : public wxStdDialogButtonSizer {
class EwxFont : public wxFont {
public: ~EwxFont() {((WxeApp *)wxTheApp)->clearPtr(this);};
- EwxFont(int size,int family,int style,int weight,bool underlined,const wxString& face,wxFontEncoding encoding) : wxFont(size,family,style,weight,underlined,face,encoding) {};
+ EwxFont(int size,wxFontFamily family,wxFontStyle style,int weight,bool underlined,const wxString& face,wxFontEncoding encoding) : wxFont(size,family,style,weight,underlined,face,encoding) {};
EwxFont(const wxString& fontname) : wxFont(fontname) {};
EwxFont() : wxFont() {};
};
@@ -712,7 +720,9 @@ class EwxMDIChildFrame : public wxMDIChildFrame {
class EwxMDIClientWindow : public wxMDIClientWindow {
public: ~EwxMDIClientWindow() {((WxeApp *)wxTheApp)->clearPtr(this);};
+#if !wxCHECK_VERSION(2,9,0)
EwxMDIClientWindow(wxMDIParentFrame * parent,long style) : wxMDIClientWindow(parent,style) {};
+#endif
EwxMDIClientWindow() : wxMDIClientWindow() {};
};
diff --git a/lib/wx/c_src/gen/wxe_events.cpp b/lib/wx/c_src/gen/wxe_events.cpp
index 0afb02150a..7a3233a410 100644
--- a/lib/wx/c_src/gen/wxe_events.cpp
+++ b/lib/wx/c_src/gen/wxe_events.cpp
@@ -107,18 +107,6 @@ void initEventTable()
{wxEVT_MIDDLE_DCLICK, 167, "middle_dclick"},
{wxEVT_RIGHT_DCLICK, 167, "right_dclick"},
{wxEVT_MOUSEWHEEL, 167, "mousewheel"},
- {wxEVT_NC_LEFT_DOWN, 167, "nc_left_down"},
- {wxEVT_NC_LEFT_UP, 167, "nc_left_up"},
- {wxEVT_NC_MIDDLE_DOWN, 167, "nc_middle_down"},
- {wxEVT_NC_MIDDLE_UP, 167, "nc_middle_up"},
- {wxEVT_NC_RIGHT_DOWN, 167, "nc_right_down"},
- {wxEVT_NC_RIGHT_UP, 167, "nc_right_up"},
- {wxEVT_NC_MOTION, 167, "nc_motion"},
- {wxEVT_NC_ENTER_WINDOW, 167, "nc_enter_window"},
- {wxEVT_NC_LEAVE_WINDOW, 167, "nc_leave_window"},
- {wxEVT_NC_LEFT_DCLICK, 167, "nc_left_dclick"},
- {wxEVT_NC_MIDDLE_DCLICK, 167, "nc_middle_dclick"},
- {wxEVT_NC_RIGHT_DCLICK, 167, "nc_right_dclick"},
{wxEVT_SET_CURSOR, 168, "set_cursor"},
{wxEVT_CHAR, 169, "char"},
{wxEVT_CHAR_HOOK, 169, "char_hook"},
@@ -127,187 +115,185 @@ void initEventTable()
{wxEVT_SIZE, 170, "size"},
{wxEVT_MOVE, 171, "move"},
{wxEVT_PAINT, 172, "paint"},
- {wxEVT_PAINT_ICON, 172, "paint_icon"},
- {wxEVT_NC_PAINT, 173, "nc_paint"},
- {wxEVT_ERASE_BACKGROUND, 174, "erase_background"},
- {wxEVT_SET_FOCUS, 175, "set_focus"},
- {wxEVT_KILL_FOCUS, 175, "kill_focus"},
- {wxEVT_CHILD_FOCUS, 176, "child_focus"},
- {wxEVT_MENU_OPEN, 177, "menu_open"},
- {wxEVT_MENU_CLOSE, 177, "menu_close"},
- {wxEVT_MENU_HIGHLIGHT, 177, "menu_highlight"},
- {wxEVT_CLOSE_WINDOW, 178, "close_window"},
- {wxEVT_END_SESSION, 178, "end_session"},
- {wxEVT_QUERY_END_SESSION, 178, "query_end_session"},
- {wxEVT_SHOW, 179, "show"},
- {wxEVT_ICONIZE, 180, "iconize"},
- {wxEVT_MAXIMIZE, 181, "maximize"},
- {wxEVT_JOY_BUTTON_DOWN, 182, "joy_button_down"},
- {wxEVT_JOY_BUTTON_UP, 182, "joy_button_up"},
- {wxEVT_JOY_MOVE, 182, "joy_move"},
- {wxEVT_JOY_ZMOVE, 182, "joy_zmove"},
- {wxEVT_UPDATE_UI, 183, "update_ui"},
- {wxEVT_SYS_COLOUR_CHANGED, 184, "sys_colour_changed"},
- {wxEVT_MOUSE_CAPTURE_CHANGED, 185, "mouse_capture_changed"},
- {wxEVT_DISPLAY_CHANGED, 186, "display_changed"},
- {wxEVT_PALETTE_CHANGED, 187, "palette_changed"},
- {wxEVT_QUERY_NEW_PALETTE, 188, "query_new_palette"},
- {wxEVT_NAVIGATION_KEY, 189, "navigation_key"},
- {wxEVT_CREATE, 190, "create"},
- {wxEVT_DESTROY, 191, "destroy"},
- {wxEVT_HELP, 192, "help"},
- {wxEVT_DETAILED_HELP, 192, "detailed_help"},
- {wxEVT_CONTEXT_MENU, 193, "context_menu"},
- {wxEVT_IDLE, 194, "idle"},
- {wxEVT_GRID_CELL_LEFT_CLICK, 195, "grid_cell_left_click"},
- {wxEVT_GRID_CELL_RIGHT_CLICK, 195, "grid_cell_right_click"},
- {wxEVT_GRID_CELL_LEFT_DCLICK, 195, "grid_cell_left_dclick"},
- {wxEVT_GRID_CELL_RIGHT_DCLICK, 195, "grid_cell_right_dclick"},
- {wxEVT_GRID_LABEL_LEFT_CLICK, 195, "grid_label_left_click"},
- {wxEVT_GRID_LABEL_RIGHT_CLICK, 195, "grid_label_right_click"},
- {wxEVT_GRID_LABEL_LEFT_DCLICK, 195, "grid_label_left_dclick"},
- {wxEVT_GRID_LABEL_RIGHT_DCLICK, 195, "grid_label_right_dclick"},
- {wxEVT_GRID_ROW_SIZE, 195, "grid_row_size"},
- {wxEVT_GRID_COL_SIZE, 195, "grid_col_size"},
- {wxEVT_GRID_RANGE_SELECT, 195, "grid_range_select"},
- {wxEVT_GRID_CELL_CHANGE, 195, "grid_cell_change"},
- {wxEVT_GRID_SELECT_CELL, 195, "grid_select_cell"},
- {wxEVT_GRID_EDITOR_SHOWN, 195, "grid_editor_shown"},
- {wxEVT_GRID_EDITOR_HIDDEN, 195, "grid_editor_hidden"},
- {wxEVT_GRID_EDITOR_CREATED, 195, "grid_editor_created"},
- {wxEVT_GRID_CELL_BEGIN_DRAG, 195, "grid_cell_begin_drag"},
- {wxEVT_SASH_DRAGGED, 197, "sash_dragged"},
- {wxEVT_COMMAND_LIST_BEGIN_DRAG, 198, "command_list_begin_drag"},
- {wxEVT_COMMAND_LIST_BEGIN_RDRAG, 198, "command_list_begin_rdrag"},
- {wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT, 198, "command_list_begin_label_edit"},
- {wxEVT_COMMAND_LIST_END_LABEL_EDIT, 198, "command_list_end_label_edit"},
- {wxEVT_COMMAND_LIST_DELETE_ITEM, 198, "command_list_delete_item"},
- {wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS, 198, "command_list_delete_all_items"},
- {wxEVT_COMMAND_LIST_KEY_DOWN, 198, "command_list_key_down"},
- {wxEVT_COMMAND_LIST_INSERT_ITEM, 198, "command_list_insert_item"},
- {wxEVT_COMMAND_LIST_COL_CLICK, 198, "command_list_col_click"},
- {wxEVT_COMMAND_LIST_COL_RIGHT_CLICK, 198, "command_list_col_right_click"},
- {wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, 198, "command_list_col_begin_drag"},
- {wxEVT_COMMAND_LIST_COL_DRAGGING, 198, "command_list_col_dragging"},
- {wxEVT_COMMAND_LIST_COL_END_DRAG, 198, "command_list_col_end_drag"},
- {wxEVT_COMMAND_LIST_ITEM_SELECTED, 198, "command_list_item_selected"},
- {wxEVT_COMMAND_LIST_ITEM_DESELECTED, 198, "command_list_item_deselected"},
- {wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, 198, "command_list_item_right_click"},
- {wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK, 198, "command_list_item_middle_click"},
- {wxEVT_COMMAND_LIST_ITEM_ACTIVATED, 198, "command_list_item_activated"},
- {wxEVT_COMMAND_LIST_ITEM_FOCUSED, 198, "command_list_item_focused"},
- {wxEVT_COMMAND_LIST_CACHE_HINT, 198, "command_list_cache_hint"},
- {wxEVT_DATE_CHANGED, 199, "date_changed"},
- {wxEVT_CALENDAR_SEL_CHANGED, 200, "calendar_sel_changed"},
- {wxEVT_CALENDAR_DAY_CHANGED, 200, "calendar_day_changed"},
- {wxEVT_CALENDAR_MONTH_CHANGED, 200, "calendar_month_changed"},
- {wxEVT_CALENDAR_YEAR_CHANGED, 200, "calendar_year_changed"},
- {wxEVT_CALENDAR_DOUBLECLICKED, 200, "calendar_doubleclicked"},
- {wxEVT_CALENDAR_WEEKDAY_CLICKED, 200, "calendar_weekday_clicked"},
- {wxEVT_COMMAND_FILEPICKER_CHANGED, 201, "command_filepicker_changed"},
- {wxEVT_COMMAND_DIRPICKER_CHANGED, 201, "command_dirpicker_changed"},
- {wxEVT_COMMAND_COLOURPICKER_CHANGED, 202, "command_colourpicker_changed"},
- {wxEVT_COMMAND_FONTPICKER_CHANGED, 203, "command_fontpicker_changed"},
- {wxEVT_STC_CHANGE, 204, "stc_change"},
- {wxEVT_STC_STYLENEEDED, 204, "stc_styleneeded"},
- {wxEVT_STC_CHARADDED, 204, "stc_charadded"},
- {wxEVT_STC_SAVEPOINTREACHED, 204, "stc_savepointreached"},
- {wxEVT_STC_SAVEPOINTLEFT, 204, "stc_savepointleft"},
- {wxEVT_STC_ROMODIFYATTEMPT, 204, "stc_romodifyattempt"},
- {wxEVT_STC_KEY, 204, "stc_key"},
- {wxEVT_STC_DOUBLECLICK, 204, "stc_doubleclick"},
- {wxEVT_STC_UPDATEUI, 204, "stc_updateui"},
- {wxEVT_STC_MODIFIED, 204, "stc_modified"},
- {wxEVT_STC_MACRORECORD, 204, "stc_macrorecord"},
- {wxEVT_STC_MARGINCLICK, 204, "stc_marginclick"},
- {wxEVT_STC_NEEDSHOWN, 204, "stc_needshown"},
- {wxEVT_STC_PAINTED, 204, "stc_painted"},
- {wxEVT_STC_USERLISTSELECTION, 204, "stc_userlistselection"},
- {wxEVT_STC_URIDROPPED, 204, "stc_uridropped"},
- {wxEVT_STC_DWELLSTART, 204, "stc_dwellstart"},
- {wxEVT_STC_DWELLEND, 204, "stc_dwellend"},
- {wxEVT_STC_START_DRAG, 204, "stc_start_drag"},
- {wxEVT_STC_DRAG_OVER, 204, "stc_drag_over"},
- {wxEVT_STC_DO_DROP, 204, "stc_do_drop"},
- {wxEVT_STC_ZOOM, 204, "stc_zoom"},
- {wxEVT_STC_HOTSPOT_CLICK, 204, "stc_hotspot_click"},
- {wxEVT_STC_HOTSPOT_DCLICK, 204, "stc_hotspot_dclick"},
- {wxEVT_STC_CALLTIP_CLICK, 204, "stc_calltip_click"},
- {wxEVT_STC_AUTOCOMP_SELECTION, 204, "stc_autocomp_selection"},
- {wxEVT_COMMAND_TREE_BEGIN_DRAG, 209, "command_tree_begin_drag"},
- {wxEVT_COMMAND_TREE_BEGIN_RDRAG, 209, "command_tree_begin_rdrag"},
- {wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, 209, "command_tree_begin_label_edit"},
- {wxEVT_COMMAND_TREE_END_LABEL_EDIT, 209, "command_tree_end_label_edit"},
- {wxEVT_COMMAND_TREE_DELETE_ITEM, 209, "command_tree_delete_item"},
- {wxEVT_COMMAND_TREE_GET_INFO, 209, "command_tree_get_info"},
- {wxEVT_COMMAND_TREE_SET_INFO, 209, "command_tree_set_info"},
- {wxEVT_COMMAND_TREE_ITEM_EXPANDED, 209, "command_tree_item_expanded"},
- {wxEVT_COMMAND_TREE_ITEM_EXPANDING, 209, "command_tree_item_expanding"},
- {wxEVT_COMMAND_TREE_ITEM_COLLAPSED, 209, "command_tree_item_collapsed"},
- {wxEVT_COMMAND_TREE_ITEM_COLLAPSING, 209, "command_tree_item_collapsing"},
- {wxEVT_COMMAND_TREE_SEL_CHANGED, 209, "command_tree_sel_changed"},
- {wxEVT_COMMAND_TREE_SEL_CHANGING, 209, "command_tree_sel_changing"},
- {wxEVT_COMMAND_TREE_KEY_DOWN, 209, "command_tree_key_down"},
- {wxEVT_COMMAND_TREE_ITEM_ACTIVATED, 209, "command_tree_item_activated"},
- {wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, 209, "command_tree_item_right_click"},
- {wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK, 209, "command_tree_item_middle_click"},
- {wxEVT_COMMAND_TREE_END_DRAG, 209, "command_tree_end_drag"},
- {wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK, 209, "command_tree_state_image_click"},
- {wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP, 209, "command_tree_item_gettooltip"},
- {wxEVT_COMMAND_TREE_ITEM_MENU, 209, "command_tree_item_menu"},
- {wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, 210, "command_notebook_page_changed"},
- {wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING, 210, "command_notebook_page_changing"},
- {wxEVT_COMMAND_SPINCTRL_UPDATED, 216, "command_spinctrl_updated"},
+ {wxEVT_ERASE_BACKGROUND, 173, "erase_background"},
+ {wxEVT_SET_FOCUS, 174, "set_focus"},
+ {wxEVT_KILL_FOCUS, 174, "kill_focus"},
+ {wxEVT_CHILD_FOCUS, 175, "child_focus"},
+ {wxEVT_MENU_OPEN, 176, "menu_open"},
+ {wxEVT_MENU_CLOSE, 176, "menu_close"},
+ {wxEVT_MENU_HIGHLIGHT, 176, "menu_highlight"},
+ {wxEVT_CLOSE_WINDOW, 177, "close_window"},
+ {wxEVT_END_SESSION, 177, "end_session"},
+ {wxEVT_QUERY_END_SESSION, 177, "query_end_session"},
+ {wxEVT_SHOW, 178, "show"},
+ {wxEVT_ICONIZE, 179, "iconize"},
+ {wxEVT_MAXIMIZE, 180, "maximize"},
+ {wxEVT_JOY_BUTTON_DOWN, 181, "joy_button_down"},
+ {wxEVT_JOY_BUTTON_UP, 181, "joy_button_up"},
+ {wxEVT_JOY_MOVE, 181, "joy_move"},
+ {wxEVT_JOY_ZMOVE, 181, "joy_zmove"},
+ {wxEVT_UPDATE_UI, 182, "update_ui"},
+ {wxEVT_SYS_COLOUR_CHANGED, 183, "sys_colour_changed"},
+ {wxEVT_MOUSE_CAPTURE_CHANGED, 184, "mouse_capture_changed"},
+ {wxEVT_DISPLAY_CHANGED, 185, "display_changed"},
+ {wxEVT_PALETTE_CHANGED, 186, "palette_changed"},
+ {wxEVT_QUERY_NEW_PALETTE, 187, "query_new_palette"},
+ {wxEVT_NAVIGATION_KEY, 188, "navigation_key"},
+ {wxEVT_CREATE, 189, "create"},
+ {wxEVT_DESTROY, 190, "destroy"},
+ {wxEVT_HELP, 191, "help"},
+ {wxEVT_DETAILED_HELP, 191, "detailed_help"},
+ {wxEVT_CONTEXT_MENU, 192, "context_menu"},
+ {wxEVT_IDLE, 193, "idle"},
+ {wxEVT_GRID_CELL_LEFT_CLICK, 194, "grid_cell_left_click"},
+ {wxEVT_GRID_CELL_RIGHT_CLICK, 194, "grid_cell_right_click"},
+ {wxEVT_GRID_CELL_LEFT_DCLICK, 194, "grid_cell_left_dclick"},
+ {wxEVT_GRID_CELL_RIGHT_DCLICK, 194, "grid_cell_right_dclick"},
+ {wxEVT_GRID_LABEL_LEFT_CLICK, 194, "grid_label_left_click"},
+ {wxEVT_GRID_LABEL_RIGHT_CLICK, 194, "grid_label_right_click"},
+ {wxEVT_GRID_LABEL_LEFT_DCLICK, 194, "grid_label_left_dclick"},
+ {wxEVT_GRID_LABEL_RIGHT_DCLICK, 194, "grid_label_right_dclick"},
+ {wxEVT_GRID_ROW_SIZE, 194, "grid_row_size"},
+ {wxEVT_GRID_COL_SIZE, 194, "grid_col_size"},
+ {wxEVT_GRID_RANGE_SELECT, 194, "grid_range_select"},
+ {wxEVT_GRID_CELL_CHANGE, 194, "grid_cell_change"},
+ {wxEVT_GRID_SELECT_CELL, 194, "grid_select_cell"},
+ {wxEVT_GRID_EDITOR_SHOWN, 194, "grid_editor_shown"},
+ {wxEVT_GRID_EDITOR_HIDDEN, 194, "grid_editor_hidden"},
+ {wxEVT_GRID_EDITOR_CREATED, 194, "grid_editor_created"},
+ {wxEVT_GRID_CELL_BEGIN_DRAG, 194, "grid_cell_begin_drag"},
+ {wxEVT_SASH_DRAGGED, 196, "sash_dragged"},
+ {wxEVT_COMMAND_LIST_BEGIN_DRAG, 197, "command_list_begin_drag"},
+ {wxEVT_COMMAND_LIST_BEGIN_RDRAG, 197, "command_list_begin_rdrag"},
+ {wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT, 197, "command_list_begin_label_edit"},
+ {wxEVT_COMMAND_LIST_END_LABEL_EDIT, 197, "command_list_end_label_edit"},
+ {wxEVT_COMMAND_LIST_DELETE_ITEM, 197, "command_list_delete_item"},
+ {wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS, 197, "command_list_delete_all_items"},
+ {wxEVT_COMMAND_LIST_KEY_DOWN, 197, "command_list_key_down"},
+ {wxEVT_COMMAND_LIST_INSERT_ITEM, 197, "command_list_insert_item"},
+ {wxEVT_COMMAND_LIST_COL_CLICK, 197, "command_list_col_click"},
+ {wxEVT_COMMAND_LIST_COL_RIGHT_CLICK, 197, "command_list_col_right_click"},
+ {wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, 197, "command_list_col_begin_drag"},
+ {wxEVT_COMMAND_LIST_COL_DRAGGING, 197, "command_list_col_dragging"},
+ {wxEVT_COMMAND_LIST_COL_END_DRAG, 197, "command_list_col_end_drag"},
+ {wxEVT_COMMAND_LIST_ITEM_SELECTED, 197, "command_list_item_selected"},
+ {wxEVT_COMMAND_LIST_ITEM_DESELECTED, 197, "command_list_item_deselected"},
+ {wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, 197, "command_list_item_right_click"},
+ {wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK, 197, "command_list_item_middle_click"},
+ {wxEVT_COMMAND_LIST_ITEM_ACTIVATED, 197, "command_list_item_activated"},
+ {wxEVT_COMMAND_LIST_ITEM_FOCUSED, 197, "command_list_item_focused"},
+ {wxEVT_COMMAND_LIST_CACHE_HINT, 197, "command_list_cache_hint"},
+ {wxEVT_DATE_CHANGED, 198, "date_changed"},
+ {wxEVT_CALENDAR_SEL_CHANGED, 199, "calendar_sel_changed"},
+ {wxEVT_CALENDAR_DAY_CHANGED, 199, "calendar_day_changed"},
+ {wxEVT_CALENDAR_MONTH_CHANGED, 199, "calendar_month_changed"},
+ {wxEVT_CALENDAR_YEAR_CHANGED, 199, "calendar_year_changed"},
+ {wxEVT_CALENDAR_DOUBLECLICKED, 199, "calendar_doubleclicked"},
+ {wxEVT_CALENDAR_WEEKDAY_CLICKED, 199, "calendar_weekday_clicked"},
+ {wxEVT_COMMAND_FILEPICKER_CHANGED, 200, "command_filepicker_changed"},
+ {wxEVT_COMMAND_DIRPICKER_CHANGED, 200, "command_dirpicker_changed"},
+ {wxEVT_COMMAND_COLOURPICKER_CHANGED, 201, "command_colourpicker_changed"},
+ {wxEVT_COMMAND_FONTPICKER_CHANGED, 202, "command_fontpicker_changed"},
+ {wxEVT_STC_CHANGE, 203, "stc_change"},
+ {wxEVT_STC_STYLENEEDED, 203, "stc_styleneeded"},
+ {wxEVT_STC_CHARADDED, 203, "stc_charadded"},
+ {wxEVT_STC_SAVEPOINTREACHED, 203, "stc_savepointreached"},
+ {wxEVT_STC_SAVEPOINTLEFT, 203, "stc_savepointleft"},
+ {wxEVT_STC_ROMODIFYATTEMPT, 203, "stc_romodifyattempt"},
+ {wxEVT_STC_KEY, 203, "stc_key"},
+ {wxEVT_STC_DOUBLECLICK, 203, "stc_doubleclick"},
+ {wxEVT_STC_UPDATEUI, 203, "stc_updateui"},
+ {wxEVT_STC_MODIFIED, 203, "stc_modified"},
+ {wxEVT_STC_MACRORECORD, 203, "stc_macrorecord"},
+ {wxEVT_STC_MARGINCLICK, 203, "stc_marginclick"},
+ {wxEVT_STC_NEEDSHOWN, 203, "stc_needshown"},
+ {wxEVT_STC_PAINTED, 203, "stc_painted"},
+ {wxEVT_STC_USERLISTSELECTION, 203, "stc_userlistselection"},
+ {wxEVT_STC_URIDROPPED, 203, "stc_uridropped"},
+ {wxEVT_STC_DWELLSTART, 203, "stc_dwellstart"},
+ {wxEVT_STC_DWELLEND, 203, "stc_dwellend"},
+ {wxEVT_STC_START_DRAG, 203, "stc_start_drag"},
+ {wxEVT_STC_DRAG_OVER, 203, "stc_drag_over"},
+ {wxEVT_STC_DO_DROP, 203, "stc_do_drop"},
+ {wxEVT_STC_ZOOM, 203, "stc_zoom"},
+ {wxEVT_STC_HOTSPOT_CLICK, 203, "stc_hotspot_click"},
+ {wxEVT_STC_HOTSPOT_DCLICK, 203, "stc_hotspot_dclick"},
+ {wxEVT_STC_CALLTIP_CLICK, 203, "stc_calltip_click"},
+ {wxEVT_STC_AUTOCOMP_SELECTION, 203, "stc_autocomp_selection"},
+ {wxEVT_COMMAND_TREE_BEGIN_DRAG, 208, "command_tree_begin_drag"},
+ {wxEVT_COMMAND_TREE_BEGIN_RDRAG, 208, "command_tree_begin_rdrag"},
+ {wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, 208, "command_tree_begin_label_edit"},
+ {wxEVT_COMMAND_TREE_END_LABEL_EDIT, 208, "command_tree_end_label_edit"},
+ {wxEVT_COMMAND_TREE_DELETE_ITEM, 208, "command_tree_delete_item"},
+ {wxEVT_COMMAND_TREE_GET_INFO, 208, "command_tree_get_info"},
+ {wxEVT_COMMAND_TREE_SET_INFO, 208, "command_tree_set_info"},
+ {wxEVT_COMMAND_TREE_ITEM_EXPANDED, 208, "command_tree_item_expanded"},
+ {wxEVT_COMMAND_TREE_ITEM_EXPANDING, 208, "command_tree_item_expanding"},
+ {wxEVT_COMMAND_TREE_ITEM_COLLAPSED, 208, "command_tree_item_collapsed"},
+ {wxEVT_COMMAND_TREE_ITEM_COLLAPSING, 208, "command_tree_item_collapsing"},
+ {wxEVT_COMMAND_TREE_SEL_CHANGED, 208, "command_tree_sel_changed"},
+ {wxEVT_COMMAND_TREE_SEL_CHANGING, 208, "command_tree_sel_changing"},
+ {wxEVT_COMMAND_TREE_KEY_DOWN, 208, "command_tree_key_down"},
+ {wxEVT_COMMAND_TREE_ITEM_ACTIVATED, 208, "command_tree_item_activated"},
+ {wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, 208, "command_tree_item_right_click"},
+ {wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK, 208, "command_tree_item_middle_click"},
+ {wxEVT_COMMAND_TREE_END_DRAG, 208, "command_tree_end_drag"},
+ {wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK, 208, "command_tree_state_image_click"},
+ {wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP, 208, "command_tree_item_gettooltip"},
+ {wxEVT_COMMAND_TREE_ITEM_MENU, 208, "command_tree_item_menu"},
+ {wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, 209, "command_notebook_page_changed"},
+ {wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING, 209, "command_notebook_page_changing"},
+ {wxEVT_COMMAND_SPINCTRL_UPDATED, 215, "command_spinctrl_updated"},
{wxEVT_SCROLL_LINEUP + wxEVT_USER_FIRST, 165, "spin_up"},
{wxEVT_SCROLL_LINEDOWN + wxEVT_USER_FIRST, 165, "spin_down"},
{wxEVT_SCROLL_THUMBTRACK + wxEVT_USER_FIRST, 165, "spin"},
- {wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGED, 218, "command_splitter_sash_pos_changed"},
- {wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGING, 218, "command_splitter_sash_pos_changing"},
- {wxEVT_COMMAND_SPLITTER_DOUBLECLICKED, 218, "command_splitter_doubleclicked"},
- {wxEVT_COMMAND_SPLITTER_UNSPLIT, 218, "command_splitter_unsplit"},
- {wxEVT_COMMAND_HTML_LINK_CLICKED, 220, "command_html_link_clicked"},
- {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, 223, "command_auinotebook_page_close"},
- {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, 223, "command_auinotebook_page_changed"},
- {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, 223, "command_auinotebook_page_changing"},
- {wxEVT_COMMAND_AUINOTEBOOK_BUTTON, 223, "command_auinotebook_button"},
- {wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, 223, "command_auinotebook_begin_drag"},
- {wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, 223, "command_auinotebook_end_drag"},
- {wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, 223, "command_auinotebook_drag_motion"},
- {wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, 223, "command_auinotebook_allow_dnd"},
+ {wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGED, 217, "command_splitter_sash_pos_changed"},
+ {wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGING, 217, "command_splitter_sash_pos_changing"},
+ {wxEVT_COMMAND_SPLITTER_DOUBLECLICKED, 217, "command_splitter_doubleclicked"},
+ {wxEVT_COMMAND_SPLITTER_UNSPLIT, 217, "command_splitter_unsplit"},
+ {wxEVT_COMMAND_HTML_LINK_CLICKED, 219, "command_html_link_clicked"},
+ {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, 222, "command_auinotebook_page_close"},
+ {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, 222, "command_auinotebook_page_changed"},
+ {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, 222, "command_auinotebook_page_changing"},
+ {wxEVT_COMMAND_AUINOTEBOOK_BUTTON, 222, "command_auinotebook_button"},
+ {wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, 222, "command_auinotebook_begin_drag"},
+ {wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, 222, "command_auinotebook_end_drag"},
+ {wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, 222, "command_auinotebook_drag_motion"},
+ {wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, 222, "command_auinotebook_allow_dnd"},
#if wxCHECK_VERSION(2,8,5)
- {wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN, 223, "command_auinotebook_tab_middle_down"},
+ {wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN, 222, "command_auinotebook_tab_middle_down"},
#endif
#if wxCHECK_VERSION(2,8,5)
- {wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP, 223, "command_auinotebook_tab_middle_up"},
+ {wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP, 222, "command_auinotebook_tab_middle_up"},
#endif
#if wxCHECK_VERSION(2,8,5)
- {wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN, 223, "command_auinotebook_tab_right_down"},
+ {wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN, 222, "command_auinotebook_tab_right_down"},
#endif
#if wxCHECK_VERSION(2,8,5)
- {wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, 223, "command_auinotebook_tab_right_up"},
+ {wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, 222, "command_auinotebook_tab_right_up"},
#endif
#if wxCHECK_VERSION(2,8,5)
- {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, 223, "command_auinotebook_page_closed"},
+ {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, 222, "command_auinotebook_page_closed"},
#endif
#if wxCHECK_VERSION(2,8,5)
- {wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE, 223, "command_auinotebook_drag_done"},
+ {wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE, 222, "command_auinotebook_drag_done"},
#endif
#if wxCHECK_VERSION(2,8,5)
- {wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, 223, "command_auinotebook_bg_dclick"},
+ {wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, 222, "command_auinotebook_bg_dclick"},
#endif
- {wxEVT_AUI_PANE_BUTTON, 224, "aui_pane_button"},
- {wxEVT_AUI_PANE_CLOSE, 224, "aui_pane_close"},
- {wxEVT_AUI_PANE_MAXIMIZE, 224, "aui_pane_maximize"},
- {wxEVT_AUI_PANE_RESTORE, 224, "aui_pane_restore"},
- {wxEVT_AUI_RENDER, 224, "aui_render"},
- {wxEVT_AUI_FIND_MANAGER, 224, "aui_find_manager"},
- {wxEVT_TASKBAR_MOVE, 227, "taskbar_move"},
- {wxEVT_TASKBAR_LEFT_DOWN, 227, "taskbar_left_down"},
- {wxEVT_TASKBAR_LEFT_UP, 227, "taskbar_left_up"},
- {wxEVT_TASKBAR_RIGHT_DOWN, 227, "taskbar_right_down"},
- {wxEVT_TASKBAR_RIGHT_UP, 227, "taskbar_right_up"},
- {wxEVT_TASKBAR_LEFT_DCLICK, 227, "taskbar_left_dclick"},
- {wxEVT_TASKBAR_RIGHT_DCLICK, 227, "taskbar_right_dclick"},
+ {wxEVT_AUI_PANE_BUTTON, 223, "aui_pane_button"},
+ {wxEVT_AUI_PANE_CLOSE, 223, "aui_pane_close"},
+ {wxEVT_AUI_PANE_MAXIMIZE, 223, "aui_pane_maximize"},
+ {wxEVT_AUI_PANE_RESTORE, 223, "aui_pane_restore"},
+ {wxEVT_AUI_RENDER, 223, "aui_render"},
+ {wxEVT_AUI_FIND_MANAGER, 223, "aui_find_manager"},
+ {wxEVT_TASKBAR_MOVE, 226, "taskbar_move"},
+ {wxEVT_TASKBAR_LEFT_DOWN, 226, "taskbar_left_down"},
+ {wxEVT_TASKBAR_LEFT_UP, 226, "taskbar_left_up"},
+ {wxEVT_TASKBAR_RIGHT_DOWN, 226, "taskbar_right_down"},
+ {wxEVT_TASKBAR_RIGHT_UP, 226, "taskbar_right_up"},
+ {wxEVT_TASKBAR_LEFT_DCLICK, 226, "taskbar_left_dclick"},
+ {wxEVT_TASKBAR_RIGHT_DCLICK, 226, "taskbar_right_dclick"},
{-1, 0, }
};
for(int i=0; event_types[i].ev_type != -1; i++) {
@@ -437,7 +423,11 @@ case 169: {// wxKeyEvent
rt.addBool(ev->m_shiftDown);
rt.addBool(ev->m_altDown);
rt.addBool(ev->m_metaDown);
+#if !wxCHECK_VERSION(2,9,0)
rt.addBool(ev->m_scanCode);
+#else
+ rt.addBool(false);
+#endif
rt.addInt(ev->m_uniChar);
rt.addUint(ev->m_rawCode);
rt.addUint(ev->m_rawFlags);
@@ -468,14 +458,7 @@ case 172: {// wxPaintEvent
rt.addTupleCount(2);
break;
}
-case 173: {// wxNcPaintEvent
- evClass = (char*)"wxNcPaintEvent";
- rt.addAtom((char*)"wxNcPaint");
- rt.addAtom(Etype->eName);
- rt.addTupleCount(2);
- break;
-}
-case 174: {// wxEraseEvent
+case 173: {// wxEraseEvent
wxEraseEvent * ev = (wxEraseEvent *) event;
wxDC * GetDC = ev->GetDC();
evClass = (char*)"wxEraseEvent";
@@ -485,105 +468,105 @@ case 174: {// wxEraseEvent
rt.addTupleCount(3);
break;
}
-case 175: {// wxFocusEvent
+case 174: {// wxFocusEvent
evClass = (char*)"wxFocusEvent";
rt.addAtom((char*)"wxFocus");
rt.addAtom(Etype->eName);
rt.addTupleCount(2);
break;
}
-case 176: {// wxChildFocusEvent
+case 175: {// wxChildFocusEvent
evClass = (char*)"wxChildFocusEvent";
rt.addAtom((char*)"wxChildFocus");
rt.addAtom(Etype->eName);
rt.addTupleCount(2);
break;
}
-case 177: {// wxMenuEvent
+case 176: {// wxMenuEvent
evClass = (char*)"wxMenuEvent";
rt.addAtom((char*)"wxMenu");
rt.addAtom(Etype->eName);
rt.addTupleCount(2);
break;
}
-case 178: {// wxCloseEvent
+case 177: {// wxCloseEvent
evClass = (char*)"wxCloseEvent";
rt.addAtom((char*)"wxClose");
rt.addAtom(Etype->eName);
rt.addTupleCount(2);
break;
}
-case 179: {// wxShowEvent
+case 178: {// wxShowEvent
evClass = (char*)"wxShowEvent";
rt.addAtom((char*)"wxShow");
rt.addAtom(Etype->eName);
rt.addTupleCount(2);
break;
}
-case 180: {// wxIconizeEvent
+case 179: {// wxIconizeEvent
evClass = (char*)"wxIconizeEvent";
rt.addAtom((char*)"wxIconize");
rt.addAtom(Etype->eName);
rt.addTupleCount(2);
break;
}
-case 181: {// wxMaximizeEvent
+case 180: {// wxMaximizeEvent
evClass = (char*)"wxMaximizeEvent";
rt.addAtom((char*)"wxMaximize");
rt.addAtom(Etype->eName);
rt.addTupleCount(2);
break;
}
-case 182: {// wxJoystickEvent
+case 181: {// wxJoystickEvent
evClass = (char*)"wxJoystickEvent";
rt.addAtom((char*)"wxJoystick");
rt.addAtom(Etype->eName);
rt.addTupleCount(2);
break;
}
-case 183: {// wxUpdateUIEvent
+case 182: {// wxUpdateUIEvent
evClass = (char*)"wxUpdateUIEvent";
rt.addAtom((char*)"wxUpdateUI");
rt.addAtom(Etype->eName);
rt.addTupleCount(2);
break;
}
-case 184: {// wxSysColourChangedEvent
+case 183: {// wxSysColourChangedEvent
evClass = (char*)"wxSysColourChangedEvent";
rt.addAtom((char*)"wxSysColourChanged");
rt.addAtom(Etype->eName);
rt.addTupleCount(2);
break;
}
-case 185: {// wxMouseCaptureChangedEvent
+case 184: {// wxMouseCaptureChangedEvent
evClass = (char*)"wxMouseCaptureChangedEvent";
rt.addAtom((char*)"wxMouseCaptureChanged");
rt.addAtom(Etype->eName);
rt.addTupleCount(2);
break;
}
-case 186: {// wxDisplayChangedEvent
+case 185: {// wxDisplayChangedEvent
evClass = (char*)"wxDisplayChangedEvent";
rt.addAtom((char*)"wxDisplayChanged");
rt.addAtom(Etype->eName);
rt.addTupleCount(2);
break;
}
-case 187: {// wxPaletteChangedEvent
+case 186: {// wxPaletteChangedEvent
evClass = (char*)"wxPaletteChangedEvent";
rt.addAtom((char*)"wxPaletteChanged");
rt.addAtom(Etype->eName);
rt.addTupleCount(2);
break;
}
-case 188: {// wxQueryNewPaletteEvent
+case 187: {// wxQueryNewPaletteEvent
evClass = (char*)"wxQueryNewPaletteEvent";
rt.addAtom((char*)"wxQueryNewPalette");
rt.addAtom(Etype->eName);
rt.addTupleCount(2);
break;
}
-case 189: {// wxNavigationKeyEvent
+case 188: {// wxNavigationKeyEvent
wxNavigationKeyEvent * ev = (wxNavigationKeyEvent *) event;
evClass = (char*)"wxNavigationKeyEvent";
rt.addAtom((char*)"wxNavigationKey");
@@ -593,42 +576,42 @@ case 189: {// wxNavigationKeyEvent
rt.addTupleCount(4);
break;
}
-case 190: {// wxWindowCreateEvent
+case 189: {// wxWindowCreateEvent
evClass = (char*)"wxWindowCreateEvent";
rt.addAtom((char*)"wxWindowCreate");
rt.addAtom(Etype->eName);
rt.addTupleCount(2);
break;
}
-case 191: {// wxWindowDestroyEvent
+case 190: {// wxWindowDestroyEvent
evClass = (char*)"wxWindowDestroyEvent";
rt.addAtom((char*)"wxWindowDestroy");
rt.addAtom(Etype->eName);
rt.addTupleCount(2);
break;
}
-case 192: {// wxHelpEvent
+case 191: {// wxHelpEvent
evClass = (char*)"wxHelpEvent";
rt.addAtom((char*)"wxHelp");
rt.addAtom(Etype->eName);
rt.addTupleCount(2);
break;
}
-case 193: {// wxContextMenuEvent
+case 192: {// wxContextMenuEvent
evClass = (char*)"wxContextMenuEvent";
rt.addAtom((char*)"wxContextMenu");
rt.addAtom(Etype->eName);
rt.addTupleCount(2);
break;
}
-case 194: {// wxIdleEvent
+case 193: {// wxIdleEvent
evClass = (char*)"wxIdleEvent";
rt.addAtom((char*)"wxIdle");
rt.addAtom(Etype->eName);
rt.addTupleCount(2);
break;
}
-case 195: {// wxGridEvent
+case 194: {// wxGridEvent
wxGridEvent * ev = (wxGridEvent *) event;
evClass = (char*)"wxGridEvent";
rt.addAtom((char*)"wxGrid");
@@ -645,7 +628,7 @@ case 195: {// wxGridEvent
rt.addTupleCount(11);
break;
}
-case 197: {// wxSashEvent
+case 196: {// wxSashEvent
wxSashEvent * ev = (wxSashEvent *) event;
evClass = (char*)"wxSashEvent";
rt.addAtom((char*)"wxSash");
@@ -656,7 +639,7 @@ case 197: {// wxSashEvent
rt.addTupleCount(5);
break;
}
-case 198: {// wxListEvent
+case 197: {// wxListEvent
wxListEvent * ev = (wxListEvent *) event;
evClass = (char*)"wxListEvent";
rt.addAtom((char*)"wxList");
@@ -669,7 +652,7 @@ case 198: {// wxListEvent
rt.addTupleCount(7);
break;
}
-case 199: {// wxDateEvent
+case 198: {// wxDateEvent
wxDateEvent * ev = (wxDateEvent *) event;
evClass = (char*)"wxDateEvent";
rt.addAtom((char*)"wxDate");
@@ -678,14 +661,14 @@ case 199: {// wxDateEvent
rt.addTupleCount(3);
break;
}
-case 200: {// wxCalendarEvent
+case 199: {// wxCalendarEvent
evClass = (char*)"wxCalendarEvent";
rt.addAtom((char*)"wxCalendar");
rt.addAtom(Etype->eName);
rt.addTupleCount(2);
break;
}
-case 201: {// wxFileDirPickerEvent
+case 200: {// wxFileDirPickerEvent
wxFileDirPickerEvent * ev = (wxFileDirPickerEvent *) event;
evClass = (char*)"wxFileDirPickerEvent";
rt.addAtom((char*)"wxFileDirPicker");
@@ -694,7 +677,7 @@ case 201: {// wxFileDirPickerEvent
rt.addTupleCount(3);
break;
}
-case 202: {// wxColourPickerEvent
+case 201: {// wxColourPickerEvent
wxColourPickerEvent * ev = (wxColourPickerEvent *) event;
evClass = (char*)"wxColourPickerEvent";
rt.addAtom((char*)"wxColourPicker");
@@ -703,7 +686,7 @@ case 202: {// wxColourPickerEvent
rt.addTupleCount(3);
break;
}
-case 203: {// wxFontPickerEvent
+case 202: {// wxFontPickerEvent
wxFontPickerEvent * ev = (wxFontPickerEvent *) event;
wxFont * GetFont = new wxFont(ev->GetFont());
app->newPtr((void *) GetFont,3, memenv);
@@ -714,7 +697,7 @@ case 203: {// wxFontPickerEvent
rt.addTupleCount(3);
break;
}
-case 204: {// wxStyledTextEvent
+case 203: {// wxStyledTextEvent
wxStyledTextEvent * ev = (wxStyledTextEvent *) event;
evClass = (char*)"wxStyledTextEvent";
rt.addAtom((char*)"wxStyledText");
@@ -742,7 +725,7 @@ case 204: {// wxStyledTextEvent
rt.addTupleCount(22);
break;
}
-case 209: {// wxTreeEvent
+case 208: {// wxTreeEvent
wxTreeEvent * ev = (wxTreeEvent *) event;
evClass = (char*)"wxTreeEvent";
rt.addAtom((char*)"wxTree");
@@ -753,14 +736,14 @@ case 209: {// wxTreeEvent
rt.addTupleCount(5);
break;
}
-case 210: {// wxNotebookEvent
+case 209: {// wxNotebookEvent
evClass = (char*)"wxNotebookEvent";
rt.addAtom((char*)"wxNotebook");
rt.addAtom(Etype->eName);
rt.addTupleCount(2);
break;
}
-case 216: {// wxSpinEvent
+case 215: {// wxSpinEvent
wxSpinEvent * ev = (wxSpinEvent *) event;
evClass = (char*)"wxSpinEvent";
rt.addAtom((char*)"wxSpin");
@@ -769,14 +752,14 @@ case 216: {// wxSpinEvent
rt.addTupleCount(3);
break;
}
-case 218: {// wxSplitterEvent
+case 217: {// wxSplitterEvent
evClass = (char*)"wxSplitterEvent";
rt.addAtom((char*)"wxSplitter");
rt.addAtom(Etype->eName);
rt.addTupleCount(2);
break;
}
-case 220: {// wxHtmlLinkEvent
+case 219: {// wxHtmlLinkEvent
wxHtmlLinkEvent * ev = (wxHtmlLinkEvent *) event;
evClass = (char*)"wxHtmlLinkEvent";
rt.addAtom((char*)"wxHtmlLink");
@@ -785,7 +768,7 @@ case 220: {// wxHtmlLinkEvent
rt.addTupleCount(3);
break;
}
-case 223: {// wxAuiNotebookEvent
+case 222: {// wxAuiNotebookEvent
wxAuiNotebookEvent * ev = (wxAuiNotebookEvent *) event;
wxAuiNotebook * GetDragSource = ev->GetDragSource();
evClass = (char*)"wxAuiNotebookEvent";
@@ -797,7 +780,7 @@ case 223: {// wxAuiNotebookEvent
rt.addTupleCount(5);
break;
}
-case 224: {// wxAuiManagerEvent
+case 223: {// wxAuiManagerEvent
wxAuiManagerEvent * ev = (wxAuiManagerEvent *) event;
wxAuiManager * GetManager = ev->GetManager();
wxAuiPaneInfo * GetPane = ev->GetPane();
@@ -814,7 +797,7 @@ case 224: {// wxAuiManagerEvent
rt.addTupleCount(8);
break;
}
-case 227: {// wxTaskBarIconEvent
+case 226: {// wxTaskBarIconEvent
evClass = (char*)"wxTaskBarIconEvent";
rt.addAtom((char*)"wxTaskBarIcon");
rt.addAtom(Etype->eName);
diff --git a/lib/wx/c_src/gen/wxe_funcs.cpp b/lib/wx/c_src/gen/wxe_funcs.cpp
index 15012011ed..5fbe8a2a9e 100644
--- a/lib/wx/c_src/gen/wxe_funcs.cpp
+++ b/lib/wx/c_src/gen/wxe_funcs.cpp
@@ -27,6 +27,15 @@
#include "wxe_macros.h"
#include "wxe_derived_dest.h"
+#if !wxCHECK_VERSION(2,9,0)
+#define wxPenJoin int
+#define wxPenCap int
+#define wxImageResizeQuality int
+#define wxPolygonFillMode int
+#define wxMappingMode int
+#define wxRasterOperationMode int
+#define wxFloodFillStyle int
+#endif
void WxeApp::wxe_dispatch(wxeCommand& Ecmd)
{
char * bp = Ecmd.buffer;
@@ -149,7 +158,7 @@ case wxWindow_new_3: { // wxWindow::wxWindow
style = (long)*(int *) bp; bp += 4;
} break;
}};
- wxWindow * Result = new EwxWindow(parent,(wxWindowID) *id,pos,size,style);
+ wxWindow * Result = new EwxWindow(parent,*id,pos,size,style);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxWindow");
break;
@@ -326,7 +335,7 @@ case wxWindow_FindWindow_1_0: { // wxWindow::FindWindow
wxWindow *This = (wxWindow *) getPtr(bp,memenv); bp += 4;
int * winid = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxWindow * Result = (wxWindow*)This->FindWindow((long) *winid);
+ wxWindow * Result = (wxWindow*)This->FindWindow(*winid);
rt.addRef(getRef((void *)Result,memenv), "wxWindow");
break;
}
@@ -349,7 +358,7 @@ case wxWindow_FindWindowById: { // wxWindow::FindWindowById
parent = (wxWindow *) getPtr(bp,memenv); bp += 4;
} break;
}};
- wxWindow * Result = (wxWindow*)wxWindow::FindWindowById((long) *winid,parent);
+ wxWindow * Result = (wxWindow*)wxWindow::FindWindowById(*winid,parent);
rt.addRef(getRef((void *)Result,memenv), "wxWindow");
break;
}
@@ -615,7 +624,7 @@ case wxWindow_GetScrollPos: { // wxWindow::GetScrollPos
wxWindow *This = (wxWindow *) getPtr(bp,memenv); bp += 4;
int * orient = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->GetScrollPos((int) *orient);
+ int Result = This->GetScrollPos(*orient);
rt.addInt(Result);
break;
}
@@ -623,7 +632,7 @@ case wxWindow_GetScrollRange: { // wxWindow::GetScrollRange
wxWindow *This = (wxWindow *) getPtr(bp,memenv); bp += 4;
int * orient = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->GetScrollRange((int) *orient);
+ int Result = This->GetScrollRange(*orient);
rt.addInt(Result);
break;
}
@@ -631,7 +640,7 @@ case wxWindow_GetScrollThumb: { // wxWindow::GetScrollThumb
wxWindow *This = (wxWindow *) getPtr(bp,memenv); bp += 4;
int * orient = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->GetScrollThumb((int) *orient);
+ int Result = This->GetScrollThumb(*orient);
rt.addInt(Result);
break;
}
@@ -719,7 +728,7 @@ case wxWindow_HasScrollbar: { // wxWindow::HasScrollbar
wxWindow *This = (wxWindow *) getPtr(bp,memenv); bp += 4;
int * orient = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->HasScrollbar((int) *orient);
+ bool Result = This->HasScrollbar(*orient);
rt.addBool(Result);
break;
}
@@ -767,7 +776,7 @@ case wxWindow_IsExposed_2: { // wxWindow::IsExposed
int * x = (int *) bp; bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->IsExposed((int) *x,(int) *y);
+ bool Result = This->IsExposed(*x,*y);
rt.addBool(Result);
break;
}
@@ -778,7 +787,7 @@ case wxWindow_IsExposed_4: { // wxWindow::IsExposed
int * w = (int *) bp; bp += 4;
int * h = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->IsExposed((int) *x,(int) *y,(int) *w,(int) *h);
+ bool Result = This->IsExposed(*x,*y,*w,*h);
rt.addBool(Result);
break;
}
@@ -877,7 +886,7 @@ case wxWindow_Move_3: { // wxWindow::Move
} break;
}};
if(!This) throw wxe_badarg(0);
- This->Move((int) *x,(int) *y,flags);
+ This->Move(*x,*y,flags);
break;
}
case wxWindow_Move_2: { // wxWindow::Move
@@ -975,7 +984,7 @@ case wxWindow_PopupMenu_3: { // wxWindow::PopupMenu
int * x = (int *) bp; bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->PopupMenu(menu,(int) *x,(int) *y);
+ bool Result = This->PopupMenu(menu,*x,*y);
rt.addBool(Result);
break;
}
@@ -1071,7 +1080,7 @@ case wxWindow_ScrollLines: { // wxWindow::ScrollLines
wxWindow *This = (wxWindow *) getPtr(bp,memenv); bp += 4;
int * lines = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->ScrollLines((int) *lines);
+ bool Result = This->ScrollLines(*lines);
rt.addBool(Result);
break;
}
@@ -1079,7 +1088,7 @@ case wxWindow_ScrollPages: { // wxWindow::ScrollPages
wxWindow *This = (wxWindow *) getPtr(bp,memenv); bp += 4;
int * pages = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->ScrollPages((int) *pages);
+ bool Result = This->ScrollPages(*pages);
rt.addBool(Result);
break;
}
@@ -1100,7 +1109,7 @@ case wxWindow_ScrollWindow: { // wxWindow::ScrollWindow
} break;
}};
if(!This) throw wxe_badarg(0);
- This->ScrollWindow((int) *dx,(int) *dy,rect);
+ This->ScrollWindow(*dx,*dy,rect);
break;
}
case wxWindow_SetAcceleratorTable: { // wxWindow::SetAcceleratorTable
@@ -1114,7 +1123,7 @@ case wxWindow_SetAutoLayout: { // wxWindow::SetAutoLayout
wxWindow *This = (wxWindow *) getPtr(bp,memenv); bp += 4;
bool * autoLayout = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetAutoLayout((bool) *autoLayout);
+ This->SetAutoLayout(*autoLayout);
break;
}
case wxWindow_SetBackgroundColour: { // wxWindow::SetBackgroundColour
@@ -1133,7 +1142,7 @@ case wxWindow_SetBackgroundStyle: { // wxWindow::SetBackgroundStyle
wxWindow *This = (wxWindow *) getPtr(bp,memenv); bp += 4;
wxBackgroundStyle style = *(wxBackgroundStyle *) bp; bp += 4;;
if(!This) throw wxe_badarg(0);
- bool Result = This->SetBackgroundStyle((wxBackgroundStyle) style);
+ bool Result = This->SetBackgroundStyle(style);
rt.addBool(Result);
break;
}
@@ -1149,7 +1158,7 @@ case wxWindow_SetClientSize_2: { // wxWindow::SetClientSize
int * width = (int *) bp; bp += 4;
int * height = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetClientSize((int) *width,(int) *height);
+ This->SetClientSize(*width,*height);
break;
}
case wxWindow_SetClientSize_1_0: { // wxWindow::SetClientSize
@@ -1245,7 +1254,7 @@ case wxWindow_SetExtraStyle: { // wxWindow::SetExtraStyle
wxWindow *This = (wxWindow *) getPtr(bp,memenv); bp += 4;
int * exStyle = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetExtraStyle((long) *exStyle);
+ This->SetExtraStyle(*exStyle);
break;
}
case wxWindow_SetFocus: { // wxWindow::SetFocus
@@ -1293,7 +1302,7 @@ case wxWindow_SetId: { // wxWindow::SetId
wxWindow *This = (wxWindow *) getPtr(bp,memenv); bp += 4;
int * winid = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetId((wxWindowID) *winid);
+ This->SetId(*winid);
break;
}
case wxWindow_SetLabel: { // wxWindow::SetLabel
@@ -1335,7 +1344,7 @@ case wxWindow_SetScrollbar: { // wxWindow::SetScrollbar
} break;
}};
if(!This) throw wxe_badarg(0);
- This->SetScrollbar((int) *orient,(int) *pos,(int) *thumbVisible,(int) *range,refresh);
+ This->SetScrollbar(*orient,*pos,*thumbVisible,*range,refresh);
break;
}
case wxWindow_SetScrollPos: { // wxWindow::SetScrollPos
@@ -1350,7 +1359,7 @@ case wxWindow_SetScrollPos: { // wxWindow::SetScrollPos
} break;
}};
if(!This) throw wxe_badarg(0);
- This->SetScrollPos((int) *orient,(int) *pos,refresh);
+ This->SetScrollPos(*orient,*pos,refresh);
break;
}
case wxWindow_SetSize_5: { // wxWindow::SetSize
@@ -1367,7 +1376,7 @@ case wxWindow_SetSize_5: { // wxWindow::SetSize
} break;
}};
if(!This) throw wxe_badarg(0);
- This->SetSize((int) *x,(int) *y,(int) *width,(int) *height,sizeFlags);
+ This->SetSize(*x,*y,*width,*height,sizeFlags);
break;
}
case wxWindow_SetSize_2_0: { // wxWindow::SetSize
@@ -1375,7 +1384,7 @@ case wxWindow_SetSize_2_0: { // wxWindow::SetSize
int * width = (int *) bp; bp += 4;
int * height = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetSize((int) *width,(int) *height);
+ This->SetSize(*width,*height);
break;
}
case wxWindow_SetSize_1: { // wxWindow::SetSize
@@ -1429,7 +1438,7 @@ case wxWindow_SetSizeHints_3: { // wxWindow::SetSizeHints
} break;
}};
if(!This) throw wxe_badarg(0);
- This->SetSizeHints((int) *minW,(int) *minH,maxW,maxH,incW,incH);
+ This->SetSizeHints(*minW,*minH,maxW,maxH,incW,incH);
break;
}
case wxWindow_SetSizeHints_2: { // wxWindow::SetSizeHints
@@ -1488,7 +1497,7 @@ case wxWindow_SetThemeEnabled: { // wxWindow::SetThemeEnabled
wxWindow *This = (wxWindow *) getPtr(bp,memenv); bp += 4;
bool * enableTheme = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetThemeEnabled((bool) *enableTheme);
+ This->SetThemeEnabled(*enableTheme);
break;
}
case wxWindow_SetToolTip_1_0: { // wxWindow::SetToolTip
@@ -1521,7 +1530,7 @@ case wxWindow_SetVirtualSize_2: { // wxWindow::SetVirtualSize
int * x = (int *) bp; bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetVirtualSize((int) *x,(int) *y);
+ This->SetVirtualSize(*x,*y);
break;
}
case wxWindow_SetVirtualSizeHints_3: { // wxWindow::SetVirtualSizeHints
@@ -1540,7 +1549,7 @@ case wxWindow_SetVirtualSizeHints_3: { // wxWindow::SetVirtualSizeHints
} break;
}};
if(!This) throw wxe_badarg(0);
- This->SetVirtualSizeHints((int) *minW,(int) *minH,maxW,maxH);
+ This->SetVirtualSizeHints(*minW,*minH,maxW,maxH);
break;
}
case wxWindow_SetVirtualSizeHints_2: { // wxWindow::SetVirtualSizeHints
@@ -1566,21 +1575,21 @@ case wxWindow_SetWindowStyle: { // wxWindow::SetWindowStyle
wxWindow *This = (wxWindow *) getPtr(bp,memenv); bp += 4;
int * style = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetWindowStyle((long) *style);
+ This->SetWindowStyle(*style);
break;
}
case wxWindow_SetWindowStyleFlag: { // wxWindow::SetWindowStyleFlag
wxWindow *This = (wxWindow *) getPtr(bp,memenv); bp += 4;
int * style = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetWindowStyleFlag((long) *style);
+ This->SetWindowStyleFlag(*style);
break;
}
case wxWindow_SetWindowVariant: { // wxWindow::SetWindowVariant
wxWindow *This = (wxWindow *) getPtr(bp,memenv); bp += 4;
wxWindowVariant variant = *(wxWindowVariant *) bp; bp += 4;;
if(!This) throw wxe_badarg(0);
- This->SetWindowVariant((wxWindowVariant) variant);
+ This->SetWindowVariant(variant);
break;
}
case wxWindow_ShouldInheritColours: { // wxWindow::ShouldInheritColours
@@ -1655,13 +1664,13 @@ case wxWindow_WarpPointer: { // wxWindow::WarpPointer
int * x = (int *) bp; bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->WarpPointer((int) *x,(int) *y);
+ This->WarpPointer(*x,*y);
break;
}
case wxTopLevelWindow_GetIcon: { // wxTopLevelWindow::GetIcon
wxTopLevelWindow *This = (wxTopLevelWindow *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- const wxIcon * Result = &This->GetIcon();
+ const wxIcon * Result = new wxIcon(This->GetIcon()); newPtr((void *) Result,3, memenv);;
rt.addRef(getRef((void *)Result,memenv), "wxIcon");
break;
}
@@ -1813,7 +1822,7 @@ case wxTopLevelWindow_ShowFullScreen: { // wxTopLevelWindow::ShowFullScreen
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->ShowFullScreen((bool) *show,style);
+ bool Result = This->ShowFullScreen(*show,style);
rt.addBool(Result);
break;
}
@@ -1843,7 +1852,7 @@ case wxFrame_new_4: { // wxFrame::wxFrame
style = (long)*(int *) bp; bp += 4;
} break;
}};
- wxFrame * Result = new EwxFrame(parent,(wxWindowID) *id,title,pos,size,style);
+ wxFrame * Result = new EwxFrame(parent,*id,title,pos,size,style);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxFrame");
break;
@@ -1882,7 +1891,7 @@ case wxFrame_Create: { // wxFrame::Create
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,title,pos,size,style);
+ bool Result = This->Create(parent,*id,title,pos,size,style);
rt.addBool(Result);
break;
}
@@ -1965,7 +1974,7 @@ case wxFrame_ProcessCommand: { // wxFrame::ProcessCommand
wxFrame *This = (wxFrame *) getPtr(bp,memenv); bp += 4;
int * winid = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->ProcessCommand((int) *winid);
+ bool Result = This->ProcessCommand(*winid);
rt.addBool(Result);
break;
}
@@ -1993,7 +2002,7 @@ case wxFrame_SetStatusBarPane: { // wxFrame::SetStatusBarPane
wxFrame *This = (wxFrame *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetStatusBarPane((int) *n);
+ This->SetStatusBarPane(*n);
break;
}
case wxFrame_SetStatusText: { // wxFrame::SetStatusText
@@ -2058,7 +2067,7 @@ case wxMiniFrame_new_4: { // wxMiniFrame::wxMiniFrame
style = (long)*(int *) bp; bp += 4;
} break;
}};
- wxMiniFrame * Result = new EwxMiniFrame(parent,(wxWindowID) *id,title,pos,size,style);
+ wxMiniFrame * Result = new EwxMiniFrame(parent,*id,title,pos,size,style);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxMiniFrame");
break;
@@ -2091,7 +2100,7 @@ case wxMiniFrame_Create: { // wxMiniFrame::Create
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,title,pos,size,style);
+ bool Result = This->Create(parent,*id,title,pos,size,style);
rt.addBool(Result);
break;
}
@@ -2128,7 +2137,7 @@ case wxSplashScreen_new_6: { // wxSplashScreen::wxSplashScreen
style = (long)*(int *) bp; bp += 4;
} break;
}};
- wxSplashScreen * Result = new EwxSplashScreen(*bitmap,(long) *splashStyle,(int) *milliseconds,parent,(wxWindowID) *id,pos,size,style);
+ wxSplashScreen * Result = new EwxSplashScreen(*bitmap,*splashStyle,*milliseconds,parent,*id,pos,size,style);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxSplashScreen");
break;
@@ -2166,7 +2175,7 @@ case wxPanel_new_6: { // wxPanel::wxPanel
style = (long)*(int *) bp; bp += 4;
} break;
}};
- wxPanel * Result = new EwxPanel(parent,(int) *x,(int) *y,(int) *width,(int) *height,style);
+ wxPanel * Result = new EwxPanel(parent,*x,*y,*width,*height,style);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxPanel");
break;
@@ -2254,7 +2263,7 @@ case wxScrolledWindow_CalcScrolledPosition_4: { // wxScrolledWindow::CalcScrolle
int * x = (int *) bp; bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->CalcScrolledPosition((int) *x,(int) *y,&xx,&yy);
+ This->CalcScrolledPosition(*x,*y,&xx,&yy);
rt.addInt(xx);
rt.addInt(yy);
rt.addTupleCount(2);
@@ -2277,7 +2286,7 @@ case wxScrolledWindow_CalcUnscrolledPosition_4: { // wxScrolledWindow::CalcUnscr
int * x = (int *) bp; bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->CalcUnscrolledPosition((int) *x,(int) *y,&xx,&yy);
+ This->CalcUnscrolledPosition(*x,*y,&xx,&yy);
rt.addInt(xx);
rt.addInt(yy);
rt.addTupleCount(2);
@@ -2298,7 +2307,7 @@ case wxScrolledWindow_EnableScrolling: { // wxScrolledWindow::EnableScrolling
bool * x_scrolling = (bool *) bp; bp += 4;
bool * y_scrolling = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->EnableScrolling((bool) *x_scrolling,(bool) *y_scrolling);
+ This->EnableScrolling(*x_scrolling,*y_scrolling);
break;
}
case wxScrolledWindow_GetScrollPixelsPerUnit: { // wxScrolledWindow::GetScrollPixelsPerUnit
@@ -2342,7 +2351,7 @@ case wxScrolledWindow_Scroll: { // wxScrolledWindow::Scroll
int * x = (int *) bp; bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->Scroll((int) *x,(int) *y);
+ This->Scroll(*x,*y);
break;
}
case wxScrolledWindow_SetScrollbars: { // wxScrolledWindow::SetScrollbars
@@ -2367,7 +2376,7 @@ case wxScrolledWindow_SetScrollbars: { // wxScrolledWindow::SetScrollbars
} break;
}};
if(!This) throw wxe_badarg(0);
- This->SetScrollbars((int) *pixelsPerUnitX,(int) *pixelsPerUnitY,(int) *noUnitsX,(int) *noUnitsY,xPos,yPos,noRefresh);
+ This->SetScrollbars(*pixelsPerUnitX,*pixelsPerUnitY,*noUnitsX,*noUnitsY,xPos,yPos,noRefresh);
break;
}
case wxScrolledWindow_SetScrollRate: { // wxScrolledWindow::SetScrollRate
@@ -2375,7 +2384,7 @@ case wxScrolledWindow_SetScrollRate: { // wxScrolledWindow::SetScrollRate
int * xstep = (int *) bp; bp += 4;
int * ystep = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetScrollRate((int) *xstep,(int) *ystep);
+ This->SetScrollRate(*xstep,*ystep);
break;
}
case wxScrolledWindow_SetTargetWindow: { // wxScrolledWindow::SetTargetWindow
@@ -2427,7 +2436,7 @@ case wxSashWindow_GetSashVisible: { // wxSashWindow::GetSashVisible
wxSashWindow *This = (wxSashWindow *) getPtr(bp,memenv); bp += 4;
wxSashEdgePosition edge = *(wxSashEdgePosition *) bp; bp += 4;;
if(!This) throw wxe_badarg(0);
- bool Result = This->GetSashVisible((wxSashEdgePosition) edge);
+ bool Result = This->GetSashVisible(edge);
rt.addBool(Result);
break;
}
@@ -2463,28 +2472,28 @@ case wxSashWindow_SetMaximumSizeX: { // wxSashWindow::SetMaximumSizeX
wxSashWindow *This = (wxSashWindow *) getPtr(bp,memenv); bp += 4;
int * max = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetMaximumSizeX((int) *max);
+ This->SetMaximumSizeX(*max);
break;
}
case wxSashWindow_SetMaximumSizeY: { // wxSashWindow::SetMaximumSizeY
wxSashWindow *This = (wxSashWindow *) getPtr(bp,memenv); bp += 4;
int * max = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetMaximumSizeY((int) *max);
+ This->SetMaximumSizeY(*max);
break;
}
case wxSashWindow_SetMinimumSizeX: { // wxSashWindow::SetMinimumSizeX
wxSashWindow *This = (wxSashWindow *) getPtr(bp,memenv); bp += 4;
int * min = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetMinimumSizeX((int) *min);
+ This->SetMinimumSizeX(*min);
break;
}
case wxSashWindow_SetMinimumSizeY: { // wxSashWindow::SetMinimumSizeY
wxSashWindow *This = (wxSashWindow *) getPtr(bp,memenv); bp += 4;
int * min = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetMinimumSizeY((int) *min);
+ This->SetMinimumSizeY(*min);
break;
}
case wxSashWindow_SetSashVisible: { // wxSashWindow::SetSashVisible
@@ -2492,7 +2501,7 @@ case wxSashWindow_SetSashVisible: { // wxSashWindow::SetSashVisible
wxSashEdgePosition edge = *(wxSashEdgePosition *) bp; bp += 4;;
bool * sash = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetSashVisible((wxSashEdgePosition) edge,(bool) *sash);
+ This->SetSashVisible(edge,*sash);
break;
}
case wxSashLayoutWindow_new_0: { // wxSashLayoutWindow::wxSashLayoutWindow
@@ -2583,7 +2592,7 @@ case wxSashLayoutWindow_SetAlignment: { // wxSashLayoutWindow::SetAlignment
wxSashLayoutWindow *This = (wxSashLayoutWindow *) getPtr(bp,memenv); bp += 4;
wxLayoutAlignment align = *(wxLayoutAlignment *) bp; bp += 4;;
if(!This) throw wxe_badarg(0);
- This->SetAlignment((wxLayoutAlignment) align);
+ This->SetAlignment(align);
break;
}
case wxSashLayoutWindow_SetDefaultSize: { // wxSashLayoutWindow::SetDefaultSize
@@ -2599,7 +2608,7 @@ case wxSashLayoutWindow_SetOrientation: { // wxSashLayoutWindow::SetOrientation
wxSashLayoutWindow *This = (wxSashLayoutWindow *) getPtr(bp,memenv); bp += 4;
wxLayoutOrientation orient = *(wxLayoutOrientation *) bp; bp += 4;;
if(!This) throw wxe_badarg(0);
- This->SetOrientation((wxLayoutOrientation) orient);
+ This->SetOrientation(orient);
break;
}
case wxGrid_new_0: { // wxGrid::wxGrid
@@ -2631,7 +2640,7 @@ case wxGrid_new_3: { // wxGrid::wxGrid
style = (long)*(int *) bp; bp += 4;
} break;
}};
- wxGrid * Result = new EwxGrid(parent,(wxWindowID) *id,pos,size,style);
+ wxGrid * Result = new EwxGrid(parent,*id,pos,size,style);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxGrid");
break;
@@ -2655,7 +2664,7 @@ case wxGrid_new_4: { // wxGrid::wxGrid
style = (long)*(int *) bp; bp += 4;
} break;
}};
- wxGrid * Result = new EwxGrid(parent,(int) *x,(int) *y,w,h,style);
+ wxGrid * Result = new EwxGrid(parent,*x,*y,w,h,style);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxGrid");
break;
@@ -2712,7 +2721,7 @@ case wxGrid_AutoSizeColumn: { // wxGrid::AutoSizeColumn
} break;
}};
if(!This) throw wxe_badarg(0);
- This->AutoSizeColumn((int) *col,setAsMin);
+ This->AutoSizeColumn(*col,setAsMin);
break;
}
case wxGrid_AutoSizeColumns: { // wxGrid::AutoSizeColumns
@@ -2738,7 +2747,7 @@ case wxGrid_AutoSizeRow: { // wxGrid::AutoSizeRow
} break;
}};
if(!This) throw wxe_badarg(0);
- This->AutoSizeRow((int) *row,setAsMin);
+ This->AutoSizeRow(*row,setAsMin);
break;
}
case wxGrid_AutoSizeRows: { // wxGrid::AutoSizeRows
@@ -2806,7 +2815,7 @@ case wxGrid_CellToRect_2: { // wxGrid::CellToRect
int * row = (int *) bp; bp += 4;
int * col = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxRect Result = This->CellToRect((int) *row,(int) *col);
+ wxRect Result = This->CellToRect(*row,*col);
rt.add(Result);
break;
}
@@ -2844,7 +2853,7 @@ selmode = *(wxGrid::wxGridSelectionModes *) bp; bp += 4;;
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->CreateGrid((int) *numRows,(int) *numCols,(wxGrid::wxGridSelectionModes) selmode);
+ bool Result = This->CreateGrid(*numRows,*numCols,selmode);
rt.addBool(Result);
break;
}
@@ -2972,7 +2981,7 @@ case wxGrid_EnableEditing: { // wxGrid::EnableEditing
wxGrid *This = (wxGrid *) getPtr(bp,memenv); bp += 4;
bool * edit = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->EnableEditing((bool) *edit);
+ This->EnableEditing(*edit);
break;
}
case wxGrid_EnableGridLines: { // wxGrid::EnableGridLines
@@ -3020,7 +3029,7 @@ case wxGrid_GetCellAlignment: { // wxGrid::GetCellAlignment
int * row = (int *) bp; bp += 4;
int * col = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->GetCellAlignment((int) *row,(int) *col,&horiz,&vert);
+ This->GetCellAlignment(*row,*col,&horiz,&vert);
rt.addInt(horiz);
rt.addInt(vert);
rt.addTupleCount(2);
@@ -3031,7 +3040,7 @@ case wxGrid_GetCellBackgroundColour: { // wxGrid::GetCellBackgroundColour
int * row = (int *) bp; bp += 4;
int * col = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxColour Result = This->GetCellBackgroundColour((int) *row,(int) *col);
+ wxColour Result = This->GetCellBackgroundColour(*row,*col);
rt.add(Result);
break;
}
@@ -3040,7 +3049,7 @@ case wxGrid_GetCellEditor: { // wxGrid::GetCellEditor
int * row = (int *) bp; bp += 4;
int * col = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxGridCellEditor * Result = (wxGridCellEditor*)This->GetCellEditor((int) *row,(int) *col);
+ wxGridCellEditor * Result = (wxGridCellEditor*)This->GetCellEditor(*row,*col);
rt.addRef(getRef((void *)Result,memenv), "wxGridCellEditor");
break;
}
@@ -3049,7 +3058,7 @@ case wxGrid_GetCellFont: { // wxGrid::GetCellFont
int * row = (int *) bp; bp += 4;
int * col = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxFont * Result = new wxFont(This->GetCellFont((int) *row,(int) *col)); newPtr((void *) Result,3, memenv);;
+ wxFont * Result = new wxFont(This->GetCellFont(*row,*col)); newPtr((void *) Result,3, memenv);;
rt.addRef(getRef((void *)Result,memenv), "wxFont");
break;
}
@@ -3058,7 +3067,7 @@ case wxGrid_GetCellRenderer: { // wxGrid::GetCellRenderer
int * row = (int *) bp; bp += 4;
int * col = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxGridCellRenderer * Result = (wxGridCellRenderer*)This->GetCellRenderer((int) *row,(int) *col);
+ wxGridCellRenderer * Result = (wxGridCellRenderer*)This->GetCellRenderer(*row,*col);
rt.addRef(getRef((void *)Result,memenv), "wxGridCellRenderer");
break;
}
@@ -3067,7 +3076,7 @@ case wxGrid_GetCellTextColour: { // wxGrid::GetCellTextColour
int * row = (int *) bp; bp += 4;
int * col = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxColour Result = This->GetCellTextColour((int) *row,(int) *col);
+ wxColour Result = This->GetCellTextColour(*row,*col);
rt.add(Result);
break;
}
@@ -3076,7 +3085,7 @@ case wxGrid_GetCellValue_2: { // wxGrid::GetCellValue
int * row = (int *) bp; bp += 4;
int * col = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxString Result = This->GetCellValue((int) *row,(int) *col);
+ wxString Result = This->GetCellValue(*row,*col);
rt.add(Result);
break;
}
@@ -3112,7 +3121,7 @@ case wxGrid_GetColLabelValue: { // wxGrid::GetColLabelValue
wxGrid *This = (wxGrid *) getPtr(bp,memenv); bp += 4;
int * col = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxString Result = This->GetColLabelValue((int) *col);
+ wxString Result = This->GetColLabelValue(*col);
rt.add(Result);
break;
}
@@ -3181,7 +3190,7 @@ case wxGrid_GetDefaultEditorForCell_2: { // wxGrid::GetDefaultEditorForCell
int * row = (int *) bp; bp += 4;
int * col = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxGridCellEditor * Result = (wxGridCellEditor*)This->GetDefaultEditorForCell((int) *row,(int) *col);
+ wxGridCellEditor * Result = (wxGridCellEditor*)This->GetDefaultEditorForCell(*row,*col);
rt.addRef(getRef((void *)Result,memenv), "wxGridCellEditor");
break;
}
@@ -3217,7 +3226,7 @@ case wxGrid_GetDefaultRendererForCell: { // wxGrid::GetDefaultRendererForCell
int * row = (int *) bp; bp += 4;
int * col = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxGridCellRenderer * Result = (wxGridCellRenderer*)This->GetDefaultRendererForCell((int) *row,(int) *col);
+ wxGridCellRenderer * Result = (wxGridCellRenderer*)This->GetDefaultRendererForCell(*row,*col);
rt.addRef(getRef((void *)Result,memenv), "wxGridCellRenderer");
break;
}
@@ -3313,7 +3322,7 @@ case wxGrid_GetOrCreateCellAttr: { // wxGrid::GetOrCreateCellAttr
int * row = (int *) bp; bp += 4;
int * col = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxGridCellAttr * Result = (wxGridCellAttr*)This->GetOrCreateCellAttr((int) *row,(int) *col);
+ wxGridCellAttr * Result = (wxGridCellAttr*)This->GetOrCreateCellAttr(*row,*col);
rt.addRef(getRef((void *)Result,memenv), "wxGridCellAttr");
break;
}
@@ -3346,7 +3355,7 @@ case wxGrid_GetRowLabelValue: { // wxGrid::GetRowLabelValue
wxGrid *This = (wxGrid *) getPtr(bp,memenv); bp += 4;
int * row = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxString Result = This->GetRowLabelValue((int) *row);
+ wxString Result = This->GetRowLabelValue(*row);
rt.add(Result);
break;
}
@@ -3354,7 +3363,7 @@ case wxGrid_GetRowSize: { // wxGrid::GetRowSize
wxGrid *This = (wxGrid *) getPtr(bp,memenv); bp += 4;
int * row = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->GetRowSize((int) *row);
+ int Result = This->GetRowSize(*row);
rt.addInt(Result);
break;
}
@@ -3541,7 +3550,7 @@ case wxGrid_IsInSelection_2: { // wxGrid::IsInSelection
int * row = (int *) bp; bp += 4;
int * col = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->IsInSelection((int) *row,(int) *col);
+ bool Result = This->IsInSelection(*row,*col);
rt.addBool(Result);
break;
}
@@ -3560,7 +3569,7 @@ case wxGrid_IsReadOnly: { // wxGrid::IsReadOnly
int * row = (int *) bp; bp += 4;
int * col = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->IsReadOnly((int) *row,(int) *col);
+ bool Result = This->IsReadOnly(*row,*col);
rt.addBool(Result);
break;
}
@@ -3583,7 +3592,7 @@ case wxGrid_IsVisible_3: { // wxGrid::IsVisible
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->IsVisible((int) *row,(int) *col,wholeCellVisible);
+ bool Result = This->IsVisible(*row,*col,wholeCellVisible);
rt.addBool(Result);
break;
}
@@ -3609,7 +3618,7 @@ case wxGrid_MakeCellVisible_2: { // wxGrid::MakeCellVisible
int * row = (int *) bp; bp += 4;
int * col = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->MakeCellVisible((int) *row,(int) *col);
+ This->MakeCellVisible(*row,*col);
break;
}
case wxGrid_MakeCellVisible_1: { // wxGrid::MakeCellVisible
@@ -3625,7 +3634,7 @@ case wxGrid_MoveCursorDown: { // wxGrid::MoveCursorDown
wxGrid *This = (wxGrid *) getPtr(bp,memenv); bp += 4;
bool * expandSelection = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->MoveCursorDown((bool) *expandSelection);
+ bool Result = This->MoveCursorDown(*expandSelection);
rt.addBool(Result);
break;
}
@@ -3633,7 +3642,7 @@ case wxGrid_MoveCursorLeft: { // wxGrid::MoveCursorLeft
wxGrid *This = (wxGrid *) getPtr(bp,memenv); bp += 4;
bool * expandSelection = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->MoveCursorLeft((bool) *expandSelection);
+ bool Result = This->MoveCursorLeft(*expandSelection);
rt.addBool(Result);
break;
}
@@ -3641,7 +3650,7 @@ case wxGrid_MoveCursorRight: { // wxGrid::MoveCursorRight
wxGrid *This = (wxGrid *) getPtr(bp,memenv); bp += 4;
bool * expandSelection = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->MoveCursorRight((bool) *expandSelection);
+ bool Result = This->MoveCursorRight(*expandSelection);
rt.addBool(Result);
break;
}
@@ -3649,7 +3658,7 @@ case wxGrid_MoveCursorUp: { // wxGrid::MoveCursorUp
wxGrid *This = (wxGrid *) getPtr(bp,memenv); bp += 4;
bool * expandSelection = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->MoveCursorUp((bool) *expandSelection);
+ bool Result = This->MoveCursorUp(*expandSelection);
rt.addBool(Result);
break;
}
@@ -3657,7 +3666,7 @@ case wxGrid_MoveCursorDownBlock: { // wxGrid::MoveCursorDownBlock
wxGrid *This = (wxGrid *) getPtr(bp,memenv); bp += 4;
bool * expandSelection = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->MoveCursorDownBlock((bool) *expandSelection);
+ bool Result = This->MoveCursorDownBlock(*expandSelection);
rt.addBool(Result);
break;
}
@@ -3665,7 +3674,7 @@ case wxGrid_MoveCursorLeftBlock: { // wxGrid::MoveCursorLeftBlock
wxGrid *This = (wxGrid *) getPtr(bp,memenv); bp += 4;
bool * expandSelection = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->MoveCursorLeftBlock((bool) *expandSelection);
+ bool Result = This->MoveCursorLeftBlock(*expandSelection);
rt.addBool(Result);
break;
}
@@ -3673,7 +3682,7 @@ case wxGrid_MoveCursorRightBlock: { // wxGrid::MoveCursorRightBlock
wxGrid *This = (wxGrid *) getPtr(bp,memenv); bp += 4;
bool * expandSelection = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->MoveCursorRightBlock((bool) *expandSelection);
+ bool Result = This->MoveCursorRightBlock(*expandSelection);
rt.addBool(Result);
break;
}
@@ -3681,7 +3690,7 @@ case wxGrid_MoveCursorUpBlock: { // wxGrid::MoveCursorUpBlock
wxGrid *This = (wxGrid *) getPtr(bp,memenv); bp += 4;
bool * expandSelection = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->MoveCursorUpBlock((bool) *expandSelection);
+ bool Result = This->MoveCursorUpBlock(*expandSelection);
rt.addBool(Result);
break;
}
@@ -3736,7 +3745,7 @@ case wxGrid_SelectBlock_5: { // wxGrid::SelectBlock
} break;
}};
if(!This) throw wxe_badarg(0);
- This->SelectBlock((int) *topRow,(int) *leftCol,(int) *bottomRow,(int) *rightCol,addToSelected);
+ This->SelectBlock(*topRow,*leftCol,*bottomRow,*rightCol,addToSelected);
break;
}
case wxGrid_SelectBlock_3: { // wxGrid::SelectBlock
@@ -3768,7 +3777,7 @@ case wxGrid_SelectCol: { // wxGrid::SelectCol
} break;
}};
if(!This) throw wxe_badarg(0);
- This->SelectCol((int) *col,addToSelected);
+ This->SelectCol(*col,addToSelected);
break;
}
case wxGrid_SelectRow: { // wxGrid::SelectRow
@@ -3781,7 +3790,7 @@ case wxGrid_SelectRow: { // wxGrid::SelectRow
} break;
}};
if(!This) throw wxe_badarg(0);
- This->SelectRow((int) *row,addToSelected);
+ This->SelectRow(*row,addToSelected);
break;
}
case wxGrid_SetCellAlignment_4: { // wxGrid::SetCellAlignment
@@ -3791,7 +3800,7 @@ case wxGrid_SetCellAlignment_4: { // wxGrid::SetCellAlignment
int * horiz = (int *) bp; bp += 4;
int * vert = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetCellAlignment((int) *row,(int) *col,(int) *horiz,(int) *vert);
+ This->SetCellAlignment(*row,*col,*horiz,*vert);
break;
}
case wxGrid_SetCellAlignment_3: { // wxGrid::SetCellAlignment
@@ -3800,14 +3809,14 @@ case wxGrid_SetCellAlignment_3: { // wxGrid::SetCellAlignment
int * row = (int *) bp; bp += 4;
int * col = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetCellAlignment((int) *align,(int) *row,(int) *col);
+ This->SetCellAlignment(*align,*row,*col);
break;
}
case wxGrid_SetCellAlignment_1: { // wxGrid::SetCellAlignment
wxGrid *This = (wxGrid *) getPtr(bp,memenv); bp += 4;
int * align = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetCellAlignment((int) *align);
+ This->SetCellAlignment(*align);
break;
}
case wxGrid_SetCellBackgroundColour_3_0: { // wxGrid::SetCellBackgroundColour
@@ -3820,7 +3829,7 @@ case wxGrid_SetCellBackgroundColour_3_0: { // wxGrid::SetCellBackgroundColour
int * valA = (int *) bp; bp += 4;
wxColour val = wxColour(*valR,*valG,*valB,*valA);
if(!This) throw wxe_badarg(0);
- This->SetCellBackgroundColour((int) *row,(int) *col,val);
+ This->SetCellBackgroundColour(*row,*col,val);
break;
}
case wxGrid_SetCellBackgroundColour_1: { // wxGrid::SetCellBackgroundColour
@@ -3844,7 +3853,7 @@ case wxGrid_SetCellBackgroundColour_3_1: { // wxGrid::SetCellBackgroundColour
int * row = (int *) bp; bp += 4;
int * col = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetCellBackgroundColour(colour,(int) *row,(int) *col);
+ This->SetCellBackgroundColour(colour,*row,*col);
break;
}
case wxGrid_SetCellEditor: { // wxGrid::SetCellEditor
@@ -3853,7 +3862,7 @@ case wxGrid_SetCellEditor: { // wxGrid::SetCellEditor
int * col = (int *) bp; bp += 4;
wxGridCellEditor *editor = (wxGridCellEditor *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetCellEditor((int) *row,(int) *col,editor);
+ This->SetCellEditor(*row,*col,editor);
break;
}
case wxGrid_SetCellFont: { // wxGrid::SetCellFont
@@ -3862,7 +3871,7 @@ case wxGrid_SetCellFont: { // wxGrid::SetCellFont
int * col = (int *) bp; bp += 4;
wxFont *val = (wxFont *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetCellFont((int) *row,(int) *col,*val);
+ This->SetCellFont(*row,*col,*val);
break;
}
case wxGrid_SetCellRenderer: { // wxGrid::SetCellRenderer
@@ -3871,7 +3880,7 @@ case wxGrid_SetCellRenderer: { // wxGrid::SetCellRenderer
int * col = (int *) bp; bp += 4;
wxGridCellRenderer *renderer = (wxGridCellRenderer *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetCellRenderer((int) *row,(int) *col,renderer);
+ This->SetCellRenderer(*row,*col,renderer);
break;
}
case wxGrid_SetCellTextColour_3_0: { // wxGrid::SetCellTextColour
@@ -3884,7 +3893,7 @@ case wxGrid_SetCellTextColour_3_0: { // wxGrid::SetCellTextColour
int * valA = (int *) bp; bp += 4;
wxColour val = wxColour(*valR,*valG,*valB,*valA);
if(!This) throw wxe_badarg(0);
- This->SetCellTextColour((int) *row,(int) *col,val);
+ This->SetCellTextColour(*row,*col,val);
break;
}
case wxGrid_SetCellTextColour_3_1: { // wxGrid::SetCellTextColour
@@ -3897,7 +3906,7 @@ case wxGrid_SetCellTextColour_3_1: { // wxGrid::SetCellTextColour
int * row = (int *) bp; bp += 4;
int * col = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetCellTextColour(val,(int) *row,(int) *col);
+ This->SetCellTextColour(val,*row,*col);
break;
}
case wxGrid_SetCellTextColour_1: { // wxGrid::SetCellTextColour
@@ -3919,7 +3928,7 @@ case wxGrid_SetCellValue_3_0: { // wxGrid::SetCellValue
wxString s = wxString(bp, wxConvUTF8);
bp += *sLen+((8-((0+ *sLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- This->SetCellValue((int) *row,(int) *col,s);
+ This->SetCellValue(*row,*col,s);
break;
}
case wxGrid_SetCellValue_2: { // wxGrid::SetCellValue
@@ -3942,7 +3951,7 @@ case wxGrid_SetCellValue_3_1: { // wxGrid::SetCellValue
int * row = (int *) bp; bp += 4;
int * col = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetCellValue(val,(int) *row,(int) *col);
+ This->SetCellValue(val,*row,*col);
break;
}
case wxGrid_SetColAttr: { // wxGrid::SetColAttr
@@ -3950,21 +3959,21 @@ case wxGrid_SetColAttr: { // wxGrid::SetColAttr
int * col = (int *) bp; bp += 4;
wxGridCellAttr *attr = (wxGridCellAttr *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetColAttr((int) *col,attr);
+ This->SetColAttr(*col,attr);
break;
}
case wxGrid_SetColFormatBool: { // wxGrid::SetColFormatBool
wxGrid *This = (wxGrid *) getPtr(bp,memenv); bp += 4;
int * col = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetColFormatBool((int) *col);
+ This->SetColFormatBool(*col);
break;
}
case wxGrid_SetColFormatNumber: { // wxGrid::SetColFormatNumber
wxGrid *This = (wxGrid *) getPtr(bp,memenv); bp += 4;
int * col = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetColFormatNumber((int) *col);
+ This->SetColFormatNumber(*col);
break;
}
case wxGrid_SetColFormatFloat: { // wxGrid::SetColFormatFloat
@@ -3981,7 +3990,7 @@ case wxGrid_SetColFormatFloat: { // wxGrid::SetColFormatFloat
} break;
}};
if(!This) throw wxe_badarg(0);
- This->SetColFormatFloat((int) *col,width,precision);
+ This->SetColFormatFloat(*col,width,precision);
break;
}
case wxGrid_SetColFormatCustom: { // wxGrid::SetColFormatCustom
@@ -3991,7 +4000,7 @@ case wxGrid_SetColFormatCustom: { // wxGrid::SetColFormatCustom
wxString typeName = wxString(bp, wxConvUTF8);
bp += *typeNameLen+((8-((4+ *typeNameLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- This->SetColFormatCustom((int) *col,typeName);
+ This->SetColFormatCustom(*col,typeName);
break;
}
case wxGrid_SetColLabelAlignment: { // wxGrid::SetColLabelAlignment
@@ -3999,14 +4008,14 @@ case wxGrid_SetColLabelAlignment: { // wxGrid::SetColLabelAlignment
int * horiz = (int *) bp; bp += 4;
int * vert = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetColLabelAlignment((int) *horiz,(int) *vert);
+ This->SetColLabelAlignment(*horiz,*vert);
break;
}
case wxGrid_SetColLabelSize: { // wxGrid::SetColLabelSize
wxGrid *This = (wxGrid *) getPtr(bp,memenv); bp += 4;
int * height = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetColLabelSize((int) *height);
+ This->SetColLabelSize(*height);
break;
}
case wxGrid_SetColLabelValue: { // wxGrid::SetColLabelValue
@@ -4016,7 +4025,7 @@ case wxGrid_SetColLabelValue: { // wxGrid::SetColLabelValue
wxString val = wxString(bp, wxConvUTF8);
bp += *valLen+((8-((4+ *valLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- This->SetColLabelValue((int) *col,val);
+ This->SetColLabelValue(*col,val);
break;
}
case wxGrid_SetColMinimalWidth: { // wxGrid::SetColMinimalWidth
@@ -4024,14 +4033,14 @@ case wxGrid_SetColMinimalWidth: { // wxGrid::SetColMinimalWidth
int * col = (int *) bp; bp += 4;
int * width = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetColMinimalWidth((int) *col,(int) *width);
+ This->SetColMinimalWidth(*col,*width);
break;
}
case wxGrid_SetColMinimalAcceptableWidth: { // wxGrid::SetColMinimalAcceptableWidth
wxGrid *This = (wxGrid *) getPtr(bp,memenv); bp += 4;
int * width = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetColMinimalAcceptableWidth((int) *width);
+ This->SetColMinimalAcceptableWidth(*width);
break;
}
case wxGrid_SetColSize: { // wxGrid::SetColSize
@@ -4039,7 +4048,7 @@ case wxGrid_SetColSize: { // wxGrid::SetColSize
int * col = (int *) bp; bp += 4;
int * width = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetColSize((int) *col,(int) *width);
+ This->SetColSize(*col,*width);
break;
}
case wxGrid_SetDefaultCellAlignment: { // wxGrid::SetDefaultCellAlignment
@@ -4047,7 +4056,7 @@ case wxGrid_SetDefaultCellAlignment: { // wxGrid::SetDefaultCellAlignment
int * horiz = (int *) bp; bp += 4;
int * vert = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetDefaultCellAlignment((int) *horiz,(int) *vert);
+ This->SetDefaultCellAlignment(*horiz,*vert);
break;
}
case wxGrid_SetDefaultCellBackgroundColour: { // wxGrid::SetDefaultCellBackgroundColour
@@ -4103,7 +4112,7 @@ case wxGrid_SetDefaultColSize: { // wxGrid::SetDefaultColSize
} break;
}};
if(!This) throw wxe_badarg(0);
- This->SetDefaultColSize((int) *width,resizeExistingCols);
+ This->SetDefaultColSize(*width,resizeExistingCols);
break;
}
case wxGrid_SetDefaultRowSize: { // wxGrid::SetDefaultRowSize
@@ -4116,7 +4125,7 @@ case wxGrid_SetDefaultRowSize: { // wxGrid::SetDefaultRowSize
} break;
}};
if(!This) throw wxe_badarg(0);
- This->SetDefaultRowSize((int) *height,resizeExistingRows);
+ This->SetDefaultRowSize(*height,resizeExistingRows);
break;
}
case wxGrid_SetGridCursor: { // wxGrid::SetGridCursor
@@ -4124,7 +4133,7 @@ case wxGrid_SetGridCursor: { // wxGrid::SetGridCursor
int * row = (int *) bp; bp += 4;
int * col = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetGridCursor((int) *row,(int) *col);
+ This->SetGridCursor(*row,*col);
break;
}
case wxGrid_SetGridLineColour: { // wxGrid::SetGridLineColour
@@ -4172,7 +4181,7 @@ case wxGrid_SetMargins: { // wxGrid::SetMargins
int * extraWidth = (int *) bp; bp += 4;
int * extraHeight = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetMargins((int) *extraWidth,(int) *extraHeight);
+ This->SetMargins(*extraWidth,*extraHeight);
break;
}
case wxGrid_SetReadOnly: { // wxGrid::SetReadOnly
@@ -4187,7 +4196,7 @@ case wxGrid_SetReadOnly: { // wxGrid::SetReadOnly
} break;
}};
if(!This) throw wxe_badarg(0);
- This->SetReadOnly((int) *row,(int) *col,isReadOnly);
+ This->SetReadOnly(*row,*col,isReadOnly);
break;
}
case wxGrid_SetRowAttr: { // wxGrid::SetRowAttr
@@ -4195,7 +4204,7 @@ case wxGrid_SetRowAttr: { // wxGrid::SetRowAttr
int * row = (int *) bp; bp += 4;
wxGridCellAttr *attr = (wxGridCellAttr *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetRowAttr((int) *row,attr);
+ This->SetRowAttr(*row,attr);
break;
}
case wxGrid_SetRowLabelAlignment: { // wxGrid::SetRowLabelAlignment
@@ -4203,14 +4212,14 @@ case wxGrid_SetRowLabelAlignment: { // wxGrid::SetRowLabelAlignment
int * horiz = (int *) bp; bp += 4;
int * vert = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetRowLabelAlignment((int) *horiz,(int) *vert);
+ This->SetRowLabelAlignment(*horiz,*vert);
break;
}
case wxGrid_SetRowLabelSize: { // wxGrid::SetRowLabelSize
wxGrid *This = (wxGrid *) getPtr(bp,memenv); bp += 4;
int * width = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetRowLabelSize((int) *width);
+ This->SetRowLabelSize(*width);
break;
}
case wxGrid_SetRowLabelValue: { // wxGrid::SetRowLabelValue
@@ -4220,7 +4229,7 @@ case wxGrid_SetRowLabelValue: { // wxGrid::SetRowLabelValue
wxString val = wxString(bp, wxConvUTF8);
bp += *valLen+((8-((4+ *valLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- This->SetRowLabelValue((int) *row,val);
+ This->SetRowLabelValue(*row,val);
break;
}
case wxGrid_SetRowMinimalHeight: { // wxGrid::SetRowMinimalHeight
@@ -4228,14 +4237,14 @@ case wxGrid_SetRowMinimalHeight: { // wxGrid::SetRowMinimalHeight
int * row = (int *) bp; bp += 4;
int * width = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetRowMinimalHeight((int) *row,(int) *width);
+ This->SetRowMinimalHeight(*row,*width);
break;
}
case wxGrid_SetRowMinimalAcceptableHeight: { // wxGrid::SetRowMinimalAcceptableHeight
wxGrid *This = (wxGrid *) getPtr(bp,memenv); bp += 4;
int * width = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetRowMinimalAcceptableHeight((int) *width);
+ This->SetRowMinimalAcceptableHeight(*width);
break;
}
case wxGrid_SetRowSize: { // wxGrid::SetRowSize
@@ -4243,21 +4252,21 @@ case wxGrid_SetRowSize: { // wxGrid::SetRowSize
int * row = (int *) bp; bp += 4;
int * height = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetRowSize((int) *row,(int) *height);
+ This->SetRowSize(*row,*height);
break;
}
case wxGrid_SetScrollLineX: { // wxGrid::SetScrollLineX
wxGrid *This = (wxGrid *) getPtr(bp,memenv); bp += 4;
int * x = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetScrollLineX((int) *x);
+ This->SetScrollLineX(*x);
break;
}
case wxGrid_SetScrollLineY: { // wxGrid::SetScrollLineY
wxGrid *This = (wxGrid *) getPtr(bp,memenv); bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetScrollLineY((int) *y);
+ This->SetScrollLineY(*y);
break;
}
case wxGrid_SetSelectionBackground: { // wxGrid::SetSelectionBackground
@@ -4286,7 +4295,7 @@ case wxGrid_SetSelectionMode: { // wxGrid::SetSelectionMode
wxGrid *This = (wxGrid *) getPtr(bp,memenv); bp += 4;
wxGrid::wxGridSelectionModes selmode = *(wxGrid::wxGridSelectionModes *) bp; bp += 4;;
if(!This) throw wxe_badarg(0);
- This->SetSelectionMode((wxGrid::wxGridSelectionModes) selmode);
+ This->SetSelectionMode(selmode);
break;
}
case wxGrid_ShowCellEditControl: { // wxGrid::ShowCellEditControl
@@ -4305,7 +4314,7 @@ case wxGrid_XToCol: { // wxGrid::XToCol
} break;
}};
if(!This) throw wxe_badarg(0);
- int Result = This->XToCol((int) *x,clipToMinMax);
+ int Result = This->XToCol(*x,clipToMinMax);
rt.addInt(Result);
break;
}
@@ -4313,7 +4322,7 @@ case wxGrid_XToEdgeOfCol: { // wxGrid::XToEdgeOfCol
wxGrid *This = (wxGrid *) getPtr(bp,memenv); bp += 4;
int * x = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->XToEdgeOfCol((int) *x);
+ int Result = This->XToEdgeOfCol(*x);
rt.addInt(Result);
break;
}
@@ -4321,7 +4330,7 @@ case wxGrid_YToEdgeOfRow: { // wxGrid::YToEdgeOfRow
wxGrid *This = (wxGrid *) getPtr(bp,memenv); bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->YToEdgeOfRow((int) *y);
+ int Result = This->YToEdgeOfRow(*y);
rt.addInt(Result);
break;
}
@@ -4329,7 +4338,7 @@ case wxGrid_YToRow: { // wxGrid::YToRow
wxGrid *This = (wxGrid *) getPtr(bp,memenv); bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->YToRow((int) *y);
+ int Result = This->YToRow(*y);
rt.addInt(Result);
break;
}
@@ -4347,7 +4356,7 @@ case wxGridCellRenderer_Draw: { // wxGridCellRenderer::Draw
int * col = (int *) bp; bp += 4;
bool * isSelected = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->Draw(*grid,*attr,*dc,rect,(int) *row,(int) *col,(bool) *isSelected);
+ This->Draw(*grid,*attr,*dc,rect,*row,*col,*isSelected);
break;
}
case wxGridCellRenderer_GetBestSize: { // wxGridCellRenderer::GetBestSize
@@ -4358,7 +4367,7 @@ case wxGridCellRenderer_GetBestSize: { // wxGridCellRenderer::GetBestSize
int * row = (int *) bp; bp += 4;
int * col = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxSize Result = This->GetBestSize(*grid,*attr,*dc,(int) *row,(int) *col);
+ wxSize Result = This->GetBestSize(*grid,*attr,*dc,*row,*col);
rt.add(Result);
break;
}
@@ -4368,7 +4377,7 @@ case wxGridCellEditor_Create: { // wxGridCellEditor::Create
int * id = (int *) bp; bp += 4;
wxEvtHandler *evtHandler = (wxEvtHandler *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- This->Create(parent,(wxWindowID) *id,evtHandler);
+ This->Create(parent,*id,evtHandler);
break;
}
case wxGridCellEditor_IsCreated: { // wxGridCellEditor::IsCreated
@@ -4399,9 +4408,10 @@ attr = (wxGridCellAttr *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- This->Show((bool) *show,attr);
+ This->Show(*show,attr);
break;
}
+#if !wxCHECK_VERSION(2,9,0)
case wxGridCellEditor_PaintBackground: { // wxGridCellEditor::PaintBackground
wxGridCellEditor *This = (wxGridCellEditor *) getPtr(bp,memenv); bp += 4;
int * rectCellX = (int *) bp; bp += 4;
@@ -4414,25 +4424,28 @@ case wxGridCellEditor_PaintBackground: { // wxGridCellEditor::PaintBackground
This->PaintBackground(rectCell,attr);
break;
}
+#endif
case wxGridCellEditor_BeginEdit: { // wxGridCellEditor::BeginEdit
wxGridCellEditor *This = (wxGridCellEditor *) getPtr(bp,memenv); bp += 4;
int * row = (int *) bp; bp += 4;
int * col = (int *) bp; bp += 4;
wxGrid *grid = (wxGrid *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- This->BeginEdit((int) *row,(int) *col,grid);
+ This->BeginEdit(*row,*col,grid);
break;
}
+#if !wxCHECK_VERSION(2,9,0)
case wxGridCellEditor_EndEdit: { // wxGridCellEditor::EndEdit
wxGridCellEditor *This = (wxGridCellEditor *) getPtr(bp,memenv); bp += 4;
int * row = (int *) bp; bp += 4;
int * col = (int *) bp; bp += 4;
wxGrid *grid = (wxGrid *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->EndEdit((int) *row,(int) *col,grid);
+ bool Result = This->EndEdit(*row,*col,grid);
rt.addBool(Result);
break;
}
+#endif
case wxGridCellEditor_Reset: { // wxGridCellEditor::Reset
wxGridCellEditor *This = (wxGridCellEditor *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
@@ -4552,14 +4565,14 @@ case wxGridCellFloatRenderer_SetPrecision: { // wxGridCellFloatRenderer::SetPrec
wxGridCellFloatRenderer *This = (wxGridCellFloatRenderer *) getPtr(bp,memenv); bp += 4;
int * precision = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetPrecision((int) *precision);
+ This->SetPrecision(*precision);
break;
}
case wxGridCellFloatRenderer_SetWidth: { // wxGridCellFloatRenderer::SetWidth
wxGridCellFloatRenderer *This = (wxGridCellFloatRenderer *) getPtr(bp,memenv); bp += 4;
int * width = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetWidth((int) *width);
+ This->SetWidth(*width);
break;
}
case wxGridCellFloatRenderer_destroy: { // wxGridCellFloatRenderer::destroy
@@ -4753,7 +4766,7 @@ case wxGridCellAttr_SetAlignment: { // wxGridCellAttr::SetAlignment
int * hAlign = (int *) bp; bp += 4;
int * vAlign = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetAlignment((int) *hAlign,(int) *vAlign);
+ This->SetAlignment(*hAlign,*vAlign);
break;
}
case wxGridCellAttr_SetReadOnly: { // wxGridCellAttr::SetReadOnly
@@ -4863,7 +4876,7 @@ case wxGridCellAttr_GetRenderer: { // wxGridCellAttr::GetRenderer
int * row = (int *) bp; bp += 4;
int * col = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxGridCellRenderer * Result = (wxGridCellRenderer*)This->GetRenderer(grid,(int) *row,(int) *col);
+ wxGridCellRenderer * Result = (wxGridCellRenderer*)This->GetRenderer(grid,*row,*col);
rt.addRef(getRef((void *)Result,memenv), "wxGridCellRenderer");
break;
}
@@ -4873,7 +4886,7 @@ case wxGridCellAttr_GetEditor: { // wxGridCellAttr::GetEditor
int * row = (int *) bp; bp += 4;
int * col = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxGridCellEditor * Result = (wxGridCellEditor*)This->GetEditor(grid,(int) *row,(int) *col);
+ wxGridCellEditor * Result = (wxGridCellEditor*)This->GetEditor(grid,*row,*col);
rt.addRef(getRef((void *)Result,memenv), "wxGridCellEditor");
break;
}
@@ -4892,7 +4905,7 @@ case wxGridCellAttr_SetDefAttr: { // wxGridCellAttr::SetDefAttr
break;
}
case wxDC_Blit: { // wxDC::Blit
- int rop=wxCOPY;
+ wxRasterOperationMode rop=wxCOPY;
bool useMask=false;
wxPoint srcPtMask= wxDefaultPosition;
wxDC *This = (wxDC *) getPtr(bp,memenv); bp += 4;
@@ -4908,7 +4921,7 @@ case wxDC_Blit: { // wxDC::Blit
wxPoint srcPt = wxPoint(*srcPtX,*srcPtY);
while( * (int*) bp) { switch (* (int*) bp) {
case 1: {bp += 4;
- rop = (int)*(int *) bp; bp += 4;
+rop = *(wxRasterOperationMode *) bp; bp += 4;;
} break;
case 2: {bp += 4;
useMask = *(bool *) bp; bp += 4;
@@ -4930,7 +4943,7 @@ case wxDC_CalcBoundingBox: { // wxDC::CalcBoundingBox
int * x = (int *) bp; bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->CalcBoundingBox((wxCoord) *x,(wxCoord) *y);
+ This->CalcBoundingBox(*x,*y);
break;
}
case wxDC_Clear: { // wxDC::Clear
@@ -4939,12 +4952,14 @@ case wxDC_Clear: { // wxDC::Clear
This->Clear();
break;
}
+#if !wxCHECK_VERSION(2,9,0)
case wxDC_ComputeScaleAndOrigin: { // wxDC::ComputeScaleAndOrigin
wxDC *This = (wxDC *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
This->ComputeScaleAndOrigin();
break;
}
+#endif
case wxDC_CrossHair: { // wxDC::CrossHair
wxDC *This = (wxDC *) getPtr(bp,memenv); bp += 4;
int * ptX = (int *) bp; bp += 4;
@@ -4964,7 +4979,7 @@ case wxDC_DeviceToLogicalX: { // wxDC::DeviceToLogicalX
wxDC *This = (wxDC *) getPtr(bp,memenv); bp += 4;
int * x = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxCoord Result = This->DeviceToLogicalX((wxCoord) *x);
+ wxCoord Result = This->DeviceToLogicalX(*x);
rt.addInt(Result);
break;
}
@@ -4972,7 +4987,7 @@ case wxDC_DeviceToLogicalXRel: { // wxDC::DeviceToLogicalXRel
wxDC *This = (wxDC *) getPtr(bp,memenv); bp += 4;
int * x = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxCoord Result = This->DeviceToLogicalXRel((wxCoord) *x);
+ wxCoord Result = This->DeviceToLogicalXRel(*x);
rt.addInt(Result);
break;
}
@@ -4980,7 +4995,7 @@ case wxDC_DeviceToLogicalY: { // wxDC::DeviceToLogicalY
wxDC *This = (wxDC *) getPtr(bp,memenv); bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxCoord Result = This->DeviceToLogicalY((wxCoord) *y);
+ wxCoord Result = This->DeviceToLogicalY(*y);
rt.addInt(Result);
break;
}
@@ -4988,7 +5003,7 @@ case wxDC_DeviceToLogicalYRel: { // wxDC::DeviceToLogicalYRel
wxDC *This = (wxDC *) getPtr(bp,memenv); bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxCoord Result = This->DeviceToLogicalYRel((wxCoord) *y);
+ wxCoord Result = This->DeviceToLogicalYRel(*y);
rt.addInt(Result);
break;
}
@@ -5041,7 +5056,7 @@ case wxDC_DrawCircle: { // wxDC::DrawCircle
wxPoint pt = wxPoint(*ptX,*ptY);
int * radius = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->DrawCircle(pt,(wxCoord) *radius);
+ This->DrawCircle(pt,*radius);
break;
}
case wxDC_DrawEllipse_2: { // wxDC::DrawEllipse
@@ -5079,7 +5094,7 @@ case wxDC_DrawEllipticArc: { // wxDC::DrawEllipticArc
double * sa = (double *) bp; bp += 8;
double * ea = (double *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->DrawEllipticArc(pt,sz,(double) *sa,(double) *ea);
+ This->DrawEllipticArc(pt,sz,*sa,*ea);
break;
}
case wxDC_DrawIcon: { // wxDC::DrawIcon
@@ -5155,7 +5170,7 @@ case wxDC_DrawLines: { // wxDC::DrawLines
case wxDC_DrawPolygon: { // wxDC::DrawPolygon
wxCoord xoffset=0;
wxCoord yoffset=0;
- int fillStyle=wxODDEVEN_RULE;
+ wxPolygonFillMode fillStyle=wxODDEVEN_RULE;
wxDC *This = (wxDC *) getPtr(bp,memenv); bp += 4;
int * pointsLen = (int *) bp; bp += 4;
wxPoint *points;
@@ -5172,7 +5187,7 @@ case wxDC_DrawPolygon: { // wxDC::DrawPolygon
yoffset = (wxCoord)*(int *) bp; bp += 4;
} break;
case 3: {bp += 4;
- fillStyle = (int)*(int *) bp; bp += 4;
+fillStyle = *(wxPolygonFillMode *) bp; bp += 4;;
} break;
}};
if(!This) throw wxe_badarg(0);
@@ -5222,7 +5237,7 @@ case wxDC_DrawRotatedText: { // wxDC::DrawRotatedText
wxPoint pt = wxPoint(*ptX,*ptY);
double * angle = (double *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->DrawRotatedText(text,pt,(double) *angle);
+ This->DrawRotatedText(text,pt,*angle);
break;
}
case wxDC_DrawRoundedRectangle_3: { // wxDC::DrawRoundedRectangle
@@ -5236,7 +5251,7 @@ case wxDC_DrawRoundedRectangle_3: { // wxDC::DrawRoundedRectangle
bp += 4; /* Align */
double * radius = (double *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->DrawRoundedRectangle(pt,sz,(double) *radius);
+ This->DrawRoundedRectangle(pt,sz,*radius);
break;
}
case wxDC_DrawRoundedRectangle_2: { // wxDC::DrawRoundedRectangle
@@ -5249,7 +5264,7 @@ case wxDC_DrawRoundedRectangle_2: { // wxDC::DrawRoundedRectangle
bp += 4; /* Align */
double * radius = (double *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->DrawRoundedRectangle(r,(double) *radius);
+ This->DrawRoundedRectangle(r,*radius);
break;
}
case wxDC_DrawText: { // wxDC::DrawText
@@ -5277,7 +5292,7 @@ case wxDC_EndPage: { // wxDC::EndPage
break;
}
case wxDC_FloodFill: { // wxDC::FloodFill
- int style=wxFLOOD_SURFACE;
+ wxFloodFillStyle style=wxFLOOD_SURFACE;
wxDC *This = (wxDC *) getPtr(bp,memenv); bp += 4;
int * ptX = (int *) bp; bp += 4;
int * ptY = (int *) bp; bp += 4;
@@ -5290,7 +5305,7 @@ case wxDC_FloodFill: { // wxDC::FloodFill
bp += 4; /* Align */
while( * (int*) bp) { switch (* (int*) bp) {
case 1: {bp += 4;
- style = (int)*(int *) bp; bp += 4;
+style = *(wxFloodFillStyle *) bp; bp += 4;;
} break;
}};
if(!This) throw wxe_badarg(0);
@@ -5591,14 +5606,14 @@ nDirection = *(wxDirection *) bp; bp += 4;;
} break;
}};
if(!This) throw wxe_badarg(0);
- This->GradientFillLinear(rect,initialColour,destColour,(wxDirection) nDirection);
+ This->GradientFillLinear(rect,initialColour,destColour,nDirection);
break;
}
case wxDC_LogicalToDeviceX: { // wxDC::LogicalToDeviceX
wxDC *This = (wxDC *) getPtr(bp,memenv); bp += 4;
int * x = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxCoord Result = This->LogicalToDeviceX((wxCoord) *x);
+ wxCoord Result = This->LogicalToDeviceX(*x);
rt.addInt(Result);
break;
}
@@ -5606,7 +5621,7 @@ case wxDC_LogicalToDeviceXRel: { // wxDC::LogicalToDeviceXRel
wxDC *This = (wxDC *) getPtr(bp,memenv); bp += 4;
int * x = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxCoord Result = This->LogicalToDeviceXRel((wxCoord) *x);
+ wxCoord Result = This->LogicalToDeviceXRel(*x);
rt.addInt(Result);
break;
}
@@ -5614,7 +5629,7 @@ case wxDC_LogicalToDeviceY: { // wxDC::LogicalToDeviceY
wxDC *This = (wxDC *) getPtr(bp,memenv); bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxCoord Result = This->LogicalToDeviceY((wxCoord) *y);
+ wxCoord Result = This->LogicalToDeviceY(*y);
rt.addInt(Result);
break;
}
@@ -5622,7 +5637,7 @@ case wxDC_LogicalToDeviceYRel: { // wxDC::LogicalToDeviceYRel
wxDC *This = (wxDC *) getPtr(bp,memenv); bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxCoord Result = This->LogicalToDeviceYRel((wxCoord) *y);
+ wxCoord Result = This->LogicalToDeviceYRel(*y);
rt.addInt(Result);
break;
}
@@ -5672,7 +5687,7 @@ case wxDC_SetAxisOrientation: { // wxDC::SetAxisOrientation
bool * xLeftRight = (bool *) bp; bp += 4;
bool * yBottomUp = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetAxisOrientation((bool) *xLeftRight,(bool) *yBottomUp);
+ This->SetAxisOrientation(*xLeftRight,*yBottomUp);
break;
}
case wxDC_SetBackground: { // wxDC::SetBackground
@@ -5686,7 +5701,7 @@ case wxDC_SetBackgroundMode: { // wxDC::SetBackgroundMode
wxDC *This = (wxDC *) getPtr(bp,memenv); bp += 4;
int * mode = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetBackgroundMode((int) *mode);
+ This->SetBackgroundMode(*mode);
break;
}
case wxDC_SetBrush: { // wxDC::SetBrush
@@ -5731,7 +5746,7 @@ case wxDC_SetDeviceOrigin: { // wxDC::SetDeviceOrigin
int * x = (int *) bp; bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetDeviceOrigin((wxCoord) *x,(wxCoord) *y);
+ This->SetDeviceOrigin(*x,*y);
break;
}
case wxDC_SetFont: { // wxDC::SetFont
@@ -5745,21 +5760,21 @@ case wxDC_SetLayoutDirection: { // wxDC::SetLayoutDirection
wxDC *This = (wxDC *) getPtr(bp,memenv); bp += 4;
wxLayoutDirection dir = *(wxLayoutDirection *) bp; bp += 4;;
if(!This) throw wxe_badarg(0);
- This->SetLayoutDirection((wxLayoutDirection) dir);
+ This->SetLayoutDirection(dir);
break;
}
case wxDC_SetLogicalFunction: { // wxDC::SetLogicalFunction
wxDC *This = (wxDC *) getPtr(bp,memenv); bp += 4;
- int * function = (int *) bp; bp += 4;
+ wxRasterOperationMode function = *(wxRasterOperationMode *) bp; bp += 4;;
if(!This) throw wxe_badarg(0);
- This->SetLogicalFunction((int) *function);
+ This->SetLogicalFunction(function);
break;
}
case wxDC_SetMapMode: { // wxDC::SetMapMode
wxDC *This = (wxDC *) getPtr(bp,memenv); bp += 4;
- int * mode = (int *) bp; bp += 4;
+ wxMappingMode mode = *(wxMappingMode *) bp; bp += 4;;
if(!This) throw wxe_badarg(0);
- This->SetMapMode((int) *mode);
+ This->SetMapMode(mode);
break;
}
case wxDC_SetPalette: { // wxDC::SetPalette
@@ -5804,7 +5819,7 @@ case wxDC_SetUserScale: { // wxDC::SetUserScale
double * x = (double *) bp; bp += 8;
double * y = (double *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->SetUserScale((double) *x,(double) *y);
+ This->SetUserScale(*x,*y);
break;
}
case wxDC_StartDoc: { // wxDC::StartDoc
@@ -5826,7 +5841,7 @@ case wxDC_StartPage: { // wxDC::StartPage
case wxMirrorDC_new: { // wxMirrorDC::wxMirrorDC
wxDC *dc = (wxDC *) getPtr(bp,memenv); bp += 4;
bool * mirror = (bool *) bp; bp += 4;
- wxMirrorDC * Result = new EwxMirrorDC(*dc,(bool) *mirror);
+ wxMirrorDC * Result = new EwxMirrorDC(*dc,*mirror);
newPtr((void *) Result, 1, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxMirrorDC");
break;
@@ -5850,22 +5865,28 @@ case wxPostScriptDC_new_1: { // wxPostScriptDC::wxPostScriptDC
rt.addRef(getRef((void *)Result,memenv), "wxPostScriptDC");
break;
}
+#if !wxCHECK_VERSION(2,9,0)
case wxPostScriptDC_SetResolution: { // wxPostScriptDC::SetResolution
int * ppi = (int *) bp; bp += 4;
- wxPostScriptDC::SetResolution((int) *ppi);
+ wxPostScriptDC::SetResolution(*ppi);
break;
}
+#endif
+#if !wxCHECK_VERSION(2,9,0)
case wxPostScriptDC_GetResolution: { // wxPostScriptDC::GetResolution
int Result = wxPostScriptDC::GetResolution();
rt.addInt(Result);
break;
}
+#endif
+#if !wxCHECK_VERSION(2,9,0)
case wxWindowDC_new_0: { // wxWindowDC::wxWindowDC
wxWindowDC * Result = new EwxWindowDC();
newPtr((void *) Result, 1, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxWindowDC");
break;
}
+#endif
case wxWindowDC_new_1: { // wxWindowDC::wxWindowDC
wxWindow *win = (wxWindow *) getPtr(bp,memenv); bp += 4;
wxWindowDC * Result = new EwxWindowDC(win);
@@ -5873,12 +5894,14 @@ case wxWindowDC_new_1: { // wxWindowDC::wxWindowDC
rt.addRef(getRef((void *)Result,memenv), "wxWindowDC");
break;
}
+#if !wxCHECK_VERSION(2,9,0)
case wxClientDC_new_0: { // wxClientDC::wxClientDC
wxClientDC * Result = new EwxClientDC();
newPtr((void *) Result, 1, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxClientDC");
break;
}
+#endif
case wxClientDC_new_1: { // wxClientDC::wxClientDC
wxWindow *win = (wxWindow *) getPtr(bp,memenv); bp += 4;
wxClientDC * Result = new EwxClientDC(win);
@@ -5886,12 +5909,14 @@ case wxClientDC_new_1: { // wxClientDC::wxClientDC
rt.addRef(getRef((void *)Result,memenv), "wxClientDC");
break;
}
+#if !wxCHECK_VERSION(2,9,0)
case wxPaintDC_new_0: { // wxPaintDC::wxPaintDC
wxPaintDC * Result = new EwxPaintDC();
newPtr((void *) Result, 1, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxPaintDC");
break;
}
+#endif
case wxPaintDC_new_1: { // wxPaintDC::wxPaintDC
wxWindow *win = (wxWindow *) getPtr(bp,memenv); bp += 4;
wxPaintDC * Result = new EwxPaintDC(win);
@@ -6085,6 +6110,7 @@ case wxGraphicsContext_CreateBrush: { // wxGraphicsContext::CreateBrush
rt.addRef(getRef((void *)Result,memenv), "wxGraphicsBrush");
break;
}
+#if !wxCHECK_VERSION(2,9,0)
case wxGraphicsContext_CreateRadialGradientBrush: { // wxGraphicsContext::CreateRadialGradientBrush
wxGraphicsContext *This = (wxGraphicsContext *) getPtr(bp,memenv); bp += 4;
bp += 4; /* Align */
@@ -6104,10 +6130,12 @@ case wxGraphicsContext_CreateRadialGradientBrush: { // wxGraphicsContext::Create
int * cColorA = (int *) bp; bp += 4;
wxColour cColor = wxColour(*cColorR,*cColorG,*cColorB,*cColorA);
if(!This) throw wxe_badarg(0);
- wxGraphicsBrush * Result = new wxGraphicsBrush(This->CreateRadialGradientBrush((wxDouble) *xo,(wxDouble) *yo,(wxDouble) *xc,(wxDouble) *yc,(wxDouble) *radius,oColor,cColor)); newPtr((void *) Result,3, memenv);;
+ wxGraphicsBrush * Result = new wxGraphicsBrush(This->CreateRadialGradientBrush(*xo,*yo,*xc,*yc,*radius,oColor,cColor)); newPtr((void *) Result,3, memenv);;
rt.addRef(getRef((void *)Result,memenv), "wxGraphicsBrush");
break;
}
+#endif
+#if !wxCHECK_VERSION(2,9,0)
case wxGraphicsContext_CreateLinearGradientBrush: { // wxGraphicsContext::CreateLinearGradientBrush
wxGraphicsContext *This = (wxGraphicsContext *) getPtr(bp,memenv); bp += 4;
bp += 4; /* Align */
@@ -6126,10 +6154,11 @@ case wxGraphicsContext_CreateLinearGradientBrush: { // wxGraphicsContext::Create
int * c2A = (int *) bp; bp += 4;
wxColour c2 = wxColour(*c2R,*c2G,*c2B,*c2A);
if(!This) throw wxe_badarg(0);
- wxGraphicsBrush * Result = new wxGraphicsBrush(This->CreateLinearGradientBrush((wxDouble) *x1,(wxDouble) *y1,(wxDouble) *x2,(wxDouble) *y2,c1,c2)); newPtr((void *) Result,3, memenv);;
+ wxGraphicsBrush * Result = new wxGraphicsBrush(This->CreateLinearGradientBrush(*x1,*y1,*x2,*y2,c1,c2)); newPtr((void *) Result,3, memenv);;
rt.addRef(getRef((void *)Result,memenv), "wxGraphicsBrush");
break;
}
+#endif
case wxGraphicsContext_CreateFont: { // wxGraphicsContext::CreateFont
wxColour col= *wxBLACK;
wxGraphicsContext *This = (wxGraphicsContext *) getPtr(bp,memenv); bp += 4;
@@ -6211,7 +6240,7 @@ case wxGraphicsContext_Clip_4: { // wxGraphicsContext::Clip
wxDouble * w = (wxDouble *) bp; bp += 8;
wxDouble * h = (wxDouble *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->Clip((wxDouble) *x,(wxDouble) *y,(wxDouble) *w,(wxDouble) *h);
+ This->Clip(*x,*y,*w,*h);
break;
}
case wxGraphicsContext_ResetClip: { // wxGraphicsContext::ResetClip
@@ -6228,7 +6257,7 @@ case wxGraphicsContext_DrawBitmap: { // wxGraphicsContext::DrawBitmap
wxDouble * w = (wxDouble *) bp; bp += 8;
wxDouble * h = (wxDouble *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->DrawBitmap(*bmp,(wxDouble) *x,(wxDouble) *y,(wxDouble) *w,(wxDouble) *h);
+ This->DrawBitmap(*bmp,*x,*y,*w,*h);
break;
}
case wxGraphicsContext_DrawEllipse: { // wxGraphicsContext::DrawEllipse
@@ -6239,7 +6268,7 @@ case wxGraphicsContext_DrawEllipse: { // wxGraphicsContext::DrawEllipse
wxDouble * w = (wxDouble *) bp; bp += 8;
wxDouble * h = (wxDouble *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->DrawEllipse((wxDouble) *x,(wxDouble) *y,(wxDouble) *w,(wxDouble) *h);
+ This->DrawEllipse(*x,*y,*w,*h);
break;
}
case wxGraphicsContext_DrawIcon: { // wxGraphicsContext::DrawIcon
@@ -6250,11 +6279,11 @@ case wxGraphicsContext_DrawIcon: { // wxGraphicsContext::DrawIcon
wxDouble * w = (wxDouble *) bp; bp += 8;
wxDouble * h = (wxDouble *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->DrawIcon(*icon,(wxDouble) *x,(wxDouble) *y,(wxDouble) *w,(wxDouble) *h);
+ This->DrawIcon(*icon,*x,*y,*w,*h);
break;
}
case wxGraphicsContext_DrawLines: { // wxGraphicsContext::DrawLines
- int fillStyle=wxODDEVEN_RULE;
+ wxPolygonFillMode fillStyle=wxODDEVEN_RULE;
wxGraphicsContext *This = (wxGraphicsContext *) getPtr(bp,memenv); bp += 4;
int * pointsLen = (int *) bp; bp += 4;
wxPoint2DDouble *points;
@@ -6265,7 +6294,7 @@ case wxGraphicsContext_DrawLines: { // wxGraphicsContext::DrawLines
points[i] = wxPoint2DDouble(x,y);}
while( * (int*) bp) { switch (* (int*) bp) {
case 1: {bp += 4;
- fillStyle = (int)*(int *) bp; bp += 4;
+fillStyle = *(wxPolygonFillMode *) bp; bp += 4;;
} break;
}};
if(!This) throw wxe_badarg(0);
@@ -6274,12 +6303,12 @@ case wxGraphicsContext_DrawLines: { // wxGraphicsContext::DrawLines
break;
}
case wxGraphicsContext_DrawPath: { // wxGraphicsContext::DrawPath
- int fillStyle=wxODDEVEN_RULE;
+ wxPolygonFillMode fillStyle=wxODDEVEN_RULE;
wxGraphicsContext *This = (wxGraphicsContext *) getPtr(bp,memenv); bp += 4;
wxGraphicsPath *path = (wxGraphicsPath *) getPtr(bp,memenv); bp += 4;
while( * (int*) bp) { switch (* (int*) bp) {
case 1: {bp += 4;
- fillStyle = (int)*(int *) bp; bp += 4;
+fillStyle = *(wxPolygonFillMode *) bp; bp += 4;;
} break;
}};
if(!This) throw wxe_badarg(0);
@@ -6294,7 +6323,7 @@ case wxGraphicsContext_DrawRectangle: { // wxGraphicsContext::DrawRectangle
wxDouble * w = (wxDouble *) bp; bp += 8;
wxDouble * h = (wxDouble *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->DrawRectangle((wxDouble) *x,(wxDouble) *y,(wxDouble) *w,(wxDouble) *h);
+ This->DrawRectangle(*x,*y,*w,*h);
break;
}
case wxGraphicsContext_DrawRoundedRectangle: { // wxGraphicsContext::DrawRoundedRectangle
@@ -6306,7 +6335,7 @@ case wxGraphicsContext_DrawRoundedRectangle: { // wxGraphicsContext::DrawRounded
wxDouble * h = (wxDouble *) bp; bp += 8;
wxDouble * radius = (wxDouble *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->DrawRoundedRectangle((wxDouble) *x,(wxDouble) *y,(wxDouble) *w,(wxDouble) *h,(wxDouble) *radius);
+ This->DrawRoundedRectangle(*x,*y,*w,*h,*radius);
break;
}
case wxGraphicsContext_DrawText_3: { // wxGraphicsContext::DrawText
@@ -6317,7 +6346,7 @@ case wxGraphicsContext_DrawText_3: { // wxGraphicsContext::DrawText
wxDouble * x = (wxDouble *) bp; bp += 8;
wxDouble * y = (wxDouble *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->DrawText(str,(wxDouble) *x,(wxDouble) *y);
+ This->DrawText(str,*x,*y);
break;
}
case wxGraphicsContext_DrawText_4_0: { // wxGraphicsContext::DrawText
@@ -6329,7 +6358,7 @@ case wxGraphicsContext_DrawText_4_0: { // wxGraphicsContext::DrawText
wxDouble * y = (wxDouble *) bp; bp += 8;
wxDouble * angle = (wxDouble *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->DrawText(str,(wxDouble) *x,(wxDouble) *y,(wxDouble) *angle);
+ This->DrawText(str,*x,*y,*angle);
break;
}
case wxGraphicsContext_DrawText_4_1: { // wxGraphicsContext::DrawText
@@ -6341,7 +6370,7 @@ case wxGraphicsContext_DrawText_4_1: { // wxGraphicsContext::DrawText
wxDouble * y = (wxDouble *) bp; bp += 8;
wxGraphicsBrush *backgroundBrush = (wxGraphicsBrush *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- This->DrawText(str,(wxDouble) *x,(wxDouble) *y,*backgroundBrush);
+ This->DrawText(str,*x,*y,*backgroundBrush);
break;
}
case wxGraphicsContext_DrawText_5: { // wxGraphicsContext::DrawText
@@ -6354,16 +6383,16 @@ case wxGraphicsContext_DrawText_5: { // wxGraphicsContext::DrawText
wxDouble * angle = (wxDouble *) bp; bp += 8;
wxGraphicsBrush *backgroundBrush = (wxGraphicsBrush *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- This->DrawText(str,(wxDouble) *x,(wxDouble) *y,(wxDouble) *angle,*backgroundBrush);
+ This->DrawText(str,*x,*y,*angle,*backgroundBrush);
break;
}
case wxGraphicsContext_FillPath: { // wxGraphicsContext::FillPath
- int fillStyle=wxODDEVEN_RULE;
+ wxPolygonFillMode fillStyle=wxODDEVEN_RULE;
wxGraphicsContext *This = (wxGraphicsContext *) getPtr(bp,memenv); bp += 4;
wxGraphicsPath *path = (wxGraphicsPath *) getPtr(bp,memenv); bp += 4;
while( * (int*) bp) { switch (* (int*) bp) {
case 1: {bp += 4;
- fillStyle = (int)*(int *) bp; bp += 4;
+fillStyle = *(wxPolygonFillMode *) bp; bp += 4;;
} break;
}};
if(!This) throw wxe_badarg(0);
@@ -6411,7 +6440,7 @@ case wxGraphicsContext_Rotate: { // wxGraphicsContext::Rotate
bp += 4; /* Align */
wxDouble * angle = (wxDouble *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->Rotate((wxDouble) *angle);
+ This->Rotate(*angle);
break;
}
case wxGraphicsContext_Scale: { // wxGraphicsContext::Scale
@@ -6420,7 +6449,7 @@ case wxGraphicsContext_Scale: { // wxGraphicsContext::Scale
wxDouble * xScale = (wxDouble *) bp; bp += 8;
wxDouble * yScale = (wxDouble *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->Scale((wxDouble) *xScale,(wxDouble) *yScale);
+ This->Scale(*xScale,*yScale);
break;
}
case wxGraphicsContext_Translate: { // wxGraphicsContext::Translate
@@ -6429,7 +6458,7 @@ case wxGraphicsContext_Translate: { // wxGraphicsContext::Translate
wxDouble * dx = (wxDouble *) bp; bp += 8;
wxDouble * dy = (wxDouble *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->Translate((wxDouble) *dx,(wxDouble) *dy);
+ This->Translate(*dx,*dy);
break;
}
case wxGraphicsContext_GetTransform: { // wxGraphicsContext::GetTransform
@@ -6508,7 +6537,7 @@ case wxGraphicsContext_StrokeLine: { // wxGraphicsContext::StrokeLine
wxDouble * x2 = (wxDouble *) bp; bp += 8;
wxDouble * y2 = (wxDouble *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->StrokeLine((wxDouble) *x1,(wxDouble) *y1,(wxDouble) *x2,(wxDouble) *y2);
+ This->StrokeLine(*x1,*y1,*x2,*y2);
break;
}
case wxGraphicsContext_StrokeLines: { // wxGraphicsContext::StrokeLines
@@ -6579,7 +6608,7 @@ case wxGraphicsMatrix_Rotate: { // wxGraphicsMatrix::Rotate
bp += 4; /* Align */
wxDouble * angle = (wxDouble *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->Rotate((wxDouble) *angle);
+ This->Rotate(*angle);
break;
}
case wxGraphicsMatrix_Scale: { // wxGraphicsMatrix::Scale
@@ -6588,7 +6617,7 @@ case wxGraphicsMatrix_Scale: { // wxGraphicsMatrix::Scale
wxDouble * xScale = (wxDouble *) bp; bp += 8;
wxDouble * yScale = (wxDouble *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->Scale((wxDouble) *xScale,(wxDouble) *yScale);
+ This->Scale(*xScale,*yScale);
break;
}
case wxGraphicsMatrix_Translate: { // wxGraphicsMatrix::Translate
@@ -6597,7 +6626,7 @@ case wxGraphicsMatrix_Translate: { // wxGraphicsMatrix::Translate
wxDouble * dx = (wxDouble *) bp; bp += 8;
wxDouble * dy = (wxDouble *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->Translate((wxDouble) *dx,(wxDouble) *dy);
+ This->Translate(*dx,*dy);
break;
}
case wxGraphicsMatrix_Set: { // wxGraphicsMatrix::Set
@@ -6669,7 +6698,7 @@ case wxGraphicsPath_MoveToPoint_2: { // wxGraphicsPath::MoveToPoint
wxDouble * x = (wxDouble *) bp; bp += 8;
wxDouble * y = (wxDouble *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->MoveToPoint((wxDouble) *x,(wxDouble) *y);
+ This->MoveToPoint(*x,*y);
break;
}
case wxGraphicsPath_MoveToPoint_1: { // wxGraphicsPath::MoveToPoint
@@ -6692,7 +6721,7 @@ case wxGraphicsPath_AddArc_6: { // wxGraphicsPath::AddArc
wxDouble * endAngle = (wxDouble *) bp; bp += 8;
bool * clockwise = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->AddArc((wxDouble) *x,(wxDouble) *y,(wxDouble) *r,(wxDouble) *startAngle,(wxDouble) *endAngle,(bool) *clockwise);
+ This->AddArc(*x,*y,*r,*startAngle,*endAngle,*clockwise);
break;
}
case wxGraphicsPath_AddArc_5: { // wxGraphicsPath::AddArc
@@ -6706,7 +6735,7 @@ case wxGraphicsPath_AddArc_5: { // wxGraphicsPath::AddArc
wxDouble * endAngle = (wxDouble *) bp; bp += 8;
bool * clockwise = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->AddArc(c,(wxDouble) *r,(wxDouble) *startAngle,(wxDouble) *endAngle,(bool) *clockwise);
+ This->AddArc(c,*r,*startAngle,*endAngle,*clockwise);
break;
}
case wxGraphicsPath_AddArcToPoint: { // wxGraphicsPath::AddArcToPoint
@@ -6718,7 +6747,7 @@ case wxGraphicsPath_AddArcToPoint: { // wxGraphicsPath::AddArcToPoint
wxDouble * y2 = (wxDouble *) bp; bp += 8;
wxDouble * r = (wxDouble *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->AddArcToPoint((wxDouble) *x1,(wxDouble) *y1,(wxDouble) *x2,(wxDouble) *y2,(wxDouble) *r);
+ This->AddArcToPoint(*x1,*y1,*x2,*y2,*r);
break;
}
case wxGraphicsPath_AddCircle: { // wxGraphicsPath::AddCircle
@@ -6728,7 +6757,7 @@ case wxGraphicsPath_AddCircle: { // wxGraphicsPath::AddCircle
wxDouble * y = (wxDouble *) bp; bp += 8;
wxDouble * r = (wxDouble *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->AddCircle((wxDouble) *x,(wxDouble) *y,(wxDouble) *r);
+ This->AddCircle(*x,*y,*r);
break;
}
case wxGraphicsPath_AddCurveToPoint_6: { // wxGraphicsPath::AddCurveToPoint
@@ -6741,7 +6770,7 @@ case wxGraphicsPath_AddCurveToPoint_6: { // wxGraphicsPath::AddCurveToPoint
wxDouble * x = (wxDouble *) bp; bp += 8;
wxDouble * y = (wxDouble *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->AddCurveToPoint((wxDouble) *cx1,(wxDouble) *cy1,(wxDouble) *cx2,(wxDouble) *cy2,(wxDouble) *x,(wxDouble) *y);
+ This->AddCurveToPoint(*cx1,*cy1,*cx2,*cy2,*x,*y);
break;
}
case wxGraphicsPath_AddCurveToPoint_3: { // wxGraphicsPath::AddCurveToPoint
@@ -6768,7 +6797,7 @@ case wxGraphicsPath_AddEllipse: { // wxGraphicsPath::AddEllipse
wxDouble * w = (wxDouble *) bp; bp += 8;
wxDouble * h = (wxDouble *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->AddEllipse((wxDouble) *x,(wxDouble) *y,(wxDouble) *w,(wxDouble) *h);
+ This->AddEllipse(*x,*y,*w,*h);
break;
}
case wxGraphicsPath_AddLineToPoint_2: { // wxGraphicsPath::AddLineToPoint
@@ -6777,7 +6806,7 @@ case wxGraphicsPath_AddLineToPoint_2: { // wxGraphicsPath::AddLineToPoint
wxDouble * x = (wxDouble *) bp; bp += 8;
wxDouble * y = (wxDouble *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->AddLineToPoint((wxDouble) *x,(wxDouble) *y);
+ This->AddLineToPoint(*x,*y);
break;
}
case wxGraphicsPath_AddLineToPoint_1: { // wxGraphicsPath::AddLineToPoint
@@ -6805,7 +6834,7 @@ case wxGraphicsPath_AddQuadCurveToPoint: { // wxGraphicsPath::AddQuadCurveToPoin
wxDouble * x = (wxDouble *) bp; bp += 8;
wxDouble * y = (wxDouble *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->AddQuadCurveToPoint((wxDouble) *cx,(wxDouble) *cy,(wxDouble) *x,(wxDouble) *y);
+ This->AddQuadCurveToPoint(*cx,*cy,*x,*y);
break;
}
case wxGraphicsPath_AddRectangle: { // wxGraphicsPath::AddRectangle
@@ -6816,7 +6845,7 @@ case wxGraphicsPath_AddRectangle: { // wxGraphicsPath::AddRectangle
wxDouble * w = (wxDouble *) bp; bp += 8;
wxDouble * h = (wxDouble *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->AddRectangle((wxDouble) *x,(wxDouble) *y,(wxDouble) *w,(wxDouble) *h);
+ This->AddRectangle(*x,*y,*w,*h);
break;
}
case wxGraphicsPath_AddRoundedRectangle: { // wxGraphicsPath::AddRoundedRectangle
@@ -6828,7 +6857,7 @@ case wxGraphicsPath_AddRoundedRectangle: { // wxGraphicsPath::AddRoundedRectangl
wxDouble * h = (wxDouble *) bp; bp += 8;
wxDouble * radius = (wxDouble *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->AddRoundedRectangle((wxDouble) *x,(wxDouble) *y,(wxDouble) *w,(wxDouble) *h,(wxDouble) *radius);
+ This->AddRoundedRectangle(*x,*y,*w,*h,*radius);
break;
}
case wxGraphicsPath_CloseSubpath: { // wxGraphicsPath::CloseSubpath
@@ -6838,23 +6867,23 @@ case wxGraphicsPath_CloseSubpath: { // wxGraphicsPath::CloseSubpath
break;
}
case wxGraphicsPath_Contains_3: { // wxGraphicsPath::Contains
- int fillStyle=wxODDEVEN_RULE;
+ wxPolygonFillMode fillStyle=wxODDEVEN_RULE;
wxGraphicsPath *This = (wxGraphicsPath *) getPtr(bp,memenv); bp += 4;
bp += 4; /* Align */
wxDouble * x = (wxDouble *) bp; bp += 8;
wxDouble * y = (wxDouble *) bp; bp += 8;
while( * (int*) bp) { switch (* (int*) bp) {
case 1: {bp += 4;
- fillStyle = (int)*(int *) bp; bp += 4;
+fillStyle = *(wxPolygonFillMode *) bp; bp += 4;;
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Contains((wxDouble) *x,(wxDouble) *y,fillStyle);
+ bool Result = This->Contains(*x,*y,fillStyle);
rt.addBool(Result);
break;
}
case wxGraphicsPath_Contains_2: { // wxGraphicsPath::Contains
- int fillStyle=wxODDEVEN_RULE;
+ wxPolygonFillMode fillStyle=wxODDEVEN_RULE;
wxGraphicsPath *This = (wxGraphicsPath *) getPtr(bp,memenv); bp += 4;
bp += 4; /* Align */
wxDouble * cX = (wxDouble *) bp; bp += 8;
@@ -6862,7 +6891,7 @@ case wxGraphicsPath_Contains_2: { // wxGraphicsPath::Contains
wxPoint2DDouble c = wxPoint2DDouble(*cX,*cY);
while( * (int*) bp) { switch (* (int*) bp) {
case 1: {bp += 4;
- fillStyle = (int)*(int *) bp; bp += 4;
+fillStyle = *(wxPolygonFillMode *) bp; bp += 4;;
} break;
}};
if(!This) throw wxe_badarg(0);
@@ -6930,6 +6959,7 @@ case wxGraphicsRenderer_CreateBrush: { // wxGraphicsRenderer::CreateBrush
rt.addRef(getRef((void *)Result,memenv), "wxGraphicsBrush");
break;
}
+#if !wxCHECK_VERSION(2,9,0)
case wxGraphicsRenderer_CreateLinearGradientBrush: { // wxGraphicsRenderer::CreateLinearGradientBrush
wxGraphicsRenderer *This = (wxGraphicsRenderer *) getPtr(bp,memenv); bp += 4;
bp += 4; /* Align */
@@ -6948,10 +6978,12 @@ case wxGraphicsRenderer_CreateLinearGradientBrush: { // wxGraphicsRenderer::Crea
int * c2A = (int *) bp; bp += 4;
wxColour c2 = wxColour(*c2R,*c2G,*c2B,*c2A);
if(!This) throw wxe_badarg(0);
- wxGraphicsBrush * Result = new wxGraphicsBrush(This->CreateLinearGradientBrush((wxDouble) *x1,(wxDouble) *y1,(wxDouble) *x2,(wxDouble) *y2,c1,c2)); newPtr((void *) Result,3, memenv);;
+ wxGraphicsBrush * Result = new wxGraphicsBrush(This->CreateLinearGradientBrush(*x1,*y1,*x2,*y2,c1,c2)); newPtr((void *) Result,3, memenv);;
rt.addRef(getRef((void *)Result,memenv), "wxGraphicsBrush");
break;
}
+#endif
+#if !wxCHECK_VERSION(2,9,0)
case wxGraphicsRenderer_CreateRadialGradientBrush: { // wxGraphicsRenderer::CreateRadialGradientBrush
wxGraphicsRenderer *This = (wxGraphicsRenderer *) getPtr(bp,memenv); bp += 4;
bp += 4; /* Align */
@@ -6971,10 +7003,11 @@ case wxGraphicsRenderer_CreateRadialGradientBrush: { // wxGraphicsRenderer::Crea
int * cColorA = (int *) bp; bp += 4;
wxColour cColor = wxColour(*cColorR,*cColorG,*cColorB,*cColorA);
if(!This) throw wxe_badarg(0);
- wxGraphicsBrush * Result = new wxGraphicsBrush(This->CreateRadialGradientBrush((wxDouble) *xo,(wxDouble) *yo,(wxDouble) *xc,(wxDouble) *yc,(wxDouble) *radius,oColor,cColor)); newPtr((void *) Result,3, memenv);;
+ wxGraphicsBrush * Result = new wxGraphicsBrush(This->CreateRadialGradientBrush(*xo,*yo,*xc,*yc,*radius,oColor,cColor)); newPtr((void *) Result,3, memenv);;
rt.addRef(getRef((void *)Result,memenv), "wxGraphicsBrush");
break;
}
+#endif
case wxGraphicsRenderer_CreateFont: { // wxGraphicsRenderer::CreateFont
wxColour col= *wxBLACK;
wxGraphicsRenderer *This = (wxGraphicsRenderer *) getPtr(bp,memenv); bp += 4;
@@ -7050,7 +7083,7 @@ case wxGraphicsRenderer_CreatePath: { // wxGraphicsRenderer::CreatePath
#endif // wxUSE_GRAPHICS_CONTEXT
case wxMenuBar_new_1: { // wxMenuBar::wxMenuBar
int * style = (int *) bp; bp += 4;
- wxMenuBar * Result = new EwxMenuBar((long) *style);
+ wxMenuBar * Result = new EwxMenuBar(*style);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxMenuBar");
break;
@@ -7077,7 +7110,7 @@ case wxMenuBar_Check: { // wxMenuBar::Check
int * itemid = (int *) bp; bp += 4;
bool * check = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->Check((int) *itemid,(bool) *check);
+ This->Check(*itemid,*check);
break;
}
case wxMenuBar_Enable_2: { // wxMenuBar::Enable
@@ -7085,7 +7118,7 @@ case wxMenuBar_Enable_2: { // wxMenuBar::Enable
int * itemid = (int *) bp; bp += 4;
bool * enable = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->Enable((int) *itemid,(bool) *enable);
+ This->Enable(*itemid,*enable);
break;
}
case wxMenuBar_Enable_1: { // wxMenuBar::Enable
@@ -7107,7 +7140,7 @@ case wxMenuBar_EnableTop: { // wxMenuBar::EnableTop
int * pos = (int *) bp; bp += 4;
bool * flag = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->EnableTop((size_t) *pos,(bool) *flag);
+ This->EnableTop(*pos,*flag);
break;
}
case wxMenuBar_FindMenu: { // wxMenuBar::FindMenu
@@ -7138,7 +7171,7 @@ case wxMenuBar_FindItem: { // wxMenuBar::FindItem
wxMenuBar *This = (wxMenuBar *) getPtr(bp,memenv); bp += 4;
int * id = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxMenuItem * Result = (wxMenuItem*)This->FindItem((int) *id,menu);
+ wxMenuItem * Result = (wxMenuItem*)This->FindItem(*id,menu);
rt.addRef(getRef((void *)Result,memenv), "wxMenuItem");
break;
}
@@ -7146,7 +7179,7 @@ case wxMenuBar_GetHelpString: { // wxMenuBar::GetHelpString
wxMenuBar *This = (wxMenuBar *) getPtr(bp,memenv); bp += 4;
int * itemid = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxString Result = This->GetHelpString((int) *itemid);
+ wxString Result = This->GetHelpString(*itemid);
rt.add(Result);
break;
}
@@ -7154,7 +7187,7 @@ case wxMenuBar_GetLabel_1: { // wxMenuBar::GetLabel
wxMenuBar *This = (wxMenuBar *) getPtr(bp,memenv); bp += 4;
int * itemid = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxString Result = This->GetLabel((int) *itemid);
+ wxString Result = This->GetLabel(*itemid);
rt.add(Result);
break;
}
@@ -7169,7 +7202,7 @@ case wxMenuBar_GetLabelTop: { // wxMenuBar::GetLabelTop
wxMenuBar *This = (wxMenuBar *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxString Result = This->GetLabelTop((size_t) *pos);
+ wxString Result = This->GetLabelTop(*pos);
rt.add(Result);
break;
}
@@ -7177,7 +7210,7 @@ case wxMenuBar_GetMenu: { // wxMenuBar::GetMenu
wxMenuBar *This = (wxMenuBar *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxMenu * Result = (wxMenu*)This->GetMenu((size_t) *pos);
+ wxMenu * Result = (wxMenu*)This->GetMenu(*pos);
rt.addRef(getRef((void *)Result,memenv), "wxMenu");
break;
}
@@ -7196,7 +7229,7 @@ case wxMenuBar_Insert: { // wxMenuBar::Insert
wxString title = wxString(bp, wxConvUTF8);
bp += *titleLen+((8-((0+ *titleLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- bool Result = This->Insert((size_t) *pos,menu,title);
+ bool Result = This->Insert(*pos,menu,title);
rt.addBool(Result);
break;
}
@@ -7204,7 +7237,7 @@ case wxMenuBar_IsChecked: { // wxMenuBar::IsChecked
wxMenuBar *This = (wxMenuBar *) getPtr(bp,memenv); bp += 4;
int * itemid = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->IsChecked((int) *itemid);
+ bool Result = This->IsChecked(*itemid);
rt.addBool(Result);
break;
}
@@ -7212,7 +7245,7 @@ case wxMenuBar_IsEnabled_1: { // wxMenuBar::IsEnabled
wxMenuBar *This = (wxMenuBar *) getPtr(bp,memenv); bp += 4;
int * itemid = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->IsEnabled((int) *itemid);
+ bool Result = This->IsEnabled(*itemid);
rt.addBool(Result);
break;
}
@@ -7227,7 +7260,7 @@ case wxMenuBar_Remove: { // wxMenuBar::Remove
wxMenuBar *This = (wxMenuBar *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxMenu * Result = (wxMenu*)This->Remove((size_t) *pos);
+ wxMenu * Result = (wxMenu*)This->Remove(*pos);
rt.addRef(getRef((void *)Result,memenv), "wxMenu");
break;
}
@@ -7239,7 +7272,7 @@ case wxMenuBar_Replace: { // wxMenuBar::Replace
wxString title = wxString(bp, wxConvUTF8);
bp += *titleLen+((8-((0+ *titleLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- wxMenu * Result = (wxMenu*)This->Replace((size_t) *pos,menu,title);
+ wxMenu * Result = (wxMenu*)This->Replace(*pos,menu,title);
rt.addRef(getRef((void *)Result,memenv), "wxMenu");
break;
}
@@ -7250,7 +7283,7 @@ case wxMenuBar_SetHelpString: { // wxMenuBar::SetHelpString
wxString helpString = wxString(bp, wxConvUTF8);
bp += *helpStringLen+((8-((4+ *helpStringLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- This->SetHelpString((int) *itemid,helpString);
+ This->SetHelpString(*itemid,helpString);
break;
}
case wxMenuBar_SetLabel_2: { // wxMenuBar::SetLabel
@@ -7260,7 +7293,7 @@ case wxMenuBar_SetLabel_2: { // wxMenuBar::SetLabel
wxString label = wxString(bp, wxConvUTF8);
bp += *labelLen+((8-((4+ *labelLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- This->SetLabel((int) *itemid,label);
+ This->SetLabel(*itemid,label);
break;
}
case wxMenuBar_SetLabel_1: { // wxMenuBar::SetLabel
@@ -7279,7 +7312,7 @@ case wxMenuBar_SetLabelTop: { // wxMenuBar::SetLabelTop
wxString label = wxString(bp, wxConvUTF8);
bp += *labelLen+((8-((4+ *labelLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- This->SetLabelTop((size_t) *pos,label);
+ This->SetLabelTop(*pos,label);
break;
}
case wxControl_GetLabel: { // wxControl::GetLabel
@@ -7345,7 +7378,7 @@ case wxControlWithItems_Delete: { // wxControlWithItems::Delete
wxControlWithItems *This = (wxControlWithItems *) getPtr(bp,memenv); bp += 4;
unsigned int * n = (unsigned int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->Delete((int) *n);
+ This->Delete(*n);
break;
}
case wxControlWithItems_FindString: { // wxControlWithItems::FindString
@@ -7368,7 +7401,7 @@ case wxControlWithItems_getClientData: { // wxControlWithItems::GetClientObject
wxControlWithItems *This = (wxControlWithItems *) getPtr(bp,memenv); bp += 4;
unsigned int * n = (unsigned int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxeErlTerm * Result = (wxeErlTerm*)This->GetClientObject((int) *n);
+ wxeErlTerm * Result = (wxeErlTerm*)This->GetClientObject(*n);
rt.addExt2Term(Result);
break;
}
@@ -7377,7 +7410,7 @@ case wxControlWithItems_setClientData: { // wxControlWithItems::SetClientObject
unsigned int * n = (unsigned int *) bp; bp += 4;
wxeErlTerm * clientData = new wxeErlTerm(Ecmd.bin[0]);
if(!This) throw wxe_badarg(0);
- This->SetClientObject((int) *n,clientData);
+ This->SetClientObject(*n,clientData);
break;
}
case wxControlWithItems_GetCount: { // wxControlWithItems::GetCount
@@ -7398,7 +7431,7 @@ case wxControlWithItems_GetString: { // wxControlWithItems::GetString
wxControlWithItems *This = (wxControlWithItems *) getPtr(bp,memenv); bp += 4;
unsigned int * n = (unsigned int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxString Result = This->GetString((int) *n);
+ wxString Result = This->GetString(*n);
rt.add(Result);
break;
}
@@ -7416,7 +7449,7 @@ case wxControlWithItems_Insert_2: { // wxControlWithItems::Insert
bp += *itemLen+((8-((0+ *itemLen) & 7)) & 7);
unsigned int * pos = (unsigned int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->Insert(item,(int) *pos);
+ int Result = This->Insert(item,*pos);
rt.addInt(Result);
break;
}
@@ -7428,7 +7461,7 @@ case wxControlWithItems_Insert_3: { // wxControlWithItems::Insert
unsigned int * pos = (unsigned int *) bp; bp += 4;
wxeErlTerm * clientData = new wxeErlTerm(Ecmd.bin[0]);
if(!This) throw wxe_badarg(0);
- int Result = This->Insert(item,(int) *pos,clientData);
+ int Result = This->Insert(item,*pos,clientData);
rt.addInt(Result);
break;
}
@@ -7443,14 +7476,14 @@ case wxControlWithItems_Select: { // wxControlWithItems::Select
wxControlWithItems *This = (wxControlWithItems *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->Select((int) *n);
+ This->Select(*n);
break;
}
case wxControlWithItems_SetSelection: { // wxControlWithItems::SetSelection
wxControlWithItems *This = (wxControlWithItems *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetSelection((int) *n);
+ This->SetSelection(*n);
break;
}
case wxControlWithItems_SetString: { // wxControlWithItems::SetString
@@ -7460,7 +7493,7 @@ case wxControlWithItems_SetString: { // wxControlWithItems::SetString
wxString s = wxString(bp, wxConvUTF8);
bp += *sLen+((8-((4+ *sLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- This->SetString((int) *n,s);
+ This->SetString(*n,s);
break;
}
case wxControlWithItems_SetStringSelection: { // wxControlWithItems::SetStringSelection
@@ -7519,7 +7552,7 @@ kind = *(wxItemKind *) bp; bp += 4;;
} break;
}};
if(!This) throw wxe_badarg(0);
- wxMenuItem * Result = (wxMenuItem*)This->Append((int) *itemid,text,help,(wxItemKind) kind);
+ wxMenuItem * Result = (wxMenuItem*)This->Append(*itemid,text,help,kind);
rt.addRef(getRef((void *)Result,memenv), "wxMenuItem");
break;
}
@@ -7542,7 +7575,7 @@ case wxMenu_Append_4_0: { // wxMenu::Append
bp += *helpLen+((8-((4+ *helpLen) & 7)) & 7);
bool * isCheckable = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->Append((int) *itemid,text,help,(bool) *isCheckable);
+ This->Append(*itemid,text,help,*isCheckable);
break;
}
case wxMenu_Append_4_1: { // wxMenu::Append
@@ -7562,7 +7595,7 @@ case wxMenu_Append_4_1: { // wxMenu::Append
} break;
}};
if(!This) throw wxe_badarg(0);
- wxMenuItem * Result = (wxMenuItem*)This->Append((int) *itemid,text,submenu,help);
+ wxMenuItem * Result = (wxMenuItem*)This->Append(*itemid,text,submenu,help);
rt.addRef(getRef((void *)Result,memenv), "wxMenuItem");
break;
}
@@ -7581,7 +7614,7 @@ case wxMenu_AppendCheckItem: { // wxMenu::AppendCheckItem
} break;
}};
if(!This) throw wxe_badarg(0);
- wxMenuItem * Result = (wxMenuItem*)This->AppendCheckItem((int) *itemid,text,help);
+ wxMenuItem * Result = (wxMenuItem*)This->AppendCheckItem(*itemid,text,help);
rt.addRef(getRef((void *)Result,memenv), "wxMenuItem");
break;
}
@@ -7600,7 +7633,7 @@ case wxMenu_AppendRadioItem: { // wxMenu::AppendRadioItem
} break;
}};
if(!This) throw wxe_badarg(0);
- wxMenuItem * Result = (wxMenuItem*)This->AppendRadioItem((int) *itemid,text,help);
+ wxMenuItem * Result = (wxMenuItem*)This->AppendRadioItem(*itemid,text,help);
rt.addRef(getRef((void *)Result,memenv), "wxMenuItem");
break;
}
@@ -7622,14 +7655,14 @@ case wxMenu_Check: { // wxMenu::Check
int * itemid = (int *) bp; bp += 4;
bool * check = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->Check((int) *itemid,(bool) *check);
+ This->Check(*itemid,*check);
break;
}
case wxMenu_Delete_1_0: { // wxMenu::Delete
wxMenu *This = (wxMenu *) getPtr(bp,memenv); bp += 4;
int * itemid = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->Delete((int) *itemid);
+ bool Result = This->Delete(*itemid);
rt.addBool(Result);
break;
}
@@ -7645,7 +7678,7 @@ case wxMenu_Destroy_1_0: { // wxMenu::Destroy
wxMenu *This = (wxMenu *) getPtr(bp,memenv); bp += 4;
int * itemid = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->Destroy((int) *itemid);
+ bool Result = This->Destroy(*itemid);
rt.addBool(Result);
break;
}
@@ -7662,7 +7695,7 @@ case wxMenu_Enable: { // wxMenu::Enable
int * itemid = (int *) bp; bp += 4;
bool * enable = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->Enable((int) *itemid,(bool) *enable);
+ This->Enable(*itemid,*enable);
break;
}
case wxMenu_FindItem_1: { // wxMenu::FindItem
@@ -7680,7 +7713,7 @@ case wxMenu_FindItem_2: { // wxMenu::FindItem
wxMenu *This = (wxMenu *) getPtr(bp,memenv); bp += 4;
int * itemid = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxMenuItem * Result = (wxMenuItem*)This->FindItem((int) *itemid,menu);
+ wxMenuItem * Result = (wxMenuItem*)This->FindItem(*itemid,menu);
rt.addRef(getRef((void *)Result,memenv), "wxMenuItem");
break;
}
@@ -7688,7 +7721,7 @@ case wxMenu_FindItemByPosition: { // wxMenu::FindItemByPosition
wxMenu *This = (wxMenu *) getPtr(bp,memenv); bp += 4;
int * position = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxMenuItem * Result = (wxMenuItem*)This->FindItemByPosition((size_t) *position);
+ wxMenuItem * Result = (wxMenuItem*)This->FindItemByPosition(*position);
rt.addRef(getRef((void *)Result,memenv), "wxMenuItem");
break;
}
@@ -7696,7 +7729,7 @@ case wxMenu_GetHelpString: { // wxMenu::GetHelpString
wxMenu *This = (wxMenu *) getPtr(bp,memenv); bp += 4;
int * itemid = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxString Result = This->GetHelpString((int) *itemid);
+ wxString Result = This->GetHelpString(*itemid);
rt.add(Result);
break;
}
@@ -7704,7 +7737,7 @@ case wxMenu_GetLabel: { // wxMenu::GetLabel
wxMenu *This = (wxMenu *) getPtr(bp,memenv); bp += 4;
int * itemid = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxString Result = This->GetLabel((int) *itemid);
+ wxString Result = This->GetLabel(*itemid);
rt.add(Result);
break;
}
@@ -7738,7 +7771,7 @@ case wxMenu_Insert_2: { // wxMenu::Insert
int * pos = (int *) bp; bp += 4;
wxMenuItem *item = (wxMenuItem *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- wxMenuItem * Result = (wxMenuItem*)This->Insert((size_t) *pos,item);
+ wxMenuItem * Result = (wxMenuItem*)This->Insert(*pos,item);
rt.addRef(getRef((void *)Result,memenv), "wxMenuItem");
break;
}
@@ -7766,7 +7799,7 @@ kind = *(wxItemKind *) bp; bp += 4;;
} break;
}};
if(!This) throw wxe_badarg(0);
- wxMenuItem * Result = (wxMenuItem*)This->Insert((size_t) *pos,(int) *itemid,text,help,(wxItemKind) kind);
+ wxMenuItem * Result = (wxMenuItem*)This->Insert(*pos,*itemid,text,help,kind);
rt.addRef(getRef((void *)Result,memenv), "wxMenuItem");
break;
}
@@ -7788,7 +7821,7 @@ case wxMenu_Insert_5_1: { // wxMenu::Insert
} break;
}};
if(!This) throw wxe_badarg(0);
- wxMenuItem * Result = (wxMenuItem*)This->Insert((size_t) *pos,(int) *itemid,text,submenu,help);
+ wxMenuItem * Result = (wxMenuItem*)This->Insert(*pos,*itemid,text,submenu,help);
rt.addRef(getRef((void *)Result,memenv), "wxMenuItem");
break;
}
@@ -7804,7 +7837,7 @@ case wxMenu_Insert_5_0: { // wxMenu::Insert
bp += *helpLen+((8-((4+ *helpLen) & 7)) & 7);
bool * isCheckable = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->Insert((size_t) *pos,(int) *itemid,text,help,(bool) *isCheckable);
+ This->Insert(*pos,*itemid,text,help,*isCheckable);
break;
}
case wxMenu_InsertCheckItem: { // wxMenu::InsertCheckItem
@@ -7823,7 +7856,7 @@ case wxMenu_InsertCheckItem: { // wxMenu::InsertCheckItem
} break;
}};
if(!This) throw wxe_badarg(0);
- wxMenuItem * Result = (wxMenuItem*)This->InsertCheckItem((size_t) *pos,(int) *itemid,text,help);
+ wxMenuItem * Result = (wxMenuItem*)This->InsertCheckItem(*pos,*itemid,text,help);
rt.addRef(getRef((void *)Result,memenv), "wxMenuItem");
break;
}
@@ -7843,7 +7876,7 @@ case wxMenu_InsertRadioItem: { // wxMenu::InsertRadioItem
} break;
}};
if(!This) throw wxe_badarg(0);
- wxMenuItem * Result = (wxMenuItem*)This->InsertRadioItem((size_t) *pos,(int) *itemid,text,help);
+ wxMenuItem * Result = (wxMenuItem*)This->InsertRadioItem(*pos,*itemid,text,help);
rt.addRef(getRef((void *)Result,memenv), "wxMenuItem");
break;
}
@@ -7851,7 +7884,7 @@ case wxMenu_InsertSeparator: { // wxMenu::InsertSeparator
wxMenu *This = (wxMenu *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxMenuItem * Result = (wxMenuItem*)This->InsertSeparator((size_t) *pos);
+ wxMenuItem * Result = (wxMenuItem*)This->InsertSeparator(*pos);
rt.addRef(getRef((void *)Result,memenv), "wxMenuItem");
break;
}
@@ -7859,7 +7892,7 @@ case wxMenu_IsChecked: { // wxMenu::IsChecked
wxMenu *This = (wxMenu *) getPtr(bp,memenv); bp += 4;
int * itemid = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->IsChecked((int) *itemid);
+ bool Result = This->IsChecked(*itemid);
rt.addBool(Result);
break;
}
@@ -7867,7 +7900,7 @@ case wxMenu_IsEnabled: { // wxMenu::IsEnabled
wxMenu *This = (wxMenu *) getPtr(bp,memenv); bp += 4;
int * itemid = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->IsEnabled((int) *itemid);
+ bool Result = This->IsEnabled(*itemid);
rt.addBool(Result);
break;
}
@@ -7901,7 +7934,7 @@ kind = *(wxItemKind *) bp; bp += 4;;
} break;
}};
if(!This) throw wxe_badarg(0);
- wxMenuItem * Result = (wxMenuItem*)This->Prepend((int) *itemid,text,help,(wxItemKind) kind);
+ wxMenuItem * Result = (wxMenuItem*)This->Prepend(*itemid,text,help,kind);
rt.addRef(getRef((void *)Result,memenv), "wxMenuItem");
break;
}
@@ -7922,7 +7955,7 @@ case wxMenu_Prepend_4_1: { // wxMenu::Prepend
} break;
}};
if(!This) throw wxe_badarg(0);
- wxMenuItem * Result = (wxMenuItem*)This->Prepend((int) *itemid,text,submenu,help);
+ wxMenuItem * Result = (wxMenuItem*)This->Prepend(*itemid,text,submenu,help);
rt.addRef(getRef((void *)Result,memenv), "wxMenuItem");
break;
}
@@ -7937,7 +7970,7 @@ case wxMenu_Prepend_4_0: { // wxMenu::Prepend
bp += *helpLen+((8-((4+ *helpLen) & 7)) & 7);
bool * isCheckable = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->Prepend((int) *itemid,text,help,(bool) *isCheckable);
+ This->Prepend(*itemid,text,help,*isCheckable);
break;
}
case wxMenu_PrependCheckItem: { // wxMenu::PrependCheckItem
@@ -7955,7 +7988,7 @@ case wxMenu_PrependCheckItem: { // wxMenu::PrependCheckItem
} break;
}};
if(!This) throw wxe_badarg(0);
- wxMenuItem * Result = (wxMenuItem*)This->PrependCheckItem((int) *itemid,text,help);
+ wxMenuItem * Result = (wxMenuItem*)This->PrependCheckItem(*itemid,text,help);
rt.addRef(getRef((void *)Result,memenv), "wxMenuItem");
break;
}
@@ -7974,7 +8007,7 @@ case wxMenu_PrependRadioItem: { // wxMenu::PrependRadioItem
} break;
}};
if(!This) throw wxe_badarg(0);
- wxMenuItem * Result = (wxMenuItem*)This->PrependRadioItem((int) *itemid,text,help);
+ wxMenuItem * Result = (wxMenuItem*)This->PrependRadioItem(*itemid,text,help);
rt.addRef(getRef((void *)Result,memenv), "wxMenuItem");
break;
}
@@ -7989,7 +8022,7 @@ case wxMenu_Remove_1_0: { // wxMenu::Remove
wxMenu *This = (wxMenu *) getPtr(bp,memenv); bp += 4;
int * itemid = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxMenuItem * Result = (wxMenuItem*)This->Remove((int) *itemid);
+ wxMenuItem * Result = (wxMenuItem*)This->Remove(*itemid);
rt.addRef(getRef((void *)Result,memenv), "wxMenuItem");
break;
}
@@ -8008,7 +8041,7 @@ case wxMenu_SetHelpString: { // wxMenu::SetHelpString
wxString helpString = wxString(bp, wxConvUTF8);
bp += *helpStringLen+((8-((4+ *helpStringLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- This->SetHelpString((int) *itemid,helpString);
+ This->SetHelpString(*itemid,helpString);
break;
}
case wxMenu_SetLabel: { // wxMenu::SetLabel
@@ -8018,7 +8051,7 @@ case wxMenu_SetLabel: { // wxMenu::SetLabel
wxString label = wxString(bp, wxConvUTF8);
bp += *labelLen+((8-((4+ *labelLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- This->SetLabel((int) *itemid,label);
+ This->SetLabel(*itemid,label);
break;
}
case wxMenu_SetTitle: { // wxMenu::SetTitle
@@ -8061,7 +8094,7 @@ kind = *(wxItemKind *) bp; bp += 4;;
subMenu = (wxMenu *) getPtr(bp,memenv); bp += 4;
} break;
}};
- wxMenuItem * Result = new EwxMenuItem(parentMenu,id,text,help,(wxItemKind) kind,subMenu);
+ wxMenuItem * Result = new EwxMenuItem(parentMenu,id,text,help,kind,subMenu);
newPtr((void *) Result, 1, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxMenuItem");
break;
@@ -8276,7 +8309,7 @@ data = (wxObject *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- wxToolBarToolBase * Result = (wxToolBarToolBase*)This->AddTool((int) *toolid,label,*bitmap,*bmpDisabled,(wxItemKind) kind,shortHelp,longHelp,data);
+ wxToolBarToolBase * Result = (wxToolBarToolBase*)This->AddTool(*toolid,label,*bitmap,*bmpDisabled,kind,shortHelp,longHelp,data);
rt.addRef(getRef((void *)Result,memenv), "wx");
break;
}
@@ -8301,7 +8334,7 @@ kind = *(wxItemKind *) bp; bp += 4;;
} break;
}};
if(!This) throw wxe_badarg(0);
- wxToolBarToolBase * Result = (wxToolBarToolBase*)This->AddTool((int) *toolid,label,*bitmap,shortHelp,(wxItemKind) kind);
+ wxToolBarToolBase * Result = (wxToolBarToolBase*)This->AddTool(*toolid,label,*bitmap,shortHelp,kind);
rt.addRef(getRef((void *)Result,memenv), "wx");
break;
}
@@ -8341,7 +8374,7 @@ clientData = (wxObject *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- wxToolBarToolBase * Result = (wxToolBarToolBase*)This->AddTool((int) *toolid,*bitmap,*bmpDisabled,toggle,clientData,shortHelpString,longHelpString);
+ wxToolBarToolBase * Result = (wxToolBarToolBase*)This->AddTool(*toolid,*bitmap,*bmpDisabled,toggle,clientData,shortHelpString,longHelpString);
rt.addRef(getRef((void *)Result,memenv), "wx");
break;
}
@@ -8365,7 +8398,7 @@ case wxToolBar_AddTool_3: { // wxToolBar::AddTool
} break;
}};
if(!This) throw wxe_badarg(0);
- wxToolBarToolBase * Result = (wxToolBarToolBase*)This->AddTool((int) *toolid,*bitmap,shortHelpString,longHelpString);
+ wxToolBarToolBase * Result = (wxToolBarToolBase*)This->AddTool(*toolid,*bitmap,shortHelpString,longHelpString);
rt.addRef(getRef((void *)Result,memenv), "wx");
break;
}
@@ -8399,7 +8432,7 @@ clientData = (wxObject *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- wxToolBarToolBase * Result = (wxToolBarToolBase*)This->AddTool((int) *toolid,*bitmap,*bmpDisabled,(bool) *toggle,(wxCoord) *xPos,yPos,clientData,shortHelp,longHelp);
+ wxToolBarToolBase * Result = (wxToolBarToolBase*)This->AddTool(*toolid,*bitmap,*bmpDisabled,*toggle,*xPos,yPos,clientData,shortHelp,longHelp);
rt.addRef(getRef((void *)Result,memenv), "wx");
break;
}
@@ -8434,7 +8467,7 @@ data = (wxObject *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- wxToolBarToolBase * Result = (wxToolBarToolBase*)This->AddCheckTool((int) *toolid,label,*bitmap,*bmpDisabled,shortHelp,longHelp,data);
+ wxToolBarToolBase * Result = (wxToolBarToolBase*)This->AddCheckTool(*toolid,label,*bitmap,*bmpDisabled,shortHelp,longHelp,data);
rt.addRef(getRef((void *)Result,memenv), "wx");
break;
}
@@ -8469,7 +8502,7 @@ data = (wxObject *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- wxToolBarToolBase * Result = (wxToolBarToolBase*)This->AddRadioTool((int) *toolid,label,*bitmap,*bmpDisabled,shortHelp,longHelp,data);
+ wxToolBarToolBase * Result = (wxToolBarToolBase*)This->AddRadioTool(*toolid,label,*bitmap,*bmpDisabled,shortHelp,longHelp,data);
rt.addRef(getRef((void *)Result,memenv), "wx");
break;
}
@@ -8477,7 +8510,7 @@ case wxToolBar_DeleteTool: { // wxToolBar::DeleteTool
wxToolBar *This = (wxToolBar *) getPtr(bp,memenv); bp += 4;
int * toolid = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->DeleteTool((int) *toolid);
+ bool Result = This->DeleteTool(*toolid);
rt.addBool(Result);
break;
}
@@ -8485,7 +8518,7 @@ case wxToolBar_DeleteToolByPos: { // wxToolBar::DeleteToolByPos
wxToolBar *This = (wxToolBar *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->DeleteToolByPos((size_t) *pos);
+ bool Result = This->DeleteToolByPos(*pos);
rt.addBool(Result);
break;
}
@@ -8494,14 +8527,14 @@ case wxToolBar_EnableTool: { // wxToolBar::EnableTool
int * toolid = (int *) bp; bp += 4;
bool * enable = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->EnableTool((int) *toolid,(bool) *enable);
+ This->EnableTool(*toolid,*enable);
break;
}
case wxToolBar_FindById: { // wxToolBar::FindById
wxToolBar *This = (wxToolBar *) getPtr(bp,memenv); bp += 4;
int * toolid = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxToolBarToolBase * Result = (wxToolBarToolBase*)This->FindById((int) *toolid);
+ wxToolBarToolBase * Result = (wxToolBarToolBase*)This->FindById(*toolid);
rt.addRef(getRef((void *)Result,memenv), "wx");
break;
}
@@ -8509,7 +8542,7 @@ case wxToolBar_FindControl: { // wxToolBar::FindControl
wxToolBar *This = (wxToolBar *) getPtr(bp,memenv); bp += 4;
int * toolid = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxControl * Result = (wxControl*)This->FindControl((int) *toolid);
+ wxControl * Result = (wxControl*)This->FindControl(*toolid);
rt.addRef(getRef((void *)Result,memenv), "wxControl");
break;
}
@@ -8518,7 +8551,7 @@ case wxToolBar_FindToolForPosition: { // wxToolBar::FindToolForPosition
int * x = (int *) bp; bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxToolBarToolBase * Result = (wxToolBarToolBase*)This->FindToolForPosition((wxCoord) *x,(wxCoord) *y);
+ wxToolBarToolBase * Result = (wxToolBarToolBase*)This->FindToolForPosition(*x,*y);
rt.addRef(getRef((void *)Result,memenv), "wx");
break;
}
@@ -8547,7 +8580,7 @@ case wxToolBar_GetToolEnabled: { // wxToolBar::GetToolEnabled
wxToolBar *This = (wxToolBar *) getPtr(bp,memenv); bp += 4;
int * toolid = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->GetToolEnabled((int) *toolid);
+ bool Result = This->GetToolEnabled(*toolid);
rt.addBool(Result);
break;
}
@@ -8555,7 +8588,7 @@ case wxToolBar_GetToolLongHelp: { // wxToolBar::GetToolLongHelp
wxToolBar *This = (wxToolBar *) getPtr(bp,memenv); bp += 4;
int * toolid = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxString Result = This->GetToolLongHelp((int) *toolid);
+ wxString Result = This->GetToolLongHelp(*toolid);
rt.add(Result);
break;
}
@@ -8570,7 +8603,7 @@ case wxToolBar_GetToolPos: { // wxToolBar::GetToolPos
wxToolBar *This = (wxToolBar *) getPtr(bp,memenv); bp += 4;
int * id = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->GetToolPos((int) *id);
+ int Result = This->GetToolPos(*id);
rt.addInt(Result);
break;
}
@@ -8585,7 +8618,7 @@ case wxToolBar_GetToolShortHelp: { // wxToolBar::GetToolShortHelp
wxToolBar *This = (wxToolBar *) getPtr(bp,memenv); bp += 4;
int * toolid = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxString Result = This->GetToolShortHelp((int) *toolid);
+ wxString Result = This->GetToolShortHelp(*toolid);
rt.add(Result);
break;
}
@@ -8593,7 +8626,7 @@ case wxToolBar_GetToolState: { // wxToolBar::GetToolState
wxToolBar *This = (wxToolBar *) getPtr(bp,memenv); bp += 4;
int * toolid = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->GetToolState((int) *toolid);
+ bool Result = This->GetToolState(*toolid);
rt.addBool(Result);
break;
}
@@ -8602,7 +8635,7 @@ case wxToolBar_InsertControl: { // wxToolBar::InsertControl
int * pos = (int *) bp; bp += 4;
wxControl *control = (wxControl *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- wxToolBarToolBase * Result = (wxToolBarToolBase*)This->InsertControl((size_t) *pos,control);
+ wxToolBarToolBase * Result = (wxToolBarToolBase*)This->InsertControl(*pos,control);
rt.addRef(getRef((void *)Result,memenv), "wx");
break;
}
@@ -8610,7 +8643,7 @@ case wxToolBar_InsertSeparator: { // wxToolBar::InsertSeparator
wxToolBar *This = (wxToolBar *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxToolBarToolBase * Result = (wxToolBarToolBase*)This->InsertSeparator((size_t) *pos);
+ wxToolBarToolBase * Result = (wxToolBarToolBase*)This->InsertSeparator(*pos);
rt.addRef(getRef((void *)Result,memenv), "wx");
break;
}
@@ -8650,7 +8683,7 @@ clientData = (wxObject *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- wxToolBarToolBase * Result = (wxToolBarToolBase*)This->InsertTool((size_t) *pos,(int) *toolid,label,*bitmap,*bmpDisabled,(wxItemKind) kind,shortHelp,longHelp,clientData);
+ wxToolBarToolBase * Result = (wxToolBarToolBase*)This->InsertTool(*pos,*toolid,label,*bitmap,*bmpDisabled,kind,shortHelp,longHelp,clientData);
rt.addRef(getRef((void *)Result,memenv), "wx");
break;
}
@@ -8659,7 +8692,7 @@ case wxToolBar_InsertTool_2: { // wxToolBar::InsertTool
int * pos = (int *) bp; bp += 4;
wxToolBarToolBase *tool = (wxToolBarToolBase *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- wxToolBarToolBase * Result = (wxToolBarToolBase*)This->InsertTool((size_t) *pos,tool);
+ wxToolBarToolBase * Result = (wxToolBarToolBase*)This->InsertTool(*pos,tool);
rt.addRef(getRef((void *)Result,memenv), "wx");
break;
}
@@ -8695,7 +8728,7 @@ clientData = (wxObject *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- wxToolBarToolBase * Result = (wxToolBarToolBase*)This->InsertTool((size_t) *pos,(int) *toolid,*bitmap,*bmpDisabled,toggle,clientData,shortHelp,longHelp);
+ wxToolBarToolBase * Result = (wxToolBarToolBase*)This->InsertTool(*pos,*toolid,*bitmap,*bmpDisabled,toggle,clientData,shortHelp,longHelp);
rt.addRef(getRef((void *)Result,memenv), "wx");
break;
}
@@ -8710,7 +8743,7 @@ case wxToolBar_RemoveTool: { // wxToolBar::RemoveTool
wxToolBar *This = (wxToolBar *) getPtr(bp,memenv); bp += 4;
int * toolid = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxToolBarToolBase * Result = (wxToolBarToolBase*)This->RemoveTool((int) *toolid);
+ wxToolBarToolBase * Result = (wxToolBarToolBase*)This->RemoveTool(*toolid);
rt.addRef(getRef((void *)Result,memenv), "wx");
break;
}
@@ -8719,7 +8752,7 @@ case wxToolBar_SetMargins: { // wxToolBar::SetMargins
int * x = (int *) bp; bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetMargins((int) *x,(int) *y);
+ This->SetMargins(*x,*y);
break;
}
case wxToolBar_SetToolBitmapSize: { // wxToolBar::SetToolBitmapSize
@@ -8738,14 +8771,14 @@ case wxToolBar_SetToolLongHelp: { // wxToolBar::SetToolLongHelp
wxString helpString = wxString(bp, wxConvUTF8);
bp += *helpStringLen+((8-((4+ *helpStringLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- This->SetToolLongHelp((int) *toolid,helpString);
+ This->SetToolLongHelp(*toolid,helpString);
break;
}
case wxToolBar_SetToolPacking: { // wxToolBar::SetToolPacking
wxToolBar *This = (wxToolBar *) getPtr(bp,memenv); bp += 4;
int * packing = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetToolPacking((int) *packing);
+ This->SetToolPacking(*packing);
break;
}
case wxToolBar_SetToolShortHelp: { // wxToolBar::SetToolShortHelp
@@ -8755,14 +8788,14 @@ case wxToolBar_SetToolShortHelp: { // wxToolBar::SetToolShortHelp
wxString helpString = wxString(bp, wxConvUTF8);
bp += *helpStringLen+((8-((4+ *helpStringLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- This->SetToolShortHelp((int) *id,helpString);
+ This->SetToolShortHelp(*id,helpString);
break;
}
case wxToolBar_SetToolSeparation: { // wxToolBar::SetToolSeparation
wxToolBar *This = (wxToolBar *) getPtr(bp,memenv); bp += 4;
int * separation = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetToolSeparation((int) *separation);
+ This->SetToolSeparation(*separation);
break;
}
case wxToolBar_ToggleTool: { // wxToolBar::ToggleTool
@@ -8770,7 +8803,7 @@ case wxToolBar_ToggleTool: { // wxToolBar::ToggleTool
int * toolid = (int *) bp; bp += 4;
bool * toggle = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->ToggleTool((int) *toolid,(bool) *toggle);
+ This->ToggleTool(*toolid,*toggle);
break;
}
case wxStatusBar_new_0: { // wxStatusBar::wxStatusBar
@@ -8824,7 +8857,7 @@ case wxStatusBar_GetFieldRect: { // wxStatusBar::GetFieldRect
int * rectH = (int *) bp; bp += 4;
wxRect rect = wxRect(*rectX,*rectY,*rectW,*rectH);
if(!This) throw wxe_badarg(0);
- bool Result = This->GetFieldRect((int) *i,rect);
+ bool Result = This->GetFieldRect(*i,rect);
rt.addBool(Result);
break;
}
@@ -8889,14 +8922,14 @@ case wxStatusBar_SetFieldsCount: { // wxStatusBar::SetFieldsCount
} break;
}};
if(!This) throw wxe_badarg(0);
- This->SetFieldsCount((int) *number,widths);
+ This->SetFieldsCount(*number,widths);
break;
}
case wxStatusBar_SetMinHeight: { // wxStatusBar::SetMinHeight
wxStatusBar *This = (wxStatusBar *) getPtr(bp,memenv); bp += 4;
int * height = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetMinHeight((int) *height);
+ This->SetMinHeight(*height);
break;
}
case wxStatusBar_SetStatusText: { // wxStatusBar::SetStatusText
@@ -8945,7 +8978,7 @@ case wxBitmap_new_3: { // wxBitmap::wxBitmap
depth = (int)*(int *) bp; bp += 4;
} break;
}};
- wxBitmap * Result = new EwxBitmap((int) *width,(int) *height,depth);
+ wxBitmap * Result = new EwxBitmap(*width,*height,depth);
newPtr((void *) Result, 1, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxBitmap");
break;
@@ -8960,7 +8993,7 @@ case wxBitmap_new_4: { // wxBitmap::wxBitmap
depth = (int)*(int *) bp; bp += 4;
} break;
}};
- wxBitmap * Result = new EwxBitmap(bits,(int) *width,(int) *height,depth);
+ wxBitmap * Result = new EwxBitmap(bits,*width,*height,depth);
newPtr((void *) Result, 1, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxBitmap");
break;
@@ -8975,7 +9008,7 @@ case wxBitmap_new_2_0: { // wxBitmap::wxBitmap
type = *(wxBitmapType *) bp; bp += 4;;
} break;
}};
- wxBitmap * Result = new EwxBitmap(filename,(wxBitmapType) type);
+ wxBitmap * Result = new EwxBitmap(filename,type);
newPtr((void *) Result, 1, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxBitmap");
break;
@@ -9021,7 +9054,7 @@ case wxBitmap_Create: { // wxBitmap::Create
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create((int) *width,(int) *height,depth);
+ bool Result = This->Create(*width,*height,depth);
rt.addBool(Result);
break;
}
@@ -9084,7 +9117,7 @@ type = *(wxBitmapType *) bp; bp += 4;;
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->LoadFile(name,(wxBitmapType) type);
+ bool Result = This->LoadFile(name,type);
rt.addBool(Result);
break;
}
@@ -9109,7 +9142,7 @@ palette = (wxPalette *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->SaveFile(name,(wxBitmapType) type,palette);
+ bool Result = This->SaveFile(name,type,palette);
rt.addBool(Result);
break;
}
@@ -9117,14 +9150,14 @@ case wxBitmap_SetDepth: { // wxBitmap::SetDepth
wxBitmap *This = (wxBitmap *) getPtr(bp,memenv); bp += 4;
int * depth = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetDepth((int) *depth);
+ This->SetDepth(*depth);
break;
}
case wxBitmap_SetHeight: { // wxBitmap::SetHeight
wxBitmap *This = (wxBitmap *) getPtr(bp,memenv); bp += 4;
int * height = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetHeight((int) *height);
+ This->SetHeight(*height);
break;
}
case wxBitmap_SetMask: { // wxBitmap::SetMask
@@ -9145,7 +9178,7 @@ case wxBitmap_SetWidth: { // wxBitmap::SetWidth
wxBitmap *This = (wxBitmap *) getPtr(bp,memenv); bp += 4;
int * width = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetWidth((int) *width);
+ This->SetWidth(*width);
break;
}
case wxIcon_new_0: { // wxIcon::wxIcon
@@ -9172,7 +9205,7 @@ type = *(wxBitmapType *) bp; bp += 4;;
desiredHeight = (int)*(int *) bp; bp += 4;
} break;
}};
- wxIcon * Result = new EwxIcon(filename,(wxBitmapType) type,desiredWidth,desiredHeight);
+ wxIcon * Result = new EwxIcon(filename,type,desiredWidth,desiredHeight);
newPtr((void *) Result, 1, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxIcon");
break;
@@ -9202,7 +9235,7 @@ case wxIconBundle_new_2: { // wxIconBundle::wxIconBundle
wxString file = wxString(bp, wxConvUTF8);
bp += *fileLen+((8-((4+ *fileLen) & 7)) & 7);
int * type = (int *) bp; bp += 4;
- wxIconBundle * Result = new wxIconBundle(file,(long) *type);
+ wxIconBundle * Result = new wxIconBundle(file,*type);
newPtr((void *) Result, 61, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxIconBundle");
break;
@@ -9234,7 +9267,7 @@ case wxIconBundle_AddIcon_2: { // wxIconBundle::AddIcon
bp += *fileLen+((8-((0+ *fileLen) & 7)) & 7);
int * type = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->AddIcon(file,(long) *type);
+ This->AddIcon(file,*type);
break;
}
case wxIconBundle_AddIcon_1: { // wxIconBundle::AddIcon
@@ -9250,7 +9283,7 @@ case wxIconBundle_GetIcon_1_1: { // wxIconBundle::GetIcon
int * sizeH = (int *) bp; bp += 4;
wxSize size = wxSize(*sizeW,*sizeH);
if(!This) throw wxe_badarg(0);
- const wxIcon * Result = &This->GetIcon(size);
+ const wxIcon * Result = new wxIcon(This->GetIcon(size)); newPtr((void *) Result,3, memenv);;
rt.addRef(getRef((void *)Result,memenv), "wxIcon");
break;
}
@@ -9264,7 +9297,7 @@ case wxIconBundle_GetIcon_1_0: { // wxIconBundle::GetIcon
} break;
}};
if(!This) throw wxe_badarg(0);
- const wxIcon * Result = &This->GetIcon(size);
+ const wxIcon * Result = new wxIcon(This->GetIcon(size)); newPtr((void *) Result,3, memenv);;
rt.addRef(getRef((void *)Result,memenv), "wxIcon");
break;
}
@@ -9276,7 +9309,7 @@ case wxCursor_new_0: { // wxCursor::wxCursor
}
case wxCursor_new_1_0: { // wxCursor::wxCursor
int * cursorId = (int *) bp; bp += 4;
- wxCursor * Result = new EwxCursor((int) *cursorId);
+ wxCursor * Result = new EwxCursor(*cursorId);
newPtr((void *) Result, 1, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxCursor");
break;
@@ -9288,6 +9321,7 @@ case wxCursor_new_1_1: { // wxCursor::wxCursor
rt.addRef(getRef((void *)Result,memenv), "wxCursor");
break;
}
+#if !wxCHECK_VERSION(2,9,0)
case wxCursor_new_4: { // wxCursor::wxCursor
int hotSpotX=-1;
int hotSpotY=-1;
@@ -9302,11 +9336,12 @@ case wxCursor_new_4: { // wxCursor::wxCursor
hotSpotY = (int)*(int *) bp; bp += 4;
} break;
}};
- wxCursor * Result = new EwxCursor(bits,(int) *width,(int) *height,hotSpotX,hotSpotY);
+ wxCursor * Result = new EwxCursor(bits,*width,*height,hotSpotX,hotSpotY);
newPtr((void *) Result, 1, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxCursor");
break;
}
+#endif
case wxCursor_Ok: { // wxCursor::Ok
wxCursor *This = (wxCursor *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
@@ -9335,7 +9370,7 @@ case wxMask_new_2_1: { // wxMask::wxMask
case wxMask_new_2_0: { // wxMask::wxMask
wxBitmap *bitmap = (wxBitmap *) getPtr(bp,memenv); bp += 4;
int * paletteIndex = (int *) bp; bp += 4;
- wxMask * Result = new EwxMask(*bitmap,(int) *paletteIndex);
+ wxMask * Result = new EwxMask(*bitmap,*paletteIndex);
newPtr((void *) Result, 1, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxMask");
break;
@@ -9365,7 +9400,7 @@ case wxMask_Create_2_0: { // wxMask::Create
wxBitmap *bitmap = (wxBitmap *) getPtr(bp,memenv); bp += 4;
int * paletteIndex = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(*bitmap,(int) *paletteIndex);
+ bool Result = This->Create(*bitmap,*paletteIndex);
rt.addBool(Result);
break;
}
@@ -9392,7 +9427,7 @@ case wxImage_new_3_0: { // wxImage::wxImage
clear = *(bool *) bp; bp += 4;
} break;
}};
- wxImage * Result = new EwxImage((int) *width,(int) *height,clear);
+ wxImage * Result = new EwxImage(*width,*height,clear);
newPtr((void *) Result, 1, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxImage");
break;
@@ -9408,7 +9443,7 @@ case wxImage_new_4: { // wxImage::wxImage
} break;
}};
if(!static_data) {data = (unsigned char *) malloc(Ecmd.bin[0]->size);memcpy(data,Ecmd.bin[0]->base,Ecmd.bin[0]->size);};
- wxImage * Result = new EwxImage((int) *width,(int) *height,data,static_data);
+ wxImage * Result = new EwxImage(*width,*height,data,static_data);
newPtr((void *) Result, 1, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxImage");
break;
@@ -9425,7 +9460,7 @@ case wxImage_new_5: { // wxImage::wxImage
} break;
}};
if(!static_data) { data = (unsigned char *) malloc(Ecmd.bin[0]->size); alpha = (unsigned char *) malloc(Ecmd.bin[1]->size); memcpy(data,Ecmd.bin[0]->base,Ecmd.bin[0]->size); memcpy(alpha,Ecmd.bin[1]->base,Ecmd.bin[1]->size);};
- wxImage * Result = new EwxImage((int) *width,(int) *height,data,alpha,static_data);
+ wxImage * Result = new EwxImage(*width,*height,data,alpha,static_data);
newPtr((void *) Result, 1, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxImage");
break;
@@ -9471,7 +9506,7 @@ case wxImage_Blur: { // wxImage::Blur
wxImage *This = (wxImage *) getPtr(bp,memenv); bp += 4;
int * radius = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxImage * Result = new wxImage(This->Blur((int) *radius)); newPtr((void *) Result,3, memenv);;
+ wxImage * Result = new wxImage(This->Blur(*radius)); newPtr((void *) Result,3, memenv);;
rt.addRef(getRef((void *)Result,memenv), "wxImage");
break;
}
@@ -9479,7 +9514,7 @@ case wxImage_BlurHorizontal: { // wxImage::BlurHorizontal
wxImage *This = (wxImage *) getPtr(bp,memenv); bp += 4;
int * radius = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxImage * Result = new wxImage(This->BlurHorizontal((int) *radius)); newPtr((void *) Result,3, memenv);;
+ wxImage * Result = new wxImage(This->BlurHorizontal(*radius)); newPtr((void *) Result,3, memenv);;
rt.addRef(getRef((void *)Result,memenv), "wxImage");
break;
}
@@ -9487,7 +9522,7 @@ case wxImage_BlurVertical: { // wxImage::BlurVertical
wxImage *This = (wxImage *) getPtr(bp,memenv); bp += 4;
int * radius = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxImage * Result = new wxImage(This->BlurVertical((int) *radius)); newPtr((void *) Result,3, memenv);;
+ wxImage * Result = new wxImage(This->BlurVertical(*radius)); newPtr((void *) Result,3, memenv);;
rt.addRef(getRef((void *)Result,memenv), "wxImage");
break;
}
@@ -9536,7 +9571,7 @@ case wxImage_ConvertToMono: { // wxImage::ConvertToMono
unsigned int * g = (unsigned int *) bp; bp += 4;
unsigned int * b = (unsigned int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxImage * Result = new wxImage(This->ConvertToMono((char) *r,(char) *g,(char) *b)); newPtr((void *) Result,3, memenv);;
+ wxImage * Result = new wxImage(This->ConvertToMono(*r,*g,*b)); newPtr((void *) Result,3, memenv);;
rt.addRef(getRef((void *)Result,memenv), "wxImage");
break;
}
@@ -9559,7 +9594,7 @@ case wxImage_Create_3: { // wxImage::Create
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create((int) *width,(int) *height,clear);
+ bool Result = This->Create(*width,*height,clear);
rt.addBool(Result);
break;
}
@@ -9577,7 +9612,7 @@ case wxImage_Create_4: { // wxImage::Create
}};
if(!static_data) {data = (unsigned char *) malloc(Ecmd.bin[0]->size);memcpy(data,Ecmd.bin[0]->base,Ecmd.bin[0]->size);};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create((int) *width,(int) *height,data,static_data);
+ bool Result = This->Create(*width,*height,data,static_data);
rt.addBool(Result);
break;
}
@@ -9596,7 +9631,7 @@ case wxImage_Create_5: { // wxImage::Create
}};
if(!static_data) { data = (unsigned char *) malloc(Ecmd.bin[0]->size); alpha = (unsigned char *) malloc(Ecmd.bin[1]->size); memcpy(data,Ecmd.bin[0]->base,Ecmd.bin[0]->size); memcpy(alpha,Ecmd.bin[1]->base,Ecmd.bin[1]->size);};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create((int) *width,(int) *height,data,alpha,static_data);
+ bool Result = This->Create(*width,*height,data,alpha,static_data);
rt.addBool(Result);
break;
}
@@ -9645,7 +9680,7 @@ case wxImage_GetAlpha_2: { // wxImage::GetAlpha
int * x = (int *) bp; bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- char Result = This->GetAlpha((int) *x,(int) *y);
+ char Result = This->GetAlpha(*x,*y);
rt.addUint(Result);
break;
}
@@ -9663,7 +9698,7 @@ case wxImage_GetBlue: { // wxImage::GetBlue
int * x = (int *) bp; bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- char Result = This->GetBlue((int) *x,(int) *y);
+ char Result = This->GetBlue(*x,*y);
rt.addUint(Result);
break;
}
@@ -9681,18 +9716,18 @@ case wxImage_GetGreen: { // wxImage::GetGreen
int * x = (int *) bp; bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- char Result = This->GetGreen((int) *x,(int) *y);
+ char Result = This->GetGreen(*x,*y);
rt.addUint(Result);
break;
}
case wxImage_GetImageCount: { // wxImage::GetImageCount
- long type=wxBITMAP_TYPE_ANY;
+ wxBitmapType type=wxBITMAP_TYPE_ANY;
int * nameLen = (int *) bp; bp += 4;
wxString name = wxString(bp, wxConvUTF8);
bp += *nameLen+((8-((4+ *nameLen) & 7)) & 7);
while( * (int*) bp) { switch (* (int*) bp) {
case 1: {bp += 4;
- type = (long)*(int *) bp; bp += 4;
+type = *(wxBitmapType *) bp; bp += 4;;
} break;
}};
int Result = wxImage::GetImageCount(name,type);
@@ -9753,7 +9788,7 @@ case wxImage_GetRed: { // wxImage::GetRed
int * x = (int *) bp; bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- char Result = This->GetRed((int) *x,(int) *y);
+ char Result = This->GetRed(*x,*y);
rt.addUint(Result);
break;
}
@@ -9842,7 +9877,7 @@ case wxImage_IsTransparent: { // wxImage::IsTransparent
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->IsTransparent((int) *x,(int) *y,threshold);
+ bool Result = This->IsTransparent(*x,*y,threshold);
rt.addBool(Result);
break;
}
@@ -9923,22 +9958,22 @@ case wxImage_Replace: { // wxImage::Replace
unsigned int * g2 = (unsigned int *) bp; bp += 4;
unsigned int * b2 = (unsigned int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->Replace((char) *r1,(char) *g1,(char) *b1,(char) *r2,(char) *g2,(char) *b2);
+ This->Replace(*r1,*g1,*b1,*r2,*g2,*b2);
break;
}
case wxImage_Rescale: { // wxImage::Rescale
- int quality=wxIMAGE_QUALITY_NORMAL;
+ wxImageResizeQuality quality=wxIMAGE_QUALITY_NORMAL;
wxImage *This = (wxImage *) getPtr(bp,memenv); bp += 4;
int * width = (int *) bp; bp += 4;
int * height = (int *) bp; bp += 4;
bp += 4; /* Align */
while( * (int*) bp) { switch (* (int*) bp) {
case 1: {bp += 4;
- quality = (int)*(int *) bp; bp += 4;
+quality = *(wxImageResizeQuality *) bp; bp += 4;;
} break;
}};
if(!This) throw wxe_badarg(0);
- wxImage * Result = &This->Rescale((int) *width,(int) *height,quality);
+ wxImage * Result = &This->Rescale(*width,*height,quality);
rt.addRef(getRef((void *)Result,memenv), "wxImage");
break;
}
@@ -9991,7 +10026,7 @@ case wxImage_Rotate: { // wxImage::Rotate
} break;
}};
if(!This) throw wxe_badarg(0);
- wxImage * Result = new wxImage(This->Rotate((double) *angle,centre_of_rotation,interpolating,offset_after_rotation)); newPtr((void *) Result,3, memenv);;
+ wxImage * Result = new wxImage(This->Rotate(*angle,centre_of_rotation,interpolating,offset_after_rotation)); newPtr((void *) Result,3, memenv);;
rt.addRef(getRef((void *)Result,memenv), "wxImage");
break;
}
@@ -10000,7 +10035,7 @@ case wxImage_RotateHue: { // wxImage::RotateHue
bp += 4; /* Align */
double * angle = (double *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->RotateHue((double) *angle);
+ This->RotateHue(*angle);
break;
}
case wxImage_Rotate90: { // wxImage::Rotate90
@@ -10034,7 +10069,7 @@ case wxImage_SaveFile_2_0: { // wxImage::SaveFile
bp += *nameLen+((8-((0+ *nameLen) & 7)) & 7);
int * type = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->SaveFile(name,(int) *type);
+ bool Result = This->SaveFile(name,*type);
rt.addBool(Result);
break;
}
@@ -10052,18 +10087,18 @@ case wxImage_SaveFile_2_1: { // wxImage::SaveFile
break;
}
case wxImage_Scale: { // wxImage::Scale
- int quality=wxIMAGE_QUALITY_NORMAL;
+ wxImageResizeQuality quality=wxIMAGE_QUALITY_NORMAL;
wxImage *This = (wxImage *) getPtr(bp,memenv); bp += 4;
int * width = (int *) bp; bp += 4;
int * height = (int *) bp; bp += 4;
bp += 4; /* Align */
while( * (int*) bp) { switch (* (int*) bp) {
case 1: {bp += 4;
- quality = (int)*(int *) bp; bp += 4;
+quality = *(wxImageResizeQuality *) bp; bp += 4;;
} break;
}};
if(!This) throw wxe_badarg(0);
- wxImage * Result = new wxImage(This->Scale((int) *width,(int) *height,quality)); newPtr((void *) Result,3, memenv);;
+ wxImage * Result = new wxImage(This->Scale(*width,*height,quality)); newPtr((void *) Result,3, memenv);;
rt.addRef(getRef((void *)Result,memenv), "wxImage");
break;
}
@@ -10101,7 +10136,7 @@ case wxImage_SetAlpha_3: { // wxImage::SetAlpha
int * y = (int *) bp; bp += 4;
unsigned int * alpha = (unsigned int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetAlpha((int) *x,(int) *y,(char) *alpha);
+ This->SetAlpha(*x,*y,*alpha);
break;
}
case wxImage_SetAlpha_2: { // wxImage::SetAlpha
@@ -10148,7 +10183,7 @@ case wxImage_SetData_4: { // wxImage::SetData
}};
if(!static_data) {data = (unsigned char *) malloc(Ecmd.bin[0]->size);memcpy(data,Ecmd.bin[0]->base,Ecmd.bin[0]->size);};
if(!This) throw wxe_badarg(0);
- This->SetData(data,(int) *new_width,(int) *new_height,static_data);
+ This->SetData(data,*new_width,*new_height,static_data);
break;
}
case wxImage_SetMask: { // wxImage::SetMask
@@ -10170,7 +10205,7 @@ case wxImage_SetMaskColour: { // wxImage::SetMaskColour
unsigned int * g = (unsigned int *) bp; bp += 4;
unsigned int * b = (unsigned int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetMaskColour((char) *r,(char) *g,(char) *b);
+ This->SetMaskColour(*r,*g,*b);
break;
}
case wxImage_SetMaskFromImage: { // wxImage::SetMaskFromImage
@@ -10180,7 +10215,7 @@ case wxImage_SetMaskFromImage: { // wxImage::SetMaskFromImage
unsigned int * mg = (unsigned int *) bp; bp += 4;
unsigned int * mb = (unsigned int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->SetMaskFromImage(*mask,(char) *mr,(char) *mg,(char) *mb);
+ bool Result = This->SetMaskFromImage(*mask,*mr,*mg,*mb);
rt.addBool(Result);
break;
}
@@ -10203,7 +10238,7 @@ case wxImage_SetOption_2_0: { // wxImage::SetOption
bp += *nameLen+((8-((0+ *nameLen) & 7)) & 7);
int * value = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetOption(name,(int) *value);
+ This->SetOption(name,*value);
break;
}
case wxImage_SetPalette: { // wxImage::SetPalette
@@ -10221,7 +10256,7 @@ case wxImage_SetRGB_5: { // wxImage::SetRGB
unsigned int * g = (unsigned int *) bp; bp += 4;
unsigned int * b = (unsigned int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetRGB((int) *x,(int) *y,(char) *r,(char) *g,(char) *b);
+ This->SetRGB(*x,*y,*r,*g,*b);
break;
}
case wxImage_SetRGB_4: { // wxImage::SetRGB
@@ -10235,7 +10270,7 @@ case wxImage_SetRGB_4: { // wxImage::SetRGB
unsigned int * g = (unsigned int *) bp; bp += 4;
unsigned int * b = (unsigned int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetRGB(rect,(char) *r,(char) *g,(char) *b);
+ This->SetRGB(rect,*r,*g,*b);
break;
}
case wxBrush_new_0: { // wxBrush::wxBrush
@@ -10271,8 +10306,8 @@ case wxBrush_new_1: { // wxBrush::wxBrush
case wxBrush_GetColour: { // wxBrush::GetColour
wxBrush *This = (wxBrush *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- wxColour * Result = &This->GetColour();
- rt.add((*Result));
+ wxColour Result = This->GetColour();
+ rt.add(Result);
break;
}
case wxBrush_GetStipple: { // wxBrush::GetStipple
@@ -10320,7 +10355,7 @@ case wxBrush_SetColour_3: { // wxBrush::SetColour
unsigned int * g = (unsigned int *) bp; bp += 4;
unsigned int * b = (unsigned int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetColour((char) *r,(char) *g,(char) *b);
+ This->SetColour(*r,*g,*b);
break;
}
case wxBrush_SetStipple: { // wxBrush::SetStipple
@@ -10334,7 +10369,7 @@ case wxBrush_SetStyle: { // wxBrush::SetStyle
wxBrush *This = (wxBrush *) getPtr(bp,memenv); bp += 4;
int * style = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetStyle((int) *style);
+ This->SetStyle(*style);
break;
}
case wxPen_new_0: { // wxPen::wxPen
@@ -10374,8 +10409,8 @@ case wxPen_GetCap: { // wxPen::GetCap
case wxPen_GetColour: { // wxPen::GetColour
wxPen *This = (wxPen *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- wxColour * Result = &This->GetColour();
- rt.add((*Result));
+ wxColour Result = This->GetColour();
+ rt.add(Result);
break;
}
case wxPen_GetJoin: { // wxPen::GetJoin
@@ -10408,9 +10443,9 @@ case wxPen_IsOk: { // wxPen::IsOk
}
case wxPen_SetCap: { // wxPen::SetCap
wxPen *This = (wxPen *) getPtr(bp,memenv); bp += 4;
- int * capStyle = (int *) bp; bp += 4;
+ wxPenCap capStyle = *(wxPenCap *) bp; bp += 4;;
if(!This) throw wxe_badarg(0);
- This->SetCap((int) *capStyle);
+ This->SetCap(capStyle);
break;
}
case wxPen_SetColour_1: { // wxPen::SetColour
@@ -10430,28 +10465,28 @@ case wxPen_SetColour_3: { // wxPen::SetColour
unsigned int * green = (unsigned int *) bp; bp += 4;
unsigned int * blue = (unsigned int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetColour((char) *red,(char) *green,(char) *blue);
+ This->SetColour(*red,*green,*blue);
break;
}
case wxPen_SetJoin: { // wxPen::SetJoin
wxPen *This = (wxPen *) getPtr(bp,memenv); bp += 4;
- int * joinStyle = (int *) bp; bp += 4;
+ wxPenJoin joinStyle = *(wxPenJoin *) bp; bp += 4;;
if(!This) throw wxe_badarg(0);
- This->SetJoin((int) *joinStyle);
+ This->SetJoin(joinStyle);
break;
}
case wxPen_SetStyle: { // wxPen::SetStyle
wxPen *This = (wxPen *) getPtr(bp,memenv); bp += 4;
int * style = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetStyle((int) *style);
+ This->SetStyle(*style);
break;
}
case wxPen_SetWidth: { // wxPen::SetWidth
wxPen *This = (wxPen *) getPtr(bp,memenv); bp += 4;
int * width = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetWidth((int) *width);
+ This->SetWidth(*width);
break;
}
case wxRegion_new_0: { // wxRegion::wxRegion
@@ -10465,7 +10500,7 @@ case wxRegion_new_4: { // wxRegion::wxRegion
int * y = (int *) bp; bp += 4;
int * w = (int *) bp; bp += 4;
int * h = (int *) bp; bp += 4;
- wxRegion * Result = new EwxRegion((wxCoord) *x,(wxCoord) *y,(wxCoord) *w,(wxCoord) *h);
+ wxRegion * Result = new EwxRegion(*x,*y,*w,*h);
newPtr((void *) Result, 1, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxRegion");
break;
@@ -10511,7 +10546,7 @@ case wxRegion_Contains_2: { // wxRegion::Contains
int * x = (int *) bp; bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->Contains((wxCoord) *x,(wxCoord) *y);
+ int Result = This->Contains(*x,*y);
rt.addInt(Result);
break;
}
@@ -10532,7 +10567,7 @@ case wxRegion_Contains_4: { // wxRegion::Contains
int * w = (int *) bp; bp += 4;
int * h = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->Contains((wxCoord) *x,(wxCoord) *y,(wxCoord) *w,(wxCoord) *h);
+ int Result = This->Contains(*x,*y,*w,*h);
rt.addInt(Result);
break;
}
@@ -10569,7 +10604,7 @@ case wxRegion_Intersect_4: { // wxRegion::Intersect
int * w = (int *) bp; bp += 4;
int * h = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->Intersect((wxCoord) *x,(wxCoord) *y,(wxCoord) *w,(wxCoord) *h);
+ bool Result = This->Intersect(*x,*y,*w,*h);
rt.addBool(Result);
break;
}
@@ -10607,7 +10642,7 @@ case wxRegion_Subtract_4: { // wxRegion::Subtract
int * w = (int *) bp; bp += 4;
int * h = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->Subtract((wxCoord) *x,(wxCoord) *y,(wxCoord) *w,(wxCoord) *h);
+ bool Result = This->Subtract(*x,*y,*w,*h);
rt.addBool(Result);
break;
}
@@ -10636,7 +10671,7 @@ case wxRegion_Offset_2: { // wxRegion::Offset
int * x = (int *) bp; bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->Offset((wxCoord) *x,(wxCoord) *y);
+ bool Result = This->Offset(*x,*y);
rt.addBool(Result);
break;
}
@@ -10657,7 +10692,7 @@ case wxRegion_Union_4: { // wxRegion::Union
int * w = (int *) bp; bp += 4;
int * h = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->Union((wxCoord) *x,(wxCoord) *y,(wxCoord) *w,(wxCoord) *h);
+ bool Result = This->Union(*x,*y,*w,*h);
rt.addBool(Result);
break;
}
@@ -10715,7 +10750,7 @@ case wxRegion_Xor_4: { // wxRegion::Xor
int * w = (int *) bp; bp += 4;
int * h = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->Xor((wxCoord) *x,(wxCoord) *y,(wxCoord) *w,(wxCoord) *h);
+ bool Result = This->Xor(*x,*y,*w,*h);
rt.addBool(Result);
break;
}
@@ -10751,7 +10786,7 @@ case wxAcceleratorTable_new_2: { // wxAcceleratorTable::wxAcceleratorTable
wxAcceleratorEntry *entries;
entries = (wxAcceleratorEntry *) driver_alloc(sizeof(wxAcceleratorEntry) * *entriesLen); for(int i=0; i < *entriesLen; i++) { entries[i] = * (wxAcceleratorEntry *) getPtr(bp,memenv); bp += 4;}
bp += ((0+ *entriesLen)%2 )*4;
- wxAcceleratorTable * Result = new EwxAcceleratorTable((int) *n,entries);
+ wxAcceleratorTable * Result = new EwxAcceleratorTable(*n,entries);
newPtr((void *) Result, 1, memenv);
driver_free(entries);
rt.addRef(getRef((void *)Result,memenv), "wxAcceleratorTable");
@@ -10828,7 +10863,7 @@ item = (wxMenuItem *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- This->Set((int) *flags,(int) *keyCode,(int) *cmd,item);
+ This->Set(*flags,*keyCode,*cmd,item);
break;
}
case wxAcceleratorEntry_destroy: { // wxAcceleratorEntry::destroy
@@ -10841,7 +10876,7 @@ case wxCaret_new_3: { // wxCaret::wxCaret
wxWindow *window = (wxWindow *) getPtr(bp,memenv); bp += 4;
int * width = (int *) bp; bp += 4;
int * height = (int *) bp; bp += 4;
- wxCaret * Result = new EwxCaret(window,(int) *width,(int) *height);
+ wxCaret * Result = new EwxCaret(window,*width,*height);
newPtr((void *) Result, 70, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxCaret");
break;
@@ -10868,7 +10903,7 @@ case wxCaret_Create_3: { // wxCaret::Create
int * width = (int *) bp; bp += 4;
int * height = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(window,(int) *width,(int) *height);
+ bool Result = This->Create(window,*width,*height);
rt.addBool(Result);
break;
}
@@ -10934,7 +10969,7 @@ case wxCaret_Move_2: { // wxCaret::Move
int * x = (int *) bp; bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->Move((int) *x,(int) *y);
+ This->Move(*x,*y);
break;
}
case wxCaret_Move_1: { // wxCaret::Move
@@ -10948,7 +10983,7 @@ case wxCaret_Move_1: { // wxCaret::Move
}
case wxCaret_SetBlinkTime: { // wxCaret::SetBlinkTime
int * milliseconds = (int *) bp; bp += 4;
- wxCaret::SetBlinkTime((int) *milliseconds);
+ wxCaret::SetBlinkTime(*milliseconds);
break;
}
case wxCaret_SetSize_2: { // wxCaret::SetSize
@@ -10956,7 +10991,7 @@ case wxCaret_SetSize_2: { // wxCaret::SetSize
int * width = (int *) bp; bp += 4;
int * height = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetSize((int) *width,(int) *height);
+ This->SetSize(*width,*height);
break;
}
case wxCaret_SetSize_1: { // wxCaret::SetSize
@@ -11057,7 +11092,7 @@ userData = (wxObject *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- wxSizerItem * Result = (wxSizerItem*)This->Add((int) *width,(int) *height,proportion,flag,border,userData);
+ wxSizerItem * Result = (wxSizerItem*)This->Add(*width,*height,proportion,flag,border,userData);
rt.addRef(getRef((void *)Result,memenv), "wxSizerItem");
break;
}
@@ -11083,7 +11118,7 @@ case wxSizer_AddSpacer: { // wxSizer::AddSpacer
wxSizer *This = (wxSizer *) getPtr(bp,memenv); bp += 4;
int * size = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxSizerItem * Result = (wxSizerItem*)This->AddSpacer((int) *size);
+ wxSizerItem * Result = (wxSizerItem*)This->AddSpacer(*size);
rt.addRef(getRef((void *)Result,memenv), "wxSizerItem");
break;
}
@@ -11141,7 +11176,7 @@ case wxSizer_Detach_1_0: { // wxSizer::Detach
wxSizer *This = (wxSizer *) getPtr(bp,memenv); bp += 4;
int * index = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->Detach((int) *index);
+ bool Result = This->Detach(*index);
rt.addBool(Result);
break;
}
@@ -11203,7 +11238,7 @@ case wxSizer_GetItem_1: { // wxSizer::GetItem
wxSizer *This = (wxSizer *) getPtr(bp,memenv); bp += 4;
int * index = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxSizerItem * Result = (wxSizerItem*)This->GetItem((size_t) *index);
+ wxSizerItem * Result = (wxSizerItem*)This->GetItem(*index);
rt.addRef(getRef((void *)Result,memenv), "wxSizerItem");
break;
}
@@ -11260,7 +11295,7 @@ case wxSizer_Hide_1: { // wxSizer::Hide
wxSizer *This = (wxSizer *) getPtr(bp,memenv); bp += 4;
int * index = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->Hide((size_t) *index);
+ bool Result = This->Hide(*index);
rt.addBool(Result);
break;
}
@@ -11288,7 +11323,7 @@ userData = (wxObject *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- wxSizerItem * Result = (wxSizerItem*)This->Insert((size_t) *index,window,proportion,flag,border,userData);
+ wxSizerItem * Result = (wxSizerItem*)This->Insert(*index,window,proportion,flag,border,userData);
rt.addRef(getRef((void *)Result,memenv), "wxSizerItem");
break;
}
@@ -11316,7 +11351,7 @@ userData = (wxObject *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- wxSizerItem * Result = (wxSizerItem*)This->Insert((size_t) *index,sizer,proportion,flag,border,userData);
+ wxSizerItem * Result = (wxSizerItem*)This->Insert(*index,sizer,proportion,flag,border,userData);
rt.addRef(getRef((void *)Result,memenv), "wxSizerItem");
break;
}
@@ -11344,7 +11379,7 @@ userData = (wxObject *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- wxSizerItem * Result = (wxSizerItem*)This->Insert((size_t) *index,(int) *width,(int) *height,proportion,flag,border,userData);
+ wxSizerItem * Result = (wxSizerItem*)This->Insert(*index,*width,*height,proportion,flag,border,userData);
rt.addRef(getRef((void *)Result,memenv), "wxSizerItem");
break;
}
@@ -11354,7 +11389,7 @@ case wxSizer_Insert_3_3: { // wxSizer::Insert
wxWindow * window = (wxWindow *) getPtr(bp,memenv); bp += 4;
wxSizerFlags *flags = (wxSizerFlags *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- wxSizerItem * Result = (wxSizerItem*)This->Insert((size_t) *index,window,*flags);
+ wxSizerItem * Result = (wxSizerItem*)This->Insert(*index,window,*flags);
rt.addRef(getRef((void *)Result,memenv), "wxSizerItem");
break;
}
@@ -11364,7 +11399,7 @@ case wxSizer_Insert_3_2: { // wxSizer::Insert
wxSizer *sizer = (wxSizer *) getPtr(bp,memenv); bp += 4;
wxSizerFlags *flags = (wxSizerFlags *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- wxSizerItem * Result = (wxSizerItem*)This->Insert((size_t) *index,sizer,*flags);
+ wxSizerItem * Result = (wxSizerItem*)This->Insert(*index,sizer,*flags);
rt.addRef(getRef((void *)Result,memenv), "wxSizerItem");
break;
}
@@ -11373,7 +11408,7 @@ case wxSizer_Insert_2: { // wxSizer::Insert
int * index = (int *) bp; bp += 4;
wxSizerItem *item = (wxSizerItem *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- wxSizerItem * Result = (wxSizerItem*)This->Insert((size_t) *index,item);
+ wxSizerItem * Result = (wxSizerItem*)This->Insert(*index,item);
rt.addRef(getRef((void *)Result,memenv), "wxSizerItem");
break;
}
@@ -11382,7 +11417,7 @@ case wxSizer_InsertSpacer: { // wxSizer::InsertSpacer
int * index = (int *) bp; bp += 4;
int * size = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxSizerItem * Result = (wxSizerItem*)This->InsertSpacer((size_t) *index,(int) *size);
+ wxSizerItem * Result = (wxSizerItem*)This->InsertSpacer(*index,*size);
rt.addRef(getRef((void *)Result,memenv), "wxSizerItem");
break;
}
@@ -11396,7 +11431,7 @@ case wxSizer_InsertStretchSpacer: { // wxSizer::InsertStretchSpacer
} break;
}};
if(!This) throw wxe_badarg(0);
- wxSizerItem * Result = (wxSizerItem*)This->InsertStretchSpacer((size_t) *index,prop);
+ wxSizerItem * Result = (wxSizerItem*)This->InsertStretchSpacer(*index,prop);
rt.addRef(getRef((void *)Result,memenv), "wxSizerItem");
break;
}
@@ -11420,7 +11455,7 @@ case wxSizer_IsShown_1_0: { // wxSizer::IsShown
wxSizer *This = (wxSizer *) getPtr(bp,memenv); bp += 4;
int * index = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->IsShown((size_t) *index);
+ bool Result = This->IsShown(*index);
rt.addBool(Result);
break;
}
@@ -11506,7 +11541,7 @@ userData = (wxObject *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- wxSizerItem * Result = (wxSizerItem*)This->Prepend((int) *width,(int) *height,proportion,flag,border,userData);
+ wxSizerItem * Result = (wxSizerItem*)This->Prepend(*width,*height,proportion,flag,border,userData);
rt.addRef(getRef((void *)Result,memenv), "wxSizerItem");
break;
}
@@ -11540,7 +11575,7 @@ case wxSizer_PrependSpacer: { // wxSizer::PrependSpacer
wxSizer *This = (wxSizer *) getPtr(bp,memenv); bp += 4;
int * size = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxSizerItem * Result = (wxSizerItem*)This->PrependSpacer((int) *size);
+ wxSizerItem * Result = (wxSizerItem*)This->PrependSpacer(*size);
rt.addRef(getRef((void *)Result,memenv), "wxSizerItem");
break;
}
@@ -11576,7 +11611,7 @@ case wxSizer_Remove_1_0: { // wxSizer::Remove
wxSizer *This = (wxSizer *) getPtr(bp,memenv); bp += 4;
int * index = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->Remove((int) *index);
+ bool Result = This->Remove(*index);
rt.addBool(Result);
break;
}
@@ -11617,7 +11652,7 @@ case wxSizer_Replace_2: { // wxSizer::Replace
int * index = (int *) bp; bp += 4;
wxSizerItem *newitem = (wxSizerItem *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->Replace((size_t) *index,newitem);
+ bool Result = This->Replace(*index,newitem);
rt.addBool(Result);
break;
}
@@ -11628,7 +11663,7 @@ case wxSizer_SetDimension: { // wxSizer::SetDimension
int * width = (int *) bp; bp += 4;
int * height = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetDimension((int) *x,(int) *y,(int) *width,(int) *height);
+ This->SetDimension(*x,*y,*width,*height);
break;
}
case wxSizer_SetMinSize_2: { // wxSizer::SetMinSize
@@ -11636,7 +11671,7 @@ case wxSizer_SetMinSize_2: { // wxSizer::SetMinSize
int * width = (int *) bp; bp += 4;
int * height = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetMinSize((int) *width,(int) *height);
+ This->SetMinSize(*width,*height);
break;
}
case wxSizer_SetMinSize_1: { // wxSizer::SetMinSize
@@ -11654,7 +11689,7 @@ case wxSizer_SetItemMinSize_3_2: { // wxSizer::SetItemMinSize
int * width = (int *) bp; bp += 4;
int * height = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->SetItemMinSize(window,(int) *width,(int) *height);
+ bool Result = This->SetItemMinSize(window,*width,*height);
rt.addBool(Result);
break;
}
@@ -11675,7 +11710,7 @@ case wxSizer_SetItemMinSize_3_1: { // wxSizer::SetItemMinSize
int * width = (int *) bp; bp += 4;
int * height = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->SetItemMinSize(sizer,(int) *width,(int) *height);
+ bool Result = This->SetItemMinSize(sizer,*width,*height);
rt.addBool(Result);
break;
}
@@ -11696,7 +11731,7 @@ case wxSizer_SetItemMinSize_3_0: { // wxSizer::SetItemMinSize
int * width = (int *) bp; bp += 4;
int * height = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->SetItemMinSize((size_t) *index,(int) *width,(int) *height);
+ bool Result = This->SetItemMinSize(*index,*width,*height);
rt.addBool(Result);
break;
}
@@ -11707,7 +11742,7 @@ case wxSizer_SetItemMinSize_2_0: { // wxSizer::SetItemMinSize
int * sizeH = (int *) bp; bp += 4;
wxSize size = wxSize(*sizeW,*sizeH);
if(!This) throw wxe_badarg(0);
- bool Result = This->SetItemMinSize((size_t) *index,size);
+ bool Result = This->SetItemMinSize(*index,size);
rt.addBool(Result);
break;
}
@@ -11771,7 +11806,7 @@ case wxSizer_Show_2_0: { // wxSizer::Show
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Show((size_t) *index,show);
+ bool Result = This->Show(*index,show);
rt.addBool(Result);
break;
}
@@ -11779,7 +11814,7 @@ case wxSizer_Show_1: { // wxSizer::Show
wxSizer *This = (wxSizer *) getPtr(bp,memenv); bp += 4;
bool * show = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->Show((bool) *show);
+ This->Show(*show);
break;
}
case wxSizerFlags_new: { // wxSizerFlags::wxSizerFlags
@@ -11798,7 +11833,7 @@ case wxSizerFlags_Align: { // wxSizerFlags::Align
wxSizerFlags *This = (wxSizerFlags *) getPtr(bp,memenv); bp += 4;
int * alignment = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxSizerFlags * Result = &This->Align((int) *alignment);
+ wxSizerFlags * Result = &This->Align(*alignment);
rt.addRef(getRef((void *)Result,memenv), "wxSizerFlags");
break;
}
@@ -11807,7 +11842,7 @@ case wxSizerFlags_Border_2: { // wxSizerFlags::Border
int * direction = (int *) bp; bp += 4;
int * borderInPixels = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxSizerFlags * Result = &This->Border((int) *direction,(int) *borderInPixels);
+ wxSizerFlags * Result = &This->Border(*direction,*borderInPixels);
rt.addRef(getRef((void *)Result,memenv), "wxSizerFlags");
break;
}
@@ -11857,7 +11892,7 @@ case wxSizerFlags_Proportion: { // wxSizerFlags::Proportion
wxSizerFlags *This = (wxSizerFlags *) getPtr(bp,memenv); bp += 4;
int * proportion = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxSizerFlags * Result = &This->Proportion((int) *proportion);
+ wxSizerFlags * Result = &This->Proportion(*proportion);
rt.addRef(getRef((void *)Result,memenv), "wxSizerFlags");
break;
}
@@ -11880,7 +11915,7 @@ case wxSizerItem_new_5_1: { // wxSizerItem::wxSizerItem
int * flag = (int *) bp; bp += 4;
int * border = (int *) bp; bp += 4;
wxObject *userData = (wxObject *) getPtr(bp,memenv); bp += 4;
- wxSizerItem * Result = new EwxSizerItem(window,(int) *proportion,(int) *flag,(int) *border,userData);
+ wxSizerItem * Result = new EwxSizerItem(window,*proportion,*flag,*border,userData);
newPtr((void *) Result, 1, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxSizerItem");
break;
@@ -11899,7 +11934,7 @@ case wxSizerItem_new_5_0: { // wxSizerItem::wxSizerItem
int * flag = (int *) bp; bp += 4;
int * border = (int *) bp; bp += 4;
wxObject *userData = (wxObject *) getPtr(bp,memenv); bp += 4;
- wxSizerItem * Result = new EwxSizerItem(sizer,(int) *proportion,(int) *flag,(int) *border,userData);
+ wxSizerItem * Result = new EwxSizerItem(sizer,*proportion,*flag,*border,userData);
newPtr((void *) Result, 1, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxSizerItem");
break;
@@ -11919,7 +11954,7 @@ case wxSizerItem_new_6: { // wxSizerItem::wxSizerItem
int * flag = (int *) bp; bp += 4;
int * border = (int *) bp; bp += 4;
wxObject *userData = (wxObject *) getPtr(bp,memenv); bp += 4;
- wxSizerItem * Result = new EwxSizerItem((int) *width,(int) *height,(int) *proportion,(int) *flag,(int) *border,userData);
+ wxSizerItem * Result = new EwxSizerItem(*width,*height,*proportion,*flag,*border,userData);
newPtr((void *) Result, 1, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxSizerItem");
break;
@@ -11928,7 +11963,7 @@ case wxSizerItem_new_3: { // wxSizerItem::wxSizerItem
int * width = (int *) bp; bp += 4;
int * height = (int *) bp; bp += 4;
wxSizerFlags *flags = (wxSizerFlags *) getPtr(bp,memenv); bp += 4;
- wxSizerItem * Result = new EwxSizerItem((int) *width,(int) *height,*flags);
+ wxSizerItem * Result = new EwxSizerItem(*width,*height,*flags);
newPtr((void *) Result, 1, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxSizerItem");
break;
@@ -12074,7 +12109,7 @@ case wxSizerItem_SetBorder: { // wxSizerItem::SetBorder
wxSizerItem *This = (wxSizerItem *) getPtr(bp,memenv); bp += 4;
int * border = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetBorder((int) *border);
+ This->SetBorder(*border);
break;
}
case wxSizerItem_SetDimension: { // wxSizerItem::SetDimension
@@ -12093,7 +12128,7 @@ case wxSizerItem_SetFlag: { // wxSizerItem::SetFlag
wxSizerItem *This = (wxSizerItem *) getPtr(bp,memenv); bp += 4;
int * flag = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetFlag((int) *flag);
+ This->SetFlag(*flag);
break;
}
case wxSizerItem_SetInitSize: { // wxSizerItem::SetInitSize
@@ -12101,7 +12136,7 @@ case wxSizerItem_SetInitSize: { // wxSizerItem::SetInitSize
int * x = (int *) bp; bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetInitSize((int) *x,(int) *y);
+ This->SetInitSize(*x,*y);
break;
}
case wxSizerItem_SetMinSize_1: { // wxSizerItem::SetMinSize
@@ -12118,14 +12153,14 @@ case wxSizerItem_SetMinSize_2: { // wxSizerItem::SetMinSize
int * x = (int *) bp; bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetMinSize((int) *x,(int) *y);
+ This->SetMinSize(*x,*y);
break;
}
case wxSizerItem_SetProportion: { // wxSizerItem::SetProportion
wxSizerItem *This = (wxSizerItem *) getPtr(bp,memenv); bp += 4;
int * proportion = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetProportion((int) *proportion);
+ This->SetProportion(*proportion);
break;
}
case wxSizerItem_SetRatio_2: { // wxSizerItem::SetRatio
@@ -12133,7 +12168,7 @@ case wxSizerItem_SetRatio_2: { // wxSizerItem::SetRatio
int * width = (int *) bp; bp += 4;
int * height = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetRatio((int) *width,(int) *height);
+ This->SetRatio(*width,*height);
break;
}
case wxSizerItem_SetRatio_1_1: { // wxSizerItem::SetRatio
@@ -12149,7 +12184,7 @@ case wxSizerItem_SetRatio_1_0: { // wxSizerItem::SetRatio
wxSizerItem *This = (wxSizerItem *) getPtr(bp,memenv); bp += 4;
float * ratio = (float *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetRatio((float) *ratio);
+ This->SetRatio(*ratio);
break;
}
case wxSizerItem_SetSizer: { // wxSizerItem::SetSizer
@@ -12173,7 +12208,7 @@ case wxSizerItem_SetSpacer_2: { // wxSizerItem::SetSpacer
int * width = (int *) bp; bp += 4;
int * height = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetSpacer((int) *width,(int) *height);
+ This->SetSpacer(*width,*height);
break;
}
case wxSizerItem_SetWindow: { // wxSizerItem::SetWindow
@@ -12187,12 +12222,12 @@ case wxSizerItem_Show: { // wxSizerItem::Show
wxSizerItem *This = (wxSizerItem *) getPtr(bp,memenv); bp += 4;
bool * show = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->Show((bool) *show);
+ This->Show(*show);
break;
}
case wxBoxSizer_new: { // wxBoxSizer::wxBoxSizer
int * orient = (int *) bp; bp += 4;
- wxBoxSizer * Result = new EwxBoxSizer((int) *orient);
+ wxBoxSizer * Result = new EwxBoxSizer(*orient);
newPtr((void *) Result, 1, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxBoxSizer");
break;
@@ -12207,7 +12242,7 @@ case wxBoxSizer_GetOrientation: { // wxBoxSizer::GetOrientation
case wxStaticBoxSizer_new_2: { // wxStaticBoxSizer::wxStaticBoxSizer
wxStaticBox *box = (wxStaticBox *) getPtr(bp,memenv); bp += 4;
int * orient = (int *) bp; bp += 4;
- wxStaticBoxSizer * Result = new EwxStaticBoxSizer(box,(int) *orient);
+ wxStaticBoxSizer * Result = new EwxStaticBoxSizer(box,*orient);
newPtr((void *) Result, 1, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxStaticBoxSizer");
break;
@@ -12223,7 +12258,7 @@ case wxStaticBoxSizer_new_3: { // wxStaticBoxSizer::wxStaticBoxSizer
bp += *labelLen+((8-((0+ *labelLen) & 7)) & 7);
} break;
}};
- wxStaticBoxSizer * Result = new EwxStaticBoxSizer((int) *orient,win,label);
+ wxStaticBoxSizer * Result = new EwxStaticBoxSizer(*orient,win,label);
newPtr((void *) Result, 1, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxStaticBoxSizer");
break;
@@ -12240,7 +12275,7 @@ case wxGridSizer_new_4: { // wxGridSizer::wxGridSizer
int * cols = (int *) bp; bp += 4;
int * vgap = (int *) bp; bp += 4;
int * hgap = (int *) bp; bp += 4;
- wxGridSizer * Result = new EwxGridSizer((int) *rows,(int) *cols,(int) *vgap,(int) *hgap);
+ wxGridSizer * Result = new EwxGridSizer(*rows,*cols,*vgap,*hgap);
newPtr((void *) Result, 1, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxGridSizer");
break;
@@ -12258,7 +12293,7 @@ case wxGridSizer_new_2: { // wxGridSizer::wxGridSizer
hgap = (int)*(int *) bp; bp += 4;
} break;
}};
- wxGridSizer * Result = new EwxGridSizer((int) *cols,vgap,hgap);
+ wxGridSizer * Result = new EwxGridSizer(*cols,vgap,hgap);
newPtr((void *) Result, 1, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxGridSizer");
break;
@@ -12295,28 +12330,28 @@ case wxGridSizer_SetCols: { // wxGridSizer::SetCols
wxGridSizer *This = (wxGridSizer *) getPtr(bp,memenv); bp += 4;
int * cols = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetCols((int) *cols);
+ This->SetCols(*cols);
break;
}
case wxGridSizer_SetHGap: { // wxGridSizer::SetHGap
wxGridSizer *This = (wxGridSizer *) getPtr(bp,memenv); bp += 4;
int * gap = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetHGap((int) *gap);
+ This->SetHGap(*gap);
break;
}
case wxGridSizer_SetRows: { // wxGridSizer::SetRows
wxGridSizer *This = (wxGridSizer *) getPtr(bp,memenv); bp += 4;
int * rows = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetRows((int) *rows);
+ This->SetRows(*rows);
break;
}
case wxGridSizer_SetVGap: { // wxGridSizer::SetVGap
wxGridSizer *This = (wxGridSizer *) getPtr(bp,memenv); bp += 4;
int * gap = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetVGap((int) *gap);
+ This->SetVGap(*gap);
break;
}
case wxFlexGridSizer_new_4: { // wxFlexGridSizer::wxFlexGridSizer
@@ -12324,7 +12359,7 @@ case wxFlexGridSizer_new_4: { // wxFlexGridSizer::wxFlexGridSizer
int * cols = (int *) bp; bp += 4;
int * vgap = (int *) bp; bp += 4;
int * hgap = (int *) bp; bp += 4;
- wxFlexGridSizer * Result = new EwxFlexGridSizer((int) *rows,(int) *cols,(int) *vgap,(int) *hgap);
+ wxFlexGridSizer * Result = new EwxFlexGridSizer(*rows,*cols,*vgap,*hgap);
newPtr((void *) Result, 1, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxFlexGridSizer");
break;
@@ -12342,7 +12377,7 @@ case wxFlexGridSizer_new_2: { // wxFlexGridSizer::wxFlexGridSizer
hgap = (int)*(int *) bp; bp += 4;
} break;
}};
- wxFlexGridSizer * Result = new EwxFlexGridSizer((int) *cols,vgap,hgap);
+ wxFlexGridSizer * Result = new EwxFlexGridSizer(*cols,vgap,hgap);
newPtr((void *) Result, 1, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxFlexGridSizer");
break;
@@ -12357,7 +12392,7 @@ case wxFlexGridSizer_AddGrowableCol: { // wxFlexGridSizer::AddGrowableCol
} break;
}};
if(!This) throw wxe_badarg(0);
- This->AddGrowableCol((size_t) *idx,proportion);
+ This->AddGrowableCol(*idx,proportion);
break;
}
case wxFlexGridSizer_AddGrowableRow: { // wxFlexGridSizer::AddGrowableRow
@@ -12370,7 +12405,7 @@ case wxFlexGridSizer_AddGrowableRow: { // wxFlexGridSizer::AddGrowableRow
} break;
}};
if(!This) throw wxe_badarg(0);
- This->AddGrowableRow((size_t) *idx,proportion);
+ This->AddGrowableRow(*idx,proportion);
break;
}
case wxFlexGridSizer_GetFlexibleDirection: { // wxFlexGridSizer::GetFlexibleDirection
@@ -12391,28 +12426,28 @@ case wxFlexGridSizer_RemoveGrowableCol: { // wxFlexGridSizer::RemoveGrowableCol
wxFlexGridSizer *This = (wxFlexGridSizer *) getPtr(bp,memenv); bp += 4;
int * idx = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->RemoveGrowableCol((size_t) *idx);
+ This->RemoveGrowableCol(*idx);
break;
}
case wxFlexGridSizer_RemoveGrowableRow: { // wxFlexGridSizer::RemoveGrowableRow
wxFlexGridSizer *This = (wxFlexGridSizer *) getPtr(bp,memenv); bp += 4;
int * idx = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->RemoveGrowableRow((size_t) *idx);
+ This->RemoveGrowableRow(*idx);
break;
}
case wxFlexGridSizer_SetFlexibleDirection: { // wxFlexGridSizer::SetFlexibleDirection
wxFlexGridSizer *This = (wxFlexGridSizer *) getPtr(bp,memenv); bp += 4;
int * direction = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetFlexibleDirection((int) *direction);
+ This->SetFlexibleDirection(*direction);
break;
}
case wxFlexGridSizer_SetNonFlexibleGrowMode: { // wxFlexGridSizer::SetNonFlexibleGrowMode
wxFlexGridSizer *This = (wxFlexGridSizer *) getPtr(bp,memenv); bp += 4;
wxFlexSizerGrowMode mode = *(wxFlexSizerGrowMode *) bp; bp += 4;;
if(!This) throw wxe_badarg(0);
- This->SetNonFlexibleGrowMode((wxFlexSizerGrowMode) mode);
+ This->SetNonFlexibleGrowMode(mode);
break;
}
case wxGridBagSizer_new: { // wxGridBagSizer::wxGridBagSizer
@@ -12525,7 +12560,7 @@ userData = (wxObject *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- wxSizerItem * Result = (wxSizerItem*)This->Add((int) *width,(int) *height,pos,span,flag,border,userData);
+ wxSizerItem * Result = (wxSizerItem*)This->Add(*width,*height,pos,span,flag,border,userData);
rt.addRef(getRef((void *)Result,memenv), "wxSizerItem");
break;
}
@@ -12613,7 +12648,7 @@ userData = (wxObject *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- wxSizerItem * Result = (wxSizerItem*)This->Add((int) *width,(int) *height,proportion,flag,border,userData);
+ wxSizerItem * Result = (wxSizerItem*)This->Add(*width,*height,proportion,flag,border,userData);
rt.addRef(getRef((void *)Result,memenv), "wxSizerItem");
break;
}
@@ -12715,7 +12750,7 @@ case wxGridBagSizer_GetCellSize: { // wxGridBagSizer::GetCellSize
int * row = (int *) bp; bp += 4;
int * col = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxSize Result = This->GetCellSize((int) *row,(int) *col);
+ wxSize Result = This->GetCellSize(*row,*col);
rt.add(Result);
break;
}
@@ -12746,7 +12781,7 @@ case wxGridBagSizer_GetItemPosition_1_0: { // wxGridBagSizer::GetItemPosition
wxGridBagSizer *This = (wxGridBagSizer *) getPtr(bp,memenv); bp += 4;
int * index = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxGBPosition Result = This->GetItemPosition((size_t) *index);
+ wxGBPosition Result = This->GetItemPosition(*index);
rt.add(Result);
break;
}
@@ -12770,7 +12805,7 @@ case wxGridBagSizer_GetItemSpan_1_0: { // wxGridBagSizer::GetItemSpan
wxGridBagSizer *This = (wxGridBagSizer *) getPtr(bp,memenv); bp += 4;
int * index = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxGBSpan Result = This->GetItemSpan((size_t) *index);
+ wxGBSpan Result = This->GetItemSpan(*index);
rt.add(Result);
break;
}
@@ -12812,7 +12847,7 @@ case wxGridBagSizer_SetItemPosition_2_0: { // wxGridBagSizer::SetItemPosition
int * posC = (int *) bp; bp += 4;
wxGBPosition pos = wxGBPosition(*posR,*posC);
if(!This) throw wxe_badarg(0);
- bool Result = This->SetItemPosition((size_t) *index,pos);
+ bool Result = This->SetItemPosition(*index,pos);
rt.addBool(Result);
break;
}
@@ -12845,7 +12880,7 @@ case wxGridBagSizer_SetItemSpan_2_0: { // wxGridBagSizer::SetItemSpan
int * spanCS = (int *) bp; bp += 4;
wxGBSpan span = wxGBSpan(*spanRS,*spanCS);
if(!This) throw wxe_badarg(0);
- bool Result = This->SetItemSpan((size_t) *index,span);
+ bool Result = This->SetItemSpan(*index,span);
rt.addBool(Result);
break;
}
@@ -12925,7 +12960,7 @@ case wxFont_new_5: { // wxFont::wxFont
encoding = *(wxFontEncoding *) bp; bp += 4;;
} break;
}};
- wxFont * Result = new EwxFont((int) *size,(wxFontFamily) family,(wxFontStyle) style,(int) *weight,underlined,face,(wxFontEncoding) encoding);
+ wxFont * Result = new EwxFont(*size,family,style,*weight,underlined,face,encoding);
newPtr((void *) Result, 1, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxFont");
break;
@@ -13007,7 +13042,7 @@ case wxFont_Ok: { // wxFont::Ok
}
case wxFont_SetDefaultEncoding: { // wxFont::SetDefaultEncoding
wxFontEncoding encoding = *(wxFontEncoding *) bp; bp += 4;;
- wxFont::SetDefaultEncoding((wxFontEncoding) encoding);
+ wxFont::SetDefaultEncoding(encoding);
break;
}
case wxFont_SetFaceName: { // wxFont::SetFaceName
@@ -13024,45 +13059,45 @@ case wxFont_SetFamily: { // wxFont::SetFamily
wxFont *This = (wxFont *) getPtr(bp,memenv); bp += 4;
wxFontFamily family = *(wxFontFamily *) bp; bp += 4;;
if(!This) throw wxe_badarg(0);
- This->SetFamily((wxFontFamily) family);
+ This->SetFamily(family);
break;
}
case wxFont_SetPointSize: { // wxFont::SetPointSize
wxFont *This = (wxFont *) getPtr(bp,memenv); bp += 4;
int * pointSize = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetPointSize((int) *pointSize);
+ This->SetPointSize(*pointSize);
break;
}
case wxFont_SetStyle: { // wxFont::SetStyle
wxFont *This = (wxFont *) getPtr(bp,memenv); bp += 4;
wxFontStyle style = *(wxFontStyle *) bp; bp += 4;;
if(!This) throw wxe_badarg(0);
- This->SetStyle((wxFontStyle) style);
+ This->SetStyle(style);
break;
}
case wxFont_SetUnderlined: { // wxFont::SetUnderlined
wxFont *This = (wxFont *) getPtr(bp,memenv); bp += 4;
bool * underlined = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetUnderlined((bool) *underlined);
+ This->SetUnderlined(*underlined);
break;
}
case wxFont_SetWeight: { // wxFont::SetWeight
wxFont *This = (wxFont *) getPtr(bp,memenv); bp += 4;
int * weight = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetWeight((int) *weight);
+ This->SetWeight(*weight);
break;
}
case wxToolTip_Enable: { // wxToolTip::Enable
bool * flag = (bool *) bp; bp += 4;
- wxToolTip::Enable((bool) *flag);
+ wxToolTip::Enable(*flag);
break;
}
case wxToolTip_SetDelay: { // wxToolTip::SetDelay
int * msecs = (int *) bp; bp += 4;
- wxToolTip::SetDelay((long) *msecs);
+ wxToolTip::SetDelay(*msecs);
break;
}
case wxToolTip_new: { // wxToolTip::wxToolTip
@@ -13130,7 +13165,7 @@ case wxButton_new_3: { // wxButton::wxButton
validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
- wxButton * Result = new EwxButton(parent,(wxWindowID) *id,label,pos,size,style,*validator);
+ wxButton * Result = new EwxButton(parent,*id,label,pos,size,style,*validator);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxButton");
break;
@@ -13177,7 +13212,7 @@ validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,label,pos,size,style,*validator);
+ bool Result = This->Create(parent,*id,label,pos,size,style,*validator);
rt.addBool(Result);
break;
}
@@ -13230,7 +13265,7 @@ case wxBitmapButton_new_4: { // wxBitmapButton::wxBitmapButton
validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
- wxBitmapButton * Result = new EwxBitmapButton(parent,(wxWindowID) *id,*bitmap,pos,size,style,*validator);
+ wxBitmapButton * Result = new EwxBitmapButton(parent,*id,*bitmap,pos,size,style,*validator);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxBitmapButton");
break;
@@ -13271,35 +13306,35 @@ validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,*bitmap,pos,size,style,*validator);
+ bool Result = This->Create(parent,*id,*bitmap,pos,size,style,*validator);
rt.addBool(Result);
break;
}
case wxBitmapButton_GetBitmapDisabled: { // wxBitmapButton::GetBitmapDisabled
wxBitmapButton *This = (wxBitmapButton *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- const wxBitmap * Result = &This->GetBitmapDisabled();
+ const wxBitmap * Result = new wxBitmap(This->GetBitmapDisabled()); newPtr((void *) Result,3, memenv);;
rt.addRef(getRef((void *)Result,memenv), "wxBitmap");
break;
}
case wxBitmapButton_GetBitmapFocus: { // wxBitmapButton::GetBitmapFocus
wxBitmapButton *This = (wxBitmapButton *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- const wxBitmap * Result = &This->GetBitmapFocus();
+ const wxBitmap * Result = new wxBitmap(This->GetBitmapFocus()); newPtr((void *) Result,3, memenv);;
rt.addRef(getRef((void *)Result,memenv), "wxBitmap");
break;
}
case wxBitmapButton_GetBitmapLabel: { // wxBitmapButton::GetBitmapLabel
wxBitmapButton *This = (wxBitmapButton *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- const wxBitmap * Result = &This->GetBitmapLabel();
+ const wxBitmap * Result = new wxBitmap(This->GetBitmapLabel()); newPtr((void *) Result,3, memenv);;
rt.addRef(getRef((void *)Result,memenv), "wxBitmap");
break;
}
case wxBitmapButton_GetBitmapSelected: { // wxBitmapButton::GetBitmapSelected
wxBitmapButton *This = (wxBitmapButton *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- const wxBitmap * Result = &This->GetBitmapSelected();
+ const wxBitmap * Result = new wxBitmap(This->GetBitmapSelected()); newPtr((void *) Result,3, memenv);;
rt.addRef(getRef((void *)Result,memenv), "wxBitmap");
break;
}
@@ -13367,7 +13402,7 @@ case wxToggleButton_new_4: { // wxToggleButton::wxToggleButton
validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
- wxToggleButton * Result = new EwxToggleButton(parent,(wxWindowID) *id,label,pos,size,style,*validator);
+ wxToggleButton * Result = new EwxToggleButton(parent,*id,label,pos,size,style,*validator);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxToggleButton");
break;
@@ -13404,7 +13439,7 @@ validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,label,pos,size,style,*validator);
+ bool Result = This->Create(parent,*id,label,pos,size,style,*validator);
rt.addBool(Result);
break;
}
@@ -13419,7 +13454,7 @@ case wxToggleButton_SetValue: { // wxToggleButton::SetValue
wxToggleButton *This = (wxToggleButton *) getPtr(bp,memenv); bp += 4;
bool * state = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetValue((bool) *state);
+ This->SetValue(*state);
break;
}
case wxCalendarCtrl_new_0: { // wxCalendarCtrl::wxCalendarCtrl
@@ -13462,7 +13497,7 @@ case wxCalendarCtrl_new_3: { // wxCalendarCtrl::wxCalendarCtrl
style = (long)*(int *) bp; bp += 4;
} break;
}};
- wxCalendarCtrl * Result = new EwxCalendarCtrl(parent,(wxWindowID) *id,date,pos,size,style);
+ wxCalendarCtrl * Result = new EwxCalendarCtrl(parent,*id,date,pos,size,style);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxCalendarCtrl");
break;
@@ -13504,7 +13539,7 @@ case wxCalendarCtrl_Create: { // wxCalendarCtrl::Create
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,date,pos,size,style);
+ bool Result = This->Create(parent,*id,date,pos,size,style);
rt.addBool(Result);
break;
}
@@ -13525,10 +13560,11 @@ case wxCalendarCtrl_SetDate: { // wxCalendarCtrl::SetDate
case wxCalendarCtrl_GetDate: { // wxCalendarCtrl::GetDate
wxCalendarCtrl *This = (wxCalendarCtrl *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- const wxDateTime * Result = &This->GetDate();
- rt.add((*Result));
+ const wxDateTime Result = This->GetDate();
+ rt.add(Result);
break;
}
+#if !wxCHECK_VERSION(2,9,0)
case wxCalendarCtrl_EnableYearChange: { // wxCalendarCtrl::EnableYearChange
bool enable=true;
wxCalendarCtrl *This = (wxCalendarCtrl *) getPtr(bp,memenv); bp += 4;
@@ -13542,6 +13578,7 @@ case wxCalendarCtrl_EnableYearChange: { // wxCalendarCtrl::EnableYearChange
This->EnableYearChange(enable);
break;
}
+#endif
case wxCalendarCtrl_EnableMonthChange: { // wxCalendarCtrl::EnableMonthChange
bool enable=true;
wxCalendarCtrl *This = (wxCalendarCtrl *) getPtr(bp,memenv); bp += 4;
@@ -13662,7 +13699,7 @@ case wxCalendarCtrl_GetAttr: { // wxCalendarCtrl::GetAttr
wxCalendarCtrl *This = (wxCalendarCtrl *) getPtr(bp,memenv); bp += 4;
int * day = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxCalendarDateAttr * Result = (wxCalendarDateAttr*)This->GetAttr((size_t) *day);
+ wxCalendarDateAttr * Result = (wxCalendarDateAttr*)This->GetAttr(*day);
rt.addRef(getRef((void *)Result,memenv), "wxCalendarDateAttr");
break;
}
@@ -13671,21 +13708,21 @@ case wxCalendarCtrl_SetAttr: { // wxCalendarCtrl::SetAttr
int * day = (int *) bp; bp += 4;
wxCalendarDateAttr *attr = (wxCalendarDateAttr *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetAttr((size_t) *day,attr);
+ This->SetAttr(*day,attr);
break;
}
case wxCalendarCtrl_SetHoliday: { // wxCalendarCtrl::SetHoliday
wxCalendarCtrl *This = (wxCalendarCtrl *) getPtr(bp,memenv); bp += 4;
int * day = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetHoliday((size_t) *day);
+ This->SetHoliday(*day);
break;
}
case wxCalendarCtrl_ResetAttr: { // wxCalendarCtrl::ResetAttr
wxCalendarCtrl *This = (wxCalendarCtrl *) getPtr(bp,memenv); bp += 4;
int * day = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->ResetAttr((size_t) *day);
+ This->ResetAttr(*day);
break;
}
case wxCalendarCtrl_HitTest: { // wxCalendarCtrl::HitTest
@@ -13743,7 +13780,7 @@ font = (wxFont *) getPtr(bp,memenv); bp += 4;
border = *(wxCalendarDateBorder *) bp; bp += 4;;
} break;
}};
- wxCalendarDateAttr * Result = new wxCalendarDateAttr(colText,colBack,colBorder,*font,(wxCalendarDateBorder) border);
+ wxCalendarDateAttr * Result = new wxCalendarDateAttr(colText,colBack,colBorder,*font,border);
newPtr((void *) Result, 88, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxCalendarDateAttr");
break;
@@ -13762,7 +13799,7 @@ case wxCalendarDateAttr_new_2_0: { // wxCalendarDateAttr::wxCalendarDateAttr
bp += 4; /* Align */
} break;
}};
- wxCalendarDateAttr * Result = new wxCalendarDateAttr((wxCalendarDateBorder) border,colBorder);
+ wxCalendarDateAttr * Result = new wxCalendarDateAttr(border,colBorder);
newPtr((void *) Result, 88, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxCalendarDateAttr");
break;
@@ -13811,14 +13848,14 @@ case wxCalendarDateAttr_SetBorder: { // wxCalendarDateAttr::SetBorder
wxCalendarDateAttr *This = (wxCalendarDateAttr *) getPtr(bp,memenv); bp += 4;
wxCalendarDateBorder border = *(wxCalendarDateBorder *) bp; bp += 4;;
if(!This) throw wxe_badarg(0);
- This->SetBorder((wxCalendarDateBorder) border);
+ This->SetBorder(border);
break;
}
case wxCalendarDateAttr_SetHoliday: { // wxCalendarDateAttr::SetHoliday
wxCalendarDateAttr *This = (wxCalendarDateAttr *) getPtr(bp,memenv); bp += 4;
bool * holiday = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetHoliday((bool) *holiday);
+ This->SetHoliday(*holiday);
break;
}
case wxCalendarDateAttr_HasTextColour: { // wxCalendarDateAttr::HasTextColour
@@ -13934,7 +13971,7 @@ case wxCheckBox_new_4: { // wxCheckBox::wxCheckBox
validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
- wxCheckBox * Result = new EwxCheckBox(parent,(wxWindowID) *id,label,pos,size,style,*validator);
+ wxCheckBox * Result = new EwxCheckBox(parent,*id,label,pos,size,style,*validator);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxCheckBox");
break;
@@ -13977,7 +14014,7 @@ validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,label,pos,size,style,*validator);
+ bool Result = This->Create(parent,*id,label,pos,size,style,*validator);
rt.addBool(Result);
break;
}
@@ -14020,14 +14057,14 @@ case wxCheckBox_SetValue: { // wxCheckBox::SetValue
wxCheckBox *This = (wxCheckBox *) getPtr(bp,memenv); bp += 4;
bool * state = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetValue((bool) *state);
+ This->SetValue(*state);
break;
}
case wxCheckBox_Set3StateValue: { // wxCheckBox::Set3StateValue
wxCheckBox *This = (wxCheckBox *) getPtr(bp,memenv); bp += 4;
wxCheckBoxState state = *(wxCheckBoxState *) bp; bp += 4;;
if(!This) throw wxe_badarg(0);
- This->Set3StateValue((wxCheckBoxState) state);
+ This->Set3StateValue(state);
break;
}
case wxCheckListBox_new_0: { // wxCheckListBox::wxCheckListBox
@@ -14075,7 +14112,7 @@ case wxCheckListBox_new_3: { // wxCheckListBox::wxCheckListBox
validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
- wxCheckListBox * Result = new EwxCheckListBox(parent,(wxWindowID) *id,pos,size,choices,style,*validator);
+ wxCheckListBox * Result = new EwxCheckListBox(parent,*id,pos,size,choices,style,*validator);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxCheckListBox");
break;
@@ -14090,14 +14127,14 @@ case wxCheckListBox_Check: { // wxCheckListBox::Check
} break;
}};
if(!This) throw wxe_badarg(0);
- This->Check((int) *index,check);
+ This->Check(*index,check);
break;
}
case wxCheckListBox_IsChecked: { // wxCheckListBox::IsChecked
wxCheckListBox *This = (wxCheckListBox *) getPtr(bp,memenv); bp += 4;
unsigned int * index = (unsigned int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->IsChecked((int) *index);
+ bool Result = This->IsChecked(*index);
rt.addBool(Result);
break;
}
@@ -14140,7 +14177,7 @@ case wxChoice_new_3: { // wxChoice::wxChoice
validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
- wxChoice * Result = new EwxChoice(parent,(wxWindowID) *id,pos,size,choices,style,*validator);
+ wxChoice * Result = new EwxChoice(parent,*id,pos,size,choices,style,*validator);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxChoice");
break;
@@ -14182,7 +14219,7 @@ validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,pos,size,choices,style,*validator);
+ bool Result = This->Create(parent,*id,pos,size,choices,style,*validator);
rt.addBool(Result);
break;
}
@@ -14190,7 +14227,7 @@ case wxChoice_Delete: { // wxChoice::Delete
wxChoice *This = (wxChoice *) getPtr(bp,memenv); bp += 4;
unsigned int * n = (unsigned int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->Delete((int) *n);
+ This->Delete(*n);
break;
}
case wxChoice_GetColumns: { // wxChoice::GetColumns
@@ -14264,7 +14301,7 @@ case wxComboBox_new_3: { // wxComboBox::wxComboBox
validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
- wxComboBox * Result = new EwxComboBox(parent,(wxWindowID) *id,value,pos,size,choices,style,*validator);
+ wxComboBox * Result = new EwxComboBox(parent,*id,value,pos,size,choices,style,*validator);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxComboBox");
break;
@@ -14303,7 +14340,7 @@ validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,value,pos,size,choices,style,*validator);
+ bool Result = This->Create(parent,*id,value,pos,size,choices,style,*validator);
rt.addBool(Result);
break;
}
@@ -14395,7 +14432,7 @@ case wxComboBox_Replace: { // wxComboBox::Replace
wxString value = wxString(bp, wxConvUTF8);
bp += *valueLen+((8-((0+ *valueLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- This->Replace((long) *from,(long) *to,value);
+ This->Replace(*from,*to,value);
break;
}
case wxComboBox_Remove: { // wxComboBox::Remove
@@ -14403,14 +14440,14 @@ case wxComboBox_Remove: { // wxComboBox::Remove
int * from = (int *) bp; bp += 4;
int * to = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->Remove((long) *from,(long) *to);
+ This->Remove(*from,*to);
break;
}
case wxComboBox_SetInsertionPoint: { // wxComboBox::SetInsertionPoint
wxComboBox *This = (wxComboBox *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetInsertionPoint((long) *pos);
+ This->SetInsertionPoint(*pos);
break;
}
case wxComboBox_SetInsertionPointEnd: { // wxComboBox::SetInsertionPointEnd
@@ -14423,7 +14460,7 @@ case wxComboBox_SetSelection_1: { // wxComboBox::SetSelection
wxComboBox *This = (wxComboBox *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetSelection((int) *n);
+ This->SetSelection(*n);
break;
}
case wxComboBox_SetSelection_2: { // wxComboBox::SetSelection
@@ -14431,7 +14468,7 @@ case wxComboBox_SetSelection_2: { // wxComboBox::SetSelection
int * from = (int *) bp; bp += 4;
int * to = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetSelection((long) *from,(long) *to);
+ This->SetSelection(*from,*to);
break;
}
case wxComboBox_SetValue: { // wxComboBox::SetValue
@@ -14484,7 +14521,7 @@ case wxGauge_new_4: { // wxGauge::wxGauge
validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
- wxGauge * Result = new EwxGauge(parent,(wxWindowID) *id,(int) *range,pos,size,style,*validator);
+ wxGauge * Result = new EwxGauge(parent,*id,*range,pos,size,style,*validator);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxGauge");
break;
@@ -14519,7 +14556,7 @@ validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,(int) *range,pos,size,style,*validator);
+ bool Result = This->Create(parent,*id,*range,pos,size,style,*validator);
rt.addBool(Result);
break;
}
@@ -14562,28 +14599,28 @@ case wxGauge_SetBezelFace: { // wxGauge::SetBezelFace
wxGauge *This = (wxGauge *) getPtr(bp,memenv); bp += 4;
int * w = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetBezelFace((int) *w);
+ This->SetBezelFace(*w);
break;
}
case wxGauge_SetRange: { // wxGauge::SetRange
wxGauge *This = (wxGauge *) getPtr(bp,memenv); bp += 4;
int * r = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetRange((int) *r);
+ This->SetRange(*r);
break;
}
case wxGauge_SetShadowWidth: { // wxGauge::SetShadowWidth
wxGauge *This = (wxGauge *) getPtr(bp,memenv); bp += 4;
int * w = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetShadowWidth((int) *w);
+ This->SetShadowWidth(*w);
break;
}
case wxGauge_SetValue: { // wxGauge::SetValue
wxGauge *This = (wxGauge *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetValue((int) *pos);
+ This->SetValue(*pos);
break;
}
case wxGauge_Pulse: { // wxGauge::Pulse
@@ -14793,7 +14830,7 @@ case wxGenericDirCtrl_SetFilterIndex: { // wxGenericDirCtrl::SetFilterIndex
wxGenericDirCtrl *This = (wxGenericDirCtrl *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetFilterIndex((int) *n);
+ This->SetFilterIndex(*n);
break;
}
case wxGenericDirCtrl_SetPath: { // wxGenericDirCtrl::SetPath
@@ -14831,7 +14868,7 @@ case wxStaticBox_new_4: { // wxStaticBox::wxStaticBox
style = (long)*(int *) bp; bp += 4;
} break;
}};
- wxStaticBox * Result = new EwxStaticBox(parent,(wxWindowID) *id,label,pos,size,style);
+ wxStaticBox * Result = new EwxStaticBox(parent,*id,label,pos,size,style);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxStaticBox");
break;
@@ -14870,7 +14907,7 @@ case wxStaticBox_Create: { // wxStaticBox::Create
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,label,pos,size,style);
+ bool Result = This->Create(parent,*id,label,pos,size,style);
rt.addBool(Result);
break;
}
@@ -14995,7 +15032,7 @@ case wxListBox_new_3: { // wxListBox::wxListBox
validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
- wxListBox * Result = new EwxListBox(parent,(wxWindowID) *id,pos,size,choices,style,*validator);
+ wxListBox * Result = new EwxListBox(parent,*id,pos,size,choices,style,*validator);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxListBox");
break;
@@ -15037,7 +15074,7 @@ validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,pos,size,choices,style,*validator);
+ bool Result = This->Create(parent,*id,pos,size,choices,style,*validator);
rt.addBool(Result);
break;
}
@@ -15045,7 +15082,7 @@ case wxListBox_Deselect: { // wxListBox::Deselect
wxListBox *This = (wxListBox *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->Deselect((int) *n);
+ This->Deselect(*n);
break;
}
case wxListBox_GetSelections: { // wxListBox::GetSelections
@@ -15072,14 +15109,14 @@ case wxListBox_InsertItems: { // wxListBox::InsertItems
bp += (8-((0+ itemsASz) & 7 )) & 7;
unsigned int * pos = (unsigned int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->InsertItems(items,(int) *pos);
+ This->InsertItems(items,*pos);
break;
}
case wxListBox_IsSelected: { // wxListBox::IsSelected
wxListBox *This = (wxListBox *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->IsSelected((int) *n);
+ bool Result = This->IsSelected(*n);
rt.addBool(Result);
break;
}
@@ -15096,7 +15133,7 @@ case wxListBox_Set: { // wxListBox::Set
}
bp += (8-((0+ itemsASz) & 7 )) & 7;
if(!This) throw wxe_badarg(0);
- This->Set(items,NULL);
+ This->Set(items,(void **) NULL);
break;
}
case wxListBox_HitTest: { // wxListBox::HitTest
@@ -15113,7 +15150,7 @@ case wxListBox_SetFirstItem_1_0: { // wxListBox::SetFirstItem
wxListBox *This = (wxListBox *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetFirstItem((int) *n);
+ This->SetFirstItem(*n);
break;
}
case wxListBox_SetFirstItem_1_1: { // wxListBox::SetFirstItem
@@ -15203,7 +15240,7 @@ case wxListCtrl_AssignImageList: { // wxListCtrl::AssignImageList
wxImageList *imageList = (wxImageList *) getPtr(bp,memenv); bp += 4;
int * which = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->AssignImageList(imageList,(int) *which);
+ This->AssignImageList(imageList,*which);
break;
}
case wxListCtrl_ClearAll: { // wxListCtrl::ClearAll
@@ -15277,7 +15314,7 @@ case wxListCtrl_DeleteColumn: { // wxListCtrl::DeleteColumn
wxListCtrl *This = (wxListCtrl *) getPtr(bp,memenv); bp += 4;
int * col = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->DeleteColumn((int) *col);
+ bool Result = This->DeleteColumn(*col);
rt.addBool(Result);
break;
}
@@ -15285,7 +15322,7 @@ case wxListCtrl_DeleteItem: { // wxListCtrl::DeleteItem
wxListCtrl *This = (wxListCtrl *) getPtr(bp,memenv); bp += 4;
int * item = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->DeleteItem((long) *item);
+ bool Result = This->DeleteItem(*item);
rt.addBool(Result);
break;
}
@@ -15293,7 +15330,7 @@ case wxListCtrl_EditLabel: { // wxListCtrl::EditLabel
wxListCtrl *This = (wxListCtrl *) getPtr(bp,memenv); bp += 4;
int * item = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxTextCtrl * Result = (wxTextCtrl*)This->EditLabel((long) *item);
+ wxTextCtrl * Result = (wxTextCtrl*)This->EditLabel(*item);
rt.addRef(getRef((void *)Result,memenv), "wxTextCtrl");
break;
}
@@ -15301,7 +15338,7 @@ case wxListCtrl_EnsureVisible: { // wxListCtrl::EnsureVisible
wxListCtrl *This = (wxListCtrl *) getPtr(bp,memenv); bp += 4;
int * item = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->EnsureVisible((long) *item);
+ bool Result = This->EnsureVisible(*item);
rt.addBool(Result);
break;
}
@@ -15318,7 +15355,7 @@ case wxListCtrl_FindItem_3_0: { // wxListCtrl::FindItem
} break;
}};
if(!This) throw wxe_badarg(0);
- long Result = This->FindItem((long) *start,str,partial);
+ long Result = This->FindItem(*start,str,partial);
rt.addInt(Result);
break;
}
@@ -15330,7 +15367,7 @@ case wxListCtrl_FindItem_3_1: { // wxListCtrl::FindItem
wxPoint pt = wxPoint(*ptX,*ptY);
int * direction = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- long Result = This->FindItem((long) *start,pt,(int) *direction);
+ long Result = This->FindItem(*start,pt,*direction);
rt.addInt(Result);
break;
}
@@ -15339,7 +15376,7 @@ case wxListCtrl_GetColumn: { // wxListCtrl::GetColumn
int * col = (int *) bp; bp += 4;
wxListItem *item = (wxListItem *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->GetColumn((int) *col,*item);
+ bool Result = This->GetColumn(*col,*item);
rt.addBool(Result);
break;
}
@@ -15354,7 +15391,7 @@ case wxListCtrl_GetColumnWidth: { // wxListCtrl::GetColumnWidth
wxListCtrl *This = (wxListCtrl *) getPtr(bp,memenv); bp += 4;
int * col = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->GetColumnWidth((int) *col);
+ int Result = This->GetColumnWidth(*col);
rt.addInt(Result);
break;
}
@@ -15376,7 +15413,7 @@ case wxListCtrl_GetImageList: { // wxListCtrl::GetImageList
wxListCtrl *This = (wxListCtrl *) getPtr(bp,memenv); bp += 4;
int * which = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxImageList * Result = (wxImageList*)This->GetImageList((int) *which);
+ wxImageList * Result = (wxImageList*)This->GetImageList(*which);
rt.addRef(getRef((void *)Result,memenv), "wxImageList");
break;
}
@@ -15392,7 +15429,7 @@ case wxListCtrl_GetItemBackgroundColour: { // wxListCtrl::GetItemBackgroundColou
wxListCtrl *This = (wxListCtrl *) getPtr(bp,memenv); bp += 4;
int * item = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxColour Result = This->GetItemBackgroundColour((long) *item);
+ wxColour Result = This->GetItemBackgroundColour(*item);
rt.add(Result);
break;
}
@@ -15407,7 +15444,7 @@ case wxListCtrl_GetItemData: { // wxListCtrl::GetItemData
wxListCtrl *This = (wxListCtrl *) getPtr(bp,memenv); bp += 4;
int * item = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxUIntPtr Result = This->GetItemData((long) *item);
+ wxUIntPtr Result = This->GetItemData(*item);
rt.addInt(Result);
break;
}
@@ -15415,7 +15452,7 @@ case wxListCtrl_GetItemFont: { // wxListCtrl::GetItemFont
wxListCtrl *This = (wxListCtrl *) getPtr(bp,memenv); bp += 4;
int * item = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxFont * Result = new wxFont(This->GetItemFont((long) *item)); newPtr((void *) Result,3, memenv);;
+ wxFont * Result = new wxFont(This->GetItemFont(*item)); newPtr((void *) Result,3, memenv);;
rt.addRef(getRef((void *)Result,memenv), "wxFont");
break;
}
@@ -15424,7 +15461,7 @@ case wxListCtrl_GetItemPosition: { // wxListCtrl::GetItemPosition
wxListCtrl *This = (wxListCtrl *) getPtr(bp,memenv); bp += 4;
int * item = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->GetItemPosition((long) *item,pos);
+ bool Result = This->GetItemPosition(*item,pos);
rt.addBool(Result);
rt.add(pos);
rt.addTupleCount(2);
@@ -15441,7 +15478,7 @@ case wxListCtrl_GetItemRect: { // wxListCtrl::GetItemRect
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->GetItemRect((long) *item,rect,code);
+ bool Result = This->GetItemRect(*item,rect,code);
rt.addBool(Result);
rt.add(rect);
rt.addTupleCount(2);
@@ -15459,7 +15496,7 @@ case wxListCtrl_GetItemState: { // wxListCtrl::GetItemState
int * item = (int *) bp; bp += 4;
int * stateMask = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->GetItemState((long) *item,(long) *stateMask);
+ int Result = This->GetItemState(*item,*stateMask);
rt.addInt(Result);
break;
}
@@ -15467,7 +15504,7 @@ case wxListCtrl_GetItemText: { // wxListCtrl::GetItemText
wxListCtrl *This = (wxListCtrl *) getPtr(bp,memenv); bp += 4;
int * item = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxString Result = This->GetItemText((long) *item);
+ wxString Result = This->GetItemText(*item);
rt.add(Result);
break;
}
@@ -15475,7 +15512,7 @@ case wxListCtrl_GetItemTextColour: { // wxListCtrl::GetItemTextColour
wxListCtrl *This = (wxListCtrl *) getPtr(bp,memenv); bp += 4;
int * item = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxColour Result = This->GetItemTextColour((long) *item);
+ wxColour Result = This->GetItemTextColour(*item);
rt.add(Result);
break;
}
@@ -15493,7 +15530,7 @@ case wxListCtrl_GetNextItem: { // wxListCtrl::GetNextItem
} break;
}};
if(!This) throw wxe_badarg(0);
- long Result = This->GetNextItem((long) *item,geometry,state);
+ long Result = This->GetNextItem(*item,geometry,state);
rt.addInt(Result);
break;
}
@@ -15541,7 +15578,7 @@ case wxListCtrl_InsertColumn_2: { // wxListCtrl::InsertColumn
int * col = (int *) bp; bp += 4;
wxListItem *info = (wxListItem *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- long Result = This->InsertColumn((long) *col,*info);
+ long Result = This->InsertColumn(*col,*info);
rt.addInt(Result);
break;
}
@@ -15562,7 +15599,7 @@ case wxListCtrl_InsertColumn_3: { // wxListCtrl::InsertColumn
} break;
}};
if(!This) throw wxe_badarg(0);
- long Result = This->InsertColumn((long) *col,heading,format,width);
+ long Result = This->InsertColumn(*col,heading,format,width);
rt.addInt(Result);
break;
}
@@ -15581,7 +15618,7 @@ case wxListCtrl_InsertItem_2_1: { // wxListCtrl::InsertItem
wxString label = wxString(bp, wxConvUTF8);
bp += *labelLen+((8-((4+ *labelLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- long Result = This->InsertItem((long) *index,label);
+ long Result = This->InsertItem(*index,label);
rt.addInt(Result);
break;
}
@@ -15590,7 +15627,7 @@ case wxListCtrl_InsertItem_2_0: { // wxListCtrl::InsertItem
int * index = (int *) bp; bp += 4;
int * imageIndex = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- long Result = This->InsertItem((long) *index,(int) *imageIndex);
+ long Result = This->InsertItem(*index,*imageIndex);
rt.addInt(Result);
break;
}
@@ -15602,7 +15639,7 @@ case wxListCtrl_InsertItem_3: { // wxListCtrl::InsertItem
bp += *labelLen+((8-((4+ *labelLen) & 7)) & 7);
int * imageIndex = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- long Result = This->InsertItem((long) *index,label,(int) *imageIndex);
+ long Result = This->InsertItem(*index,label,*imageIndex);
rt.addInt(Result);
break;
}
@@ -15610,7 +15647,7 @@ case wxListCtrl_RefreshItem: { // wxListCtrl::RefreshItem
wxListCtrl *This = (wxListCtrl *) getPtr(bp,memenv); bp += 4;
int * item = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->RefreshItem((long) *item);
+ This->RefreshItem(*item);
break;
}
case wxListCtrl_RefreshItems: { // wxListCtrl::RefreshItems
@@ -15618,7 +15655,7 @@ case wxListCtrl_RefreshItems: { // wxListCtrl::RefreshItems
int * itemFrom = (int *) bp; bp += 4;
int * itemTo = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->RefreshItems((long) *itemFrom,(long) *itemTo);
+ This->RefreshItems(*itemFrom,*itemTo);
break;
}
case wxListCtrl_ScrollList: { // wxListCtrl::ScrollList
@@ -15626,7 +15663,7 @@ case wxListCtrl_ScrollList: { // wxListCtrl::ScrollList
int * dx = (int *) bp; bp += 4;
int * dy = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->ScrollList((int) *dx,(int) *dy);
+ bool Result = This->ScrollList(*dx,*dy);
rt.addBool(Result);
break;
}
@@ -15647,7 +15684,7 @@ case wxListCtrl_SetColumn: { // wxListCtrl::SetColumn
int * col = (int *) bp; bp += 4;
wxListItem *item = (wxListItem *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->SetColumn((int) *col,*item);
+ bool Result = This->SetColumn(*col,*item);
rt.addBool(Result);
break;
}
@@ -15656,7 +15693,7 @@ case wxListCtrl_SetColumnWidth: { // wxListCtrl::SetColumnWidth
int * col = (int *) bp; bp += 4;
int * width = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->SetColumnWidth((int) *col,(int) *width);
+ bool Result = This->SetColumnWidth(*col,*width);
rt.addBool(Result);
break;
}
@@ -15665,7 +15702,7 @@ case wxListCtrl_SetImageList: { // wxListCtrl::SetImageList
wxImageList *imageList = (wxImageList *) getPtr(bp,memenv); bp += 4;
int * which = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetImageList(imageList,(int) *which);
+ This->SetImageList(imageList,*which);
break;
}
case wxListCtrl_SetItem_1: { // wxListCtrl::SetItem
@@ -15690,7 +15727,7 @@ case wxListCtrl_SetItem_4: { // wxListCtrl::SetItem
} break;
}};
if(!This) throw wxe_badarg(0);
- long Result = This->SetItem((long) *index,(int) *col,label,imageId);
+ long Result = This->SetItem(*index,*col,label,imageId);
rt.addInt(Result);
break;
}
@@ -15703,14 +15740,14 @@ case wxListCtrl_SetItemBackgroundColour: { // wxListCtrl::SetItemBackgroundColou
int * colA = (int *) bp; bp += 4;
wxColour col = wxColour(*colR,*colG,*colB,*colA);
if(!This) throw wxe_badarg(0);
- This->SetItemBackgroundColour((long) *item,col);
+ This->SetItemBackgroundColour(*item,col);
break;
}
case wxListCtrl_SetItemCount: { // wxListCtrl::SetItemCount
wxListCtrl *This = (wxListCtrl *) getPtr(bp,memenv); bp += 4;
int * count = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetItemCount((long) *count);
+ This->SetItemCount(*count);
break;
}
case wxListCtrl_SetItemData: { // wxListCtrl::SetItemData
@@ -15718,7 +15755,7 @@ case wxListCtrl_SetItemData: { // wxListCtrl::SetItemData
int * item = (int *) bp; bp += 4;
int * data = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->SetItemData((long) *item,(long) *data);
+ bool Result = This->SetItemData(*item,*data);
rt.addBool(Result);
break;
}
@@ -15727,7 +15764,7 @@ case wxListCtrl_SetItemFont: { // wxListCtrl::SetItemFont
int * item = (int *) bp; bp += 4;
wxFont *f = (wxFont *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetItemFont((long) *item,*f);
+ This->SetItemFont(*item,*f);
break;
}
case wxListCtrl_SetItemImage: { // wxListCtrl::SetItemImage
@@ -15742,7 +15779,7 @@ case wxListCtrl_SetItemImage: { // wxListCtrl::SetItemImage
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->SetItemImage((long) *item,(int) *image,selImage);
+ bool Result = This->SetItemImage(*item,*image,selImage);
rt.addBool(Result);
break;
}
@@ -15752,7 +15789,7 @@ case wxListCtrl_SetItemColumnImage: { // wxListCtrl::SetItemColumnImage
int * column = (int *) bp; bp += 4;
int * image = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->SetItemColumnImage((long) *item,(long) *column,(int) *image);
+ bool Result = This->SetItemColumnImage(*item,*column,*image);
rt.addBool(Result);
break;
}
@@ -15763,7 +15800,7 @@ case wxListCtrl_SetItemPosition: { // wxListCtrl::SetItemPosition
int * posY = (int *) bp; bp += 4;
wxPoint pos = wxPoint(*posX,*posY);
if(!This) throw wxe_badarg(0);
- bool Result = This->SetItemPosition((long) *item,pos);
+ bool Result = This->SetItemPosition(*item,pos);
rt.addBool(Result);
break;
}
@@ -15773,7 +15810,7 @@ case wxListCtrl_SetItemState: { // wxListCtrl::SetItemState
int * state = (int *) bp; bp += 4;
int * stateMask = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->SetItemState((long) *item,(long) *state,(long) *stateMask);
+ bool Result = This->SetItemState(*item,*state,*stateMask);
rt.addBool(Result);
break;
}
@@ -15784,7 +15821,7 @@ case wxListCtrl_SetItemText: { // wxListCtrl::SetItemText
wxString str = wxString(bp, wxConvUTF8);
bp += *strLen+((8-((4+ *strLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- This->SetItemText((long) *item,str);
+ This->SetItemText(*item,str);
break;
}
case wxListCtrl_SetItemTextColour: { // wxListCtrl::SetItemTextColour
@@ -15796,7 +15833,7 @@ case wxListCtrl_SetItemTextColour: { // wxListCtrl::SetItemTextColour
int * colA = (int *) bp; bp += 4;
wxColour col = wxColour(*colR,*colG,*colB,*colA);
if(!This) throw wxe_badarg(0);
- This->SetItemTextColour((long) *item,col);
+ This->SetItemTextColour(*item,col);
break;
}
case wxListCtrl_SetSingleStyle: { // wxListCtrl::SetSingleStyle
@@ -15809,7 +15846,7 @@ case wxListCtrl_SetSingleStyle: { // wxListCtrl::SetSingleStyle
} break;
}};
if(!This) throw wxe_badarg(0);
- This->SetSingleStyle((long) *style,add);
+ This->SetSingleStyle(*style,add);
break;
}
case wxListCtrl_SetTextColour: { // wxListCtrl::SetTextColour
@@ -15827,7 +15864,7 @@ case wxListCtrl_SetWindowStyleFlag: { // wxListCtrl::SetWindowStyleFlag
wxListCtrl *This = (wxListCtrl *) getPtr(bp,memenv); bp += 4;
int * style = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetWindowStyleFlag((long) *style);
+ This->SetWindowStyleFlag(*style);
break;
}
@@ -15857,14 +15894,14 @@ case wxListView_ClearColumnImage: { // wxListView::ClearColumnImage
wxListView *This = (wxListView *) getPtr(bp,memenv); bp += 4;
int * col = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->ClearColumnImage((int) *col);
+ This->ClearColumnImage(*col);
break;
}
case wxListView_Focus: { // wxListView::Focus
wxListView *This = (wxListView *) getPtr(bp,memenv); bp += 4;
int * index = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->Focus((long) *index);
+ This->Focus(*index);
break;
}
case wxListView_GetFirstSelected: { // wxListView::GetFirstSelected
@@ -15885,7 +15922,7 @@ case wxListView_GetNextSelected: { // wxListView::GetNextSelected
wxListView *This = (wxListView *) getPtr(bp,memenv); bp += 4;
int * item = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- long Result = This->GetNextSelected((long) *item);
+ long Result = This->GetNextSelected(*item);
rt.addInt(Result);
break;
}
@@ -15893,7 +15930,7 @@ case wxListView_IsSelected: { // wxListView::IsSelected
wxListView *This = (wxListView *) getPtr(bp,memenv); bp += 4;
int * index = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->IsSelected((long) *index);
+ bool Result = This->IsSelected(*index);
rt.addBool(Result);
break;
}
@@ -15907,7 +15944,7 @@ case wxListView_Select: { // wxListView::Select
} break;
}};
if(!This) throw wxe_badarg(0);
- This->Select((long) *n,on);
+ This->Select(*n,on);
break;
}
case wxListView_SetColumnImage: { // wxListView::SetColumnImage
@@ -15915,7 +15952,7 @@ case wxListView_SetColumnImage: { // wxListView::SetColumnImage
int * col = (int *) bp; bp += 4;
int * image = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetColumnImage((int) *col,(int) *image);
+ This->SetColumnImage(*col,*image);
break;
}
case wxListItem_new_0: { // wxListItem::wxListItem
@@ -16018,7 +16055,7 @@ case wxListItem_SetAlign: { // wxListItem::SetAlign
wxListItem *This = (wxListItem *) getPtr(bp,memenv); bp += 4;
wxListColumnFormat align = *(wxListColumnFormat *) bp; bp += 4;;
if(!This) throw wxe_badarg(0);
- This->SetAlign((wxListColumnFormat) align);
+ This->SetAlign(align);
break;
}
case wxListItem_SetBackgroundColour: { // wxListItem::SetBackgroundColour
@@ -16036,7 +16073,7 @@ case wxListItem_SetColumn: { // wxListItem::SetColumn
wxListItem *This = (wxListItem *) getPtr(bp,memenv); bp += 4;
int * col = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetColumn((int) *col);
+ This->SetColumn(*col);
break;
}
case wxListItem_SetFont: { // wxListItem::SetFont
@@ -16050,35 +16087,35 @@ case wxListItem_SetId: { // wxListItem::SetId
wxListItem *This = (wxListItem *) getPtr(bp,memenv); bp += 4;
int * id = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetId((long) *id);
+ This->SetId(*id);
break;
}
case wxListItem_SetImage: { // wxListItem::SetImage
wxListItem *This = (wxListItem *) getPtr(bp,memenv); bp += 4;
int * image = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetImage((int) *image);
+ This->SetImage(*image);
break;
}
case wxListItem_SetMask: { // wxListItem::SetMask
wxListItem *This = (wxListItem *) getPtr(bp,memenv); bp += 4;
int * mask = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetMask((long) *mask);
+ This->SetMask(*mask);
break;
}
case wxListItem_SetState: { // wxListItem::SetState
wxListItem *This = (wxListItem *) getPtr(bp,memenv); bp += 4;
int * state = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetState((long) *state);
+ This->SetState(*state);
break;
}
case wxListItem_SetStateMask: { // wxListItem::SetStateMask
wxListItem *This = (wxListItem *) getPtr(bp,memenv); bp += 4;
int * stateMask = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetStateMask((long) *stateMask);
+ This->SetStateMask(*stateMask);
break;
}
case wxListItem_SetText: { // wxListItem::SetText
@@ -16105,7 +16142,7 @@ case wxListItem_SetWidth: { // wxListItem::SetWidth
wxListItem *This = (wxListItem *) getPtr(bp,memenv); bp += 4;
int * width = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetWidth((int) *width);
+ This->SetWidth(*width);
break;
}
case wxListItemAttr_new_0: { // wxListItemAttr::wxListItemAttr
@@ -16227,7 +16264,7 @@ case wxImageList_new_3: { // wxImageList::wxImageList
initialCount = (int)*(int *) bp; bp += 4;
} break;
}};
- wxImageList * Result = new EwxImageList((int) *width,(int) *height,mask,initialCount);
+ wxImageList * Result = new EwxImageList(*width,*height,mask,initialCount);
newPtr((void *) Result, 1, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxImageList");
break;
@@ -16278,7 +16315,7 @@ case wxImageList_Create: { // wxImageList::Create
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create((int) *width,(int) *height,mask,initialCount);
+ bool Result = This->Create(*width,*height,mask,initialCount);
rt.addBool(Result);
break;
}
@@ -16300,7 +16337,7 @@ case wxImageList_Draw: { // wxImageList::Draw
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Draw((int) *index,*dc,(int) *x,(int) *y,flags,solidBackground);
+ bool Result = This->Draw(*index,*dc,*x,*y,flags,solidBackground);
rt.addBool(Result);
break;
}
@@ -16308,7 +16345,7 @@ case wxImageList_GetBitmap: { // wxImageList::GetBitmap
wxImageList *This = (wxImageList *) getPtr(bp,memenv); bp += 4;
int * index = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxBitmap * Result = new wxBitmap(This->GetBitmap((int) *index)); newPtr((void *) Result,3, memenv);;
+ wxBitmap * Result = new wxBitmap(This->GetBitmap(*index)); newPtr((void *) Result,3, memenv);;
rt.addRef(getRef((void *)Result,memenv), "wxBitmap");
break;
}
@@ -16316,7 +16353,7 @@ case wxImageList_GetIcon: { // wxImageList::GetIcon
wxImageList *This = (wxImageList *) getPtr(bp,memenv); bp += 4;
int * index = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxIcon * Result = new wxIcon(This->GetIcon((int) *index)); newPtr((void *) Result,3, memenv);;
+ wxIcon * Result = new wxIcon(This->GetIcon(*index)); newPtr((void *) Result,3, memenv);;
rt.addRef(getRef((void *)Result,memenv), "wxIcon");
break;
}
@@ -16333,7 +16370,7 @@ case wxImageList_GetSize: { // wxImageList::GetSize
wxImageList *This = (wxImageList *) getPtr(bp,memenv); bp += 4;
int * index = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->GetSize((int) *index,width,height);
+ bool Result = This->GetSize(*index,width,height);
rt.addBool(Result);
rt.addInt(width);
rt.addInt(height);
@@ -16344,7 +16381,7 @@ case wxImageList_Remove: { // wxImageList::Remove
wxImageList *This = (wxImageList *) getPtr(bp,memenv); bp += 4;
int * index = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->Remove((int) *index);
+ bool Result = This->Remove(*index);
rt.addBool(Result);
break;
}
@@ -16360,7 +16397,7 @@ case wxImageList_Replace_2: { // wxImageList::Replace
int * index = (int *) bp; bp += 4;
wxBitmap *bitmap = (wxBitmap *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->Replace((int) *index,*bitmap);
+ bool Result = This->Replace(*index,*bitmap);
rt.addBool(Result);
break;
}
@@ -16370,7 +16407,7 @@ case wxImageList_Replace_3: { // wxImageList::Replace
wxBitmap *bitmap = (wxBitmap *) getPtr(bp,memenv); bp += 4;
wxBitmap *mask = (wxBitmap *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->Replace((int) *index,*bitmap,*mask);
+ bool Result = This->Replace(*index,*bitmap,*mask);
rt.addBool(Result);
break;
}
@@ -16405,7 +16442,7 @@ font = (wxFont *) getPtr(bp,memenv); bp += 4;
alignment = *(wxTextAttrAlignment *) bp; bp += 4;;
} break;
}};
- wxTextAttr * Result = new wxTextAttr(colText,colBack,*font,(wxTextAttrAlignment) alignment);
+ wxTextAttr * Result = new wxTextAttr(colText,colBack,*font,alignment);
newPtr((void *) Result, 103, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxTextAttr");
break;
@@ -16427,7 +16464,7 @@ case wxTextAttr_GetBackgroundColour: { // wxTextAttr::GetBackgroundColour
case wxTextAttr_GetFont: { // wxTextAttr::GetFont
wxTextAttr *This = (wxTextAttr *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- const wxFont * Result = &This->GetFont();
+ const wxFont * Result = new wxFont(This->GetFont()); newPtr((void *) Result,3, memenv);;
rt.addRef(getRef((void *)Result,memenv), "wxFont");
break;
}
@@ -16505,7 +16542,7 @@ case wxTextAttr_SetAlignment: { // wxTextAttr::SetAlignment
wxTextAttr *This = (wxTextAttr *) getPtr(bp,memenv); bp += 4;
wxTextAttrAlignment alignment = *(wxTextAttrAlignment *) bp; bp += 4;;
if(!This) throw wxe_badarg(0);
- This->SetAlignment((wxTextAttrAlignment) alignment);
+ This->SetAlignment(alignment);
break;
}
case wxTextAttr_SetBackgroundColour: { // wxTextAttr::SetBackgroundColour
@@ -16523,7 +16560,7 @@ case wxTextAttr_SetFlags: { // wxTextAttr::SetFlags
wxTextAttr *This = (wxTextAttr *) getPtr(bp,memenv); bp += 4;
int * flags = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetFlags((long) *flags);
+ This->SetFlags(*flags);
break;
}
case wxTextAttr_SetFont: { // wxTextAttr::SetFont
@@ -16549,14 +16586,14 @@ case wxTextAttr_SetLeftIndent: { // wxTextAttr::SetLeftIndent
} break;
}};
if(!This) throw wxe_badarg(0);
- This->SetLeftIndent((int) *indent,subIndent);
+ This->SetLeftIndent(*indent,subIndent);
break;
}
case wxTextAttr_SetRightIndent: { // wxTextAttr::SetRightIndent
wxTextAttr *This = (wxTextAttr *) getPtr(bp,memenv); bp += 4;
int * indent = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetRightIndent((int) *indent);
+ This->SetRightIndent(*indent);
break;
}
case wxTextAttr_SetTabs: { // wxTextAttr::SetTabs
@@ -16619,7 +16656,7 @@ case wxTextCtrl_new_3: { // wxTextCtrl::wxTextCtrl
validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
- wxTextCtrl * Result = new EwxTextCtrl(parent,(wxWindowID) *id,value,pos,size,style,*validator);
+ wxTextCtrl * Result = new EwxTextCtrl(parent,*id,value,pos,size,style,*validator);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxTextCtrl");
break;
@@ -16722,7 +16759,7 @@ validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,value,pos,size,style,*validator);
+ bool Result = This->Create(parent,*id,value,pos,size,style,*validator);
rt.addBool(Result);
break;
}
@@ -16771,7 +16808,7 @@ case wxTextCtrl_GetLineLength: { // wxTextCtrl::GetLineLength
wxTextCtrl *This = (wxTextCtrl *) getPtr(bp,memenv); bp += 4;
int * lineNo = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->GetLineLength((long) *lineNo);
+ int Result = This->GetLineLength(*lineNo);
rt.addInt(Result);
break;
}
@@ -16779,7 +16816,7 @@ case wxTextCtrl_GetLineText: { // wxTextCtrl::GetLineText
wxTextCtrl *This = (wxTextCtrl *) getPtr(bp,memenv); bp += 4;
int * lineNo = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxString Result = This->GetLineText((long) *lineNo);
+ wxString Result = This->GetLineText(*lineNo);
rt.add(Result);
break;
}
@@ -16795,7 +16832,7 @@ case wxTextCtrl_GetRange: { // wxTextCtrl::GetRange
int * from = (int *) bp; bp += 4;
int * to = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxString Result = This->GetRange((long) *from,(long) *to);
+ wxString Result = This->GetRange(*from,*to);
rt.add(Result);
break;
}
@@ -16822,7 +16859,7 @@ case wxTextCtrl_GetStyle: { // wxTextCtrl::GetStyle
int * position = (int *) bp; bp += 4;
wxTextAttr *style = (wxTextAttr *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->GetStyle((long) *position,*style);
+ bool Result = This->GetStyle(*position,*style);
rt.addBool(Result);
break;
}
@@ -16895,7 +16932,7 @@ case wxTextCtrl_PositionToXY: { // wxTextCtrl::PositionToXY
wxTextCtrl *This = (wxTextCtrl *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->PositionToXY((long) *pos,&x,&y);
+ bool Result = This->PositionToXY(*pos,&x,&y);
rt.addBool(Result);
rt.addInt(x);
rt.addInt(y);
@@ -16913,7 +16950,7 @@ case wxTextCtrl_Remove: { // wxTextCtrl::Remove
int * from = (int *) bp; bp += 4;
int * to = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->Remove((long) *from,(long) *to);
+ This->Remove(*from,*to);
break;
}
case wxTextCtrl_Replace: { // wxTextCtrl::Replace
@@ -16924,7 +16961,7 @@ case wxTextCtrl_Replace: { // wxTextCtrl::Replace
wxString value = wxString(bp, wxConvUTF8);
bp += *valueLen+((8-((0+ *valueLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- This->Replace((long) *from,(long) *to,value);
+ This->Replace(*from,*to,value);
break;
}
case wxTextCtrl_SaveFile: { // wxTextCtrl::SaveFile
@@ -16959,14 +16996,14 @@ case wxTextCtrl_SetEditable: { // wxTextCtrl::SetEditable
wxTextCtrl *This = (wxTextCtrl *) getPtr(bp,memenv); bp += 4;
bool * editable = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetEditable((bool) *editable);
+ This->SetEditable(*editable);
break;
}
case wxTextCtrl_SetInsertionPoint: { // wxTextCtrl::SetInsertionPoint
wxTextCtrl *This = (wxTextCtrl *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetInsertionPoint((long) *pos);
+ This->SetInsertionPoint(*pos);
break;
}
case wxTextCtrl_SetInsertionPointEnd: { // wxTextCtrl::SetInsertionPointEnd
@@ -16979,7 +17016,7 @@ case wxTextCtrl_SetMaxLength: { // wxTextCtrl::SetMaxLength
wxTextCtrl *This = (wxTextCtrl *) getPtr(bp,memenv); bp += 4;
unsigned int * len = (unsigned int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetMaxLength((long) *len);
+ This->SetMaxLength(*len);
break;
}
case wxTextCtrl_SetSelection: { // wxTextCtrl::SetSelection
@@ -16987,7 +17024,7 @@ case wxTextCtrl_SetSelection: { // wxTextCtrl::SetSelection
int * from = (int *) bp; bp += 4;
int * to = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetSelection((long) *from,(long) *to);
+ This->SetSelection(*from,*to);
break;
}
case wxTextCtrl_SetStyle: { // wxTextCtrl::SetStyle
@@ -16996,7 +17033,7 @@ case wxTextCtrl_SetStyle: { // wxTextCtrl::SetStyle
int * end = (int *) bp; bp += 4;
wxTextAttr *style = (wxTextAttr *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->SetStyle((long) *start,(long) *end,*style);
+ bool Result = This->SetStyle(*start,*end,*style);
rt.addBool(Result);
break;
}
@@ -17013,7 +17050,7 @@ case wxTextCtrl_ShowPosition: { // wxTextCtrl::ShowPosition
wxTextCtrl *This = (wxTextCtrl *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->ShowPosition((long) *pos);
+ This->ShowPosition(*pos);
break;
}
case wxTextCtrl_Undo: { // wxTextCtrl::Undo
@@ -17036,7 +17073,7 @@ case wxTextCtrl_XYToPosition: { // wxTextCtrl::XYToPosition
int * x = (int *) bp; bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- long Result = This->XYToPosition((long) *x,(long) *y);
+ long Result = This->XYToPosition(*x,*y);
rt.addInt(Result);
break;
}
@@ -17069,7 +17106,7 @@ case wxNotebook_new_3: { // wxNotebook::wxNotebook
style = (long)*(int *) bp; bp += 4;
} break;
}};
- wxNotebook * Result = new EwxNotebook(parent,(wxWindowID) *winid,pos,size,style);
+ wxNotebook * Result = new EwxNotebook(parent,*winid,pos,size,style);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxNotebook");
break;
@@ -17141,7 +17178,7 @@ case wxNotebook_Create: { // wxNotebook::Create
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,pos,size,style);
+ bool Result = This->Create(parent,*id,pos,size,style);
rt.addBool(Result);
break;
}
@@ -17156,7 +17193,7 @@ case wxNotebook_DeletePage: { // wxNotebook::DeletePage
wxNotebook *This = (wxNotebook *) getPtr(bp,memenv); bp += 4;
int * nPage = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->DeletePage((size_t) *nPage);
+ bool Result = This->DeletePage(*nPage);
rt.addBool(Result);
break;
}
@@ -17164,7 +17201,7 @@ case wxNotebook_RemovePage: { // wxNotebook::RemovePage
wxNotebook *This = (wxNotebook *) getPtr(bp,memenv); bp += 4;
int * nPage = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->RemovePage((size_t) *nPage);
+ bool Result = This->RemovePage(*nPage);
rt.addBool(Result);
break;
}
@@ -17186,7 +17223,7 @@ case wxNotebook_GetPage: { // wxNotebook::GetPage
wxNotebook *This = (wxNotebook *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxWindow * Result = (wxWindow*)This->GetPage((size_t) *n);
+ wxWindow * Result = (wxWindow*)This->GetPage(*n);
rt.addRef(getRef((void *)Result,memenv), "wxWindow");
break;
}
@@ -17201,7 +17238,7 @@ case wxNotebook_GetPageImage: { // wxNotebook::GetPageImage
wxNotebook *This = (wxNotebook *) getPtr(bp,memenv); bp += 4;
int * nPage = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->GetPageImage((size_t) *nPage);
+ int Result = This->GetPageImage(*nPage);
rt.addInt(Result);
break;
}
@@ -17209,7 +17246,7 @@ case wxNotebook_GetPageText: { // wxNotebook::GetPageText
wxNotebook *This = (wxNotebook *) getPtr(bp,memenv); bp += 4;
int * nPage = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxString Result = This->GetPageText((size_t) *nPage);
+ wxString Result = This->GetPageText(*nPage);
rt.add(Result);
break;
}
@@ -17265,7 +17302,7 @@ case wxNotebook_InsertPage: { // wxNotebook::InsertPage
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->InsertPage((size_t) *position,win,strText,bSelect,imageId);
+ bool Result = This->InsertPage(*position,win,strText,bSelect,imageId);
rt.addBool(Result);
break;
}
@@ -17299,7 +17336,7 @@ case wxNotebook_SetPageImage: { // wxNotebook::SetPageImage
int * nPage = (int *) bp; bp += 4;
int * nImage = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->SetPageImage((size_t) *nPage,(int) *nImage);
+ bool Result = This->SetPageImage(*nPage,*nImage);
rt.addBool(Result);
break;
}
@@ -17310,7 +17347,7 @@ case wxNotebook_SetPageText: { // wxNotebook::SetPageText
wxString strText = wxString(bp, wxConvUTF8);
bp += *strTextLen+((8-((4+ *strTextLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- bool Result = This->SetPageText((size_t) *nPage,strText);
+ bool Result = This->SetPageText(*nPage,strText);
rt.addBool(Result);
break;
}
@@ -17318,7 +17355,7 @@ case wxNotebook_SetSelection: { // wxNotebook::SetSelection
wxNotebook *This = (wxNotebook *) getPtr(bp,memenv); bp += 4;
int * nPage = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->SetSelection((size_t) *nPage);
+ int Result = This->SetSelection(*nPage);
rt.addInt(Result);
break;
}
@@ -17326,7 +17363,7 @@ case wxNotebook_ChangeSelection: { // wxNotebook::ChangeSelection
wxNotebook *This = (wxNotebook *) getPtr(bp,memenv); bp += 4;
int * nPage = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->ChangeSelection((size_t) *nPage);
+ int Result = This->ChangeSelection(*nPage);
rt.addInt(Result);
break;
}
@@ -17359,7 +17396,7 @@ case wxChoicebook_new_3: { // wxChoicebook::wxChoicebook
style = (long)*(int *) bp; bp += 4;
} break;
}};
- wxChoicebook * Result = new EwxChoicebook(parent,(wxWindowID) *id,pos,size,style);
+ wxChoicebook * Result = new EwxChoicebook(parent,*id,pos,size,style);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxChoicebook");
break;
@@ -17431,7 +17468,7 @@ case wxChoicebook_Create: { // wxChoicebook::Create
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,pos,size,style);
+ bool Result = This->Create(parent,*id,pos,size,style);
rt.addBool(Result);
break;
}
@@ -17446,7 +17483,7 @@ case wxChoicebook_DeletePage: { // wxChoicebook::DeletePage
wxChoicebook *This = (wxChoicebook *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->DeletePage((size_t) *n);
+ bool Result = This->DeletePage(*n);
rt.addBool(Result);
break;
}
@@ -17454,7 +17491,7 @@ case wxChoicebook_RemovePage: { // wxChoicebook::RemovePage
wxChoicebook *This = (wxChoicebook *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->RemovePage((size_t) *n);
+ bool Result = This->RemovePage(*n);
rt.addBool(Result);
break;
}
@@ -17476,7 +17513,7 @@ case wxChoicebook_GetPage: { // wxChoicebook::GetPage
wxChoicebook *This = (wxChoicebook *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxWindow * Result = (wxWindow*)This->GetPage((size_t) *n);
+ wxWindow * Result = (wxWindow*)This->GetPage(*n);
rt.addRef(getRef((void *)Result,memenv), "wxWindow");
break;
}
@@ -17491,7 +17528,7 @@ case wxChoicebook_GetPageImage: { // wxChoicebook::GetPageImage
wxChoicebook *This = (wxChoicebook *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->GetPageImage((size_t) *n);
+ int Result = This->GetPageImage(*n);
rt.addInt(Result);
break;
}
@@ -17499,7 +17536,7 @@ case wxChoicebook_GetPageText: { // wxChoicebook::GetPageText
wxChoicebook *This = (wxChoicebook *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxString Result = This->GetPageText((size_t) *n);
+ wxString Result = This->GetPageText(*n);
rt.add(Result);
break;
}
@@ -17541,7 +17578,7 @@ case wxChoicebook_InsertPage: { // wxChoicebook::InsertPage
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->InsertPage((size_t) *n,page,text,bSelect,imageId);
+ bool Result = This->InsertPage(*n,page,text,bSelect,imageId);
rt.addBool(Result);
break;
}
@@ -17566,7 +17603,7 @@ case wxChoicebook_SetPageImage: { // wxChoicebook::SetPageImage
int * n = (int *) bp; bp += 4;
int * imageId = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->SetPageImage((size_t) *n,(int) *imageId);
+ bool Result = This->SetPageImage(*n,*imageId);
rt.addBool(Result);
break;
}
@@ -17577,7 +17614,7 @@ case wxChoicebook_SetPageText: { // wxChoicebook::SetPageText
wxString strText = wxString(bp, wxConvUTF8);
bp += *strTextLen+((8-((4+ *strTextLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- bool Result = This->SetPageText((size_t) *n,strText);
+ bool Result = This->SetPageText(*n,strText);
rt.addBool(Result);
break;
}
@@ -17585,7 +17622,7 @@ case wxChoicebook_SetSelection: { // wxChoicebook::SetSelection
wxChoicebook *This = (wxChoicebook *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->SetSelection((size_t) *n);
+ int Result = This->SetSelection(*n);
rt.addInt(Result);
break;
}
@@ -17593,7 +17630,7 @@ case wxChoicebook_ChangeSelection: { // wxChoicebook::ChangeSelection
wxChoicebook *This = (wxChoicebook *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->ChangeSelection((size_t) *n);
+ int Result = This->ChangeSelection(*n);
rt.addInt(Result);
break;
}
@@ -17626,7 +17663,7 @@ case wxToolbook_new_3: { // wxToolbook::wxToolbook
style = (long)*(int *) bp; bp += 4;
} break;
}};
- wxToolbook * Result = new EwxToolbook(parent,(wxWindowID) *id,pos,size,style);
+ wxToolbook * Result = new EwxToolbook(parent,*id,pos,size,style);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxToolbook");
break;
@@ -17698,7 +17735,7 @@ case wxToolbook_Create: { // wxToolbook::Create
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,pos,size,style);
+ bool Result = This->Create(parent,*id,pos,size,style);
rt.addBool(Result);
break;
}
@@ -17713,7 +17750,7 @@ case wxToolbook_DeletePage: { // wxToolbook::DeletePage
wxToolbook *This = (wxToolbook *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->DeletePage((size_t) *n);
+ bool Result = This->DeletePage(*n);
rt.addBool(Result);
break;
}
@@ -17721,7 +17758,7 @@ case wxToolbook_RemovePage: { // wxToolbook::RemovePage
wxToolbook *This = (wxToolbook *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->RemovePage((size_t) *n);
+ bool Result = This->RemovePage(*n);
rt.addBool(Result);
break;
}
@@ -17743,7 +17780,7 @@ case wxToolbook_GetPage: { // wxToolbook::GetPage
wxToolbook *This = (wxToolbook *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxWindow * Result = (wxWindow*)This->GetPage((size_t) *n);
+ wxWindow * Result = (wxWindow*)This->GetPage(*n);
rt.addRef(getRef((void *)Result,memenv), "wxWindow");
break;
}
@@ -17758,7 +17795,7 @@ case wxToolbook_GetPageImage: { // wxToolbook::GetPageImage
wxToolbook *This = (wxToolbook *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->GetPageImage((size_t) *n);
+ int Result = This->GetPageImage(*n);
rt.addInt(Result);
break;
}
@@ -17766,7 +17803,7 @@ case wxToolbook_GetPageText: { // wxToolbook::GetPageText
wxToolbook *This = (wxToolbook *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxString Result = This->GetPageText((size_t) *n);
+ wxString Result = This->GetPageText(*n);
rt.add(Result);
break;
}
@@ -17808,7 +17845,7 @@ case wxToolbook_InsertPage: { // wxToolbook::InsertPage
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->InsertPage((size_t) *n,page,text,bSelect,imageId);
+ bool Result = This->InsertPage(*n,page,text,bSelect,imageId);
rt.addBool(Result);
break;
}
@@ -17833,7 +17870,7 @@ case wxToolbook_SetPageImage: { // wxToolbook::SetPageImage
int * n = (int *) bp; bp += 4;
int * imageId = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->SetPageImage((size_t) *n,(int) *imageId);
+ bool Result = This->SetPageImage(*n,*imageId);
rt.addBool(Result);
break;
}
@@ -17844,7 +17881,7 @@ case wxToolbook_SetPageText: { // wxToolbook::SetPageText
wxString strText = wxString(bp, wxConvUTF8);
bp += *strTextLen+((8-((4+ *strTextLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- bool Result = This->SetPageText((size_t) *n,strText);
+ bool Result = This->SetPageText(*n,strText);
rt.addBool(Result);
break;
}
@@ -17852,7 +17889,7 @@ case wxToolbook_SetSelection: { // wxToolbook::SetSelection
wxToolbook *This = (wxToolbook *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->SetSelection((size_t) *n);
+ int Result = This->SetSelection(*n);
rt.addInt(Result);
break;
}
@@ -17860,7 +17897,7 @@ case wxToolbook_ChangeSelection: { // wxToolbook::ChangeSelection
wxToolbook *This = (wxToolbook *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->ChangeSelection((size_t) *n);
+ int Result = This->ChangeSelection(*n);
rt.addInt(Result);
break;
}
@@ -17893,7 +17930,7 @@ case wxListbook_new_3: { // wxListbook::wxListbook
style = (long)*(int *) bp; bp += 4;
} break;
}};
- wxListbook * Result = new EwxListbook(parent,(wxWindowID) *id,pos,size,style);
+ wxListbook * Result = new EwxListbook(parent,*id,pos,size,style);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxListbook");
break;
@@ -17965,7 +18002,7 @@ case wxListbook_Create: { // wxListbook::Create
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,pos,size,style);
+ bool Result = This->Create(parent,*id,pos,size,style);
rt.addBool(Result);
break;
}
@@ -17980,7 +18017,7 @@ case wxListbook_DeletePage: { // wxListbook::DeletePage
wxListbook *This = (wxListbook *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->DeletePage((size_t) *n);
+ bool Result = This->DeletePage(*n);
rt.addBool(Result);
break;
}
@@ -17988,7 +18025,7 @@ case wxListbook_RemovePage: { // wxListbook::RemovePage
wxListbook *This = (wxListbook *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->RemovePage((size_t) *n);
+ bool Result = This->RemovePage(*n);
rt.addBool(Result);
break;
}
@@ -18010,7 +18047,7 @@ case wxListbook_GetPage: { // wxListbook::GetPage
wxListbook *This = (wxListbook *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxWindow * Result = (wxWindow*)This->GetPage((size_t) *n);
+ wxWindow * Result = (wxWindow*)This->GetPage(*n);
rt.addRef(getRef((void *)Result,memenv), "wxWindow");
break;
}
@@ -18025,7 +18062,7 @@ case wxListbook_GetPageImage: { // wxListbook::GetPageImage
wxListbook *This = (wxListbook *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->GetPageImage((size_t) *n);
+ int Result = This->GetPageImage(*n);
rt.addInt(Result);
break;
}
@@ -18033,7 +18070,7 @@ case wxListbook_GetPageText: { // wxListbook::GetPageText
wxListbook *This = (wxListbook *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxString Result = This->GetPageText((size_t) *n);
+ wxString Result = This->GetPageText(*n);
rt.add(Result);
break;
}
@@ -18075,7 +18112,7 @@ case wxListbook_InsertPage: { // wxListbook::InsertPage
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->InsertPage((size_t) *n,page,text,bSelect,imageId);
+ bool Result = This->InsertPage(*n,page,text,bSelect,imageId);
rt.addBool(Result);
break;
}
@@ -18100,7 +18137,7 @@ case wxListbook_SetPageImage: { // wxListbook::SetPageImage
int * n = (int *) bp; bp += 4;
int * imageId = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->SetPageImage((size_t) *n,(int) *imageId);
+ bool Result = This->SetPageImage(*n,*imageId);
rt.addBool(Result);
break;
}
@@ -18111,7 +18148,7 @@ case wxListbook_SetPageText: { // wxListbook::SetPageText
wxString strText = wxString(bp, wxConvUTF8);
bp += *strTextLen+((8-((4+ *strTextLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- bool Result = This->SetPageText((size_t) *n,strText);
+ bool Result = This->SetPageText(*n,strText);
rt.addBool(Result);
break;
}
@@ -18119,7 +18156,7 @@ case wxListbook_SetSelection: { // wxListbook::SetSelection
wxListbook *This = (wxListbook *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->SetSelection((size_t) *n);
+ int Result = This->SetSelection(*n);
rt.addInt(Result);
break;
}
@@ -18127,7 +18164,7 @@ case wxListbook_ChangeSelection: { // wxListbook::ChangeSelection
wxListbook *This = (wxListbook *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->ChangeSelection((size_t) *n);
+ int Result = This->ChangeSelection(*n);
rt.addInt(Result);
break;
}
@@ -18160,7 +18197,7 @@ case wxTreebook_new_3: { // wxTreebook::wxTreebook
style = (long)*(int *) bp; bp += 4;
} break;
}};
- wxTreebook * Result = new EwxTreebook(parent,(wxWindowID) *id,pos,size,style);
+ wxTreebook * Result = new EwxTreebook(parent,*id,pos,size,style);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxTreebook");
break;
@@ -18232,7 +18269,7 @@ case wxTreebook_Create: { // wxTreebook::Create
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,pos,size,style);
+ bool Result = This->Create(parent,*id,pos,size,style);
rt.addBool(Result);
break;
}
@@ -18247,7 +18284,7 @@ case wxTreebook_DeletePage: { // wxTreebook::DeletePage
wxTreebook *This = (wxTreebook *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->DeletePage((size_t) *pos);
+ bool Result = This->DeletePage(*pos);
rt.addBool(Result);
break;
}
@@ -18255,7 +18292,7 @@ case wxTreebook_RemovePage: { // wxTreebook::RemovePage
wxTreebook *This = (wxTreebook *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->RemovePage((size_t) *n);
+ bool Result = This->RemovePage(*n);
rt.addBool(Result);
break;
}
@@ -18277,7 +18314,7 @@ case wxTreebook_GetPage: { // wxTreebook::GetPage
wxTreebook *This = (wxTreebook *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxWindow * Result = (wxWindow*)This->GetPage((size_t) *n);
+ wxWindow * Result = (wxWindow*)This->GetPage(*n);
rt.addRef(getRef((void *)Result,memenv), "wxWindow");
break;
}
@@ -18292,7 +18329,7 @@ case wxTreebook_GetPageImage: { // wxTreebook::GetPageImage
wxTreebook *This = (wxTreebook *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->GetPageImage((size_t) *n);
+ int Result = This->GetPageImage(*n);
rt.addInt(Result);
break;
}
@@ -18300,7 +18337,7 @@ case wxTreebook_GetPageText: { // wxTreebook::GetPageText
wxTreebook *This = (wxTreebook *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxString Result = This->GetPageText((size_t) *n);
+ wxString Result = This->GetPageText(*n);
rt.add(Result);
break;
}
@@ -18321,7 +18358,7 @@ case wxTreebook_ExpandNode: { // wxTreebook::ExpandNode
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->ExpandNode((size_t) *pos,expand);
+ bool Result = This->ExpandNode(*pos,expand);
rt.addBool(Result);
break;
}
@@ -18329,7 +18366,7 @@ case wxTreebook_IsNodeExpanded: { // wxTreebook::IsNodeExpanded
wxTreebook *This = (wxTreebook *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->IsNodeExpanded((size_t) *pos);
+ bool Result = This->IsNodeExpanded(*pos);
rt.addBool(Result);
break;
}
@@ -18364,7 +18401,7 @@ case wxTreebook_InsertPage: { // wxTreebook::InsertPage
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->InsertPage((size_t) *pos,page,text,bSelect,imageId);
+ bool Result = This->InsertPage(*pos,page,text,bSelect,imageId);
rt.addBool(Result);
break;
}
@@ -18386,7 +18423,7 @@ case wxTreebook_InsertSubPage: { // wxTreebook::InsertSubPage
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->InsertSubPage((size_t) *pos,page,text,bSelect,imageId);
+ bool Result = This->InsertSubPage(*pos,page,text,bSelect,imageId);
rt.addBool(Result);
break;
}
@@ -18411,7 +18448,7 @@ case wxTreebook_SetPageImage: { // wxTreebook::SetPageImage
int * n = (int *) bp; bp += 4;
int * imageId = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->SetPageImage((size_t) *n,(int) *imageId);
+ bool Result = This->SetPageImage(*n,*imageId);
rt.addBool(Result);
break;
}
@@ -18422,7 +18459,7 @@ case wxTreebook_SetPageText: { // wxTreebook::SetPageText
wxString strText = wxString(bp, wxConvUTF8);
bp += *strTextLen+((8-((4+ *strTextLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- bool Result = This->SetPageText((size_t) *n,strText);
+ bool Result = This->SetPageText(*n,strText);
rt.addBool(Result);
break;
}
@@ -18430,7 +18467,7 @@ case wxTreebook_SetSelection: { // wxTreebook::SetSelection
wxTreebook *This = (wxTreebook *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->SetSelection((size_t) *n);
+ int Result = This->SetSelection(*n);
rt.addInt(Result);
break;
}
@@ -18438,7 +18475,7 @@ case wxTreebook_ChangeSelection: { // wxTreebook::ChangeSelection
wxTreebook *This = (wxTreebook *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->ChangeSelection((size_t) *n);
+ int Result = This->ChangeSelection(*n);
rt.addInt(Result);
break;
}
@@ -18790,7 +18827,7 @@ which = *(wxTreeItemIcon *) bp; bp += 4;;
} break;
}};
if(!This) throw wxe_badarg(0);
- int Result = This->GetItemImage(item,(wxTreeItemIcon) which);
+ int Result = This->GetItemImage(item,which);
rt.addInt(Result);
break;
}
@@ -18933,7 +18970,7 @@ case wxTreeCtrl_InsertItem: { // wxTreeCtrl::InsertItem
} break;
}};
if(!This) throw wxe_badarg(0);
- wxTreeItemId Result = This->InsertItem(parent,(size_t) *pos,text,image,selImage,data);
+ wxTreeItemId Result = This->InsertItem(parent,*pos,text,image,selImage,data);
rt.add((wxUIntPtr *) Result.m_pItem);
break;
}
@@ -19043,7 +19080,7 @@ case wxTreeCtrl_SetIndent: { // wxTreeCtrl::SetIndent
wxTreeCtrl *This = (wxTreeCtrl *) getPtr(bp,memenv); bp += 4;
unsigned int * indent = (unsigned int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetIndent((int) *indent);
+ This->SetIndent(*indent);
break;
}
case wxTreeCtrl_SetImageList: { // wxTreeCtrl::SetImageList
@@ -19132,7 +19169,7 @@ case wxTreeCtrl_SetItemImage_2: { // wxTreeCtrl::SetItemImage
wxTreeItemId item = wxTreeItemId((void *) *(wxUint64 *) bp); bp += 8;
int * image = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetItemImage(item,(int) *image);
+ This->SetItemImage(item,*image);
break;
}
case wxTreeCtrl_SetItemImage_3: { // wxTreeCtrl::SetItemImage
@@ -19148,7 +19185,7 @@ which = *(wxTreeItemIcon *) bp; bp += 4;;
} break;
}};
if(!This) throw wxe_badarg(0);
- This->SetItemImage(item,(int) *image,(wxTreeItemIcon) which);
+ This->SetItemImage(item,*image,which);
break;
}
case wxTreeCtrl_SetItemText: { // wxTreeCtrl::SetItemText
@@ -19186,7 +19223,7 @@ case wxTreeCtrl_SetWindowStyle: { // wxTreeCtrl::SetWindowStyle
wxTreeCtrl *This = (wxTreeCtrl *) getPtr(bp,memenv); bp += 4;
const int * styles = (const int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetWindowStyle((long) *styles);
+ This->SetWindowStyle(*styles);
break;
}
case wxTreeCtrl_SortChildren: { // wxTreeCtrl::SortChildren
@@ -19266,7 +19303,7 @@ case wxScrollBar_new_3: { // wxScrollBar::wxScrollBar
validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
- wxScrollBar * Result = new EwxScrollBar(parent,(wxWindowID) *id,pos,size,style,*validator);
+ wxScrollBar * Result = new EwxScrollBar(parent,*id,pos,size,style,*validator);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxScrollBar");
break;
@@ -19301,7 +19338,7 @@ validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,pos,size,style,*validator);
+ bool Result = This->Create(parent,*id,pos,size,style,*validator);
rt.addBool(Result);
break;
}
@@ -19337,7 +19374,7 @@ case wxScrollBar_SetThumbPosition: { // wxScrollBar::SetThumbPosition
wxScrollBar *This = (wxScrollBar *) getPtr(bp,memenv); bp += 4;
int * viewStart = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetThumbPosition((int) *viewStart);
+ This->SetThumbPosition(*viewStart);
break;
}
case wxScrollBar_SetScrollbar: { // wxScrollBar::SetScrollbar
@@ -19354,7 +19391,7 @@ case wxScrollBar_SetScrollbar: { // wxScrollBar::SetScrollbar
} break;
}};
if(!This) throw wxe_badarg(0);
- This->SetScrollbar((int) *position,(int) *thumbSize,(int) *range,(int) *pageSize,refresh);
+ This->SetScrollbar(*position,*thumbSize,*range,*pageSize,refresh);
break;
}
case wxSpinButton_new_2: { // wxSpinButton::wxSpinButton
@@ -19453,14 +19490,14 @@ case wxSpinButton_SetRange: { // wxSpinButton::SetRange
int * minVal = (int *) bp; bp += 4;
int * maxVal = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetRange((int) *minVal,(int) *maxVal);
+ This->SetRange(*minVal,*maxVal);
break;
}
case wxSpinButton_SetValue: { // wxSpinButton::SetValue
wxSpinButton *This = (wxSpinButton *) getPtr(bp,memenv); bp += 4;
int * value = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetValue((int) *value);
+ This->SetValue(*value);
break;
}
case wxSpinCtrl_new_0: { // wxSpinCtrl::wxSpinCtrl
@@ -19582,7 +19619,7 @@ case wxSpinCtrl_SetValue_1_0: { // wxSpinCtrl::SetValue
wxSpinCtrl *This = (wxSpinCtrl *) getPtr(bp,memenv); bp += 4;
int * value = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetValue((int) *value);
+ This->SetValue(*value);
break;
}
case wxSpinCtrl_GetValue: { // wxSpinCtrl::GetValue
@@ -19597,7 +19634,7 @@ case wxSpinCtrl_SetRange: { // wxSpinCtrl::SetRange
int * minVal = (int *) bp; bp += 4;
int * maxVal = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetRange((int) *minVal,(int) *maxVal);
+ This->SetRange(*minVal,*maxVal);
break;
}
case wxSpinCtrl_SetSelection: { // wxSpinCtrl::SetSelection
@@ -19605,7 +19642,7 @@ case wxSpinCtrl_SetSelection: { // wxSpinCtrl::SetSelection
int * from = (int *) bp; bp += 4;
int * to = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetSelection((long) *from,(long) *to);
+ This->SetSelection(*from,*to);
break;
}
case wxSpinCtrl_GetMin: { // wxSpinCtrl::GetMin
@@ -19654,7 +19691,7 @@ case wxStaticText_new_4: { // wxStaticText::wxStaticText
style = (long)*(int *) bp; bp += 4;
} break;
}};
- wxStaticText * Result = new EwxStaticText(parent,(wxWindowID) *id,label,pos,size,style);
+ wxStaticText * Result = new EwxStaticText(parent,*id,label,pos,size,style);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxStaticText");
break;
@@ -19687,7 +19724,7 @@ case wxStaticText_Create: { // wxStaticText::Create
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,label,pos,size,style);
+ bool Result = This->Create(parent,*id,label,pos,size,style);
rt.addBool(Result);
break;
}
@@ -19711,7 +19748,7 @@ case wxStaticText_Wrap: { // wxStaticText::Wrap
wxStaticText *This = (wxStaticText *) getPtr(bp,memenv); bp += 4;
int * width = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->Wrap((int) *width);
+ This->Wrap(*width);
break;
}
case wxStaticBitmap_new_0: { // wxStaticBitmap::wxStaticBitmap
@@ -19745,7 +19782,7 @@ case wxStaticBitmap_new_4: { // wxStaticBitmap::wxStaticBitmap
style = (long)*(int *) bp; bp += 4;
} break;
}};
- wxStaticBitmap * Result = new EwxStaticBitmap(parent,(wxWindowID) *id,*label,pos,size,style);
+ wxStaticBitmap * Result = new EwxStaticBitmap(parent,*id,*label,pos,size,style);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxStaticBitmap");
break;
@@ -19776,7 +19813,7 @@ case wxStaticBitmap_Create: { // wxStaticBitmap::Create
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,*label,pos,size,style);
+ bool Result = This->Create(parent,*id,*label,pos,size,style);
rt.addBool(Result);
break;
}
@@ -19830,7 +19867,7 @@ case wxRadioBox_new: { // wxRadioBox::wxRadioBox
val = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
- wxRadioBox * Result = new EwxRadioBox(parent,(wxWindowID) *id,title,pos,size,choices,majorDim,style,*val);
+ wxRadioBox * Result = new EwxRadioBox(parent,*id,title,pos,size,choices,majorDim,style,*val);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxRadioBox");
break;
@@ -19873,7 +19910,7 @@ val = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,title,pos,size,choices,majorDim,style,*val);
+ bool Result = This->Create(parent,*id,title,pos,size,choices,majorDim,style,*val);
rt.addBool(Result);
break;
}
@@ -19887,7 +19924,7 @@ case wxRadioBox_Enable_2: { // wxRadioBox::Enable
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Enable((int) *n,enable);
+ bool Result = This->Enable(*n,enable);
rt.addBool(Result);
break;
}
@@ -19916,7 +19953,7 @@ case wxRadioBox_GetString: { // wxRadioBox::GetString
wxRadioBox *This = (wxRadioBox *) getPtr(bp,memenv); bp += 4;
unsigned int * n = (unsigned int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxString Result = This->GetString((int) *n);
+ wxString Result = This->GetString(*n);
rt.add(Result);
break;
}
@@ -19924,7 +19961,7 @@ case wxRadioBox_SetSelection: { // wxRadioBox::SetSelection
wxRadioBox *This = (wxRadioBox *) getPtr(bp,memenv); bp += 4;
int * n = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetSelection((int) *n);
+ This->SetSelection(*n);
break;
}
case wxRadioBox_Show_2: { // wxRadioBox::Show
@@ -19937,7 +19974,7 @@ case wxRadioBox_Show_2: { // wxRadioBox::Show
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Show((int) *n,show);
+ bool Result = This->Show(*n,show);
rt.addBool(Result);
break;
}
@@ -19966,7 +20003,7 @@ case wxRadioBox_GetItemHelpText: { // wxRadioBox::GetItemHelpText
wxRadioBox *This = (wxRadioBox *) getPtr(bp,memenv); bp += 4;
unsigned int * n = (unsigned int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxString Result = This->GetItemHelpText((int) *n);
+ wxString Result = This->GetItemHelpText(*n);
rt.add(Result);
break;
}
@@ -19974,7 +20011,7 @@ case wxRadioBox_GetItemToolTip: { // wxRadioBox::GetItemToolTip
wxRadioBox *This = (wxRadioBox *) getPtr(bp,memenv); bp += 4;
unsigned int * item = (unsigned int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxToolTip * Result = (wxToolTip*)This->GetItemToolTip((int) *item);
+ wxToolTip * Result = (wxToolTip*)This->GetItemToolTip(*item);
rt.addRef(getRef((void *)Result,memenv), "wxToolTip");
break;
}
@@ -19999,7 +20036,7 @@ case wxRadioBox_IsItemEnabled: { // wxRadioBox::IsItemEnabled
wxRadioBox *This = (wxRadioBox *) getPtr(bp,memenv); bp += 4;
unsigned int * n = (unsigned int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->IsItemEnabled((int) *n);
+ bool Result = This->IsItemEnabled(*n);
rt.addBool(Result);
break;
}
@@ -20007,7 +20044,7 @@ case wxRadioBox_IsItemShown: { // wxRadioBox::IsItemShown
wxRadioBox *This = (wxRadioBox *) getPtr(bp,memenv); bp += 4;
unsigned int * n = (unsigned int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->IsItemShown((int) *n);
+ bool Result = This->IsItemShown(*n);
rt.addBool(Result);
break;
}
@@ -20018,7 +20055,7 @@ case wxRadioBox_SetItemHelpText: { // wxRadioBox::SetItemHelpText
wxString helpText = wxString(bp, wxConvUTF8);
bp += *helpTextLen+((8-((4+ *helpTextLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- This->SetItemHelpText((int) *n,helpText);
+ This->SetItemHelpText(*n,helpText);
break;
}
case wxRadioBox_SetItemToolTip: { // wxRadioBox::SetItemToolTip
@@ -20028,7 +20065,7 @@ case wxRadioBox_SetItemToolTip: { // wxRadioBox::SetItemToolTip
wxString text = wxString(bp, wxConvUTF8);
bp += *textLen+((8-((4+ *textLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- This->SetItemToolTip((int) *item,text);
+ This->SetItemToolTip(*item,text);
break;
}
case wxRadioButton_new_0: { // wxRadioButton::wxRadioButton
@@ -20067,7 +20104,7 @@ case wxRadioButton_new_4: { // wxRadioButton::wxRadioButton
validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
- wxRadioButton * Result = new EwxRadioButton(parent,(wxWindowID) *id,label,pos,size,style,*validator);
+ wxRadioButton * Result = new EwxRadioButton(parent,*id,label,pos,size,style,*validator);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxRadioButton");
break;
@@ -20104,7 +20141,7 @@ validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,label,pos,size,style,*validator);
+ bool Result = This->Create(parent,*id,label,pos,size,style,*validator);
rt.addBool(Result);
break;
}
@@ -20119,7 +20156,7 @@ case wxRadioButton_SetValue: { // wxRadioButton::SetValue
wxRadioButton *This = (wxRadioButton *) getPtr(bp,memenv); bp += 4;
bool * val = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetValue((bool) *val);
+ This->SetValue(*val);
break;
}
case wxSlider_new_6: { // wxSlider::wxSlider
@@ -20153,7 +20190,7 @@ case wxSlider_new_6: { // wxSlider::wxSlider
validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
- wxSlider * Result = new EwxSlider(parent,(wxWindowID) *id,(int) *value,(int) *minValue,(int) *maxValue,pos,size,style,*validator);
+ wxSlider * Result = new EwxSlider(parent,*id,*value,*minValue,*maxValue,pos,size,style,*validator);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxSlider");
break;
@@ -20196,7 +20233,7 @@ validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,(int) *value,(int) *minValue,(int) *maxValue,pos,size,style,*validator);
+ bool Result = This->Create(parent,*id,*value,*minValue,*maxValue,pos,size,style,*validator);
rt.addBool(Result);
break;
}
@@ -20246,14 +20283,14 @@ case wxSlider_SetLineSize: { // wxSlider::SetLineSize
wxSlider *This = (wxSlider *) getPtr(bp,memenv); bp += 4;
int * lineSize = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetLineSize((int) *lineSize);
+ This->SetLineSize(*lineSize);
break;
}
case wxSlider_SetPageSize: { // wxSlider::SetPageSize
wxSlider *This = (wxSlider *) getPtr(bp,memenv); bp += 4;
int * pageSize = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetPageSize((int) *pageSize);
+ This->SetPageSize(*pageSize);
break;
}
case wxSlider_SetRange: { // wxSlider::SetRange
@@ -20261,21 +20298,21 @@ case wxSlider_SetRange: { // wxSlider::SetRange
int * minValue = (int *) bp; bp += 4;
int * maxValue = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetRange((int) *minValue,(int) *maxValue);
+ This->SetRange(*minValue,*maxValue);
break;
}
case wxSlider_SetThumbLength: { // wxSlider::SetThumbLength
wxSlider *This = (wxSlider *) getPtr(bp,memenv); bp += 4;
int * lenPixels = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetThumbLength((int) *lenPixels);
+ This->SetThumbLength(*lenPixels);
break;
}
case wxSlider_SetValue: { // wxSlider::SetValue
wxSlider *This = (wxSlider *) getPtr(bp,memenv); bp += 4;
int * value = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetValue((int) *value);
+ This->SetValue(*value);
break;
}
case wxDialog_new_4: { // wxDialog::wxDialog
@@ -20304,7 +20341,7 @@ case wxDialog_new_4: { // wxDialog::wxDialog
style = (long)*(int *) bp; bp += 4;
} break;
}};
- wxDialog * Result = new EwxDialog(parent,(wxWindowID) *id,title,pos,size,style);
+ wxDialog * Result = new EwxDialog(parent,*id,title,pos,size,style);
newPtr((void *) Result, 2, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxDialog");
break;
@@ -20343,7 +20380,7 @@ case wxDialog_Create: { // wxDialog::Create
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,title,pos,size,style);
+ bool Result = This->Create(parent,*id,title,pos,size,style);
rt.addBool(Result);
break;
}
@@ -20351,7 +20388,7 @@ case wxDialog_CreateButtonSizer: { // wxDialog::CreateButtonSizer
wxDialog *This = (wxDialog *) getPtr(bp,memenv); bp += 4;
int * flags = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxSizer * Result = (wxSizer*)This->CreateButtonSizer((long) *flags);
+ wxSizer * Result = (wxSizer*)This->CreateButtonSizer(*flags);
rt.addRef(getRef((void *)Result,memenv), "wxSizer");
break;
}
@@ -20359,7 +20396,7 @@ case wxDialog_CreateStdDialogButtonSizer: { // wxDialog::CreateStdDialogButtonSi
wxDialog *This = (wxDialog *) getPtr(bp,memenv); bp += 4;
int * flags = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxStdDialogButtonSizer * Result = (wxStdDialogButtonSizer*)This->CreateStdDialogButtonSizer((long) *flags);
+ wxStdDialogButtonSizer * Result = (wxStdDialogButtonSizer*)This->CreateStdDialogButtonSizer(*flags);
rt.addRef(getRef((void *)Result,memenv), "wxStdDialogButtonSizer");
break;
}
@@ -20367,7 +20404,7 @@ case wxDialog_EndModal: { // wxDialog::EndModal
wxDialog *This = (wxDialog *) getPtr(bp,memenv); bp += 4;
int * retCode = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->EndModal((int) *retCode);
+ This->EndModal(*retCode);
break;
}
case wxDialog_GetAffirmativeId: { // wxDialog::GetAffirmativeId
@@ -20395,14 +20432,14 @@ case wxDialog_SetAffirmativeId: { // wxDialog::SetAffirmativeId
wxDialog *This = (wxDialog *) getPtr(bp,memenv); bp += 4;
int * affirmativeId = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetAffirmativeId((int) *affirmativeId);
+ This->SetAffirmativeId(*affirmativeId);
break;
}
case wxDialog_SetReturnCode: { // wxDialog::SetReturnCode
wxDialog *This = (wxDialog *) getPtr(bp,memenv); bp += 4;
int * returnCode = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetReturnCode((int) *returnCode);
+ This->SetReturnCode(*returnCode);
break;
}
case wxDialog_Show: { // wxDialog::Show
@@ -20498,7 +20535,7 @@ case wxColourData_GetCustomColour: { // wxColourData::GetCustomColour
wxColourData *This = (wxColourData *) getPtr(bp,memenv); bp += 4;
int * i = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxColour Result = This->GetCustomColour((int) *i);
+ wxColour Result = This->GetCustomColour(*i);
rt.add(Result);
break;
}
@@ -20506,7 +20543,7 @@ case wxColourData_SetChooseFull: { // wxColourData::SetChooseFull
wxColourData *This = (wxColourData *) getPtr(bp,memenv); bp += 4;
bool * flag = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetChooseFull((bool) *flag);
+ This->SetChooseFull(*flag);
break;
}
case wxColourData_SetColour: { // wxColourData::SetColour
@@ -20529,7 +20566,7 @@ case wxColourData_SetCustomColour: { // wxColourData::SetCustomColour
int * colourA = (int *) bp; bp += 4;
wxColour colour = wxColour(*colourR,*colourG,*colourB,*colourA);
if(!This) throw wxe_badarg(0);
- This->SetCustomColour((int) *i,colour);
+ This->SetCustomColour(*i,colour);
break;
}
case wxPalette_new_0: { // wxPalette::wxPalette
@@ -20570,7 +20607,7 @@ case wxPalette_GetPixel: { // wxPalette::GetPixel
unsigned int * green = (unsigned int *) bp; bp += 4;
unsigned int * blue = (unsigned int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->GetPixel((char) *red,(char) *green,(char) *blue);
+ int Result = This->GetPixel(*red,*green,*blue);
rt.addInt(Result);
break;
}
@@ -20581,7 +20618,7 @@ case wxPalette_GetRGB: { // wxPalette::GetRGB
wxPalette *This = (wxPalette *) getPtr(bp,memenv); bp += 4;
int * pixel = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->GetRGB((int) *pixel,&red,&green,&blue);
+ bool Result = This->GetRGB(*pixel,&red,&green,&blue);
rt.addBool(Result);
rt.addUint(red);
rt.addUint(green);
@@ -20800,7 +20837,7 @@ case wxFileDialog_SetFilterIndex: { // wxFileDialog::SetFilterIndex
wxFileDialog *This = (wxFileDialog *) getPtr(bp,memenv); bp += 4;
int * filterIndex = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetFilterIndex((int) *filterIndex);
+ This->SetFilterIndex(*filterIndex);
break;
}
case wxFileDialog_SetMessage: { // wxFileDialog::SetMessage
@@ -20834,7 +20871,7 @@ case wxPickerBase_SetInternalMargin: { // wxPickerBase::SetInternalMargin
wxPickerBase *This = (wxPickerBase *) getPtr(bp,memenv); bp += 4;
int * newmargin = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetInternalMargin((int) *newmargin);
+ This->SetInternalMargin(*newmargin);
break;
}
case wxPickerBase_GetInternalMargin: { // wxPickerBase::GetInternalMargin
@@ -20848,14 +20885,14 @@ case wxPickerBase_SetTextCtrlProportion: { // wxPickerBase::SetTextCtrlProportio
wxPickerBase *This = (wxPickerBase *) getPtr(bp,memenv); bp += 4;
int * prop = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetTextCtrlProportion((int) *prop);
+ This->SetTextCtrlProportion(*prop);
break;
}
case wxPickerBase_SetPickerCtrlProportion: { // wxPickerBase::SetPickerCtrlProportion
wxPickerBase *This = (wxPickerBase *) getPtr(bp,memenv); bp += 4;
int * prop = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetPickerCtrlProportion((int) *prop);
+ This->SetPickerCtrlProportion(*prop);
break;
}
case wxPickerBase_GetTextCtrlProportion: { // wxPickerBase::GetTextCtrlProportion
@@ -20977,7 +21014,7 @@ case wxFilePickerCtrl_new_3: { // wxFilePickerCtrl::wxFilePickerCtrl
validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
- wxFilePickerCtrl * Result = new EwxFilePickerCtrl(parent,(wxWindowID) *id,path,message,wildcard,pos,size,style,*validator);
+ wxFilePickerCtrl * Result = new EwxFilePickerCtrl(parent,*id,path,message,wildcard,pos,size,style,*validator);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxFilePickerCtrl");
break;
@@ -21030,7 +21067,7 @@ validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,path,message,wildcard,pos,size,style,*validator);
+ bool Result = This->Create(parent,*id,path,message,wildcard,pos,size,style,*validator);
rt.addBool(Result);
break;
}
@@ -21095,7 +21132,7 @@ case wxDirPickerCtrl_new_3: { // wxDirPickerCtrl::wxDirPickerCtrl
validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
- wxDirPickerCtrl * Result = new EwxDirPickerCtrl(parent,(wxWindowID) *id,path,message,pos,size,style,*validator);
+ wxDirPickerCtrl * Result = new EwxDirPickerCtrl(parent,*id,path,message,pos,size,style,*validator);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxDirPickerCtrl");
break;
@@ -21142,7 +21179,7 @@ validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,path,message,pos,size,style,*validator);
+ bool Result = This->Create(parent,*id,path,message,pos,size,style,*validator);
rt.addBool(Result);
break;
}
@@ -21204,7 +21241,7 @@ case wxColourPickerCtrl_new_3: { // wxColourPickerCtrl::wxColourPickerCtrl
validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
- wxColourPickerCtrl * Result = new EwxColourPickerCtrl(parent,(wxWindowID) *id,col,pos,size,style,*validator);
+ wxColourPickerCtrl * Result = new EwxColourPickerCtrl(parent,*id,col,pos,size,style,*validator);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxColourPickerCtrl");
break;
@@ -21248,7 +21285,7 @@ validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,col,pos,size,style,*validator);
+ bool Result = This->Create(parent,*id,col,pos,size,style,*validator);
rt.addBool(Result);
break;
}
@@ -21324,7 +21361,7 @@ case wxDatePickerCtrl_new_3: { // wxDatePickerCtrl::wxDatePickerCtrl
validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
- wxDatePickerCtrl * Result = new EwxDatePickerCtrl(parent,(wxWindowID) *id,date,pos,size,style,*validator);
+ wxDatePickerCtrl * Result = new EwxDatePickerCtrl(parent,*id,date,pos,size,style,*validator);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxDatePickerCtrl");
break;
@@ -21427,7 +21464,7 @@ initial = (wxFont *) getPtr(bp,memenv); bp += 4;
validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
- wxFontPickerCtrl * Result = new EwxFontPickerCtrl(parent,(wxWindowID) *id,*initial,pos,size,style,*validator);
+ wxFontPickerCtrl * Result = new EwxFontPickerCtrl(parent,*id,*initial,pos,size,style,*validator);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxFontPickerCtrl");
break;
@@ -21466,7 +21503,7 @@ validator = (wxValidator *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,*initial,pos,size,style,*validator);
+ bool Result = This->Create(parent,*id,*initial,pos,size,style,*validator);
rt.addBool(Result);
break;
}
@@ -21495,7 +21532,7 @@ case wxFontPickerCtrl_SetMaxPointSize: { // wxFontPickerCtrl::SetMaxPointSize
wxFontPickerCtrl *This = (wxFontPickerCtrl *) getPtr(bp,memenv); bp += 4;
unsigned int * max = (unsigned int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetMaxPointSize((int) *max);
+ This->SetMaxPointSize(*max);
break;
}
case wxFindReplaceDialog_new_0: { // wxFindReplaceDialog::wxFindReplaceDialog
@@ -21554,7 +21591,7 @@ case wxFindReplaceData_new_0: { // wxFindReplaceData::wxFindReplaceData
}
case wxFindReplaceData_new_1: { // wxFindReplaceData::wxFindReplaceData
unsigned int * flags = (unsigned int *) bp; bp += 4;
- wxFindReplaceData * Result = new EwxFindReplaceData((int) *flags);
+ wxFindReplaceData * Result = new EwxFindReplaceData(*flags);
newPtr((void *) Result, 1, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxFindReplaceData");
break;
@@ -21584,7 +21621,7 @@ case wxFindReplaceData_SetFlags: { // wxFindReplaceData::SetFlags
wxFindReplaceData *This = (wxFindReplaceData *) getPtr(bp,memenv); bp += 4;
unsigned int * flags = (unsigned int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetFlags((int) *flags);
+ This->SetFlags(*flags);
break;
}
case wxFindReplaceData_SetFindString: { // wxFindReplaceData::SetFindString
@@ -21725,7 +21762,7 @@ case wxSingleChoiceDialog_SetSelection: { // wxSingleChoiceDialog::SetSelection
wxSingleChoiceDialog *This = (wxSingleChoiceDialog *) getPtr(bp,memenv); bp += 4;
int * sel = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetSelection((int) *sel);
+ This->SetSelection(*sel);
break;
}
case wxTextEntryDialog_new: { // wxTextEntryDialog::wxTextEntryDialog
@@ -21831,7 +21868,7 @@ case wxFontData_EnableEffects: { // wxFontData::EnableEffects
wxFontData *This = (wxFontData *) getPtr(bp,memenv); bp += 4;
bool * flag = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->EnableEffects((bool) *flag);
+ This->EnableEffects(*flag);
break;
}
case wxFontData_GetAllowSymbols: { // wxFontData::GetAllowSymbols
@@ -21880,7 +21917,7 @@ case wxFontData_SetAllowSymbols: { // wxFontData::SetAllowSymbols
wxFontData *This = (wxFontData *) getPtr(bp,memenv); bp += 4;
bool * flag = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetAllowSymbols((bool) *flag);
+ This->SetAllowSymbols(*flag);
break;
}
case wxFontData_SetChosenFont: { // wxFontData::SetChosenFont
@@ -21913,14 +21950,14 @@ case wxFontData_SetRange: { // wxFontData::SetRange
int * minRange = (int *) bp; bp += 4;
int * maxRange = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetRange((int) *minRange,(int) *maxRange);
+ This->SetRange(*minRange,*maxRange);
break;
}
case wxFontData_SetShowHelp: { // wxFontData::SetShowHelp
wxFontData *This = (wxFontData *) getPtr(bp,memenv); bp += 4;
bool * flag = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetShowHelp((bool) *flag);
+ This->SetShowHelp(*flag);
break;
}
case wxFontDialog_new_0: { // wxFontDialog::wxFontDialog
@@ -21997,7 +22034,7 @@ case wxProgressDialog_Update_2: { // wxProgressDialog::Update
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Update((int) *value,newmsg);
+ bool Result = This->Update(*value,newmsg);
rt.addBool(Result);
break;
}
@@ -22088,35 +22125,35 @@ case wxPageSetupDialogData_EnableHelp: { // wxPageSetupDialogData::EnableHelp
wxPageSetupDialogData *This = (wxPageSetupDialogData *) getPtr(bp,memenv); bp += 4;
bool * flag = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->EnableHelp((bool) *flag);
+ This->EnableHelp(*flag);
break;
}
case wxPageSetupDialogData_EnableMargins: { // wxPageSetupDialogData::EnableMargins
wxPageSetupDialogData *This = (wxPageSetupDialogData *) getPtr(bp,memenv); bp += 4;
bool * flag = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->EnableMargins((bool) *flag);
+ This->EnableMargins(*flag);
break;
}
case wxPageSetupDialogData_EnableOrientation: { // wxPageSetupDialogData::EnableOrientation
wxPageSetupDialogData *This = (wxPageSetupDialogData *) getPtr(bp,memenv); bp += 4;
bool * flag = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->EnableOrientation((bool) *flag);
+ This->EnableOrientation(*flag);
break;
}
case wxPageSetupDialogData_EnablePaper: { // wxPageSetupDialogData::EnablePaper
wxPageSetupDialogData *This = (wxPageSetupDialogData *) getPtr(bp,memenv); bp += 4;
bool * flag = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->EnablePaper((bool) *flag);
+ This->EnablePaper(*flag);
break;
}
case wxPageSetupDialogData_EnablePrinter: { // wxPageSetupDialogData::EnablePrinter
wxPageSetupDialogData *This = (wxPageSetupDialogData *) getPtr(bp,memenv); bp += 4;
bool * flag = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->EnablePrinter((bool) *flag);
+ This->EnablePrinter(*flag);
break;
}
case wxPageSetupDialogData_GetDefaultMinMargins: { // wxPageSetupDialogData::GetDefaultMinMargins
@@ -22199,7 +22236,7 @@ case wxPageSetupDialogData_GetMinMarginBottomRight: { // wxPageSetupDialogData::
case wxPageSetupDialogData_GetPaperId: { // wxPageSetupDialogData::GetPaperId
wxPageSetupDialogData *This = (wxPageSetupDialogData *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- wxPaperSize Result = This->GetPaperId();
+ int Result = This->GetPaperId();
rt.addInt(Result);
break;
}
@@ -22228,14 +22265,14 @@ case wxPageSetupDialogData_SetDefaultInfo: { // wxPageSetupDialogData::SetDefaul
wxPageSetupDialogData *This = (wxPageSetupDialogData *) getPtr(bp,memenv); bp += 4;
bool * flag = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetDefaultInfo((bool) *flag);
+ This->SetDefaultInfo(*flag);
break;
}
case wxPageSetupDialogData_SetDefaultMinMargins: { // wxPageSetupDialogData::SetDefaultMinMargins
wxPageSetupDialogData *This = (wxPageSetupDialogData *) getPtr(bp,memenv); bp += 4;
bool * flag = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetDefaultMinMargins((bool) *flag);
+ This->SetDefaultMinMargins(*flag);
break;
}
case wxPageSetupDialogData_SetMarginTopLeft: { // wxPageSetupDialogData::SetMarginTopLeft
@@ -22276,9 +22313,9 @@ case wxPageSetupDialogData_SetMinMarginBottomRight: { // wxPageSetupDialogData::
}
case wxPageSetupDialogData_SetPaperId: { // wxPageSetupDialogData::SetPaperId
wxPageSetupDialogData *This = (wxPageSetupDialogData *) getPtr(bp,memenv); bp += 4;
- int * id = (int *) bp; bp += 4;
+ wxPaperSize id = *(wxPaperSize *) bp; bp += 4;;
if(!This) throw wxe_badarg(0);
- This->SetPaperId((wxPaperSize) *id);
+ This->SetPaperId(id);
break;
}
case wxPageSetupDialogData_SetPaperSize_1_1: { // wxPageSetupDialogData::SetPaperSize
@@ -22292,9 +22329,9 @@ case wxPageSetupDialogData_SetPaperSize_1_1: { // wxPageSetupDialogData::SetPape
}
case wxPageSetupDialogData_SetPaperSize_1_0: { // wxPageSetupDialogData::SetPaperSize
wxPageSetupDialogData *This = (wxPageSetupDialogData *) getPtr(bp,memenv); bp += 4;
- int * id = (int *) bp; bp += 4;
+ wxPaperSize id = *(wxPaperSize *) bp; bp += 4;;
if(!This) throw wxe_badarg(0);
- This->SetPaperSize((wxPaperSize) *id);
+ This->SetPaperSize(id);
break;
}
case wxPageSetupDialogData_SetPrintData: { // wxPageSetupDialogData::SetPrintData
@@ -22364,28 +22401,28 @@ case wxPrintDialogData_EnableHelp: { // wxPrintDialogData::EnableHelp
wxPrintDialogData *This = (wxPrintDialogData *) getPtr(bp,memenv); bp += 4;
bool * flag = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->EnableHelp((bool) *flag);
+ This->EnableHelp(*flag);
break;
}
case wxPrintDialogData_EnablePageNumbers: { // wxPrintDialogData::EnablePageNumbers
wxPrintDialogData *This = (wxPrintDialogData *) getPtr(bp,memenv); bp += 4;
bool * flag = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->EnablePageNumbers((bool) *flag);
+ This->EnablePageNumbers(*flag);
break;
}
case wxPrintDialogData_EnablePrintToFile: { // wxPrintDialogData::EnablePrintToFile
wxPrintDialogData *This = (wxPrintDialogData *) getPtr(bp,memenv); bp += 4;
bool * flag = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->EnablePrintToFile((bool) *flag);
+ This->EnablePrintToFile(*flag);
break;
}
case wxPrintDialogData_EnableSelection: { // wxPrintDialogData::EnableSelection
wxPrintDialogData *This = (wxPrintDialogData *) getPtr(bp,memenv); bp += 4;
bool * flag = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->EnableSelection((bool) *flag);
+ This->EnableSelection(*flag);
break;
}
case wxPrintDialogData_GetAllPages: { // wxPrintDialogData::GetAllPages
@@ -22469,35 +22506,35 @@ case wxPrintDialogData_SetCollate: { // wxPrintDialogData::SetCollate
wxPrintDialogData *This = (wxPrintDialogData *) getPtr(bp,memenv); bp += 4;
bool * flag = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetCollate((bool) *flag);
+ This->SetCollate(*flag);
break;
}
case wxPrintDialogData_SetFromPage: { // wxPrintDialogData::SetFromPage
wxPrintDialogData *This = (wxPrintDialogData *) getPtr(bp,memenv); bp += 4;
int * v = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetFromPage((int) *v);
+ This->SetFromPage(*v);
break;
}
case wxPrintDialogData_SetMaxPage: { // wxPrintDialogData::SetMaxPage
wxPrintDialogData *This = (wxPrintDialogData *) getPtr(bp,memenv); bp += 4;
int * v = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetMaxPage((int) *v);
+ This->SetMaxPage(*v);
break;
}
case wxPrintDialogData_SetMinPage: { // wxPrintDialogData::SetMinPage
wxPrintDialogData *This = (wxPrintDialogData *) getPtr(bp,memenv); bp += 4;
int * v = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetMinPage((int) *v);
+ This->SetMinPage(*v);
break;
}
case wxPrintDialogData_SetNoCopies: { // wxPrintDialogData::SetNoCopies
wxPrintDialogData *This = (wxPrintDialogData *) getPtr(bp,memenv); bp += 4;
int * v = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetNoCopies((int) *v);
+ This->SetNoCopies(*v);
break;
}
case wxPrintDialogData_SetPrintData: { // wxPrintDialogData::SetPrintData
@@ -22511,21 +22548,21 @@ case wxPrintDialogData_SetPrintToFile: { // wxPrintDialogData::SetPrintToFile
wxPrintDialogData *This = (wxPrintDialogData *) getPtr(bp,memenv); bp += 4;
bool * flag = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetPrintToFile((bool) *flag);
+ This->SetPrintToFile(*flag);
break;
}
case wxPrintDialogData_SetSelection: { // wxPrintDialogData::SetSelection
wxPrintDialogData *This = (wxPrintDialogData *) getPtr(bp,memenv); bp += 4;
bool * flag = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetSelection((bool) *flag);
+ This->SetSelection(*flag);
break;
}
case wxPrintDialogData_SetToPage: { // wxPrintDialogData::SetToPage
wxPrintDialogData *This = (wxPrintDialogData *) getPtr(bp,memenv); bp += 4;
int * v = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetToPage((int) *v);
+ This->SetToPage(*v);
break;
}
case wxPrintData_new_0: { // wxPrintData::wxPrintData
@@ -22586,7 +22623,7 @@ case wxPrintData_GetOrientation: { // wxPrintData::GetOrientation
case wxPrintData_GetPaperId: { // wxPrintData::GetPaperId
wxPrintData *This = (wxPrintData *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- wxPaperSize Result = This->GetPaperId();
+ int Result = This->GetPaperId();
rt.addInt(Result);
break;
}
@@ -22615,49 +22652,49 @@ case wxPrintData_SetBin: { // wxPrintData::SetBin
wxPrintData *This = (wxPrintData *) getPtr(bp,memenv); bp += 4;
wxPrintBin bin = *(wxPrintBin *) bp; bp += 4;;
if(!This) throw wxe_badarg(0);
- This->SetBin((wxPrintBin) bin);
+ This->SetBin(bin);
break;
}
case wxPrintData_SetCollate: { // wxPrintData::SetCollate
wxPrintData *This = (wxPrintData *) getPtr(bp,memenv); bp += 4;
bool * flag = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetCollate((bool) *flag);
+ This->SetCollate(*flag);
break;
}
case wxPrintData_SetColour: { // wxPrintData::SetColour
wxPrintData *This = (wxPrintData *) getPtr(bp,memenv); bp += 4;
bool * colour = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetColour((bool) *colour);
+ This->SetColour(*colour);
break;
}
case wxPrintData_SetDuplex: { // wxPrintData::SetDuplex
wxPrintData *This = (wxPrintData *) getPtr(bp,memenv); bp += 4;
wxDuplexMode duplex = *(wxDuplexMode *) bp; bp += 4;;
if(!This) throw wxe_badarg(0);
- This->SetDuplex((wxDuplexMode) duplex);
+ This->SetDuplex(duplex);
break;
}
case wxPrintData_SetNoCopies: { // wxPrintData::SetNoCopies
wxPrintData *This = (wxPrintData *) getPtr(bp,memenv); bp += 4;
int * v = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetNoCopies((int) *v);
+ This->SetNoCopies(*v);
break;
}
case wxPrintData_SetOrientation: { // wxPrintData::SetOrientation
wxPrintData *This = (wxPrintData *) getPtr(bp,memenv); bp += 4;
int * orient = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetOrientation((int) *orient);
+ This->SetOrientation(*orient);
break;
}
case wxPrintData_SetPaperId: { // wxPrintData::SetPaperId
wxPrintData *This = (wxPrintData *) getPtr(bp,memenv); bp += 4;
- int * sizeId = (int *) bp; bp += 4;
+ wxPaperSize sizeId = *(wxPaperSize *) bp; bp += 4;;
if(!This) throw wxe_badarg(0);
- This->SetPaperId((wxPaperSize) *sizeId);
+ This->SetPaperId(sizeId);
break;
}
case wxPrintData_SetPrinterName: { // wxPrintData::SetPrinterName
@@ -22673,7 +22710,7 @@ case wxPrintData_SetQuality: { // wxPrintData::SetQuality
wxPrintData *This = (wxPrintData *) getPtr(bp,memenv); bp += 4;
int * quality = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetQuality((wxPrintQuality) *quality);
+ This->SetQuality(*quality);
break;
}
case wxPrintPreview_new_2: { // wxPrintPreview::wxPrintPreview
@@ -22772,7 +22809,7 @@ case wxPrintPreview_Print: { // wxPrintPreview::Print
wxPrintPreview *This = (wxPrintPreview *) getPtr(bp,memenv); bp += 4;
bool * interactive = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->Print((bool) *interactive);
+ bool Result = This->Print(*interactive);
rt.addBool(Result);
break;
}
@@ -22780,7 +22817,7 @@ case wxPrintPreview_RenderPage: { // wxPrintPreview::RenderPage
wxPrintPreview *This = (wxPrintPreview *) getPtr(bp,memenv); bp += 4;
int * pageNum = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->RenderPage((int) *pageNum);
+ bool Result = This->RenderPage(*pageNum);
rt.addBool(Result);
break;
}
@@ -22795,7 +22832,7 @@ case wxPrintPreview_SetCurrentPage: { // wxPrintPreview::SetCurrentPage
wxPrintPreview *This = (wxPrintPreview *) getPtr(bp,memenv); bp += 4;
int * pageNum = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->SetCurrentPage((int) *pageNum);
+ bool Result = This->SetCurrentPage(*pageNum);
rt.addBool(Result);
break;
}
@@ -22817,7 +22854,7 @@ case wxPrintPreview_SetZoom: { // wxPrintPreview::SetZoom
wxPrintPreview *This = (wxPrintPreview *) getPtr(bp,memenv); bp += 4;
int * percent = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetZoom((int) *percent);
+ This->SetZoom(*percent);
break;
}
case wxPreviewFrame_new: { // wxPreviewFrame::wxPreviewFrame
@@ -22904,7 +22941,7 @@ case wxPreviewControlBar_new: { // wxPreviewControlBar::wxPreviewControlBar
style = (long)*(int *) bp; bp += 4;
} break;
}};
- wxPreviewControlBar * Result = new EwxPreviewControlBar(preview,(long) *buttons,parent,pos,size,style);
+ wxPreviewControlBar * Result = new EwxPreviewControlBar(preview,*buttons,parent,pos,size,style);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxPreviewControlBar");
break;
@@ -22933,7 +22970,7 @@ case wxPreviewControlBar_SetZoomControl: { // wxPreviewControlBar::SetZoomContro
wxPreviewControlBar *This = (wxPreviewControlBar *) getPtr(bp,memenv); bp += 4;
int * zoom = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetZoomControl((int) *zoom);
+ This->SetZoomControl(*zoom);
break;
}
case wxPrinter_new: { // wxPrinter::wxPrinter
@@ -23089,7 +23126,7 @@ case wxXmlResource_CompareVersion: { // wxXmlResource::CompareVersion
int * release = (int *) bp; bp += 4;
int * revision = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->CompareVersion((int) *major,(int) *minor,(int) *release,(int) *revision);
+ int Result = This->CompareVersion(*major,*minor,*release,*revision);
rt.addInt(Result);
break;
}
@@ -23283,7 +23320,7 @@ case wxXmlResource_SetFlags: { // wxXmlResource::SetFlags
wxXmlResource *This = (wxXmlResource *) getPtr(bp,memenv); bp += 4;
int * flags = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetFlags((int) *flags);
+ This->SetFlags(*flags);
break;
}
case wxXmlResource_Unload: { // wxXmlResource::Unload
@@ -23811,14 +23848,14 @@ case wxAuiManager_SetDockSizeConstraint: { // wxAuiManager::SetDockSizeConstrain
double * width_pct = (double *) bp; bp += 8;
double * height_pct = (double *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->SetDockSizeConstraint((double) *width_pct,(double) *height_pct);
+ This->SetDockSizeConstraint(*width_pct,*height_pct);
break;
}
case wxAuiManager_SetFlags: { // wxAuiManager::SetFlags
wxAuiManager *This = (wxAuiManager *) getPtr(bp,memenv); bp += 4;
unsigned int * flags = (unsigned int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetFlags((int) *flags);
+ This->SetFlags(*flags);
break;
}
case wxAuiManager_SetManagedWindow: { // wxAuiManager::SetManagedWindow
@@ -23887,7 +23924,7 @@ case wxAuiPaneInfo_BestSize_2: { // wxAuiPaneInfo::BestSize
int * x = (int *) bp; bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxAuiPaneInfo * Result = &This->BestSize((int) *x,(int) *y);
+ wxAuiPaneInfo * Result = &This->BestSize(*x,*y);
rt.addRef(getRef((void *)Result,memenv), "wxAuiPaneInfo");
break;
}
@@ -23989,7 +24026,7 @@ case wxAuiPaneInfo_Direction: { // wxAuiPaneInfo::Direction
wxAuiPaneInfo *This = (wxAuiPaneInfo *) getPtr(bp,memenv); bp += 4;
int * direction = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxAuiPaneInfo * Result = &This->Direction((int) *direction);
+ wxAuiPaneInfo * Result = &This->Direction(*direction);
rt.addRef(getRef((void *)Result,memenv), "wxAuiPaneInfo");
break;
}
@@ -24057,7 +24094,7 @@ case wxAuiPaneInfo_FloatingPosition_2: { // wxAuiPaneInfo::FloatingPosition
int * x = (int *) bp; bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxAuiPaneInfo * Result = &This->FloatingPosition((int) *x,(int) *y);
+ wxAuiPaneInfo * Result = &This->FloatingPosition(*x,*y);
rt.addRef(getRef((void *)Result,memenv), "wxAuiPaneInfo");
break;
}
@@ -24076,7 +24113,7 @@ case wxAuiPaneInfo_FloatingSize_2: { // wxAuiPaneInfo::FloatingSize
int * x = (int *) bp; bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxAuiPaneInfo * Result = &This->FloatingSize((int) *x,(int) *y);
+ wxAuiPaneInfo * Result = &This->FloatingSize(*x,*y);
rt.addRef(getRef((void *)Result,memenv), "wxAuiPaneInfo");
break;
}
@@ -24133,7 +24170,7 @@ case wxAuiPaneInfo_HasFlag: { // wxAuiPaneInfo::HasFlag
wxAuiPaneInfo *This = (wxAuiPaneInfo *) getPtr(bp,memenv); bp += 4;
unsigned int * flag = (unsigned int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->HasFlag((int) *flag);
+ bool Result = This->HasFlag(*flag);
rt.addBool(Result);
break;
}
@@ -24274,7 +24311,7 @@ case wxAuiPaneInfo_Layer: { // wxAuiPaneInfo::Layer
wxAuiPaneInfo *This = (wxAuiPaneInfo *) getPtr(bp,memenv); bp += 4;
int * layer = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxAuiPaneInfo * Result = &This->Layer((int) *layer);
+ wxAuiPaneInfo * Result = &This->Layer(*layer);
rt.addRef(getRef((void *)Result,memenv), "wxAuiPaneInfo");
break;
}
@@ -24314,7 +24351,7 @@ case wxAuiPaneInfo_MaxSize_2: { // wxAuiPaneInfo::MaxSize
int * x = (int *) bp; bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxAuiPaneInfo * Result = &This->MaxSize((int) *x,(int) *y);
+ wxAuiPaneInfo * Result = &This->MaxSize(*x,*y);
rt.addRef(getRef((void *)Result,memenv), "wxAuiPaneInfo");
break;
}
@@ -24347,7 +24384,7 @@ case wxAuiPaneInfo_MinSize_2: { // wxAuiPaneInfo::MinSize
int * x = (int *) bp; bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxAuiPaneInfo * Result = &This->MinSize((int) *x,(int) *y);
+ wxAuiPaneInfo * Result = &This->MinSize(*x,*y);
rt.addRef(getRef((void *)Result,memenv), "wxAuiPaneInfo");
break;
}
@@ -24421,7 +24458,7 @@ case wxAuiPaneInfo_Position: { // wxAuiPaneInfo::Position
wxAuiPaneInfo *This = (wxAuiPaneInfo *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxAuiPaneInfo * Result = &This->Position((int) *pos);
+ wxAuiPaneInfo * Result = &This->Position(*pos);
rt.addRef(getRef((void *)Result,memenv), "wxAuiPaneInfo");
break;
}
@@ -24464,7 +24501,7 @@ case wxAuiPaneInfo_Row: { // wxAuiPaneInfo::Row
wxAuiPaneInfo *This = (wxAuiPaneInfo *) getPtr(bp,memenv); bp += 4;
int * row = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxAuiPaneInfo * Result = &This->Row((int) *row);
+ wxAuiPaneInfo * Result = &This->Row(*row);
rt.addRef(getRef((void *)Result,memenv), "wxAuiPaneInfo");
break;
}
@@ -24480,7 +24517,7 @@ case wxAuiPaneInfo_SetFlag: { // wxAuiPaneInfo::SetFlag
unsigned int * flag = (unsigned int *) bp; bp += 4;
bool * option_state = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxAuiPaneInfo * Result = &This->SetFlag((int) *flag,(bool) *option_state);
+ wxAuiPaneInfo * Result = &This->SetFlag(*flag,*option_state);
rt.addRef(getRef((void *)Result,memenv), "wxAuiPaneInfo");
break;
}
@@ -24631,7 +24668,7 @@ case wxAuiNotebook_DeletePage: { // wxAuiNotebook::DeletePage
wxAuiNotebook *This = (wxAuiNotebook *) getPtr(bp,memenv); bp += 4;
int * page = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->DeletePage((size_t) *page);
+ bool Result = This->DeletePage(*page);
rt.addBool(Result);
break;
}
@@ -24646,7 +24683,7 @@ case wxAuiNotebook_GetPage: { // wxAuiNotebook::GetPage
wxAuiNotebook *This = (wxAuiNotebook *) getPtr(bp,memenv); bp += 4;
int * page_idx = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxWindow * Result = (wxWindow*)This->GetPage((size_t) *page_idx);
+ wxWindow * Result = (wxWindow*)This->GetPage(*page_idx);
rt.addRef(getRef((void *)Result,memenv), "wxWindow");
break;
}
@@ -24654,7 +24691,7 @@ case wxAuiNotebook_GetPageBitmap: { // wxAuiNotebook::GetPageBitmap
wxAuiNotebook *This = (wxAuiNotebook *) getPtr(bp,memenv); bp += 4;
int * page_idx = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxBitmap * Result = new wxBitmap(This->GetPageBitmap((size_t) *page_idx)); newPtr((void *) Result,3, memenv);;
+ wxBitmap * Result = new wxBitmap(This->GetPageBitmap(*page_idx)); newPtr((void *) Result,3, memenv);;
rt.addRef(getRef((void *)Result,memenv), "wxBitmap");
break;
}
@@ -24677,7 +24714,7 @@ case wxAuiNotebook_GetPageText: { // wxAuiNotebook::GetPageText
wxAuiNotebook *This = (wxAuiNotebook *) getPtr(bp,memenv); bp += 4;
int * page_idx = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxString Result = This->GetPageText((size_t) *page_idx);
+ wxString Result = This->GetPageText(*page_idx);
rt.add(Result);
break;
}
@@ -24706,7 +24743,7 @@ bitmap = (wxBitmap *) getPtr(bp,memenv); bp += 4;
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->InsertPage((size_t) *page_idx,page,caption,select,*bitmap);
+ bool Result = This->InsertPage(*page_idx,page,caption,select,*bitmap);
rt.addBool(Result);
break;
}
@@ -24714,7 +24751,7 @@ case wxAuiNotebook_RemovePage: { // wxAuiNotebook::RemovePage
wxAuiNotebook *This = (wxAuiNotebook *) getPtr(bp,memenv); bp += 4;
int * page = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->RemovePage((size_t) *page);
+ bool Result = This->RemovePage(*page);
rt.addBool(Result);
break;
}
@@ -24738,7 +24775,7 @@ case wxAuiNotebook_SetPageBitmap: { // wxAuiNotebook::SetPageBitmap
int * page = (int *) bp; bp += 4;
wxBitmap *bitmap = (wxBitmap *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->SetPageBitmap((size_t) *page,*bitmap);
+ bool Result = This->SetPageBitmap(*page,*bitmap);
rt.addBool(Result);
break;
}
@@ -24749,7 +24786,7 @@ case wxAuiNotebook_SetPageText: { // wxAuiNotebook::SetPageText
wxString text = wxString(bp, wxConvUTF8);
bp += *textLen+((8-((4+ *textLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- bool Result = This->SetPageText((size_t) *page,text);
+ bool Result = This->SetPageText(*page,text);
rt.addBool(Result);
break;
}
@@ -24757,7 +24794,7 @@ case wxAuiNotebook_SetSelection: { // wxAuiNotebook::SetSelection
wxAuiNotebook *This = (wxAuiNotebook *) getPtr(bp,memenv); bp += 4;
int * new_page = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- size_t Result = This->SetSelection((size_t) *new_page);
+ size_t Result = This->SetSelection(*new_page);
rt.addInt(Result);
break;
}
@@ -24765,7 +24802,7 @@ case wxAuiNotebook_SetTabCtrlHeight: { // wxAuiNotebook::SetTabCtrlHeight
wxAuiNotebook *This = (wxAuiNotebook *) getPtr(bp,memenv); bp += 4;
int * height = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetTabCtrlHeight((int) *height);
+ This->SetTabCtrlHeight(*height);
break;
}
case wxAuiNotebook_SetUniformBitmapSize: { // wxAuiNotebook::SetUniformBitmapSize
@@ -24814,7 +24851,7 @@ case wxMDIParentFrame_new_4: { // wxMDIParentFrame::wxMDIParentFrame
style = (long)*(int *) bp; bp += 4;
} break;
}};
- wxMDIParentFrame * Result = new EwxMDIParentFrame(parent,(wxWindowID) *id,title,pos,size,style);
+ wxMDIParentFrame * Result = new EwxMDIParentFrame(parent,*id,title,pos,size,style);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxMDIParentFrame");
break;
@@ -24871,7 +24908,7 @@ case wxMDIParentFrame_Create: { // wxMDIParentFrame::Create
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,title,pos,size,style);
+ bool Result = This->Create(parent,*id,title,pos,size,style);
rt.addBool(Result);
break;
}
@@ -24899,7 +24936,7 @@ orient = *(wxOrientation *) bp; bp += 4;;
} break;
}};
if(!This) throw wxe_badarg(0);
- This->Tile((wxOrientation) orient);
+ This->Tile(orient);
break;
}
case wxMDIChildFrame_new_0: { // wxMDIChildFrame::wxMDIChildFrame
@@ -24934,7 +24971,7 @@ case wxMDIChildFrame_new_4: { // wxMDIChildFrame::wxMDIChildFrame
style = (long)*(int *) bp; bp += 4;
} break;
}};
- wxMDIChildFrame * Result = new EwxMDIChildFrame(parent,(wxWindowID) *id,title,pos,size,style);
+ wxMDIChildFrame * Result = new EwxMDIChildFrame(parent,*id,title,pos,size,style);
newPtr((void *) Result, 0, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxMDIChildFrame");
break;
@@ -24973,7 +25010,7 @@ case wxMDIChildFrame_Create: { // wxMDIChildFrame::Create
} break;
}};
if(!This) throw wxe_badarg(0);
- bool Result = This->Create(parent,(wxWindowID) *id,title,pos,size,style);
+ bool Result = This->Create(parent,*id,title,pos,size,style);
rt.addBool(Result);
break;
}
@@ -25002,6 +25039,7 @@ case wxMDIClientWindow_new_0: { // wxMDIClientWindow::wxMDIClientWindow
rt.addRef(getRef((void *)Result,memenv), "wxMDIClientWindow");
break;
}
+#if !wxCHECK_VERSION(2,9,0)
case wxMDIClientWindow_new_2: { // wxMDIClientWindow::wxMDIClientWindow
long style=0;
wxMDIParentFrame *parent = (wxMDIParentFrame *) getPtr(bp,memenv); bp += 4;
@@ -25016,6 +25054,7 @@ case wxMDIClientWindow_new_2: { // wxMDIClientWindow::wxMDIClientWindow
rt.addRef(getRef((void *)Result,memenv), "wxMDIClientWindow");
break;
}
+#endif
case wxMDIClientWindow_CreateClient: { // wxMDIClientWindow::CreateClient
long style=wxVSCROLL|wxHSCROLL;
wxMDIClientWindow *This = (wxMDIClientWindow *) getPtr(bp,memenv); bp += 4;
@@ -25115,7 +25154,7 @@ case wxEvent_ResumePropagation: { // wxEvent::ResumePropagation
wxEvent *This = (wxEvent *) getPtr(bp,memenv); bp += 4;
int * propagationLevel = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->ResumePropagation((int) *propagationLevel);
+ This->ResumePropagation(*propagationLevel);
break;
}
case wxEvent_ShouldPropagate: { // wxEvent::ShouldPropagate
@@ -25198,7 +25237,7 @@ case wxCommandEvent_SetInt: { // wxCommandEvent::SetInt
wxCommandEvent *This = (wxCommandEvent *) getPtr(bp,memenv); bp += 4;
int * i = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetInt((int) *i);
+ This->SetInt(*i);
break;
}
case wxCommandEvent_SetString: { // wxCommandEvent::SetString
@@ -25249,7 +25288,7 @@ case wxMouseEvent_Button: { // wxMouseEvent::Button
wxMouseEvent *This = (wxMouseEvent *) getPtr(bp,memenv); bp += 4;
int * but = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->Button((int) *but);
+ bool Result = This->Button(*but);
rt.addBool(Result);
break;
}
@@ -25713,14 +25752,14 @@ case wxCloseEvent_SetCanVeto: { // wxCloseEvent::SetCanVeto
wxCloseEvent *This = (wxCloseEvent *) getPtr(bp,memenv); bp += 4;
bool * canVeto = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetCanVeto((bool) *canVeto);
+ This->SetCanVeto(*canVeto);
break;
}
case wxCloseEvent_SetLoggingOff: { // wxCloseEvent::SetLoggingOff
wxCloseEvent *This = (wxCloseEvent *) getPtr(bp,memenv); bp += 4;
bool * logOff = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetLoggingOff((bool) *logOff);
+ This->SetLoggingOff(*logOff);
break;
}
case wxCloseEvent_Veto: { // wxCloseEvent::Veto
@@ -25740,7 +25779,7 @@ case wxShowEvent_SetShow: { // wxShowEvent::SetShow
wxShowEvent *This = (wxShowEvent *) getPtr(bp,memenv); bp += 4;
bool * show = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetShow((bool) *show);
+ This->SetShow(*show);
break;
}
case wxShowEvent_GetShow: { // wxShowEvent::GetShow
@@ -25865,21 +25904,21 @@ case wxUpdateUIEvent_Check: { // wxUpdateUIEvent::Check
wxUpdateUIEvent *This = (wxUpdateUIEvent *) getPtr(bp,memenv); bp += 4;
bool * check = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->Check((bool) *check);
+ This->Check(*check);
break;
}
case wxUpdateUIEvent_Enable: { // wxUpdateUIEvent::Enable
wxUpdateUIEvent *This = (wxUpdateUIEvent *) getPtr(bp,memenv); bp += 4;
bool * enable = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->Enable((bool) *enable);
+ This->Enable(*enable);
break;
}
case wxUpdateUIEvent_Show: { // wxUpdateUIEvent::Show
wxUpdateUIEvent *This = (wxUpdateUIEvent *) getPtr(bp,memenv); bp += 4;
bool * show = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->Show((bool) *show);
+ This->Show(*show);
break;
}
case wxUpdateUIEvent_GetChecked: { // wxUpdateUIEvent::GetChecked
@@ -25954,7 +25993,7 @@ case wxUpdateUIEvent_ResetUpdateTime: { // wxUpdateUIEvent::ResetUpdateTime
}
case wxUpdateUIEvent_SetMode: { // wxUpdateUIEvent::SetMode
wxUpdateUIMode mode = *(wxUpdateUIMode *) bp; bp += 4;;
- wxUpdateUIEvent::SetMode((wxUpdateUIMode) mode);
+ wxUpdateUIEvent::SetMode(mode);
break;
}
case wxUpdateUIEvent_SetText: { // wxUpdateUIEvent::SetText
@@ -25968,7 +26007,7 @@ case wxUpdateUIEvent_SetText: { // wxUpdateUIEvent::SetText
}
case wxUpdateUIEvent_SetUpdateInterval: { // wxUpdateUIEvent::SetUpdateInterval
int * updateInterval = (int *) bp; bp += 4;
- wxUpdateUIEvent::SetUpdateInterval((long) *updateInterval);
+ wxUpdateUIEvent::SetUpdateInterval(*updateInterval);
break;
}
case wxMouseCaptureChangedEvent_GetCapturedWindow: { // wxMouseCaptureChangedEvent::GetCapturedWindow
@@ -25996,7 +26035,7 @@ case wxQueryNewPaletteEvent_SetPaletteRealized: { // wxQueryNewPaletteEvent::Set
wxQueryNewPaletteEvent *This = (wxQueryNewPaletteEvent *) getPtr(bp,memenv); bp += 4;
bool * realized = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetPaletteRealized((bool) *realized);
+ This->SetPaletteRealized(*realized);
break;
}
case wxQueryNewPaletteEvent_GetPaletteRealized: { // wxQueryNewPaletteEvent::GetPaletteRealized
@@ -26017,7 +26056,7 @@ case wxNavigationKeyEvent_SetDirection: { // wxNavigationKeyEvent::SetDirection
wxNavigationKeyEvent *This = (wxNavigationKeyEvent *) getPtr(bp,memenv); bp += 4;
bool * bForward = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetDirection((bool) *bForward);
+ This->SetDirection(*bForward);
break;
}
case wxNavigationKeyEvent_IsWindowChange: { // wxNavigationKeyEvent::IsWindowChange
@@ -26031,7 +26070,7 @@ case wxNavigationKeyEvent_SetWindowChange: { // wxNavigationKeyEvent::SetWindowC
wxNavigationKeyEvent *This = (wxNavigationKeyEvent *) getPtr(bp,memenv); bp += 4;
bool * bIs = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetWindowChange((bool) *bIs);
+ This->SetWindowChange(*bIs);
break;
}
case wxNavigationKeyEvent_IsFromTab: { // wxNavigationKeyEvent::IsFromTab
@@ -26045,7 +26084,7 @@ case wxNavigationKeyEvent_SetFromTab: { // wxNavigationKeyEvent::SetFromTab
wxNavigationKeyEvent *This = (wxNavigationKeyEvent *) getPtr(bp,memenv); bp += 4;
bool * bIs = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetFromTab((bool) *bIs);
+ This->SetFromTab(*bIs);
break;
}
case wxNavigationKeyEvent_GetCurrentFocus: { // wxNavigationKeyEvent::GetCurrentFocus
@@ -26080,7 +26119,7 @@ case wxHelpEvent_SetOrigin: { // wxHelpEvent::SetOrigin
wxHelpEvent *This = (wxHelpEvent *) getPtr(bp,memenv); bp += 4;
wxHelpEvent::Origin origin = *(wxHelpEvent::Origin *) bp; bp += 4;;
if(!This) throw wxe_badarg(0);
- This->SetOrigin((wxHelpEvent::Origin) origin);
+ This->SetOrigin(origin);
break;
}
case wxHelpEvent_SetPosition: { // wxHelpEvent::SetPosition
@@ -26108,12 +26147,14 @@ case wxContextMenuEvent_SetPosition: { // wxContextMenuEvent::SetPosition
This->SetPosition(pos);
break;
}
+#if !wxCHECK_VERSION(2,9,0)
case wxIdleEvent_CanSend: { // wxIdleEvent::CanSend
wxWindow *win = (wxWindow *) getPtr(bp,memenv); bp += 4;
bool Result = wxIdleEvent::CanSend(win);
rt.addBool(Result);
break;
}
+#endif
case wxIdleEvent_GetMode: { // wxIdleEvent::GetMode
int Result = wxIdleEvent::GetMode();
rt.addInt(Result);
@@ -26141,7 +26182,7 @@ case wxIdleEvent_MoreRequested: { // wxIdleEvent::MoreRequested
}
case wxIdleEvent_SetMode: { // wxIdleEvent::SetMode
wxIdleMode mode = *(wxIdleMode *) bp; bp += 4;;
- wxIdleEvent::SetMode((wxIdleMode) mode);
+ wxIdleEvent::SetMode(mode);
break;
}
case wxGridEvent_AltDown: { // wxGridEvent::AltDown
@@ -26529,7 +26570,7 @@ case wxStyledTextEvent_GetAlt: { // wxStyledTextEvent::GetAlt
}
case utils_wxGetKeyState: { // utils::wxGetKeyState
wxKeyCode key = *(wxKeyCode *) bp; bp += 4;;
- bool Result = ::wxGetKeyState((wxKeyCode) key);
+ bool Result = ::wxGetKeyState(key);
rt.addBool(Result);
break;
}
@@ -26549,7 +26590,7 @@ case utils_wxGetMouseState: { // utils::wxGetMouseState
}
case utils_wxSetDetectableAutoRepeat: { // utils::wxSetDetectableAutoRepeat
bool * flag = (bool *) bp; bp += 4;
- bool Result = ::wxSetDetectableAutoRepeat((bool) *flag);
+ bool Result = ::wxSetDetectableAutoRepeat(*flag);
rt.addBool(Result);
break;
}
@@ -26606,7 +26647,7 @@ case utils_wxIsBusy: { // utils::wxIsBusy
}
case utils_wxShutdown: { // utils::wxShutdown
wxShutdownFlags wFlags = *(wxShutdownFlags *) bp; bp += 4;;
- bool Result = ::wxShutdown((wxShutdownFlags) wFlags);
+ bool Result = ::wxShutdown(wFlags);
rt.addBool(Result);
break;
}
@@ -26659,7 +26700,7 @@ case utils_wxNewId: { // utils::wxNewId
}
case utils_wxRegisterId: { // utils::wxRegisterId
int * id = (int *) bp; bp += 4;
- ::wxRegisterId((long) *id);
+ ::wxRegisterId(*id);
break;
}
case utils_wxGetCurrentId: { // utils::wxGetCurrentId
@@ -26862,7 +26903,7 @@ case wxPrintout_SetLogicalOrigin: { // wxPrintout::SetLogicalOrigin
int * x = (int *) bp; bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetLogicalOrigin((wxCoord) *x,(wxCoord) *y);
+ This->SetLogicalOrigin(*x,*y);
break;
}
case wxPrintout_OffsetLogicalOrigin: { // wxPrintout::OffsetLogicalOrigin
@@ -26870,7 +26911,7 @@ case wxPrintout_OffsetLogicalOrigin: { // wxPrintout::OffsetLogicalOrigin
int * xoff = (int *) bp; bp += 4;
int * yoff = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->OffsetLogicalOrigin((wxCoord) *xoff,(wxCoord) *yoff);
+ This->OffsetLogicalOrigin(*xoff,*yoff);
break;
}
case wxStyledTextCtrl_new_2: { // wxStyledTextCtrl::wxStyledTextCtrl
@@ -26966,7 +27007,7 @@ case wxStyledTextCtrl_InsertText: { // wxStyledTextCtrl::InsertText
wxString text = wxString(bp, wxConvUTF8);
bp += *textLen+((8-((4+ *textLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- This->InsertText((int) *pos,text);
+ This->InsertText(*pos,text);
break;
}
case wxStyledTextCtrl_ClearAll: { // wxStyledTextCtrl::ClearAll
@@ -26992,7 +27033,7 @@ case wxStyledTextCtrl_GetCharAt: { // wxStyledTextCtrl::GetCharAt
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->GetCharAt((int) *pos);
+ int Result = This->GetCharAt(*pos);
rt.addInt(Result);
break;
}
@@ -27014,7 +27055,7 @@ case wxStyledTextCtrl_GetStyleAt: { // wxStyledTextCtrl::GetStyleAt
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->GetStyleAt((int) *pos);
+ int Result = This->GetStyleAt(*pos);
rt.addInt(Result);
break;
}
@@ -27028,7 +27069,7 @@ case wxStyledTextCtrl_SetUndoCollection: { // wxStyledTextCtrl::SetUndoCollectio
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
bool * collectUndo = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetUndoCollection((bool) *collectUndo);
+ This->SetUndoCollection(*collectUndo);
break;
}
case wxStyledTextCtrl_SelectAll: { // wxStyledTextCtrl::SelectAll
@@ -27048,7 +27089,7 @@ case wxStyledTextCtrl_GetStyledText: { // wxStyledTextCtrl::GetStyledText
int * startPos = (int *) bp; bp += 4;
int * endPos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxMemoryBuffer * Result = new wxMemoryBuffer(This->GetStyledText((int) *startPos,(int) *endPos)); newPtr((void *) Result,3, memenv);;
+ wxMemoryBuffer * Result = new wxMemoryBuffer(This->GetStyledText(*startPos,*endPos)); newPtr((void *) Result,3, memenv);;
rt.addRef(getRef((void *)Result,memenv), "wxMemoryBuffer");
break;
}
@@ -27063,7 +27104,7 @@ case wxStyledTextCtrl_MarkerLineFromHandle: { // wxStyledTextCtrl::MarkerLineFro
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * handle = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->MarkerLineFromHandle((int) *handle);
+ int Result = This->MarkerLineFromHandle(*handle);
rt.addInt(Result);
break;
}
@@ -27071,7 +27112,7 @@ case wxStyledTextCtrl_MarkerDeleteHandle: { // wxStyledTextCtrl::MarkerDeleteHan
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * handle = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->MarkerDeleteHandle((int) *handle);
+ This->MarkerDeleteHandle(*handle);
break;
}
case wxStyledTextCtrl_GetUndoCollection: { // wxStyledTextCtrl::GetUndoCollection
@@ -27092,7 +27133,7 @@ case wxStyledTextCtrl_SetViewWhiteSpace: { // wxStyledTextCtrl::SetViewWhiteSpac
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * viewWS = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetViewWhiteSpace((int) *viewWS);
+ This->SetViewWhiteSpace(*viewWS);
break;
}
case wxStyledTextCtrl_PositionFromPoint: { // wxStyledTextCtrl::PositionFromPoint
@@ -27110,7 +27151,7 @@ case wxStyledTextCtrl_PositionFromPointClose: { // wxStyledTextCtrl::PositionFro
int * x = (int *) bp; bp += 4;
int * y = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->PositionFromPointClose((int) *x,(int) *y);
+ int Result = This->PositionFromPointClose(*x,*y);
rt.addInt(Result);
break;
}
@@ -27118,21 +27159,21 @@ case wxStyledTextCtrl_GotoLine: { // wxStyledTextCtrl::GotoLine
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * line = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->GotoLine((int) *line);
+ This->GotoLine(*line);
break;
}
case wxStyledTextCtrl_GotoPos: { // wxStyledTextCtrl::GotoPos
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->GotoPos((int) *pos);
+ This->GotoPos(*pos);
break;
}
case wxStyledTextCtrl_SetAnchor: { // wxStyledTextCtrl::SetAnchor
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * posAnchor = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetAnchor((int) *posAnchor);
+ This->SetAnchor(*posAnchor);
break;
}
case wxStyledTextCtrl_GetCurLine: { // wxStyledTextCtrl::GetCurLine
@@ -27156,7 +27197,7 @@ case wxStyledTextCtrl_ConvertEOLs: { // wxStyledTextCtrl::ConvertEOLs
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * eolMode = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->ConvertEOLs((int) *eolMode);
+ This->ConvertEOLs(*eolMode);
break;
}
case wxStyledTextCtrl_GetEOLMode: { // wxStyledTextCtrl::GetEOLMode
@@ -27170,7 +27211,7 @@ case wxStyledTextCtrl_SetEOLMode: { // wxStyledTextCtrl::SetEOLMode
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * eolMode = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetEOLMode((int) *eolMode);
+ This->SetEOLMode(*eolMode);
break;
}
case wxStyledTextCtrl_StartStyling: { // wxStyledTextCtrl::StartStyling
@@ -27178,7 +27219,7 @@ case wxStyledTextCtrl_StartStyling: { // wxStyledTextCtrl::StartStyling
int * pos = (int *) bp; bp += 4;
int * mask = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->StartStyling((int) *pos,(int) *mask);
+ This->StartStyling(*pos,*mask);
break;
}
case wxStyledTextCtrl_SetStyling: { // wxStyledTextCtrl::SetStyling
@@ -27186,7 +27227,7 @@ case wxStyledTextCtrl_SetStyling: { // wxStyledTextCtrl::SetStyling
int * length = (int *) bp; bp += 4;
int * style = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetStyling((int) *length,(int) *style);
+ This->SetStyling(*length,*style);
break;
}
case wxStyledTextCtrl_GetBufferedDraw: { // wxStyledTextCtrl::GetBufferedDraw
@@ -27200,14 +27241,14 @@ case wxStyledTextCtrl_SetBufferedDraw: { // wxStyledTextCtrl::SetBufferedDraw
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
bool * buffered = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetBufferedDraw((bool) *buffered);
+ This->SetBufferedDraw(*buffered);
break;
}
case wxStyledTextCtrl_SetTabWidth: { // wxStyledTextCtrl::SetTabWidth
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * tabWidth = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetTabWidth((int) *tabWidth);
+ This->SetTabWidth(*tabWidth);
break;
}
case wxStyledTextCtrl_GetTabWidth: { // wxStyledTextCtrl::GetTabWidth
@@ -27221,7 +27262,7 @@ case wxStyledTextCtrl_SetCodePage: { // wxStyledTextCtrl::SetCodePage
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * codePage = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetCodePage((int) *codePage);
+ This->SetCodePage(*codePage);
break;
}
case wxStyledTextCtrl_MarkerDefine: { // wxStyledTextCtrl::MarkerDefine
@@ -27250,7 +27291,7 @@ case wxStyledTextCtrl_MarkerDefine: { // wxStyledTextCtrl::MarkerDefine
} break;
}};
if(!This) throw wxe_badarg(0);
- This->MarkerDefine((int) *markerNumber,(int) *markerSymbol,foreground,background);
+ This->MarkerDefine(*markerNumber,*markerSymbol,foreground,background);
break;
}
case wxStyledTextCtrl_MarkerSetForeground: { // wxStyledTextCtrl::MarkerSetForeground
@@ -27262,7 +27303,7 @@ case wxStyledTextCtrl_MarkerSetForeground: { // wxStyledTextCtrl::MarkerSetForeg
int * foreA = (int *) bp; bp += 4;
wxColour fore = wxColour(*foreR,*foreG,*foreB,*foreA);
if(!This) throw wxe_badarg(0);
- This->MarkerSetForeground((int) *markerNumber,fore);
+ This->MarkerSetForeground(*markerNumber,fore);
break;
}
case wxStyledTextCtrl_MarkerSetBackground: { // wxStyledTextCtrl::MarkerSetBackground
@@ -27274,7 +27315,7 @@ case wxStyledTextCtrl_MarkerSetBackground: { // wxStyledTextCtrl::MarkerSetBackg
int * backA = (int *) bp; bp += 4;
wxColour back = wxColour(*backR,*backG,*backB,*backA);
if(!This) throw wxe_badarg(0);
- This->MarkerSetBackground((int) *markerNumber,back);
+ This->MarkerSetBackground(*markerNumber,back);
break;
}
case wxStyledTextCtrl_MarkerAdd: { // wxStyledTextCtrl::MarkerAdd
@@ -27282,7 +27323,7 @@ case wxStyledTextCtrl_MarkerAdd: { // wxStyledTextCtrl::MarkerAdd
int * line = (int *) bp; bp += 4;
int * markerNumber = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->MarkerAdd((int) *line,(int) *markerNumber);
+ int Result = This->MarkerAdd(*line,*markerNumber);
rt.addInt(Result);
break;
}
@@ -27291,21 +27332,21 @@ case wxStyledTextCtrl_MarkerDelete: { // wxStyledTextCtrl::MarkerDelete
int * line = (int *) bp; bp += 4;
int * markerNumber = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->MarkerDelete((int) *line,(int) *markerNumber);
+ This->MarkerDelete(*line,*markerNumber);
break;
}
case wxStyledTextCtrl_MarkerDeleteAll: { // wxStyledTextCtrl::MarkerDeleteAll
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * markerNumber = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->MarkerDeleteAll((int) *markerNumber);
+ This->MarkerDeleteAll(*markerNumber);
break;
}
case wxStyledTextCtrl_MarkerGet: { // wxStyledTextCtrl::MarkerGet
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * line = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->MarkerGet((int) *line);
+ int Result = This->MarkerGet(*line);
rt.addInt(Result);
break;
}
@@ -27314,7 +27355,7 @@ case wxStyledTextCtrl_MarkerNext: { // wxStyledTextCtrl::MarkerNext
int * lineStart = (int *) bp; bp += 4;
int * markerMask = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->MarkerNext((int) *lineStart,(int) *markerMask);
+ int Result = This->MarkerNext(*lineStart,*markerMask);
rt.addInt(Result);
break;
}
@@ -27323,7 +27364,7 @@ case wxStyledTextCtrl_MarkerPrevious: { // wxStyledTextCtrl::MarkerPrevious
int * lineStart = (int *) bp; bp += 4;
int * markerMask = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->MarkerPrevious((int) *lineStart,(int) *markerMask);
+ int Result = This->MarkerPrevious(*lineStart,*markerMask);
rt.addInt(Result);
break;
}
@@ -27332,7 +27373,7 @@ case wxStyledTextCtrl_MarkerDefineBitmap: { // wxStyledTextCtrl::MarkerDefineBit
int * markerNumber = (int *) bp; bp += 4;
wxBitmap *bmp = (wxBitmap *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- This->MarkerDefineBitmap((int) *markerNumber,*bmp);
+ This->MarkerDefineBitmap(*markerNumber,*bmp);
break;
}
case wxStyledTextCtrl_MarkerAddSet: { // wxStyledTextCtrl::MarkerAddSet
@@ -27340,7 +27381,7 @@ case wxStyledTextCtrl_MarkerAddSet: { // wxStyledTextCtrl::MarkerAddSet
int * line = (int *) bp; bp += 4;
int * set = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->MarkerAddSet((int) *line,(int) *set);
+ This->MarkerAddSet(*line,*set);
break;
}
case wxStyledTextCtrl_MarkerSetAlpha: { // wxStyledTextCtrl::MarkerSetAlpha
@@ -27348,7 +27389,7 @@ case wxStyledTextCtrl_MarkerSetAlpha: { // wxStyledTextCtrl::MarkerSetAlpha
int * markerNumber = (int *) bp; bp += 4;
int * alpha = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->MarkerSetAlpha((int) *markerNumber,(int) *alpha);
+ This->MarkerSetAlpha(*markerNumber,*alpha);
break;
}
case wxStyledTextCtrl_SetMarginType: { // wxStyledTextCtrl::SetMarginType
@@ -27356,14 +27397,14 @@ case wxStyledTextCtrl_SetMarginType: { // wxStyledTextCtrl::SetMarginType
int * margin = (int *) bp; bp += 4;
int * marginType = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetMarginType((int) *margin,(int) *marginType);
+ This->SetMarginType(*margin,*marginType);
break;
}
case wxStyledTextCtrl_GetMarginType: { // wxStyledTextCtrl::GetMarginType
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * margin = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->GetMarginType((int) *margin);
+ int Result = This->GetMarginType(*margin);
rt.addInt(Result);
break;
}
@@ -27372,14 +27413,14 @@ case wxStyledTextCtrl_SetMarginWidth: { // wxStyledTextCtrl::SetMarginWidth
int * margin = (int *) bp; bp += 4;
int * pixelWidth = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetMarginWidth((int) *margin,(int) *pixelWidth);
+ This->SetMarginWidth(*margin,*pixelWidth);
break;
}
case wxStyledTextCtrl_GetMarginWidth: { // wxStyledTextCtrl::GetMarginWidth
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * margin = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->GetMarginWidth((int) *margin);
+ int Result = This->GetMarginWidth(*margin);
rt.addInt(Result);
break;
}
@@ -27388,14 +27429,14 @@ case wxStyledTextCtrl_SetMarginMask: { // wxStyledTextCtrl::SetMarginMask
int * margin = (int *) bp; bp += 4;
int * mask = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetMarginMask((int) *margin,(int) *mask);
+ This->SetMarginMask(*margin,*mask);
break;
}
case wxStyledTextCtrl_GetMarginMask: { // wxStyledTextCtrl::GetMarginMask
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * margin = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->GetMarginMask((int) *margin);
+ int Result = This->GetMarginMask(*margin);
rt.addInt(Result);
break;
}
@@ -27404,14 +27445,14 @@ case wxStyledTextCtrl_SetMarginSensitive: { // wxStyledTextCtrl::SetMarginSensit
int * margin = (int *) bp; bp += 4;
bool * sensitive = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetMarginSensitive((int) *margin,(bool) *sensitive);
+ This->SetMarginSensitive(*margin,*sensitive);
break;
}
case wxStyledTextCtrl_GetMarginSensitive: { // wxStyledTextCtrl::GetMarginSensitive
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * margin = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->GetMarginSensitive((int) *margin);
+ bool Result = This->GetMarginSensitive(*margin);
rt.addBool(Result);
break;
}
@@ -27430,7 +27471,7 @@ case wxStyledTextCtrl_StyleSetForeground: { // wxStyledTextCtrl::StyleSetForegro
int * foreA = (int *) bp; bp += 4;
wxColour fore = wxColour(*foreR,*foreG,*foreB,*foreA);
if(!This) throw wxe_badarg(0);
- This->StyleSetForeground((int) *style,fore);
+ This->StyleSetForeground(*style,fore);
break;
}
case wxStyledTextCtrl_StyleSetBackground: { // wxStyledTextCtrl::StyleSetBackground
@@ -27442,7 +27483,7 @@ case wxStyledTextCtrl_StyleSetBackground: { // wxStyledTextCtrl::StyleSetBackgro
int * backA = (int *) bp; bp += 4;
wxColour back = wxColour(*backR,*backG,*backB,*backA);
if(!This) throw wxe_badarg(0);
- This->StyleSetBackground((int) *style,back);
+ This->StyleSetBackground(*style,back);
break;
}
case wxStyledTextCtrl_StyleSetBold: { // wxStyledTextCtrl::StyleSetBold
@@ -27450,7 +27491,7 @@ case wxStyledTextCtrl_StyleSetBold: { // wxStyledTextCtrl::StyleSetBold
int * style = (int *) bp; bp += 4;
bool * bold = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->StyleSetBold((int) *style,(bool) *bold);
+ This->StyleSetBold(*style,*bold);
break;
}
case wxStyledTextCtrl_StyleSetItalic: { // wxStyledTextCtrl::StyleSetItalic
@@ -27458,7 +27499,7 @@ case wxStyledTextCtrl_StyleSetItalic: { // wxStyledTextCtrl::StyleSetItalic
int * style = (int *) bp; bp += 4;
bool * italic = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->StyleSetItalic((int) *style,(bool) *italic);
+ This->StyleSetItalic(*style,*italic);
break;
}
case wxStyledTextCtrl_StyleSetSize: { // wxStyledTextCtrl::StyleSetSize
@@ -27466,7 +27507,7 @@ case wxStyledTextCtrl_StyleSetSize: { // wxStyledTextCtrl::StyleSetSize
int * style = (int *) bp; bp += 4;
int * sizePoints = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->StyleSetSize((int) *style,(int) *sizePoints);
+ This->StyleSetSize(*style,*sizePoints);
break;
}
case wxStyledTextCtrl_StyleSetFaceName: { // wxStyledTextCtrl::StyleSetFaceName
@@ -27476,7 +27517,7 @@ case wxStyledTextCtrl_StyleSetFaceName: { // wxStyledTextCtrl::StyleSetFaceName
wxString fontName = wxString(bp, wxConvUTF8);
bp += *fontNameLen+((8-((4+ *fontNameLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- This->StyleSetFaceName((int) *style,fontName);
+ This->StyleSetFaceName(*style,fontName);
break;
}
case wxStyledTextCtrl_StyleSetEOLFilled: { // wxStyledTextCtrl::StyleSetEOLFilled
@@ -27484,7 +27525,7 @@ case wxStyledTextCtrl_StyleSetEOLFilled: { // wxStyledTextCtrl::StyleSetEOLFille
int * style = (int *) bp; bp += 4;
bool * filled = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->StyleSetEOLFilled((int) *style,(bool) *filled);
+ This->StyleSetEOLFilled(*style,*filled);
break;
}
case wxStyledTextCtrl_StyleResetDefault: { // wxStyledTextCtrl::StyleResetDefault
@@ -27498,7 +27539,7 @@ case wxStyledTextCtrl_StyleSetUnderline: { // wxStyledTextCtrl::StyleSetUnderlin
int * style = (int *) bp; bp += 4;
bool * underline = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->StyleSetUnderline((int) *style,(bool) *underline);
+ This->StyleSetUnderline(*style,*underline);
break;
}
case wxStyledTextCtrl_StyleSetCase: { // wxStyledTextCtrl::StyleSetCase
@@ -27506,7 +27547,7 @@ case wxStyledTextCtrl_StyleSetCase: { // wxStyledTextCtrl::StyleSetCase
int * style = (int *) bp; bp += 4;
int * caseForce = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->StyleSetCase((int) *style,(int) *caseForce);
+ This->StyleSetCase(*style,*caseForce);
break;
}
case wxStyledTextCtrl_StyleSetHotSpot: { // wxStyledTextCtrl::StyleSetHotSpot
@@ -27514,7 +27555,7 @@ case wxStyledTextCtrl_StyleSetHotSpot: { // wxStyledTextCtrl::StyleSetHotSpot
int * style = (int *) bp; bp += 4;
bool * hotspot = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->StyleSetHotSpot((int) *style,(bool) *hotspot);
+ This->StyleSetHotSpot(*style,*hotspot);
break;
}
case wxStyledTextCtrl_SetSelForeground: { // wxStyledTextCtrl::SetSelForeground
@@ -27526,7 +27567,7 @@ case wxStyledTextCtrl_SetSelForeground: { // wxStyledTextCtrl::SetSelForeground
int * foreA = (int *) bp; bp += 4;
wxColour fore = wxColour(*foreR,*foreG,*foreB,*foreA);
if(!This) throw wxe_badarg(0);
- This->SetSelForeground((bool) *useSetting,fore);
+ This->SetSelForeground(*useSetting,fore);
break;
}
case wxStyledTextCtrl_SetSelBackground: { // wxStyledTextCtrl::SetSelBackground
@@ -27538,7 +27579,7 @@ case wxStyledTextCtrl_SetSelBackground: { // wxStyledTextCtrl::SetSelBackground
int * backA = (int *) bp; bp += 4;
wxColour back = wxColour(*backR,*backG,*backB,*backA);
if(!This) throw wxe_badarg(0);
- This->SetSelBackground((bool) *useSetting,back);
+ This->SetSelBackground(*useSetting,back);
break;
}
case wxStyledTextCtrl_GetSelAlpha: { // wxStyledTextCtrl::GetSelAlpha
@@ -27552,7 +27593,7 @@ case wxStyledTextCtrl_SetSelAlpha: { // wxStyledTextCtrl::SetSelAlpha
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * alpha = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetSelAlpha((int) *alpha);
+ This->SetSelAlpha(*alpha);
break;
}
case wxStyledTextCtrl_SetCaretForeground: { // wxStyledTextCtrl::SetCaretForeground
@@ -27572,7 +27613,7 @@ case wxStyledTextCtrl_CmdKeyAssign: { // wxStyledTextCtrl::CmdKeyAssign
int * modifiers = (int *) bp; bp += 4;
int * cmd = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->CmdKeyAssign((int) *key,(int) *modifiers,(int) *cmd);
+ This->CmdKeyAssign(*key,*modifiers,*cmd);
break;
}
case wxStyledTextCtrl_CmdKeyClear: { // wxStyledTextCtrl::CmdKeyClear
@@ -27580,7 +27621,7 @@ case wxStyledTextCtrl_CmdKeyClear: { // wxStyledTextCtrl::CmdKeyClear
int * key = (int *) bp; bp += 4;
int * modifiers = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->CmdKeyClear((int) *key,(int) *modifiers);
+ This->CmdKeyClear(*key,*modifiers);
break;
}
case wxStyledTextCtrl_CmdKeyClearAll: { // wxStyledTextCtrl::CmdKeyClearAll
@@ -27594,7 +27635,7 @@ case wxStyledTextCtrl_SetStyleBytes: { // wxStyledTextCtrl::SetStyleBytes
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * length = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetStyleBytes((int) *length,&styleBytes);
+ This->SetStyleBytes(*length,&styleBytes);
rt.addInt(styleBytes);
break;
}
@@ -27603,7 +27644,7 @@ case wxStyledTextCtrl_StyleSetVisible: { // wxStyledTextCtrl::StyleSetVisible
int * style = (int *) bp; bp += 4;
bool * visible = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->StyleSetVisible((int) *style,(bool) *visible);
+ This->StyleSetVisible(*style,*visible);
break;
}
case wxStyledTextCtrl_GetCaretPeriod: { // wxStyledTextCtrl::GetCaretPeriod
@@ -27617,7 +27658,7 @@ case wxStyledTextCtrl_SetCaretPeriod: { // wxStyledTextCtrl::SetCaretPeriod
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * periodMilliseconds = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetCaretPeriod((int) *periodMilliseconds);
+ This->SetCaretPeriod(*periodMilliseconds);
break;
}
case wxStyledTextCtrl_SetWordChars: { // wxStyledTextCtrl::SetWordChars
@@ -27646,14 +27687,14 @@ case wxStyledTextCtrl_IndicatorSetStyle: { // wxStyledTextCtrl::IndicatorSetStyl
int * indic = (int *) bp; bp += 4;
int * style = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->IndicatorSetStyle((int) *indic,(int) *style);
+ This->IndicatorSetStyle(*indic,*style);
break;
}
case wxStyledTextCtrl_IndicatorGetStyle: { // wxStyledTextCtrl::IndicatorGetStyle
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * indic = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->IndicatorGetStyle((int) *indic);
+ int Result = This->IndicatorGetStyle(*indic);
rt.addInt(Result);
break;
}
@@ -27666,14 +27707,14 @@ case wxStyledTextCtrl_IndicatorSetForeground: { // wxStyledTextCtrl::IndicatorSe
int * foreA = (int *) bp; bp += 4;
wxColour fore = wxColour(*foreR,*foreG,*foreB,*foreA);
if(!This) throw wxe_badarg(0);
- This->IndicatorSetForeground((int) *indic,fore);
+ This->IndicatorSetForeground(*indic,fore);
break;
}
case wxStyledTextCtrl_IndicatorGetForeground: { // wxStyledTextCtrl::IndicatorGetForeground
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * indic = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxColour Result = This->IndicatorGetForeground((int) *indic);
+ wxColour Result = This->IndicatorGetForeground(*indic);
rt.add(Result);
break;
}
@@ -27686,7 +27727,7 @@ case wxStyledTextCtrl_SetWhitespaceForeground: { // wxStyledTextCtrl::SetWhitesp
int * foreA = (int *) bp; bp += 4;
wxColour fore = wxColour(*foreR,*foreG,*foreB,*foreA);
if(!This) throw wxe_badarg(0);
- This->SetWhitespaceForeground((bool) *useSetting,fore);
+ This->SetWhitespaceForeground(*useSetting,fore);
break;
}
case wxStyledTextCtrl_SetWhitespaceBackground: { // wxStyledTextCtrl::SetWhitespaceBackground
@@ -27698,7 +27739,7 @@ case wxStyledTextCtrl_SetWhitespaceBackground: { // wxStyledTextCtrl::SetWhitesp
int * backA = (int *) bp; bp += 4;
wxColour back = wxColour(*backR,*backG,*backB,*backA);
if(!This) throw wxe_badarg(0);
- This->SetWhitespaceBackground((bool) *useSetting,back);
+ This->SetWhitespaceBackground(*useSetting,back);
break;
}
case wxStyledTextCtrl_GetStyleBits: { // wxStyledTextCtrl::GetStyleBits
@@ -27713,14 +27754,14 @@ case wxStyledTextCtrl_SetLineState: { // wxStyledTextCtrl::SetLineState
int * line = (int *) bp; bp += 4;
int * state = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetLineState((int) *line,(int) *state);
+ This->SetLineState(*line,*state);
break;
}
case wxStyledTextCtrl_GetLineState: { // wxStyledTextCtrl::GetLineState
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * line = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->GetLineState((int) *line);
+ int Result = This->GetLineState(*line);
rt.addInt(Result);
break;
}
@@ -27742,7 +27783,7 @@ case wxStyledTextCtrl_SetCaretLineVisible: { // wxStyledTextCtrl::SetCaretLineVi
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
bool * show = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetCaretLineVisible((bool) *show);
+ This->SetCaretLineVisible(*show);
break;
}
case wxStyledTextCtrl_GetCaretLineBackground: { // wxStyledTextCtrl::GetCaretLineBackground
@@ -27770,7 +27811,7 @@ case wxStyledTextCtrl_AutoCompShow: { // wxStyledTextCtrl::AutoCompShow
wxString itemList = wxString(bp, wxConvUTF8);
bp += *itemListLen+((8-((4+ *itemListLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- This->AutoCompShow((int) *lenEntered,itemList);
+ This->AutoCompShow(*lenEntered,itemList);
break;
}
case wxStyledTextCtrl_AutoCompCancel: { // wxStyledTextCtrl::AutoCompCancel
@@ -27812,7 +27853,7 @@ case wxStyledTextCtrl_AutoCompSetSeparator: { // wxStyledTextCtrl::AutoCompSetSe
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * separatorCharacter = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->AutoCompSetSeparator((int) *separatorCharacter);
+ This->AutoCompSetSeparator(*separatorCharacter);
break;
}
case wxStyledTextCtrl_AutoCompGetSeparator: { // wxStyledTextCtrl::AutoCompGetSeparator
@@ -27835,7 +27876,7 @@ case wxStyledTextCtrl_AutoCompSetCancelAtStart: { // wxStyledTextCtrl::AutoCompS
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
bool * cancel = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->AutoCompSetCancelAtStart((bool) *cancel);
+ This->AutoCompSetCancelAtStart(*cancel);
break;
}
case wxStyledTextCtrl_AutoCompGetCancelAtStart: { // wxStyledTextCtrl::AutoCompGetCancelAtStart
@@ -27858,7 +27899,7 @@ case wxStyledTextCtrl_AutoCompSetChooseSingle: { // wxStyledTextCtrl::AutoCompSe
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
bool * chooseSingle = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->AutoCompSetChooseSingle((bool) *chooseSingle);
+ This->AutoCompSetChooseSingle(*chooseSingle);
break;
}
case wxStyledTextCtrl_AutoCompGetChooseSingle: { // wxStyledTextCtrl::AutoCompGetChooseSingle
@@ -27872,7 +27913,7 @@ case wxStyledTextCtrl_AutoCompSetIgnoreCase: { // wxStyledTextCtrl::AutoCompSetI
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
bool * ignoreCase = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->AutoCompSetIgnoreCase((bool) *ignoreCase);
+ This->AutoCompSetIgnoreCase(*ignoreCase);
break;
}
case wxStyledTextCtrl_AutoCompGetIgnoreCase: { // wxStyledTextCtrl::AutoCompGetIgnoreCase
@@ -27889,14 +27930,14 @@ case wxStyledTextCtrl_UserListShow: { // wxStyledTextCtrl::UserListShow
wxString itemList = wxString(bp, wxConvUTF8);
bp += *itemListLen+((8-((4+ *itemListLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- This->UserListShow((int) *listType,itemList);
+ This->UserListShow(*listType,itemList);
break;
}
case wxStyledTextCtrl_AutoCompSetAutoHide: { // wxStyledTextCtrl::AutoCompSetAutoHide
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
bool * autoHide = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->AutoCompSetAutoHide((bool) *autoHide);
+ This->AutoCompSetAutoHide(*autoHide);
break;
}
case wxStyledTextCtrl_AutoCompGetAutoHide: { // wxStyledTextCtrl::AutoCompGetAutoHide
@@ -27910,7 +27951,7 @@ case wxStyledTextCtrl_AutoCompSetDropRestOfWord: { // wxStyledTextCtrl::AutoComp
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
bool * dropRestOfWord = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->AutoCompSetDropRestOfWord((bool) *dropRestOfWord);
+ This->AutoCompSetDropRestOfWord(*dropRestOfWord);
break;
}
case wxStyledTextCtrl_AutoCompGetDropRestOfWord: { // wxStyledTextCtrl::AutoCompGetDropRestOfWord
@@ -27925,7 +27966,7 @@ case wxStyledTextCtrl_RegisterImage: { // wxStyledTextCtrl::RegisterImage
int * type = (int *) bp; bp += 4;
wxBitmap *bmp = (wxBitmap *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- This->RegisterImage((int) *type,*bmp);
+ This->RegisterImage(*type,*bmp);
break;
}
case wxStyledTextCtrl_ClearRegisteredImages: { // wxStyledTextCtrl::ClearRegisteredImages
@@ -27945,14 +27986,14 @@ case wxStyledTextCtrl_AutoCompSetTypeSeparator: { // wxStyledTextCtrl::AutoCompS
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * separatorCharacter = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->AutoCompSetTypeSeparator((int) *separatorCharacter);
+ This->AutoCompSetTypeSeparator(*separatorCharacter);
break;
}
case wxStyledTextCtrl_AutoCompSetMaxWidth: { // wxStyledTextCtrl::AutoCompSetMaxWidth
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * characterCount = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->AutoCompSetMaxWidth((int) *characterCount);
+ This->AutoCompSetMaxWidth(*characterCount);
break;
}
case wxStyledTextCtrl_AutoCompGetMaxWidth: { // wxStyledTextCtrl::AutoCompGetMaxWidth
@@ -27966,7 +28007,7 @@ case wxStyledTextCtrl_AutoCompSetMaxHeight: { // wxStyledTextCtrl::AutoCompSetMa
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * rowCount = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->AutoCompSetMaxHeight((int) *rowCount);
+ This->AutoCompSetMaxHeight(*rowCount);
break;
}
case wxStyledTextCtrl_AutoCompGetMaxHeight: { // wxStyledTextCtrl::AutoCompGetMaxHeight
@@ -27980,7 +28021,7 @@ case wxStyledTextCtrl_SetIndent: { // wxStyledTextCtrl::SetIndent
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * indentSize = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetIndent((int) *indentSize);
+ This->SetIndent(*indentSize);
break;
}
case wxStyledTextCtrl_GetIndent: { // wxStyledTextCtrl::GetIndent
@@ -27994,7 +28035,7 @@ case wxStyledTextCtrl_SetUseTabs: { // wxStyledTextCtrl::SetUseTabs
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
bool * useTabs = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetUseTabs((bool) *useTabs);
+ This->SetUseTabs(*useTabs);
break;
}
case wxStyledTextCtrl_GetUseTabs: { // wxStyledTextCtrl::GetUseTabs
@@ -28009,14 +28050,14 @@ case wxStyledTextCtrl_SetLineIndentation: { // wxStyledTextCtrl::SetLineIndentat
int * line = (int *) bp; bp += 4;
int * indentSize = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetLineIndentation((int) *line,(int) *indentSize);
+ This->SetLineIndentation(*line,*indentSize);
break;
}
case wxStyledTextCtrl_GetLineIndentation: { // wxStyledTextCtrl::GetLineIndentation
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * line = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->GetLineIndentation((int) *line);
+ int Result = This->GetLineIndentation(*line);
rt.addInt(Result);
break;
}
@@ -28024,7 +28065,7 @@ case wxStyledTextCtrl_GetLineIndentPosition: { // wxStyledTextCtrl::GetLineInden
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * line = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->GetLineIndentPosition((int) *line);
+ int Result = This->GetLineIndentPosition(*line);
rt.addInt(Result);
break;
}
@@ -28032,7 +28073,7 @@ case wxStyledTextCtrl_GetColumn: { // wxStyledTextCtrl::GetColumn
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->GetColumn((int) *pos);
+ int Result = This->GetColumn(*pos);
rt.addInt(Result);
break;
}
@@ -28040,7 +28081,7 @@ case wxStyledTextCtrl_SetUseHorizontalScrollBar: { // wxStyledTextCtrl::SetUseHo
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
bool * show = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetUseHorizontalScrollBar((bool) *show);
+ This->SetUseHorizontalScrollBar(*show);
break;
}
case wxStyledTextCtrl_GetUseHorizontalScrollBar: { // wxStyledTextCtrl::GetUseHorizontalScrollBar
@@ -28054,7 +28095,7 @@ case wxStyledTextCtrl_SetIndentationGuides: { // wxStyledTextCtrl::SetIndentatio
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
bool * show = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetIndentationGuides((bool) *show);
+ This->SetIndentationGuides(*show);
break;
}
case wxStyledTextCtrl_GetIndentationGuides: { // wxStyledTextCtrl::GetIndentationGuides
@@ -28068,7 +28109,7 @@ case wxStyledTextCtrl_SetHighlightGuide: { // wxStyledTextCtrl::SetHighlightGuid
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * column = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetHighlightGuide((int) *column);
+ This->SetHighlightGuide(*column);
break;
}
case wxStyledTextCtrl_GetHighlightGuide: { // wxStyledTextCtrl::GetHighlightGuide
@@ -28082,7 +28123,7 @@ case wxStyledTextCtrl_GetLineEndPosition: { // wxStyledTextCtrl::GetLineEndPosit
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * line = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->GetLineEndPosition((int) *line);
+ int Result = This->GetLineEndPosition(*line);
rt.addInt(Result);
break;
}
@@ -28111,14 +28152,14 @@ case wxStyledTextCtrl_SetCurrentPos: { // wxStyledTextCtrl::SetCurrentPos
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetCurrentPos((int) *pos);
+ This->SetCurrentPos(*pos);
break;
}
case wxStyledTextCtrl_SetSelectionStart: { // wxStyledTextCtrl::SetSelectionStart
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetSelectionStart((int) *pos);
+ This->SetSelectionStart(*pos);
break;
}
case wxStyledTextCtrl_GetSelectionStart: { // wxStyledTextCtrl::GetSelectionStart
@@ -28132,7 +28173,7 @@ case wxStyledTextCtrl_SetSelectionEnd: { // wxStyledTextCtrl::SetSelectionEnd
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetSelectionEnd((int) *pos);
+ This->SetSelectionEnd(*pos);
break;
}
case wxStyledTextCtrl_GetSelectionEnd: { // wxStyledTextCtrl::GetSelectionEnd
@@ -28146,7 +28187,7 @@ case wxStyledTextCtrl_SetPrintMagnification: { // wxStyledTextCtrl::SetPrintMagn
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * magnification = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetPrintMagnification((int) *magnification);
+ This->SetPrintMagnification(*magnification);
break;
}
case wxStyledTextCtrl_GetPrintMagnification: { // wxStyledTextCtrl::GetPrintMagnification
@@ -28160,7 +28201,7 @@ case wxStyledTextCtrl_SetPrintColourMode: { // wxStyledTextCtrl::SetPrintColourM
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * mode = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetPrintColourMode((int) *mode);
+ This->SetPrintColourMode(*mode);
break;
}
case wxStyledTextCtrl_GetPrintColourMode: { // wxStyledTextCtrl::GetPrintColourMode
@@ -28184,7 +28225,7 @@ case wxStyledTextCtrl_FindText: { // wxStyledTextCtrl::FindText
} break;
}};
if(!This) throw wxe_badarg(0);
- int Result = This->FindText((int) *minPos,(int) *maxPos,text,flags);
+ int Result = This->FindText(*minPos,*maxPos,text,flags);
rt.addInt(Result);
break;
}
@@ -28206,7 +28247,7 @@ case wxStyledTextCtrl_FormatRange: { // wxStyledTextCtrl::FormatRange
int * pageRectH = (int *) bp; bp += 4;
wxRect pageRect = wxRect(*pageRectX,*pageRectY,*pageRectW,*pageRectH);
if(!This) throw wxe_badarg(0);
- int Result = This->FormatRange((bool) *doDraw,(int) *startPos,(int) *endPos,draw,target,renderRect,pageRect);
+ int Result = This->FormatRange(*doDraw,*startPos,*endPos,draw,target,renderRect,pageRect);
rt.addInt(Result);
break;
}
@@ -28221,7 +28262,7 @@ case wxStyledTextCtrl_GetLine: { // wxStyledTextCtrl::GetLine
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * line = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxString Result = This->GetLine((int) *line);
+ wxString Result = This->GetLine(*line);
rt.add(Result);
break;
}
@@ -28236,7 +28277,7 @@ case wxStyledTextCtrl_SetMarginLeft: { // wxStyledTextCtrl::SetMarginLeft
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * pixelWidth = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetMarginLeft((int) *pixelWidth);
+ This->SetMarginLeft(*pixelWidth);
break;
}
case wxStyledTextCtrl_GetMarginLeft: { // wxStyledTextCtrl::GetMarginLeft
@@ -28250,7 +28291,7 @@ case wxStyledTextCtrl_SetMarginRight: { // wxStyledTextCtrl::SetMarginRight
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * pixelWidth = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetMarginRight((int) *pixelWidth);
+ This->SetMarginRight(*pixelWidth);
break;
}
case wxStyledTextCtrl_GetMarginRight: { // wxStyledTextCtrl::GetMarginRight
@@ -28272,7 +28313,7 @@ case wxStyledTextCtrl_SetSelection: { // wxStyledTextCtrl::SetSelection
int * start = (int *) bp; bp += 4;
int * end = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetSelection((int) *start,(int) *end);
+ This->SetSelection(*start,*end);
break;
}
case wxStyledTextCtrl_GetSelectedText: { // wxStyledTextCtrl::GetSelectedText
@@ -28287,7 +28328,7 @@ case wxStyledTextCtrl_GetTextRange: { // wxStyledTextCtrl::GetTextRange
int * startPos = (int *) bp; bp += 4;
int * endPos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxString Result = This->GetTextRange((int) *startPos,(int) *endPos);
+ wxString Result = This->GetTextRange(*startPos,*endPos);
rt.add(Result);
break;
}
@@ -28295,14 +28336,14 @@ case wxStyledTextCtrl_HideSelection: { // wxStyledTextCtrl::HideSelection
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
bool * normal = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->HideSelection((bool) *normal);
+ This->HideSelection(*normal);
break;
}
case wxStyledTextCtrl_LineFromPosition: { // wxStyledTextCtrl::LineFromPosition
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->LineFromPosition((int) *pos);
+ int Result = This->LineFromPosition(*pos);
rt.addInt(Result);
break;
}
@@ -28310,7 +28351,7 @@ case wxStyledTextCtrl_PositionFromLine: { // wxStyledTextCtrl::PositionFromLine
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * line = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->PositionFromLine((int) *line);
+ int Result = This->PositionFromLine(*line);
rt.addInt(Result);
break;
}
@@ -28319,7 +28360,7 @@ case wxStyledTextCtrl_LineScroll: { // wxStyledTextCtrl::LineScroll
int * columns = (int *) bp; bp += 4;
int * lines = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->LineScroll((int) *columns,(int) *lines);
+ This->LineScroll(*columns,*lines);
break;
}
case wxStyledTextCtrl_EnsureCaretVisible: { // wxStyledTextCtrl::EnsureCaretVisible
@@ -28341,7 +28382,7 @@ case wxStyledTextCtrl_SetReadOnly: { // wxStyledTextCtrl::SetReadOnly
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
bool * readOnly = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetReadOnly((bool) *readOnly);
+ This->SetReadOnly(*readOnly);
break;
}
case wxStyledTextCtrl_CanPaste: { // wxStyledTextCtrl::CanPaste
@@ -28428,7 +28469,7 @@ case wxStyledTextCtrl_SetCaretWidth: { // wxStyledTextCtrl::SetCaretWidth
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * pixelWidth = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetCaretWidth((int) *pixelWidth);
+ This->SetCaretWidth(*pixelWidth);
break;
}
case wxStyledTextCtrl_GetCaretWidth: { // wxStyledTextCtrl::GetCaretWidth
@@ -28442,7 +28483,7 @@ case wxStyledTextCtrl_SetTargetStart: { // wxStyledTextCtrl::SetTargetStart
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetTargetStart((int) *pos);
+ This->SetTargetStart(*pos);
break;
}
case wxStyledTextCtrl_GetTargetStart: { // wxStyledTextCtrl::GetTargetStart
@@ -28456,7 +28497,7 @@ case wxStyledTextCtrl_SetTargetEnd: { // wxStyledTextCtrl::SetTargetEnd
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetTargetEnd((int) *pos);
+ This->SetTargetEnd(*pos);
break;
}
case wxStyledTextCtrl_GetTargetEnd: { // wxStyledTextCtrl::GetTargetEnd
@@ -28490,7 +28531,7 @@ case wxStyledTextCtrl_SetSearchFlags: { // wxStyledTextCtrl::SetSearchFlags
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * flags = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetSearchFlags((int) *flags);
+ This->SetSearchFlags(*flags);
break;
}
case wxStyledTextCtrl_GetSearchFlags: { // wxStyledTextCtrl::GetSearchFlags
@@ -28507,7 +28548,7 @@ case wxStyledTextCtrl_CallTipShow: { // wxStyledTextCtrl::CallTipShow
wxString definition = wxString(bp, wxConvUTF8);
bp += *definitionLen+((8-((4+ *definitionLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- This->CallTipShow((int) *pos,definition);
+ This->CallTipShow(*pos,definition);
break;
}
case wxStyledTextCtrl_CallTipCancel: { // wxStyledTextCtrl::CallTipCancel
@@ -28535,7 +28576,7 @@ case wxStyledTextCtrl_CallTipSetHighlight: { // wxStyledTextCtrl::CallTipSetHigh
int * start = (int *) bp; bp += 4;
int * end = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->CallTipSetHighlight((int) *start,(int) *end);
+ This->CallTipSetHighlight(*start,*end);
break;
}
case wxStyledTextCtrl_CallTipSetBackground: { // wxStyledTextCtrl::CallTipSetBackground
@@ -28575,14 +28616,14 @@ case wxStyledTextCtrl_CallTipUseStyle: { // wxStyledTextCtrl::CallTipUseStyle
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * tabSize = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->CallTipUseStyle((int) *tabSize);
+ This->CallTipUseStyle(*tabSize);
break;
}
case wxStyledTextCtrl_VisibleFromDocLine: { // wxStyledTextCtrl::VisibleFromDocLine
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * line = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->VisibleFromDocLine((int) *line);
+ int Result = This->VisibleFromDocLine(*line);
rt.addInt(Result);
break;
}
@@ -28590,7 +28631,7 @@ case wxStyledTextCtrl_DocLineFromVisible: { // wxStyledTextCtrl::DocLineFromVisi
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * lineDisplay = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->DocLineFromVisible((int) *lineDisplay);
+ int Result = This->DocLineFromVisible(*lineDisplay);
rt.addInt(Result);
break;
}
@@ -28598,7 +28639,7 @@ case wxStyledTextCtrl_WrapCount: { // wxStyledTextCtrl::WrapCount
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * line = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->WrapCount((int) *line);
+ int Result = This->WrapCount(*line);
rt.addInt(Result);
break;
}
@@ -28607,14 +28648,14 @@ case wxStyledTextCtrl_SetFoldLevel: { // wxStyledTextCtrl::SetFoldLevel
int * line = (int *) bp; bp += 4;
int * level = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetFoldLevel((int) *line,(int) *level);
+ This->SetFoldLevel(*line,*level);
break;
}
case wxStyledTextCtrl_GetFoldLevel: { // wxStyledTextCtrl::GetFoldLevel
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * line = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->GetFoldLevel((int) *line);
+ int Result = This->GetFoldLevel(*line);
rt.addInt(Result);
break;
}
@@ -28623,7 +28664,7 @@ case wxStyledTextCtrl_GetLastChild: { // wxStyledTextCtrl::GetLastChild
int * line = (int *) bp; bp += 4;
int * level = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->GetLastChild((int) *line,(int) *level);
+ int Result = This->GetLastChild(*line,*level);
rt.addInt(Result);
break;
}
@@ -28631,7 +28672,7 @@ case wxStyledTextCtrl_GetFoldParent: { // wxStyledTextCtrl::GetFoldParent
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * line = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->GetFoldParent((int) *line);
+ int Result = This->GetFoldParent(*line);
rt.addInt(Result);
break;
}
@@ -28640,7 +28681,7 @@ case wxStyledTextCtrl_ShowLines: { // wxStyledTextCtrl::ShowLines
int * lineStart = (int *) bp; bp += 4;
int * lineEnd = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->ShowLines((int) *lineStart,(int) *lineEnd);
+ This->ShowLines(*lineStart,*lineEnd);
break;
}
case wxStyledTextCtrl_HideLines: { // wxStyledTextCtrl::HideLines
@@ -28648,14 +28689,14 @@ case wxStyledTextCtrl_HideLines: { // wxStyledTextCtrl::HideLines
int * lineStart = (int *) bp; bp += 4;
int * lineEnd = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->HideLines((int) *lineStart,(int) *lineEnd);
+ This->HideLines(*lineStart,*lineEnd);
break;
}
case wxStyledTextCtrl_GetLineVisible: { // wxStyledTextCtrl::GetLineVisible
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * line = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->GetLineVisible((int) *line);
+ bool Result = This->GetLineVisible(*line);
rt.addBool(Result);
break;
}
@@ -28664,14 +28705,14 @@ case wxStyledTextCtrl_SetFoldExpanded: { // wxStyledTextCtrl::SetFoldExpanded
int * line = (int *) bp; bp += 4;
bool * expanded = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetFoldExpanded((int) *line,(bool) *expanded);
+ This->SetFoldExpanded(*line,*expanded);
break;
}
case wxStyledTextCtrl_GetFoldExpanded: { // wxStyledTextCtrl::GetFoldExpanded
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * line = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- bool Result = This->GetFoldExpanded((int) *line);
+ bool Result = This->GetFoldExpanded(*line);
rt.addBool(Result);
break;
}
@@ -28679,35 +28720,35 @@ case wxStyledTextCtrl_ToggleFold: { // wxStyledTextCtrl::ToggleFold
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * line = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->ToggleFold((int) *line);
+ This->ToggleFold(*line);
break;
}
case wxStyledTextCtrl_EnsureVisible: { // wxStyledTextCtrl::EnsureVisible
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * line = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->EnsureVisible((int) *line);
+ This->EnsureVisible(*line);
break;
}
case wxStyledTextCtrl_SetFoldFlags: { // wxStyledTextCtrl::SetFoldFlags
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * flags = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetFoldFlags((int) *flags);
+ This->SetFoldFlags(*flags);
break;
}
case wxStyledTextCtrl_EnsureVisibleEnforcePolicy: { // wxStyledTextCtrl::EnsureVisibleEnforcePolicy
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * line = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->EnsureVisibleEnforcePolicy((int) *line);
+ This->EnsureVisibleEnforcePolicy(*line);
break;
}
case wxStyledTextCtrl_SetTabIndents: { // wxStyledTextCtrl::SetTabIndents
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
bool * tabIndents = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetTabIndents((bool) *tabIndents);
+ This->SetTabIndents(*tabIndents);
break;
}
case wxStyledTextCtrl_GetTabIndents: { // wxStyledTextCtrl::GetTabIndents
@@ -28721,7 +28762,7 @@ case wxStyledTextCtrl_SetBackSpaceUnIndents: { // wxStyledTextCtrl::SetBackSpace
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
bool * bsUnIndents = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetBackSpaceUnIndents((bool) *bsUnIndents);
+ This->SetBackSpaceUnIndents(*bsUnIndents);
break;
}
case wxStyledTextCtrl_GetBackSpaceUnIndents: { // wxStyledTextCtrl::GetBackSpaceUnIndents
@@ -28735,7 +28776,7 @@ case wxStyledTextCtrl_SetMouseDwellTime: { // wxStyledTextCtrl::SetMouseDwellTim
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * periodMilliseconds = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetMouseDwellTime((int) *periodMilliseconds);
+ This->SetMouseDwellTime(*periodMilliseconds);
break;
}
case wxStyledTextCtrl_GetMouseDwellTime: { // wxStyledTextCtrl::GetMouseDwellTime
@@ -28750,7 +28791,7 @@ case wxStyledTextCtrl_WordStartPosition: { // wxStyledTextCtrl::WordStartPositio
int * pos = (int *) bp; bp += 4;
bool * onlyWordCharacters = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->WordStartPosition((int) *pos,(bool) *onlyWordCharacters);
+ int Result = This->WordStartPosition(*pos,*onlyWordCharacters);
rt.addInt(Result);
break;
}
@@ -28759,7 +28800,7 @@ case wxStyledTextCtrl_WordEndPosition: { // wxStyledTextCtrl::WordEndPosition
int * pos = (int *) bp; bp += 4;
bool * onlyWordCharacters = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->WordEndPosition((int) *pos,(bool) *onlyWordCharacters);
+ int Result = This->WordEndPosition(*pos,*onlyWordCharacters);
rt.addInt(Result);
break;
}
@@ -28767,7 +28808,7 @@ case wxStyledTextCtrl_SetWrapMode: { // wxStyledTextCtrl::SetWrapMode
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * mode = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetWrapMode((int) *mode);
+ This->SetWrapMode(*mode);
break;
}
case wxStyledTextCtrl_GetWrapMode: { // wxStyledTextCtrl::GetWrapMode
@@ -28781,7 +28822,7 @@ case wxStyledTextCtrl_SetWrapVisualFlags: { // wxStyledTextCtrl::SetWrapVisualFl
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * wrapVisualFlags = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetWrapVisualFlags((int) *wrapVisualFlags);
+ This->SetWrapVisualFlags(*wrapVisualFlags);
break;
}
case wxStyledTextCtrl_GetWrapVisualFlags: { // wxStyledTextCtrl::GetWrapVisualFlags
@@ -28795,7 +28836,7 @@ case wxStyledTextCtrl_SetWrapVisualFlagsLocation: { // wxStyledTextCtrl::SetWrap
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * wrapVisualFlagsLocation = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetWrapVisualFlagsLocation((int) *wrapVisualFlagsLocation);
+ This->SetWrapVisualFlagsLocation(*wrapVisualFlagsLocation);
break;
}
case wxStyledTextCtrl_GetWrapVisualFlagsLocation: { // wxStyledTextCtrl::GetWrapVisualFlagsLocation
@@ -28809,7 +28850,7 @@ case wxStyledTextCtrl_SetWrapStartIndent: { // wxStyledTextCtrl::SetWrapStartInd
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * indent = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetWrapStartIndent((int) *indent);
+ This->SetWrapStartIndent(*indent);
break;
}
case wxStyledTextCtrl_GetWrapStartIndent: { // wxStyledTextCtrl::GetWrapStartIndent
@@ -28823,7 +28864,7 @@ case wxStyledTextCtrl_SetLayoutCache: { // wxStyledTextCtrl::SetLayoutCache
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * mode = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetLayoutCache((int) *mode);
+ This->SetLayoutCache(*mode);
break;
}
case wxStyledTextCtrl_GetLayoutCache: { // wxStyledTextCtrl::GetLayoutCache
@@ -28837,7 +28878,7 @@ case wxStyledTextCtrl_SetScrollWidth: { // wxStyledTextCtrl::SetScrollWidth
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * pixelWidth = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetScrollWidth((int) *pixelWidth);
+ This->SetScrollWidth(*pixelWidth);
break;
}
case wxStyledTextCtrl_GetScrollWidth: { // wxStyledTextCtrl::GetScrollWidth
@@ -28854,7 +28895,7 @@ case wxStyledTextCtrl_TextWidth: { // wxStyledTextCtrl::TextWidth
wxString text = wxString(bp, wxConvUTF8);
bp += *textLen+((8-((4+ *textLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- int Result = This->TextWidth((int) *style,text);
+ int Result = This->TextWidth(*style,text);
rt.addInt(Result);
break;
}
@@ -28869,7 +28910,7 @@ case wxStyledTextCtrl_TextHeight: { // wxStyledTextCtrl::TextHeight
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * line = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->TextHeight((int) *line);
+ int Result = This->TextHeight(*line);
rt.addInt(Result);
break;
}
@@ -28877,7 +28918,7 @@ case wxStyledTextCtrl_SetUseVerticalScrollBar: { // wxStyledTextCtrl::SetUseVert
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
bool * show = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetUseVerticalScrollBar((bool) *show);
+ This->SetUseVerticalScrollBar(*show);
break;
}
case wxStyledTextCtrl_GetUseVerticalScrollBar: { // wxStyledTextCtrl::GetUseVerticalScrollBar
@@ -28907,7 +28948,7 @@ case wxStyledTextCtrl_SetTwoPhaseDraw: { // wxStyledTextCtrl::SetTwoPhaseDraw
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
bool * twoPhase = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetTwoPhaseDraw((bool) *twoPhase);
+ This->SetTwoPhaseDraw(*twoPhase);
break;
}
case wxStyledTextCtrl_TargetFromSelection: { // wxStyledTextCtrl::TargetFromSelection
@@ -28926,7 +28967,7 @@ case wxStyledTextCtrl_LinesSplit: { // wxStyledTextCtrl::LinesSplit
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * pixelWidth = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->LinesSplit((int) *pixelWidth);
+ This->LinesSplit(*pixelWidth);
break;
}
case wxStyledTextCtrl_SetFoldMarginColour: { // wxStyledTextCtrl::SetFoldMarginColour
@@ -28938,7 +28979,7 @@ case wxStyledTextCtrl_SetFoldMarginColour: { // wxStyledTextCtrl::SetFoldMarginC
int * backA = (int *) bp; bp += 4;
wxColour back = wxColour(*backR,*backG,*backB,*backA);
if(!This) throw wxe_badarg(0);
- This->SetFoldMarginColour((bool) *useSetting,back);
+ This->SetFoldMarginColour(*useSetting,back);
break;
}
case wxStyledTextCtrl_SetFoldMarginHiColour: { // wxStyledTextCtrl::SetFoldMarginHiColour
@@ -28950,7 +28991,7 @@ case wxStyledTextCtrl_SetFoldMarginHiColour: { // wxStyledTextCtrl::SetFoldMargi
int * foreA = (int *) bp; bp += 4;
wxColour fore = wxColour(*foreR,*foreG,*foreB,*foreA);
if(!This) throw wxe_badarg(0);
- This->SetFoldMarginHiColour((bool) *useSetting,fore);
+ This->SetFoldMarginHiColour(*useSetting,fore);
break;
}
case wxStyledTextCtrl_LineDown: { // wxStyledTextCtrl::LineDown
@@ -29299,7 +29340,7 @@ case wxStyledTextCtrl_LineLength: { // wxStyledTextCtrl::LineLength
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * line = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->LineLength((int) *line);
+ int Result = This->LineLength(*line);
rt.addInt(Result);
break;
}
@@ -29308,21 +29349,21 @@ case wxStyledTextCtrl_BraceHighlight: { // wxStyledTextCtrl::BraceHighlight
int * pos1 = (int *) bp; bp += 4;
int * pos2 = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->BraceHighlight((int) *pos1,(int) *pos2);
+ This->BraceHighlight(*pos1,*pos2);
break;
}
case wxStyledTextCtrl_BraceBadLight: { // wxStyledTextCtrl::BraceBadLight
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->BraceBadLight((int) *pos);
+ This->BraceBadLight(*pos);
break;
}
case wxStyledTextCtrl_BraceMatch: { // wxStyledTextCtrl::BraceMatch
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->BraceMatch((int) *pos);
+ int Result = This->BraceMatch(*pos);
rt.addInt(Result);
break;
}
@@ -29337,14 +29378,14 @@ case wxStyledTextCtrl_SetViewEOL: { // wxStyledTextCtrl::SetViewEOL
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
bool * visible = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetViewEOL((bool) *visible);
+ This->SetViewEOL(*visible);
break;
}
case wxStyledTextCtrl_SetModEventMask: { // wxStyledTextCtrl::SetModEventMask
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * mask = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetModEventMask((int) *mask);
+ This->SetModEventMask(*mask);
break;
}
case wxStyledTextCtrl_GetEdgeColumn: { // wxStyledTextCtrl::GetEdgeColumn
@@ -29358,14 +29399,14 @@ case wxStyledTextCtrl_SetEdgeColumn: { // wxStyledTextCtrl::SetEdgeColumn
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * column = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetEdgeColumn((int) *column);
+ This->SetEdgeColumn(*column);
break;
}
case wxStyledTextCtrl_SetEdgeMode: { // wxStyledTextCtrl::SetEdgeMode
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * mode = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetEdgeMode((int) *mode);
+ This->SetEdgeMode(*mode);
break;
}
case wxStyledTextCtrl_GetEdgeMode: { // wxStyledTextCtrl::GetEdgeMode
@@ -29406,7 +29447,7 @@ case wxStyledTextCtrl_SearchNext: { // wxStyledTextCtrl::SearchNext
wxString text = wxString(bp, wxConvUTF8);
bp += *textLen+((8-((4+ *textLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- int Result = This->SearchNext((int) *flags,text);
+ int Result = This->SearchNext(*flags,text);
rt.addInt(Result);
break;
}
@@ -29417,7 +29458,7 @@ case wxStyledTextCtrl_SearchPrev: { // wxStyledTextCtrl::SearchPrev
wxString text = wxString(bp, wxConvUTF8);
bp += *textLen+((8-((4+ *textLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- int Result = This->SearchPrev((int) *flags,text);
+ int Result = This->SearchPrev(*flags,text);
rt.addInt(Result);
break;
}
@@ -29432,7 +29473,7 @@ case wxStyledTextCtrl_UsePopUp: { // wxStyledTextCtrl::UsePopUp
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
bool * allowPopUp = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->UsePopUp((bool) *allowPopUp);
+ This->UsePopUp(*allowPopUp);
break;
}
case wxStyledTextCtrl_SelectionIsRectangle: { // wxStyledTextCtrl::SelectionIsRectangle
@@ -29446,7 +29487,7 @@ case wxStyledTextCtrl_SetZoom: { // wxStyledTextCtrl::SetZoom
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * zoom = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetZoom((int) *zoom);
+ This->SetZoom(*zoom);
break;
}
case wxStyledTextCtrl_GetZoom: { // wxStyledTextCtrl::GetZoom
@@ -29467,7 +29508,7 @@ case wxStyledTextCtrl_SetSTCFocus: { // wxStyledTextCtrl::SetSTCFocus
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
bool * focus = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetSTCFocus((bool) *focus);
+ This->SetSTCFocus(*focus);
break;
}
case wxStyledTextCtrl_GetSTCFocus: { // wxStyledTextCtrl::GetSTCFocus
@@ -29481,7 +29522,7 @@ case wxStyledTextCtrl_SetStatus: { // wxStyledTextCtrl::SetStatus
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * statusCode = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetStatus((int) *statusCode);
+ This->SetStatus(*statusCode);
break;
}
case wxStyledTextCtrl_GetStatus: { // wxStyledTextCtrl::GetStatus
@@ -29495,7 +29536,7 @@ case wxStyledTextCtrl_SetMouseDownCaptures: { // wxStyledTextCtrl::SetMouseDownC
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
bool * captures = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetMouseDownCaptures((bool) *captures);
+ This->SetMouseDownCaptures(*captures);
break;
}
case wxStyledTextCtrl_GetMouseDownCaptures: { // wxStyledTextCtrl::GetMouseDownCaptures
@@ -29509,7 +29550,7 @@ case wxStyledTextCtrl_SetSTCCursor: { // wxStyledTextCtrl::SetSTCCursor
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * cursorType = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetSTCCursor((int) *cursorType);
+ This->SetSTCCursor(*cursorType);
break;
}
case wxStyledTextCtrl_GetSTCCursor: { // wxStyledTextCtrl::GetSTCCursor
@@ -29523,7 +29564,7 @@ case wxStyledTextCtrl_SetControlCharSymbol: { // wxStyledTextCtrl::SetControlCha
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * symbol = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetControlCharSymbol((int) *symbol);
+ This->SetControlCharSymbol(*symbol);
break;
}
case wxStyledTextCtrl_GetControlCharSymbol: { // wxStyledTextCtrl::GetControlCharSymbol
@@ -29562,7 +29603,7 @@ case wxStyledTextCtrl_SetVisiblePolicy: { // wxStyledTextCtrl::SetVisiblePolicy
int * visiblePolicy = (int *) bp; bp += 4;
int * visibleSlop = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetVisiblePolicy((int) *visiblePolicy,(int) *visibleSlop);
+ This->SetVisiblePolicy(*visiblePolicy,*visibleSlop);
break;
}
case wxStyledTextCtrl_DelLineLeft: { // wxStyledTextCtrl::DelLineLeft
@@ -29595,7 +29636,7 @@ case wxStyledTextCtrl_SetXCaretPolicy: { // wxStyledTextCtrl::SetXCaretPolicy
int * caretPolicy = (int *) bp; bp += 4;
int * caretSlop = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetXCaretPolicy((int) *caretPolicy,(int) *caretSlop);
+ This->SetXCaretPolicy(*caretPolicy,*caretSlop);
break;
}
case wxStyledTextCtrl_SetYCaretPolicy: { // wxStyledTextCtrl::SetYCaretPolicy
@@ -29603,7 +29644,7 @@ case wxStyledTextCtrl_SetYCaretPolicy: { // wxStyledTextCtrl::SetYCaretPolicy
int * caretPolicy = (int *) bp; bp += 4;
int * caretSlop = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetYCaretPolicy((int) *caretPolicy,(int) *caretSlop);
+ This->SetYCaretPolicy(*caretPolicy,*caretSlop);
break;
}
case wxStyledTextCtrl_GetPrintWrapMode: { // wxStyledTextCtrl::GetPrintWrapMode
@@ -29622,7 +29663,7 @@ case wxStyledTextCtrl_SetHotspotActiveForeground: { // wxStyledTextCtrl::SetHots
int * foreA = (int *) bp; bp += 4;
wxColour fore = wxColour(*foreR,*foreG,*foreB,*foreA);
if(!This) throw wxe_badarg(0);
- This->SetHotspotActiveForeground((bool) *useSetting,fore);
+ This->SetHotspotActiveForeground(*useSetting,fore);
break;
}
case wxStyledTextCtrl_SetHotspotActiveBackground: { // wxStyledTextCtrl::SetHotspotActiveBackground
@@ -29634,21 +29675,21 @@ case wxStyledTextCtrl_SetHotspotActiveBackground: { // wxStyledTextCtrl::SetHots
int * backA = (int *) bp; bp += 4;
wxColour back = wxColour(*backR,*backG,*backB,*backA);
if(!This) throw wxe_badarg(0);
- This->SetHotspotActiveBackground((bool) *useSetting,back);
+ This->SetHotspotActiveBackground(*useSetting,back);
break;
}
case wxStyledTextCtrl_SetHotspotActiveUnderline: { // wxStyledTextCtrl::SetHotspotActiveUnderline
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
bool * underline = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetHotspotActiveUnderline((bool) *underline);
+ This->SetHotspotActiveUnderline(*underline);
break;
}
case wxStyledTextCtrl_SetHotspotSingleLine: { // wxStyledTextCtrl::SetHotspotSingleLine
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
bool * singleLine = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetHotspotSingleLine((bool) *singleLine);
+ This->SetHotspotSingleLine(*singleLine);
break;
}
case wxStyledTextCtrl_ParaDownExtend: { // wxStyledTextCtrl::ParaDownExtend
@@ -29673,7 +29714,7 @@ case wxStyledTextCtrl_PositionBefore: { // wxStyledTextCtrl::PositionBefore
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->PositionBefore((int) *pos);
+ int Result = This->PositionBefore(*pos);
rt.addInt(Result);
break;
}
@@ -29681,7 +29722,7 @@ case wxStyledTextCtrl_PositionAfter: { // wxStyledTextCtrl::PositionAfter
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->PositionAfter((int) *pos);
+ int Result = This->PositionAfter(*pos);
rt.addInt(Result);
break;
}
@@ -29690,7 +29731,7 @@ case wxStyledTextCtrl_CopyRange: { // wxStyledTextCtrl::CopyRange
int * start = (int *) bp; bp += 4;
int * end = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->CopyRange((int) *start,(int) *end);
+ This->CopyRange(*start,*end);
break;
}
case wxStyledTextCtrl_CopyText: { // wxStyledTextCtrl::CopyText
@@ -29700,14 +29741,14 @@ case wxStyledTextCtrl_CopyText: { // wxStyledTextCtrl::CopyText
wxString text = wxString(bp, wxConvUTF8);
bp += *textLen+((8-((4+ *textLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- This->CopyText((int) *length,text);
+ This->CopyText(*length,text);
break;
}
case wxStyledTextCtrl_SetSelectionMode: { // wxStyledTextCtrl::SetSelectionMode
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * mode = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetSelectionMode((int) *mode);
+ This->SetSelectionMode(*mode);
break;
}
case wxStyledTextCtrl_GetSelectionMode: { // wxStyledTextCtrl::GetSelectionMode
@@ -29845,7 +29886,7 @@ case wxStyledTextCtrl_Allocate: { // wxStyledTextCtrl::Allocate
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * bytes = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->Allocate((int) *bytes);
+ This->Allocate(*bytes);
break;
}
case wxStyledTextCtrl_FindColumn: { // wxStyledTextCtrl::FindColumn
@@ -29853,7 +29894,7 @@ case wxStyledTextCtrl_FindColumn: { // wxStyledTextCtrl::FindColumn
int * line = (int *) bp; bp += 4;
int * column = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- int Result = This->FindColumn((int) *line,(int) *column);
+ int Result = This->FindColumn(*line,*column);
rt.addInt(Result);
break;
}
@@ -29868,7 +29909,7 @@ case wxStyledTextCtrl_SetCaretSticky: { // wxStyledTextCtrl::SetCaretSticky
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
bool * useCaretStickyBehaviour = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetCaretSticky((bool) *useCaretStickyBehaviour);
+ This->SetCaretSticky(*useCaretStickyBehaviour);
break;
}
case wxStyledTextCtrl_ToggleCaretSticky: { // wxStyledTextCtrl::ToggleCaretSticky
@@ -29881,7 +29922,7 @@ case wxStyledTextCtrl_SetPasteConvertEndings: { // wxStyledTextCtrl::SetPasteCon
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
bool * convert = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetPasteConvertEndings((bool) *convert);
+ This->SetPasteConvertEndings(*convert);
break;
}
case wxStyledTextCtrl_GetPasteConvertEndings: { // wxStyledTextCtrl::GetPasteConvertEndings
@@ -29901,7 +29942,7 @@ case wxStyledTextCtrl_SetCaretLineBackAlpha: { // wxStyledTextCtrl::SetCaretLine
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * alpha = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetCaretLineBackAlpha((int) *alpha);
+ This->SetCaretLineBackAlpha(*alpha);
break;
}
case wxStyledTextCtrl_GetCaretLineBackAlpha: { // wxStyledTextCtrl::GetCaretLineBackAlpha
@@ -29927,7 +29968,7 @@ case wxStyledTextCtrl_SetLexer: { // wxStyledTextCtrl::SetLexer
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * lexer = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetLexer((int) *lexer);
+ This->SetLexer(*lexer);
break;
}
case wxStyledTextCtrl_GetLexer: { // wxStyledTextCtrl::GetLexer
@@ -29942,7 +29983,7 @@ case wxStyledTextCtrl_Colourise: { // wxStyledTextCtrl::Colourise
int * start = (int *) bp; bp += 4;
int * end = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->Colourise((int) *start,(int) *end);
+ This->Colourise(*start,*end);
break;
}
case wxStyledTextCtrl_SetProperty: { // wxStyledTextCtrl::SetProperty
@@ -29964,7 +30005,7 @@ case wxStyledTextCtrl_SetKeyWords: { // wxStyledTextCtrl::SetKeyWords
wxString keyWords = wxString(bp, wxConvUTF8);
bp += *keyWordsLen+((8-((4+ *keyWordsLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- This->SetKeyWords((int) *keywordSet,keyWords);
+ This->SetKeyWords(*keywordSet,keyWords);
break;
}
case wxStyledTextCtrl_SetLexerLanguage: { // wxStyledTextCtrl::SetLexerLanguage
@@ -30007,7 +30048,7 @@ case wxStyledTextCtrl_StyleSetSpec: { // wxStyledTextCtrl::StyleSetSpec
wxString spec = wxString(bp, wxConvUTF8);
bp += *specLen+((8-((4+ *specLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- This->StyleSetSpec((int) *styleNum,spec);
+ This->StyleSetSpec(*styleNum,spec);
break;
}
case wxStyledTextCtrl_StyleSetFont: { // wxStyledTextCtrl::StyleSetFont
@@ -30015,7 +30056,7 @@ case wxStyledTextCtrl_StyleSetFont: { // wxStyledTextCtrl::StyleSetFont
int * styleNum = (int *) bp; bp += 4;
wxFont *font = (wxFont *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- This->StyleSetFont((int) *styleNum,*font);
+ This->StyleSetFont(*styleNum,*font);
break;
}
case wxStyledTextCtrl_StyleSetFontAttr: { // wxStyledTextCtrl::StyleSetFontAttr
@@ -30036,7 +30077,7 @@ encoding = *(wxFontEncoding *) bp; bp += 4;;
} break;
}};
if(!This) throw wxe_badarg(0);
- This->StyleSetFontAttr((int) *styleNum,(int) *size,faceName,(bool) *bold,(bool) *italic,(bool) *underline,(wxFontEncoding) encoding);
+ This->StyleSetFontAttr(*styleNum,*size,faceName,*bold,*italic,*underline,encoding);
break;
}
case wxStyledTextCtrl_StyleSetCharacterSet: { // wxStyledTextCtrl::StyleSetCharacterSet
@@ -30044,7 +30085,7 @@ case wxStyledTextCtrl_StyleSetCharacterSet: { // wxStyledTextCtrl::StyleSetChara
int * style = (int *) bp; bp += 4;
int * characterSet = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->StyleSetCharacterSet((int) *style,(int) *characterSet);
+ This->StyleSetCharacterSet(*style,*characterSet);
break;
}
case wxStyledTextCtrl_StyleSetFontEncoding: { // wxStyledTextCtrl::StyleSetFontEncoding
@@ -30052,14 +30093,14 @@ case wxStyledTextCtrl_StyleSetFontEncoding: { // wxStyledTextCtrl::StyleSetFontE
int * style = (int *) bp; bp += 4;
wxFontEncoding encoding = *(wxFontEncoding *) bp; bp += 4;;
if(!This) throw wxe_badarg(0);
- This->StyleSetFontEncoding((int) *style,(wxFontEncoding) encoding);
+ This->StyleSetFontEncoding(*style,encoding);
break;
}
case wxStyledTextCtrl_CmdKeyExecute: { // wxStyledTextCtrl::CmdKeyExecute
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * cmd = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->CmdKeyExecute((int) *cmd);
+ This->CmdKeyExecute(*cmd);
break;
}
case wxStyledTextCtrl_SetMargins: { // wxStyledTextCtrl::SetMargins
@@ -30067,7 +30108,7 @@ case wxStyledTextCtrl_SetMargins: { // wxStyledTextCtrl::SetMargins
int * left = (int *) bp; bp += 4;
int * right = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetMargins((int) *left,(int) *right);
+ This->SetMargins(*left,*right);
break;
}
case wxStyledTextCtrl_GetSelection: { // wxStyledTextCtrl::GetSelection
@@ -30085,7 +30126,7 @@ case wxStyledTextCtrl_PointFromPosition: { // wxStyledTextCtrl::PointFromPositio
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- wxPoint Result = This->PointFromPosition((int) *pos);
+ wxPoint Result = This->PointFromPosition(*pos);
rt.add(Result);
break;
}
@@ -30093,32 +30134,14 @@ case wxStyledTextCtrl_ScrollToLine: { // wxStyledTextCtrl::ScrollToLine
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * line = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->ScrollToLine((int) *line);
+ This->ScrollToLine(*line);
break;
}
case wxStyledTextCtrl_ScrollToColumn: { // wxStyledTextCtrl::ScrollToColumn
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * column = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->ScrollToColumn((int) *column);
- break;
-}
-case wxStyledTextCtrl_SendMsg: { // wxStyledTextCtrl::SendMsg
- long wp=0;
- long lp=0;
- wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
- int * msg = (int *) bp; bp += 4;
- while( * (int*) bp) { switch (* (int*) bp) {
- case 1: {bp += 4;
- wp = (long)*(int *) bp; bp += 4;
- } break;
- case 2: {bp += 4;
- lp = (long)*(int *) bp; bp += 4;
- } break;
- }};
- if(!This) throw wxe_badarg(0);
- long Result = This->SendMsg((int) *msg,wp,lp);
- rt.addInt(Result);
+ This->ScrollToColumn(*column);
break;
}
case wxStyledTextCtrl_SetVScrollBar: { // wxStyledTextCtrl::SetVScrollBar
@@ -30146,7 +30169,7 @@ case wxStyledTextCtrl_SetLastKeydownProcessed: { // wxStyledTextCtrl::SetLastKey
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
bool * val = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetLastKeydownProcessed((bool) *val);
+ This->SetLastKeydownProcessed(*val);
break;
}
case wxStyledTextCtrl_SaveFile: { // wxStyledTextCtrl::SaveFile
@@ -30175,7 +30198,7 @@ case wxStyledTextCtrl_DoDragOver: { // wxStyledTextCtrl::DoDragOver
int * y = (int *) bp; bp += 4;
wxDragResult def = *(wxDragResult *) bp; bp += 4;;
if(!This) throw wxe_badarg(0);
- int Result = This->DoDragOver((wxCoord) *x,(wxCoord) *y,(wxDragResult) def);
+ int Result = This->DoDragOver(*x,*y,def);
rt.addInt(Result);
break;
}
@@ -30187,7 +30210,7 @@ case wxStyledTextCtrl_DoDropText: { // wxStyledTextCtrl::DoDropText
wxString data = wxString(bp, wxConvUTF8);
bp += *dataLen+((8-((0+ *dataLen) & 7)) & 7);
if(!This) throw wxe_badarg(0);
- bool Result = This->DoDropText((long) *x,(long) *y,data);
+ bool Result = This->DoDropText(*x,*y,data);
rt.addBool(Result);
break;
}
@@ -30210,7 +30233,7 @@ case wxStyledTextCtrl_InsertTextRaw: { // wxStyledTextCtrl::InsertTextRaw
int * pos = (int *) bp; bp += 4;
const char * text = (const char*) Ecmd.bin[0]->base;
if(!This) throw wxe_badarg(0);
- This->InsertTextRaw((int) *pos,text);
+ This->InsertTextRaw(*pos,text);
break;
}
case wxStyledTextCtrl_GetCurLineRaw: { // wxStyledTextCtrl::GetCurLineRaw
@@ -30229,7 +30252,7 @@ case wxStyledTextCtrl_GetLineRaw: { // wxStyledTextCtrl::GetLineRaw
wxStyledTextCtrl *This = (wxStyledTextCtrl *) getPtr(bp,memenv); bp += 4;
int * line = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- char * Result = This->GetLineRaw((int) *line).data();
+ char * Result = This->GetLineRaw(*line).data();
if(Result) {
rt.addBinary(Result, strlen(Result));
} else {rt.addAtom("null");};
@@ -30249,7 +30272,7 @@ case wxStyledTextCtrl_GetTextRangeRaw: { // wxStyledTextCtrl::GetTextRangeRaw
int * startPos = (int *) bp; bp += 4;
int * endPos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- char * Result = This->GetTextRangeRaw((int) *startPos,(int) *endPos).data();
+ char * Result = This->GetTextRangeRaw(*startPos,*endPos).data();
if(Result) {
rt.addBinary(Result, strlen(Result));
} else {rt.addAtom("null");};
@@ -30400,19 +30423,19 @@ case wxNotebookEvent_SetOldSelection: { // wxNotebookEvent::SetOldSelection
wxNotebookEvent *This = (wxNotebookEvent *) getPtr(bp,memenv); bp += 4;
int * nOldSel = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetOldSelection((int) *nOldSel);
+ This->SetOldSelection(*nOldSel);
break;
}
case wxNotebookEvent_SetSelection: { // wxNotebookEvent::SetSelection
wxNotebookEvent *This = (wxNotebookEvent *) getPtr(bp,memenv); bp += 4;
int * nSel = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetSelection((int) *nSel);
+ This->SetSelection(*nSel);
break;
}
case wxFileDataObject_new: { // wxFileDataObject::wxFileDataObject
wxFileDataObject * Result = new wxFileDataObject();
- newPtr((void *) Result, 212, memenv);
+ newPtr((void *) Result, 211, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxFileDataObject");
break;
}
@@ -30448,7 +30471,7 @@ case wxTextDataObject_new: { // wxTextDataObject::wxTextDataObject
} break;
}};
wxTextDataObject * Result = new wxTextDataObject(text);
- newPtr((void *) Result, 213, memenv);
+ newPtr((void *) Result, 212, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxTextDataObject");
break;
}
@@ -30484,7 +30507,7 @@ case wxTextDataObject_destroy: { // wxTextDataObject::destroy
case wxBitmapDataObject_new_1_1: { // wxBitmapDataObject::wxBitmapDataObject
wxBitmap *bitmap = (wxBitmap *) getPtr(bp,memenv); bp += 4;
wxBitmapDataObject * Result = new wxBitmapDataObject(*bitmap);
- newPtr((void *) Result, 214, memenv);
+ newPtr((void *) Result, 213, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxBitmapDataObject");
break;
}
@@ -30496,7 +30519,7 @@ bitmap = (wxBitmap *) getPtr(bp,memenv); bp += 4;
} break;
}};
wxBitmapDataObject * Result = new wxBitmapDataObject(*bitmap);
- newPtr((void *) Result, 214, memenv);
+ newPtr((void *) Result, 213, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxBitmapDataObject");
break;
}
@@ -30598,9 +30621,9 @@ case wxClipboard_UsePrimarySelection: { // wxClipboard::UsePrimarySelection
}
case wxClipboard_IsSupported: { // wxClipboard::IsSupported
wxClipboard *This = (wxClipboard *) getPtr(bp,memenv); bp += 4;
- const int * format = (const int *) bp; bp += 4;
+ wxDataFormatId format = *(wxDataFormatId *) bp; bp += 4;;
if(!This) throw wxe_badarg(0);
- bool Result = This->IsSupported((wxDataFormatId) *format);
+ bool Result = This->IsSupported(format);
rt.addBool(Result);
break;
}
@@ -30620,7 +30643,7 @@ case wxSpinEvent_SetPosition: { // wxSpinEvent::SetPosition
wxSpinEvent *This = (wxSpinEvent *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetPosition((int) *pos);
+ This->SetPosition(*pos);
break;
}
case wxSplitterWindow_new_0: { // wxSplitterWindow::wxSplitterWindow
@@ -30763,7 +30786,7 @@ case wxSplitterWindow_SetSashGravity: { // wxSplitterWindow::SetSashGravity
bp += 4; /* Align */
double * gravity = (double *) bp; bp += 8;
if(!This) throw wxe_badarg(0);
- This->SetSashGravity((double) *gravity);
+ This->SetSashGravity(*gravity);
break;
}
case wxSplitterWindow_SetSashPosition: { // wxSplitterWindow::SetSashPosition
@@ -30776,28 +30799,28 @@ case wxSplitterWindow_SetSashPosition: { // wxSplitterWindow::SetSashPosition
} break;
}};
if(!This) throw wxe_badarg(0);
- This->SetSashPosition((int) *position,redraw);
+ This->SetSashPosition(*position,redraw);
break;
}
case wxSplitterWindow_SetSashSize: { // wxSplitterWindow::SetSashSize
wxSplitterWindow *This = (wxSplitterWindow *) getPtr(bp,memenv); bp += 4;
int * width = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetSashSize((int) *width);
+ This->SetSashSize(*width);
break;
}
case wxSplitterWindow_SetMinimumPaneSize: { // wxSplitterWindow::SetMinimumPaneSize
wxSplitterWindow *This = (wxSplitterWindow *) getPtr(bp,memenv); bp += 4;
int * min = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetMinimumPaneSize((int) *min);
+ This->SetMinimumPaneSize(*min);
break;
}
case wxSplitterWindow_SetSplitMode: { // wxSplitterWindow::SetSplitMode
wxSplitterWindow *This = (wxSplitterWindow *) getPtr(bp,memenv); bp += 4;
int * mode = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetSplitMode((int) *mode);
+ This->SetSplitMode(*mode);
break;
}
case wxSplitterWindow_SplitHorizontally: { // wxSplitterWindow::SplitHorizontally
@@ -30884,7 +30907,7 @@ case wxSplitterEvent_SetSashPosition: { // wxSplitterEvent::SetSashPosition
wxSplitterEvent *This = (wxSplitterEvent *) getPtr(bp,memenv); bp += 4;
int * pos = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetSashPosition((int) *pos);
+ This->SetSashPosition(*pos);
break;
}
case wxHtmlWindow_new_0: { // wxHtmlWindow::wxHtmlWindow
@@ -31053,7 +31076,7 @@ case wxHtmlWindow_SetBorders: { // wxHtmlWindow::SetBorders
wxHtmlWindow *This = (wxHtmlWindow *) getPtr(bp,memenv); bp += 4;
int * b = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetBorders((int) *b);
+ This->SetBorders(*b);
break;
}
case wxHtmlWindow_SetFonts: { // wxHtmlWindow::SetFonts
@@ -31098,7 +31121,7 @@ case wxHtmlWindow_SetRelatedStatusBar: { // wxHtmlWindow::SetRelatedStatusBar
wxHtmlWindow *This = (wxHtmlWindow *) getPtr(bp,memenv); bp += 4;
int * bar = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetRelatedStatusBar((int) *bar);
+ This->SetRelatedStatusBar(*bar);
break;
}
case wxHtmlWindow_ToText: { // wxHtmlWindow::ToText
@@ -31117,13 +31140,13 @@ case wxHtmlLinkEvent_GetLinkInfo: { // wxHtmlLinkEvent::GetLinkInfo
}
case wxSystemSettings_GetColour: { // wxSystemSettings::GetColour
wxSystemColour index = *(wxSystemColour *) bp; bp += 4;;
- wxColour Result = wxSystemSettings::GetColour((wxSystemColour) index);
+ wxColour Result = wxSystemSettings::GetColour(index);
rt.add(Result);
break;
}
case wxSystemSettings_GetFont: { // wxSystemSettings::GetFont
wxSystemFont index = *(wxSystemFont *) bp; bp += 4;;
- wxFont * Result = new wxFont(wxSystemSettings::GetFont((wxSystemFont) index)); newPtr((void *) Result,3, memenv);;
+ wxFont * Result = new wxFont(wxSystemSettings::GetFont(index)); newPtr((void *) Result,3, memenv);;
rt.addRef(getRef((void *)Result,memenv), "wxFont");
break;
}
@@ -31136,7 +31159,7 @@ case wxSystemSettings_GetMetric: { // wxSystemSettings::GetMetric
win = (wxWindow *) getPtr(bp,memenv); bp += 4;
} break;
}};
- int Result = wxSystemSettings::GetMetric((wxSystemMetric) index,win);
+ int Result = wxSystemSettings::GetMetric(index,win);
rt.addInt(Result);
break;
}
@@ -31192,14 +31215,14 @@ case wxSystemOptions_SetOption_2_0: { // wxSystemOptions::SetOption
wxString name = wxString(bp, wxConvUTF8);
bp += *nameLen+((8-((4+ *nameLen) & 7)) & 7);
int * value = (int *) bp; bp += 4;
- wxSystemOptions::SetOption(name,(int) *value);
+ wxSystemOptions::SetOption(name,*value);
break;
}
case wxAuiNotebookEvent_SetSelection: { // wxAuiNotebookEvent::SetSelection
wxAuiNotebookEvent *This = (wxAuiNotebookEvent *) getPtr(bp,memenv); bp += 4;
int * s = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetSelection((int) *s);
+ This->SetSelection(*s);
break;
}
case wxAuiNotebookEvent_GetSelection: { // wxAuiNotebookEvent::GetSelection
@@ -31213,7 +31236,7 @@ case wxAuiNotebookEvent_SetOldSelection: { // wxAuiNotebookEvent::SetOldSelectio
wxAuiNotebookEvent *This = (wxAuiNotebookEvent *) getPtr(bp,memenv); bp += 4;
int * s = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetOldSelection((int) *s);
+ This->SetOldSelection(*s);
break;
}
case wxAuiNotebookEvent_GetOldSelection: { // wxAuiNotebookEvent::GetOldSelection
@@ -31269,7 +31292,7 @@ case wxAuiManagerEvent_SetButton: { // wxAuiManagerEvent::SetButton
wxAuiManagerEvent *This = (wxAuiManagerEvent *) getPtr(bp,memenv); bp += 4;
int * b = (int *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetButton((int) *b);
+ This->SetButton(*b);
break;
}
case wxAuiManagerEvent_GetButton: { // wxAuiManagerEvent::GetButton
@@ -31317,7 +31340,7 @@ case wxAuiManagerEvent_SetCanVeto: { // wxAuiManagerEvent::SetCanVeto
wxAuiManagerEvent *This = (wxAuiManagerEvent *) getPtr(bp,memenv); bp += 4;
bool * can_veto = (bool *) bp; bp += 4;
if(!This) throw wxe_badarg(0);
- This->SetCanVeto((bool) *can_veto);
+ This->SetCanVeto(*can_veto);
break;
}
case wxAuiManagerEvent_CanVeto: { // wxAuiManagerEvent::CanVeto
@@ -31329,7 +31352,7 @@ case wxAuiManagerEvent_CanVeto: { // wxAuiManagerEvent::CanVeto
}
case wxLogNull_new: { // wxLogNull::wxLogNull
wxLogNull * Result = new wxLogNull();
- newPtr((void *) Result, 225, memenv);
+ newPtr((void *) Result, 224, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxLogNull");
break;
}
@@ -31416,10 +31439,10 @@ void WxeApp::delete_object(void *ptr, wxeRefData *refd) {
case 101: delete (wxListItemAttr *) ptr; break;
case 103: delete (wxTextAttr *) ptr; break;
case 155: delete (wxAuiPaneInfo *) ptr; break;
- case 212: /* delete (wxFileDataObject *) ptr;These objects must be deleted by owner object */ break;
- case 213: /* delete (wxTextDataObject *) ptr;These objects must be deleted by owner object */ break;
- case 214: /* delete (wxBitmapDataObject *) ptr;These objects must be deleted by owner object */ break;
- case 225: delete (wxLogNull *) ptr; break;
+ case 211: /* delete (wxFileDataObject *) ptr;These objects must be deleted by owner object */ break;
+ case 212: /* delete (wxTextDataObject *) ptr;These objects must be deleted by owner object */ break;
+ case 213: /* delete (wxBitmapDataObject *) ptr;These objects must be deleted by owner object */ break;
+ case 224: delete (wxLogNull *) ptr; break;
default: delete (wxObject *) ptr;
}}
diff --git a/lib/wx/c_src/gen/wxe_macros.h b/lib/wx/c_src/gen/wxe_macros.h
index b24becae06..4b87c2340e 100644
--- a/lib/wx/c_src/gen/wxe_macros.h
+++ b/lib/wx/c_src/gen/wxe_macros.h
@@ -3201,155 +3201,154 @@
#define wxStyledTextCtrl_PointFromPosition 3370
#define wxStyledTextCtrl_ScrollToLine 3371
#define wxStyledTextCtrl_ScrollToColumn 3372
-#define wxStyledTextCtrl_SendMsg 3373
-#define wxStyledTextCtrl_SetVScrollBar 3374
-#define wxStyledTextCtrl_SetHScrollBar 3375
-#define wxStyledTextCtrl_GetLastKeydownProcessed 3376
-#define wxStyledTextCtrl_SetLastKeydownProcessed 3377
-#define wxStyledTextCtrl_SaveFile 3378
-#define wxStyledTextCtrl_LoadFile 3379
-#define wxStyledTextCtrl_DoDragOver 3380
-#define wxStyledTextCtrl_DoDropText 3381
-#define wxStyledTextCtrl_GetUseAntiAliasing 3382
-#define wxStyledTextCtrl_AddTextRaw 3383
-#define wxStyledTextCtrl_InsertTextRaw 3384
-#define wxStyledTextCtrl_GetCurLineRaw 3385
-#define wxStyledTextCtrl_GetLineRaw 3386
-#define wxStyledTextCtrl_GetSelectedTextRaw 3387
-#define wxStyledTextCtrl_GetTextRangeRaw 3388
-#define wxStyledTextCtrl_SetTextRaw 3389
-#define wxStyledTextCtrl_GetTextRaw 3390
-#define wxStyledTextCtrl_AppendTextRaw 3391
-#define wxArtProvider_GetBitmap 3392
-#define wxArtProvider_GetIcon 3393
-#define wxTreeEvent_GetKeyCode 3394
-#define wxTreeEvent_GetItem 3395
-#define wxTreeEvent_GetKeyEvent 3396
-#define wxTreeEvent_GetLabel 3397
-#define wxTreeEvent_GetOldItem 3398
-#define wxTreeEvent_GetPoint 3399
-#define wxTreeEvent_IsEditCancelled 3400
-#define wxTreeEvent_SetToolTip 3401
-#define wxNotebookEvent_GetOldSelection 3402
-#define wxNotebookEvent_GetSelection 3403
-#define wxNotebookEvent_SetOldSelection 3404
-#define wxNotebookEvent_SetSelection 3405
-#define wxFileDataObject_new 3406
-#define wxFileDataObject_AddFile 3407
-#define wxFileDataObject_GetFilenames 3408
-#define wxFileDataObject_destroy 3409
-#define wxTextDataObject_new 3410
-#define wxTextDataObject_GetTextLength 3411
-#define wxTextDataObject_GetText 3412
-#define wxTextDataObject_SetText 3413
-#define wxTextDataObject_destroy 3414
-#define wxBitmapDataObject_new_1_1 3415
-#define wxBitmapDataObject_new_1_0 3416
-#define wxBitmapDataObject_GetBitmap 3417
-#define wxBitmapDataObject_SetBitmap 3418
-#define wxBitmapDataObject_destroy 3419
-#define wxClipboard_new 3421
-#define wxClipboard_destruct 3422
-#define wxClipboard_AddData 3423
-#define wxClipboard_Clear 3424
-#define wxClipboard_Close 3425
-#define wxClipboard_Flush 3426
-#define wxClipboard_GetData 3427
-#define wxClipboard_IsOpened 3428
-#define wxClipboard_Open 3429
-#define wxClipboard_SetData 3430
-#define wxClipboard_UsePrimarySelection 3432
-#define wxClipboard_IsSupported 3433
-#define wxClipboard_Get 3434
-#define wxSpinEvent_GetPosition 3435
-#define wxSpinEvent_SetPosition 3436
-#define wxSplitterWindow_new_0 3437
-#define wxSplitterWindow_new_2 3438
-#define wxSplitterWindow_destruct 3439
-#define wxSplitterWindow_Create 3440
-#define wxSplitterWindow_GetMinimumPaneSize 3441
-#define wxSplitterWindow_GetSashGravity 3442
-#define wxSplitterWindow_GetSashPosition 3443
-#define wxSplitterWindow_GetSplitMode 3444
-#define wxSplitterWindow_GetWindow1 3445
-#define wxSplitterWindow_GetWindow2 3446
-#define wxSplitterWindow_Initialize 3447
-#define wxSplitterWindow_IsSplit 3448
-#define wxSplitterWindow_ReplaceWindow 3449
-#define wxSplitterWindow_SetSashGravity 3450
-#define wxSplitterWindow_SetSashPosition 3451
-#define wxSplitterWindow_SetSashSize 3452
-#define wxSplitterWindow_SetMinimumPaneSize 3453
-#define wxSplitterWindow_SetSplitMode 3454
-#define wxSplitterWindow_SplitHorizontally 3455
-#define wxSplitterWindow_SplitVertically 3456
-#define wxSplitterWindow_Unsplit 3457
-#define wxSplitterWindow_UpdateSize 3458
-#define wxSplitterEvent_GetSashPosition 3459
-#define wxSplitterEvent_GetX 3460
-#define wxSplitterEvent_GetY 3461
-#define wxSplitterEvent_GetWindowBeingRemoved 3462
-#define wxSplitterEvent_SetSashPosition 3463
-#define wxHtmlWindow_new_0 3464
-#define wxHtmlWindow_new_2 3465
-#define wxHtmlWindow_AppendToPage 3466
-#define wxHtmlWindow_GetOpenedAnchor 3467
-#define wxHtmlWindow_GetOpenedPage 3468
-#define wxHtmlWindow_GetOpenedPageTitle 3469
-#define wxHtmlWindow_GetRelatedFrame 3470
-#define wxHtmlWindow_HistoryBack 3471
-#define wxHtmlWindow_HistoryCanBack 3472
-#define wxHtmlWindow_HistoryCanForward 3473
-#define wxHtmlWindow_HistoryClear 3474
-#define wxHtmlWindow_HistoryForward 3475
-#define wxHtmlWindow_LoadFile 3476
-#define wxHtmlWindow_LoadPage 3477
-#define wxHtmlWindow_SelectAll 3478
-#define wxHtmlWindow_SelectionToText 3479
-#define wxHtmlWindow_SelectLine 3480
-#define wxHtmlWindow_SelectWord 3481
-#define wxHtmlWindow_SetBorders 3482
-#define wxHtmlWindow_SetFonts 3483
-#define wxHtmlWindow_SetPage 3484
-#define wxHtmlWindow_SetRelatedFrame 3485
-#define wxHtmlWindow_SetRelatedStatusBar 3486
-#define wxHtmlWindow_ToText 3487
-#define wxHtmlWindow_destroy 3488
-#define wxHtmlLinkEvent_GetLinkInfo 3489
-#define wxSystemSettings_GetColour 3490
-#define wxSystemSettings_GetFont 3491
-#define wxSystemSettings_GetMetric 3492
-#define wxSystemSettings_GetScreenType 3493
-#define wxSystemOptions_GetOption 3494
-#define wxSystemOptions_GetOptionInt 3495
-#define wxSystemOptions_HasOption 3496
-#define wxSystemOptions_IsFalse 3497
-#define wxSystemOptions_SetOption_2_1 3498
-#define wxSystemOptions_SetOption_2_0 3499
-#define wxAuiNotebookEvent_SetSelection 3500
-#define wxAuiNotebookEvent_GetSelection 3501
-#define wxAuiNotebookEvent_SetOldSelection 3502
-#define wxAuiNotebookEvent_GetOldSelection 3503
-#define wxAuiNotebookEvent_SetDragSource 3504
-#define wxAuiNotebookEvent_GetDragSource 3505
-#define wxAuiManagerEvent_SetManager 3506
-#define wxAuiManagerEvent_GetManager 3507
-#define wxAuiManagerEvent_SetPane 3508
-#define wxAuiManagerEvent_GetPane 3509
-#define wxAuiManagerEvent_SetButton 3510
-#define wxAuiManagerEvent_GetButton 3511
-#define wxAuiManagerEvent_SetDC 3512
-#define wxAuiManagerEvent_GetDC 3513
-#define wxAuiManagerEvent_Veto 3514
-#define wxAuiManagerEvent_GetVeto 3515
-#define wxAuiManagerEvent_SetCanVeto 3516
-#define wxAuiManagerEvent_CanVeto 3517
-#define wxLogNull_new 3518
-#define wxLogNull_destroy 3519
-#define wxTaskBarIcon_new 3520
-#define wxTaskBarIcon_destruct 3521
-#define wxTaskBarIcon_PopupMenu 3522
-#define wxTaskBarIcon_RemoveIcon 3523
-#define wxTaskBarIcon_SetIcon 3524
+#define wxStyledTextCtrl_SetVScrollBar 3373
+#define wxStyledTextCtrl_SetHScrollBar 3374
+#define wxStyledTextCtrl_GetLastKeydownProcessed 3375
+#define wxStyledTextCtrl_SetLastKeydownProcessed 3376
+#define wxStyledTextCtrl_SaveFile 3377
+#define wxStyledTextCtrl_LoadFile 3378
+#define wxStyledTextCtrl_DoDragOver 3379
+#define wxStyledTextCtrl_DoDropText 3380
+#define wxStyledTextCtrl_GetUseAntiAliasing 3381
+#define wxStyledTextCtrl_AddTextRaw 3382
+#define wxStyledTextCtrl_InsertTextRaw 3383
+#define wxStyledTextCtrl_GetCurLineRaw 3384
+#define wxStyledTextCtrl_GetLineRaw 3385
+#define wxStyledTextCtrl_GetSelectedTextRaw 3386
+#define wxStyledTextCtrl_GetTextRangeRaw 3387
+#define wxStyledTextCtrl_SetTextRaw 3388
+#define wxStyledTextCtrl_GetTextRaw 3389
+#define wxStyledTextCtrl_AppendTextRaw 3390
+#define wxArtProvider_GetBitmap 3391
+#define wxArtProvider_GetIcon 3392
+#define wxTreeEvent_GetKeyCode 3393
+#define wxTreeEvent_GetItem 3394
+#define wxTreeEvent_GetKeyEvent 3395
+#define wxTreeEvent_GetLabel 3396
+#define wxTreeEvent_GetOldItem 3397
+#define wxTreeEvent_GetPoint 3398
+#define wxTreeEvent_IsEditCancelled 3399
+#define wxTreeEvent_SetToolTip 3400
+#define wxNotebookEvent_GetOldSelection 3401
+#define wxNotebookEvent_GetSelection 3402
+#define wxNotebookEvent_SetOldSelection 3403
+#define wxNotebookEvent_SetSelection 3404
+#define wxFileDataObject_new 3405
+#define wxFileDataObject_AddFile 3406
+#define wxFileDataObject_GetFilenames 3407
+#define wxFileDataObject_destroy 3408
+#define wxTextDataObject_new 3409
+#define wxTextDataObject_GetTextLength 3410
+#define wxTextDataObject_GetText 3411
+#define wxTextDataObject_SetText 3412
+#define wxTextDataObject_destroy 3413
+#define wxBitmapDataObject_new_1_1 3414
+#define wxBitmapDataObject_new_1_0 3415
+#define wxBitmapDataObject_GetBitmap 3416
+#define wxBitmapDataObject_SetBitmap 3417
+#define wxBitmapDataObject_destroy 3418
+#define wxClipboard_new 3420
+#define wxClipboard_destruct 3421
+#define wxClipboard_AddData 3422
+#define wxClipboard_Clear 3423
+#define wxClipboard_Close 3424
+#define wxClipboard_Flush 3425
+#define wxClipboard_GetData 3426
+#define wxClipboard_IsOpened 3427
+#define wxClipboard_Open 3428
+#define wxClipboard_SetData 3429
+#define wxClipboard_UsePrimarySelection 3431
+#define wxClipboard_IsSupported 3432
+#define wxClipboard_Get 3433
+#define wxSpinEvent_GetPosition 3434
+#define wxSpinEvent_SetPosition 3435
+#define wxSplitterWindow_new_0 3436
+#define wxSplitterWindow_new_2 3437
+#define wxSplitterWindow_destruct 3438
+#define wxSplitterWindow_Create 3439
+#define wxSplitterWindow_GetMinimumPaneSize 3440
+#define wxSplitterWindow_GetSashGravity 3441
+#define wxSplitterWindow_GetSashPosition 3442
+#define wxSplitterWindow_GetSplitMode 3443
+#define wxSplitterWindow_GetWindow1 3444
+#define wxSplitterWindow_GetWindow2 3445
+#define wxSplitterWindow_Initialize 3446
+#define wxSplitterWindow_IsSplit 3447
+#define wxSplitterWindow_ReplaceWindow 3448
+#define wxSplitterWindow_SetSashGravity 3449
+#define wxSplitterWindow_SetSashPosition 3450
+#define wxSplitterWindow_SetSashSize 3451
+#define wxSplitterWindow_SetMinimumPaneSize 3452
+#define wxSplitterWindow_SetSplitMode 3453
+#define wxSplitterWindow_SplitHorizontally 3454
+#define wxSplitterWindow_SplitVertically 3455
+#define wxSplitterWindow_Unsplit 3456
+#define wxSplitterWindow_UpdateSize 3457
+#define wxSplitterEvent_GetSashPosition 3458
+#define wxSplitterEvent_GetX 3459
+#define wxSplitterEvent_GetY 3460
+#define wxSplitterEvent_GetWindowBeingRemoved 3461
+#define wxSplitterEvent_SetSashPosition 3462
+#define wxHtmlWindow_new_0 3463
+#define wxHtmlWindow_new_2 3464
+#define wxHtmlWindow_AppendToPage 3465
+#define wxHtmlWindow_GetOpenedAnchor 3466
+#define wxHtmlWindow_GetOpenedPage 3467
+#define wxHtmlWindow_GetOpenedPageTitle 3468
+#define wxHtmlWindow_GetRelatedFrame 3469
+#define wxHtmlWindow_HistoryBack 3470
+#define wxHtmlWindow_HistoryCanBack 3471
+#define wxHtmlWindow_HistoryCanForward 3472
+#define wxHtmlWindow_HistoryClear 3473
+#define wxHtmlWindow_HistoryForward 3474
+#define wxHtmlWindow_LoadFile 3475
+#define wxHtmlWindow_LoadPage 3476
+#define wxHtmlWindow_SelectAll 3477
+#define wxHtmlWindow_SelectionToText 3478
+#define wxHtmlWindow_SelectLine 3479
+#define wxHtmlWindow_SelectWord 3480
+#define wxHtmlWindow_SetBorders 3481
+#define wxHtmlWindow_SetFonts 3482
+#define wxHtmlWindow_SetPage 3483
+#define wxHtmlWindow_SetRelatedFrame 3484
+#define wxHtmlWindow_SetRelatedStatusBar 3485
+#define wxHtmlWindow_ToText 3486
+#define wxHtmlWindow_destroy 3487
+#define wxHtmlLinkEvent_GetLinkInfo 3488
+#define wxSystemSettings_GetColour 3489
+#define wxSystemSettings_GetFont 3490
+#define wxSystemSettings_GetMetric 3491
+#define wxSystemSettings_GetScreenType 3492
+#define wxSystemOptions_GetOption 3493
+#define wxSystemOptions_GetOptionInt 3494
+#define wxSystemOptions_HasOption 3495
+#define wxSystemOptions_IsFalse 3496
+#define wxSystemOptions_SetOption_2_1 3497
+#define wxSystemOptions_SetOption_2_0 3498
+#define wxAuiNotebookEvent_SetSelection 3499
+#define wxAuiNotebookEvent_GetSelection 3500
+#define wxAuiNotebookEvent_SetOldSelection 3501
+#define wxAuiNotebookEvent_GetOldSelection 3502
+#define wxAuiNotebookEvent_SetDragSource 3503
+#define wxAuiNotebookEvent_GetDragSource 3504
+#define wxAuiManagerEvent_SetManager 3505
+#define wxAuiManagerEvent_GetManager 3506
+#define wxAuiManagerEvent_SetPane 3507
+#define wxAuiManagerEvent_GetPane 3508
+#define wxAuiManagerEvent_SetButton 3509
+#define wxAuiManagerEvent_GetButton 3510
+#define wxAuiManagerEvent_SetDC 3511
+#define wxAuiManagerEvent_GetDC 3512
+#define wxAuiManagerEvent_Veto 3513
+#define wxAuiManagerEvent_GetVeto 3514
+#define wxAuiManagerEvent_SetCanVeto 3515
+#define wxAuiManagerEvent_CanVeto 3516
+#define wxLogNull_new 3517
+#define wxLogNull_destroy 3518
+#define wxTaskBarIcon_new 3519
+#define wxTaskBarIcon_destruct 3520
+#define wxTaskBarIcon_PopupMenu 3521
+#define wxTaskBarIcon_RemoveIcon 3522
+#define wxTaskBarIcon_SetIcon 3523
diff --git a/lib/wx/c_src/wxe_impl.cpp b/lib/wx/c_src/wxe_impl.cpp
index 69fcd4e362..527fabc315 100644
--- a/lib/wx/c_src/wxe_impl.cpp
+++ b/lib/wx/c_src/wxe_impl.cpp
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2008-2012. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -30,6 +30,11 @@
// Ok ugly but needed for wxBufferedDC crash workaround
#define private public
#include <wx/dcbuffer.h>
+
+#if defined(__WXMSW__)
+ #include <wx/msw/private.h> // for wxSetInstance
+#endif
+
#undef private
#include "wxe_impl.h"
@@ -222,6 +227,11 @@ void *wxe_main_loop(void *vpdl)
// This should be done in emulator but it's not in yet.
#ifndef _WIN32
erts_thread_disable_fpe();
+#else
+ // Setup that wxWidgets should look for cursors and icons in
+ // this dll and not in werl.exe (which is the default)
+ HMODULE WXEHandle = GetModuleHandle(_T("wxe_driver"));
+ wxSetInstance((HINSTANCE) WXEHandle);
#endif
result = wxEntry(argc, argv);
@@ -248,20 +258,30 @@ wxFrame * dummy_window;
void create_dummy_window() {
dummy_window = new wxFrame(NULL,-1, wxT("wx driver"),
- wxDefaultPosition, wxSize(5,5),
+ wxPoint(0,0), wxSize(5,5),
wxFRAME_NO_TASKBAR);
+
+ wxMenuBar * menubar = new wxMenuBar();
+ dummy_window->SetMenuBar(menubar);
+ // wx-2.9 Don't delete the app menubar correctly
dummy_window->Connect(wxID_ANY, wxEVT_CLOSE_WINDOW,
(wxObjectEventFunction) (wxEventFunction) &WxeApp::dummy_close);
+ dummy_window->Connect(wxID_ANY, wxEVT_COMMAND_MENU_SELECTED,
+ (wxObjectEventFunction) (wxEventFunction) &WxeApp::dummy_close);
+ dummy_window->Show(true);
+ // dummy_window->Show(false);
}
// wxMac really wants a top level window which command-q quits if there are no
// windows open, and this will kill the thread, so restart the dummy_window each
// time a we receive a close.
void WxeApp::dummy_close(wxEvent& Ev) {
- // fprintf(stderr, "Tried to close dummy window\r\n"); fflush(stderr);
- create_dummy_window();
+ if(Ev.GetEventType() == wxEVT_CLOSE_WINDOW) {
+ create_dummy_window();
+ }
}
+
// Init wx-widgets thread
bool WxeApp::OnInit()
{
@@ -272,7 +292,7 @@ bool WxeApp::OnInit()
wxe_batch_cb_saved = new wxList;
cb_buff = NULL;
- wxIdleEvent::SetMode(wxIDLE_PROCESS_SPECIFIED);
+ // wxIdleEvent::SetMode(wxIDLE_PROCESS_SPECIFIED); Hmm printpreview doesn't work in 2.9 with this
this->Connect(wxID_ANY, wxEVT_IDLE,
(wxObjectEventFunction) (wxEventFunction) &WxeApp::idle);
@@ -290,7 +310,11 @@ bool WxeApp::OnInit()
/* Create a dummy window so wxWidgets don't automagicly quits the main loop
after the last window */
+#ifdef __DARWIN__
create_dummy_window();
+#else
+ SetExitOnFrameDelete(false);
+#endif
init_nonconsts(global_me, init_caller);
erl_drv_mutex_lock(wxe_status_m);
@@ -301,7 +325,9 @@ bool WxeApp::OnInit()
}
void WxeApp::shutdown(wxeMetaCommand& Ecmd) {
+#ifdef __DARWIN__
delete dummy_window;
+#endif
ExitMainLoop();
}
diff --git a/lib/wx/c_src/wxe_ps_init.c b/lib/wx/c_src/wxe_ps_init.c
index a85f751024..025ea90f8b 100644
--- a/lib/wx/c_src/wxe_ps_init.c
+++ b/lib/wx/c_src/wxe_ps_init.c
@@ -25,12 +25,17 @@
#include <Cocoa/Cocoa.h>
#include <objc/objc-runtime.h>
+extern OSErr CPSSetProcessName (ProcessSerialNumber *psn, char *processname);
+
void * wxe_ps_init()
{
ProcessSerialNumber psn;
NSAutoreleasePool *pool;
// Enable GUI
GetCurrentProcess(&psn);
+ char *app_title = getenv("WX_APP_TITLE");
+ // Undocumented function (but no documented way of doing this exists)
+ CPSSetProcessName(&psn, app_title?app_title:"Erlang");
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
SetFrontProcess(&psn);
// Enable Cocoa calls from Carbon app
diff --git a/lib/wx/configure.in b/lib/wx/configure.in
index 7b35fed672..c45d2285af 100755
--- a/lib/wx/configure.in
+++ b/lib/wx/configure.in
@@ -80,20 +80,20 @@ fi
## Otherwise skip building wxErlang
AC_CHECK_SIZEOF(void *)
-case $ac_cv_sizeof_void_p-$host_os in
- 8-darwin*)
- if test X"$WX_BUILDING_INSIDE_ERLSRC" != X"true" ; then
- AC_MSG_ERROR([Can not use 64bits wxWidgets on Darwin])
- else
- echo "Can not combine 64bits erlang with wxWidgets on MacOSX, wx will not be useable" > ./CONF_INFO
- WXERL_CAN_BUILD_DRIVER=false
- AC_MSG_WARN([Can not combine 64bits erlang with wxWidgets on MacOSX, wx will not be useable])
- fi
- WXERL_CAN_BUILD_DRIVER=false
- ;;
- *)
- ;;
-esac
+# case $ac_cv_sizeof_void_p-$host_os in
+# 8-darwin*)
+# if test X"$WX_BUILDING_INSIDE_ERLSRC" != X"true" ; then
+# AC_MSG_ERROR([Can not use 64bits wxWidgets on Darwin])
+# else
+# echo "Can not combine 64bits erlang with wxWidgets on MacOSX, wx will not be useable" > ./CONF_INFO
+# WXERL_CAN_BUILD_DRIVER=false
+# AC_MSG_WARN([Can not combine 64bits erlang with wxWidgets on MacOSX, wx will not be useable])
+# fi
+# WXERL_CAN_BUILD_DRIVER=false
+# ;;
+# *)
+# ;;
+# esac
PTHR_CFLAGS="-D_THREAD_SAFE -D_REENTRANT"
@@ -155,7 +155,7 @@ case $host_os in
OBJC_CFLAGS="-ObjC"
fi
fi
- CFLAGS=$saved_CFLAGS
+ CFLAGS="$saved_CFLAGS -Wno-deprecated-declarations"
CPPFLAGS="$CPPFLAGS -D_MACOSX $PTHR_CFLAGS"
;;
mingw32)
@@ -169,6 +169,7 @@ case $host_os in
CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0500"
;;
*)
+ CFLAGS="$CFLAGS -Wno-deprecated-declarations"
CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE $PTHR_CFLAGS"
;;
esac
@@ -252,6 +253,18 @@ else
AC_CHECK_HEADERS([gl/gl.h],[],[],[#include <windows.h>])
fi
+if test X"$host_os" != X"win32" ; then
+ AC_CHECK_HEADERS([GL/glu.h], [],
+ [AC_CHECK_HEADERS([OpenGL/glu.h])])
+ if test X"$ac_cv_header_GL_glu_h" != Xyes &&
+ test X"$ac_cv_header_OpenGL_glu_h" != Xyes
+ then
+ AC_MSG_WARN([No GLU headers found, wx will NOT be usable])
+ fi
+else
+ AC_CHECK_HEADERS([gl/glu.h],[],[],[#include <windows.h>])
+fi
+
AC_SUBST(GL_LIBS)
CXXFLAGS="$CFLAGS $CPPFLAGS"
@@ -308,7 +321,15 @@ if test "$cross_compiling" = "yes"; then
echo "Cross compilation of the wx driver is not supported yet, wx will NOT be usable" > ./CONF_INFO
WXERL_CAN_BUILD_DRIVER=false
elif test X"$MIXED_CYGWIN_VC" == X"no" -a X"$MIXED_MSYS_VC" == X"no"; then
- m4_include(wxwin.m4)
+ WX_VERSION=`wx-config --version`
+ case $WX_VERSION in
+ 2.8.*)
+ m4_include(wxwin-2.8.m4)
+ ;;
+ *)
+ m4_include(wxwin-2.9.m4)
+ ;;
+ esac
AM_OPTIONS_WXCONFIG
reqwx=2.8.4
@@ -395,12 +416,12 @@ else
else
CWXWIN_PROG=`cygpath -d "$PROGRAMFILES" | cygpath -f - 2>/dev/null`
fi
- CWXWIN3=$CWXWIN_PROG/wxWidgets-2.8
- CWXWIN4=$CWXWIN_PROG/wxMSW-2.8
- CWX_DOCUMENTED="/opt/local/pgm/wxMSW-2.8.* /opt/local/pgm/wxWidgets-2.8.*"
+ CWXWIN3=$CWXWIN_PROG/wxWidgets-2.*.*
+ CWXWIN4=$CWXWIN_PROG/wxMSW-2.*.*
+ CWX_DOCUMENTED="/opt/local/pgm/wxMSW-2.*.* /opt/local/pgm/wxWidgets-2.*.*"
case $ac_cv_sizeof_void_p in
8)
- CWX_DOCUMENTED="/opt/local64/pgm/wxMSW-2.8.* /opt/local64/pgm/wxWidgets-2.8.* $CWX_DOCUMENTED"
+ CWX_DOCUMENTED="/opt/local64/pgm/wxMSW-2.*.* /opt/local64/pgm/wxWidgets-2.*.* $CWX_DOCUMENTED"
;;
*)
true
@@ -442,6 +463,7 @@ else
fi
fi
done
+
if test -z "$WX_LIBS_STATIC"; then
AC_MSG_RESULT([failed])
if test X"$WX_BUILDING_INSIDE_ERLSRC" != X"true" ; then
@@ -621,6 +643,12 @@ fi dnl - if test "$WXERL_CAN_BUILD_DRIVER" != "false"
AC_SUBST(WXERL_CAN_BUILD_DRIVER)
+if test "x$GCC" = xyes; then
+ # Treat certain GCC warnings as errors
+ LM_TRY_ENABLE_CFLAG([-Werror=return-type], [CFLAGS])
+ LM_TRY_ENABLE_CFLAG([-Werror=return-type], [CXXFLAGS])
+fi
+
#############################################################################
dnl
diff --git a/lib/wx/examples/demo/demo.erl b/lib/wx/examples/demo/demo.erl
index 61e71af021..2f560096f5 100644
--- a/lib/wx/examples/demo/demo.erl
+++ b/lib/wx/examples/demo/demo.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -32,6 +32,21 @@
-record(state, {win, demo, example, selector, log, code}).
+%% For wx-2.9 usage
+-ifndef(wxSTC_ERLANG_COMMENT_FUNCTION).
+-define(wxSTC_ERLANG_COMMENT_FUNCTION, 14).
+-define(wxSTC_ERLANG_COMMENT_MODULE, 15).
+-define(wxSTC_ERLANG_COMMENT_DOC, 16).
+-define(wxSTC_ERLANG_COMMENT_DOC_MACRO, 17).
+-define(wxSTC_ERLANG_ATOM_QUOTED, 18).
+-define(wxSTC_ERLANG_MACRO_QUOTED, 19).
+-define(wxSTC_ERLANG_RECORD_QUOTED, 20).
+-define(wxSTC_ERLANG_NODE_NAME_QUOTED, 21).
+-define(wxSTC_ERLANG_BIFS, 22).
+-define(wxSTC_ERLANG_MODULES, 23).
+-define(wxSTC_ERLANG_MODULES_ATT, 24).
+-endif.
+
start() ->
start([]).
@@ -78,6 +93,7 @@ init(Options) ->
wxFrame:setMenuBar(Frame,MB),
wxFrame:connect(Frame, command_menu_selected),
+ wxFrame:connect(Frame, close_window),
_SB = wxFrame:createStatusBar(Frame,[]),
@@ -179,6 +195,8 @@ create_subwindow(Parent, BoxLabel, Funs) ->
%% Handled as in normal gen_server callbacks
handle_info({'EXIT',_, wx_deleted}, State) ->
{noreply,State};
+handle_info({'EXIT',_, shutdown}, State) ->
+ {noreply,State};
handle_info({'EXIT',_, normal}, State) ->
{noreply,State};
handle_info(Msg, State) ->
@@ -197,13 +215,13 @@ handle_cast(Msg, State) ->
handle_event(#wx{event=#wxCommand{type=command_listbox_selected, cmdString=Ex}},
State = #state{demo={_,DemoSz}, example=Example, code=Code}) ->
case Ex of
- [] ->
+ [] ->
{noreply, State};
_ ->
wxSizer:detach(DemoSz, Example),
- wxWindow:destroy(Example),
+ wx_object:call(Example, shutdown),
unload_code(Code),
- NewExample = load_example(Ex, State),
+ NewExample = load_example(Ex, State),
wxSizer:add(DemoSz, NewExample, [{proportion,1}, {flag, ?wxEXPAND}]),
wxSizer:layout(DemoSz),
{noreply, State#state{example=NewExample}}
@@ -247,9 +265,9 @@ handle_event(#wx{id = Id,
?wxICON_INFORMATION bor
?wxSTAY_ON_TOP},
{caption, "About"}])),
- {noreply, State};
+ {noreply, State};
?wxID_EXIT ->
- wx_object:get_pid(State#state.example) ! stop,
+ wx_object:call(State#state.example, shutdown),
{stop, normal, State};
_ ->
{noreply, State}
@@ -265,9 +283,9 @@ handle_event(Ev,State) ->
code_change(_, _, State) ->
{stop, not_yet_implemented, State}.
-terminate(_Reason, State) ->
- wx_object:get_pid(State#state.example) ! stop,
- timer:sleep(200), %% Give the example process some time to cleanup.
+terminate(_Reason, State = #state{win=Frame}) ->
+ catch wx_object:call(State#state.example, shutdown),
+ wxFrame:destroy(Frame),
wx:destroy().
%%%%%%%%%%%%%%%%% Internals %%%%%%%%%%
@@ -275,8 +293,6 @@ terminate(_Reason, State) ->
load_example(Ex, #state{demo={DemoPanel,DemoSz}, log=EvCtrl, code=Code}) ->
ModStr = "ex_" ++ Ex,
Mod = list_to_atom(ModStr),
-%% WxDir = code:lib_dir(wx),
-%% ModFile = filename:join([WxDir, "examples","demo", ModStr ++ ".erl"]),
ModFile = ModStr ++ ".erl",
load_code(Code, file:read_file(ModFile)),
find(Code),
@@ -312,7 +328,20 @@ code_area(Parent) ->
{?wxSTC_ERLANG_MACRO, {40,144,170}},
{?wxSTC_ERLANG_RECORD, {40,100,20}},
{?wxSTC_ERLANG_SEPARATOR,{0,0,0}},
- {?wxSTC_ERLANG_NODE_NAME,{0,0,0}}],
+ {?wxSTC_ERLANG_NODE_NAME,{0,0,0}},
+ %% Optional 2.9 stuff
+ {?wxSTC_ERLANG_COMMENT_FUNCTION, {160,53,35}},
+ {?wxSTC_ERLANG_COMMENT_MODULE, {160,53,35}},
+ {?wxSTC_ERLANG_COMMENT_DOC, {160,53,35}},
+ {?wxSTC_ERLANG_COMMENT_DOC_MACRO, {160,53,35}},
+ {?wxSTC_ERLANG_ATOM_QUOTED, {0,0,0}},
+ {?wxSTC_ERLANG_MACRO_QUOTED, {40,144,170}},
+ {?wxSTC_ERLANG_RECORD_QUOTED, {40,100,20}},
+ {?wxSTC_ERLANG_NODE_NAME_QUOTED, {0,0,0}},
+ {?wxSTC_ERLANG_BIFS, {130,40,172}},
+ {?wxSTC_ERLANG_MODULES, {64,102,244}},
+ {?wxSTC_ERLANG_MODULES_ATT, {64,102,244}}
+ ],
SetStyle = fun({Style, Color}) ->
?stc:styleSetFont(Ed, Style, FixedFont),
?stc:styleSetForeground(Ed, Style, Color)
diff --git a/lib/wx/examples/demo/ex_aui.erl b/lib/wx/examples/demo/ex_aui.erl
index 50f077638d..70372caad8 100644
--- a/lib/wx/examples/demo/ex_aui.erl
+++ b/lib/wx/examples/demo/ex_aui.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -32,7 +32,8 @@
-record(state,
{
parent,
- config
+ config,
+ aui
}).
start(Config) ->
@@ -47,12 +48,10 @@ init(Config) ->
do_init(Config) ->
Parent = proplists:get_value(parent, Config),
Panel = wxPanel:new(Parent, []),
-
%% Setup sizers
MainSizer = wxBoxSizer:new(?wxVERTICAL),
- Manager = wxAuiManager:new([{managed_wnd, Panel}
- ]),
+ Manager = wxAuiManager:new([{managed_wnd, Panel}]),
Pane = ?pi:new(),
?pi:closeButton(Pane),
@@ -79,8 +78,8 @@ do_init(Config) ->
wxAuiManager:connect(Manager, aui_pane_button, [{skip,true}]),
wxAuiManager:connect(Manager, aui_pane_maximize, [{skip,true}]),
wxAuiManager:update(Manager),
-
- {Panel, #state{parent=Panel, config=Config}}.
+ process_flag(trap_exit, true),
+ {Panel, #state{parent=Panel, config=Config, aui=Manager}}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Callbacks handled as normal gen_server callbacks
@@ -88,6 +87,12 @@ handle_info(Msg, State) ->
demo:format(State#state.config, "Got Info ~p\n", [Msg]),
{noreply, State}.
+handle_call(shutdown, _From, State=#state{parent=Panel, aui=Manager}) ->
+ wxAuiManager:unInit(Manager),
+ wxAuiManager:destroy(Manager),
+ wxPanel:destroy(Panel),
+ {stop, normal, ok, State};
+
handle_call(Msg, _From, State) ->
demo:format(State#state.config, "Got Call ~p\n", [Msg]),
{reply,{error, nyi}, State}.
@@ -134,11 +139,10 @@ handle_event(Ev = #wx{}, State) ->
io:format("~p\n", [Ev]),
{noreply, State}.
-
code_change(_, _, State) ->
{stop, ignore, State}.
-terminate(_Reason, _State) ->
+terminate(_Reason, _) ->
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/wx/examples/demo/ex_button.erl b/lib/wx/examples/demo/ex_button.erl
index 0dd0363933..41bf34e572 100644
--- a/lib/wx/examples/demo/ex_button.erl
+++ b/lib/wx/examples/demo/ex_button.erl
@@ -25,7 +25,8 @@
-include_lib("wx/include/wx.hrl").
-behaviour(wx_object).
--export([start/1, init/1, terminate/2, code_change/3,
+-export([start/1, init/1,
+ terminate/2, code_change/3,
handle_info/2, handle_call/3, handle_cast/2, handle_event/2]).
-record(state,
@@ -120,6 +121,7 @@ do_init(Config) ->
wxWindow:connect(Panel, command_button_clicked),
wxWindow:setSizer(Panel, Sz),
wxSizer:layout(Sz),
+ wxWindow:refresh(Panel),
wxScrolledWindow:setScrollRate(Panel, 5, 5),
{Panel, #state{parent=Panel, config=Config}}.
@@ -149,6 +151,10 @@ handle_info(Msg, State) ->
demo:format(State#state.config, "Got Info ~p~n",[Msg]),
{noreply,State}.
+handle_call(shutdown, _From, State=#state{parent=Panel}) ->
+ wxPanel:destroy(Panel),
+ {stop, normal, ok, State};
+
handle_call(Msg, _From, State) ->
demo:format(State#state.config,"Got Call ~p~n",[Msg]),
{reply,ok,State}.
@@ -160,7 +166,7 @@ handle_cast(Msg, State) ->
code_change(_, _, State) ->
{stop, ignore, State}.
-terminate(_Reason, _State) ->
+terminate(_Reason, _) ->
ok.
%%%%% a copy from wxwidgets samples.
diff --git a/lib/wx/examples/demo/ex_canvas.erl b/lib/wx/examples/demo/ex_canvas.erl
index 1ec4760f40..1f1d260276 100644
--- a/lib/wx/examples/demo/ex_canvas.erl
+++ b/lib/wx/examples/demo/ex_canvas.erl
@@ -140,6 +140,9 @@ handle_info(Msg, State) ->
demo:format(State#state.config, "Got Info ~p\n", [Msg]),
{noreply, State}.
+handle_call(shutdown, _From, State=#state{parent=Panel}) ->
+ wxPanel:destroy(Panel),
+ {stop, normal, ok, State};
handle_call(Msg, _From, State) ->
demo:format(State#state.config, "Got Call ~p\n", [Msg]),
{reply,{error, nyi}, State}.
@@ -151,7 +154,7 @@ handle_cast(Msg, State) ->
code_change(_, _, State) ->
{stop, ignore, State}.
-terminate(_Reason, _State) ->
+terminate(_Reason, _) ->
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/wx/examples/demo/ex_canvas_paint.erl b/lib/wx/examples/demo/ex_canvas_paint.erl
index 9bc083766a..6873724655 100644
--- a/lib/wx/examples/demo/ex_canvas_paint.erl
+++ b/lib/wx/examples/demo/ex_canvas_paint.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -207,6 +207,10 @@ handle_info(Msg, State) ->
demo:format(State#state.config, "Got Info ~p\n", [Msg]),
{noreply, State}.
+handle_call(shutdown, _From, State=#state{parent=Panel}) ->
+ wxPanel:destroy(Panel),
+ {stop, normal, ok, State};
+
handle_call(Msg, _From, State) ->
demo:format(State#state.config, "Got Call ~p\n", [Msg]),
{reply,{error, nyi}, State}.
@@ -218,7 +222,7 @@ handle_cast(Msg, State) ->
code_change(_, _, State) ->
{stop, ignore, State}.
-terminate(_Reason, _State) ->
+terminate(_Reason, _) ->
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -239,14 +243,17 @@ draw(Canvas, Bitmap, Fun) ->
wxMemoryDC:destroy(MemoryDC).
redraw(DC, Bitmap) ->
- MemoryDC = wxMemoryDC:new(Bitmap),
+ try
+ MemoryDC = wxMemoryDC:new(Bitmap),
- wxDC:blit(DC, {0,0},
- {wxBitmap:getWidth(Bitmap), wxBitmap:getHeight(Bitmap)},
- MemoryDC, {0,0}),
-
- wxMemoryDC:destroy(MemoryDC).
+ wxDC:blit(DC, {0,0},
+ {wxBitmap:getWidth(Bitmap), wxBitmap:getHeight(Bitmap)},
+ MemoryDC, {0,0}),
+ wxMemoryDC:destroy(MemoryDC)
+ catch error:{{badarg,_},_} -> %% Bitmap have been deleted
+ ok
+ end.
-getPageInfo(_This) ->
+getPageInfo(_This) ->
{1,1,1,1}.
diff --git a/lib/wx/examples/demo/ex_choices.erl b/lib/wx/examples/demo/ex_choices.erl
index 2e456ae249..b4418293c1 100644
--- a/lib/wx/examples/demo/ex_choices.erl
+++ b/lib/wx/examples/demo/ex_choices.erl
@@ -143,6 +143,10 @@ handle_info(Msg, State) ->
demo:format(State#state.config, "Got Info ~p\n",[Msg]),
{noreply, State}.
+handle_call(shutdown, _From, State=#state{parent=Panel}) ->
+ wxPanel:destroy(Panel),
+ {stop, normal, ok, State};
+
handle_call(Msg, _From, State) ->
demo:format(State#state.config,"Got Call ~p\n",[Msg]),
{reply, {error,nyi}, State}.
@@ -154,7 +158,7 @@ handle_cast(Msg, State) ->
code_change(_, _, State) ->
{stop, ignore, State}.
-terminate(_Reason, _State) ->
+terminate(_Reason, _) ->
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/wx/examples/demo/ex_cursor.erl b/lib/wx/examples/demo/ex_cursor.erl
index c1a558541b..2f1eaaf7c7 100644
--- a/lib/wx/examples/demo/ex_cursor.erl
+++ b/lib/wx/examples/demo/ex_cursor.erl
@@ -131,6 +131,10 @@ handle_info(Msg, State) ->
demo:format(State#state.config, "Got Info ~p\n", [Msg]),
{noreply, State}.
+handle_call(shutdown, _From, State=#state{parent=Panel}) ->
+ wxPanel:destroy(Panel),
+ {stop, normal, ok, State};
+
handle_call(Msg, _From, State) ->
demo:format(State#state.config, "Got Call ~p\n", [Msg]),
{reply,{error, nyi}, State}.
diff --git a/lib/wx/examples/demo/ex_dialogs.erl b/lib/wx/examples/demo/ex_dialogs.erl
index b39344f8b1..5c47b51271 100644
--- a/lib/wx/examples/demo/ex_dialogs.erl
+++ b/lib/wx/examples/demo/ex_dialogs.erl
@@ -149,6 +149,10 @@ handle_info(Msg, State) ->
demo:format(State#state.config, "Got Info ~p\n", [Msg]),
{noreply, State}.
+handle_call(shutdown, _From, State=#state{parent=Panel}) ->
+ wxPanel:destroy(Panel),
+ {stop, normal, ok, State};
+
handle_call(Msg, _From, State) ->
demo:format(State#state.config, "Got Call ~p\n", [Msg]),
{reply,{error, nyi}, State}.
diff --git a/lib/wx/examples/demo/ex_frame_utils.erl b/lib/wx/examples/demo/ex_frame_utils.erl
index a90642b355..4a59bb3a68 100644
--- a/lib/wx/examples/demo/ex_frame_utils.erl
+++ b/lib/wx/examples/demo/ex_frame_utils.erl
@@ -98,6 +98,10 @@ handle_info(Msg, State) ->
demo:format(State#state.config, "Got Info ~p\n", [Msg]),
{noreply, State}.
+handle_call(shutdown, _From, State=#state{parent=Panel}) ->
+ wxPanel:destroy(Panel),
+ {stop, normal, ok, State};
+
handle_call(Msg, _From, State) ->
demo:format(State#state.config, "Got Call ~p\n", [Msg]),
{reply,{error, nyi}, State}.
diff --git a/lib/wx/examples/demo/ex_gauge.erl b/lib/wx/examples/demo/ex_gauge.erl
index ffc667ff05..c53dfb807b 100644
--- a/lib/wx/examples/demo/ex_gauge.erl
+++ b/lib/wx/examples/demo/ex_gauge.erl
@@ -114,6 +114,10 @@ handle_info(pulse, State=#state{undeterminate_gauge = Gauge=#gauge{obj = Obj}})
Timer = erlang:send_after(300, self(), pulse),
{noreply, State#state{undeterminate_gauge = Gauge#gauge{timer = Timer}}}.
+handle_call(shutdown, _From, State=#state{parent=Panel}) ->
+ wxPanel:destroy(Panel),
+ {stop, normal, ok, State};
+
handle_call(Msg, _From, State) ->
demo:format(State#state.config,"Got Call ~p\n",[Msg]),
{reply,ok, State}.
diff --git a/lib/wx/examples/demo/ex_gl.erl b/lib/wx/examples/demo/ex_gl.erl
index 72dad2cf9d..6bb2d12dff 100644
--- a/lib/wx/examples/demo/ex_gl.erl
+++ b/lib/wx/examples/demo/ex_gl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -20,7 +20,8 @@
-behaviour(wx_object).
--export([init/1, code_change/3, handle_info/2, handle_event/2,
+-export([init/1, code_change/3, handle_info/2,
+ handle_sync_event/3, handle_event/2,
handle_call/3, handle_cast/2, terminate/2,
start/1]).
@@ -34,6 +35,7 @@
config,
gl,
canvas,
+ image,
timer,
time
}).
@@ -58,7 +60,7 @@ do_init(Config) ->
%% Setup sizer
Sizer = wxStaticBoxSizer:new(?wxHORIZONTAL, Panel, [{label, "wxGLCanvas"}]),
- Opts = [{size, {300,300}}, {style, ?wxSUNKEN_BORDER}],
+ Opts = [{style, ?wxFULL_REPAINT_ON_RESIZE}],
GLAttrib = [{attribList, [?WX_GL_RGBA,
?WX_GL_DOUBLEBUFFER,
?WX_GL_MIN_RED,8,
@@ -67,34 +69,48 @@ do_init(Config) ->
?WX_GL_DEPTH_SIZE,24,0]}],
Canvas = wxGLCanvas:new(Panel,Opts ++ GLAttrib),
wxGLCanvas:connect(Canvas, size),
+ wxGLCanvas:connect(Canvas, paint, [callback]),
- wxGLCanvas:setCurrent(Canvas),
Image = wxImage:scale(wxImage:new("image.jpg"), 128,128),
- GL = setup_gl(Canvas,Image),
- Timer = timer:send_interval(20, self(), update),
%% Add to sizers
wxSizer:add(Sizer, Canvas, [{flag, ?wxEXPAND},{proportion, 1}]),
wxWindow:setSizer(Panel,Sizer),
wxSizer:layout(Sizer),
+ Timer = timer:send_interval(20, self(), update),
{Panel, #state{parent = Panel, config = Config,
- canvas = Canvas,
- gl = GL, timer = Timer}}.
+ canvas = Canvas, image=Image,
+ timer = Timer}}.
%% Event handling
-handle_event(#wx{event = #wxSize{size = {W,H}}}, State) ->
- case W =:= 0 orelse H =:= 0 of
- true -> skip;
- _ ->
+handle_sync_event(_PaintEvent, _, #state{canvas=Canvas}) ->
+ %% Sync events are called from a temporary process,
+ %% we need to setup the gl canvas on cocoa for some reason
+ %% We do not really have to do anything, the timer event will refresh the painting
+ wxGLCanvas:setCurrent(Canvas),
+ DC= wxPaintDC:new(Canvas),
+ wxPaintDC:destroy(DC),
+ ok.
+
+handle_event(#wx{event = #wxSize{size = {W,H}}}, State = #state{gl=GL}) ->
+ if
+ GL =:= undefined ->
+ #state{canvas=Canvas, image=Image} = State,
+ wxGLCanvas:setCurrent(Canvas),
+ {noreply, State#state{gl=setup_gl(Canvas,Image)}};
+ W =:= 0, H =:= 0 -> {noreply, State};
+ true ->
gl:viewport(0,0,W,H),
gl:matrixMode(?GL_PROJECTION),
gl:loadIdentity(),
gl:ortho( -2.0, 2.0, -2.0*H/W, 2.0*H/W, -20.0, 20.0),
gl:matrixMode(?GL_MODELVIEW),
- gl:loadIdentity()
- end,
- {noreply, State}.
+ gl:loadIdentity(),
+ {noreply, State}
+ end.
+handle_info(update, State=#state{gl=undefined}) ->
+ {noreply, State};
handle_info(update, State) ->
S1 = update_rotation(State),
GL = S1#state.gl,
@@ -113,7 +129,13 @@ handle_info(stop, State) ->
timer:cancel(State#state.timer),
catch wxGLCanvas:destroy(State#state.canvas),
{stop, normal, State}.
-
+
+handle_call(shutdown, _From, State=#state{parent=Panel}) ->
+ catch wxGLCanvas:destroy(State#state.canvas),
+ timer:cancel(State#state.timer),
+ wxPanel:destroy(Panel),
+ {stop, normal, ok, State};
+
handle_call(Msg, _From, State) ->
io:format("Got Call ~p~n",[Msg]),
{reply,ok,State}.
@@ -125,11 +147,8 @@ handle_cast(Msg, State) ->
code_change(_, _, State) ->
{stop, not_yet_implemented, State}.
-terminate(_Reason, State) ->
- catch wxGLCanvas:destroy(State#state.canvas),
- timer:cancel(State#state.timer),
- timer:sleep(300).
-
+terminate(_Reason, _State) ->
+ ok.
-define(VS, {{-0.5, -0.5, -0.5}, %1
diff --git a/lib/wx/examples/demo/ex_graphicsContext.erl b/lib/wx/examples/demo/ex_graphicsContext.erl
index c356500d99..59bfe7ff64 100644
--- a/lib/wx/examples/demo/ex_graphicsContext.erl
+++ b/lib/wx/examples/demo/ex_graphicsContext.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -25,8 +25,8 @@
%% wx_object callbacks
-export([init/1, terminate/2, code_change/3,
- handle_info/2, handle_call/3,
-handle_cast/2, handle_event/2, handle_sync_event/3]).
+ handle_info/2, handle_call/3,handle_cast/2,
+ handle_event/2, handle_sync_event/3]).
-include_lib("wx/include/wx.hrl").
@@ -57,11 +57,9 @@ do_init(Config) ->
[{label, "wxGrapicsContext"}]),
Win = wxPanel:new(Panel, []),
- Pen = wxPen:new(),
- Brush = wxBrush:new(?wxBLACK),
- Font = wxFont:new(),
- wxFont:setWeight(Font, ?wxBOLD),
-
+ Pen = ?wxBLACK_PEN,
+ Brush = wxBrush:new({30, 175, 23, 127}),
+ Font = ?wxITALIC_FONT,
wxPanel:connect(Win, paint, [callback]),
%% Add to sizers
@@ -94,6 +92,10 @@ handle_info(Msg, State) ->
demo:format(State#state.config, "Got Info ~p\n", [Msg]),
{noreply, State}.
+handle_call(shutdown, _From, State=#state{parent=Panel}) ->
+ wxPanel:destroy(Panel),
+ {stop, normal, ok, State};
+
handle_call(Msg, _From, State) ->
demo:format(State#state.config, "Got Call ~p\n", [Msg]),
{reply,{error, nyi}, State}.
@@ -112,36 +114,26 @@ terminate(_Reason, _State) ->
%% Local functions
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-draw(Win, Pen0, _Brush0, Font0) ->
+draw(Win, Pen, Brush, Font) ->
try
Canvas = wxGraphicsContext:create(Win),
- Pen = wxGraphicsContext:createPen(Canvas, Pen0),
wxGraphicsContext:setPen(Canvas, Pen),
- Brush = wxGraphicsContext:createLinearGradientBrush(Canvas, 0.0,0.0, 30.0,30.0,
- {200,50,50,50},
- {200,50,50,200}),
wxGraphicsContext:setBrush(Canvas, Brush),
- Font = wxGraphicsContext:createFont(Canvas, Font0),
- wxGraphicsContext:setFont(Canvas, Font),
+ wxGraphicsContext:setFont(Canvas, Font, {0, 0, 50}),
wxGraphicsContext:drawRoundedRectangle(Canvas, 35.0,35.0, 100.0, 50.0, 10.0),
- wxGraphicsContext:drawText(Canvas, "Welcome", 60.0, 55.0),
+ wxGraphicsContext:drawText(Canvas, "This text should be antialised", 60.0, 55.0),
Path = wxGraphicsContext:createPath(Canvas),
wxGraphicsPath:addCircle(Path, 0.0, 0.0, 40.0),
wxGraphicsPath:closeSubpath(Path),
- wxGraphicsContext:translate(Canvas, 100.0, 100.0),
-
- Brush2 = wxGraphicsContext:createLinearGradientBrush(Canvas, 0.0,0.0, 30.0,30.0,
- {50,200,50,50},
- {50,50,200,50}),
- wxGraphicsContext:setBrush(Canvas, Brush2),
+ wxGraphicsContext:translate(Canvas, 100.0, 250.0),
- F = fun(_) ->
+ F = fun(N) ->
wxGraphicsContext:scale(Canvas, 1.1, 1.1),
- wxGraphicsContext:translate(Canvas, 3.0,3.0),
+ wxGraphicsContext:translate(Canvas, 15.0,-1.0*N),
wxGraphicsContext:drawPath(Canvas, Path)
end,
- wx:foreach(F, lists:seq(1,5)),
+ wx:foreach(F, lists:seq(1,10)),
ok
catch _:{not_supported, _} ->
Err = "wxGraphicsContext not available in this build of wxwidgets",
diff --git a/lib/wx/examples/demo/ex_grid.erl b/lib/wx/examples/demo/ex_grid.erl
index d1a9952ab2..e284836d5b 100644
--- a/lib/wx/examples/demo/ex_grid.erl
+++ b/lib/wx/examples/demo/ex_grid.erl
@@ -78,6 +78,10 @@ handle_event(#wx{event = #wxGrid{type = grid_cell_change,
handle_info(_Msg, State) ->
{noreply, State}.
+handle_call(shutdown, _From, State=#state{parent=Panel}) ->
+ wxPanel:destroy(Panel),
+ {stop, normal, ok, State};
+
handle_call(_Msg, _From, State) ->
{reply,{error, nyi}, State}.
diff --git a/lib/wx/examples/demo/ex_htmlWindow.erl b/lib/wx/examples/demo/ex_htmlWindow.erl
index 564c790e48..af3d4c71f5 100644
--- a/lib/wx/examples/demo/ex_htmlWindow.erl
+++ b/lib/wx/examples/demo/ex_htmlWindow.erl
@@ -77,6 +77,10 @@ handle_info(Msg, State) ->
demo:format(State#state.config, "Got Info ~p\n", [Msg]),
{noreply, State}.
+handle_call(shutdown, _From, State=#state{parent=Panel}) ->
+ wxPanel:destroy(Panel),
+ {stop, normal, ok, State};
+
handle_call(Msg, _From, State) ->
demo:format(State#state.config, "Got Call ~p\n", [Msg]),
{reply,{error, nyi}, State}.
diff --git a/lib/wx/examples/demo/ex_listCtrl.erl b/lib/wx/examples/demo/ex_listCtrl.erl
index 13096dfa52..2c62ac9d5f 100644
--- a/lib/wx/examples/demo/ex_listCtrl.erl
+++ b/lib/wx/examples/demo/ex_listCtrl.erl
@@ -58,8 +58,8 @@ do_init(Config) ->
IL = wxImageList:new(16,16),
wxImageList:add(IL, wxArtProvider:getBitmap("wxART_COPY", [{size, {16,16}}])),
wxImageList:add(IL, wxArtProvider:getBitmap("wxART_MISSING_IMAGE", [{size, {16,16}}])),
- wxImageList:add(IL, wxArtProvider:getBitmap("wxART_TICK_MARK", [{size, {16,16}}])),
- wxImageList:add(IL, wxArtProvider:getBitmap("wxART_CROSS_MARK", [{size, {16,16}}])),
+ wxImageList:add(IL, wxArtProvider:getBitmap("wxART_QUESTION", [{size, {16,16}}])),
+ wxImageList:add(IL, wxArtProvider:getBitmap("wxART_WARNING", [{size, {16,16}}])),
wxListCtrl:assignImageList(ListCtrl2, IL, ?wxIMAGE_LIST_SMALL),
Fun =
fun(Item) ->
@@ -143,6 +143,10 @@ handle_info(Msg, State) ->
demo:format(State#state.config, "Got Info ~p\n",[Msg]),
{noreply,State}.
+handle_call(shutdown, _From, State=#state{parent=Panel}) ->
+ wxPanel:destroy(Panel),
+ {stop, normal, ok, State};
+
handle_call(Msg, _From, State) ->
demo:format(State#state.config,"Got Call ~p\n",[Msg]),
{reply,ok,State}.
diff --git a/lib/wx/examples/demo/ex_notebook.erl b/lib/wx/examples/demo/ex_notebook.erl
index fc38fdae08..5edcc65082 100644
--- a/lib/wx/examples/demo/ex_notebook.erl
+++ b/lib/wx/examples/demo/ex_notebook.erl
@@ -129,6 +129,10 @@ handle_info(Msg, State) ->
demo:format(State#state.config, "Got Info ~p\n",[Msg]),
{noreply,State}.
+handle_call(shutdown, _From, State=#state{parent=Panel}) ->
+ wxPanel:destroy(Panel),
+ {stop, normal, ok, State};
+
handle_call(Msg, _From, State) ->
demo:format(State#state.config,"Got Call ~p\n",[Msg]),
{reply,ok,State}.
diff --git a/lib/wx/examples/demo/ex_pickers.erl b/lib/wx/examples/demo/ex_pickers.erl
index 8013a5ba32..54f8c7a8e5 100644
--- a/lib/wx/examples/demo/ex_pickers.erl
+++ b/lib/wx/examples/demo/ex_pickers.erl
@@ -120,6 +120,10 @@ handle_info(Msg, State) ->
demo:format(State#state.config, "Got Info ~p\n", [Msg]),
{noreply, State}.
+handle_call(shutdown, _From, State=#state{parent=Panel}) ->
+ wxPanel:destroy(Panel),
+ {stop, normal, ok, State};
+
handle_call(Msg, _From, State) ->
demo:format(State#state.config, "Got Call ~p\n", [Msg]),
{reply,{error, nyi}, State}.
diff --git a/lib/wx/examples/demo/ex_popupMenu.erl b/lib/wx/examples/demo/ex_popupMenu.erl
index d6778c5dc5..f48b00963d 100644
--- a/lib/wx/examples/demo/ex_popupMenu.erl
+++ b/lib/wx/examples/demo/ex_popupMenu.erl
@@ -86,6 +86,10 @@ handle_info(Msg, State) ->
demo:format(State#state.config, "Got Info ~p\n", [Msg]),
{noreply, State}.
+handle_call(shutdown, _From, State=#state{parent=Panel}) ->
+ wxPanel:destroy(Panel),
+ {stop, normal, ok, State};
+
handle_call(Msg, _From, State) ->
demo:format(State#state.config, "Got Call ~p\n", [Msg]),
{reply,{error, nyi}, State}.
diff --git a/lib/wx/examples/demo/ex_radioBox.erl b/lib/wx/examples/demo/ex_radioBox.erl
index ab7685f41f..17a11d1054 100644
--- a/lib/wx/examples/demo/ex_radioBox.erl
+++ b/lib/wx/examples/demo/ex_radioBox.erl
@@ -103,6 +103,10 @@ handle_info(Msg, State) ->
demo:format(State#state.config, "Got Info ~p\n",[Msg]),
{noreply, State}.
+handle_call(shutdown, _From, State=#state{parent=Panel}) ->
+ wxPanel:destroy(Panel),
+ {stop, normal, ok, State};
+
handle_call(Msg, _From, State) ->
demo:format(State#state.config,"Got Call ~p\n",[Msg]),
{reply, {error, nyi}, State}.
diff --git a/lib/wx/examples/demo/ex_sashWindow.erl b/lib/wx/examples/demo/ex_sashWindow.erl
index d8a8958f28..9eb3b9b27e 100644
--- a/lib/wx/examples/demo/ex_sashWindow.erl
+++ b/lib/wx/examples/demo/ex_sashWindow.erl
@@ -112,6 +112,10 @@ handle_info(Msg, State) ->
demo:format(State#state.config, "Got Info ~p\n", [Msg]),
{noreply, State}.
+handle_call(shutdown, _From, State=#state{parent=Panel}) ->
+ wxPanel:destroy(Panel),
+ {stop, normal, ok, State};
+
handle_call(Msg, _From, State) ->
demo:format(State#state.config, "Got Call ~p\n", [Msg]),
{reply,{error, nyi}, State}.
diff --git a/lib/wx/examples/demo/ex_sizers.erl b/lib/wx/examples/demo/ex_sizers.erl
index 7b9e8eb37f..ecd539cd62 100644
--- a/lib/wx/examples/demo/ex_sizers.erl
+++ b/lib/wx/examples/demo/ex_sizers.erl
@@ -97,6 +97,10 @@ handle_info(Msg, State) ->
demo:format(State#state.config, "Got Info ~p\n", [Msg]),
{noreply, State}.
+handle_call(shutdown, _From, State=#state{parent=Panel}) ->
+ wxPanel:destroy(Panel),
+ {stop, normal, ok, State};
+
handle_call(Msg, _From, State) ->
demo:format(State#state.config, "Got Call ~p\n", [Msg]),
{reply,{error, nyi}, State}.
diff --git a/lib/wx/examples/demo/ex_slider.erl b/lib/wx/examples/demo/ex_slider.erl
index 612543ff26..4979e8b4f4 100644
--- a/lib/wx/examples/demo/ex_slider.erl
+++ b/lib/wx/examples/demo/ex_slider.erl
@@ -97,6 +97,10 @@ handle_info(Msg, State) ->
demo:format(State#state.config, "Got Info ~p\n",[Msg]),
{noreply, State}.
+handle_call(shutdown, _From, State=#state{parent=Panel}) ->
+ wxPanel:destroy(Panel),
+ {stop, normal, ok, State};
+
handle_call(Msg, _From, State) ->
demo:format(State#state.config,"Got Call ~p\n",[Msg]),
{reply, {error, nyi},State}.
diff --git a/lib/wx/examples/demo/ex_splitterWindow.erl b/lib/wx/examples/demo/ex_splitterWindow.erl
index 4f25b73293..ac2fbe0113 100644
--- a/lib/wx/examples/demo/ex_splitterWindow.erl
+++ b/lib/wx/examples/demo/ex_splitterWindow.erl
@@ -86,6 +86,10 @@ handle_info(Msg, State) ->
demo:format(State#state.config, "Got Info ~p\n", [Msg]),
{noreply, State}.
+handle_call(shutdown, _From, State=#state{parent=Panel}) ->
+ wxPanel:destroy(Panel),
+ {stop, normal, ok, State};
+
handle_call(Msg, _From, State) ->
demo:format(State#state.config, "Got Call ~p\n", [Msg]),
{reply,{error, nyi}, State}.
diff --git a/lib/wx/examples/demo/ex_static.erl b/lib/wx/examples/demo/ex_static.erl
index 013bd5ac35..8cf477b55a 100644
--- a/lib/wx/examples/demo/ex_static.erl
+++ b/lib/wx/examples/demo/ex_static.erl
@@ -101,6 +101,10 @@ handle_info(Msg, State) ->
demo:format(State#state.config, "Got Info ~p\n", [Msg]),
{noreply, State}.
+handle_call(shutdown, _From, State=#state{parent=Panel}) ->
+ wxPanel:destroy(Panel),
+ {stop, normal, ok, State};
+
handle_call(Msg, _From, State) ->
demo:format(State#state.config, "Got Call ~p\n", [Msg]),
{reply,{error, nyi}, State}.
diff --git a/lib/wx/examples/demo/ex_textCtrl.erl b/lib/wx/examples/demo/ex_textCtrl.erl
index d82884f30b..57088ad878 100644
--- a/lib/wx/examples/demo/ex_textCtrl.erl
+++ b/lib/wx/examples/demo/ex_textCtrl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -51,27 +51,23 @@ do_init(Config) ->
Sizer3 = wxStaticBoxSizer:new(?wxVERTICAL, Panel,
[{label, "wxTextCtrl multiline"}]),
- TextCtrl = wxTextCtrl:new(Panel, 1, [{value, "This is a single line wxTextCtrl"},
+ TextCtrl = wxTextCtrl:new(Panel, 1, [{value, "This is a single line wxTextCtrl"},
{style, ?wxDEFAULT}]),
TextCtrl2 = wxTextCtrl:new(Panel, 2, [{value, "password"},
- {style, ?wxDEFAULT bor
- ?wxTE_PASSWORD}]),
- TextCtrl3 = wxTextCtrl:new(Panel, 3, [{value, "This is a\n"
- "multiline\n"
- "wxTextCtrl"},
- {style, ?wxDEFAULT bor
- ?wxTE_MULTILINE}]),
+ {style, ?wxDEFAULT bor ?wxTE_PASSWORD}]),
+ TextCtrl3 = wxTextCtrl:new(Panel, 3, [{value, "This is a\nmultiline\nwxTextCtrl"},
+ {style, ?wxDEFAULT bor ?wxTE_MULTILINE}]),
%% Add to sizers
- wxSizer:add(Sizer, TextCtrl, [{flag, ?wxEXPAND}]),
+ wxSizer:add(Sizer, TextCtrl, [{flag, ?wxEXPAND}]),
wxSizer:add(Sizer2, TextCtrl2, []),
- wxSizer:add(Sizer3, TextCtrl3, [{flag, ?wxEXPAND}]),
+ wxSizer:add(Sizer3, TextCtrl3, [{flag, ?wxEXPAND}, {proportion, 1}]),
wxSizer:add(MainSizer, Sizer, [{flag, ?wxEXPAND}]),
wxSizer:addSpacer(MainSizer, 10),
wxSizer:add(MainSizer, Sizer2, [{flag, ?wxEXPAND}]),
wxSizer:addSpacer(MainSizer, 10),
- wxSizer:add(MainSizer, Sizer3, [{flag, ?wxEXPAND}]),
+ wxSizer:add(MainSizer, Sizer3, [{flag, ?wxEXPAND}, {proportion, 1}]),
wxPanel:setSizer(Panel, MainSizer),
{Panel, #state{parent=Panel, config=Config}}.
@@ -88,6 +84,10 @@ handle_info(Msg, State) ->
demo:format(State#state.config, "Got Info ~p\n",[Msg]),
{noreply, State}.
+handle_call(shutdown, _From, State=#state{parent=Panel}) ->
+ wxPanel:destroy(Panel),
+ {stop, normal, ok, State};
+
handle_call(Msg, _From, State) ->
demo:format(State#state.config,"Got Call ~p\n",[Msg]),
{reply, {error,nyi}, State}.
diff --git a/lib/wx/examples/demo/ex_treeCtrl.erl b/lib/wx/examples/demo/ex_treeCtrl.erl
index 611904500a..7698ab1f00 100644
--- a/lib/wx/examples/demo/ex_treeCtrl.erl
+++ b/lib/wx/examples/demo/ex_treeCtrl.erl
@@ -105,6 +105,10 @@ handle_info(Msg, State) ->
demo:format(State#state.config, "Got Info ~p\n", [Msg]),
{noreply, State}.
+handle_call(shutdown, _From, State=#state{parent=Panel}) ->
+ wxPanel:destroy(Panel),
+ {stop, normal, ok, State};
+
handle_call(Msg, _From, State) ->
demo:format(State#state.config, "Got Call ~p\n", [Msg]),
{reply,{error, nyi}, State}.
diff --git a/lib/wx/examples/simple/menu.erl b/lib/wx/examples/simple/menu.erl
index 0025a0b027..9e6b28b46b 100644
--- a/lib/wx/examples/simple/menu.erl
+++ b/lib/wx/examples/simple/menu.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -105,7 +105,7 @@ create_frame(Wx) ->
Frame = wxFrame:new(Wx, -1, "wxErlang menu sample", [{size, {600,400}}]),
Path = filename:dirname(code:which(?MODULE)),
- wxFrame:setIcon(Frame, wxIcon:new(filename:join(Path,"sample.xpm"))),
+ wxFrame:setIcon(Frame, wxIcon:new(filename:join(Path,"sample.xpm"), [{type, ?wxBITMAP_TYPE_XPM}])),
wxFrame:createStatusBar(Frame,[]),
wxFrame:connect(Frame, close_window),
diff --git a/lib/wx/examples/simple/minimal.erl b/lib/wx/examples/simple/minimal.erl
index bdff66e217..4782745dfc 100644
--- a/lib/wx/examples/simple/minimal.erl
+++ b/lib/wx/examples/simple/minimal.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -41,8 +41,8 @@ start() ->
create_window(Wx) ->
Frame = wxFrame:new(Wx, -1, "Minimal wxErlang App", [{size, {600,400}}]),
- Path = filename:dirname(code:which(?MODULE)),
- wxFrame:setIcon(Frame, wxIcon:new(filename:join(Path,"sample.xpm"))),
+ Path = filename:dirname(code:which(?MODULE)),
+ wxFrame:setIcon(Frame, wxIcon:new(filename:join(Path,"sample.xpm"), [{type, ?wxBITMAP_TYPE_XPM}])),
wxFrame:createStatusBar(Frame,[]),
wxFrame:connect(Frame, close_window),
diff --git a/lib/wx/examples/sudoku/sudoku_board.erl b/lib/wx/examples/sudoku/sudoku_board.erl
index 4b26ff97da..ed9c62b7c8 100644
--- a/lib/wx/examples/sudoku/sudoku_board.erl
+++ b/lib/wx/examples/sudoku/sudoku_board.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -27,7 +27,7 @@
-export([new/1, setup_board/2, clear_board/1, left/1,
get_board_data/1,set_board_data/2,
set_butt/3, butt_correct/3,
- draw/3,
+ get_state/1, redraw/3,
%% Callbacks
init/1, handle_sync_event/3,
handle_event/2, handle_info/2, handle_call/3, handle_cast/2,
@@ -69,9 +69,8 @@ get_board_data(Board) ->
set_board_data(Board, List) ->
wx_object:call(Board, {set_board_data, List}).
-
-draw(Board, DC, Size) ->
- wx_object:call(Board, {draw, DC, Size}).
+get_state(Board) ->
+ wx_object:call(Board, get_state).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -85,26 +84,29 @@ init([ParentObj, ParentPid]) ->
wxWindow:connect(Win, erase_background, []),
wxWindow:connect(Win, key_up, [{skip, true}]),
wxWindow:connect(Win, left_down, [{skip, true}]),
- wxWindow:connect(Win, enter_window, [{skip, true}]),
+ wxWindow:connect(Win, enter_window, [{skip, true}]),
%% Init pens and fonts
Pen = wxPen:new({0,0,0}, [{width, 3}]),
Fs0 = [{Sz,wxFont:new(Sz, ?wxSWISS, ?wxNORMAL, ?wxNORMAL,[])} ||
Sz <- [8,9,10,11,12,13,14,16,18,20,22,24,26,28,30,34,38,42,44,46]],
- TestDC = wxClientDC:new(Win),
+ TestDC = wxMemoryDC:new(),
+ Bitmap = wxBitmap:new(256,256),
+ wxMemoryDC:selectObject(TestDC, Bitmap),
+ true = wxDC:isOk(TestDC),
CW = fun({Sz,Font},Acc) ->
case wxFont:ok(Font) of
- true ->
+ true ->
wxDC:setFont(TestDC, Font),
- CH = wxDC:getCharHeight(TestDC),
+ CH = wxDC:getCharHeight(TestDC),
[{CH,Sz,Font} | Acc];
false ->
Acc
end
end,
Fs = lists:foldl(CW, [], Fs0),
- wxClientDC:destroy(TestDC),
- {Win, #state{win=Win, board=[], pen=Pen, fonts=Fs, parent=ParentPid}}.
+ wxMemoryDC:destroy(TestDC),
+ {Win, #state{win=Win, board=[], pen=Pen, fonts=Fs,parent=ParentPid}}.
handle_sync_event(#wx{event=#wxPaint{}}, _Obj, State = #state{win=Win}) ->
%% io:format("EPaint~n",[]),
@@ -119,22 +121,17 @@ handle_sync_event(#wx{event=#wxPaint{}}, _Obj, State = #state{win=Win}) ->
handle_event(#wx{event=#wxMouse{type=enter_window}}, State = #state{win=Win}) ->
wxWindow:setFocus(Win), %% Get keyboard focus
{noreply,State};
-handle_event(#wx{event=#wxKey{keyCode=KeyC, x=X,y=Y}},
+handle_event(#wx{event=#wxKey{keyCode=KeyC}},
S = #state{parent=Pid, win=Win}) ->
Val = if KeyC > 47, KeyC < 58 -> KeyC - $0;
KeyC > 325, KeyC < 336 -> KeyC - 326; %% NUM LOCK
true -> 0
end,
- case get_butt(X,Y,S) of
- error -> %% Mac don't get correct coordinates.
- Global = wx_misc:getMousePosition(),
- {CX,CY} = wxWindow:screenToClient(Win, Global),
- case get_butt(CX,CY,S) of
- error -> ignore;
- Id -> Pid ! {set_val,Id,Val}
- end;
- Id ->
- Pid ! {set_val,Id,Val}
+ Global = wx_misc:getMousePosition(),
+ {CX,CY} = wxWindow:screenToClient(Win, Global),
+ case get_butt(CX,CY,S) of
+ error -> ignore;
+ Id -> Pid ! {set_val,Id,Val}
end,
{noreply, S};
handle_event(#wx{event=#wxMouse{type=left_down,x=X,y=Y}},
@@ -205,9 +202,8 @@ handle_call({set_board_data, B},_From, S0) ->
handle_call(left,_From, S = #state{board=B}) ->
Res = 81 - length([ok || #sq{correct=C} <- B, C /= false]),
{reply, Res, S};
-handle_call({draw, DC, Size},_From, S) ->
- redraw(DC,Size,S),
- {reply, ok, S}.
+handle_call(get_state, _From, S) ->
+ {reply, {ok,S}, S}.
handle_cast(Msg, State) ->
io:format("Got cast ~p~n",[Msg]),
diff --git a/lib/wx/examples/sudoku/sudoku_gui.erl b/lib/wx/examples/sudoku/sudoku_gui.erl
index 3d0c95ffa7..5f3f1a2621 100644
--- a/lib/wx/examples/sudoku/sudoku_gui.erl
+++ b/lib/wx/examples/sudoku/sudoku_gui.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -307,19 +307,19 @@ dialog(?PRINT_PAGE_SETUP, S = #gs{frame=Frame, print_psdd=PsDD0, print_d=PD0}) -
wxPageSetupDialogData:destroy(PsDD0),
wxPrintData:destroy(PD0),
S#gs{print_psdd=PsDD, print_d=PD};
-dialog(?PRINT_PRE, S = #gs{frame=Frame, print_d=PD}) ->
+dialog(?PRINT_PRE, S = #gs{frame=Frame, print_d=PD, board=Board}) ->
+ {ok, BoardS} = sudoku_board:get_state(Board),
PDD = wxPrintDialogData:new(PD),
- Printout1 = wxPrintout:new("Print", fun(This,Page) -> printout(This,Page,S) end,
+ Printout1 = wxPrintout:new("Print 1", fun(This,Page) -> printout(This,Page,BoardS, S) end,
[{getPageInfo, fun getPageInfo/1}]),
- Printout2 = wxPrintout:new("Print", fun(This,Page) -> printout(This,Page,S) end,
+ Printout2 = wxPrintout:new("Print 2", fun(This,Page) -> printout(This,Page,BoardS, S) end,
[{getPageInfo, fun getPageInfo/1}]),
- Preview = wxPrintPreview:new(Printout1, [{printoutForPrinting,Printout2},{data,PDD}]),
+ Preview = wxPrintPreview:new(Printout1, [{printoutForPrinting,Printout2},{data,PDD}]),
case wxPrintPreview:isOk(Preview) of
true ->
PF = wxPreviewFrame:new(Preview, Frame, [{title, "Print Preview"}]),
wxPreviewFrame:centre(PF, [{dir, ?wxBOTH}]),
wxPreviewFrame:initialize(PF),
- wxPreviewFrame:centre(PF),
wxPreviewFrame:show(PF);
false ->
io:format("Could not create preview window.\n"
@@ -327,10 +327,11 @@ dialog(?PRINT_PRE, S = #gs{frame=Frame, print_d=PD}) ->
wxPrintPreview:destroy(Preview)
end,
S;
-dialog(?PRINT, S = #gs{frame=Frame, print_d=PD}) ->
+dialog(?PRINT, S = #gs{frame=Frame, print_d=PD, board=Board}) ->
+ {ok, BoardS} = sudoku_board:get_state(Board),
PDD = wxPrintDialogData:new(PD),
Printer = wxPrinter:new([{data,PDD}]),
- Printout = wxPrintout:new("Print", fun(This,Page) -> printout(This,Page,S) end,
+ Printout = wxPrintout:new("Print", fun(This,Page) -> printout(This,Page,BoardS,S) end,
[{getPageInfo, fun getPageInfo/1}]),
case wxPrinter:print(Printer, Frame, Printout, [{prompt,true}]) of
@@ -374,16 +375,14 @@ init_printer(S) ->
getPageInfo(_This) ->
{1,1,1,1}.
-printout(This, _Page, #gs{board=Board, print_psdd=PsDD}) ->
+printout(This, _Page, Board, #gs{print_psdd=PsDD}) ->
MX = MY = 500,
wxPrintout:fitThisSizeToPageMargins(This, {MX,MY}, PsDD),
-
+
_DBG = {_X,_Y,W,H} = wxPrintout:getLogicalPageMarginsRect(This, PsDD),
wxPrintout:offsetLogicalOrigin(This,(W-MX) div 2, (H-MY) div 2),
-%% io:format("~p ->{~p,~p} ~n", [_DBG, (W-MX) div 2, (H-MY) div 2]),
-
DC = wxPrintout:getDC(This),
- sudoku_board:draw(Board, DC, {500,500}),
+ sudoku_board:redraw(DC, {500,500}, Board),
true.
set_val(Id, Val, Board, G) ->
diff --git a/lib/wx/include/wx.hrl b/lib/wx/include/wx.hrl
index 62979908a6..a48c756dea 100644
--- a/lib/wx/include/wx.hrl
+++ b/lib/wx/include/wx.hrl
@@ -131,7 +131,7 @@
-type wxScrollWin() :: #wxScrollWin{}. %% Callback event: {@link wxScrollWinEvent}
-record(wxPaint, {type :: wxPaintEventType()}). %% Callback event: {@link wxPaintEvent}
--type wxPaintEventType() :: paint | paint_icon.
+-type wxPaintEventType() :: paint.
-type wxPaint() :: #wxPaint{}. %% Callback event: {@link wxPaintEvent}
-record(wxChildFocus, {type :: wxChildFocusEventType()}). %% Callback event: {@link wxChildFocusEvent}
@@ -252,7 +252,7 @@
wheelRotation :: integer(),
wheelDelta :: integer(),
linesPerAction :: integer()}).
--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 | nc_left_down | nc_left_up | nc_middle_down | nc_middle_up | nc_right_down | nc_right_up | nc_motion | nc_enter_window | nc_leave_window | nc_left_dclick | nc_middle_dclick | nc_right_dclick.
+-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(wxWindowCreate, {type :: wxWindowCreateEventType()}). %% Callback event: {@link wxWindowCreateEvent}
@@ -292,10 +292,6 @@
-type wxIdleEventType() :: idle.
-type wxIdle() :: #wxIdle{}. %% Callback event: {@link wxIdleEvent}
--record(wxNcPaint, {type :: wxNcPaintEventType()}). %% Callback event: {@link wxNcPaintEvent}
--type wxNcPaintEventType() :: nc_paint.
--type wxNcPaint() :: #wxNcPaint{}. %% Callback event: {@link wxNcPaintEvent}
-
-record(wxColourPicker,{type :: wxColourPickerEventType(), %% Callback event: {@link wxColourPickerEvent}
colour :: wx:wx_colour()}).
-type wxColourPickerEventType() :: command_colourpicker_changed.
@@ -312,8 +308,8 @@
-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}
--type event() :: wxAuiManager() | wxAuiNotebook() | wxCalendar() | wxChildFocus() | wxClose() | wxColourPicker() | wxCommand() | wxContextMenu() | wxDate() | wxDisplayChanged() | wxErase() | wxFileDirPicker() | wxFocus() | wxFontPicker() | wxGrid() | wxHelp() | wxHtmlLink() | wxIconize() | wxIdle() | wxJoystick() | wxKey() | wxList() | wxMaximize() | wxMenu() | wxMouse() | wxMouseCaptureChanged() | wxMove() | wxNavigationKey() | wxNcPaint() | wxNotebook() | wxPaint() | wxPaletteChanged() | wxQueryNewPalette() | wxSash() | wxScroll() | wxScrollWin() | wxSetCursor() | wxShow() | wxSize() | wxSpin() | wxSplitter() | wxStyledText() | wxSysColourChanged() | wxTaskBarIcon() | wxTree() | wxUpdateUI() | wxWindowCreate() | wxWindowDestroy().
--type wxEventType() :: wxAuiManagerEventType() | wxAuiNotebookEventType() | wxCalendarEventType() | wxChildFocusEventType() | wxCloseEventType() | wxColourPickerEventType() | wxCommandEventType() | wxContextMenuEventType() | wxDateEventType() | wxDisplayChangedEventType() | wxEraseEventType() | wxFileDirPickerEventType() | wxFocusEventType() | wxFontPickerEventType() | wxGridEventType() | wxHelpEventType() | wxHtmlLinkEventType() | wxIconizeEventType() | wxIdleEventType() | wxJoystickEventType() | wxKeyEventType() | wxListEventType() | wxMaximizeEventType() | wxMenuEventType() | wxMouseCaptureChangedEventType() | wxMouseEventType() | wxMoveEventType() | wxNavigationKeyEventType() | wxNcPaintEventType() | wxNotebookEventType() | wxPaintEventType() | wxPaletteChangedEventType() | wxQueryNewPaletteEventType() | wxSashEventType() | wxScrollEventType() | wxScrollWinEventType() | wxSetCursorEventType() | wxShowEventType() | wxSizeEventType() | wxSpinEventType() | wxSplitterEventType() | wxStyledTextEventType() | wxSysColourChangedEventType() | wxTaskBarIconEventType() | wxTreeEventType() | wxUpdateUIEventType() | wxWindowCreateEventType() | wxWindowDestroyEventType().
+-type event() :: wxAuiManager() | wxAuiNotebook() | wxCalendar() | wxChildFocus() | wxClose() | wxColourPicker() | wxCommand() | wxContextMenu() | wxDate() | wxDisplayChanged() | wxErase() | wxFileDirPicker() | wxFocus() | wxFontPicker() | wxGrid() | wxHelp() | wxHtmlLink() | wxIconize() | wxIdle() | wxJoystick() | wxKey() | wxList() | wxMaximize() | wxMenu() | wxMouse() | wxMouseCaptureChanged() | wxMove() | wxNavigationKey() | wxNotebook() | wxPaint() | wxPaletteChanged() | wxQueryNewPalette() | wxSash() | wxScroll() | wxScrollWin() | wxSetCursor() | wxShow() | wxSize() | wxSpin() | wxSplitter() | wxStyledText() | wxSysColourChanged() | wxTaskBarIcon() | wxTree() | wxUpdateUI() | wxWindowCreate() | wxWindowDestroy().
+-type wxEventType() :: wxAuiManagerEventType() | wxAuiNotebookEventType() | wxCalendarEventType() | wxChildFocusEventType() | wxCloseEventType() | wxColourPickerEventType() | wxCommandEventType() | wxContextMenuEventType() | wxDateEventType() | wxDisplayChangedEventType() | wxEraseEventType() | wxFileDirPickerEventType() | wxFocusEventType() | wxFontPickerEventType() | wxGridEventType() | wxHelpEventType() | wxHtmlLinkEventType() | wxIconizeEventType() | wxIdleEventType() | wxJoystickEventType() | wxKeyEventType() | wxListEventType() | wxMaximizeEventType() | wxMenuEventType() | wxMouseCaptureChangedEventType() | 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(),
@@ -420,78 +416,78 @@
-define(wxDateTime_Country_Unknown, 0).
-define(wxDateTime_Country_Default, 1).
-define(wxDateTime_Country_WesternEurope_Start, 2).
--define(wxDateTime_Country_EEC, ?Country_WesternEurope_Start).
--define(wxDateTime_France, (?Country_WesternEurope_Start+1)).
--define(wxDateTime_Germany, (?Country_WesternEurope_Start+2)).
--define(wxDateTime_UK, (?Country_WesternEurope_Start+3)).
--define(wxDateTime_Country_WesternEurope_End, ?UK).
--define(wxDateTime_Russia, (?UK+1)).
--define(wxDateTime_USA, (?UK+2)).
+-define(wxDateTime_Country_EEC, ?wxDateTime_Country_WesternEurope_Start).
+-define(wxDateTime_France, (?wxDateTime_Country_WesternEurope_Start+1)).
+-define(wxDateTime_Germany, (?wxDateTime_Country_WesternEurope_Start+2)).
+-define(wxDateTime_UK, (?wxDateTime_Country_WesternEurope_Start+3)).
+-define(wxDateTime_Country_WesternEurope_End, ?wxDateTime_UK).
+-define(wxDateTime_Russia, (?wxDateTime_UK+1)).
+-define(wxDateTime_USA, (?wxDateTime_UK+2)).
% From class wxDateTime::GregorianAdoption
-define(wxDateTime_Gr_Unknown, 0).
-define(wxDateTime_Gr_Standard, 1).
-define(wxDateTime_Gr_Alaska, 2).
-define(wxDateTime_Gr_Albania, 3).
--define(wxDateTime_Gr_Austria, ?Gr_Unknown).
--define(wxDateTime_Gr_Austria_Brixen, (?Gr_Unknown+1)).
--define(wxDateTime_Gr_Austria_Salzburg, ?Gr_Austria_Brixen).
--define(wxDateTime_Gr_Austria_Tyrol, ?Gr_Austria_Brixen).
--define(wxDateTime_Gr_Austria_Carinthia, (?Gr_Austria_Brixen+1)).
--define(wxDateTime_Gr_Austria_Styria, ?Gr_Austria_Carinthia).
--define(wxDateTime_Gr_Belgium, (?Gr_Austria_Carinthia+1)).
--define(wxDateTime_Gr_Bulgaria, ?Gr_Unknown).
--define(wxDateTime_Gr_Bulgaria_1, (?Gr_Unknown+1)).
--define(wxDateTime_Gr_Bulgaria_2, (?Gr_Unknown+2)).
--define(wxDateTime_Gr_Bulgaria_3, (?Gr_Unknown+3)).
--define(wxDateTime_Gr_Canada, ?Gr_Unknown).
--define(wxDateTime_Gr_China, ?Gr_Unknown).
--define(wxDateTime_Gr_China_1, (?Gr_Unknown+1)).
--define(wxDateTime_Gr_China_2, (?Gr_Unknown+2)).
--define(wxDateTime_Gr_Czechoslovakia, (?Gr_Unknown+3)).
--define(wxDateTime_Gr_Denmark, (?Gr_Unknown+4)).
--define(wxDateTime_Gr_Egypt, (?Gr_Unknown+5)).
--define(wxDateTime_Gr_Estonia, (?Gr_Unknown+6)).
--define(wxDateTime_Gr_Finland, (?Gr_Unknown+7)).
--define(wxDateTime_Gr_France, (?Gr_Unknown+8)).
--define(wxDateTime_Gr_France_Alsace, (?Gr_Unknown+9)).
--define(wxDateTime_Gr_France_Lorraine, (?Gr_Unknown+10)).
--define(wxDateTime_Gr_France_Strasbourg, (?Gr_Unknown+11)).
--define(wxDateTime_Gr_Germany, ?Gr_Unknown).
--define(wxDateTime_Gr_Germany_Catholic, (?Gr_Unknown+1)).
--define(wxDateTime_Gr_Germany_Prussia, (?Gr_Unknown+2)).
--define(wxDateTime_Gr_Germany_Protestant, (?Gr_Unknown+3)).
--define(wxDateTime_Gr_GreatBritain, (?Gr_Unknown+4)).
--define(wxDateTime_Gr_Greece, (?Gr_Unknown+5)).
--define(wxDateTime_Gr_Hungary, (?Gr_Unknown+6)).
--define(wxDateTime_Gr_Ireland, ?Gr_GreatBritain).
--define(wxDateTime_Gr_Italy, ?Gr_Standard).
--define(wxDateTime_Gr_Japan, ?Gr_Unknown).
--define(wxDateTime_Gr_Japan_1, (?Gr_Unknown+1)).
--define(wxDateTime_Gr_Japan_2, (?Gr_Unknown+2)).
--define(wxDateTime_Gr_Japan_3, (?Gr_Unknown+3)).
--define(wxDateTime_Gr_Latvia, (?Gr_Unknown+4)).
--define(wxDateTime_Gr_Lithuania, (?Gr_Unknown+5)).
--define(wxDateTime_Gr_Luxemburg, (?Gr_Unknown+6)).
--define(wxDateTime_Gr_Netherlands, ?Gr_Belgium).
--define(wxDateTime_Gr_Netherlands_Groningen, (?Gr_Belgium+1)).
--define(wxDateTime_Gr_Netherlands_Gelderland, (?Gr_Belgium+2)).
--define(wxDateTime_Gr_Netherlands_Utrecht, (?Gr_Belgium+3)).
--define(wxDateTime_Gr_Netherlands_Friesland, (?Gr_Belgium+4)).
--define(wxDateTime_Gr_Norway, ?Gr_Denmark).
--define(wxDateTime_Gr_Poland, ?Gr_Standard).
--define(wxDateTime_Gr_Portugal, ?Gr_Standard).
--define(wxDateTime_Gr_Romania, (?Gr_Standard+1)).
--define(wxDateTime_Gr_Russia, (?Gr_Standard+2)).
--define(wxDateTime_Gr_Scotland, ?Gr_GreatBritain).
--define(wxDateTime_Gr_Spain, ?Gr_Standard).
--define(wxDateTime_Gr_Sweden, ?Gr_Finland).
--define(wxDateTime_Gr_Switzerland, ?Gr_Unknown).
--define(wxDateTime_Gr_Switzerland_Catholic, (?Gr_Unknown+1)).
--define(wxDateTime_Gr_Switzerland_Protestant, (?Gr_Unknown+2)).
--define(wxDateTime_Gr_Turkey, (?Gr_Unknown+3)).
--define(wxDateTime_Gr_USA, ?Gr_GreatBritain).
--define(wxDateTime_Gr_Wales, ?Gr_GreatBritain).
--define(wxDateTime_Gr_Yugoslavia, (?Gr_GreatBritain+1)).
+-define(wxDateTime_Gr_Austria, ?wxDateTime_Gr_Unknown).
+-define(wxDateTime_Gr_Austria_Brixen, (?wxDateTime_Gr_Unknown+1)).
+-define(wxDateTime_Gr_Austria_Salzburg, ?wxDateTime_Gr_Austria_Brixen).
+-define(wxDateTime_Gr_Austria_Tyrol, ?wxDateTime_Gr_Austria_Brixen).
+-define(wxDateTime_Gr_Austria_Carinthia, (?wxDateTime_Gr_Austria_Brixen+1)).
+-define(wxDateTime_Gr_Austria_Styria, ?wxDateTime_Gr_Austria_Carinthia).
+-define(wxDateTime_Gr_Belgium, (?wxDateTime_Gr_Austria_Carinthia+1)).
+-define(wxDateTime_Gr_Bulgaria, ?wxDateTime_Gr_Unknown).
+-define(wxDateTime_Gr_Bulgaria_1, (?wxDateTime_Gr_Unknown+1)).
+-define(wxDateTime_Gr_Bulgaria_2, (?wxDateTime_Gr_Unknown+2)).
+-define(wxDateTime_Gr_Bulgaria_3, (?wxDateTime_Gr_Unknown+3)).
+-define(wxDateTime_Gr_Canada, ?wxDateTime_Gr_Unknown).
+-define(wxDateTime_Gr_China, ?wxDateTime_Gr_Unknown).
+-define(wxDateTime_Gr_China_1, (?wxDateTime_Gr_Unknown+1)).
+-define(wxDateTime_Gr_China_2, (?wxDateTime_Gr_Unknown+2)).
+-define(wxDateTime_Gr_Czechoslovakia, (?wxDateTime_Gr_Unknown+3)).
+-define(wxDateTime_Gr_Denmark, (?wxDateTime_Gr_Unknown+4)).
+-define(wxDateTime_Gr_Egypt, (?wxDateTime_Gr_Unknown+5)).
+-define(wxDateTime_Gr_Estonia, (?wxDateTime_Gr_Unknown+6)).
+-define(wxDateTime_Gr_Finland, (?wxDateTime_Gr_Unknown+7)).
+-define(wxDateTime_Gr_France, (?wxDateTime_Gr_Unknown+8)).
+-define(wxDateTime_Gr_France_Alsace, (?wxDateTime_Gr_Unknown+9)).
+-define(wxDateTime_Gr_France_Lorraine, (?wxDateTime_Gr_Unknown+10)).
+-define(wxDateTime_Gr_France_Strasbourg, (?wxDateTime_Gr_Unknown+11)).
+-define(wxDateTime_Gr_Germany, ?wxDateTime_Gr_Unknown).
+-define(wxDateTime_Gr_Germany_Catholic, (?wxDateTime_Gr_Unknown+1)).
+-define(wxDateTime_Gr_Germany_Prussia, (?wxDateTime_Gr_Unknown+2)).
+-define(wxDateTime_Gr_Germany_Protestant, (?wxDateTime_Gr_Unknown+3)).
+-define(wxDateTime_Gr_GreatBritain, (?wxDateTime_Gr_Unknown+4)).
+-define(wxDateTime_Gr_Greece, (?wxDateTime_Gr_Unknown+5)).
+-define(wxDateTime_Gr_Hungary, (?wxDateTime_Gr_Unknown+6)).
+-define(wxDateTime_Gr_Ireland, ?wxDateTime_Gr_GreatBritain).
+-define(wxDateTime_Gr_Italy, ?wxDateTime_Gr_Standard).
+-define(wxDateTime_Gr_Japan, ?wxDateTime_Gr_Unknown).
+-define(wxDateTime_Gr_Japan_1, (?wxDateTime_Gr_Unknown+1)).
+-define(wxDateTime_Gr_Japan_2, (?wxDateTime_Gr_Unknown+2)).
+-define(wxDateTime_Gr_Japan_3, (?wxDateTime_Gr_Unknown+3)).
+-define(wxDateTime_Gr_Latvia, (?wxDateTime_Gr_Unknown+4)).
+-define(wxDateTime_Gr_Lithuania, (?wxDateTime_Gr_Unknown+5)).
+-define(wxDateTime_Gr_Luxemburg, (?wxDateTime_Gr_Unknown+6)).
+-define(wxDateTime_Gr_Netherlands, ?wxDateTime_Gr_Belgium).
+-define(wxDateTime_Gr_Netherlands_Groningen, (?wxDateTime_Gr_Belgium+1)).
+-define(wxDateTime_Gr_Netherlands_Gelderland, (?wxDateTime_Gr_Belgium+2)).
+-define(wxDateTime_Gr_Netherlands_Utrecht, (?wxDateTime_Gr_Belgium+3)).
+-define(wxDateTime_Gr_Netherlands_Friesland, (?wxDateTime_Gr_Belgium+4)).
+-define(wxDateTime_Gr_Norway, ?wxDateTime_Gr_Denmark).
+-define(wxDateTime_Gr_Poland, ?wxDateTime_Gr_Standard).
+-define(wxDateTime_Gr_Portugal, ?wxDateTime_Gr_Standard).
+-define(wxDateTime_Gr_Romania, (?wxDateTime_Gr_Standard+1)).
+-define(wxDateTime_Gr_Russia, (?wxDateTime_Gr_Standard+2)).
+-define(wxDateTime_Gr_Scotland, ?wxDateTime_Gr_GreatBritain).
+-define(wxDateTime_Gr_Spain, ?wxDateTime_Gr_Standard).
+-define(wxDateTime_Gr_Sweden, ?wxDateTime_Gr_Finland).
+-define(wxDateTime_Gr_Switzerland, ?wxDateTime_Gr_Unknown).
+-define(wxDateTime_Gr_Switzerland_Catholic, (?wxDateTime_Gr_Unknown+1)).
+-define(wxDateTime_Gr_Switzerland_Protestant, (?wxDateTime_Gr_Unknown+2)).
+-define(wxDateTime_Gr_Turkey, (?wxDateTime_Gr_Unknown+3)).
+-define(wxDateTime_Gr_USA, ?wxDateTime_Gr_GreatBritain).
+-define(wxDateTime_Gr_Wales, ?wxDateTime_Gr_GreatBritain).
+-define(wxDateTime_Gr_Yugoslavia, (?wxDateTime_Gr_GreatBritain+1)).
% From class wxDateTime::Month
-define(wxDateTime_Jan, 0).
-define(wxDateTime_Feb, 1).
@@ -537,34 +533,34 @@
-define(wxDateTime_GMT11, 24).
-define(wxDateTime_GMT12, 25).
-define(wxDateTime_GMT13, 26).
--define(wxDateTime_WET, ?GMT0).
--define(wxDateTime_WEST, ?GMT1).
--define(wxDateTime_CET, ?GMT1).
--define(wxDateTime_CEST, ?GMT2).
--define(wxDateTime_EET, ?GMT2).
--define(wxDateTime_EEST, ?GMT3).
--define(wxDateTime_MSK, ?GMT3).
--define(wxDateTime_MSD, ?GMT4).
--define(wxDateTime_AST, ?GMT_4).
--define(wxDateTime_ADT, ?GMT_3).
--define(wxDateTime_EST, ?GMT_5).
--define(wxDateTime_EDT, ?GMT_4).
--define(wxDateTime_CST, ?GMT_6).
--define(wxDateTime_CDT, ?GMT_5).
--define(wxDateTime_MST, ?GMT_7).
--define(wxDateTime_MDT, ?GMT_6).
--define(wxDateTime_PST, ?GMT_8).
--define(wxDateTime_PDT, ?GMT_7).
--define(wxDateTime_HST, ?GMT_10).
--define(wxDateTime_AKST, ?GMT_9).
--define(wxDateTime_AKDT, ?GMT_8).
--define(wxDateTime_A_WST, ?GMT8).
--define(wxDateTime_A_CST, ?GMT13+1).
--define(wxDateTime_A_EST, ?GMT10).
--define(wxDateTime_A_ESST, ?GMT11).
--define(wxDateTime_NZST, ?GMT12).
--define(wxDateTime_NZDT, ?GMT13).
--define(wxDateTime_UTC, ?GMT0).
+-define(wxDateTime_WET, ?wxDateTime_GMT0).
+-define(wxDateTime_WEST, ?wxDateTime_GMT1).
+-define(wxDateTime_CET, ?wxDateTime_GMT1).
+-define(wxDateTime_CEST, ?wxDateTime_GMT2).
+-define(wxDateTime_EET, ?wxDateTime_GMT2).
+-define(wxDateTime_EEST, ?wxDateTime_GMT3).
+-define(wxDateTime_MSK, ?wxDateTime_GMT3).
+-define(wxDateTime_MSD, ?wxDateTime_GMT4).
+-define(wxDateTime_AST, ?wxDateTime_GMT_4).
+-define(wxDateTime_ADT, ?wxDateTime_GMT_3).
+-define(wxDateTime_EST, ?wxDateTime_GMT_5).
+-define(wxDateTime_EDT, ?wxDateTime_GMT_4).
+-define(wxDateTime_CST, ?wxDateTime_GMT_6).
+-define(wxDateTime_CDT, ?wxDateTime_GMT_5).
+-define(wxDateTime_MST, ?wxDateTime_GMT_7).
+-define(wxDateTime_MDT, ?wxDateTime_GMT_6).
+-define(wxDateTime_PST, ?wxDateTime_GMT_8).
+-define(wxDateTime_PDT, ?wxDateTime_GMT_7).
+-define(wxDateTime_HST, ?wxDateTime_GMT_10).
+-define(wxDateTime_AKST, ?wxDateTime_GMT_9).
+-define(wxDateTime_AKDT, ?wxDateTime_GMT_8).
+-define(wxDateTime_A_WST, ?wxDateTime_GMT8).
+-define(wxDateTime_A_CST, (?wxDateTime_GMT13+1)).
+-define(wxDateTime_A_EST, ?wxDateTime_GMT10).
+-define(wxDateTime_A_ESST, ?wxDateTime_GMT11).
+-define(wxDateTime_NZST, ?wxDateTime_GMT12).
+-define(wxDateTime_NZDT, ?wxDateTime_GMT13).
+-define(wxDateTime_UTC, ?wxDateTime_GMT0).
% From class wxDateTime::WeekDay
-define(wxDateTime_Sun, 0).
-define(wxDateTime_Mon, 1).
@@ -579,7 +575,6 @@
-define(wxDateTime_Monday_First, 1).
-define(wxDateTime_Sunday_First, 2).
% From class wxDateTime::Year
--define(wxDateTime_Inv_Year, ?SHRT_MIN).
% From class wxDialog
-define(wxDialog_ButtonSizerFlags, (?wxOK bor ?wxCANCEL bor ?wxYES bor ?wxNO bor ?wxHELP bor ?wxNO_DEFAULT)).
% From class wxGrid
@@ -760,6 +755,7 @@
-define(wxCLRP_DEFAULT_STYLE, 0).
-define(wxCLRP_USE_TEXTCTRL, ?wxPB_USE_TEXTCTRL).
-define(wxCLRP_SHOW_LABEL, 8).
+% From "cmndata.h"
% From "cmndata.h": wxPrintBin
-define(wxPRINTBIN_DEFAULT, 0).
-define(wxPRINTBIN_ONLYONE, 1).
@@ -782,6 +778,8 @@
-define(wxC2S_NAME, 1).
% From "confbase.h"
-define(wxCONFIG_CASE_SENSITIVE, 0).
+% From "cpp.h"
+-define(wxEMPTY_PARAMETER_VALUE, ()).
% From "datectrl.h"
-define(wxDP_DEFAULT, 0).
-define(wxDP_SPIN, 1).
@@ -789,7 +787,6 @@
-define(wxDP_SHOWCENTURY, 4).
-define(wxDP_ALLOWNONE, 8).
% From "datetime.h"
--define(wxInvalidDateTime, ?wxDefaultDateTime).
% From "dcbuffer.h"
-define(wxBUFFER_CLIENT_AREA, 2).
-define(wxBUFFER_VIRTUAL_AREA, 1).
@@ -1560,13 +1557,13 @@
% From "event.h"
% From "event.h": Propagation_state
-define(wxEVENT_PROPAGATE_NONE, 0).
--define(wxEVENT_PROPAGATE_MAX, ?INT_MAX).
% From "event.h": wxIdleMode
-define(wxIDLE_PROCESS_ALL, 0).
-define(wxIDLE_PROCESS_SPECIFIED, 1).
% From "event.h": wxUpdateUIMode
-define(wxUPDATE_UI_PROCESS_ALL, 0).
-define(wxUPDATE_UI_PROCESS_SPECIFIED, 1).
+% From "fdrepdlg.h"
% From "fdrepdlg.h": wxFindReplaceDialogStyles
-define(wxFR_REPLACEDIALOG, 1).
-define(wxFR_NOUPDOWN, 2).
@@ -1810,7 +1807,6 @@
-define(wxGA_VERTICAL, ?wxVERTICAL).
-define(wxGA_HORIZONTAL, ?wxHORIZONTAL).
% From "gdicmn.h"
--define(wxGetDisplayDepth, ?wxDisplayDepth).
% From "gdicmn.h": wxBitmapType
-define(wxBITMAP_TYPE_INVALID, 0).
-define(wxBITMAP_TYPE_BMP, 1).
@@ -2091,7 +2087,6 @@
-define(wxLB_TOP, ?wxBK_TOP).
-define(wxLB_DEFAULT, ?wxBK_DEFAULT).
% From "log.h"
--define(wxTRACE_OleCalls, ?wxEmptyString).
-define(wxTraceRefCount, 8).
-define(wxTraceResAlloc, 4).
-define(wxTraceMessages, 2).
@@ -2195,7 +2190,8 @@
-define(wxSYS_COLOUR_MENUHILIGHT, (?wxSYS_COLOUR_BTNHIGHLIGHT+9)).
-define(wxSYS_COLOUR_MENUBAR, (?wxSYS_COLOUR_BTNHIGHLIGHT+10)).
-define(wxSYS_COLOUR_LISTBOXTEXT, (?wxSYS_COLOUR_BTNHIGHLIGHT+11)).
--define(wxSYS_COLOUR_MAX, (?wxSYS_COLOUR_BTNHIGHLIGHT+12)).
+-define(wxSYS_COLOUR_LISTBOXHIGHLIGHTTEXT, (?wxSYS_COLOUR_BTNHIGHLIGHT+12)).
+-define(wxSYS_COLOUR_MAX, (?wxSYS_COLOUR_BTNHIGHLIGHT+13)).
% From "settings.h": wxSystemFeature
-define(wxSYS_CAN_DRAW_FRAME_DECORATIONS, 1).
-define(wxSYS_CAN_ICONIZE_FRAME, 2).
@@ -3797,6 +3793,7 @@
-define(wxRELEASE_NUMBER, wxe_util:get_const(wxRELEASE_NUMBER)).
-define(wxMINOR_VERSION, wxe_util:get_const(wxMINOR_VERSION)).
-define(wxMAJOR_VERSION, wxe_util:get_const(wxMAJOR_VERSION)).
+% From "window.h"
% From "window.h": wxWindowVariant
-define(wxWINDOW_VARIANT_NORMAL, 0).
-define(wxWINDOW_VARIANT_SMALL, 1).
diff --git a/lib/wx/src/Makefile b/lib/wx/src/Makefile
index 777fb7d998..26574ed86f 100644
--- a/lib/wx/src/Makefile
+++ b/lib/wx/src/Makefile
@@ -101,19 +101,19 @@ archive: opt
# ----------------------------------------------------
$(APP_TARGET): $(APP_SRC) ../vsn.mk Makefile
- sed -e 's;%GEN_MODS%;$(GEN_MODS);' $< > [email protected]
- sed -e 's;%VSN%;$(VSN);' [email protected] > $@
+ $(gen_verbose)sed -e 's;%GEN_MODS%;$(GEN_MODS);' $< > [email protected]
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' [email protected] > $@
+ $(V_at)rm [email protected]
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk Makefile
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
# Rules
$(EBIN)/%.beam: $(ESRC)/%.erl $(HEADER_FILES)
- $(ERLC) -W -bbeam $(ERL_FLAGS) $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
+ $(V_ERLC) -W -bbeam $(ERL_FLAGS) $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
$(EBIN)/%.beam: $(EGEN)/%.erl $(HEADER_FILES)
- $(ERLC) -W -bbeam $(ERL_FLAGS) $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
+ $(V_ERLC) -W -bbeam $(ERL_FLAGS) $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
# ----------------------------------------------------
# Release Target
diff --git a/lib/wx/src/gen/gl.erl b/lib/wx/src/gen/gl.erl
index ff381683ee..8a8158c35e 100644
--- a/lib/wx/src/gen/gl.erl
+++ b/lib/wx/src/gen/gl.erl
@@ -1,7 +1,9 @@
+%% -*- coding: utf-8 -*-
+
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -460,7 +462,7 @@ alphaFunc(Func,Ref) ->
%% as (R s0 G s0 B s0 A s0), (R s1 G s1 B s1 A s1) and (R d G d B d A d), respectively. The color specified by {@link gl:blendColor/4} is referred to
%% as (R c G c B c A c). They are understood to have integer values between 0 and (k R k G k B k A), where
%%
-%% k c= 2(m c)-1
+%% k c=2(m c)-1
%%
%% and (m R m G m B m A) is the number of red, green, blue, and alpha bitplanes.
%%
@@ -489,12 +491,12 @@ alphaFunc(Func,Ref) ->
%%
%% In the table,
%%
-%% i= min(A s k A-A d) k/A
+%% i=min(A s k A-A d) k/A
%%
%% To determine the blended RGBA values of a pixel, the system uses the following equations:
%%
%%
-%% R d= min(k R R s s R+R d d R) G d= min(k G G s s G+G d d G) B d= min(k B B s s B+B d d B) A d= min(k A A s s A+A d d A)
+%% R d=min(k R R s s R+R d d R) G d=min(k G G s s G+G d d G) B d=min(k B B s s B+B d d B) A d=min(k A A s s A+A d d A)
%%
%% Despite the apparent precision of the above equations, blending arithmetic is not exactly
%% specified, because blending operates with imprecise integer color values. However, a blend
@@ -503,7 +505,7 @@ alphaFunc(Func,Ref) ->
%% , `Dfactor' is `?GL_ONE_MINUS_SRC_ALPHA', and A s is equal to k A, the equations
%% reduce to simple replacement:
%%
-%% R d= R s G d= G s B d= B s A d= A s
+%% R d=R s G d=G s B d=B s A d=A s
%%
%%
%%
@@ -643,7 +645,7 @@ lineWidth(Width) ->
%% is 0, otherwise these fragments are sent to the frame buffer. Bit zero of `Pattern'
%% is the least significant bit.
%%
-%% Antialiased lines are treated as a sequence of 1*width rectangles for purposes of stippling.
+%% Antialiased lines are treated as a sequence of 1×width rectangles for purposes of stippling.
%% Whether rectangle s is rasterized or not depends on the fragment rule described for
%% aliased lines, counting rectangles rather than groups of fragments.
%%
@@ -690,7 +692,7 @@ polygonMode(Face,Mode) ->
%% When `?GL_POLYGON_OFFSET_FILL', `?GL_POLYGON_OFFSET_LINE', or `?GL_POLYGON_OFFSET_POINT'
%% is enabled, each fragment's `depth' value will be offset after it is interpolated
%% from the `depth' values of the appropriate vertices. The value of the offset is
-%% factor*DZ+r*units, where DZ is a measurement of the change in depth relative to the
+%% factor×DZ+r×units, where DZ is a measurement of the change in depth relative to the
%% screen area of the polygon, and r is the smallest value that is guaranteed to produce
%% a resolvable offset for a given implementation. The offset is added before the depth test
%% is performed and before the value is written into the depth buffer.
@@ -709,10 +711,10 @@ polygonOffset(Factor,Units) ->
%% fragments produced by rasterization, creating a pattern. Stippling is independent of polygon
%% antialiasing.
%%
-%% `Pattern' is a pointer to a 32*32 stipple pattern that is stored in memory just
+%% `Pattern' is a pointer to a 32×32 stipple pattern that is stored in memory just
%% like the pixel data supplied to a {@link gl:drawPixels/5} call with height and `width'
%% both equal to 32, a pixel format of `?GL_COLOR_INDEX', and data type of `?GL_BITMAP'
-%% . That is, the stipple pattern is represented as a 32*32 array of 1-bit color indices
+%% . That is, the stipple pattern is represented as a 32×32 array of 1-bit color indices
%% packed in unsigned bytes. {@link gl:pixelStoref/2} parameters like `?GL_UNPACK_SWAP_BYTES'
%% and `?GL_UNPACK_LSB_FIRST' affect the assembling of the bits into a stipple pattern.
%% Pixel transfer operations (shift, offset, pixel map) are not applied to the stipple image,
@@ -737,10 +739,10 @@ polygonStipple(Mask) ->
%% @doc Return the polygon stipple pattern
%%
-%% ``gl:getPolygonStipple'' returns to `Pattern' a 32*32 polygon stipple pattern.
+%% ``gl:getPolygonStipple'' returns to `Pattern' a 32×32 polygon stipple pattern.
%% The pattern is packed into memory as if {@link gl:readPixels/7} with both `height'
%% and `width' of 32, `type' of `?GL_BITMAP', and `format' of `?GL_COLOR_INDEX'
-%% were called, and the stipple pattern were stored in an internal 32*32 color index buffer.
+%% were called, and the stipple pattern were stored in an internal 32×32 color index buffer.
%% Unlike {@link gl:readPixels/7} , however, pixel transfer operations (shift, offset, pixel
%% map) are not applied to the returned stipple image.
%%
@@ -2635,7 +2637,7 @@ loadIdentity() ->
%% and `M' points to an array of 16 single- or double-precision floating-point values
%% m={m[0] m[1] ... m[15]}, then the modelview transformation M(v) does the following:
%%
-%% M(v)=(m[0] m[4] m[8] m[12] m[1] m[5] m[9] m[13] m[2] m[6] m[10] m[14] m[3] m[7] m[11] m[15])*(v[0] v[1] v[2] v[3])
+%% M(v)=(m[0] m[4] m[8] m[12] m[1] m[5] m[9] m[13] m[2] m[6] m[10] m[14] m[3] m[7] m[11] m[15])×(v[0] v[1] v[2] v[3])
%%
%% Projection and texture transformations are similarly defined.
%%
@@ -2687,7 +2689,7 @@ multMatrixf({M1,M2,M3,M4,M5,M6,M7,M8,M9,M10,M11,M12}) ->
%% (x 2(1-c)+c x y(1-c)-z s x z(1-c)+y s 0 y x(1-c)+z s y 2(1-c)+c y z(1-c)-x s 0 x z(1-c)-y s y z(1-c)+x s z 2(1-c)+c 0 0 0 0
%% 1)
%%
-%% Where c= cos(angle), s= sin(angle), and ||(x y z)||= 1 (if not, the GL will normalize this vector).
+%% Where c=cos(angle), s=sin(angle), and ||(x y z)||=1 (if not, the GL will normalize this vector).
%%
%% If the matrix mode is either `?GL_MODELVIEW' or `?GL_PROJECTION', all objects
%% drawn after ``gl:rotate'' is called are rotated. Use {@link gl:pushMatrix/0} and {@link gl:pushMatrix/0}
@@ -3814,7 +3816,7 @@ rasterPos4sv({X,Y,Z,W}) -> rasterPos4s(X,Y,Z,W).
%% ``gl:rect'' supports efficient specification of rectangles as two corner points. Each
%% rectangle command takes four arguments, organized either as two consecutive pairs of (x y)
%% coordinates or as two pointers to arrays, each containing an (x y) pair. The resulting rectangle
-%% is defined in the z= 0 plane.
+%% is defined in the z=0 plane.
%%
%% ``gl:rect''( `X1' , `Y1' , `X2' , `Y2' ) is exactly equivalent to the
%% following sequence: glBegin(`?GL_POLYGON'); glVertex2( `X1' , `Y1' ); glVertex2(
@@ -4684,9 +4686,9 @@ pixelZoom(Xfactor,Yfactor) ->
%% is the number of pixels in a row (`?GL_PACK_ROW_LENGTH' if it is greater than 0,
%% the width argument to the pixel routine otherwise), a is the value of `?GL_PACK_ALIGNMENT'
%% , and s is the size, in bytes, of a single component (if a&lt; s, then it is as if a=
-%% s). In the case of 1-bit values, the location of the next row is obtained by skipping
+%% s). In the case of 1-bit values, the location of the next row is obtained by skipping
%%
-%% k= 8 a |(n l)/(8 a)|
+%% k=8 a |(n l)/(8 a)|
%%
%% components or indices.
%%
@@ -4708,7 +4710,7 @@ pixelZoom(Xfactor,Yfactor) ->
%% a pixel image (`?GL_PACK_IMAGE_HEIGHT' if it is greater than 0, the height argument
%% to the {@link gl:texImage3D/10} routine otherwise), a is the value of `?GL_PACK_ALIGNMENT'
%% , and s is the size, in bytes, of a single component (if a&lt; s, then it is as if
-%% a= s).
+%% a=s).
%%
%% The word `component' in this description refers to the nonindex values red, green,
%% blue, alpha, and depth. Storage format `?GL_RGB', for example, has three components
@@ -4758,9 +4760,9 @@ pixelZoom(Xfactor,Yfactor) ->
%% is the number of pixels in a row (`?GL_UNPACK_ROW_LENGTH' if it is greater than 0,
%% the width argument to the pixel routine otherwise), a is the value of `?GL_UNPACK_ALIGNMENT'
%% , and s is the size, in bytes, of a single component (if a&lt; s, then it is as if a=
-%% s). In the case of 1-bit values, the location of the next row is obtained by skipping
+%% s). In the case of 1-bit values, the location of the next row is obtained by skipping
%%
-%% k= 8 a |(n l)/(8 a)|
+%% k=8 a |(n l)/(8 a)|
%%
%% components or indices.
%%
@@ -4781,8 +4783,8 @@ pixelZoom(Xfactor,Yfactor) ->
%% the width argument to {@link gl:texImage3D/10} otherwise), h is the number of rows in
%% an image (`?GL_UNPACK_IMAGE_HEIGHT' if it is greater than 0, the height argument
%% to {@link gl:texImage3D/10} otherwise), a is the value of `?GL_UNPACK_ALIGNMENT',
-%% and s is the size, in bytes, of a single component (if a&lt; s, then it is as if a=
-%% s).
+%% and s is the size, in bytes, of a single component (if a&lt; s, then it is as if a=s).
+%%
%%
%% The word `component' in this description refers to the nonindex values red, green,
%% blue, alpha, and depth. Storage format `?GL_RGB', for example, has three components
@@ -5327,7 +5329,7 @@ readPixels(X,Y,Width,Height,Format,Type,Pixels) ->
%% or `?GL_STENCIL_INDEX'. Each unsigned byte is treated as eight 1-bit pixels, with
%% bit ordering determined by `?GL_UNPACK_LSB_FIRST' (see {@link gl:pixelStoref/2} ).
%%
-%% width*height pixels are read from memory, starting at location `Data' . By default,
+%% width×height pixels are read from memory, starting at location `Data' . By default,
%% these pixels are taken from adjacent memory locations, except that after all `Width'
%% pixels are read, the read pointer is advanced to the next four-byte boundary. The four-byte
%% row alignment is specified by {@link gl:pixelStoref/2} with argument `?GL_UNPACK_ALIGNMENT'
@@ -5340,7 +5342,7 @@ readPixels(X,Y,Width,Height,Format,Type,Pixels) ->
%% (see {@link gl:bindBuffer/2} ) while a block of pixels is specified, `Data' is treated
%% as a byte offset into the buffer object's data store.
%%
-%% The width*height pixels that are read from memory are each operated on in the same
+%% The width×height pixels that are read from memory are each operated on in the same
%% way, based on the values of several parameters specified by {@link gl:pixelTransferf/2}
%% and {@link gl:pixelMapfv/3} . The details of these operations, as well as the target buffer
%% into which the pixels are drawn, are specific to the format of the pixels, as specified
@@ -5366,10 +5368,10 @@ readPixels(X,Y,Width,Height,Format,Type,Pixels) ->
%%
%% The GL then converts the resulting indices or RGBA colors to fragments by attaching the
%% current raster position `z' coordinate and texture coordinates to each pixel, then
-%% assigning x and y window coordinates to the nth fragment such that x n= x r+n%
-%% width
+%% assigning x and y window coordinates to the nth fragment such that x n=x r+n% width
+%%
%%
-%% y n= y r+|n/width|
+%% y n=y r+|n/width|
%%
%% where (x r y r) is the current raster position. These pixel fragments are then treated just like
%% the fragments generated by rasterizing points, lines, or polygons. Texture mapping, fog,
@@ -5391,9 +5393,9 @@ readPixels(X,Y,Width,Height,Format,Type,Pixels) ->
%% the number of bits in the stencil buffer. The resulting stencil indices are then written
%% to the stencil buffer such that the nth index is written to location
%%
-%% x n= x r+n% width
+%% x n=x r+n% width
%%
-%% y n= y r+|n/width|
+%% y n=y r+|n/width|
%%
%% where (x r y r) is the current raster position. Only the pixel ownership test, the scissor test,
%% and the stencil writemask affect these write operations.
@@ -5411,9 +5413,9 @@ readPixels(X,Y,Width,Height,Format,Type,Pixels) ->
%% raster position color or color index and texture coordinates to each pixel, then assigning
%% x and y window coordinates to the nth fragment such that
%%
-%% x n= x r+n% width
+%% x n=x r+n% width
%%
-%% y n= y r+|n/width|
+%% y n=y r+|n/width|
%%
%% where (x r y r) is the current raster position. These pixel fragments are then treated just like
%% the fragments generated by rasterizing points, lines, or polygons. Texture mapping, fog,
@@ -5442,9 +5444,9 @@ readPixels(X,Y,Width,Height,Format,Type,Pixels) ->
%% raster position `z' coordinate and texture coordinates to each pixel, then assigning
%% x and y window coordinates to the nth fragment such that
%%
-%% x n= x r+n% width
+%% x n=x r+n% width
%%
-%% y n= y r+|n/width|
+%% y n=y r+|n/width|
%%
%% where (x r y r) is the current raster position. These pixel fragments are then treated just like
%% the fragments generated by rasterizing points, lines, or polygons. Texture mapping, fog,
@@ -5810,7 +5812,7 @@ clearStencil(S) ->
%%
%% If the texture generation function is `?GL_OBJECT_LINEAR', the function
%%
-%% g= p 1*x o+p 2*y o+p 3*z o+p 4*w o
+%% g=p 1×x o+p 2×y o+p 3×z o+p 4×w o
%%
%% is used, where g is the value computed for the coordinate named in `Coord' , p 1,
%% p 2, p 3, and p 4 are the four values supplied in `Params' , and x o, y o, z o,
@@ -5823,7 +5825,7 @@ clearStencil(S) ->
%%
%% If the texture generation function is `?GL_EYE_LINEAR', the function
%%
-%% g=(p 1)"*x e+(p 2)"*y e+(p 3)"*z e+(p 4)"*w e
+%% g=(p 1)"×x e+(p 2)"×y e+(p 3)"×z e+(p 4)"×w e
%%
%% is used, where
%%
@@ -5847,14 +5849,14 @@ clearStencil(S) ->
%%
%% f=(f x f y f z) T be the reflection vector such that
%%
-%% f= u-2 n" (n") T u
+%% f=u-2 n" (n") T u
%%
-%% Finally, let m= 2 ((f x) 2+(f y) 2+(f z+1) 2). Then the values assigned to the s and t texture coordinates
+%% Finally, let m=2 ((f x) 2+(f y) 2+(f z+1) 2). Then the values assigned to the s and t texture coordinates
%% are
%%
-%% s= f x/m+1/2
+%% s=f x/m+1/2
%%
-%% t= f y/m+1/2
+%% t=f y/m+1/2
%%
%% To enable or disable a texture-coordinate generation function, call {@link gl:enable/1}
%% or {@link gl:enable/1} with one of the symbolic texture-coordinate names (`?GL_TEXTURE_GEN_S'
@@ -6002,7 +6004,7 @@ texEnvi(Target,Pname,Param) ->
%% `?GL_BLEND' Function </td><td>`?GL_ADD' Function </td></tr></tbody><tbody><tr><td>
%% `?GL_ALPHA'</td><td> C v=</td><td> C p</td><td> C p</td><td> undefined </td><td> C p</td>
%% <td> C p</td></tr><tr><td></td><td> A v=</td><td> A s</td><td> A p A s</td><td></td><td>
-%% A v= A p A s</td><td> A p A s</td></tr><tr><td>`?GL_LUMINANCE'</td><td> C v=</td><td>
+%% A v=A p A s</td><td> A p A s</td></tr><tr><td>`?GL_LUMINANCE'</td><td> C v=</td><td>
%% C s</td><td> C p C s</td><td> undefined </td><td> C p (1-C s)+C c C s</td><td> C p+C s</td></tr>
%% <tr><td> (or 1) </td><td> A v=</td><td> A p</td><td> A p</td><td></td><td> A p</td><td> A
%% p</td></tr><tr><td>`?GL_LUMINANCE_ALPHA'</td><td> C v=</td><td> C s</td><td> C p C
@@ -6034,11 +6036,11 @@ texEnvi(Target,Pname,Param) ->
%%
%% <table><tbody><tr><td>`?GL_COMBINE_RGB'</td><td>` Texture Function '</td></tr></tbody>
%% <tbody><tr><td>`?GL_REPLACE'</td><td> Arg0</td></tr><tr><td>`?GL_MODULATE'</td><td>
-%% Arg0*Arg1</td></tr><tr><td>`?GL_ADD'</td><td> Arg0+Arg1</td></tr><tr><td>`?GL_ADD_SIGNED'
-%% </td><td> Arg0+Arg1-0.5</td></tr><tr><td>`?GL_INTERPOLATE'</td><td> Arg0*Arg2+Arg1*(1-
+%% Arg0×Arg1</td></tr><tr><td>`?GL_ADD'</td><td> Arg0+Arg1</td></tr><tr><td>`?GL_ADD_SIGNED'
+%% </td><td> Arg0+Arg1-0.5</td></tr><tr><td>`?GL_INTERPOLATE'</td><td> Arg0×Arg2+Arg1×(1-
%% Arg2)</td>
%% </tr><tr><td>`?GL_SUBTRACT'</td><td> Arg0-Arg1</td></tr><tr><td>`?GL_DOT3_RGB'
-%% or `?GL_DOT3_RGBA'</td><td> 4*((((Arg0 r)-0.5)*((Arg1 r)-0.5))+(((Arg0 g)-0.5)*((Arg1 g)-0.5))+(((Arg0 b)-0.5)*((Arg1 b)-0.5)))</td></tr></tbody></table>
+%% or `?GL_DOT3_RGBA'</td><td> 4×((((Arg0 r)-0.5)×((Arg1 r)-0.5))+(((Arg0 g)-0.5)×((Arg1 g)-0.5))+(((Arg0 b)-0.5)×((Arg1 b)-0.5)))</td></tr></tbody></table>
%%
%% The scalar results for `?GL_DOT3_RGB' and `?GL_DOT3_RGBA' are placed into each
%% of the 3 (RGB) or 4 (RGBA) components on output.
@@ -6049,8 +6051,8 @@ texEnvi(Target,Pname,Param) ->
%%
%% <table><tbody><tr><td>`?GL_COMBINE_ALPHA'</td><td>` Texture Function '</td></tr>
%% </tbody><tbody><tr><td>`?GL_REPLACE'</td><td> Arg0</td></tr><tr><td>`?GL_MODULATE'
-%% </td><td> Arg0*Arg1</td></tr><tr><td>`?GL_ADD'</td><td> Arg0+Arg1</td></tr><tr><td>`?GL_ADD_SIGNED'
-%% </td><td> Arg0+Arg1-0.5</td></tr><tr><td>`?GL_INTERPOLATE'</td><td> Arg0*Arg2+Arg1*(1-
+%% </td><td> Arg0×Arg1</td></tr><tr><td>`?GL_ADD'</td><td> Arg0+Arg1</td></tr><tr><td>`?GL_ADD_SIGNED'
+%% </td><td> Arg0+Arg1-0.5</td></tr><tr><td>`?GL_INTERPOLATE'</td><td> Arg0×Arg2+Arg1×(1-
%% Arg2)</td>
%% </tr><tr><td>`?GL_SUBTRACT'</td><td> Arg0-Arg1</td></tr></tbody></table>
%%
@@ -6245,19 +6247,18 @@ getTexEnviv(Target,Pname) ->
%% If the values for `?GL_TEXTURE_BORDER_COLOR' are specified with ``gl:texParameterIiv''
%% or ``gl:texParameterIuiv'', the values are stored unmodified with an internal data
%% type of integer. If specified with ``gl:texParameteriv'', they are converted to floating
-%% point with the following equation: f= 2 c+1 2 b-/1. If specified with ``gl:texParameterfv''
+%% point with the following equation: f=2 c+1 2 b-/1. If specified with ``gl:texParameterfv''
%% , they are stored unmodified as floating-point values.
%%
%% `?GL_TEXTURE_COMPARE_FUNC': Specifies the comparison operator used when `?GL_TEXTURE_COMPARE_MODE'
%% is set to `?GL_COMPARE_REF_TO_TEXTURE'. Permissible values are: <table><tbody><tr><td>
%% ` Texture Comparison Function '</td><td>` Computed result '</td></tr></tbody><tbody>
-%% <tr><td>`?GL_LEQUAL'</td><td> result={1.0 0.0 &amp;nbsp;&amp;nbsp; r&lt;=(D t) r&gt;(D t))</td></tr><tr><td>`?GL_GEQUAL'</td><td>
-%% result={1.0 0.0 &amp;nbsp;&amp;nbsp; r&gt;=(D t) r&lt;(D t))</td></tr><tr><td>`?GL_LESS'</td><td> result={1.0 0.0 &amp;nbsp;&amp;nbsp; r&lt;
-%% (D t) r&gt;=(D t))</td></tr><tr><td>`?GL_GREATER'
-%% </td><td> result={1.0 0.0 &amp;nbsp;&amp;nbsp; r&gt;(D t) r&lt;=(D t))</td></tr><tr><td>`?GL_EQUAL'</td><td> result={1.0 0.0 &amp;nbsp;&amp;nbsp;
-%% r=(D t) r&amp;ne;(D t))</td></tr><tr><td>`?GL_NOTEQUAL'
-%% </td><td> result={1.0 0.0 &amp;nbsp;&amp;nbsp; r&amp;ne;(D t) r=(D t))</td></tr><tr><td>`?GL_ALWAYS'</td><td> result= 1.0</td></tr><tr><td>
-%% `?GL_NEVER'</td><td> result= 0.0</td></tr></tbody></table> where r is the current
+%% <tr><td>`?GL_LEQUAL'</td><td> result={1.0 0.0 r&lt;=(D t) r&gt;(D t))</td></tr><tr><td>`?GL_GEQUAL'</td><td>
+%% result={1.0 0.0 r&gt;=(D t) r&lt;(D t))</td></tr><tr><td>`?GL_LESS'</td><td> result={1.0 0.0 r&lt;(D t) r&gt;=(D t))</td></tr><tr><td>`?GL_GREATER'
+%% </td><td> result={1.0 0.0 r&gt;(D t) r&lt;=(D t))</td></tr><tr><td>`?GL_EQUAL'</td><td> result={1.0 0.0 r=(D t) r&amp;ne;
+%% (D t))</td></tr><tr><td>`?GL_NOTEQUAL'
+%% </td><td> result={1.0 0.0 r&amp;ne;(D t) r=(D t))</td></tr><tr><td>`?GL_ALWAYS'</td><td> result=1.0</td></tr><tr><td>
+%% `?GL_NEVER'</td><td> result=0.0</td></tr></tbody></table> where r is the current
%% interpolated texture coordinate, and D t is the depth texture value sampled from the
%% currently bound depth texture. result is assigned to the the red channel.
%%
@@ -6286,14 +6287,14 @@ getTexEnviv(Target,Pname) ->
%% The other four use mipmaps.
%%
%% A mipmap is an ordered set of arrays representing the same image at progressively lower
-%% resolutions. If the texture has dimensions 2 n*2 m, there are max(n m)+1 mipmaps. The first
-%% mipmap is the original texture, with dimensions 2 n*2 m. Each subsequent mipmap has
-%% dimensions 2(k-1)*2(l-1), where 2 k*2 l are the dimensions of the previous mipmap, until either
-%% k= 0 or l= 0. At that point, subsequent mipmaps have dimension 1*2(l-1) or 2(k-1)*1 until
-%% the final mipmap, which has dimension 1*1. To define the mipmaps, call {@link gl:texImage1D/8}
+%% resolutions. If the texture has dimensions 2 n×2 m, there are max(n m)+1 mipmaps. The first
+%% mipmap is the original texture, with dimensions 2 n×2 m. Each subsequent mipmap has
+%% dimensions 2(k-1)×2(l-1), where 2 k×2 l are the dimensions of the previous mipmap, until either
+%% k=0 or l=0. At that point, subsequent mipmaps have dimension 1×2(l-1) or 2(k-1)×1 until
+%% the final mipmap, which has dimension 1×1. To define the mipmaps, call {@link gl:texImage1D/8}
%% , {@link gl:texImage2D/9} , {@link gl:texImage3D/10} , {@link gl:copyTexImage1D/7} , or {@link gl:copyTexImage2D/8}
%% with the `level' argument indicating the order of the mipmaps. Level 0 is the original
-%% texture; level max(n m) is the final 1*1 mipmap.
+%% texture; level max(n m) is the final 1×1 mipmap.
%%
%% `Params' supplies a function for minifying the texture as one of the following:
%%
@@ -7255,7 +7256,7 @@ map2f(Target,U1,U2,Ustride,Uorder,V1,V2,Vstride,Vorder,Points) ->
%% `Query' can assume the following values:
%%
%% `?GL_COEFF': `V' returns the control points for the evaluator function. One-dimensional
-%% evaluators return order control points, and two-dimensional evaluators return uorder*vorder
+%% evaluators return order control points, and two-dimensional evaluators return uorder×vorder
%% control points. Each control point consists of one, two, three, or four integer, single-precision
%% floating-point, or double-precision floating-point values, depending on the type of the
%% evaluator. The GL returns two-dimensional control points in row-major order, incrementing
@@ -7330,9 +7331,9 @@ getMapiv(Target,Query,V) ->
%% `?GL_AUTO_NORMAL', ``gl:evalCoord2'' generates surface normals analytically, regardless
%% of the contents or enabling of the `?GL_MAP2_NORMAL' map. Let
%%
-%% m=((&amp;PartialD; p)/(&amp;PartialD; u))*((&amp;PartialD; p)/(&amp;PartialD; v))
+%% m=((&amp;PartialD; p)/(&amp;PartialD; u))×((&amp;PartialD; p)/(&amp;PartialD; v))
%%
-%% Then the generated normal n is n= m/(||m||)
+%% Then the generated normal n is n=m/(||m||)
%%
%% If automatic normal generation is disabled, the corresponding normal map `?GL_MAP2_NORMAL'
%% , if enabled, is used to produce a normal. If neither automatic normal generation nor
@@ -7393,17 +7394,17 @@ evalCoord2fv({U,V}) -> evalCoord2f(U,V).
%% 0 maps exactly to `U1' , and integer grid coordinate `Un' maps exactly to `U2'
%% . All other integer grid coordinates i are mapped so that
%%
-%% u= i(u2-u1)/un+u1
+%% u=i(u2-u1)/un+u1
%%
%% ``gl:mapGrid2'' specifies two such linear mappings. One maps integer grid coordinate
-%% i= 0 exactly to `U1' , and integer grid coordinate i= un exactly to `U2' . The
-%% other maps integer grid coordinate j= 0 exactly to `V1' , and integer grid coordinate
-%% j= vn exactly to `V2' . Other integer grid coordinates i and j are mapped such
+%% i=0 exactly to `U1' , and integer grid coordinate i=un exactly to `U2' . The
+%% other maps integer grid coordinate j=0 exactly to `V1' , and integer grid coordinate
+%% j=vn exactly to `V2' . Other integer grid coordinates i and j are mapped such
%% that
%%
-%% u= i(u2-u1)/un+u1
+%% u=i(u2-u1)/un+u1
%%
-%% v= j(v2-v1)/vn+v1
+%% v=j(v2-v1)/vn+v1
%%
%% The mappings specified by ``gl:mapGrid'' are used identically by {@link gl:evalMesh1/3}
%% and {@link gl:evalPoint1/1} .
@@ -7440,7 +7441,7 @@ mapGrid2f(Un,U1,U2,Vn,V1,V2) ->
%% 1 ); where &amp;Delta; u=(u 2-u 1)/n
%%
%% and n, u 1, and u 2 are the arguments to the most recent {@link gl:mapGrid1d/3} command.
-%% The one absolute numeric requirement is that if i= n, then the value computed from i.&amp;Delta;
+%% The one absolute numeric requirement is that if i=n, then the value computed from i.&amp;Delta;
%% u+u 1 is exactly u 2.
%%
%% In the two-dimensional case, ``gl:evalPoint2'', let
@@ -7452,8 +7453,8 @@ mapGrid2f(Un,U1,U2,Vn,V1,V2) ->
%% where n, u 1, u 2, m, v 1, and v 2 are the arguments to the most recent {@link gl:mapGrid1d/3}
%% command. Then the ``gl:evalPoint2'' command is equivalent to calling glEvalCoord2( i.
%% &amp;Delta; u+u 1, j.&amp;Delta; v+v 1 ); The only absolute numeric requirements are
-%% that if i= n, then the value computed from i.&amp;Delta; u+u 1 is exactly u 2, and
-%% if j= m, then the value computed from j.&amp;Delta; v+v 1 is exactly v 2.
+%% that if i=n, then the value computed from i.&amp;Delta; u+u 1 is exactly u 2, and
+%% if j=m, then the value computed from j.&amp;Delta; v+v 1 is exactly v 2.
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glEvalPoint.xml">external</a> documentation.
-spec evalPoint1(I) -> ok when I :: integer().
@@ -7486,8 +7487,8 @@ evalPoint2(I,J) ->
%% `type' is `?GL_POINTS' if `Mode' is `?GL_POINT', or `?GL_LINES'
%% if `Mode' is `?GL_LINE'.
%%
-%% The one absolute numeric requirement is that if i= n, then the value computed from i.
-%% &amp;Delta; u+u 1 is exactly u 2.
+%% The one absolute numeric requirement is that if i=n, then the value computed from i.&amp;Delta;
+%% u+u 1 is exactly u 2.
%%
%% In the two-dimensional case, ``gl:evalMesh2'', let .cp &amp;Delta; u=(u 2-u 1)/n
%%
@@ -7516,8 +7517,8 @@ evalPoint2(I,J) ->
%% ; i &lt;= `I2' ; i += 1 ) glEvalCoord2( i.&amp;Delta; u+u 1, j.&amp;Delta; v+v 1
%% ); glEnd();
%%
-%% In all three cases, the only absolute numeric requirements are that if i= n, then the
-%% value computed from i.&amp;Delta; u+u 1 is exactly u 2, and if j= m, then the value
+%% In all three cases, the only absolute numeric requirements are that if i=n, then the
+%% value computed from i.&amp;Delta; u+u 1 is exactly u 2, and if j=m, then the value
%% computed from j.&amp;Delta; v+v 1 is exactly v 2.
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glEvalMesh.xml">external</a> documentation.
@@ -7578,21 +7579,21 @@ evalMesh2(Mode,I1,I2,J1,J2) ->
%% (in the case that `?GL_FOG_COORD_SRC' is `?GL_FOG_COORD'). The equation for `?GL_LINEAR'
%% fog is f=(end-c)/(end-start)
%%
-%% The equation for `?GL_EXP' fog is f= e(-(density. c))
+%% The equation for `?GL_EXP' fog is f=e(-(density. c))
%%
-%% The equation for `?GL_EXP2' fog is f= e(-(density. c)) 2
+%% The equation for `?GL_EXP2' fog is f=e(-(density. c)) 2
%%
%% Regardless of the fog mode, f is clamped to the range [0 1] after it is computed. Then,
%% if the GL is in RGBA color mode, the fragment's red, green, and blue colors, represented
%% by C r, are replaced by
%%
-%% (C r)"= f*C r+(1-f)*C f
+%% (C r)"=f×C r+(1-f)×C f
%%
%% Fog does not affect a fragment's alpha component.
%%
%% In color index mode, the fragment's color index i r is replaced by
%%
-%% (i r)"= i r+(1-f)*i f
+%% (i r)"=i r+(1-f)×i f
%%
%%
%%
@@ -7664,44 +7665,45 @@ fogiv(Pname,Params) ->
%% is fed back as some number of floating-point values, as determined by `Type' . Colors
%% are fed back as four values in RGBA mode and one value in color index mode.
%%
-%% feedbackList feedbackItem feedbackList | feedbackItem
+%% feedbackList ← feedbackItem feedbackList | feedbackItem
%%
-%% feedbackItem point | lineSegment | polygon | bitmap | pixelRectangle | passThru
+%% feedbackItem ← point | lineSegment | polygon | bitmap | pixelRectangle | passThru
%%
-%% point `?GL_POINT_TOKEN' vertex
+%% point ←`?GL_POINT_TOKEN' vertex
%%
-%% lineSegment `?GL_LINE_TOKEN' vertex vertex | `?GL_LINE_RESET_TOKEN' vertex
+%% lineSegment ←`?GL_LINE_TOKEN' vertex vertex | `?GL_LINE_RESET_TOKEN' vertex
%% vertex
%%
-%% polygon `?GL_POLYGON_TOKEN' n polySpec
+%% polygon ←`?GL_POLYGON_TOKEN' n polySpec
%%
-%% polySpec polySpec vertex | vertex vertex vertex
+%% polySpec ← polySpec vertex | vertex vertex vertex
%%
-%% bitmap `?GL_BITMAP_TOKEN' vertex
+%% bitmap ←`?GL_BITMAP_TOKEN' vertex
%%
-%% pixelRectangle `?GL_DRAW_PIXEL_TOKEN' vertex | `?GL_COPY_PIXEL_TOKEN' vertex
+%% pixelRectangle ←`?GL_DRAW_PIXEL_TOKEN' vertex | `?GL_COPY_PIXEL_TOKEN' vertex
+%%
%%
-%% passThru `?GL_PASS_THROUGH_TOKEN' value
+%% passThru ←`?GL_PASS_THROUGH_TOKEN' value
%%
-%% vertex 2d | 3d | 3dColor | 3dColorTexture | 4dColorTexture
+%% vertex ← 2d | 3d | 3dColor | 3dColorTexture | 4dColorTexture
%%
-%% 2d value value
+%% 2d ← value value
%%
-%% 3d value value value
+%% 3d ← value value value
%%
-%% 3dColor value value value color
+%% 3dColor ← value value value color
%%
-%% 3dColorTexture value value value color tex
+%% 3dColorTexture ← value value value color tex
%%
-%% 4dColorTexture value value value value color tex
+%% 4dColorTexture ← value value value value color tex
%%
-%% color rgba | index
+%% color ← rgba | index
%%
-%% rgba value value value value
+%% rgba ← value value value value
%%
-%% index value
+%% index ← value
%%
-%% tex value value value value
+%% tex ← value value value value
%%
%% `value' is a floating-point number, and `n' is a floating-point integer giving
%% the number of vertices in the polygon. `?GL_POINT_TOKEN', `?GL_LINE_TOKEN', `?GL_LINE_RESET_TOKEN'
@@ -7886,13 +7888,13 @@ blendColor(Red,Green,Blue,Alpha) ->
%% blend factors are denoted (s R s G s B s A) and (d R d G d B d A), respectively. For these equations all color components
%% are understood to have values in the range [0 1]. <table><tbody><tr><td>` Mode '</td><td>
%% ` RGB Components '</td><td>` Alpha Component '</td></tr></tbody><tbody><tr><td>`?GL_FUNC_ADD'
-%% </td><td> Rr= R s s R+R d d R Gr= G s s G+G d d G Br= B s s B+B d d B</td><td> Ar=
-%% A s s A+A d d A</td></tr><tr><td>`?GL_FUNC_SUBTRACT'</td><td> Rr= R s s R-R d d
-%% R Gr= G s s G-G d d G Br= B s s B-B d d B</td><td> Ar= A s s A-A d d A</td></tr><tr>
-%% <td>`?GL_FUNC_REVERSE_SUBTRACT'</td><td> Rr= R d d R-R s s R Gr= G d d G-G s s G
-%% Br= B d d B-B s s B</td><td> Ar= A d d A-A s s A</td></tr><tr><td>`?GL_MIN'</td><td>
-%% Rr= min(R s R d) Gr= min(G s G d) Br= min(B s B d)</td><td> Ar= min(A s A d)</td></tr><tr><td>`?GL_MAX'</td><td> Rr=
-%% max(R s R d) Gr= max(G s G d) Br= max(B s B d)</td><td> Ar= max(A s A d)</td></tr></tbody></table>
+%% </td><td> Rr=R s s R+R d d R Gr=G s s G+G d d G Br=B s s B+B d d B</td><td> Ar=A s
+%% s A+A d d A</td></tr><tr><td>`?GL_FUNC_SUBTRACT'</td><td> Rr=R s s R-R d d R Gr=G
+%% s s G-G d d G Br=B s s B-B d d B</td><td> Ar=A s s A-A d d A</td></tr><tr><td>`?GL_FUNC_REVERSE_SUBTRACT'
+%% </td><td> Rr=R d d R-R s s R Gr=G d d G-G s s G Br=B d d B-B s s B</td><td> Ar=A d
+%% d A-A s s A</td></tr><tr><td>`?GL_MIN'</td><td> Rr=min(R s R d) Gr=min(G s G d) Br=min(B s B d)</td><td> Ar=min
+%% (A s A d)</td></tr><tr><td>`?GL_MAX'</td><td> Rr=max(R s R d) Gr=max(G s G d) Br=max(B s B d)</td><td> Ar=max(A s A d)</td></tr></tbody>
+%% </table>
%%
%% The results of these equations are clamped to the range [0 1].
%%
@@ -9062,7 +9064,7 @@ sampleCoverage(Value,Invert) ->
%%
%% `ImageSize' must be equal to:
%%
-%% b s*|width b/w|*|height b/h|*|depth b/d|
+%% b s×|width b/w|×|height b/h|×|depth b/d|
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glCompressedTexImage3D.xml">external</a> documentation.
-spec compressedTexImage3D(Target, Level, Internalformat, Width, Height, Depth, Border, ImageSize, Data) -> ok when Target :: enum(),Level :: integer(),Internalformat :: enum(),Width :: integer(),Height :: integer(),Depth :: integer(),Border :: integer(),ImageSize :: integer(),Data :: offset()|mem().
@@ -9124,7 +9126,7 @@ compressedTexImage3D(Target,Level,Internalformat,Width,Height,Depth,Border,Image
%%
%% `ImageSize' must be equal to:
%%
-%% b s*|width b/w|*|height b/h|
+%% b s×|width b/w|×|height b/h|
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glCompressedTexImage2D.xml">external</a> documentation.
-spec compressedTexImage2D(Target, Level, Internalformat, Width, Height, Border, ImageSize, Data) -> ok when Target :: enum(),Level :: integer(),Internalformat :: enum(),Width :: integer(),Height :: integer(),Border :: integer(),ImageSize :: integer(),Data :: offset()|mem().
@@ -9181,7 +9183,7 @@ compressedTexImage2D(Target,Level,Internalformat,Width,Height,Border,ImageSize,D
%%
%% `ImageSize' must be equal to:
%%
-%% b s*|width b/w|
+%% b s×|width b/w|
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glCompressedTexImage1D.xml">external</a> documentation.
-spec compressedTexImage1D(Target, Level, Internalformat, Width, Border, ImageSize, Data) -> ok when Target :: enum(),Level :: integer(),Internalformat :: enum(),Width :: integer(),Border :: integer(),ImageSize :: integer(),Data :: offset()|mem().
@@ -9502,7 +9504,7 @@ multiTexCoord4sv(Target,{S,T,R,Q}) -> multiTexCoord4s(Target,S,T,R,Q).
%% and `M' points to an array of 16 single- or double-precision floating-point values
%% m={m[0] m[1] ... m[15]}, then the modelview transformation M(v) does the following:
%%
-%% M(v)=(m[0] m[1] m[2] m[3] m[4] m[5] m[6] m[7] m[8] m[9] m[10] m[11] m[12] m[13] m[14] m[15])*(v[0] v[1] v[2] v[3])
+%% M(v)=(m[0] m[1] m[2] m[3] m[4] m[5] m[6] m[7] m[8] m[9] m[10] m[11] m[12] m[13] m[14] m[15])×(v[0] v[1] v[2] v[3])
%%
%% Projection and texture transformations are similarly defined.
%%
@@ -9569,7 +9571,7 @@ multTransposeMatrixd({M1,M2,M3,M4,M5,M6,M7,M8,M9,M10,M11,M12}) ->
%% is referred to as (R c G c B c A c). They are understood to have integer values between 0 and (k R k G k B
%% k A), where
%%
-%% k c= 2(m c)-1
+%% k c=2(m c)-1
%%
%% and (m R m G m B m A) is the number of red, green, blue, and alpha bitplanes.
%%
@@ -9601,12 +9603,12 @@ multTransposeMatrixd({M1,M2,M3,M4,M5,M6,M7,M8,M9,M10,M11,M12}) ->
%%
%% In the table,
%%
-%% i= min(A s 1-(A d))
+%% i=min(A s 1-(A d))
%%
%% To determine the blended RGBA values of a pixel, the system uses the following equations:
%%
%%
-%% R d= min(k R R s s R+R d d R) G d= min(k G G s s G+G d d G) B d= min(k B B s s B+B d d B) A d= min(k A A s s A+A d d A)
+%% R d=min(k R R s s R+R d d R) G d=min(k G G s s G+G d d G) B d=min(k B B s s B+B d d B) A d=min(k A A s s A+A d d A)
%%
%% Despite the apparent precision of the above equations, blending arithmetic is not exactly
%% specified, because blending operates with imprecise integer color values. However, a blend
@@ -9615,7 +9617,7 @@ multTransposeMatrixd({M1,M2,M3,M4,M5,M6,M7,M8,M9,M10,M11,M12}) ->
%% , `DstRGB' is `?GL_ONE_MINUS_SRC_ALPHA', and A s is equal to k A, the equations
%% reduce to simple replacement:
%%
-%% R d= R s G d= G s B d= B s A d= A s
+%% R d=R s G d=G s B d=B s A d=A s
%%
%%
%%
@@ -9899,7 +9901,7 @@ secondaryColorPointer(Size,Type,Stride,Pointer) ->
%% current modelview and projection matrices, nor by the viewport-to-window transform. The
%% z coordinate of the current raster position is updated in the following manner:
%%
-%% z={n f(n+z*(f-n)) if z&lt;= 0 if z&gt;= 1(otherwise))
+%% z={n f(n+z×(f-n)) if z&lt;= 0 if z&gt;= 1(otherwise))
%%
%% where n is `?GL_DEPTH_RANGE''s near value, and f is `?GL_DEPTH_RANGE''s
%% far value. See {@link gl:depthRange/2} .
@@ -10397,13 +10399,13 @@ getBufferParameteriv(Target,Pname) ->
%% blend factors are denoted (s R s G s B s A) and (d R d G d B d A), respectively. For these equations all color components
%% are understood to have values in the range [0 1]. <table><tbody><tr><td>` Mode '</td><td>
%% ` RGB Components '</td><td>` Alpha Component '</td></tr></tbody><tbody><tr><td>`?GL_FUNC_ADD'
-%% </td><td> Rr= R s s R+R d d R Gr= G s s G+G d d G Br= B s s B+B d d B</td><td> Ar=
-%% A s s A+A d d A</td></tr><tr><td>`?GL_FUNC_SUBTRACT'</td><td> Rr= R s s R-R d d
-%% R Gr= G s s G-G d d G Br= B s s B-B d d B</td><td> Ar= A s s A-A d d A</td></tr><tr>
-%% <td>`?GL_FUNC_REVERSE_SUBTRACT'</td><td> Rr= R d d R-R s s R Gr= G d d G-G s s G
-%% Br= B d d B-B s s B</td><td> Ar= A d d A-A s s A</td></tr><tr><td>`?GL_MIN'</td><td>
-%% Rr= min(R s R d) Gr= min(G s G d) Br= min(B s B d)</td><td> Ar= min(A s A d)</td></tr><tr><td>`?GL_MAX'</td><td> Rr=
-%% max(R s R d) Gr= max(G s G d) Br= max(B s B d)</td><td> Ar= max(A s A d)</td></tr></tbody></table>
+%% </td><td> Rr=R s s R+R d d R Gr=G s s G+G d d G Br=B s s B+B d d B</td><td> Ar=A s
+%% s A+A d d A</td></tr><tr><td>`?GL_FUNC_SUBTRACT'</td><td> Rr=R s s R-R d d R Gr=G
+%% s s G-G d d G Br=B s s B-B d d B</td><td> Ar=A s s A-A d d A</td></tr><tr><td>`?GL_FUNC_REVERSE_SUBTRACT'
+%% </td><td> Rr=R d d R-R s s R Gr=G d d G-G s s G Br=B d d B-B s s B</td><td> Ar=A d
+%% d A-A s s A</td></tr><tr><td>`?GL_MIN'</td><td> Rr=min(R s R d) Gr=min(G s G d) Br=min(B s B d)</td><td> Ar=min
+%% (A s A d)</td></tr><tr><td>`?GL_MAX'</td><td> Rr=max(R s R d) Gr=max(G s G d) Br=max(B s B d)</td><td> Ar=max(A s A d)</td></tr></tbody>
+%% </table>
%%
%% The results of these equations are clamped to the range [0 1].
%%
@@ -11626,11 +11628,11 @@ useProgram(Program) ->
%%
%% The commands ``gl:uniformMatrix{2|3|4|2x3|3x2|2x4|4x2|3x4|4x3}fv'' are used to modify
%% a matrix or an array of matrices. The numbers in the command name are interpreted as the
-%% dimensionality of the matrix. The number `2' indicates a 2 � 2 matrix (i.e., 4 values),
-%% the number `3' indicates a 3 � 3 matrix (i.e., 9 values), and the number `4'
-%% indicates a 4 � 4 matrix (i.e., 16 values). Non-square matrix dimensionality is explicit,
+%% dimensionality of the matrix. The number `2' indicates a 2 × 2 matrix (i.e., 4 values),
+%% the number `3' indicates a 3 × 3 matrix (i.e., 9 values), and the number `4'
+%% indicates a 4 × 4 matrix (i.e., 16 values). Non-square matrix dimensionality is explicit,
%% with the first number representing the number of columns and the second number representing
-%% the number of rows. For example, `2x4' indicates a 2 � 4 matrix with 2 columns and
+%% the number of rows. For example, `2x4' indicates a 2 × 4 matrix with 2 columns and
%% 4 rows (i.e., 8 values). If `Transpose' is `?GL_FALSE', each matrix is assumed
%% to be supplied in column major order. If `Transpose' is `?GL_TRUE', each matrix
%% is assumed to be supplied in row major order. The `Count' argument indicates the
@@ -12753,7 +12755,7 @@ drawElementsInstanced(Mode,Count,Type,Indices,Primcount) ->
%%
%% When a buffer object is attached to a buffer texture, the buffer object's data store
%% is taken as the texture's texel array. The number of texels in the buffer texture's texel
-%% array is given by buffer_size components� sizeof( base_type/)
+%% array is given by buffer_size components×sizeof( base_type/)
%%
%% where `buffer_size' is the size of the buffer object, in basic machine units and
%% components and base type are the element count and base data type for elements, as specified
@@ -14576,14 +14578,14 @@ bindSampler(Unit,Sampler) ->
%% to compute the texture value. The other four use mipmaps.
%%
%% A mipmap is an ordered set of arrays representing the same image at progressively lower
-%% resolutions. If the texture has dimensions 2 n*2 m, there are max(n m)+1 mipmaps. The first
-%% mipmap is the original texture, with dimensions 2 n*2 m. Each subsequent mipmap has
-%% dimensions 2(k-1)*2(l-1), where 2 k*2 l are the dimensions of the previous mipmap, until either
-%% k= 0 or l= 0. At that point, subsequent mipmaps have dimension 1*2(l-1) or 2(k-1)*1 until
-%% the final mipmap, which has dimension 1*1. To define the mipmaps, call {@link gl:texImage1D/8}
+%% resolutions. If the texture has dimensions 2 n×2 m, there are max(n m)+1 mipmaps. The first
+%% mipmap is the original texture, with dimensions 2 n×2 m. Each subsequent mipmap has
+%% dimensions 2(k-1)×2(l-1), where 2 k×2 l are the dimensions of the previous mipmap, until either
+%% k=0 or l=0. At that point, subsequent mipmaps have dimension 1×2(l-1) or 2(k-1)×1 until
+%% the final mipmap, which has dimension 1×1. To define the mipmaps, call {@link gl:texImage1D/8}
%% , {@link gl:texImage2D/9} , {@link gl:texImage3D/10} , {@link gl:copyTexImage1D/7} , or {@link gl:copyTexImage2D/8}
%% with the `level' argument indicating the order of the mipmaps. Level 0 is the original
-%% texture; level max(n m) is the final 1*1 mipmap.
+%% texture; level max(n m) is the final 1×1 mipmap.
%%
%% `Params' supplies a function for minifying the texture as one of the following:
%%
@@ -14695,13 +14697,12 @@ bindSampler(Unit,Sampler) ->
%% `?GL_TEXTURE_COMPARE_FUNC': Specifies the comparison operator used when `?GL_TEXTURE_COMPARE_MODE'
%% is set to `?GL_COMPARE_REF_TO_TEXTURE'. Permissible values are: <table><tbody><tr><td>
%% ` Texture Comparison Function '</td><td>` Computed result '</td></tr></tbody><tbody>
-%% <tr><td>`?GL_LEQUAL'</td><td> result={1.0 0.0 &amp;nbsp;&amp;nbsp; r&lt;=(D t) r&gt;(D t))</td></tr><tr><td>`?GL_GEQUAL'</td><td>
-%% result={1.0 0.0 &amp;nbsp;&amp;nbsp; r&gt;=(D t) r&lt;(D t))</td></tr><tr><td>`?GL_LESS'</td><td> result={1.0 0.0 &amp;nbsp;&amp;nbsp; r&lt;
-%% (D t) r&gt;=(D t))</td></tr><tr><td>`?GL_GREATER'
-%% </td><td> result={1.0 0.0 &amp;nbsp;&amp;nbsp; r&gt;(D t) r&lt;=(D t))</td></tr><tr><td>`?GL_EQUAL'</td><td> result={1.0 0.0 &amp;nbsp;&amp;nbsp;
-%% r=(D t) r&amp;ne;(D t))</td></tr><tr><td>`?GL_NOTEQUAL'
-%% </td><td> result={1.0 0.0 &amp;nbsp;&amp;nbsp; r&amp;ne;(D t) r=(D t))</td></tr><tr><td>`?GL_ALWAYS'</td><td> result= 1.0</td></tr><tr><td>
-%% `?GL_NEVER'</td><td> result= 0.0</td></tr></tbody></table> where r is the current
+%% <tr><td>`?GL_LEQUAL'</td><td> result={1.0 0.0 r&lt;=(D t) r&gt;(D t))</td></tr><tr><td>`?GL_GEQUAL'</td><td>
+%% result={1.0 0.0 r&gt;=(D t) r&lt;(D t))</td></tr><tr><td>`?GL_LESS'</td><td> result={1.0 0.0 r&lt;(D t) r&gt;=(D t))</td></tr><tr><td>`?GL_GREATER'
+%% </td><td> result={1.0 0.0 r&gt;(D t) r&lt;=(D t))</td></tr><tr><td>`?GL_EQUAL'</td><td> result={1.0 0.0 r=(D t) r&amp;ne;
+%% (D t))</td></tr><tr><td>`?GL_NOTEQUAL'
+%% </td><td> result={1.0 0.0 r&amp;ne;(D t) r=(D t))</td></tr><tr><td>`?GL_ALWAYS'</td><td> result=1.0</td></tr><tr><td>
+%% `?GL_NEVER'</td><td> result=0.0</td></tr></tbody></table> where r is the current
%% interpolated texture coordinate, and D t is the texture value sampled from the currently
%% bound texture. result is assigned to R t.
%%
@@ -15774,11 +15775,11 @@ getProgramPipelineiv(Pipeline,Pname) ->
%%
%% The commands ``gl:programUniformMatrix{2|3|4|2x3|3x2|2x4|4x2|3x4|4x3}fv'' are used
%% to modify a matrix or an array of matrices. The numbers in the command name are interpreted
-%% as the dimensionality of the matrix. The number `2' indicates a 2 � 2 matrix (i.e.,
-%% 4 values), the number `3' indicates a 3 � 3 matrix (i.e., 9 values), and the number `4'
-%% indicates a 4 � 4 matrix (i.e., 16 values). Non-square matrix dimensionality is explicit,
+%% as the dimensionality of the matrix. The number `2' indicates a 2 × 2 matrix (i.e.,
+%% 4 values), the number `3' indicates a 3 × 3 matrix (i.e., 9 values), and the number `4'
+%% indicates a 4 × 4 matrix (i.e., 16 values). Non-square matrix dimensionality is explicit,
%% with the first number representing the number of columns and the second number representing
-%% the number of rows. For example, `2x4' indicates a 2 � 4 matrix with 2 columns and
+%% the number of rows. For example, `2x4' indicates a 2 × 4 matrix with 2 columns and
%% 4 rows (i.e., 8 values). If `Transpose' is `?GL_FALSE', each matrix is assumed
%% to be supplied in column major order. If `Transpose' is `?GL_TRUE', each matrix
%% is assumed to be supplied in row major order. The `Count' argument indicates the
diff --git a/lib/wx/src/gen/glu.erl b/lib/wx/src/gen/glu.erl
index 2c82c9792f..dc64c3c3a7 100644
--- a/lib/wx/src/gen/glu.erl
+++ b/lib/wx/src/gen/glu.erl
@@ -1,7 +1,9 @@
+%% -*- coding: utf-8 -*-
+
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -91,19 +93,19 @@ tesselate({Nx,Ny,Nz}, Vs) ->
%% ).
%%
%% A series of mipmap levels from `Base' to `Max' is built by decimating `Data'
-%% in half until size 1*1 is reached. At each level, each texel in the halved mipmap
+%% in half until size 1×1 is reached. At each level, each texel in the halved mipmap
%% level is an average of the corresponding two texels in the larger mipmap level. {@link gl:texImage1D/8}
%% is called to load these mipmap levels from `Base' to `Max' . If `Max' is
%% larger than the highest mipmap level for the texture of the specified size, then a GLU
%% error code is returned (see {@link glu:errorString/1} ) and nothing is loaded.
%%
%% For example, if `Level' is 2 and `Width' is 16, the following levels are possible:
-%% 16*1, 8*1, 4*1, 2*1, 1*1. These correspond to levels 2 through 6 respectively.
-%% If `Base' is 3 and `Max' is 5, then only mipmap levels 8*1, 4*1 and 2*1
+%% 16×1, 8×1, 4×1, 2×1, 1×1. These correspond to levels 2 through 6 respectively.
+%% If `Base' is 3 and `Max' is 5, then only mipmap levels 8×1, 4×1 and 2×1
%% are loaded. However, if `Max' is 7, then an error is returned and nothing is loaded
%% since `Max' is larger than the highest mipmap level which is, in this case, 6.
%%
-%% The highest mipmap level can be derived from the formula log 2(width*2 level).
+%% The highest mipmap level can be derived from the formula log 2(width×2 level).
%%
%% See the {@link gl:texImage1D/8} reference page for a description of the acceptable values
%% for `Type' parameter. See the {@link gl:drawPixels/5} reference page for a description
@@ -134,13 +136,13 @@ build1DMipmapLevels(Target,InternalFormat,Width,Format,Type,Level,Base,Max,Data)
%% can fit the requested texture. If not, `Width' is continually halved until it fits.
%%
%% Next, a series of mipmap levels is built by decimating a copy of `Data' in half
-%% until size 1*1 is reached. At each level, each texel in the halved mipmap level is an
+%% until size 1×1 is reached. At each level, each texel in the halved mipmap level is an
%% average of the corresponding two texels in the larger mipmap level.
%%
%% {@link gl:texImage1D/8} is called to load each of these mipmap levels. Level 0 is a copy
%% of `Data' . The highest level is (log 2)(width). For example, if `Width' is 64 and the implementation
-%% can store a texture of this size, the following mipmap levels are built: 64*1, 32*1,
-%% 16*1, 8*1, 4*1, 2*1, and 1*1. These correspond to levels 0 through 6, respectively.
+%% can store a texture of this size, the following mipmap levels are built: 64×1, 32×1,
+%% 16×1, 8×1, 4×1, 2×1, and 1×1. These correspond to levels 0 through 6, respectively.
%%
%%
%% See the {@link gl:texImage1D/8} reference page for a description of the acceptable values
@@ -163,22 +165,22 @@ build1DMipmaps(Target,InternalFormat,Width,Format,Type,Data) ->
%% ).
%%
%% A series of mipmap levels from `Base' to `Max' is built by decimating `Data'
-%% in half along both dimensions until size 1*1 is reached. At each level, each texel
+%% in half along both dimensions until size 1×1 is reached. At each level, each texel
%% in the halved mipmap level is an average of the corresponding four texels in the larger
%% mipmap level. (In the case of rectangular images, the decimation will ultimately reach
-%% an N*1 or 1*N configuration. Here, two texels are averaged instead.) {@link gl:texImage2D/9}
+%% an N×1 or 1×N configuration. Here, two texels are averaged instead.) {@link gl:texImage2D/9}
%% is called to load these mipmap levels from `Base' to `Max' . If `Max' is
%% larger than the highest mipmap level for the texture of the specified size, then a GLU
%% error code is returned (see {@link glu:errorString/1} ) and nothing is loaded.
%%
%% For example, if `Level' is 2 and `Width' is 16 and `Height' is 8, the
-%% following levels are possible: 16*8, 8*4, 4*2, 2*1, 1*1. These correspond to
+%% following levels are possible: 16×8, 8×4, 4×2, 2×1, 1×1. These correspond to
%% levels 2 through 6 respectively. If `Base' is 3 and `Max' is 5, then only mipmap
-%% levels 8*4, 4*2, and 2*1 are loaded. However, if `Max' is 7, then an error is
+%% levels 8×4, 4×2, and 2×1 are loaded. However, if `Max' is 7, then an error is
%% returned and nothing is loaded since `Max' is larger than the highest mipmap level
%% which is, in this case, 6.
%%
-%% The highest mipmap level can be derived from the formula log 2(max(width height)*2 level).
+%% The highest mipmap level can be derived from the formula log 2(max(width height)×2 level).
%%
%% See the {@link gl:texImage1D/8} reference page for a description of the acceptable values
%% for `Format' parameter. See the {@link gl:drawPixels/5} reference page for a description
@@ -214,15 +216,15 @@ build2DMipmapLevels(Target,InternalFormat,Width,Height,Format,Type,Level,Base,Ma
%% .)
%%
%% Next, a series of mipmap levels is built by decimating a copy of `Data' in half
-%% along both dimensions until size 1*1 is reached. At each level, each texel in the halved
+%% along both dimensions until size 1×1 is reached. At each level, each texel in the halved
%% mipmap level is an average of the corresponding four texels in the larger mipmap level.
-%% (In the case of rectangular images, the decimation will ultimately reach an N*1 or 1*N
+%% (In the case of rectangular images, the decimation will ultimately reach an N×1 or 1×N
%% configuration. Here, two texels are averaged instead.)
%%
%% {@link gl:texImage2D/9} is called to load each of these mipmap levels. Level 0 is a copy
%% of `Data' . The highest level is (log 2)(max(width height)). For example, if `Width' is 64 and `Height'
%% is 16 and the implementation can store a texture of this size, the following mipmap levels
-%% are built: 64*16, 32*8, 16*4, 8*2, 4*1, 2*1, and 1*1 These correspond to
+%% are built: 64×16, 32×8, 16×4, 8×2, 4×1, 2×1, and 1×1 These correspond to
%% levels 0 through 6, respectively.
%%
%% See the {@link gl:texImage1D/8} reference page for a description of the acceptable values
@@ -245,7 +247,7 @@ build2DMipmaps(Target,InternalFormat,Width,Height,Format,Type,Data) ->
%% ).
%%
%% A series of mipmap levels from `Base' to `Max' is built by decimating `Data'
-%% in half along both dimensions until size 1*1*1 is reached. At each level, each texel
+%% in half along both dimensions until size 1×1×1 is reached. At each level, each texel
%% in the halved mipmap level is an average of the corresponding eight texels in the larger
%% mipmap level. (If exactly one of the dimensions is 1, four texels are averaged. If exactly
%% two of the dimensions are 1, two texels are averaged.) {@link gl:texImage3D/10} is called
@@ -254,13 +256,13 @@ build2DMipmaps(Target,InternalFormat,Width,Height,Format,Type,Data) ->
%% is returned (see {@link glu:errorString/1} ) and nothing is loaded.
%%
%% For example, if `Level' is 2 and `Width' is 16, `Height' is 8 and `Depth'
-%% is 4, the following levels are possible: 16*8*4, 8*4*2, 4*2*1, 2*1*1, 1*1*1.
+%% is 4, the following levels are possible: 16×8×4, 8×4×2, 4×2×1, 2×1×1, 1×1×1.
%% These correspond to levels 2 through 6 respectively. If `Base' is 3 and `Max'
-%% is 5, then only mipmap levels 8*4*2, 4*2*1, and 2*1*1 are loaded. However, if `Max'
+%% is 5, then only mipmap levels 8×4×2, 4×2×1, and 2×1×1 are loaded. However, if `Max'
%% is 7, then an error is returned and nothing is loaded, since `Max' is larger than
%% the highest mipmap level which is, in this case, 6.
%%
-%% The highest mipmap level can be derived from the formula log 2(max(width height depth)*2 level).
+%% The highest mipmap level can be derived from the formula log 2(max(width height depth)×2 level).
%%
%% See the {@link gl:texImage1D/8} reference page for a description of the acceptable values
%% for `Format' parameter. See the {@link gl:drawPixels/5} reference page for a description
@@ -295,7 +297,7 @@ build3DMipmapLevels(Target,InternalFormat,Width,Height,Depth,Format,Type,Level,B
%% it fits.
%%
%% Next, a series of mipmap levels is built by decimating a copy of `Data' in half
-%% along all three dimensions until size 1*1*1 is reached. At each level, each texel in
+%% along all three dimensions until size 1×1×1 is reached. At each level, each texel in
%% the halved mipmap level is an average of the corresponding eight texels in the larger
%% mipmap level. (If exactly one of the dimensions is 1, four texels are averaged. If exactly
%% two of the dimensions are 1, two texels are averaged.)
@@ -303,8 +305,8 @@ build3DMipmapLevels(Target,InternalFormat,Width,Height,Depth,Format,Type,Level,B
%% {@link gl:texImage3D/10} is called to load each of these mipmap levels. Level 0 is a copy
%% of `Data' . The highest level is (log 2)(max(width height depth)). For example, if `Width' is 64, `Height'
%% is 16, and `Depth' is 32, and the implementation can store a texture of this size,
-%% the following mipmap levels are built: 64*16*32, 32*8*16, 16*4*8, 8*2*4, 4*1*2,
-%% 2*1*1, and 1*1*1. These correspond to levels 0 through 6, respectively.
+%% the following mipmap levels are built: 64×16×32, 32×8×16, 16×4×8, 8×2×4, 4×1×2,
+%% 2×1×1, and 1×1×1. These correspond to levels 0 through 6, respectively.
%%
%% See the {@link gl:texImage1D/8} reference page for a description of the acceptable values
%% for `Format' parameter. See the {@link gl:drawPixels/5} reference page for a description
@@ -334,7 +336,7 @@ checkExtension(ExtName,ExtString) ->
%% @doc Draw a cylinder
%%
%% ``glu:cylinder'' draws a cylinder oriented along the `z' axis. The base of the
-%% cylinder is placed at `z' = 0 and the top at z= height. Like a sphere, a cylinder
+%% cylinder is placed at `z' = 0 and the top at z=height. Like a sphere, a cylinder
%% is subdivided around the `z' axis into slices and along the `z' axis into stacks.
%%
%%
@@ -380,7 +382,7 @@ deleteQuadric(Quad) ->
%% the -`z' axis.
%%
%% If texturing has been turned on (with {@link glu:quadricTexture/2} ), texture coordinates
-%% are generated linearly such that where r= outer, the value at (`r', 0, 0) is (1,
+%% are generated linearly such that where r=outer, the value at (`r', 0, 0) is (1,
%% 0.5), at (0, `r', 0) it is (0.5, 1), at (-`r', 0, 0) it is (0, 0.5), and at
%% (0, -`r', 0) it is (0.5, 0).
%%
@@ -451,11 +453,11 @@ getString(Name) ->
%%
%% Let `UP' be the vector (upX upY upZ).
%%
-%% Then normalize as follows: f= F/(||F||)
+%% Then normalize as follows: f=F/(||F||)
%%
-%% UP"= UP/(||UP||)
+%% UP"=UP/(||UP||)
%%
-%% Finally, let s= f*UP", and u= s*f.
+%% Finally, let s=f×UP", and u=s×f.
%%
%% M is then constructed as follows: M=(s[0] s[1] s[2] 0 u[0] u[1] u[2] 0-f[0]-f[1]-f[2] 0 0 0 0 1)
%%
@@ -481,7 +483,7 @@ newQuadric() ->
%% @doc Define a 2D orthographic projection matrix
%%
%% ``glu:ortho2D'' sets up a two-dimensional orthographic viewing region. This is equivalent
-%% to calling {@link gl:ortho/6} with near= -1 and far= 1.
+%% to calling {@link gl:ortho/6} with near=-1 and far=1.
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/gluOrtho2D.xml">external</a> documentation.
-spec ortho2D(Left, Right, Bottom, Top) -> ok when Left :: float(),Right :: float(),Bottom :: float(),Top :: float().
@@ -490,7 +492,7 @@ ortho2D(Left,Right,Bottom,Top) ->
%% @doc Draw an arc of a disk
%%
-%% ``glu:partialDisk'' renders a partial disk on the z= 0 plane. A partial disk is similar
+%% ``glu:partialDisk'' renders a partial disk on the z=0 plane. A partial disk is similar
%% to a full disk, except that only the subset of the disk from `Start' through `Start'
%% + `Sweep' is included (where 0 degrees is along the +f2yf axis, 90 degrees along
%% the +`x' axis, 180 degrees along the -`y' axis, and 270 degrees along the -`x'
@@ -508,7 +510,7 @@ ortho2D(Left,Right,Bottom,Top) ->
%% Otherwise, they point along the -`z' axis.
%%
%% If texturing is turned on (with {@link glu:quadricTexture/2} ), texture coordinates are
-%% generated linearly such that where r= outer, the value at (`r', 0, 0) is (1.0,
+%% generated linearly such that where r=outer, the value at (`r', 0, 0) is (1.0,
%% 0.5), at (0, `r', 0) it is (0.5, 1.0), at (-`r', 0, 0) it is (0.0, 0.5), and
%% at (0, -`r', 0) it is (0.5, 0.0).
%%
@@ -521,7 +523,7 @@ partialDisk(Quad,Inner,Outer,Slices,Loops,Start,Sweep) ->
%%
%% ``glu:perspective'' specifies a viewing frustum into the world coordinate system. In
%% general, the aspect ratio in ``glu:perspective'' should match the aspect ratio of the
-%% associated viewport. For example, aspect= 2.0 means the viewer's angle of view is twice
+%% associated viewport. For example, aspect=2.0 means the viewer's angle of view is twice
%% as wide in `x' as it is in `y'. If the viewport is twice as wide as it is tall,
%% it displays the image without distortion.
%%
@@ -532,9 +534,9 @@ partialDisk(Quad,Inner,Outer,Slices,Loops,Start,Sweep) ->
%%
%% Given `f' defined as follows:
%%
-%% f= cotangent(fovy/2) The generated matrix is
+%% f=cotangent(fovy/2) The generated matrix is
%%
-%% (f/aspect 0 0 0 0 f 0 0 0 0(zFar+zNear)/(zNear-zFar)(2*zFar*zNear)/(zNear-zFar) 0 0 -1 0)
+%% (f/aspect 0 0 0 0 f 0 0 0 0(zFar+zNear)/(zNear-zFar)(2×zFar×zNear)/(zNear-zFar) 0 0 -1 0)
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/gluPerspective.xml">external</a> documentation.
-spec perspective(Fovy, Aspect, ZNear, ZFar) -> ok when Fovy :: float(),Aspect :: float(),ZNear :: float(),ZFar :: float().
@@ -577,16 +579,16 @@ pickMatrix(X,Y,DelX,DelY,{V1,V2,V3,V4}) ->
%% To compute the coordinates, let v=(objX objY objZ 1.0) represented as a matrix with 4 rows and 1 column.
%% Then ``glu:project'' computes v" as follows:
%%
-%% v"= P*M*v
+%% v"=P×M×v
%%
%% where P is the current projection matrix `Proj' and M is the current modelview
-%% matrix `Model' (both represented as 4*4 matrices in column-major order).
+%% matrix `Model' (both represented as 4×4 matrices in column-major order).
%%
%% The window coordinates are then computed as follows:
%%
-%% winX= view(0)+view(2)*(v"(0)+1)/2
+%% winX=view(0)+view(2)×(v"(0)+1)/2
%%
-%% winY= view(1)+view(3)*(v"(1)+1)/2
+%% winY=view(1)+view(3)×(v"(1)+1)/2
%%
%% winZ=(v"(2)+1)/2
%%
@@ -703,7 +705,7 @@ scaleImage(Format,WIn,HIn,TypeIn,DataIn,WOut,HOut,TypeOut,DataOut) ->
%% point toward the center of the sphere.
%%
%% If texturing is turned on (with {@link glu:quadricTexture/2} ), then texture coordinates
-%% are generated so that `t' ranges from 0.0 at z=-radius to 1.0 at z= radius (`t'
+%% are generated so that `t' ranges from 0.0 at z=-radius to 1.0 at z=radius (`t'
%% increases linearly along longitudinal lines), and `s' ranges from 0.0 at the +`y'
%% axis, to 0.25 at the +`x' axis, to 0.5 at the -`y' axis, to 0.75 at the -`x'
%% axis, and back to 1.0 at the +`y' axis.
@@ -723,7 +725,7 @@ sphere(Quad,Radius,Slices,Stacks) ->
%% To compute the coordinates (objX objY objZ), ``glu:unProject'' multiplies the normalized device coordinates
%% by the inverse of `Model' * `Proj' as follows:
%%
-%% (objX objY objZ W)= INV(P M) ((2(winX-view[0]))/(view[2])-1(2(winY-view[1]))/(view[3])-1 2(winZ)-1 1) INV denotes matrix inversion. W is an unused variable, included for consistent
+%% (objX objY objZ W)=INV(P M) ((2(winX-view[0]))/(view[2])-1(2(winY-view[1]))/(view[3])-1 2(winZ)-1 1) INV denotes matrix inversion. W is an unused variable, included for consistent
%% matrix notation.
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/gluUnProject.xml">external</a> documentation.
diff --git a/lib/wx/src/gen/wxCalendarCtrl.erl b/lib/wx/src/gen/wxCalendarCtrl.erl
index 01d171800b..2a476c5e92 100644
--- a/lib/wx/src/gen/wxCalendarCtrl.erl
+++ b/lib/wx/src/gen/wxCalendarCtrl.erl
@@ -75,6 +75,8 @@
update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]).
-export_type([wxCalendarCtrl/0]).
+-deprecated([enableYearChange/1,enableYearChange/2]).
+
%% @hidden
parent_class(wxControl) -> true;
parent_class(wxWindow) -> true;
diff --git a/lib/wx/src/gen/wxClientDC.erl b/lib/wx/src/gen/wxClientDC.erl
index 7dfebe4068..cb75fdc58d 100644
--- a/lib/wx/src/gen/wxClientDC.erl
+++ b/lib/wx/src/gen/wxClientDC.erl
@@ -54,6 +54,8 @@
startPage/1]).
-export_type([wxClientDC/0]).
+-deprecated([new/0]).
+
%% @hidden
parent_class(wxWindowDC) -> true;
parent_class(wxDC) -> true;
diff --git a/lib/wx/src/gen/wxClipboard.erl b/lib/wx/src/gen/wxClipboard.erl
index 8f1d59f603..c7336fcc47 100644
--- a/lib/wx/src/gen/wxClipboard.erl
+++ b/lib/wx/src/gen/wxClipboard.erl
@@ -130,8 +130,9 @@ usePrimarySelection(#wx_ref{type=ThisT,ref=ThisRef}, Options)
<<ThisRef:32/?UI, 0:32,BinOpt/binary>>).
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxclipboard.html#wxclipboardissupported">external documentation</a>.
+%%<br /> Format = ?wxDF_INVALID | ?wxDF_TEXT | ?wxDF_BITMAP | ?wxDF_METAFILE | ?wxDF_SYLK | ?wxDF_DIF | ?wxDF_TIFF | ?wxDF_OEMTEXT | ?wxDF_DIB | ?wxDF_PALETTE | ?wxDF_PENDATA | ?wxDF_RIFF | ?wxDF_WAVE | ?wxDF_UNICODETEXT | ?wxDF_ENHMETAFILE | ?wxDF_FILENAME | ?wxDF_LOCALE | ?wxDF_PRIVATE | ?wxDF_HTML | ?wxDF_MAX
-spec isSupported(This, Format) -> boolean() when
- This::wxClipboard(), Format::integer().
+ This::wxClipboard(), Format::wx:wx_enum().
isSupported(#wx_ref{type=ThisT,ref=ThisRef},Format)
when is_integer(Format) ->
?CLASS(ThisT,wxClipboard),
diff --git a/lib/wx/src/gen/wxCursor.erl b/lib/wx/src/gen/wxCursor.erl
index b9e3a8e3f7..423e444f2f 100644
--- a/lib/wx/src/gen/wxCursor.erl
+++ b/lib/wx/src/gen/wxCursor.erl
@@ -35,6 +35,8 @@
saveFile/4,setDepth/2,setHeight/2,setMask/2,setPalette/2,setWidth/2]).
-export_type([wxCursor/0]).
+-deprecated([new/3,new/4]).
+
%% @hidden
parent_class(wxBitmap) -> true;
parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
diff --git a/lib/wx/src/gen/wxDC.erl b/lib/wx/src/gen/wxDC.erl
index 9f57978849..42d5d7b1df 100644
--- a/lib/wx/src/gen/wxDC.erl
+++ b/lib/wx/src/gen/wxDC.erl
@@ -50,6 +50,8 @@
-export([parent_class/1]).
-export_type([wxDC/0]).
+-deprecated([computeScaleAndOrigin/1]).
+
%% @hidden
parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
@@ -63,9 +65,10 @@ blit(This,DestPt={DestPtX,DestPtY},Sz={SzW,SzH},Source,SrcPt={SrcPtX,SrcPtY})
blit(This,DestPt,Sz,Source,SrcPt, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcblit">external documentation</a>.
+%%<br /> Rop = integer
-spec blit(This, DestPt, Sz, Source, SrcPt, [Option]) -> boolean() when
This::wxDC(), DestPt::{X::integer(), Y::integer()}, Sz::{W::integer(), H::integer()}, Source::wxDC(), SrcPt::{X::integer(), Y::integer()},
- Option :: {rop, integer()}
+ Option :: {rop, wx:wx_enum()}
| {useMask, boolean()}
| {srcPtMask, {X::integer(), Y::integer()}}.
blit(#wx_ref{type=ThisT,ref=ThisRef},{DestPtX,DestPtY},{SzW,SzH},#wx_ref{type=SourceT,ref=SourceRef},{SrcPtX,SrcPtY}, Options)
@@ -310,11 +313,12 @@ drawPolygon(This,Points)
drawPolygon(This,Points, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawpolygon">external documentation</a>.
+%%<br /> FillStyle = integer
-spec drawPolygon(This, Points, [Option]) -> ok when
This::wxDC(), Points::[{X::integer(), Y::integer()}],
Option :: {xoffset, integer()}
| {yoffset, integer()}
- | {fillStyle, integer()}.
+ | {fillStyle, wx:wx_enum()}.
drawPolygon(#wx_ref{type=ThisT,ref=ThisRef},Points, Options)
when is_list(Points),is_list(Options) ->
?CLASS(ThisT,wxDC),
@@ -417,9 +421,10 @@ floodFill(This,Pt={PtX,PtY},Col)
floodFill(This,Pt,Col, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcfloodfill">external documentation</a>.
+%%<br /> Style = integer
-spec floodFill(This, Pt, Col, [Option]) -> boolean() when
This::wxDC(), Pt::{X::integer(), Y::integer()}, Col::wx:wx_colour(),
- Option :: {style, integer()}.
+ Option :: {style, wx:wx_enum()}.
floodFill(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},Col, Options)
when is_integer(PtX),is_integer(PtY),tuple_size(Col) =:= 3; tuple_size(Col) =:= 4,is_list(Options) ->
?CLASS(ThisT,wxDC),
@@ -855,8 +860,9 @@ setLayoutDirection(#wx_ref{type=ThisT,ref=ThisRef},Dir)
<<ThisRef:32/?UI,Dir:32/?UI>>).
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcsetlogicalfunction">external documentation</a>.
+%%<br /> Function = integer
-spec setLogicalFunction(This, Function) -> ok when
- This::wxDC(), Function::integer().
+ This::wxDC(), Function::wx:wx_enum().
setLogicalFunction(#wx_ref{type=ThisT,ref=ThisRef},Function)
when is_integer(Function) ->
?CLASS(ThisT,wxDC),
@@ -864,8 +870,9 @@ setLogicalFunction(#wx_ref{type=ThisT,ref=ThisRef},Function)
<<ThisRef:32/?UI,Function:32/?UI>>).
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcsetmapmode">external documentation</a>.
+%%<br /> Mode = integer
-spec setMapMode(This, Mode) -> ok when
- This::wxDC(), Mode::integer().
+ This::wxDC(), Mode::wx:wx_enum().
setMapMode(#wx_ref{type=ThisT,ref=ThisRef},Mode)
when is_integer(Mode) ->
?CLASS(ThisT,wxDC),
diff --git a/lib/wx/src/gen/wxGraphicsContext.erl b/lib/wx/src/gen/wxGraphicsContext.erl
index 1dfa0dd405..575e48d7af 100644
--- a/lib/wx/src/gen/wxGraphicsContext.erl
+++ b/lib/wx/src/gen/wxGraphicsContext.erl
@@ -40,6 +40,8 @@
-export([getRenderer/1,isNull/1,parent_class/1]).
-export_type([wxGraphicsContext/0]).
+-deprecated([createLinearGradientBrush/7,createRadialGradientBrush/8]).
+
%% @hidden
parent_class(wxGraphicsObject) -> true;
parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
@@ -225,9 +227,10 @@ drawLines(This,Points)
drawLines(This,Points, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgraphicscontext.html#wxgraphicscontextdrawlines">external documentation</a>.
+%%<br /> FillStyle = integer
-spec drawLines(This, Points, [Option]) -> ok when
This::wxGraphicsContext(), Points::[{X::float(), Y::float()}],
- Option :: {fillStyle, integer()}.
+ Option :: {fillStyle, wx:wx_enum()}.
drawLines(#wx_ref{type=ThisT,ref=ThisRef},Points, Options)
when is_list(Points),is_list(Options) ->
?CLASS(ThisT,wxGraphicsContext),
@@ -247,9 +250,10 @@ drawPath(This,Path)
drawPath(This,Path, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgraphicscontext.html#wxgraphicscontextdrawpath">external documentation</a>.
+%%<br /> FillStyle = integer
-spec drawPath(This, Path, [Option]) -> ok when
This::wxGraphicsContext(), Path::wxGraphicsPath:wxGraphicsPath(),
- Option :: {fillStyle, integer()}.
+ Option :: {fillStyle, wx:wx_enum()}.
drawPath(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=PathT,ref=PathRef}, Options)
when is_list(Options) ->
?CLASS(ThisT,wxGraphicsContext),
@@ -331,9 +335,10 @@ fillPath(This,Path)
fillPath(This,Path, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgraphicscontext.html#wxgraphicscontextfillpath">external documentation</a>.
+%%<br /> FillStyle = integer
-spec fillPath(This, Path, [Option]) -> ok when
This::wxGraphicsContext(), Path::wxGraphicsPath:wxGraphicsPath(),
- Option :: {fillStyle, integer()}.
+ Option :: {fillStyle, wx:wx_enum()}.
fillPath(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=PathT,ref=PathRef}, Options)
when is_list(Options) ->
?CLASS(ThisT,wxGraphicsContext),
diff --git a/lib/wx/src/gen/wxGraphicsPath.erl b/lib/wx/src/gen/wxGraphicsPath.erl
index 56b853899a..246ea489ec 100644
--- a/lib/wx/src/gen/wxGraphicsPath.erl
+++ b/lib/wx/src/gen/wxGraphicsPath.erl
@@ -197,13 +197,14 @@ contains(This,C={CX,CY})
%% <br /> Also:<br />
%% contains(This, C, [Option]) -> boolean() when<br />
%% This::wxGraphicsPath(), C::{X::float(), Y::float()},<br />
-%% Option :: {fillStyle, integer()}.<br />
+%% Option :: {fillStyle, wx:wx_enum()}.<br />
%%
+%%<br /> FillStyle = integer
-spec contains(This, X, Y) -> boolean() when
This::wxGraphicsPath(), X::number(), Y::number();
(This, C, [Option]) -> boolean() when
This::wxGraphicsPath(), C::{X::float(), Y::float()},
- Option :: {fillStyle, integer()}.
+ Option :: {fillStyle, wx:wx_enum()}.
contains(This,X,Y)
when is_record(This, wx_ref),is_number(X),is_number(Y) ->
@@ -218,9 +219,10 @@ contains(#wx_ref{type=ThisT,ref=ThisRef},{CX,CY}, Options)
<<ThisRef:32/?UI,0:32,CX:64/?F,CY:64/?F, BinOpt/binary>>).
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgraphicspath.html#wxgraphicspathcontains">external documentation</a>.
+%%<br /> FillStyle = integer
-spec contains(This, X, Y, [Option]) -> boolean() when
This::wxGraphicsPath(), X::number(), Y::number(),
- Option :: {fillStyle, integer()}.
+ Option :: {fillStyle, wx:wx_enum()}.
contains(#wx_ref{type=ThisT,ref=ThisRef},X,Y, Options)
when is_number(X),is_number(Y),is_list(Options) ->
?CLASS(ThisT,wxGraphicsPath),
diff --git a/lib/wx/src/gen/wxGraphicsRenderer.erl b/lib/wx/src/gen/wxGraphicsRenderer.erl
index 21082bde23..2b64f86182 100644
--- a/lib/wx/src/gen/wxGraphicsRenderer.erl
+++ b/lib/wx/src/gen/wxGraphicsRenderer.erl
@@ -32,6 +32,8 @@
-export([parent_class/1]).
-export_type([wxGraphicsRenderer/0]).
+-deprecated([createLinearGradientBrush/7,createRadialGradientBrush/8]).
+
%% @hidden
parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
diff --git a/lib/wx/src/gen/wxGridCellEditor.erl b/lib/wx/src/gen/wxGridCellEditor.erl
index e84cdeb49a..4f86e307b5 100644
--- a/lib/wx/src/gen/wxGridCellEditor.erl
+++ b/lib/wx/src/gen/wxGridCellEditor.erl
@@ -31,6 +31,8 @@
-export([parent_class/1]).
-export_type([wxGridCellEditor/0]).
+-deprecated([endEdit/4,paintBackground/3]).
+
%% @hidden
parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
diff --git a/lib/wx/src/gen/wxIdleEvent.erl b/lib/wx/src/gen/wxIdleEvent.erl
index 4749026446..a19fdcc48e 100644
--- a/lib/wx/src/gen/wxIdleEvent.erl
+++ b/lib/wx/src/gen/wxIdleEvent.erl
@@ -38,6 +38,8 @@
resumePropagation/2,shouldPropagate/1,skip/1,skip/2,stopPropagation/1]).
-export_type([wxIdleEvent/0]).
+-deprecated([canSend/1]).
+
%% @hidden
parent_class(wxEvent) -> true;
parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
diff --git a/lib/wx/src/gen/wxImage.erl b/lib/wx/src/gen/wxImage.erl
index c21b5d4789..0edaee2979 100644
--- a/lib/wx/src/gen/wxImage.erl
+++ b/lib/wx/src/gen/wxImage.erl
@@ -424,9 +424,10 @@ getImageCount(Name)
getImageCount(Name, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wximage.html#wximagegetimagecount">external documentation</a>.
+%%<br /> Type = ?wxBITMAP_TYPE_INVALID | ?wxBITMAP_TYPE_BMP | ?wxBITMAP_TYPE_BMP_RESOURCE | ?wxBITMAP_TYPE_RESOURCE | ?wxBITMAP_TYPE_ICO | ?wxBITMAP_TYPE_ICO_RESOURCE | ?wxBITMAP_TYPE_CUR | ?wxBITMAP_TYPE_CUR_RESOURCE | ?wxBITMAP_TYPE_XBM | ?wxBITMAP_TYPE_XBM_DATA | ?wxBITMAP_TYPE_XPM | ?wxBITMAP_TYPE_XPM_DATA | ?wxBITMAP_TYPE_TIF | ?wxBITMAP_TYPE_TIF_RESOURCE | ?wxBITMAP_TYPE_GIF | ?wxBITMAP_TYPE_GIF_RESOURCE | ?wxBITMAP_TYPE_PNG | ?wxBITMAP_TYPE_PNG_RESOURCE | ?wxBITMAP_TYPE_JPEG | ?wxBITMAP_TYPE_JPEG_RESOURCE | ?wxBITMAP_TYPE_PNM | ?wxBITMAP_TYPE_PNM_RESOURCE | ?wxBITMAP_TYPE_PCX | ?wxBITMAP_TYPE_PCX_RESOURCE | ?wxBITMAP_TYPE_PICT | ?wxBITMAP_TYPE_PICT_RESOURCE | ?wxBITMAP_TYPE_ICON | ?wxBITMAP_TYPE_ICON_RESOURCE | ?wxBITMAP_TYPE_ANI | ?wxBITMAP_TYPE_IFF | ?wxBITMAP_TYPE_TGA | ?wxBITMAP_TYPE_MACCURSOR | ?wxBITMAP_TYPE_MACCURSOR_RESOURCE | ?wxBITMAP_TYPE_ANY
-spec getImageCount(Name, [Option]) -> integer() when
Name::unicode:chardata(),
- Option :: {type, integer()}.
+ Option :: {type, wx:wx_enum()}.
getImageCount(Name, Options)
when is_list(Name),is_list(Options) ->
Name_UC = unicode:characters_to_binary([Name,0]),
@@ -687,9 +688,10 @@ rescale(This,Width,Height)
rescale(This,Width,Height, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wximage.html#wximagerescale">external documentation</a>.
+%%<br /> Quality = integer
-spec rescale(This, Width, Height, [Option]) -> wxImage() when
This::wxImage(), Width::integer(), Height::integer(),
- Option :: {quality, integer()}.
+ Option :: {quality, wx:wx_enum()}.
rescale(#wx_ref{type=ThisT,ref=ThisRef},Width,Height, Options)
when is_integer(Width),is_integer(Height),is_list(Options) ->
?CLASS(ThisT,wxImage),
@@ -819,9 +821,10 @@ scale(This,Width,Height)
scale(This,Width,Height, []).
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wximage.html#wximagescale">external documentation</a>.
+%%<br /> Quality = integer
-spec scale(This, Width, Height, [Option]) -> wxImage() when
This::wxImage(), Width::integer(), Height::integer(),
- Option :: {quality, integer()}.
+ Option :: {quality, wx:wx_enum()}.
scale(#wx_ref{type=ThisT,ref=ThisRef},Width,Height, Options)
when is_integer(Width),is_integer(Height),is_list(Options) ->
?CLASS(ThisT,wxImage),
diff --git a/lib/wx/src/gen/wxMDIClientWindow.erl b/lib/wx/src/gen/wxMDIClientWindow.erl
index 344dcdbbaf..bfdba336f8 100644
--- a/lib/wx/src/gen/wxMDIClientWindow.erl
+++ b/lib/wx/src/gen/wxMDIClientWindow.erl
@@ -69,6 +69,8 @@
update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]).
-export_type([wxMDIClientWindow/0]).
+-deprecated([new/1,new/2]).
+
%% @hidden
parent_class(wxWindow) -> true;
parent_class(wxEvtHandler) -> true;
diff --git a/lib/wx/src/gen/wxMouseEvent.erl b/lib/wx/src/gen/wxMouseEvent.erl
index 97ea9e908f..29a4f13ba8 100644
--- a/lib/wx/src/gen/wxMouseEvent.erl
+++ b/lib/wx/src/gen/wxMouseEvent.erl
@@ -19,7 +19,7 @@
%% @doc See external documentation: <a href="http://www.wxwidgets.org/manuals/stable/wx_wxmouseevent.html">wxMouseEvent</a>.
%% <dl><dt>Use {@link wxEvtHandler:connect/3.} with EventType:</dt>
-%% <dd><em>left_down</em>, <em>left_up</em>, <em>middle_down</em>, <em>middle_up</em>, <em>right_down</em>, <em>right_up</em>, <em>motion</em>, <em>enter_window</em>, <em>leave_window</em>, <em>left_dclick</em>, <em>middle_dclick</em>, <em>right_dclick</em>, <em>mousewheel</em>, <em>nc_left_down</em>, <em>nc_left_up</em>, <em>nc_middle_down</em>, <em>nc_middle_up</em>, <em>nc_right_down</em>, <em>nc_right_up</em>, <em>nc_motion</em>, <em>nc_enter_window</em>, <em>nc_leave_window</em>, <em>nc_left_dclick</em>, <em>nc_middle_dclick</em>, <em>nc_right_dclick</em></dd></dl>
+%% <dd><em>left_down</em>, <em>left_up</em>, <em>middle_down</em>, <em>middle_up</em>, <em>right_down</em>, <em>right_up</em>, <em>motion</em>, <em>enter_window</em>, <em>leave_window</em>, <em>left_dclick</em>, <em>middle_dclick</em>, <em>right_dclick</em>, <em>mousewheel</em></dd></dl>
%% See also the message variant {@link wxEvtHandler:wxMouse(). #wxMouse{}} event record type.
%%
%% <p>This class is derived (and can use functions) from:
diff --git a/lib/wx/src/gen/wxPageSetupDialogData.erl b/lib/wx/src/gen/wxPageSetupDialogData.erl
index 7c453a9872..4850e62925 100644
--- a/lib/wx/src/gen/wxPageSetupDialogData.erl
+++ b/lib/wx/src/gen/wxPageSetupDialogData.erl
@@ -194,7 +194,8 @@ getMinMarginBottomRight(#wx_ref{type=ThisT,ref=ThisRef}) ->
<<ThisRef:32/?UI>>).
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpagesetupdialogdata.html#wxpagesetupdialogdatagetpaperid">external documentation</a>.
--spec getPaperId(This) -> integer() when
+%%<br /> Res = ?wxPAPER_NONE | ?wxPAPER_LETTER | ?wxPAPER_LEGAL | ?wxPAPER_A4 | ?wxPAPER_CSHEET | ?wxPAPER_DSHEET | ?wxPAPER_ESHEET | ?wxPAPER_LETTERSMALL | ?wxPAPER_TABLOID | ?wxPAPER_LEDGER | ?wxPAPER_STATEMENT | ?wxPAPER_EXECUTIVE | ?wxPAPER_A3 | ?wxPAPER_A4SMALL | ?wxPAPER_A5 | ?wxPAPER_B4 | ?wxPAPER_B5 | ?wxPAPER_FOLIO | ?wxPAPER_QUARTO | ?wxPAPER_10X14 | ?wxPAPER_11X17 | ?wxPAPER_NOTE | ?wxPAPER_ENV_9 | ?wxPAPER_ENV_10 | ?wxPAPER_ENV_11 | ?wxPAPER_ENV_12 | ?wxPAPER_ENV_14 | ?wxPAPER_ENV_DL | ?wxPAPER_ENV_C5 | ?wxPAPER_ENV_C3 | ?wxPAPER_ENV_C4 | ?wxPAPER_ENV_C6 | ?wxPAPER_ENV_C65 | ?wxPAPER_ENV_B4 | ?wxPAPER_ENV_B5 | ?wxPAPER_ENV_B6 | ?wxPAPER_ENV_ITALY | ?wxPAPER_ENV_MONARCH | ?wxPAPER_ENV_PERSONAL | ?wxPAPER_FANFOLD_US | ?wxPAPER_FANFOLD_STD_GERMAN | ?wxPAPER_FANFOLD_LGL_GERMAN | ?wxPAPER_ISO_B4 | ?wxPAPER_JAPANESE_POSTCARD | ?wxPAPER_9X11 | ?wxPAPER_10X11 | ?wxPAPER_15X11 | ?wxPAPER_ENV_INVITE | ?wxPAPER_LETTER_EXTRA | ?wxPAPER_LEGAL_EXTRA | ?wxPAPER_TABLOID_EXTRA | ?wxPAPER_A4_EXTRA | ?wxPAPER_LETTER_TRANSVERSE | ?wxPAPER_A4_TRANSVERSE | ?wxPAPER_LETTER_EXTRA_TRANSVERSE | ?wxPAPER_A_PLUS | ?wxPAPER_B_PLUS | ?wxPAPER_LETTER_PLUS | ?wxPAPER_A4_PLUS | ?wxPAPER_A5_TRANSVERSE | ?wxPAPER_B5_TRANSVERSE | ?wxPAPER_A3_EXTRA | ?wxPAPER_A5_EXTRA | ?wxPAPER_B5_EXTRA | ?wxPAPER_A2 | ?wxPAPER_A3_TRANSVERSE | ?wxPAPER_A3_EXTRA_TRANSVERSE | ?wxPAPER_DBL_JAPANESE_POSTCARD | ?wxPAPER_A6 | ?wxPAPER_JENV_KAKU2 | ?wxPAPER_JENV_KAKU3 | ?wxPAPER_JENV_CHOU3 | ?wxPAPER_JENV_CHOU4 | ?wxPAPER_LETTER_ROTATED | ?wxPAPER_A3_ROTATED | ?wxPAPER_A4_ROTATED | ?wxPAPER_A5_ROTATED | ?wxPAPER_B4_JIS_ROTATED | ?wxPAPER_B5_JIS_ROTATED | ?wxPAPER_JAPANESE_POSTCARD_ROTATED | ?wxPAPER_DBL_JAPANESE_POSTCARD_ROTATED | ?wxPAPER_A6_ROTATED | ?wxPAPER_JENV_KAKU2_ROTATED | ?wxPAPER_JENV_KAKU3_ROTATED | ?wxPAPER_JENV_CHOU3_ROTATED | ?wxPAPER_JENV_CHOU4_ROTATED | ?wxPAPER_B6_JIS | ?wxPAPER_B6_JIS_ROTATED | ?wxPAPER_12X11 | ?wxPAPER_JENV_YOU4 | ?wxPAPER_JENV_YOU4_ROTATED | ?wxPAPER_P16K | ?wxPAPER_P32K | ?wxPAPER_P32KBIG | ?wxPAPER_PENV_1 | ?wxPAPER_PENV_2 | ?wxPAPER_PENV_3 | ?wxPAPER_PENV_4 | ?wxPAPER_PENV_5 | ?wxPAPER_PENV_6 | ?wxPAPER_PENV_7 | ?wxPAPER_PENV_8 | ?wxPAPER_PENV_9 | ?wxPAPER_PENV_10 | ?wxPAPER_P16K_ROTATED | ?wxPAPER_P32K_ROTATED | ?wxPAPER_P32KBIG_ROTATED | ?wxPAPER_PENV_1_ROTATED | ?wxPAPER_PENV_2_ROTATED | ?wxPAPER_PENV_3_ROTATED | ?wxPAPER_PENV_4_ROTATED | ?wxPAPER_PENV_5_ROTATED | ?wxPAPER_PENV_6_ROTATED | ?wxPAPER_PENV_7_ROTATED | ?wxPAPER_PENV_8_ROTATED | ?wxPAPER_PENV_9_ROTATED | ?wxPAPER_PENV_10_ROTATED
+-spec getPaperId(This) -> wx:wx_enum() when
This::wxPageSetupDialogData().
getPaperId(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxPageSetupDialogData),
@@ -280,8 +281,9 @@ setMinMarginBottomRight(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
<<ThisRef:32/?UI,PtX:32/?UI,PtY:32/?UI>>).
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpagesetupdialogdata.html#wxpagesetupdialogdatasetpaperid">external documentation</a>.
+%%<br /> Id = ?wxPAPER_NONE | ?wxPAPER_LETTER | ?wxPAPER_LEGAL | ?wxPAPER_A4 | ?wxPAPER_CSHEET | ?wxPAPER_DSHEET | ?wxPAPER_ESHEET | ?wxPAPER_LETTERSMALL | ?wxPAPER_TABLOID | ?wxPAPER_LEDGER | ?wxPAPER_STATEMENT | ?wxPAPER_EXECUTIVE | ?wxPAPER_A3 | ?wxPAPER_A4SMALL | ?wxPAPER_A5 | ?wxPAPER_B4 | ?wxPAPER_B5 | ?wxPAPER_FOLIO | ?wxPAPER_QUARTO | ?wxPAPER_10X14 | ?wxPAPER_11X17 | ?wxPAPER_NOTE | ?wxPAPER_ENV_9 | ?wxPAPER_ENV_10 | ?wxPAPER_ENV_11 | ?wxPAPER_ENV_12 | ?wxPAPER_ENV_14 | ?wxPAPER_ENV_DL | ?wxPAPER_ENV_C5 | ?wxPAPER_ENV_C3 | ?wxPAPER_ENV_C4 | ?wxPAPER_ENV_C6 | ?wxPAPER_ENV_C65 | ?wxPAPER_ENV_B4 | ?wxPAPER_ENV_B5 | ?wxPAPER_ENV_B6 | ?wxPAPER_ENV_ITALY | ?wxPAPER_ENV_MONARCH | ?wxPAPER_ENV_PERSONAL | ?wxPAPER_FANFOLD_US | ?wxPAPER_FANFOLD_STD_GERMAN | ?wxPAPER_FANFOLD_LGL_GERMAN | ?wxPAPER_ISO_B4 | ?wxPAPER_JAPANESE_POSTCARD | ?wxPAPER_9X11 | ?wxPAPER_10X11 | ?wxPAPER_15X11 | ?wxPAPER_ENV_INVITE | ?wxPAPER_LETTER_EXTRA | ?wxPAPER_LEGAL_EXTRA | ?wxPAPER_TABLOID_EXTRA | ?wxPAPER_A4_EXTRA | ?wxPAPER_LETTER_TRANSVERSE | ?wxPAPER_A4_TRANSVERSE | ?wxPAPER_LETTER_EXTRA_TRANSVERSE | ?wxPAPER_A_PLUS | ?wxPAPER_B_PLUS | ?wxPAPER_LETTER_PLUS | ?wxPAPER_A4_PLUS | ?wxPAPER_A5_TRANSVERSE | ?wxPAPER_B5_TRANSVERSE | ?wxPAPER_A3_EXTRA | ?wxPAPER_A5_EXTRA | ?wxPAPER_B5_EXTRA | ?wxPAPER_A2 | ?wxPAPER_A3_TRANSVERSE | ?wxPAPER_A3_EXTRA_TRANSVERSE | ?wxPAPER_DBL_JAPANESE_POSTCARD | ?wxPAPER_A6 | ?wxPAPER_JENV_KAKU2 | ?wxPAPER_JENV_KAKU3 | ?wxPAPER_JENV_CHOU3 | ?wxPAPER_JENV_CHOU4 | ?wxPAPER_LETTER_ROTATED | ?wxPAPER_A3_ROTATED | ?wxPAPER_A4_ROTATED | ?wxPAPER_A5_ROTATED | ?wxPAPER_B4_JIS_ROTATED | ?wxPAPER_B5_JIS_ROTATED | ?wxPAPER_JAPANESE_POSTCARD_ROTATED | ?wxPAPER_DBL_JAPANESE_POSTCARD_ROTATED | ?wxPAPER_A6_ROTATED | ?wxPAPER_JENV_KAKU2_ROTATED | ?wxPAPER_JENV_KAKU3_ROTATED | ?wxPAPER_JENV_CHOU3_ROTATED | ?wxPAPER_JENV_CHOU4_ROTATED | ?wxPAPER_B6_JIS | ?wxPAPER_B6_JIS_ROTATED | ?wxPAPER_12X11 | ?wxPAPER_JENV_YOU4 | ?wxPAPER_JENV_YOU4_ROTATED | ?wxPAPER_P16K | ?wxPAPER_P32K | ?wxPAPER_P32KBIG | ?wxPAPER_PENV_1 | ?wxPAPER_PENV_2 | ?wxPAPER_PENV_3 | ?wxPAPER_PENV_4 | ?wxPAPER_PENV_5 | ?wxPAPER_PENV_6 | ?wxPAPER_PENV_7 | ?wxPAPER_PENV_8 | ?wxPAPER_PENV_9 | ?wxPAPER_PENV_10 | ?wxPAPER_P16K_ROTATED | ?wxPAPER_P32K_ROTATED | ?wxPAPER_P32KBIG_ROTATED | ?wxPAPER_PENV_1_ROTATED | ?wxPAPER_PENV_2_ROTATED | ?wxPAPER_PENV_3_ROTATED | ?wxPAPER_PENV_4_ROTATED | ?wxPAPER_PENV_5_ROTATED | ?wxPAPER_PENV_6_ROTATED | ?wxPAPER_PENV_7_ROTATED | ?wxPAPER_PENV_8_ROTATED | ?wxPAPER_PENV_9_ROTATED | ?wxPAPER_PENV_10_ROTATED
-spec setPaperId(This, Id) -> ok when
- This::wxPageSetupDialogData(), Id::integer().
+ This::wxPageSetupDialogData(), Id::wx:wx_enum().
setPaperId(#wx_ref{type=ThisT,ref=ThisRef},Id)
when is_integer(Id) ->
?CLASS(ThisT,wxPageSetupDialogData),
@@ -293,8 +295,9 @@ setPaperId(#wx_ref{type=ThisT,ref=ThisRef},Id)
%% setPaperSize(This, Sz) -> ok when<br />
%% This::wxPageSetupDialogData(), Sz::{W::integer(), H::integer()}.<br />
%%
+%%<br /> Id = ?wxPAPER_NONE | ?wxPAPER_LETTER | ?wxPAPER_LEGAL | ?wxPAPER_A4 | ?wxPAPER_CSHEET | ?wxPAPER_DSHEET | ?wxPAPER_ESHEET | ?wxPAPER_LETTERSMALL | ?wxPAPER_TABLOID | ?wxPAPER_LEDGER | ?wxPAPER_STATEMENT | ?wxPAPER_EXECUTIVE | ?wxPAPER_A3 | ?wxPAPER_A4SMALL | ?wxPAPER_A5 | ?wxPAPER_B4 | ?wxPAPER_B5 | ?wxPAPER_FOLIO | ?wxPAPER_QUARTO | ?wxPAPER_10X14 | ?wxPAPER_11X17 | ?wxPAPER_NOTE | ?wxPAPER_ENV_9 | ?wxPAPER_ENV_10 | ?wxPAPER_ENV_11 | ?wxPAPER_ENV_12 | ?wxPAPER_ENV_14 | ?wxPAPER_ENV_DL | ?wxPAPER_ENV_C5 | ?wxPAPER_ENV_C3 | ?wxPAPER_ENV_C4 | ?wxPAPER_ENV_C6 | ?wxPAPER_ENV_C65 | ?wxPAPER_ENV_B4 | ?wxPAPER_ENV_B5 | ?wxPAPER_ENV_B6 | ?wxPAPER_ENV_ITALY | ?wxPAPER_ENV_MONARCH | ?wxPAPER_ENV_PERSONAL | ?wxPAPER_FANFOLD_US | ?wxPAPER_FANFOLD_STD_GERMAN | ?wxPAPER_FANFOLD_LGL_GERMAN | ?wxPAPER_ISO_B4 | ?wxPAPER_JAPANESE_POSTCARD | ?wxPAPER_9X11 | ?wxPAPER_10X11 | ?wxPAPER_15X11 | ?wxPAPER_ENV_INVITE | ?wxPAPER_LETTER_EXTRA | ?wxPAPER_LEGAL_EXTRA | ?wxPAPER_TABLOID_EXTRA | ?wxPAPER_A4_EXTRA | ?wxPAPER_LETTER_TRANSVERSE | ?wxPAPER_A4_TRANSVERSE | ?wxPAPER_LETTER_EXTRA_TRANSVERSE | ?wxPAPER_A_PLUS | ?wxPAPER_B_PLUS | ?wxPAPER_LETTER_PLUS | ?wxPAPER_A4_PLUS | ?wxPAPER_A5_TRANSVERSE | ?wxPAPER_B5_TRANSVERSE | ?wxPAPER_A3_EXTRA | ?wxPAPER_A5_EXTRA | ?wxPAPER_B5_EXTRA | ?wxPAPER_A2 | ?wxPAPER_A3_TRANSVERSE | ?wxPAPER_A3_EXTRA_TRANSVERSE | ?wxPAPER_DBL_JAPANESE_POSTCARD | ?wxPAPER_A6 | ?wxPAPER_JENV_KAKU2 | ?wxPAPER_JENV_KAKU3 | ?wxPAPER_JENV_CHOU3 | ?wxPAPER_JENV_CHOU4 | ?wxPAPER_LETTER_ROTATED | ?wxPAPER_A3_ROTATED | ?wxPAPER_A4_ROTATED | ?wxPAPER_A5_ROTATED | ?wxPAPER_B4_JIS_ROTATED | ?wxPAPER_B5_JIS_ROTATED | ?wxPAPER_JAPANESE_POSTCARD_ROTATED | ?wxPAPER_DBL_JAPANESE_POSTCARD_ROTATED | ?wxPAPER_A6_ROTATED | ?wxPAPER_JENV_KAKU2_ROTATED | ?wxPAPER_JENV_KAKU3_ROTATED | ?wxPAPER_JENV_CHOU3_ROTATED | ?wxPAPER_JENV_CHOU4_ROTATED | ?wxPAPER_B6_JIS | ?wxPAPER_B6_JIS_ROTATED | ?wxPAPER_12X11 | ?wxPAPER_JENV_YOU4 | ?wxPAPER_JENV_YOU4_ROTATED | ?wxPAPER_P16K | ?wxPAPER_P32K | ?wxPAPER_P32KBIG | ?wxPAPER_PENV_1 | ?wxPAPER_PENV_2 | ?wxPAPER_PENV_3 | ?wxPAPER_PENV_4 | ?wxPAPER_PENV_5 | ?wxPAPER_PENV_6 | ?wxPAPER_PENV_7 | ?wxPAPER_PENV_8 | ?wxPAPER_PENV_9 | ?wxPAPER_PENV_10 | ?wxPAPER_P16K_ROTATED | ?wxPAPER_P32K_ROTATED | ?wxPAPER_P32KBIG_ROTATED | ?wxPAPER_PENV_1_ROTATED | ?wxPAPER_PENV_2_ROTATED | ?wxPAPER_PENV_3_ROTATED | ?wxPAPER_PENV_4_ROTATED | ?wxPAPER_PENV_5_ROTATED | ?wxPAPER_PENV_6_ROTATED | ?wxPAPER_PENV_7_ROTATED | ?wxPAPER_PENV_8_ROTATED | ?wxPAPER_PENV_9_ROTATED | ?wxPAPER_PENV_10_ROTATED
-spec setPaperSize(This, Id) -> ok when
- This::wxPageSetupDialogData(), Id::integer();
+ This::wxPageSetupDialogData(), Id::wx:wx_enum();
(This, Sz) -> ok when
This::wxPageSetupDialogData(), Sz::{W::integer(), H::integer()}.
setPaperSize(#wx_ref{type=ThisT,ref=ThisRef},Id)
diff --git a/lib/wx/src/gen/wxPaintDC.erl b/lib/wx/src/gen/wxPaintDC.erl
index 9e81bc31af..6648f278bb 100644
--- a/lib/wx/src/gen/wxPaintDC.erl
+++ b/lib/wx/src/gen/wxPaintDC.erl
@@ -54,6 +54,8 @@
startPage/1]).
-export_type([wxPaintDC/0]).
+-deprecated([new/0]).
+
%% @hidden
parent_class(wxWindowDC) -> true;
parent_class(wxDC) -> true;
diff --git a/lib/wx/src/gen/wxPaintEvent.erl b/lib/wx/src/gen/wxPaintEvent.erl
index a13db607a4..80ac7d78ce 100644
--- a/lib/wx/src/gen/wxPaintEvent.erl
+++ b/lib/wx/src/gen/wxPaintEvent.erl
@@ -19,7 +19,7 @@
%% @doc See external documentation: <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpaintevent.html">wxPaintEvent</a>.
%% <dl><dt>Use {@link wxEvtHandler:connect/3.} with EventType:</dt>
-%% <dd><em>paint</em>, <em>paint_icon</em></dd></dl>
+%% <dd><em>paint</em></dd></dl>
%% See also the message variant {@link wxEvtHandler:wxPaint(). #wxPaint{}} event record type.
%%
%% <p>This class is derived (and can use functions) from:
diff --git a/lib/wx/src/gen/wxPen.erl b/lib/wx/src/gen/wxPen.erl
index 8b8aafddba..681a7edebc 100644
--- a/lib/wx/src/gen/wxPen.erl
+++ b/lib/wx/src/gen/wxPen.erl
@@ -113,8 +113,9 @@ isOk(#wx_ref{type=ThisT,ref=ThisRef}) ->
<<ThisRef:32/?UI>>).
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpen.html#wxpensetcap">external documentation</a>.
+%%<br /> CapStyle = integer
-spec setCap(This, CapStyle) -> ok when
- This::wxPen(), CapStyle::integer().
+ This::wxPen(), CapStyle::wx:wx_enum().
setCap(#wx_ref{type=ThisT,ref=ThisRef},CapStyle)
when is_integer(CapStyle) ->
?CLASS(ThisT,wxPen),
@@ -140,8 +141,9 @@ setColour(#wx_ref{type=ThisT,ref=ThisRef},Red,Green,Blue)
<<ThisRef:32/?UI,Red:32/?UI,Green:32/?UI,Blue:32/?UI>>).
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpen.html#wxpensetjoin">external documentation</a>.
+%%<br /> JoinStyle = integer
-spec setJoin(This, JoinStyle) -> ok when
- This::wxPen(), JoinStyle::integer().
+ This::wxPen(), JoinStyle::wx:wx_enum().
setJoin(#wx_ref{type=ThisT,ref=ThisRef},JoinStyle)
when is_integer(JoinStyle) ->
?CLASS(ThisT,wxPen),
diff --git a/lib/wx/src/gen/wxPostScriptDC.erl b/lib/wx/src/gen/wxPostScriptDC.erl
index 2eb25b6a8e..5329d4562e 100644
--- a/lib/wx/src/gen/wxPostScriptDC.erl
+++ b/lib/wx/src/gen/wxPostScriptDC.erl
@@ -53,6 +53,8 @@
startPage/1]).
-export_type([wxPostScriptDC/0]).
+-deprecated([getResolution/0,setResolution/1]).
+
%% @hidden
parent_class(wxDC) -> true;
parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
diff --git a/lib/wx/src/gen/wxPrintData.erl b/lib/wx/src/gen/wxPrintData.erl
index 2cb8dd3c5f..79ba26afab 100644
--- a/lib/wx/src/gen/wxPrintData.erl
+++ b/lib/wx/src/gen/wxPrintData.erl
@@ -102,7 +102,8 @@ getOrientation(#wx_ref{type=ThisT,ref=ThisRef}) ->
<<ThisRef:32/?UI>>).
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxprintdata.html#wxprintdatagetpaperid">external documentation</a>.
--spec getPaperId(This) -> integer() when
+%%<br /> Res = ?wxPAPER_NONE | ?wxPAPER_LETTER | ?wxPAPER_LEGAL | ?wxPAPER_A4 | ?wxPAPER_CSHEET | ?wxPAPER_DSHEET | ?wxPAPER_ESHEET | ?wxPAPER_LETTERSMALL | ?wxPAPER_TABLOID | ?wxPAPER_LEDGER | ?wxPAPER_STATEMENT | ?wxPAPER_EXECUTIVE | ?wxPAPER_A3 | ?wxPAPER_A4SMALL | ?wxPAPER_A5 | ?wxPAPER_B4 | ?wxPAPER_B5 | ?wxPAPER_FOLIO | ?wxPAPER_QUARTO | ?wxPAPER_10X14 | ?wxPAPER_11X17 | ?wxPAPER_NOTE | ?wxPAPER_ENV_9 | ?wxPAPER_ENV_10 | ?wxPAPER_ENV_11 | ?wxPAPER_ENV_12 | ?wxPAPER_ENV_14 | ?wxPAPER_ENV_DL | ?wxPAPER_ENV_C5 | ?wxPAPER_ENV_C3 | ?wxPAPER_ENV_C4 | ?wxPAPER_ENV_C6 | ?wxPAPER_ENV_C65 | ?wxPAPER_ENV_B4 | ?wxPAPER_ENV_B5 | ?wxPAPER_ENV_B6 | ?wxPAPER_ENV_ITALY | ?wxPAPER_ENV_MONARCH | ?wxPAPER_ENV_PERSONAL | ?wxPAPER_FANFOLD_US | ?wxPAPER_FANFOLD_STD_GERMAN | ?wxPAPER_FANFOLD_LGL_GERMAN | ?wxPAPER_ISO_B4 | ?wxPAPER_JAPANESE_POSTCARD | ?wxPAPER_9X11 | ?wxPAPER_10X11 | ?wxPAPER_15X11 | ?wxPAPER_ENV_INVITE | ?wxPAPER_LETTER_EXTRA | ?wxPAPER_LEGAL_EXTRA | ?wxPAPER_TABLOID_EXTRA | ?wxPAPER_A4_EXTRA | ?wxPAPER_LETTER_TRANSVERSE | ?wxPAPER_A4_TRANSVERSE | ?wxPAPER_LETTER_EXTRA_TRANSVERSE | ?wxPAPER_A_PLUS | ?wxPAPER_B_PLUS | ?wxPAPER_LETTER_PLUS | ?wxPAPER_A4_PLUS | ?wxPAPER_A5_TRANSVERSE | ?wxPAPER_B5_TRANSVERSE | ?wxPAPER_A3_EXTRA | ?wxPAPER_A5_EXTRA | ?wxPAPER_B5_EXTRA | ?wxPAPER_A2 | ?wxPAPER_A3_TRANSVERSE | ?wxPAPER_A3_EXTRA_TRANSVERSE | ?wxPAPER_DBL_JAPANESE_POSTCARD | ?wxPAPER_A6 | ?wxPAPER_JENV_KAKU2 | ?wxPAPER_JENV_KAKU3 | ?wxPAPER_JENV_CHOU3 | ?wxPAPER_JENV_CHOU4 | ?wxPAPER_LETTER_ROTATED | ?wxPAPER_A3_ROTATED | ?wxPAPER_A4_ROTATED | ?wxPAPER_A5_ROTATED | ?wxPAPER_B4_JIS_ROTATED | ?wxPAPER_B5_JIS_ROTATED | ?wxPAPER_JAPANESE_POSTCARD_ROTATED | ?wxPAPER_DBL_JAPANESE_POSTCARD_ROTATED | ?wxPAPER_A6_ROTATED | ?wxPAPER_JENV_KAKU2_ROTATED | ?wxPAPER_JENV_KAKU3_ROTATED | ?wxPAPER_JENV_CHOU3_ROTATED | ?wxPAPER_JENV_CHOU4_ROTATED | ?wxPAPER_B6_JIS | ?wxPAPER_B6_JIS_ROTATED | ?wxPAPER_12X11 | ?wxPAPER_JENV_YOU4 | ?wxPAPER_JENV_YOU4_ROTATED | ?wxPAPER_P16K | ?wxPAPER_P32K | ?wxPAPER_P32KBIG | ?wxPAPER_PENV_1 | ?wxPAPER_PENV_2 | ?wxPAPER_PENV_3 | ?wxPAPER_PENV_4 | ?wxPAPER_PENV_5 | ?wxPAPER_PENV_6 | ?wxPAPER_PENV_7 | ?wxPAPER_PENV_8 | ?wxPAPER_PENV_9 | ?wxPAPER_PENV_10 | ?wxPAPER_P16K_ROTATED | ?wxPAPER_P32K_ROTATED | ?wxPAPER_P32KBIG_ROTATED | ?wxPAPER_PENV_1_ROTATED | ?wxPAPER_PENV_2_ROTATED | ?wxPAPER_PENV_3_ROTATED | ?wxPAPER_PENV_4_ROTATED | ?wxPAPER_PENV_5_ROTATED | ?wxPAPER_PENV_6_ROTATED | ?wxPAPER_PENV_7_ROTATED | ?wxPAPER_PENV_8_ROTATED | ?wxPAPER_PENV_9_ROTATED | ?wxPAPER_PENV_10_ROTATED
+-spec getPaperId(This) -> wx:wx_enum() when
This::wxPrintData().
getPaperId(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxPrintData),
@@ -190,8 +191,9 @@ setOrientation(#wx_ref{type=ThisT,ref=ThisRef},Orient)
<<ThisRef:32/?UI,Orient:32/?UI>>).
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxprintdata.html#wxprintdatasetpaperid">external documentation</a>.
+%%<br /> SizeId = ?wxPAPER_NONE | ?wxPAPER_LETTER | ?wxPAPER_LEGAL | ?wxPAPER_A4 | ?wxPAPER_CSHEET | ?wxPAPER_DSHEET | ?wxPAPER_ESHEET | ?wxPAPER_LETTERSMALL | ?wxPAPER_TABLOID | ?wxPAPER_LEDGER | ?wxPAPER_STATEMENT | ?wxPAPER_EXECUTIVE | ?wxPAPER_A3 | ?wxPAPER_A4SMALL | ?wxPAPER_A5 | ?wxPAPER_B4 | ?wxPAPER_B5 | ?wxPAPER_FOLIO | ?wxPAPER_QUARTO | ?wxPAPER_10X14 | ?wxPAPER_11X17 | ?wxPAPER_NOTE | ?wxPAPER_ENV_9 | ?wxPAPER_ENV_10 | ?wxPAPER_ENV_11 | ?wxPAPER_ENV_12 | ?wxPAPER_ENV_14 | ?wxPAPER_ENV_DL | ?wxPAPER_ENV_C5 | ?wxPAPER_ENV_C3 | ?wxPAPER_ENV_C4 | ?wxPAPER_ENV_C6 | ?wxPAPER_ENV_C65 | ?wxPAPER_ENV_B4 | ?wxPAPER_ENV_B5 | ?wxPAPER_ENV_B6 | ?wxPAPER_ENV_ITALY | ?wxPAPER_ENV_MONARCH | ?wxPAPER_ENV_PERSONAL | ?wxPAPER_FANFOLD_US | ?wxPAPER_FANFOLD_STD_GERMAN | ?wxPAPER_FANFOLD_LGL_GERMAN | ?wxPAPER_ISO_B4 | ?wxPAPER_JAPANESE_POSTCARD | ?wxPAPER_9X11 | ?wxPAPER_10X11 | ?wxPAPER_15X11 | ?wxPAPER_ENV_INVITE | ?wxPAPER_LETTER_EXTRA | ?wxPAPER_LEGAL_EXTRA | ?wxPAPER_TABLOID_EXTRA | ?wxPAPER_A4_EXTRA | ?wxPAPER_LETTER_TRANSVERSE | ?wxPAPER_A4_TRANSVERSE | ?wxPAPER_LETTER_EXTRA_TRANSVERSE | ?wxPAPER_A_PLUS | ?wxPAPER_B_PLUS | ?wxPAPER_LETTER_PLUS | ?wxPAPER_A4_PLUS | ?wxPAPER_A5_TRANSVERSE | ?wxPAPER_B5_TRANSVERSE | ?wxPAPER_A3_EXTRA | ?wxPAPER_A5_EXTRA | ?wxPAPER_B5_EXTRA | ?wxPAPER_A2 | ?wxPAPER_A3_TRANSVERSE | ?wxPAPER_A3_EXTRA_TRANSVERSE | ?wxPAPER_DBL_JAPANESE_POSTCARD | ?wxPAPER_A6 | ?wxPAPER_JENV_KAKU2 | ?wxPAPER_JENV_KAKU3 | ?wxPAPER_JENV_CHOU3 | ?wxPAPER_JENV_CHOU4 | ?wxPAPER_LETTER_ROTATED | ?wxPAPER_A3_ROTATED | ?wxPAPER_A4_ROTATED | ?wxPAPER_A5_ROTATED | ?wxPAPER_B4_JIS_ROTATED | ?wxPAPER_B5_JIS_ROTATED | ?wxPAPER_JAPANESE_POSTCARD_ROTATED | ?wxPAPER_DBL_JAPANESE_POSTCARD_ROTATED | ?wxPAPER_A6_ROTATED | ?wxPAPER_JENV_KAKU2_ROTATED | ?wxPAPER_JENV_KAKU3_ROTATED | ?wxPAPER_JENV_CHOU3_ROTATED | ?wxPAPER_JENV_CHOU4_ROTATED | ?wxPAPER_B6_JIS | ?wxPAPER_B6_JIS_ROTATED | ?wxPAPER_12X11 | ?wxPAPER_JENV_YOU4 | ?wxPAPER_JENV_YOU4_ROTATED | ?wxPAPER_P16K | ?wxPAPER_P32K | ?wxPAPER_P32KBIG | ?wxPAPER_PENV_1 | ?wxPAPER_PENV_2 | ?wxPAPER_PENV_3 | ?wxPAPER_PENV_4 | ?wxPAPER_PENV_5 | ?wxPAPER_PENV_6 | ?wxPAPER_PENV_7 | ?wxPAPER_PENV_8 | ?wxPAPER_PENV_9 | ?wxPAPER_PENV_10 | ?wxPAPER_P16K_ROTATED | ?wxPAPER_P32K_ROTATED | ?wxPAPER_P32KBIG_ROTATED | ?wxPAPER_PENV_1_ROTATED | ?wxPAPER_PENV_2_ROTATED | ?wxPAPER_PENV_3_ROTATED | ?wxPAPER_PENV_4_ROTATED | ?wxPAPER_PENV_5_ROTATED | ?wxPAPER_PENV_6_ROTATED | ?wxPAPER_PENV_7_ROTATED | ?wxPAPER_PENV_8_ROTATED | ?wxPAPER_PENV_9_ROTATED | ?wxPAPER_PENV_10_ROTATED
-spec setPaperId(This, SizeId) -> ok when
- This::wxPrintData(), SizeId::integer().
+ This::wxPrintData(), SizeId::wx:wx_enum().
setPaperId(#wx_ref{type=ThisT,ref=ThisRef},SizeId)
when is_integer(SizeId) ->
?CLASS(ThisT,wxPrintData),
diff --git a/lib/wx/src/gen/wxPrintout.erl b/lib/wx/src/gen/wxPrintout.erl
index ab96a09c09..c75edd2b5a 100644
--- a/lib/wx/src/gen/wxPrintout.erl
+++ b/lib/wx/src/gen/wxPrintout.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -61,7 +61,8 @@ new(Title, OnPrintPage) ->
%% <pre>OnBeginDocument(This,StartPage,EndPage) -> boolean() </pre>
%% <pre>OnEndDocument(This) -> term() </pre>
%% <pre>HasPage(This,Page)} -> boolean() </pre>
-%% <pre>GetPageInfo(This) -> {MinPage:.integer(), MaxPage::integer(), PageFrom::integer(), PageTo::integer()} </pre>
+%% <pre>GetPageInfo(This) -> {MinPage::integer(), MaxPage::integer(),
+%% PageFrom::integer(), PageTo::integer()} </pre>
%% The <b>This</b> argument is the wxPrintout object reference to this object
%% <br /> NOTE: The callbacks may not call other processes.
new(Title, OnPrintPage, Opts) when is_list(Title), is_function(OnPrintPage), is_list(Opts) ->
diff --git a/lib/wx/src/gen/wxStyledTextCtrl.erl b/lib/wx/src/gen/wxStyledTextCtrl.erl
index f6dc2176b7..55ac410407 100644
--- a/lib/wx/src/gen/wxStyledTextCtrl.erl
+++ b/lib/wx/src/gen/wxStyledTextCtrl.erl
@@ -95,18 +95,18 @@
redo/1,registerImage/3,replaceSelection/2,replaceTarget/2,saveFile/2,
scrollToColumn/2,scrollToLine/2,searchAnchor/1,searchInTarget/2,searchNext/3,
searchPrev/3,selectAll/1,selectionDuplicate/1,selectionIsRectangle/1,
- sendMsg/2,sendMsg/3,setAnchor/2,setBackSpaceUnIndents/2,setBufferedDraw/2,
- setCaretForeground/2,setCaretLineBackAlpha/2,setCaretLineBackground/2,
- setCaretLineVisible/2,setCaretPeriod/2,setCaretSticky/2,setCaretWidth/2,
- setCharsDefault/1,setCodePage/2,setControlCharSymbol/2,setCurrentPos/2,
- setEOLMode/2,setEdgeColour/2,setEdgeColumn/2,setEdgeMode/2,setFoldExpanded/3,
- setFoldFlags/2,setFoldLevel/3,setFoldMarginColour/3,setFoldMarginHiColour/3,
- setHScrollBar/2,setHighlightGuide/2,setHotspotActiveBackground/3,
- setHotspotActiveForeground/3,setHotspotActiveUnderline/2,setHotspotSingleLine/2,
- setIndent/2,setIndentationGuides/2,setKeyWords/3,setLastKeydownProcessed/2,
- setLayoutCache/2,setLexer/2,setLexerLanguage/2,setLineIndentation/3,
- setLineState/3,setMarginLeft/2,setMarginMask/3,setMarginRight/2,setMarginSensitive/3,
- setMarginType/3,setMarginWidth/3,setMargins/3,setModEventMask/2,setMouseDownCaptures/2,
+ setAnchor/2,setBackSpaceUnIndents/2,setBufferedDraw/2,setCaretForeground/2,
+ setCaretLineBackAlpha/2,setCaretLineBackground/2,setCaretLineVisible/2,
+ setCaretPeriod/2,setCaretSticky/2,setCaretWidth/2,setCharsDefault/1,
+ setCodePage/2,setControlCharSymbol/2,setCurrentPos/2,setEOLMode/2,
+ setEdgeColour/2,setEdgeColumn/2,setEdgeMode/2,setFoldExpanded/3,setFoldFlags/2,
+ setFoldLevel/3,setFoldMarginColour/3,setFoldMarginHiColour/3,setHScrollBar/2,
+ setHighlightGuide/2,setHotspotActiveBackground/3,setHotspotActiveForeground/3,
+ setHotspotActiveUnderline/2,setHotspotSingleLine/2,setIndent/2,setIndentationGuides/2,
+ setKeyWords/3,setLastKeydownProcessed/2,setLayoutCache/2,setLexer/2,
+ setLexerLanguage/2,setLineIndentation/3,setLineState/3,setMarginLeft/2,
+ setMarginMask/3,setMarginRight/2,setMarginSensitive/3,setMarginType/3,
+ setMarginWidth/3,setMargins/3,setModEventMask/2,setMouseDownCaptures/2,
setMouseDwellTime/2,setPasteConvertEndings/2,setPrintColourMode/2,
setPrintMagnification/2,setProperty/3,setReadOnly/2,setSTCCursor/2,
setSTCFocus/2,setSavePoint/1,setScrollWidth/2,setSearchFlags/2,setSelAlpha/2,
@@ -3897,29 +3897,6 @@ scrollToColumn(#wx_ref{type=ThisT,ref=ThisRef},Column)
wxe_util:cast(?wxStyledTextCtrl_ScrollToColumn,
<<ThisRef:32/?UI,Column:32/?UI>>).
-%% @equiv sendMsg(This,Msg, [])
--spec sendMsg(This, Msg) -> integer() when
- This::wxStyledTextCtrl(), Msg::integer().
-
-sendMsg(This,Msg)
- when is_record(This, wx_ref),is_integer(Msg) ->
- sendMsg(This,Msg, []).
-
-%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstyledtextctrl.html#wxstyledtextctrlsendmsg">external documentation</a>.
--spec sendMsg(This, Msg, [Option]) -> integer() when
- This::wxStyledTextCtrl(), Msg::integer(),
- Option :: {wp, integer()}
- | {lp, integer()}.
-sendMsg(#wx_ref{type=ThisT,ref=ThisRef},Msg, Options)
- when is_integer(Msg),is_list(Options) ->
- ?CLASS(ThisT,wxStyledTextCtrl),
- MOpts = fun({wp, Wp}, Acc) -> [<<1:32/?UI,Wp:32/?UI>>|Acc];
- ({lp, Lp}, Acc) -> [<<2:32/?UI,Lp:32/?UI>>|Acc];
- (BadOpt, _) -> erlang:error({badoption, BadOpt}) end,
- BinOpt = list_to_binary(lists:foldl(MOpts, [<<0:32>>], Options)),
- wxe_util:call(?wxStyledTextCtrl_SendMsg,
- <<ThisRef:32/?UI,Msg:32/?UI, BinOpt/binary>>).
-
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstyledtextctrl.html#wxstyledtextctrlsetvscrollbar">external documentation</a>.
-spec setVScrollBar(This, Bar) -> ok when
This::wxStyledTextCtrl(), Bar::wxScrollBar:wxScrollBar().
diff --git a/lib/wx/src/gen/wxSystemSettings.erl b/lib/wx/src/gen/wxSystemSettings.erl
index a3bae5c85f..630162afd2 100644
--- a/lib/wx/src/gen/wxSystemSettings.erl
+++ b/lib/wx/src/gen/wxSystemSettings.erl
@@ -35,7 +35,7 @@ parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
-type wxSystemSettings() :: wx:wx_object().
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsystemsettings.html#wxsystemsettingsgetcolour">external documentation</a>.
-%%<br /> Index = ?wxSYS_COLOUR_SCROLLBAR | ?wxSYS_COLOUR_BACKGROUND | ?wxSYS_COLOUR_DESKTOP | ?wxSYS_COLOUR_ACTIVECAPTION | ?wxSYS_COLOUR_INACTIVECAPTION | ?wxSYS_COLOUR_MENU | ?wxSYS_COLOUR_WINDOW | ?wxSYS_COLOUR_WINDOWFRAME | ?wxSYS_COLOUR_MENUTEXT | ?wxSYS_COLOUR_WINDOWTEXT | ?wxSYS_COLOUR_CAPTIONTEXT | ?wxSYS_COLOUR_ACTIVEBORDER | ?wxSYS_COLOUR_INACTIVEBORDER | ?wxSYS_COLOUR_APPWORKSPACE | ?wxSYS_COLOUR_HIGHLIGHT | ?wxSYS_COLOUR_HIGHLIGHTTEXT | ?wxSYS_COLOUR_BTNFACE | ?wxSYS_COLOUR_3DFACE | ?wxSYS_COLOUR_BTNSHADOW | ?wxSYS_COLOUR_3DSHADOW | ?wxSYS_COLOUR_GRAYTEXT | ?wxSYS_COLOUR_BTNTEXT | ?wxSYS_COLOUR_INACTIVECAPTIONTEXT | ?wxSYS_COLOUR_BTNHIGHLIGHT | ?wxSYS_COLOUR_BTNHILIGHT | ?wxSYS_COLOUR_3DHIGHLIGHT | ?wxSYS_COLOUR_3DHILIGHT | ?wxSYS_COLOUR_3DDKSHADOW | ?wxSYS_COLOUR_3DLIGHT | ?wxSYS_COLOUR_INFOTEXT | ?wxSYS_COLOUR_INFOBK | ?wxSYS_COLOUR_LISTBOX | ?wxSYS_COLOUR_HOTLIGHT | ?wxSYS_COLOUR_GRADIENTACTIVECAPTION | ?wxSYS_COLOUR_GRADIENTINACTIVECAPTION | ?wxSYS_COLOUR_MENUHILIGHT | ?wxSYS_COLOUR_MENUBAR | ?wxSYS_COLOUR_LISTBOXTEXT | ?wxSYS_COLOUR_MAX
+%%<br /> Index = ?wxSYS_COLOUR_SCROLLBAR | ?wxSYS_COLOUR_BACKGROUND | ?wxSYS_COLOUR_DESKTOP | ?wxSYS_COLOUR_ACTIVECAPTION | ?wxSYS_COLOUR_INACTIVECAPTION | ?wxSYS_COLOUR_MENU | ?wxSYS_COLOUR_WINDOW | ?wxSYS_COLOUR_WINDOWFRAME | ?wxSYS_COLOUR_MENUTEXT | ?wxSYS_COLOUR_WINDOWTEXT | ?wxSYS_COLOUR_CAPTIONTEXT | ?wxSYS_COLOUR_ACTIVEBORDER | ?wxSYS_COLOUR_INACTIVEBORDER | ?wxSYS_COLOUR_APPWORKSPACE | ?wxSYS_COLOUR_HIGHLIGHT | ?wxSYS_COLOUR_HIGHLIGHTTEXT | ?wxSYS_COLOUR_BTNFACE | ?wxSYS_COLOUR_3DFACE | ?wxSYS_COLOUR_BTNSHADOW | ?wxSYS_COLOUR_3DSHADOW | ?wxSYS_COLOUR_GRAYTEXT | ?wxSYS_COLOUR_BTNTEXT | ?wxSYS_COLOUR_INACTIVECAPTIONTEXT | ?wxSYS_COLOUR_BTNHIGHLIGHT | ?wxSYS_COLOUR_BTNHILIGHT | ?wxSYS_COLOUR_3DHIGHLIGHT | ?wxSYS_COLOUR_3DHILIGHT | ?wxSYS_COLOUR_3DDKSHADOW | ?wxSYS_COLOUR_3DLIGHT | ?wxSYS_COLOUR_INFOTEXT | ?wxSYS_COLOUR_INFOBK | ?wxSYS_COLOUR_LISTBOX | ?wxSYS_COLOUR_HOTLIGHT | ?wxSYS_COLOUR_GRADIENTACTIVECAPTION | ?wxSYS_COLOUR_GRADIENTINACTIVECAPTION | ?wxSYS_COLOUR_MENUHILIGHT | ?wxSYS_COLOUR_MENUBAR | ?wxSYS_COLOUR_LISTBOXTEXT | ?wxSYS_COLOUR_LISTBOXHIGHLIGHTTEXT | ?wxSYS_COLOUR_MAX
-spec getColour(Index) -> wx:wx_colour4() when
Index::wx:wx_enum().
getColour(Index)
diff --git a/lib/wx/src/gen/wxWindowDC.erl b/lib/wx/src/gen/wxWindowDC.erl
index babb3c0e90..4515f0e6b9 100644
--- a/lib/wx/src/gen/wxWindowDC.erl
+++ b/lib/wx/src/gen/wxWindowDC.erl
@@ -53,6 +53,8 @@
startPage/1]).
-export_type([wxWindowDC/0]).
+-deprecated([new/0]).
+
%% @hidden
parent_class(wxDC) -> true;
parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
diff --git a/lib/wx/src/gen/wxe_debug.hrl b/lib/wx/src/gen/wxe_debug.hrl
index 297d99324a..6f4fa3fe34 100644
--- a/lib/wx/src/gen/wxe_debug.hrl
+++ b/lib/wx/src/gen/wxe_debug.hrl
@@ -3154,156 +3154,155 @@ wxdebug_table() ->
{3370, {wxStyledTextCtrl, pointFromPosition, 1}},
{3371, {wxStyledTextCtrl, scrollToLine, 1}},
{3372, {wxStyledTextCtrl, scrollToColumn, 1}},
- {3373, {wxStyledTextCtrl, sendMsg, 2}},
- {3374, {wxStyledTextCtrl, setVScrollBar, 1}},
- {3375, {wxStyledTextCtrl, setHScrollBar, 1}},
- {3376, {wxStyledTextCtrl, getLastKeydownProcessed, 0}},
- {3377, {wxStyledTextCtrl, setLastKeydownProcessed, 1}},
- {3378, {wxStyledTextCtrl, saveFile, 1}},
- {3379, {wxStyledTextCtrl, loadFile, 1}},
- {3380, {wxStyledTextCtrl, doDragOver, 3}},
- {3381, {wxStyledTextCtrl, doDropText, 3}},
- {3382, {wxStyledTextCtrl, getUseAntiAliasing, 0}},
- {3383, {wxStyledTextCtrl, addTextRaw, 1}},
- {3384, {wxStyledTextCtrl, insertTextRaw, 2}},
- {3385, {wxStyledTextCtrl, getCurLineRaw, 1}},
- {3386, {wxStyledTextCtrl, getLineRaw, 1}},
- {3387, {wxStyledTextCtrl, getSelectedTextRaw, 0}},
- {3388, {wxStyledTextCtrl, getTextRangeRaw, 2}},
- {3389, {wxStyledTextCtrl, setTextRaw, 1}},
- {3390, {wxStyledTextCtrl, getTextRaw, 0}},
- {3391, {wxStyledTextCtrl, appendTextRaw, 1}},
- {3392, {wxArtProvider, getBitmap, 2}},
- {3393, {wxArtProvider, getIcon, 2}},
- {3394, {wxTreeEvent, getKeyCode, 0}},
- {3395, {wxTreeEvent, getItem, 0}},
- {3396, {wxTreeEvent, getKeyEvent, 0}},
- {3397, {wxTreeEvent, getLabel, 0}},
- {3398, {wxTreeEvent, getOldItem, 0}},
- {3399, {wxTreeEvent, getPoint, 0}},
- {3400, {wxTreeEvent, isEditCancelled, 0}},
- {3401, {wxTreeEvent, setToolTip, 1}},
- {3402, {wxNotebookEvent, getOldSelection, 0}},
- {3403, {wxNotebookEvent, getSelection, 0}},
- {3404, {wxNotebookEvent, setOldSelection, 1}},
- {3405, {wxNotebookEvent, setSelection, 1}},
- {3406, {wxFileDataObject, new, 0}},
- {3407, {wxFileDataObject, addFile, 1}},
- {3408, {wxFileDataObject, getFilenames, 0}},
- {3409, {wxFileDataObject, 'Destroy', undefined}},
- {3410, {wxTextDataObject, new, 1}},
- {3411, {wxTextDataObject, getTextLength, 0}},
- {3412, {wxTextDataObject, getText, 0}},
- {3413, {wxTextDataObject, setText, 1}},
- {3414, {wxTextDataObject, 'Destroy', undefined}},
- {3415, {wxBitmapDataObject, new_1_1, 1}},
- {3416, {wxBitmapDataObject, new_1_0, 1}},
- {3417, {wxBitmapDataObject, getBitmap, 0}},
- {3418, {wxBitmapDataObject, setBitmap, 1}},
- {3419, {wxBitmapDataObject, 'Destroy', undefined}},
- {3421, {wxClipboard, new, 0}},
- {3422, {wxClipboard, destruct, 0}},
- {3423, {wxClipboard, addData, 1}},
- {3424, {wxClipboard, clear, 0}},
- {3425, {wxClipboard, close, 0}},
- {3426, {wxClipboard, flush, 0}},
- {3427, {wxClipboard, getData, 1}},
- {3428, {wxClipboard, isOpened, 0}},
- {3429, {wxClipboard, open, 0}},
- {3430, {wxClipboard, setData, 1}},
- {3432, {wxClipboard, usePrimarySelection, 1}},
- {3433, {wxClipboard, isSupported, 1}},
- {3434, {wxClipboard, get, 0}},
- {3435, {wxSpinEvent, getPosition, 0}},
- {3436, {wxSpinEvent, setPosition, 1}},
- {3437, {wxSplitterWindow, new_0, 0}},
- {3438, {wxSplitterWindow, new_2, 2}},
- {3439, {wxSplitterWindow, destruct, 0}},
- {3440, {wxSplitterWindow, create, 2}},
- {3441, {wxSplitterWindow, getMinimumPaneSize, 0}},
- {3442, {wxSplitterWindow, getSashGravity, 0}},
- {3443, {wxSplitterWindow, getSashPosition, 0}},
- {3444, {wxSplitterWindow, getSplitMode, 0}},
- {3445, {wxSplitterWindow, getWindow1, 0}},
- {3446, {wxSplitterWindow, getWindow2, 0}},
- {3447, {wxSplitterWindow, initialize, 1}},
- {3448, {wxSplitterWindow, isSplit, 0}},
- {3449, {wxSplitterWindow, replaceWindow, 2}},
- {3450, {wxSplitterWindow, setSashGravity, 1}},
- {3451, {wxSplitterWindow, setSashPosition, 2}},
- {3452, {wxSplitterWindow, setSashSize, 1}},
- {3453, {wxSplitterWindow, setMinimumPaneSize, 1}},
- {3454, {wxSplitterWindow, setSplitMode, 1}},
- {3455, {wxSplitterWindow, splitHorizontally, 3}},
- {3456, {wxSplitterWindow, splitVertically, 3}},
- {3457, {wxSplitterWindow, unsplit, 1}},
- {3458, {wxSplitterWindow, updateSize, 0}},
- {3459, {wxSplitterEvent, getSashPosition, 0}},
- {3460, {wxSplitterEvent, getX, 0}},
- {3461, {wxSplitterEvent, getY, 0}},
- {3462, {wxSplitterEvent, getWindowBeingRemoved, 0}},
- {3463, {wxSplitterEvent, setSashPosition, 1}},
- {3464, {wxHtmlWindow, new_0, 0}},
- {3465, {wxHtmlWindow, new_2, 2}},
- {3466, {wxHtmlWindow, appendToPage, 1}},
- {3467, {wxHtmlWindow, getOpenedAnchor, 0}},
- {3468, {wxHtmlWindow, getOpenedPage, 0}},
- {3469, {wxHtmlWindow, getOpenedPageTitle, 0}},
- {3470, {wxHtmlWindow, getRelatedFrame, 0}},
- {3471, {wxHtmlWindow, historyBack, 0}},
- {3472, {wxHtmlWindow, historyCanBack, 0}},
- {3473, {wxHtmlWindow, historyCanForward, 0}},
- {3474, {wxHtmlWindow, historyClear, 0}},
- {3475, {wxHtmlWindow, historyForward, 0}},
- {3476, {wxHtmlWindow, loadFile, 1}},
- {3477, {wxHtmlWindow, loadPage, 1}},
- {3478, {wxHtmlWindow, selectAll, 0}},
- {3479, {wxHtmlWindow, selectionToText, 0}},
- {3480, {wxHtmlWindow, selectLine, 1}},
- {3481, {wxHtmlWindow, selectWord, 1}},
- {3482, {wxHtmlWindow, setBorders, 1}},
- {3483, {wxHtmlWindow, setFonts, 3}},
- {3484, {wxHtmlWindow, setPage, 1}},
- {3485, {wxHtmlWindow, setRelatedFrame, 2}},
- {3486, {wxHtmlWindow, setRelatedStatusBar, 1}},
- {3487, {wxHtmlWindow, toText, 0}},
- {3488, {wxHtmlWindow, 'Destroy', undefined}},
- {3489, {wxHtmlLinkEvent, getLinkInfo, 0}},
- {3490, {wxSystemSettings, getColour, 1}},
- {3491, {wxSystemSettings, getFont, 1}},
- {3492, {wxSystemSettings, getMetric, 2}},
- {3493, {wxSystemSettings, getScreenType, 0}},
- {3494, {wxSystemOptions, getOption, 1}},
- {3495, {wxSystemOptions, getOptionInt, 1}},
- {3496, {wxSystemOptions, hasOption, 1}},
- {3497, {wxSystemOptions, isFalse, 1}},
- {3498, {wxSystemOptions, setOption_2_1, 2}},
- {3499, {wxSystemOptions, setOption_2_0, 2}},
- {3500, {wxAuiNotebookEvent, setSelection, 1}},
- {3501, {wxAuiNotebookEvent, getSelection, 0}},
- {3502, {wxAuiNotebookEvent, setOldSelection, 1}},
- {3503, {wxAuiNotebookEvent, getOldSelection, 0}},
- {3504, {wxAuiNotebookEvent, setDragSource, 1}},
- {3505, {wxAuiNotebookEvent, getDragSource, 0}},
- {3506, {wxAuiManagerEvent, setManager, 1}},
- {3507, {wxAuiManagerEvent, getManager, 0}},
- {3508, {wxAuiManagerEvent, setPane, 1}},
- {3509, {wxAuiManagerEvent, getPane, 0}},
- {3510, {wxAuiManagerEvent, setButton, 1}},
- {3511, {wxAuiManagerEvent, getButton, 0}},
- {3512, {wxAuiManagerEvent, setDC, 1}},
- {3513, {wxAuiManagerEvent, getDC, 0}},
- {3514, {wxAuiManagerEvent, veto, 1}},
- {3515, {wxAuiManagerEvent, getVeto, 0}},
- {3516, {wxAuiManagerEvent, setCanVeto, 1}},
- {3517, {wxAuiManagerEvent, canVeto, 0}},
- {3518, {wxLogNull, new, 0}},
- {3519, {wxLogNull, 'Destroy', undefined}},
- {3520, {wxTaskBarIcon, new, 0}},
- {3521, {wxTaskBarIcon, destruct, 0}},
- {3522, {wxTaskBarIcon, popupMenu, 1}},
- {3523, {wxTaskBarIcon, removeIcon, 0}},
- {3524, {wxTaskBarIcon, setIcon, 2}},
+ {3373, {wxStyledTextCtrl, setVScrollBar, 1}},
+ {3374, {wxStyledTextCtrl, setHScrollBar, 1}},
+ {3375, {wxStyledTextCtrl, getLastKeydownProcessed, 0}},
+ {3376, {wxStyledTextCtrl, setLastKeydownProcessed, 1}},
+ {3377, {wxStyledTextCtrl, saveFile, 1}},
+ {3378, {wxStyledTextCtrl, loadFile, 1}},
+ {3379, {wxStyledTextCtrl, doDragOver, 3}},
+ {3380, {wxStyledTextCtrl, doDropText, 3}},
+ {3381, {wxStyledTextCtrl, getUseAntiAliasing, 0}},
+ {3382, {wxStyledTextCtrl, addTextRaw, 1}},
+ {3383, {wxStyledTextCtrl, insertTextRaw, 2}},
+ {3384, {wxStyledTextCtrl, getCurLineRaw, 1}},
+ {3385, {wxStyledTextCtrl, getLineRaw, 1}},
+ {3386, {wxStyledTextCtrl, getSelectedTextRaw, 0}},
+ {3387, {wxStyledTextCtrl, getTextRangeRaw, 2}},
+ {3388, {wxStyledTextCtrl, setTextRaw, 1}},
+ {3389, {wxStyledTextCtrl, getTextRaw, 0}},
+ {3390, {wxStyledTextCtrl, appendTextRaw, 1}},
+ {3391, {wxArtProvider, getBitmap, 2}},
+ {3392, {wxArtProvider, getIcon, 2}},
+ {3393, {wxTreeEvent, getKeyCode, 0}},
+ {3394, {wxTreeEvent, getItem, 0}},
+ {3395, {wxTreeEvent, getKeyEvent, 0}},
+ {3396, {wxTreeEvent, getLabel, 0}},
+ {3397, {wxTreeEvent, getOldItem, 0}},
+ {3398, {wxTreeEvent, getPoint, 0}},
+ {3399, {wxTreeEvent, isEditCancelled, 0}},
+ {3400, {wxTreeEvent, setToolTip, 1}},
+ {3401, {wxNotebookEvent, getOldSelection, 0}},
+ {3402, {wxNotebookEvent, getSelection, 0}},
+ {3403, {wxNotebookEvent, setOldSelection, 1}},
+ {3404, {wxNotebookEvent, setSelection, 1}},
+ {3405, {wxFileDataObject, new, 0}},
+ {3406, {wxFileDataObject, addFile, 1}},
+ {3407, {wxFileDataObject, getFilenames, 0}},
+ {3408, {wxFileDataObject, 'Destroy', undefined}},
+ {3409, {wxTextDataObject, new, 1}},
+ {3410, {wxTextDataObject, getTextLength, 0}},
+ {3411, {wxTextDataObject, getText, 0}},
+ {3412, {wxTextDataObject, setText, 1}},
+ {3413, {wxTextDataObject, 'Destroy', undefined}},
+ {3414, {wxBitmapDataObject, new_1_1, 1}},
+ {3415, {wxBitmapDataObject, new_1_0, 1}},
+ {3416, {wxBitmapDataObject, getBitmap, 0}},
+ {3417, {wxBitmapDataObject, setBitmap, 1}},
+ {3418, {wxBitmapDataObject, 'Destroy', undefined}},
+ {3420, {wxClipboard, new, 0}},
+ {3421, {wxClipboard, destruct, 0}},
+ {3422, {wxClipboard, addData, 1}},
+ {3423, {wxClipboard, clear, 0}},
+ {3424, {wxClipboard, close, 0}},
+ {3425, {wxClipboard, flush, 0}},
+ {3426, {wxClipboard, getData, 1}},
+ {3427, {wxClipboard, isOpened, 0}},
+ {3428, {wxClipboard, open, 0}},
+ {3429, {wxClipboard, setData, 1}},
+ {3431, {wxClipboard, usePrimarySelection, 1}},
+ {3432, {wxClipboard, isSupported, 1}},
+ {3433, {wxClipboard, get, 0}},
+ {3434, {wxSpinEvent, getPosition, 0}},
+ {3435, {wxSpinEvent, setPosition, 1}},
+ {3436, {wxSplitterWindow, new_0, 0}},
+ {3437, {wxSplitterWindow, new_2, 2}},
+ {3438, {wxSplitterWindow, destruct, 0}},
+ {3439, {wxSplitterWindow, create, 2}},
+ {3440, {wxSplitterWindow, getMinimumPaneSize, 0}},
+ {3441, {wxSplitterWindow, getSashGravity, 0}},
+ {3442, {wxSplitterWindow, getSashPosition, 0}},
+ {3443, {wxSplitterWindow, getSplitMode, 0}},
+ {3444, {wxSplitterWindow, getWindow1, 0}},
+ {3445, {wxSplitterWindow, getWindow2, 0}},
+ {3446, {wxSplitterWindow, initialize, 1}},
+ {3447, {wxSplitterWindow, isSplit, 0}},
+ {3448, {wxSplitterWindow, replaceWindow, 2}},
+ {3449, {wxSplitterWindow, setSashGravity, 1}},
+ {3450, {wxSplitterWindow, setSashPosition, 2}},
+ {3451, {wxSplitterWindow, setSashSize, 1}},
+ {3452, {wxSplitterWindow, setMinimumPaneSize, 1}},
+ {3453, {wxSplitterWindow, setSplitMode, 1}},
+ {3454, {wxSplitterWindow, splitHorizontally, 3}},
+ {3455, {wxSplitterWindow, splitVertically, 3}},
+ {3456, {wxSplitterWindow, unsplit, 1}},
+ {3457, {wxSplitterWindow, updateSize, 0}},
+ {3458, {wxSplitterEvent, getSashPosition, 0}},
+ {3459, {wxSplitterEvent, getX, 0}},
+ {3460, {wxSplitterEvent, getY, 0}},
+ {3461, {wxSplitterEvent, getWindowBeingRemoved, 0}},
+ {3462, {wxSplitterEvent, setSashPosition, 1}},
+ {3463, {wxHtmlWindow, new_0, 0}},
+ {3464, {wxHtmlWindow, new_2, 2}},
+ {3465, {wxHtmlWindow, appendToPage, 1}},
+ {3466, {wxHtmlWindow, getOpenedAnchor, 0}},
+ {3467, {wxHtmlWindow, getOpenedPage, 0}},
+ {3468, {wxHtmlWindow, getOpenedPageTitle, 0}},
+ {3469, {wxHtmlWindow, getRelatedFrame, 0}},
+ {3470, {wxHtmlWindow, historyBack, 0}},
+ {3471, {wxHtmlWindow, historyCanBack, 0}},
+ {3472, {wxHtmlWindow, historyCanForward, 0}},
+ {3473, {wxHtmlWindow, historyClear, 0}},
+ {3474, {wxHtmlWindow, historyForward, 0}},
+ {3475, {wxHtmlWindow, loadFile, 1}},
+ {3476, {wxHtmlWindow, loadPage, 1}},
+ {3477, {wxHtmlWindow, selectAll, 0}},
+ {3478, {wxHtmlWindow, selectionToText, 0}},
+ {3479, {wxHtmlWindow, selectLine, 1}},
+ {3480, {wxHtmlWindow, selectWord, 1}},
+ {3481, {wxHtmlWindow, setBorders, 1}},
+ {3482, {wxHtmlWindow, setFonts, 3}},
+ {3483, {wxHtmlWindow, setPage, 1}},
+ {3484, {wxHtmlWindow, setRelatedFrame, 2}},
+ {3485, {wxHtmlWindow, setRelatedStatusBar, 1}},
+ {3486, {wxHtmlWindow, toText, 0}},
+ {3487, {wxHtmlWindow, 'Destroy', undefined}},
+ {3488, {wxHtmlLinkEvent, getLinkInfo, 0}},
+ {3489, {wxSystemSettings, getColour, 1}},
+ {3490, {wxSystemSettings, getFont, 1}},
+ {3491, {wxSystemSettings, getMetric, 2}},
+ {3492, {wxSystemSettings, getScreenType, 0}},
+ {3493, {wxSystemOptions, getOption, 1}},
+ {3494, {wxSystemOptions, getOptionInt, 1}},
+ {3495, {wxSystemOptions, hasOption, 1}},
+ {3496, {wxSystemOptions, isFalse, 1}},
+ {3497, {wxSystemOptions, setOption_2_1, 2}},
+ {3498, {wxSystemOptions, setOption_2_0, 2}},
+ {3499, {wxAuiNotebookEvent, setSelection, 1}},
+ {3500, {wxAuiNotebookEvent, getSelection, 0}},
+ {3501, {wxAuiNotebookEvent, setOldSelection, 1}},
+ {3502, {wxAuiNotebookEvent, getOldSelection, 0}},
+ {3503, {wxAuiNotebookEvent, setDragSource, 1}},
+ {3504, {wxAuiNotebookEvent, getDragSource, 0}},
+ {3505, {wxAuiManagerEvent, setManager, 1}},
+ {3506, {wxAuiManagerEvent, getManager, 0}},
+ {3507, {wxAuiManagerEvent, setPane, 1}},
+ {3508, {wxAuiManagerEvent, getPane, 0}},
+ {3509, {wxAuiManagerEvent, setButton, 1}},
+ {3510, {wxAuiManagerEvent, getButton, 0}},
+ {3511, {wxAuiManagerEvent, setDC, 1}},
+ {3512, {wxAuiManagerEvent, getDC, 0}},
+ {3513, {wxAuiManagerEvent, veto, 1}},
+ {3514, {wxAuiManagerEvent, getVeto, 0}},
+ {3515, {wxAuiManagerEvent, setCanVeto, 1}},
+ {3516, {wxAuiManagerEvent, canVeto, 0}},
+ {3517, {wxLogNull, new, 0}},
+ {3518, {wxLogNull, 'Destroy', undefined}},
+ {3519, {wxTaskBarIcon, new, 0}},
+ {3520, {wxTaskBarIcon, destruct, 0}},
+ {3521, {wxTaskBarIcon, popupMenu, 1}},
+ {3522, {wxTaskBarIcon, removeIcon, 0}},
+ {3523, {wxTaskBarIcon, setIcon, 2}},
{-1, {mod, func, -1}}
].
diff --git a/lib/wx/src/gen/wxe_funcs.hrl b/lib/wx/src/gen/wxe_funcs.hrl
index fe35cb1374..e6aced6e09 100644
--- a/lib/wx/src/gen/wxe_funcs.hrl
+++ b/lib/wx/src/gen/wxe_funcs.hrl
@@ -3151,153 +3151,152 @@
-define(wxStyledTextCtrl_PointFromPosition, 3370).
-define(wxStyledTextCtrl_ScrollToLine, 3371).
-define(wxStyledTextCtrl_ScrollToColumn, 3372).
--define(wxStyledTextCtrl_SendMsg, 3373).
--define(wxStyledTextCtrl_SetVScrollBar, 3374).
--define(wxStyledTextCtrl_SetHScrollBar, 3375).
--define(wxStyledTextCtrl_GetLastKeydownProcessed, 3376).
--define(wxStyledTextCtrl_SetLastKeydownProcessed, 3377).
--define(wxStyledTextCtrl_SaveFile, 3378).
--define(wxStyledTextCtrl_LoadFile, 3379).
--define(wxStyledTextCtrl_DoDragOver, 3380).
--define(wxStyledTextCtrl_DoDropText, 3381).
--define(wxStyledTextCtrl_GetUseAntiAliasing, 3382).
--define(wxStyledTextCtrl_AddTextRaw, 3383).
--define(wxStyledTextCtrl_InsertTextRaw, 3384).
--define(wxStyledTextCtrl_GetCurLineRaw, 3385).
--define(wxStyledTextCtrl_GetLineRaw, 3386).
--define(wxStyledTextCtrl_GetSelectedTextRaw, 3387).
--define(wxStyledTextCtrl_GetTextRangeRaw, 3388).
--define(wxStyledTextCtrl_SetTextRaw, 3389).
--define(wxStyledTextCtrl_GetTextRaw, 3390).
--define(wxStyledTextCtrl_AppendTextRaw, 3391).
--define(wxArtProvider_GetBitmap, 3392).
--define(wxArtProvider_GetIcon, 3393).
--define(wxTreeEvent_GetKeyCode, 3394).
--define(wxTreeEvent_GetItem, 3395).
--define(wxTreeEvent_GetKeyEvent, 3396).
--define(wxTreeEvent_GetLabel, 3397).
--define(wxTreeEvent_GetOldItem, 3398).
--define(wxTreeEvent_GetPoint, 3399).
--define(wxTreeEvent_IsEditCancelled, 3400).
--define(wxTreeEvent_SetToolTip, 3401).
--define(wxNotebookEvent_GetOldSelection, 3402).
--define(wxNotebookEvent_GetSelection, 3403).
--define(wxNotebookEvent_SetOldSelection, 3404).
--define(wxNotebookEvent_SetSelection, 3405).
--define(wxFileDataObject_new, 3406).
--define(wxFileDataObject_AddFile, 3407).
--define(wxFileDataObject_GetFilenames, 3408).
--define(wxFileDataObject_destroy, 3409).
--define(wxTextDataObject_new, 3410).
--define(wxTextDataObject_GetTextLength, 3411).
--define(wxTextDataObject_GetText, 3412).
--define(wxTextDataObject_SetText, 3413).
--define(wxTextDataObject_destroy, 3414).
--define(wxBitmapDataObject_new_1_1, 3415).
--define(wxBitmapDataObject_new_1_0, 3416).
--define(wxBitmapDataObject_GetBitmap, 3417).
--define(wxBitmapDataObject_SetBitmap, 3418).
--define(wxBitmapDataObject_destroy, 3419).
--define(wxClipboard_new, 3421).
--define(wxClipboard_destruct, 3422).
--define(wxClipboard_AddData, 3423).
--define(wxClipboard_Clear, 3424).
--define(wxClipboard_Close, 3425).
--define(wxClipboard_Flush, 3426).
--define(wxClipboard_GetData, 3427).
--define(wxClipboard_IsOpened, 3428).
--define(wxClipboard_Open, 3429).
--define(wxClipboard_SetData, 3430).
--define(wxClipboard_UsePrimarySelection, 3432).
--define(wxClipboard_IsSupported, 3433).
--define(wxClipboard_Get, 3434).
--define(wxSpinEvent_GetPosition, 3435).
--define(wxSpinEvent_SetPosition, 3436).
--define(wxSplitterWindow_new_0, 3437).
--define(wxSplitterWindow_new_2, 3438).
--define(wxSplitterWindow_destruct, 3439).
--define(wxSplitterWindow_Create, 3440).
--define(wxSplitterWindow_GetMinimumPaneSize, 3441).
--define(wxSplitterWindow_GetSashGravity, 3442).
--define(wxSplitterWindow_GetSashPosition, 3443).
--define(wxSplitterWindow_GetSplitMode, 3444).
--define(wxSplitterWindow_GetWindow1, 3445).
--define(wxSplitterWindow_GetWindow2, 3446).
--define(wxSplitterWindow_Initialize, 3447).
--define(wxSplitterWindow_IsSplit, 3448).
--define(wxSplitterWindow_ReplaceWindow, 3449).
--define(wxSplitterWindow_SetSashGravity, 3450).
--define(wxSplitterWindow_SetSashPosition, 3451).
--define(wxSplitterWindow_SetSashSize, 3452).
--define(wxSplitterWindow_SetMinimumPaneSize, 3453).
--define(wxSplitterWindow_SetSplitMode, 3454).
--define(wxSplitterWindow_SplitHorizontally, 3455).
--define(wxSplitterWindow_SplitVertically, 3456).
--define(wxSplitterWindow_Unsplit, 3457).
--define(wxSplitterWindow_UpdateSize, 3458).
--define(wxSplitterEvent_GetSashPosition, 3459).
--define(wxSplitterEvent_GetX, 3460).
--define(wxSplitterEvent_GetY, 3461).
--define(wxSplitterEvent_GetWindowBeingRemoved, 3462).
--define(wxSplitterEvent_SetSashPosition, 3463).
--define(wxHtmlWindow_new_0, 3464).
--define(wxHtmlWindow_new_2, 3465).
--define(wxHtmlWindow_AppendToPage, 3466).
--define(wxHtmlWindow_GetOpenedAnchor, 3467).
--define(wxHtmlWindow_GetOpenedPage, 3468).
--define(wxHtmlWindow_GetOpenedPageTitle, 3469).
--define(wxHtmlWindow_GetRelatedFrame, 3470).
--define(wxHtmlWindow_HistoryBack, 3471).
--define(wxHtmlWindow_HistoryCanBack, 3472).
--define(wxHtmlWindow_HistoryCanForward, 3473).
--define(wxHtmlWindow_HistoryClear, 3474).
--define(wxHtmlWindow_HistoryForward, 3475).
--define(wxHtmlWindow_LoadFile, 3476).
--define(wxHtmlWindow_LoadPage, 3477).
--define(wxHtmlWindow_SelectAll, 3478).
--define(wxHtmlWindow_SelectionToText, 3479).
--define(wxHtmlWindow_SelectLine, 3480).
--define(wxHtmlWindow_SelectWord, 3481).
--define(wxHtmlWindow_SetBorders, 3482).
--define(wxHtmlWindow_SetFonts, 3483).
--define(wxHtmlWindow_SetPage, 3484).
--define(wxHtmlWindow_SetRelatedFrame, 3485).
--define(wxHtmlWindow_SetRelatedStatusBar, 3486).
--define(wxHtmlWindow_ToText, 3487).
--define(wxHtmlWindow_destroy, 3488).
--define(wxHtmlLinkEvent_GetLinkInfo, 3489).
--define(wxSystemSettings_GetColour, 3490).
--define(wxSystemSettings_GetFont, 3491).
--define(wxSystemSettings_GetMetric, 3492).
--define(wxSystemSettings_GetScreenType, 3493).
--define(wxSystemOptions_GetOption, 3494).
--define(wxSystemOptions_GetOptionInt, 3495).
--define(wxSystemOptions_HasOption, 3496).
--define(wxSystemOptions_IsFalse, 3497).
--define(wxSystemOptions_SetOption_2_1, 3498).
--define(wxSystemOptions_SetOption_2_0, 3499).
--define(wxAuiNotebookEvent_SetSelection, 3500).
--define(wxAuiNotebookEvent_GetSelection, 3501).
--define(wxAuiNotebookEvent_SetOldSelection, 3502).
--define(wxAuiNotebookEvent_GetOldSelection, 3503).
--define(wxAuiNotebookEvent_SetDragSource, 3504).
--define(wxAuiNotebookEvent_GetDragSource, 3505).
--define(wxAuiManagerEvent_SetManager, 3506).
--define(wxAuiManagerEvent_GetManager, 3507).
--define(wxAuiManagerEvent_SetPane, 3508).
--define(wxAuiManagerEvent_GetPane, 3509).
--define(wxAuiManagerEvent_SetButton, 3510).
--define(wxAuiManagerEvent_GetButton, 3511).
--define(wxAuiManagerEvent_SetDC, 3512).
--define(wxAuiManagerEvent_GetDC, 3513).
--define(wxAuiManagerEvent_Veto, 3514).
--define(wxAuiManagerEvent_GetVeto, 3515).
--define(wxAuiManagerEvent_SetCanVeto, 3516).
--define(wxAuiManagerEvent_CanVeto, 3517).
--define(wxLogNull_new, 3518).
--define(wxLogNull_destroy, 3519).
--define(wxTaskBarIcon_new, 3520).
--define(wxTaskBarIcon_destruct, 3521).
--define(wxTaskBarIcon_PopupMenu, 3522).
--define(wxTaskBarIcon_RemoveIcon, 3523).
--define(wxTaskBarIcon_SetIcon, 3524).
+-define(wxStyledTextCtrl_SetVScrollBar, 3373).
+-define(wxStyledTextCtrl_SetHScrollBar, 3374).
+-define(wxStyledTextCtrl_GetLastKeydownProcessed, 3375).
+-define(wxStyledTextCtrl_SetLastKeydownProcessed, 3376).
+-define(wxStyledTextCtrl_SaveFile, 3377).
+-define(wxStyledTextCtrl_LoadFile, 3378).
+-define(wxStyledTextCtrl_DoDragOver, 3379).
+-define(wxStyledTextCtrl_DoDropText, 3380).
+-define(wxStyledTextCtrl_GetUseAntiAliasing, 3381).
+-define(wxStyledTextCtrl_AddTextRaw, 3382).
+-define(wxStyledTextCtrl_InsertTextRaw, 3383).
+-define(wxStyledTextCtrl_GetCurLineRaw, 3384).
+-define(wxStyledTextCtrl_GetLineRaw, 3385).
+-define(wxStyledTextCtrl_GetSelectedTextRaw, 3386).
+-define(wxStyledTextCtrl_GetTextRangeRaw, 3387).
+-define(wxStyledTextCtrl_SetTextRaw, 3388).
+-define(wxStyledTextCtrl_GetTextRaw, 3389).
+-define(wxStyledTextCtrl_AppendTextRaw, 3390).
+-define(wxArtProvider_GetBitmap, 3391).
+-define(wxArtProvider_GetIcon, 3392).
+-define(wxTreeEvent_GetKeyCode, 3393).
+-define(wxTreeEvent_GetItem, 3394).
+-define(wxTreeEvent_GetKeyEvent, 3395).
+-define(wxTreeEvent_GetLabel, 3396).
+-define(wxTreeEvent_GetOldItem, 3397).
+-define(wxTreeEvent_GetPoint, 3398).
+-define(wxTreeEvent_IsEditCancelled, 3399).
+-define(wxTreeEvent_SetToolTip, 3400).
+-define(wxNotebookEvent_GetOldSelection, 3401).
+-define(wxNotebookEvent_GetSelection, 3402).
+-define(wxNotebookEvent_SetOldSelection, 3403).
+-define(wxNotebookEvent_SetSelection, 3404).
+-define(wxFileDataObject_new, 3405).
+-define(wxFileDataObject_AddFile, 3406).
+-define(wxFileDataObject_GetFilenames, 3407).
+-define(wxFileDataObject_destroy, 3408).
+-define(wxTextDataObject_new, 3409).
+-define(wxTextDataObject_GetTextLength, 3410).
+-define(wxTextDataObject_GetText, 3411).
+-define(wxTextDataObject_SetText, 3412).
+-define(wxTextDataObject_destroy, 3413).
+-define(wxBitmapDataObject_new_1_1, 3414).
+-define(wxBitmapDataObject_new_1_0, 3415).
+-define(wxBitmapDataObject_GetBitmap, 3416).
+-define(wxBitmapDataObject_SetBitmap, 3417).
+-define(wxBitmapDataObject_destroy, 3418).
+-define(wxClipboard_new, 3420).
+-define(wxClipboard_destruct, 3421).
+-define(wxClipboard_AddData, 3422).
+-define(wxClipboard_Clear, 3423).
+-define(wxClipboard_Close, 3424).
+-define(wxClipboard_Flush, 3425).
+-define(wxClipboard_GetData, 3426).
+-define(wxClipboard_IsOpened, 3427).
+-define(wxClipboard_Open, 3428).
+-define(wxClipboard_SetData, 3429).
+-define(wxClipboard_UsePrimarySelection, 3431).
+-define(wxClipboard_IsSupported, 3432).
+-define(wxClipboard_Get, 3433).
+-define(wxSpinEvent_GetPosition, 3434).
+-define(wxSpinEvent_SetPosition, 3435).
+-define(wxSplitterWindow_new_0, 3436).
+-define(wxSplitterWindow_new_2, 3437).
+-define(wxSplitterWindow_destruct, 3438).
+-define(wxSplitterWindow_Create, 3439).
+-define(wxSplitterWindow_GetMinimumPaneSize, 3440).
+-define(wxSplitterWindow_GetSashGravity, 3441).
+-define(wxSplitterWindow_GetSashPosition, 3442).
+-define(wxSplitterWindow_GetSplitMode, 3443).
+-define(wxSplitterWindow_GetWindow1, 3444).
+-define(wxSplitterWindow_GetWindow2, 3445).
+-define(wxSplitterWindow_Initialize, 3446).
+-define(wxSplitterWindow_IsSplit, 3447).
+-define(wxSplitterWindow_ReplaceWindow, 3448).
+-define(wxSplitterWindow_SetSashGravity, 3449).
+-define(wxSplitterWindow_SetSashPosition, 3450).
+-define(wxSplitterWindow_SetSashSize, 3451).
+-define(wxSplitterWindow_SetMinimumPaneSize, 3452).
+-define(wxSplitterWindow_SetSplitMode, 3453).
+-define(wxSplitterWindow_SplitHorizontally, 3454).
+-define(wxSplitterWindow_SplitVertically, 3455).
+-define(wxSplitterWindow_Unsplit, 3456).
+-define(wxSplitterWindow_UpdateSize, 3457).
+-define(wxSplitterEvent_GetSashPosition, 3458).
+-define(wxSplitterEvent_GetX, 3459).
+-define(wxSplitterEvent_GetY, 3460).
+-define(wxSplitterEvent_GetWindowBeingRemoved, 3461).
+-define(wxSplitterEvent_SetSashPosition, 3462).
+-define(wxHtmlWindow_new_0, 3463).
+-define(wxHtmlWindow_new_2, 3464).
+-define(wxHtmlWindow_AppendToPage, 3465).
+-define(wxHtmlWindow_GetOpenedAnchor, 3466).
+-define(wxHtmlWindow_GetOpenedPage, 3467).
+-define(wxHtmlWindow_GetOpenedPageTitle, 3468).
+-define(wxHtmlWindow_GetRelatedFrame, 3469).
+-define(wxHtmlWindow_HistoryBack, 3470).
+-define(wxHtmlWindow_HistoryCanBack, 3471).
+-define(wxHtmlWindow_HistoryCanForward, 3472).
+-define(wxHtmlWindow_HistoryClear, 3473).
+-define(wxHtmlWindow_HistoryForward, 3474).
+-define(wxHtmlWindow_LoadFile, 3475).
+-define(wxHtmlWindow_LoadPage, 3476).
+-define(wxHtmlWindow_SelectAll, 3477).
+-define(wxHtmlWindow_SelectionToText, 3478).
+-define(wxHtmlWindow_SelectLine, 3479).
+-define(wxHtmlWindow_SelectWord, 3480).
+-define(wxHtmlWindow_SetBorders, 3481).
+-define(wxHtmlWindow_SetFonts, 3482).
+-define(wxHtmlWindow_SetPage, 3483).
+-define(wxHtmlWindow_SetRelatedFrame, 3484).
+-define(wxHtmlWindow_SetRelatedStatusBar, 3485).
+-define(wxHtmlWindow_ToText, 3486).
+-define(wxHtmlWindow_destroy, 3487).
+-define(wxHtmlLinkEvent_GetLinkInfo, 3488).
+-define(wxSystemSettings_GetColour, 3489).
+-define(wxSystemSettings_GetFont, 3490).
+-define(wxSystemSettings_GetMetric, 3491).
+-define(wxSystemSettings_GetScreenType, 3492).
+-define(wxSystemOptions_GetOption, 3493).
+-define(wxSystemOptions_GetOptionInt, 3494).
+-define(wxSystemOptions_HasOption, 3495).
+-define(wxSystemOptions_IsFalse, 3496).
+-define(wxSystemOptions_SetOption_2_1, 3497).
+-define(wxSystemOptions_SetOption_2_0, 3498).
+-define(wxAuiNotebookEvent_SetSelection, 3499).
+-define(wxAuiNotebookEvent_GetSelection, 3500).
+-define(wxAuiNotebookEvent_SetOldSelection, 3501).
+-define(wxAuiNotebookEvent_GetOldSelection, 3502).
+-define(wxAuiNotebookEvent_SetDragSource, 3503).
+-define(wxAuiNotebookEvent_GetDragSource, 3504).
+-define(wxAuiManagerEvent_SetManager, 3505).
+-define(wxAuiManagerEvent_GetManager, 3506).
+-define(wxAuiManagerEvent_SetPane, 3507).
+-define(wxAuiManagerEvent_GetPane, 3508).
+-define(wxAuiManagerEvent_SetButton, 3509).
+-define(wxAuiManagerEvent_GetButton, 3510).
+-define(wxAuiManagerEvent_SetDC, 3511).
+-define(wxAuiManagerEvent_GetDC, 3512).
+-define(wxAuiManagerEvent_Veto, 3513).
+-define(wxAuiManagerEvent_GetVeto, 3514).
+-define(wxAuiManagerEvent_SetCanVeto, 3515).
+-define(wxAuiManagerEvent_CanVeto, 3516).
+-define(wxLogNull_new, 3517).
+-define(wxLogNull_destroy, 3518).
+-define(wxTaskBarIcon_new, 3519).
+-define(wxTaskBarIcon_destruct, 3520).
+-define(wxTaskBarIcon_PopupMenu, 3521).
+-define(wxTaskBarIcon_RemoveIcon, 3522).
+-define(wxTaskBarIcon_SetIcon, 3523).
diff --git a/lib/wx/src/wx.erl b/lib/wx/src/wx.erl
index 7d62305048..2a4b18d101 100644
--- a/lib/wx/src/wx.erl
+++ b/lib/wx/src/wx.erl
@@ -102,12 +102,18 @@ new() ->
%% @doc Starts a wx server.
%% Option may be {debug, Level}, see debug/1.
--spec new([Option]) -> wx_object() when Option :: {debug, list() | atom()}.
+%% Or {silent_start, Bool}, which causes error messages at startup to
+%% be suppressed. The latter can be used as a silent test of whether
+%% wx is properly installed or not.
+-spec new([Option]) -> wx_object() when Option :: {debug, list() | atom()} |
+ {silent_start, boolean()}.
new(Options) when is_list(Options) ->
- #wx_env{port=Port} = wxe_server:start(),
- put(opengl_port, Port),
Debug = proplists:get_value(debug, Options, 0),
- debug(Debug),
+ SilentStart = proplists:get_value(silent_start, Options, false),
+ Level = calc_level(Debug),
+ #wx_env{port=Port} = wxe_server:start(SilentStart andalso Level =:= 0),
+ put(opengl_port, Port),
+ set_debug(Level),
null().
%% @doc Stops a wx server.
@@ -282,13 +288,16 @@ release_memory(Bin) when is_binary(Bin) ->
-spec debug(Level | [Level]) -> ok
when Level :: none | verbose | trace | driver | integer().
-debug(none) -> debug(0);
-debug(verbose) -> debug(1);
-debug(trace) -> debug(2);
-debug(driver) -> debug(16);
-debug([]) -> debug(0);
+debug(Debug) ->
+ Level = calc_level(Debug),
+ set_debug(Level).
-debug(List) when is_list(List) ->
+calc_level(none) -> calc_level(0);
+calc_level(verbose) -> calc_level(1);
+calc_level(trace) -> calc_level(2);
+calc_level(driver) -> calc_level(16);
+calc_level([]) -> calc_level(0);
+calc_level(List) when is_list(List) ->
{Drv,Erl} =
lists:foldl(fun(verbose, {Drv,_Erl}) ->
{Drv,1};
@@ -297,8 +306,11 @@ debug(List) when is_list(List) ->
(driver, {_Drv,Erl}) ->
{16, Erl}
end, {0,0}, List),
- debug(Drv + Erl);
-debug(Level) when is_integer(Level) ->
+ Drv + Erl;
+calc_level(Level) when is_integer(Level) ->
+ Level.
+
+set_debug(Level) when is_integer(Level) ->
case get(?WXE_IDENTIFIER) of
undefined -> erlang:error({wxe,unknown_port});
#wx_env{debug=Old} when Old =:= Level -> ok;
diff --git a/lib/wx/src/wxe_master.erl b/lib/wx/src/wxe_master.erl
index ac6e4a56e6..b98a7c793e 100644
--- a/lib/wx/src/wxe_master.erl
+++ b/lib/wx/src/wxe_master.erl
@@ -28,7 +28,7 @@
-behaviour(gen_server).
%% API
--export([start/0, init_port/0, init_opengl/0]).
+-export([start/1, init_port/1, init_opengl/0]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
@@ -47,20 +47,20 @@
%% API
%%====================================================================
%%--------------------------------------------------------------------
-%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
+%% Function: start(SilentStart) -> {ok,Pid} | ignore | {error,Error}
%% Description: Starts the server
%%--------------------------------------------------------------------
-start() ->
- gen_server:start({local, ?MODULE}, ?MODULE, [], []).
+start(SilentStart) ->
+ gen_server:start({local, ?MODULE}, ?MODULE, [SilentStart], []).
%%--------------------------------------------------------------------
-%% Function: init_port() -> {UserPort,CallBackPort} | error(Error)
+%% Function: init_port(SilentStart) -> {UserPort,CallBackPort} | error(Error)
%% Description: Creates the port
%%--------------------------------------------------------------------
-init_port() ->
+init_port(SilentStart) ->
case whereis(?MODULE) of
undefined ->
- case start() of
+ case start(SilentStart) of
{ok,Pid} -> Pid;
{error,{already_started,Pid}} -> Pid;
{error, {Reason,Stack}} ->
@@ -93,14 +93,17 @@ init_opengl() ->
%% {stop, Reason}
%% Description: Initiates the server
%%--------------------------------------------------------------------
-init([]) ->
+init([SilentStart]) ->
DriverName = ?DRIVER,
- PrivDir = wxe_util:priv_dir(?DRIVER),
+ PrivDir = wxe_util:priv_dir(?DRIVER, SilentStart),
erlang:group_leader(whereis(init), self()),
case catch erlang:system_info(smp_support) of
true -> ok;
_ ->
- error_logger:format("WX ERROR: SMP emulator required (start with erl -smp)", []),
+ wxe_util:opt_error_log(SilentStart,
+ "WX ERROR: SMP emulator required"
+ " (start with erl -smp)",
+ []),
erlang:error(not_smp)
end,
@@ -114,7 +117,9 @@ init([]) ->
case erl_ddll:load_driver(PrivDir,DriverName) of
ok -> ok;
{error, What} ->
- error_logger:format("WX Failed loading ~p@~p ~n", [DriverName,PrivDir]),
+ wxe_util:opt_error_log(SilentStart,
+ "WX Failed loading ~p@~p ~n",
+ [DriverName,PrivDir]),
Str = erl_ddll:format_error(What),
erlang:error({load_driver,Str})
end,
@@ -210,4 +215,3 @@ debug_ping(Port) ->
_R = (catch erlang:port_call(Port, 0, [])),
%% io:format("Erlang ping ~p ~n", [_R]),
debug_ping(Port).
-
diff --git a/lib/wx/src/wxe_server.erl b/lib/wx/src/wxe_server.erl
index 6e982c97f6..689fe16a70 100644
--- a/lib/wx/src/wxe_server.erl
+++ b/lib/wx/src/wxe_server.erl
@@ -29,7 +29,7 @@
-behaviour(gen_server).
%% API
--export([start/0, stop/0, register_me/1, set_debug/2, invoke_callback/1]).
+-export([start/1, stop/0, register_me/1, set_debug/2, invoke_callback/1]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
@@ -49,13 +49,13 @@
%% API
%%====================================================================
%%--------------------------------------------------------------------
-%% Function: start() -> #wx_env{}
+%% Function: start(SilentStart) -> #wx_env{}
%% Description: Starts the server
%%--------------------------------------------------------------------
-start() ->
+start(SilentStart) ->
case get(?WXE_IDENTIFIER) of
undefined ->
- case gen_server:start(?MODULE, [], []) of
+ case gen_server:start(?MODULE, [SilentStart], []) of
{ok, Pid} ->
{ok, Port} = gen_server:call(Pid, get_port, infinity),
wx:set_env(Env = #wx_env{port=Port,sv=Pid}),
@@ -69,7 +69,7 @@ start() ->
Env;
false -> %% Ok we got an old wx env, someone forgot
erase(?WXE_IDENTIFIER), %% to call wx:destroy()
- start()
+ start(SilentStart)
end
end.
@@ -88,8 +88,8 @@ set_debug(Pid, Level) ->
%% gen_server callbacks
%%====================================================================
-init([]) ->
- {Port,CBPort} = wxe_master:init_port(),
+init([SilentStart]) ->
+ {Port,CBPort} = wxe_master:init_port(SilentStart),
put(?WXE_IDENTIFIER, #wx_env{port=Port,sv=self()}),
{ok,#state{port=Port, cb_port=CBPort,
users=gb_trees:empty(), cb=gb_trees:empty(), cb_cnt=1}}.
diff --git a/lib/wx/src/wxe_util.erl b/lib/wx/src/wxe_util.erl
index 02bca62486..a31c3e30b8 100644
--- a/lib/wx/src/wxe_util.erl
+++ b/lib/wx/src/wxe_util.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -32,7 +32,7 @@
get_const/1,colour_bin/1,datetime_bin/1,
to_bool/1,from_bool/1]).
--export([wxgl_dl/0, priv_dir/1]).
+-export([wxgl_dl/0, priv_dir/2, opt_error_log/3]).
-include("wxe.hrl").
@@ -205,7 +205,7 @@ check_previous() ->
wxgl_dl() ->
DynLib0 = "erl_gl",
- PrivDir = priv_dir(DynLib0),
+ PrivDir = priv_dir(DynLib0, false),
DynLib = case os:type() of
{win32,_} ->
DynLib0 ++ ".dll";
@@ -214,7 +214,7 @@ wxgl_dl() ->
end,
filename:join(PrivDir, DynLib).
-priv_dir(Driver0) ->
+priv_dir(Driver0, Silent) ->
{file, Path} = code:is_loaded(?MODULE),
Priv = case filelib:is_regular(Path) of
true ->
@@ -229,14 +229,20 @@ priv_dir(Driver0) ->
_ ->
Driver0 ++ ".so"
end,
-
case file:read_file_info(filename:join(Priv, Driver)) of
{ok, _} ->
Priv;
{error, _} ->
- error_logger:format("ERROR: Could not find \'~s\' in: ~s~n",
- [Driver, Priv]),
- erlang:error({load_driver, "No driver found"})
+ SrcPriv = filename:join(Priv, erlang:system_info(system_architecture)),
+ case file:read_file_info(filename:join(SrcPriv, Driver)) of
+ {ok, _} ->
+ SrcPriv;
+ {error, _} ->
+ opt_error_log(Silent,
+ "ERROR: Could not find \'~s\' in: ~s~n",
+ [Driver, Priv]),
+ erlang:error({load_driver, "No driver found"})
+ end
end.
strip(Src, Src) ->
@@ -244,3 +250,7 @@ strip(Src, Src) ->
strip([H|R], Src) ->
[H| strip(R, Src)].
+opt_error_log(false, Format, Args) ->
+ error_logger:format(Format, Args);
+opt_error_log(true, _Format, _Args) ->
+ ok.
diff --git a/lib/wx/test/wx_basic_SUITE.erl b/lib/wx/test/wx_basic_SUITE.erl
index 46c72bb453..cf17818a9d 100644
--- a/lib/wx/test/wx_basic_SUITE.erl
+++ b/lib/wx/test/wx_basic_SUITE.erl
@@ -1,7 +1,8 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -47,7 +48,7 @@ end_per_testcase(Func,Config) ->
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [create_window, several_apps, wx_api, wx_misc,
+ [silent_start, create_window, several_apps, wx_api, wx_misc,
data_types, wx_object].
groups() ->
@@ -62,6 +63,25 @@ end_per_group(_GroupName, Config) ->
%% The test cases
+%% test silent start of wx
+silent_start(TestInfo) when is_atom(TestInfo) -> wx_test_lib:tc_info(TestInfo);
+silent_start(_Config) ->
+ ?mr(wx_ref, wx:new([])),
+ wx:destroy(),
+
+ ?mr(wx_ref, wx:new([{silent_start, true}])),
+ wx:destroy(),
+
+ ?mr(wx_ref, wx:new([{silent_start, true}, {debug, verbose}])),
+ wx:destroy(),
+
+ ?mr(wx_ref, wx:new([{silent_start, false}])),
+ wx:destroy(),
+
+ ?mr('EXIT', catch wx:new([{silent_start, foo}])),
+
+ ok.
+
%% create and test creating a window
create_window(TestInfo) when is_atom(TestInfo) -> wx_test_lib:tc_info(TestInfo);
create_window(Config) ->
@@ -109,7 +129,7 @@ wx_api(Config) ->
?m(true, wx:is_null(Wx)),
Null = ?mr(wx_ref, wx:null()),
?m(true, wx:is_null(Null)),
- Frame = ?mt(wxFrame, wxFrame:new(Wx, 1, "WX API: " ++ unicode:characters_to_list("������"))),
+ Frame = ?mt(wxFrame, wxFrame:new(Wx, 1, "WX API: " ++ unicode:characters_to_list("åäöÅÄÖ"))),
?m(false, wx:is_null(Frame)),
?m(wxFrame, wx:getObjectType(Frame)),
Env = ?mr(wx_env, wx:get_env()),
@@ -288,12 +308,12 @@ data_types(_Config) ->
?m({_,_}, wxWindow:getSize(Frame)),
%% DateTime
- DateTime = calendar:now_to_datetime(erlang:now()),
+ DateTime = {Date, _Time} = calendar:now_to_datetime(erlang:now()),
io:format("DateTime ~p ~n",[DateTime]),
Cal = ?mt(wxCalendarCtrl, wxCalendarCtrl:new(Frame, ?wxID_ANY, [{date,DateTime}])),
- ?m(DateTime, wxCalendarCtrl:getDate(Cal)),
+ ?m({Date,_}, wxCalendarCtrl:getDate(Cal)),
?m(true, is_boolean(wxCalendarCtrl:setDate(Cal,DateTime))),
- ?m(DateTime, wxCalendarCtrl:getDate(Cal)),
+ ?m({Date,_}, wxCalendarCtrl:getDate(Cal)),
wxClientDC:destroy(CDC),
%%wx_test_lib:wx_destroy(Frame,Config).
diff --git a/lib/wx/test/wx_class_SUITE.erl b/lib/wx/test/wx_class_SUITE.erl
index 6ed7243c5b..22bfa53e0a 100644
--- a/lib/wx/test/wx_class_SUITE.erl
+++ b/lib/wx/test/wx_class_SUITE.erl
@@ -82,13 +82,14 @@ calendarCtrl(Config) ->
true ->
?log("DateAttr is null~n",[]);
false ->
- ?log("DateAttr is useable~n",[])
+ ?log("DateAttr is useable~n",[]),
+ DateAttr = ?mt(wxCalendarDateAttr, wxCalendarDateAttr:new()),
+ wxCalendarDateAttr:setBackgroundColour(DateAttr, {0,243,0}),
+ wxCalendarCtrl:setAttr(Cal, Day, DateAttr),
+ DateAttr1 = ?mt(wxCalendarDateAttr, wxCalendarCtrl:getAttr(Cal,Day)),
+ io:format("DateAttr ~p~n",[DateAttr1]),
+ ?m({0,243,0,255}, wxCalendarDateAttr:getBackgroundColour(DateAttr1))
end,
- DateAttr = ?mt(wxCalendarDateAttr, wxCalendarDateAttr:new()),
- wxCalendarDateAttr:setBackgroundColour(DateAttr, {0,243,0}),
- wxCalendarCtrl:setAttr(Cal, Day, DateAttr),
- DateAttr1 = ?mt(wxCalendarDateAttr, wxCalendarCtrl:getAttr(Cal,Day)),
- ?m({0,243,0,255}, wxCalendarDateAttr:getBackgroundColour(DateAttr1)),
?m({YMD, _},wxCalendarCtrl:getDate(Cal)),
@@ -476,7 +477,9 @@ taskBarIcon(Config) ->
Wx = wx:new(),
Frame = wxFrame:new(Wx, ?wxID_ANY, "Frame"),
TBI = wxTaskBarIcon:new(),
- Icon = wxIcon:new(filename:join(code:priv_dir(debugger), "erlang_bug.png")),
+ Image = wxImage:new(filename:join(code:priv_dir(debugger), "erlang_bug.png")),
+ io:format("Image ~p~n",[wxImage:ok(Image)]),
+ Icon = wxIcon:new(filename:join(code:priv_dir(debugger), "erlang_bug.png"), [{type, ?wxBITMAP_TYPE_PNG}]),
wxTaskBarIcon:setIcon(TBI, Icon, [{tooltip, "Testing wxTaskBarIcon"}]),
wxWindow:show(Frame),
wxTaskBarIcon:connect(TBI, taskbar_left_down, [{callback, fun(Ev,_) -> io:format("Left clicked: ~p~n",[Ev]) end}]),
diff --git a/lib/wx/test/wx_event_SUITE.erl b/lib/wx/test/wx_event_SUITE.erl
index 8f364049b4..53a2ee7d7b 100644
--- a/lib/wx/test/wx_event_SUITE.erl
+++ b/lib/wx/test/wx_event_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -301,35 +301,70 @@ connect_in_callback(TestInfo)
when is_atom(TestInfo) -> wx_test_lib:tc_info(TestInfo);
connect_in_callback(Config) ->
Wx = ?mr(wx_ref, wx:new()),
+ %% wx:debug([driver,trace]),
+ %% io:format("gdb -p ~s~n",[os:getpid()]),
Frame = wxFrame:new(Wx, ?wxID_ANY, "Connect in callback"),
Panel = wxPanel:new(Frame, []),
-
+
+ Tester = self(),
+
+ %% Connect in callbacks works different in 2.9
+ %% such that new events are not fired until the previous
+ %% callback have returned.
+
+ %% That means that a callback can not wait for other events
+ %% in receive since they will not come.
+ %% It also means that you can not attach a new callback directly from
+ %% the callback since that callback will be removed when the temporary
+ %% process that executes the outer callback (may) die(s) before the callback
+ %% is invoked
+
+ %% Thus connect in callbacks needs to done in a another process, and
+ %% not in the fun directly
+ Env = wx:get_env(),
+ TestWindow =
+ fun() ->
+ wx:set_env(Env),
+ Me = self(),
+ F1 = wxFrame:new(Frame, ?wxID_ANY, "Frame size event"),
+ wxFrame:connect(F1,size,[{callback,
+ fun(_,_) ->
+ io:format("CB2 got size~n",[]),
+ Me ! {continue, F1}
+ end}]),
+ wxWindow:show(F1),
+ receive
+ {continue, F1} -> Tester ! {continue, F1}
+ end
+ end,
wxFrame:connect(Frame,size,
- [{callback,
- fun(#wx{event=#wxSize{}},_SizeEv) ->
- io:format("Frame got size~n",[]),
- F1 = wxFrame:new(Frame, ?wxID_ANY, "Frame size event"),
- CBPid = self(),
- wxFrame:connect(F1,size,[{callback,
- fun(_,_) ->
- io:format("CB2 got size~n",[]),
- CBPid ! continue
- end}]),
- wxWindow:show(F1),
- receive continue -> wxFrame:destroy(F1) end
+ [{callback,
+ fun(#wx{event=#wxSize{}},_SizeEv) ->
+ io:format("Frame got size~n",[]),
+ spawn(TestWindow)
end}]),
wxPanel:connect(Panel,size,
- [{callback,
- fun(#wx{event=#wxSize{}},_SizeEv) ->
+ [{callback,
+ fun(#wx{event=#wxSize{}},_SizeEv) ->
io:format("Panel got size~n",[]),
- F1 = wxFrame:new(Frame, ?wxID_ANY, "Panel size event"),
- wxFrame:connect(F1,size),
- wxWindow:show(F1),
- receive #wx{event=#wxSize{}} -> wxFrame:destroy(F1) end
- end}]),
+ spawn(fun() ->
+ wx:set_env(Env),
+ F1 = wxFrame:new(Frame, ?wxID_ANY,
+ "Panel size event"),
+ wxFrame:connect(F1,size),
+ wxWindow:show(F1),
+ receive
+ #wx{event=#wxSize{}} ->
+ io:format("All Fine ~n",[]),
+ wxFrame:destroy(F1)
+ end
+ end)
+ end}]),
wxFrame:show(Frame),
+
+ ok = receive {continue, F1} -> wxFrame:destroy(F1)
+ after 5000 -> timeout end,
wx_test_lib:flush(),
-
wx_test_lib:wx_destroy(Frame, Config).
%% Test that event callback which triggers another callback works
diff --git a/lib/wx/test/wx_opengl_SUITE.erl b/lib/wx/test/wx_opengl_SUITE.erl
index e8fdf603d6..f351bc93ed 100644
--- a/lib/wx/test/wx_opengl_SUITE.erl
+++ b/lib/wx/test/wx_opengl_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -92,10 +92,22 @@ canvas(TestInfo) when is_atom(TestInfo) -> wx_test_lib:tc_info(TestInfo);
canvas(Config) ->
WX = ?mr(wx_ref, wx:new()),
Frame = wxFrame:new(WX,1,"Hello 3D-World",[]),
- Attrs = [{attribList, [?WX_GL_RGBA,?WX_GL_DOUBLEBUFFER,0]}],
- Canvas = ?mt(wxGLCanvas, wxGLCanvas:new(Frame, Attrs)),
+ Attrs = [{attribList, [?WX_GL_RGBA,
+ ?WX_GL_DOUBLEBUFFER,
+ ?WX_GL_MIN_RED,8,
+ ?WX_GL_MIN_GREEN,8,
+ ?WX_GL_MIN_BLUE,8,
+ ?WX_GL_DEPTH_SIZE,24,0]}],
+ Canvas = ?mt(wxGLCanvas, wxGLCanvas:new(Frame, [{style,?wxFULL_REPAINT_ON_RESIZE}|
+ Attrs])),
+ wxFrame:connect(Frame, show),
?m(true, wxWindow:show(Frame)),
+
+ receive #wx{event=#wxShow{}} -> ok
+ after 1000 -> exit(show_timeout)
+ end,
+
?m(false, wx:is_null(wxGLCanvas:getContext(Canvas))),
?m({'EXIT', {{error, no_gl_context,_},_}}, gl:getString(?GL_VENDOR)),
@@ -111,7 +123,7 @@ canvas(Config) ->
%%gl:frustum( -2.0, 2.0, -2.0, 2.0, 5.0, 25.0 ),
gl:ortho( -2.0, 2.0, -2.0*H/W, 2.0*H/W, -20.0, 20.0),
gl:matrixMode(?GL_MODELVIEW),
- gl:loadIdentity(),
+ gl:loadIdentity(),
gl:enable(?GL_DEPTH_TEST),
gl:depthFunc(?GL_LESS),
{R,G,B,_} = wxWindow:getBackgroundColour(Frame),
@@ -122,7 +134,7 @@ canvas(Config) ->
?m([], flush()),
Env = wx:get_env(),
Tester = self(),
- spawn_link(fun() ->
+ spawn_link(fun() ->
wx:set_env(Env),
?m(ok, wxGLCanvas:setCurrent(Canvas)),
?m(ok, drawBox(1, Data)),
@@ -131,11 +143,20 @@ canvas(Config) ->
%% This may fail when window is deleted
catch draw_loop(2,Data,Canvas)
end),
+ %% Needed on mac with wx-2.9
+ wxGLCanvas:connect(Canvas, paint,
+ [{callback, fun(_,_) ->
+ wxGLCanvas:setCurrent(Canvas),
+ DC= wxPaintDC:new(Canvas),
+ wxPaintDC:destroy(DC)
+ end}]),
+
+
?m_receive(works),
?m([], flush()),
io:format("Undef func ~p ~n", [catch gl:uniform1d(2, 0.75)]),
timer:sleep(500),
- ?m([], flush()),
+ flush(),
wx_test_lib:wx_destroy(Frame, Config).
flush() ->
@@ -150,6 +171,8 @@ flush(Collected) ->
draw_loop(Deg,Data,Canvas) ->
timer:sleep(15),
+ {NW,NH} = wxGLCanvas:getClientSize(Canvas),
+ gl:viewport(0,0,NW,NH),
drawBox(Deg,Data),
?m(ok, wxGLCanvas:swapBuffers(Canvas)),
draw_loop(Deg+1, Data,Canvas).
@@ -181,7 +204,12 @@ glu_tesselation(Config) ->
Frame = wxFrame:new(WX,1,"Hello 3D-World",[]),
Attrs = [{attribList, [?WX_GL_RGBA,?WX_GL_DOUBLEBUFFER,0]}],
Canvas = ?mt(wxGLCanvas, wxGLCanvas:new(Frame, Attrs)),
+ wxFrame:connect(Frame, show),
?m(true, wxWindow:show(Frame)),
+
+ receive #wx{event=#wxShow{}} -> ok
+ after 1000 -> exit(show_timeout)
+ end,
?m(ok, wxGLCanvas:setCurrent(Canvas)),
{RL1,RB1} = ?m({_,_}, glu:tesselate({0,0,1}, [{-1,0,0},{1,0,0},{0,1,0}])),
diff --git a/lib/wx/test/wx_xtra_SUITE.erl b/lib/wx/test/wx_xtra_SUITE.erl
index 02a0672594..a2d4c26319 100644
--- a/lib/wx/test/wx_xtra_SUITE.erl
+++ b/lib/wx/test/wx_xtra_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -111,6 +111,7 @@ app_dies(_Config) ->
oops(Die,?LINE),
wxFrame:show(Frame),
oops(Die,?LINE),
+ timer:sleep(100), %% Let the window be shown before DC can be created
DC0 = wxClientDC:new(Win),
oops(Die,?LINE),
DC = wxBufferedDC:new(DC0),
@@ -134,7 +135,7 @@ app_dies2(Test, N) ->
end.
oops(Die, Line) when (Die =:= last) orelse (Die =< Line) ->
- timer:sleep(500),
+ timer:sleep(300),
?log(" Exits at line ~p~n",[Line]),
exit({oops, Die});
oops(_,_) -> ok.
@@ -191,8 +192,12 @@ menu_item_debug(Config) ->
wxFrame:connect(Frame, close_window),
wxPanel:new(Frame),
- create_menus(Frame),
+ MenuBar = create_menus(Frame),
wxWindow:show(Frame),
+ N = wxMenuBar:getMenuCount(MenuBar),
+ io:format("No of menus ~p~n",[N]),
+ [io:format("Menu ~p ~p~n",[Id, wxMenuBar:getLabelTop(MenuBar, Id)])
+ || Id <- lists:seq(0, N-1)],
wx_test_lib:wx_destroy(Frame,Config).
@@ -224,14 +229,15 @@ create_menus(Frame) ->
|| Id <- lists:seq(600, 620)],
?m(ok,wxFrame:connect(Frame, command_menu_selected)),
- ?m(true, wxMenuBar:append(MenuBar, File, "&File")),
- ?m(true, wxMenuBar:append(MenuBar, Help, "&Help")),
- ?m(true, wxMenuBar:append(MenuBar, T1, "T1")),
- ?m(true, wxMenuBar:append(MenuBar, T2, "T2")),
- ?m(true, wxMenuBar:append(MenuBar, T3, "T3")),
- ?m(true, wxMenuBar:append(MenuBar, T4, "T4")),
- ?m(true, wxMenuBar:append(MenuBar, T5, "T5")),
- ?m(true, wxMenuBar:append(MenuBar, T6, "T6")),
-
- ?m(ok, wxFrame:setMenuBar(Frame,MenuBar)).
+ ?m(true, wxMenuBar:insert(MenuBar, 0,File, "&File")),
+ ?m(true, wxMenuBar:insert(MenuBar, 1,Help, "&Help")),
+ ?m(true, wxMenuBar:insert(MenuBar, 2,T1, "T1")),
+ ?m(true, wxMenuBar:insert(MenuBar, 3,T2, "T2")),
+ ?m(true, wxMenuBar:insert(MenuBar, 4,T3, "T3")),
+ ?m(true, wxMenuBar:insert(MenuBar, 5,T4, "T4")),
+ ?m(true, wxMenuBar:insert(MenuBar, 6,T5, "T5")),
+ ?m(true, wxMenuBar:insert(MenuBar, 7,T6, "T6")),
+
+ ?m(ok, wxFrame:setMenuBar(Frame,MenuBar)),
+ MenuBar.
diff --git a/lib/wx/wxwin.m4 b/lib/wx/wxwin-2.8.m4
index 52c55e2e6e..52c55e2e6e 100644
--- a/lib/wx/wxwin.m4
+++ b/lib/wx/wxwin-2.8.m4
diff --git a/lib/wx/wxwin-2.9.m4 b/lib/wx/wxwin-2.9.m4
new file mode 100644
index 0000000000..1c50dcc272
--- /dev/null
+++ b/lib/wx/wxwin-2.9.m4
@@ -0,0 +1,1060 @@
+dnl ---------------------------------------------------------------------------
+dnl Author: wxWidgets development team,
+dnl Francesco Montorsi,
+dnl Bob McCown (Mac-testing)
+dnl Creation date: 24/11/2001
+dnl RCS-ID: $Id$
+dnl ---------------------------------------------------------------------------
+
+dnl ===========================================================================
+dnl Table of Contents of this macro file:
+dnl -------------------------------------
+dnl
+dnl SECTION A: wxWidgets main macros
+dnl - WX_CONFIG_OPTIONS
+dnl - WX_CONFIG_CHECK
+dnl - WXRC_CHECK
+dnl - WX_STANDARD_OPTIONS
+dnl - WX_CONVERT_STANDARD_OPTIONS_TO_WXCONFIG_FLAGS
+dnl - WX_DETECT_STANDARD_OPTION_VALUES
+dnl
+dnl SECTION B: wxWidgets-related utilities
+dnl - WX_LIKE_LIBNAME
+dnl - WX_ARG_ENABLE_YESNOAUTO
+dnl - WX_ARG_WITH_YESNOAUTO
+dnl
+dnl SECTION C: messages to the user
+dnl - WX_STANDARD_OPTIONS_SUMMARY_MSG
+dnl - WX_STANDARD_OPTIONS_SUMMARY_MSG_BEGIN
+dnl - WX_STANDARD_OPTIONS_SUMMARY_MSG_END
+dnl - WX_BOOLOPT_SUMMARY
+dnl
+dnl The special "WX_DEBUG_CONFIGURE" variable can be set to 1 to enable extra
+dnl debug output on stdout from these macros.
+dnl ===========================================================================
+
+
+dnl ---------------------------------------------------------------------------
+dnl Macros for wxWidgets detection. Typically used in configure.in as:
+dnl
+dnl AC_ARG_ENABLE(...)
+dnl AC_ARG_WITH(...)
+dnl ...
+dnl WX_CONFIG_OPTIONS
+dnl ...
+dnl ...
+dnl WX_CONFIG_CHECK([2.6.0], [wxWin=1])
+dnl if test "$wxWin" != 1; then
+dnl AC_MSG_ERROR([
+dnl wxWidgets must be installed on your system
+dnl but wx-config script couldn't be found.
+dnl
+dnl Please check that wx-config is in path, the directory
+dnl where wxWidgets libraries are installed (returned by
+dnl 'wx-config --libs' command) is in LD_LIBRARY_PATH or
+dnl equivalent variable and wxWidgets version is 2.3.4 or above.
+dnl ])
+dnl fi
+dnl CPPFLAGS="$CPPFLAGS $WX_CPPFLAGS"
+dnl CXXFLAGS="$CXXFLAGS $WX_CXXFLAGS_ONLY"
+dnl CFLAGS="$CFLAGS $WX_CFLAGS_ONLY"
+dnl
+dnl LIBS="$LIBS $WX_LIBS"
+dnl
+dnl If you want to support standard --enable-debug/unicode/shared options, you
+dnl may do the following:
+dnl
+dnl ...
+dnl AC_CANONICAL_SYSTEM
+dnl
+dnl # define configure options
+dnl WX_CONFIG_OPTIONS
+dnl WX_STANDARD_OPTIONS([debug,unicode,shared,toolkit,wxshared])
+dnl
+dnl # basic configure checks
+dnl ...
+dnl
+dnl # we want to always have DEBUG==WX_DEBUG and UNICODE==WX_UNICODE
+dnl WX_DEBUG=$DEBUG
+dnl WX_UNICODE=$UNICODE
+dnl
+dnl WX_CONVERT_STANDARD_OPTIONS_TO_WXCONFIG_FLAGS
+dnl WX_CONFIG_CHECK([2.8.0], [wxWin=1],,[html,core,net,base],[$WXCONFIG_FLAGS])
+dnl WX_DETECT_STANDARD_OPTION_VALUES
+dnl
+dnl # write the output files
+dnl AC_CONFIG_FILES([Makefile ...])
+dnl AC_OUTPUT
+dnl
+dnl # optional: just to show a message to the user
+dnl WX_STANDARD_OPTIONS_SUMMARY_MSG
+dnl
+dnl ---------------------------------------------------------------------------
+
+
+dnl ---------------------------------------------------------------------------
+dnl WX_CONFIG_OPTIONS
+dnl
+dnl adds support for --wx-prefix, --wx-exec-prefix, --with-wxdir and
+dnl --wx-config command line options
+dnl ---------------------------------------------------------------------------
+
+AC_DEFUN([WX_CONFIG_OPTIONS],
+[
+ AC_ARG_WITH(wxdir,
+ [ --with-wxdir=PATH Use uninstalled version of wxWidgets in PATH],
+ [ wx_config_name="$withval/wx-config"
+ wx_config_args="--inplace"])
+ AC_ARG_WITH(wx-config,
+ [ --with-wx-config=CONFIG wx-config script to use (optional)],
+ wx_config_name="$withval" )
+ AC_ARG_WITH(wx-prefix,
+ [ --with-wx-prefix=PREFIX Prefix where wxWidgets is installed (optional)],
+ wx_config_prefix="$withval", wx_config_prefix="")
+ AC_ARG_WITH(wx-exec-prefix,
+ [ --with-wx-exec-prefix=PREFIX
+ Exec prefix where wxWidgets is installed (optional)],
+ wx_config_exec_prefix="$withval", wx_config_exec_prefix="")
+])
+
+dnl Helper macro for checking if wx version is at least $1.$2.$3, set's
+dnl wx_ver_ok=yes if it is:
+AC_DEFUN([_WX_PRIVATE_CHECK_VERSION],
+[
+ wx_ver_ok=""
+ if test "x$WX_VERSION" != x ; then
+ if test $wx_config_major_version -gt $1; then
+ wx_ver_ok=yes
+ else
+ if test $wx_config_major_version -eq $1; then
+ if test $wx_config_minor_version -gt $2; then
+ wx_ver_ok=yes
+ else
+ if test $wx_config_minor_version -eq $2; then
+ if test $wx_config_micro_version -ge $3; then
+ wx_ver_ok=yes
+ fi
+ fi
+ fi
+ fi
+ fi
+ fi
+])
+
+dnl ---------------------------------------------------------------------------
+dnl WX_CONFIG_CHECK(VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND
+dnl [, WX-LIBS [, ADDITIONAL-WX-CONFIG-FLAGS]]]])
+dnl
+dnl Test for wxWidgets, and define WX_C*FLAGS, WX_LIBS and WX_LIBS_STATIC
+dnl (the latter is for static linking against wxWidgets). Set WX_CONFIG_NAME
+dnl environment variable to override the default name of the wx-config script
+dnl to use. Set WX_CONFIG_PATH to specify the full path to wx-config - in this
+dnl case the macro won't even waste time on tests for its existence.
+dnl
+dnl Optional WX-LIBS argument contains comma- or space-separated list of
+dnl wxWidgets libraries to link against. If it is not specified then WX_LIBS
+dnl and WX_LIBS_STATIC will contain flags to link with all of the core
+dnl wxWidgets libraries.
+dnl
+dnl Optional ADDITIONAL-WX-CONFIG-FLAGS argument is appended to wx-config
+dnl invocation command in present. It can be used to fine-tune lookup of
+dnl best wxWidgets build available.
+dnl
+dnl Example use:
+dnl WX_CONFIG_CHECK([2.6.0], [wxWin=1], [wxWin=0], [html,core,net]
+dnl [--unicode --debug])
+dnl ---------------------------------------------------------------------------
+
+dnl
+dnl Get the cflags and libraries from the wx-config script
+dnl
+AC_DEFUN([WX_CONFIG_CHECK],
+[
+ dnl do we have wx-config name: it can be wx-config or wxd-config or ...
+ if test x${WX_CONFIG_NAME+set} != xset ; then
+ WX_CONFIG_NAME=wx-config
+ fi
+
+ if test "x$wx_config_name" != x ; then
+ WX_CONFIG_NAME="$wx_config_name"
+ fi
+
+ dnl deal with optional prefixes
+ if test x$wx_config_exec_prefix != x ; then
+ wx_config_args="$wx_config_args --exec-prefix=$wx_config_exec_prefix"
+ WX_LOOKUP_PATH="$wx_config_exec_prefix/bin"
+ fi
+ if test x$wx_config_prefix != x ; then
+ wx_config_args="$wx_config_args --prefix=$wx_config_prefix"
+ WX_LOOKUP_PATH="$WX_LOOKUP_PATH:$wx_config_prefix/bin"
+ fi
+ if test "$cross_compiling" = "yes"; then
+ wx_config_args="$wx_config_args --host=$host_alias"
+ fi
+
+ dnl don't search the PATH if WX_CONFIG_NAME is absolute filename
+ if test -x "$WX_CONFIG_NAME" ; then
+ AC_MSG_CHECKING(for wx-config)
+ WX_CONFIG_PATH="$WX_CONFIG_NAME"
+ AC_MSG_RESULT($WX_CONFIG_PATH)
+ else
+ AC_PATH_PROG(WX_CONFIG_PATH, $WX_CONFIG_NAME, no, "$WX_LOOKUP_PATH:$PATH")
+ fi
+
+ if test "$WX_CONFIG_PATH" != "no" ; then
+ WX_VERSION=""
+
+ min_wx_version=ifelse([$1], ,2.2.1,$1)
+ if test -z "$5" ; then
+ AC_MSG_CHECKING([for wxWidgets version >= $min_wx_version])
+ else
+ AC_MSG_CHECKING([for wxWidgets version >= $min_wx_version ($5)])
+ fi
+
+ dnl don't add the libraries ($4) to this variable as this would result in
+ dnl an error when it's used with --version below
+ WX_CONFIG_WITH_ARGS="$WX_CONFIG_PATH $wx_config_args $5"
+
+ WX_VERSION=`$WX_CONFIG_WITH_ARGS --version 2>/dev/null`
+ wx_config_major_version=`echo $WX_VERSION | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+ wx_config_minor_version=`echo $WX_VERSION | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+ wx_config_micro_version=`echo $WX_VERSION | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+
+ wx_requested_major_version=`echo $min_wx_version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+ wx_requested_minor_version=`echo $min_wx_version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+ wx_requested_micro_version=`echo $min_wx_version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+
+ _WX_PRIVATE_CHECK_VERSION([$wx_requested_major_version],
+ [$wx_requested_minor_version],
+ [$wx_requested_micro_version])
+
+ if test -n "$wx_ver_ok"; then
+ AC_MSG_RESULT(yes (version $WX_VERSION))
+ WX_LIBS=`$WX_CONFIG_WITH_ARGS --libs $4`
+
+ dnl is this even still appropriate? --static is a real option now
+ dnl and WX_CONFIG_WITH_ARGS is likely to contain it if that is
+ dnl what the user actually wants, making this redundant at best.
+ dnl For now keep it in case anyone actually used it in the past.
+ AC_MSG_CHECKING([for wxWidgets static library])
+ WX_LIBS_STATIC=`$WX_CONFIG_WITH_ARGS --static --libs $4 2>/dev/null`
+ if test "x$WX_LIBS_STATIC" = "x"; then
+ AC_MSG_RESULT(no)
+ else
+ AC_MSG_RESULT(yes)
+ fi
+
+ dnl starting with version 2.2.6 wx-config has --cppflags argument
+ wx_has_cppflags=""
+ if test $wx_config_major_version -gt 2; then
+ wx_has_cppflags=yes
+ else
+ if test $wx_config_major_version -eq 2; then
+ if test $wx_config_minor_version -gt 2; then
+ wx_has_cppflags=yes
+ else
+ if test $wx_config_minor_version -eq 2; then
+ if test $wx_config_micro_version -ge 6; then
+ wx_has_cppflags=yes
+ fi
+ fi
+ fi
+ fi
+ fi
+
+ dnl starting with version 2.7.0 wx-config has --rescomp option
+ wx_has_rescomp=""
+ if test $wx_config_major_version -gt 2; then
+ wx_has_rescomp=yes
+ else
+ if test $wx_config_major_version -eq 2; then
+ if test $wx_config_minor_version -ge 7; then
+ wx_has_rescomp=yes
+ fi
+ fi
+ fi
+ if test "x$wx_has_rescomp" = x ; then
+ dnl cannot give any useful info for resource compiler
+ WX_RESCOMP=
+ else
+ WX_RESCOMP=`$WX_CONFIG_WITH_ARGS --rescomp`
+ fi
+
+ if test "x$wx_has_cppflags" = x ; then
+ dnl no choice but to define all flags like CFLAGS
+ WX_CFLAGS=`$WX_CONFIG_WITH_ARGS --cflags $4`
+ WX_CPPFLAGS=$WX_CFLAGS
+ WX_CXXFLAGS=$WX_CFLAGS
+
+ WX_CFLAGS_ONLY=$WX_CFLAGS
+ WX_CXXFLAGS_ONLY=$WX_CFLAGS
+ else
+ dnl we have CPPFLAGS included in CFLAGS included in CXXFLAGS
+ WX_CPPFLAGS=`$WX_CONFIG_WITH_ARGS --cppflags $4`
+ WX_CXXFLAGS=`$WX_CONFIG_WITH_ARGS --cxxflags $4`
+ WX_CFLAGS=`$WX_CONFIG_WITH_ARGS --cflags $4`
+
+ WX_CFLAGS_ONLY=`echo $WX_CFLAGS | sed "s@^$WX_CPPFLAGS *@@"`
+ WX_CXXFLAGS_ONLY=`echo $WX_CXXFLAGS | sed "s@^$WX_CFLAGS *@@"`
+ fi
+
+ ifelse([$2], , :, [$2])
+
+ else
+
+ if test "x$WX_VERSION" = x; then
+ dnl no wx-config at all
+ AC_MSG_RESULT(no)
+ else
+ AC_MSG_RESULT(no (version $WX_VERSION is not new enough))
+ fi
+
+ WX_CFLAGS=""
+ WX_CPPFLAGS=""
+ WX_CXXFLAGS=""
+ WX_LIBS=""
+ WX_LIBS_STATIC=""
+ WX_RESCOMP=""
+
+ if test ! -z "$5"; then
+
+ wx_error_message="
+ The configuration you asked for $PACKAGE_NAME requires a wxWidgets
+ build with the following settings:
+ $5
+ but such build is not available.
+
+ To see the wxWidgets builds available on this system, please use
+ 'wx-config --list' command. To use the default build, returned by
+ 'wx-config --selected-config', use the options with their 'auto'
+ default values."
+
+ fi
+
+ wx_error_message="
+ The requested wxWidgets build couldn't be found.
+ $wx_error_message
+
+ If you still get this error, then check that 'wx-config' is
+ in path, the directory where wxWidgets libraries are installed
+ (returned by 'wx-config --libs' command) is in LD_LIBRARY_PATH
+ or equivalent variable and wxWidgets version is $1 or above."
+
+ ifelse([$3], , AC_MSG_ERROR([$wx_error_message]), [$3])
+
+ fi
+ else
+
+ WX_CFLAGS=""
+ WX_CPPFLAGS=""
+ WX_CXXFLAGS=""
+ WX_LIBS=""
+ WX_LIBS_STATIC=""
+ WX_RESCOMP=""
+
+ ifelse([$3], , :, [$3])
+
+ fi
+
+ AC_SUBST(WX_CPPFLAGS)
+ AC_SUBST(WX_CFLAGS)
+ AC_SUBST(WX_CXXFLAGS)
+ AC_SUBST(WX_CFLAGS_ONLY)
+ AC_SUBST(WX_CXXFLAGS_ONLY)
+ AC_SUBST(WX_LIBS)
+ AC_SUBST(WX_LIBS_STATIC)
+ AC_SUBST(WX_VERSION)
+ AC_SUBST(WX_RESCOMP)
+
+ dnl need to export also WX_VERSION_MINOR and WX_VERSION_MAJOR symbols
+ dnl to support wxpresets bakefiles (we export also WX_VERSION_MICRO for completeness):
+ WX_VERSION_MAJOR="$wx_config_major_version"
+ WX_VERSION_MINOR="$wx_config_minor_version"
+ WX_VERSION_MICRO="$wx_config_micro_version"
+ AC_SUBST(WX_VERSION_MAJOR)
+ AC_SUBST(WX_VERSION_MINOR)
+ AC_SUBST(WX_VERSION_MICRO)
+])
+
+dnl ---------------------------------------------------------------------------
+dnl Get information on the wxrc program for making C++, Python and xrs
+dnl resource files.
+dnl
+dnl AC_ARG_ENABLE(...)
+dnl AC_ARG_WITH(...)
+dnl ...
+dnl WX_CONFIG_OPTIONS
+dnl ...
+dnl WX_CONFIG_CHECK(2.6.0, wxWin=1)
+dnl if test "$wxWin" != 1; then
+dnl AC_MSG_ERROR([
+dnl wxWidgets must be installed on your system
+dnl but wx-config script couldn't be found.
+dnl
+dnl Please check that wx-config is in path, the directory
+dnl where wxWidgets libraries are installed (returned by
+dnl 'wx-config --libs' command) is in LD_LIBRARY_PATH or
+dnl equivalent variable and wxWidgets version is 2.6.0 or above.
+dnl ])
+dnl fi
+dnl
+dnl WXRC_CHECK([HAVE_WXRC=1], [HAVE_WXRC=0])
+dnl if test "x$HAVE_WXRC" != x1; then
+dnl AC_MSG_ERROR([
+dnl The wxrc program was not installed or not found.
+dnl
+dnl Please check the wxWidgets installation.
+dnl ])
+dnl fi
+dnl
+dnl CPPFLAGS="$CPPFLAGS $WX_CPPFLAGS"
+dnl CXXFLAGS="$CXXFLAGS $WX_CXXFLAGS_ONLY"
+dnl CFLAGS="$CFLAGS $WX_CFLAGS_ONLY"
+dnl
+dnl LDFLAGS="$LDFLAGS $WX_LIBS"
+dnl ---------------------------------------------------------------------------
+
+dnl ---------------------------------------------------------------------------
+dnl WXRC_CHECK([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl
+dnl Test for wxWidgets' wxrc program for creating either C++, Python or XRS
+dnl resources. The variable WXRC will be set and substituted in the configure
+dnl script and Makefiles.
+dnl
+dnl Example use:
+dnl WXRC_CHECK([wxrc=1], [wxrc=0])
+dnl ---------------------------------------------------------------------------
+
+dnl
+dnl wxrc program from the wx-config script
+dnl
+AC_DEFUN([WXRC_CHECK],
+[
+ AC_ARG_VAR([WXRC], [Path to wxWidget's wxrc resource compiler])
+
+ if test "x$WX_CONFIG_NAME" = x; then
+ AC_MSG_ERROR([The wxrc tests must run after wxWidgets test.])
+ else
+
+ AC_MSG_CHECKING([for wxrc])
+
+ if test "x$WXRC" = x ; then
+ dnl wx-config --utility is a new addition to wxWidgets:
+ _WX_PRIVATE_CHECK_VERSION(2,5,3)
+ if test -n "$wx_ver_ok"; then
+ WXRC=`$WX_CONFIG_WITH_ARGS --utility=wxrc`
+ fi
+ fi
+
+ if test "x$WXRC" = x ; then
+ AC_MSG_RESULT([not found])
+ ifelse([$2], , :, [$2])
+ else
+ AC_MSG_RESULT([$WXRC])
+ ifelse([$1], , :, [$1])
+ fi
+
+ AC_SUBST(WXRC)
+ fi
+])
+
+dnl ---------------------------------------------------------------------------
+dnl WX_LIKE_LIBNAME([output-var] [prefix], [name])
+dnl
+dnl Sets the "output-var" variable to the name of a library named with same
+dnl wxWidgets rule.
+dnl E.g. for output-var=='lib', name=='test', prefix='mine', sets
+dnl the $lib variable to:
+dnl 'mine_gtk2ud_test-2.8'
+dnl if WX_PORT=gtk2, WX_UNICODE=1, WX_DEBUG=1 and WX_RELEASE=28
+dnl ---------------------------------------------------------------------------
+AC_DEFUN([WX_LIKE_LIBNAME],
+ [
+ wx_temp="$2""_""$WX_PORT"
+
+ dnl add the [u][d] string
+ if test "$WX_UNICODE" = "1"; then
+ wx_temp="$wx_temp""u"
+ fi
+ if test "$WX_DEBUG" = "1"; then
+ wx_temp="$wx_temp""d"
+ fi
+
+ dnl complete the name of the lib
+ wx_temp="$wx_temp""_""$3""-$WX_VERSION_MAJOR.$WX_VERSION_MINOR"
+
+ dnl save it in the user's variable
+ $1=$wx_temp
+ ])
+
+dnl ---------------------------------------------------------------------------
+dnl WX_ARG_ENABLE_YESNOAUTO/WX_ARG_WITH_YESNOAUTO
+dnl
+dnl Two little custom macros which define the ENABLE/WITH configure arguments.
+dnl Macro arguments:
+dnl $1 = the name of the --enable / --with feature
+dnl $2 = the name of the variable associated
+dnl $3 = the description of that feature
+dnl $4 = the default value for that feature
+dnl $5 = additional action to do in case option is given with "yes" value
+dnl ---------------------------------------------------------------------------
+AC_DEFUN([WX_ARG_ENABLE_YESNOAUTO],
+ [AC_ARG_ENABLE($1,
+ AC_HELP_STRING([--enable-$1], [$3 (default is $4)]),
+ [], [enableval="$4"])
+
+ dnl Show a message to the user about this option
+ AC_MSG_CHECKING([for the --enable-$1 option])
+ if test "$enableval" = "yes" ; then
+ AC_MSG_RESULT([yes])
+ $2=1
+ $5
+ elif test "$enableval" = "no" ; then
+ AC_MSG_RESULT([no])
+ $2=0
+ elif test "$enableval" = "auto" ; then
+ AC_MSG_RESULT([will be automatically detected])
+ $2="auto"
+ else
+ AC_MSG_ERROR([
+ Unrecognized option value (allowed values: yes, no, auto)
+ ])
+ fi
+ ])
+
+AC_DEFUN([WX_ARG_WITH_YESNOAUTO],
+ [AC_ARG_WITH($1,
+ AC_HELP_STRING([--with-$1], [$3 (default is $4)]),
+ [], [withval="$4"])
+
+ dnl Show a message to the user about this option
+ AC_MSG_CHECKING([for the --with-$1 option])
+ if test "$withval" = "yes" ; then
+ AC_MSG_RESULT([yes])
+ $2=1
+ $5
+ dnl NB: by default we don't allow --with-$1=no option
+ dnl since it does not make much sense !
+ elif test "$6" = "1" -a "$withval" = "no" ; then
+ AC_MSG_RESULT([no])
+ $2=0
+ elif test "$withval" = "auto" ; then
+ AC_MSG_RESULT([will be automatically detected])
+ $2="auto"
+ else
+ AC_MSG_ERROR([
+ Unrecognized option value (allowed values: yes, auto)
+ ])
+ fi
+ ])
+
+
+dnl ---------------------------------------------------------------------------
+dnl WX_STANDARD_OPTIONS([options-to-add])
+dnl
+dnl Adds to the configure script one or more of the following options:
+dnl --enable-[debug|unicode|shared|wxshared|wxdebug]
+dnl --with-[gtk|msw|motif|x11|mac|dfb]
+dnl --with-wxversion
+dnl Then checks for their presence and eventually set the DEBUG, UNICODE, SHARED,
+dnl PORT, WX_SHARED, WX_DEBUG, variables to one of the "yes", "no", "auto" values.
+dnl
+dnl Note that e.g. UNICODE != WX_UNICODE; the first is the value of the
+dnl --enable-unicode option (in boolean format) while the second indicates
+dnl if wxWidgets was built in Unicode mode (and still is in boolean format).
+dnl ---------------------------------------------------------------------------
+AC_DEFUN([WX_STANDARD_OPTIONS],
+ [
+
+ dnl the following lines will expand to WX_ARG_ENABLE_YESNOAUTO calls if and only if
+ dnl the $1 argument contains respectively the debug,unicode or shared options.
+
+ dnl be careful here not to set debug flag if only "wxdebug" was specified
+ ifelse(regexp([$1], [\bdebug]), [-1],,
+ [WX_ARG_ENABLE_YESNOAUTO([debug], [DEBUG], [Build in debug mode], [auto])])
+
+ ifelse(index([$1], [unicode]), [-1],,
+ [WX_ARG_ENABLE_YESNOAUTO([unicode], [UNICODE], [Build in Unicode mode], [auto])])
+
+ ifelse(regexp([$1], [\bshared]), [-1],,
+ [WX_ARG_ENABLE_YESNOAUTO([shared], [SHARED], [Build as shared library], [auto])])
+
+ dnl WX_ARG_WITH_YESNOAUTO cannot be used for --with-toolkit since it's an option
+ dnl which must be able to accept the auto|gtk1|gtk2|msw|... values
+ ifelse(index([$1], [toolkit]), [-1],,
+ [
+ AC_ARG_WITH([toolkit],
+ AC_HELP_STRING([--with-toolkit],
+ [Build against a specific wxWidgets toolkit (default is auto)]),
+ [], [withval="auto"])
+
+ dnl Show a message to the user about this option
+ AC_MSG_CHECKING([for the --with-toolkit option])
+ if test "$withval" = "auto" ; then
+ AC_MSG_RESULT([will be automatically detected])
+ TOOLKIT="auto"
+ else
+ TOOLKIT="$withval"
+
+ dnl PORT must be one of the allowed values
+ if test "$TOOLKIT" != "gtk1" -a "$TOOLKIT" != "gtk2" -a \
+ "$TOOLKIT" != "msw" -a "$TOOLKIT" != "motif" -a \
+ "$TOOLKIT" != "osx_carbon" -a "$TOOLKIT" != "osx_cocoa" -a \
+ "$TOOLKIT" != "dfb" -a "$TOOLKIT" != "x11"; then
+ AC_MSG_ERROR([
+ Unrecognized option value (allowed values: auto, gtk1, gtk2, msw, motif, osx_carbon, osx_cocoa, dfb, x11)
+ ])
+ fi
+
+ AC_MSG_RESULT([$TOOLKIT])
+ fi
+ ])
+
+ dnl ****** IMPORTANT *******
+ dnl Unlike for the UNICODE setting, you can build your program in
+ dnl shared mode against a static build of wxWidgets. Thus we have the
+ dnl following option which allows these mixtures. E.g.
+ dnl
+ dnl ./configure --disable-shared --with-wxshared
+ dnl
+ dnl will build your library in static mode against the first available
+ dnl shared build of wxWidgets.
+ dnl
+ dnl Note that's not possible to do the viceversa:
+ dnl
+ dnl ./configure --enable-shared --without-wxshared
+ dnl
+ dnl Doing so you would try to build your library in shared mode against a static
+ dnl build of wxWidgets. This is not possible (you would mix PIC and non PIC code) !
+ dnl A check for this combination of options is in WX_DETECT_STANDARD_OPTION_VALUES
+ dnl (where we know what 'auto' should be expanded to).
+ dnl
+ dnl If you try to build something in ANSI mode against a UNICODE build
+ dnl of wxWidgets or in RELEASE mode against a DEBUG build of wxWidgets,
+ dnl then at best you'll get ton of linking errors !
+ dnl ************************
+
+ ifelse(index([$1], [wxshared]), [-1],,
+ [
+ WX_ARG_WITH_YESNOAUTO(
+ [wxshared], [WX_SHARED],
+ [Force building against a shared build of wxWidgets, even if --disable-shared is given],
+ [auto], [], [1])
+ ])
+
+ dnl Just like for SHARED and WX_SHARED it may happen that some adventurous
+ dnl peoples will want to mix a wxWidgets release build with a debug build of
+ dnl his app/lib. So, we have both DEBUG and WX_DEBUG variables.
+ ifelse(index([$1], [wxdebug]), [-1],,
+ [
+ WX_ARG_WITH_YESNOAUTO(
+ [wxdebug], [WX_DEBUG],
+ [Force building against a debug build of wxWidgets, even if --disable-debug is given],
+ [auto], [], [1])
+ ])
+
+ dnl WX_ARG_WITH_YESNOAUTO cannot be used for --with-wxversion since it's an option
+ dnl which accepts the "auto|2.6|2.7|2.8|2.9|3.0" etc etc values
+ ifelse(index([$1], [wxversion]), [-1],,
+ [
+ AC_ARG_WITH([wxversion],
+ AC_HELP_STRING([--with-wxversion],
+ [Build against a specific version of wxWidgets (default is auto)]),
+ [], [withval="auto"])
+
+ dnl Show a message to the user about this option
+ AC_MSG_CHECKING([for the --with-wxversion option])
+ if test "$withval" = "auto" ; then
+ AC_MSG_RESULT([will be automatically detected])
+ WX_RELEASE="auto"
+ else
+
+ wx_requested_major_version=`echo $withval | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).*/\1/'`
+ wx_requested_minor_version=`echo $withval | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).*/\2/'`
+
+ dnl both vars above must be exactly 1 digit
+ if test "${#wx_requested_major_version}" != "1" -o \
+ "${#wx_requested_minor_version}" != "1" ; then
+ AC_MSG_ERROR([
+ Unrecognized option value (allowed values: auto, 2.6, 2.7, 2.8, 2.9, 3.0)
+ ])
+ fi
+
+ WX_RELEASE="$wx_requested_major_version"".""$wx_requested_minor_version"
+ AC_MSG_RESULT([$WX_RELEASE])
+ fi
+ ])
+
+ if test "$WX_DEBUG_CONFIGURE" = "1"; then
+ echo "[[dbg]] DEBUG: $DEBUG, WX_DEBUG: $WX_DEBUG"
+ echo "[[dbg]] UNICODE: $UNICODE, WX_UNICODE: $WX_UNICODE"
+ echo "[[dbg]] SHARED: $SHARED, WX_SHARED: $WX_SHARED"
+ echo "[[dbg]] TOOLKIT: $TOOLKIT, WX_TOOLKIT: $WX_TOOLKIT"
+ echo "[[dbg]] VERSION: $VERSION, WX_RELEASE: $WX_RELEASE"
+ fi
+ ])
+
+
+dnl ---------------------------------------------------------------------------
+dnl WX_CONVERT_STANDARD_OPTIONS_TO_WXCONFIG_FLAGS
+dnl
+dnl Sets the WXCONFIG_FLAGS string using the SHARED,DEBUG,UNICODE variable values
+dnl which are different from "auto".
+dnl Thus this macro needs to be called only once all options have been set.
+dnl ---------------------------------------------------------------------------
+AC_DEFUN([WX_CONVERT_STANDARD_OPTIONS_TO_WXCONFIG_FLAGS],
+ [
+ if test "$WX_SHARED" = "1" ; then
+ WXCONFIG_FLAGS="--static=no "
+ elif test "$WX_SHARED" = "0" ; then
+ WXCONFIG_FLAGS="--static=yes "
+ fi
+
+ if test "$WX_DEBUG" = "1" ; then
+ WXCONFIG_FLAGS="$WXCONFIG_FLAGS""--debug=yes "
+ elif test "$WX_DEBUG" = "0" ; then
+ WXCONFIG_FLAGS="$WXCONFIG_FLAGS""--debug=no "
+ fi
+
+ dnl The user should have set WX_UNICODE=UNICODE
+ if test "$WX_UNICODE" = "1" ; then
+ WXCONFIG_FLAGS="$WXCONFIG_FLAGS""--unicode=yes "
+ elif test "$WX_UNICODE" = "0" ; then
+ WXCONFIG_FLAGS="$WXCONFIG_FLAGS""--unicode=no "
+ fi
+
+ if test "$TOOLKIT" != "auto" ; then
+ WXCONFIG_FLAGS="$WXCONFIG_FLAGS""--toolkit=$TOOLKIT "
+ fi
+
+ if test "$WX_RELEASE" != "auto" ; then
+ WXCONFIG_FLAGS="$WXCONFIG_FLAGS""--version=$WX_RELEASE "
+ fi
+
+ dnl strip out the last space of the string
+ WXCONFIG_FLAGS=${WXCONFIG_FLAGS% }
+
+ if test "$WX_DEBUG_CONFIGURE" = "1"; then
+ echo "[[dbg]] WXCONFIG_FLAGS: $WXCONFIG_FLAGS"
+ fi
+ ])
+
+
+dnl ---------------------------------------------------------------------------
+dnl _WX_SELECTEDCONFIG_CHECKFOR([RESULTVAR], [STRING], [MSG]
+dnl [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl
+dnl Outputs the given MSG. Then searches the given STRING in the wxWidgets
+dnl additional CPP flags and put the result of the search in WX_$RESULTVAR
+dnl also adding the "yes" or "no" message result to MSG.
+dnl ---------------------------------------------------------------------------
+AC_DEFUN([_WX_SELECTEDCONFIG_CHECKFOR],
+ [
+ if test "$$1" = "auto" ; then
+
+ dnl The user does not have particular preferences for this option;
+ dnl so we will detect the wxWidgets relative build setting and use it
+ AC_MSG_CHECKING([$3])
+
+ dnl set WX_$1 variable to 1 if the $WX_SELECTEDCONFIG contains the $2
+ dnl string or to 0 otherwise.
+ dnl NOTE: 'expr match STRING REGEXP' cannot be used since on Mac it
+ dnl doesn't work; we use 'expr STRING : REGEXP' instead
+ WX_$1=$(expr "$WX_SELECTEDCONFIG" : ".*$2.*")
+
+ if test "$WX_$1" != "0"; then
+ WX_$1=1
+ AC_MSG_RESULT([yes])
+ ifelse([$4], , :, [$4])
+ else
+ WX_$1=0
+ AC_MSG_RESULT([no])
+ ifelse([$5], , :, [$5])
+ fi
+ else
+
+ dnl Use the setting given by the user
+ WX_$1=$$1
+ fi
+ ])
+
+dnl ---------------------------------------------------------------------------
+dnl WX_DETECT_STANDARD_OPTION_VALUES
+dnl
+dnl Detects the values of the following variables:
+dnl 1) WX_RELEASE
+dnl 2) WX_UNICODE
+dnl 3) WX_DEBUG
+dnl 4) WX_SHARED (and also WX_STATIC)
+dnl 5) WX_PORT
+dnl from the previously selected wxWidgets build; this macro in fact must be
+dnl called *after* calling the WX_CONFIG_CHECK macro.
+dnl
+dnl Note that the WX_VERSION_MAJOR, WX_VERSION_MINOR symbols are already set
+dnl by WX_CONFIG_CHECK macro
+dnl ---------------------------------------------------------------------------
+AC_DEFUN([WX_DETECT_STANDARD_OPTION_VALUES],
+ [
+ dnl IMPORTANT: WX_VERSION contains all three major.minor.micro digits,
+ dnl while WX_RELEASE only the major.minor ones.
+ WX_RELEASE="$WX_VERSION_MAJOR""$WX_VERSION_MINOR"
+ if test $WX_RELEASE -lt 26 ; then
+
+ AC_MSG_ERROR([
+ Cannot detect the wxWidgets configuration for the selected wxWidgets build
+ since its version is $WX_VERSION < 2.6.0; please install a newer
+ version of wxWidgets.
+ ])
+ fi
+
+ dnl The wx-config we are using understands the "--selected_config"
+ dnl option which returns an easy-parseable string !
+ WX_SELECTEDCONFIG=$($WX_CONFIG_WITH_ARGS --selected_config)
+
+ if test "$WX_DEBUG_CONFIGURE" = "1"; then
+ echo "[[dbg]] Using wx-config --selected-config"
+ echo "[[dbg]] WX_SELECTEDCONFIG: $WX_SELECTEDCONFIG"
+ fi
+
+
+ dnl we could test directly for WX_SHARED with a line like:
+ dnl _WX_SELECTEDCONFIG_CHECKFOR([SHARED], [shared],
+ dnl [if wxWidgets was built in SHARED mode])
+ dnl but wx-config --selected-config DOES NOT outputs the 'shared'
+ dnl word when wx was built in shared mode; it rather outputs the
+ dnl 'static' word when built in static mode.
+ if test $WX_SHARED = "1"; then
+ STATIC=0
+ elif test $WX_SHARED = "0"; then
+ STATIC=1
+ elif test $WX_SHARED = "auto"; then
+ STATIC="auto"
+ fi
+
+ dnl Now set the WX_UNICODE, WX_DEBUG, WX_STATIC variables
+ _WX_SELECTEDCONFIG_CHECKFOR([UNICODE], [unicode],
+ [if wxWidgets was built with UNICODE enabled])
+ _WX_SELECTEDCONFIG_CHECKFOR([DEBUG], [debug],
+ [if wxWidgets was built in DEBUG mode])
+ _WX_SELECTEDCONFIG_CHECKFOR([STATIC], [static],
+ [if wxWidgets was built in STATIC mode])
+
+ dnl init WX_SHARED from WX_STATIC
+ if test "$WX_STATIC" != "0"; then
+ WX_SHARED=0
+ else
+ WX_SHARED=1
+ fi
+
+ AC_SUBST(WX_UNICODE)
+ AC_SUBST(WX_DEBUG)
+ AC_SUBST(WX_SHARED)
+
+ dnl detect the WX_PORT to use
+ if test "$TOOLKIT" = "auto" ; then
+
+ dnl The user does not have particular preferences for this option;
+ dnl so we will detect the wxWidgets relative build setting and use it
+ AC_MSG_CHECKING([which wxWidgets toolkit was selected])
+
+ WX_GTKPORT1=$(expr "$WX_SELECTEDCONFIG" : ".*gtk1.*")
+ WX_GTKPORT2=$(expr "$WX_SELECTEDCONFIG" : ".*gtk2.*")
+ WX_MSWPORT=$(expr "$WX_SELECTEDCONFIG" : ".*msw.*")
+ WX_MOTIFPORT=$(expr "$WX_SELECTEDCONFIG" : ".*motif.*")
+ WX_OSXCOCOAPORT=$(expr "$WX_SELECTEDCONFIG" : ".*osx_cocoa.*")
+ WX_OSXCARBONPORT=$(expr "$WX_SELECTEDCONFIG" : ".*osx_carbon.*")
+ WX_X11PORT=$(expr "$WX_SELECTEDCONFIG" : ".*x11.*")
+ WX_DFBPORT=$(expr "$WX_SELECTEDCONFIG" : ".*dfb.*")
+
+ WX_PORT="unknown"
+ if test "$WX_GTKPORT1" != "0"; then WX_PORT="gtk1"; fi
+ if test "$WX_GTKPORT2" != "0"; then WX_PORT="gtk2"; fi
+ if test "$WX_MSWPORT" != "0"; then WX_PORT="msw"; fi
+ if test "$WX_MOTIFPORT" != "0"; then WX_PORT="motif"; fi
+ if test "$WX_OSXCOCOAPORT" != "0"; then WX_PORT="osx_cocoa"; fi
+ if test "$WX_OSXCARBONPORT" != "0"; then WX_PORT="osx_carbon"; fi
+ if test "$WX_X11PORT" != "0"; then WX_PORT="x11"; fi
+ if test "$WX_DFBPORT" != "0"; then WX_PORT="dfb"; fi
+
+ dnl NOTE: backward-compatible check for wx2.8; in wx2.9 the mac
+ dnl ports are called 'osx_cocoa' and 'osx_carbon' (see above)
+ WX_MACPORT=$(expr "$WX_SELECTEDCONFIG" : ".*mac.*")
+ if test "$WX_MACPORT" != "0"; then WX_PORT="mac"; fi
+
+ dnl check at least one of the WX_*PORT has been set !
+
+ if test "$WX_PORT" = "unknown" ; then
+ AC_MSG_ERROR([
+ Cannot detect the currently installed wxWidgets port !
+ Please check your 'wx-config --cxxflags'...
+ ])
+ fi
+
+ AC_MSG_RESULT([$WX_PORT])
+ else
+
+ dnl Use the setting given by the user
+ if test -z "$TOOLKIT" ; then
+ WX_PORT=$TOOLKIT
+ else
+ dnl try with PORT
+ WX_PORT=$PORT
+ fi
+ fi
+
+ AC_SUBST(WX_PORT)
+
+ if test "$WX_DEBUG_CONFIGURE" = "1"; then
+ echo "[[dbg]] Values of all WX_* options after final detection:"
+ echo "[[dbg]] WX_DEBUG: $WX_DEBUG"
+ echo "[[dbg]] WX_UNICODE: $WX_UNICODE"
+ echo "[[dbg]] WX_SHARED: $WX_SHARED"
+ echo "[[dbg]] WX_RELEASE: $WX_RELEASE"
+ echo "[[dbg]] WX_PORT: $WX_PORT"
+ fi
+
+ dnl Avoid problem described in the WX_STANDARD_OPTIONS which happens when
+ dnl the user gives the options:
+ dnl ./configure --enable-shared --without-wxshared
+ dnl or just do
+ dnl ./configure --enable-shared
+ dnl but there is only a static build of wxWidgets available.
+ if test "$WX_SHARED" = "0" -a "$SHARED" = "1"; then
+ AC_MSG_ERROR([
+ Cannot build shared library against a static build of wxWidgets !
+ This error happens because the wxWidgets build which was selected
+ has been detected as static while you asked to build $PACKAGE_NAME
+ as shared library and this is not possible.
+ Use the '--disable-shared' option to build $PACKAGE_NAME
+ as static library or '--with-wxshared' to use wxWidgets as shared library.
+ ])
+ fi
+
+ dnl now we can finally update the DEBUG,UNICODE,SHARED options
+ dnl to their final values if they were set to 'auto'
+ if test "$DEBUG" = "auto"; then
+ DEBUG=$WX_DEBUG
+ fi
+ if test "$UNICODE" = "auto"; then
+ UNICODE=$WX_UNICODE
+ fi
+ if test "$SHARED" = "auto"; then
+ SHARED=$WX_SHARED
+ fi
+ if test "$TOOLKIT" = "auto"; then
+ TOOLKIT=$WX_PORT
+ fi
+
+ dnl in case the user needs a BUILD=debug/release var...
+ if test "$DEBUG" = "1"; then
+ BUILD="debug"
+ elif test "$DEBUG" = "0" -o "$DEBUG" = ""; then
+ BUILD="release"
+ fi
+
+ dnl respect the DEBUG variable adding the optimize/debug flags
+ dnl NOTE: the CXXFLAGS are merged together with the CPPFLAGS so we
+ dnl don't need to set them, too
+ if test "$DEBUG" = "1"; then
+ CXXFLAGS="$CXXFLAGS -g -O0"
+ CFLAGS="$CFLAGS -g -O0"
+ else
+ CXXFLAGS="$CXXFLAGS -O2"
+ CFLAGS="$CFLAGS -O2"
+ fi
+ ])
+
+dnl ---------------------------------------------------------------------------
+dnl WX_BOOLOPT_SUMMARY([name of the boolean variable to show summary for],
+dnl [what to print when var is 1],
+dnl [what to print when var is 0])
+dnl
+dnl Prints $2 when variable $1 == 1 and prints $3 when variable $1 == 0.
+dnl This macro mainly exists just to make configure.ac scripts more readable.
+dnl
+dnl NOTE: you need to use the [" my message"] syntax for 2nd and 3rd arguments
+dnl if you want that m4 avoid to throw away the spaces prefixed to the
+dnl argument value.
+dnl ---------------------------------------------------------------------------
+AC_DEFUN([WX_BOOLOPT_SUMMARY],
+ [
+ if test "x$$1" = "x1" ; then
+ echo $2
+ elif test "x$$1" = "x0" ; then
+ echo $3
+ else
+ echo "$1 is $$1"
+ fi
+ ])
+
+dnl ---------------------------------------------------------------------------
+dnl WX_STANDARD_OPTIONS_SUMMARY_MSG
+dnl
+dnl Shows a summary message to the user about the WX_* variable contents.
+dnl This macro is used typically at the end of the configure script.
+dnl ---------------------------------------------------------------------------
+AC_DEFUN([WX_STANDARD_OPTIONS_SUMMARY_MSG],
+ [
+ echo
+ echo " The wxWidgets build which will be used by $PACKAGE_NAME $PACKAGE_VERSION"
+ echo " has the following settings:"
+ WX_BOOLOPT_SUMMARY([WX_DEBUG], [" - DEBUG build"], [" - RELEASE build"])
+ WX_BOOLOPT_SUMMARY([WX_UNICODE], [" - UNICODE mode"], [" - ANSI mode"])
+ WX_BOOLOPT_SUMMARY([WX_SHARED], [" - SHARED mode"], [" - STATIC mode"])
+ echo " - VERSION: $WX_VERSION"
+ echo " - PORT: $WX_PORT"
+ ])
+
+
+dnl ---------------------------------------------------------------------------
+dnl WX_STANDARD_OPTIONS_SUMMARY_MSG_BEGIN, WX_STANDARD_OPTIONS_SUMMARY_MSG_END
+dnl
+dnl Like WX_STANDARD_OPTIONS_SUMMARY_MSG macro but these two macros also gives info
+dnl about the configuration of the package which used the wxpresets.
+dnl
+dnl Typical usage:
+dnl WX_STANDARD_OPTIONS_SUMMARY_MSG_BEGIN
+dnl echo " - Package setting 1: $SETTING1"
+dnl echo " - Package setting 2: $SETTING1"
+dnl ...
+dnl WX_STANDARD_OPTIONS_SUMMARY_MSG_END
+dnl
+dnl ---------------------------------------------------------------------------
+AC_DEFUN([WX_STANDARD_OPTIONS_SUMMARY_MSG_BEGIN],
+ [
+ echo
+ echo " ----------------------------------------------------------------"
+ echo " Configuration for $PACKAGE_NAME $PACKAGE_VERSION successfully completed."
+ echo " Summary of main configuration settings for $PACKAGE_NAME:"
+ WX_BOOLOPT_SUMMARY([DEBUG], [" - DEBUG build"], [" - RELEASE build"])
+ WX_BOOLOPT_SUMMARY([UNICODE], [" - UNICODE mode"], [" - ANSI mode"])
+ WX_BOOLOPT_SUMMARY([SHARED], [" - SHARED mode"], [" - STATIC mode"])
+ ])
+
+AC_DEFUN([WX_STANDARD_OPTIONS_SUMMARY_MSG_END],
+ [
+ WX_STANDARD_OPTIONS_SUMMARY_MSG
+ echo
+ echo " Now, just run make."
+ echo " ----------------------------------------------------------------"
+ echo
+ ])
+
+
+dnl ---------------------------------------------------------------------------
+dnl Deprecated macro wrappers
+dnl ---------------------------------------------------------------------------
+
+AC_DEFUN([AM_OPTIONS_WXCONFIG], [WX_CONFIG_OPTIONS])
+AC_DEFUN([AM_PATH_WXCONFIG], [
+ WX_CONFIG_CHECK([$1],[$2],[$3],[$4],[$5])
+])
+AC_DEFUN([AM_PATH_WXRC], [WXRC_CHECK([$1],[$2])])
diff --git a/lib/xmerl/doc/src/motorcycles_dtd.txt b/lib/xmerl/doc/src/motorcycles_dtd.txt
index bab0d563f0..62ad4ac5fe 100644
--- a/lib/xmerl/doc/src/motorcycles_dtd.txt
+++ b/lib/xmerl/doc/src/motorcycles_dtd.txt
@@ -15,4 +15,5 @@
<!ELEMENT date (#PCDATA)>
<!ATTLIST bike year NMTOKEN #REQUIRED
color NMTOKENS #REQUIRED
- condition (useless | bad | serviceable | moderate | good | excellent | new | outstanding) "excellent" >
+ condition (useless | bad | serviceable | moderate | good |
+ excellent | new | outstanding) "excellent" >
diff --git a/lib/xmerl/src/Makefile b/lib/xmerl/src/Makefile
index ce1aa11fba..d5ce3fe6ff 100644
--- a/lib/xmerl/src/Makefile
+++ b/lib/xmerl/src/Makefile
@@ -166,34 +166,34 @@ EDOC_PATHS = \
-pa $(EDOC_APP)/ebin -pa $(XMERL_APP)/ebin -pa $(SYNTAX_TOOLS_APP)/ebin
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
xmerl_xpath_parse.erl: xmerl_xpath_parse.yrl
- $(ERLC) -o $(ESRC) $<
+ $(yecc_verbose)$(ERLC) -o $(ESRC) $<
xmerl_b64Bin.erl: xmerl_b64Bin.yrl
- $(ERLC) -o $(ESRC) $<
+ $(yecc_verbose)$(ERLC) -o $(ESRC) $<
xmerl_sax_parser_list.erl: xmerl_sax_parser_list.erlsrc xmerl_sax_parser_base.erlsrc
- cat xmerl_sax_parser_list.erlsrc xmerl_sax_parser_base.erlsrc >$@
+ $(gen_verbose)cat xmerl_sax_parser_list.erlsrc xmerl_sax_parser_base.erlsrc >$@
xmerl_sax_parser_latin1.erl: xmerl_sax_parser_latin1.erlsrc xmerl_sax_parser_base.erlsrc
- cat xmerl_sax_parser_latin1.erlsrc xmerl_sax_parser_base.erlsrc >$@
+ $(gen_verbose)cat xmerl_sax_parser_latin1.erlsrc xmerl_sax_parser_base.erlsrc >$@
xmerl_sax_parser_utf8.erl: xmerl_sax_parser_utf8.erlsrc xmerl_sax_parser_base.erlsrc
- cat xmerl_sax_parser_utf8.erlsrc xmerl_sax_parser_base.erlsrc >$@
+ $(gen_verbose)cat xmerl_sax_parser_utf8.erlsrc xmerl_sax_parser_base.erlsrc >$@
xmerl_sax_parser_utf16be.erl: xmerl_sax_parser_utf16be.erlsrc xmerl_sax_parser_base.erlsrc
- cat xmerl_sax_parser_utf16be.erlsrc xmerl_sax_parser_base.erlsrc >$@
+ $(gen_verbose)cat xmerl_sax_parser_utf16be.erlsrc xmerl_sax_parser_base.erlsrc >$@
xmerl_sax_parser_utf16le.erl: xmerl_sax_parser_utf16le.erlsrc xmerl_sax_parser_base.erlsrc
- cat xmerl_sax_parser_utf16le.erlsrc xmerl_sax_parser_base.erlsrc >$@
+ $(gen_verbose)cat xmerl_sax_parser_utf16le.erlsrc xmerl_sax_parser_base.erlsrc >$@
$(EBIN)/%.beam: %.erl
- $(ERLC) $(ERL_COMPILE_FLAGS) -o $(EBIN) $<
+ $(V_ERLC) $(ERL_COMPILE_FLAGS) -o $(EBIN) $<
$(DOCDIR)/%.html: %.erl
$(ERL) -noshell $(EDOC_PATHS) \
diff --git a/lib/xmerl/src/xmerl_scan.erl b/lib/xmerl/src/xmerl_scan.erl
index 05431a5fd2..883153628c 100644
--- a/lib/xmerl/src/xmerl_scan.erl
+++ b/lib/xmerl/src/xmerl_scan.erl
@@ -1,7 +1,8 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -461,7 +462,7 @@ hook(X, State) ->
event(_X, S) ->
S.
-%% The acc/3 function can return either {Acc�, S'} or {Acc', Pos', S'},
+%% The acc/3 function can return either {Acc´, S'} or {Acc', Pos', S'},
%% where Pos' can be derived from X#xmlElement.pos, X#xmlText.pos, or
%% X#xmlAttribute.pos (whichever is the current object type.)
%% The acc/3 function is not allowed to redefine the type of object
diff --git a/lib/xmerl/src/xmerl_xsd.erl b/lib/xmerl/src/xmerl_xsd.erl
index 78d84d23a4..ffe227c671 100644
--- a/lib/xmerl/src/xmerl_xsd.erl
+++ b/lib/xmerl/src/xmerl_xsd.erl
@@ -1,3 +1,4 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
@@ -849,7 +850,7 @@ element_content({import,S=#xsd_state{schema_name=ThisSchema,
SchemaLocation = get_attribute_value(schemaLocation,I,absent),
%% If SchemaLocation is absent, the identification of that schema
%% is leaved to the instance, application or user, via the
- %% mechanisms described ��4.3 in XML Schema Part 1.
+ %% mechanisms described §4.3 in XML Schema Part 1.
S2 = process_external_schema_once(SchemaLocation,Namespace,S),
{{import,[]},S2#xsd_state{schema_name=ThisSchema,
diff --git a/lib/xmerl/test/xmerl_SUITE.erl b/lib/xmerl/test/xmerl_SUITE.erl
index 55b6d1844c..e21355f877 100644
--- a/lib/xmerl/test/xmerl_SUITE.erl
+++ b/lib/xmerl/test/xmerl_SUITE.erl
@@ -1,7 +1,8 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -531,8 +532,8 @@ ticket_7430(Config) ->
{xmlElement,a,a,[],
{xmlNamespace,[],[]},
[],1,[],
- [{xmlText,[{a,1}],1,[],"�",text},
- {xmlText,[{a,1}],2,[],"\n�",text}],
+ [{xmlText,[{a,1}],1,[],"é",text},
+ {xmlText,[{a,1}],2,[],"\né",text}],
[],_,undeclared} ->
ok;
_ ->
diff --git a/make/otp.mk.in b/make/otp.mk.in
index ed2fd8a70b..fca9cf3cff 100644
--- a/make/otp.mk.in
+++ b/make/otp.mk.in
@@ -25,6 +25,11 @@
.3 .1 .fig .dvi .tex .class .java .pdf .fo .psframe .pscrop .el .elc
# ----------------------------------------------------
+# Output
+# ----------------------------------------------------
+include $(ERL_TOP)/make/output.mk
+
+# ----------------------------------------------------
# Cross Compiling
# ----------------------------------------------------
CROSS_COMPILING = @CROSS_COMPILING@
@@ -104,19 +109,19 @@ ESRC = .
endif
$(EBIN)/%.beam: $(EGEN)/%.erl
- $(ERLC) $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
+ $(V_ERLC) $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
$(EBIN)/%.beam: $(ESRC)/%.erl
- $(ERLC) $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
+ $(V_ERLC) $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
ifeq ($(NATIVE_LIBS_ENABLED),yes)
# Special rule for the HIPE bootstrap w/ native libs
../boot_ebin/%.beam: $(ESRC)/%.erl
- $(ERLC) $(ERL_COMPILE_FLAGS) -o../boot_ebin $<
+ $(V_ERLC) $(ERL_COMPILE_FLAGS) -o../boot_ebin $<
endif
.erl.beam:
- $(ERLC) $(ERL_COMPILE_FLAGS) -o$(dir $@) $<
+ $(V_ERLC) $(ERL_COMPILE_FLAGS) -o$(dir $@) $<
#
# When .erl files are automatically created GNU make removes them if
@@ -131,10 +136,10 @@ endif
## $(ERLC) $(IDL_FLAGS) $<
$(EGEN)/%.erl: $(ESRC)/%.yrl
- $(ERLC) $(YRL_FLAGS) -o$(EGEN) $<
+ $(yecc_verbose)$(ERLC) $(YRL_FLAGS) -o$(EGEN) $<
$(EGEN)/%.erl: $(ESRC)/%.xrl
- $(ERLC) $(XRL_FLAGS) -o$(EGEN) $<
+ $(leex_verbose)$(ERLC) $(XRL_FLAGS) -o$(EGEN) $<
# ----------------------------------------------------
# SNMP language section
@@ -149,16 +154,16 @@ endif
$(SNMP_BIN_TARGET_DIR)/%.bin: %.mib
- $(ERLC) -pa $(SNMP_TOOLKIT)/ebin -I $(SNMP_TOOLKIT)/priv/mibs $(SNMP_FLAGS) -o $(SNMP_BIN_TARGET_DIR) $<
+ $(snmp_verbose)$(ERLC) -pa $(SNMP_TOOLKIT)/ebin -I $(SNMP_TOOLKIT)/priv/mibs $(SNMP_FLAGS) -o $(SNMP_BIN_TARGET_DIR) $<
$(SNMP_HRL_TARGET_DIR)/%.hrl: $(SNMP_BIN_TARGET_DIR)/%.bin
- $(ERLC) -pa $(SNMP_TOOLKIT)/ebin -o $(SNMP_HRL_TARGET_DIR) $<
+ $(snmp_verbose)$(ERLC) -pa $(SNMP_TOOLKIT)/ebin -o $(SNMP_HRL_TARGET_DIR) $<
.mib.bin:
- $(ERLC) -pa $(SNMP_TOOLKIT)/ebin -I $(SNMP_TOOLKIT)/priv/mibs $(SNMP_FLAGS) $<
+ $(snmp_verbose)$(ERLC) -pa $(SNMP_TOOLKIT)/ebin -I $(SNMP_TOOLKIT)/priv/mibs $(SNMP_FLAGS) $<
.bin.hrl:
- $(ERLC) -pa $(SNMP_TOOLKIT)/ebin $<
+ $(snmp_verbose)$(ERLC) -pa $(SNMP_TOOLKIT)/ebin $<
# ----------------------------------------------------
# Java language section
@@ -170,11 +175,11 @@ JAVA_DEST_ROOT = ../priv/
endif
.java.class:
- CLASSPATH=$(CLASSPATH) $(JAVA) $(JAVA_OPTIONS) $<
+ $(javac_verbose)CLASSPATH=$(CLASSPATH) $(JAVA) $(JAVA_OPTIONS) $<
$(JAVA_DEST_ROOT)$(JAVA_CLASS_SUBDIR)%.class: %.java
- CLASSPATH=$(CLASSPATH) $(JAVA) $(JAVA_OPTIONS) -d $(JAVA_DEST_ROOT) $<
+ $(javac_verbose)CLASSPATH=$(CLASSPATH) $(JAVA) $(JAVA_OPTIONS) -d $(JAVA_DEST_ROOT) $<
# ----------------------------------------------------
# Emacs byte code compiling
@@ -183,7 +188,7 @@ EMACS_COMPILER=emacs-20
EMACS_COMPILE_OPTIONS=-q --no-site-file -batch -f batch-byte-compile
.el.elc:
- $(EMACS_COMPILER) $(EMACS_COMPILE_OPTIONS) $<
+ $(emacs_verbose)$(EMACS_COMPILER) $(EMACS_COMPILE_OPTIONS) $<
# ----------------------------------------------------
# Documentation section
@@ -209,6 +214,22 @@ TEXDIR = .
SPECDIR = $(DOCDIR)/specs
+ifeq ($(CSS_FILE),)
+CSS_FILE = otp_doc.css
+endif
+ifeq ($(WINPREFIX),)
+WINPREFIX = Erlang
+endif
+ifeq ($(HTMLLOGO),)
+HTMLLOGO_FILE = erlang-logo.png
+endif
+ifeq ($(PDFLOGO),)
+PDFLOGO_FILE = $(DOCGEN)/priv/images/erlang-logo.gif
+endif
+ifeq ($(PDFCOLOR),)
+PDFCOLOR = \#960003
+endif
+
# HTML & GIF files that always are generated and must be delivered
SGML_COLL_FILES = $(SGML_APPLICATION_FILES) $(SGML_PART_FILES)
XML_COLL_FILES = $(XML_APPLICATION_FILES) $(XML_PART_FILES)
@@ -234,8 +255,10 @@ DEFAULT_GIF_FILES = $(HTMLDIR)/min_head.gif
#
XSLTPROC = @XSLTPROC@
FOP = @FOP@
+XMLLINT = @XMLLINT@
DOCGEN=$(ERL_TOP)/lib/erl_docgen
+FOP_CONFIG = $(DOCGEN)/priv/fop.xconf
ifneq (,$(findstring $(origin SPECS_ESRC),$(DUBIOUS_ORIGINS)))
SPECS_ESRC = ../../src
@@ -250,12 +273,10 @@ $(MAN1DIR)/%.1: %.xml
date=`date +"%B %e %Y"`; \
xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $<
-
$(MAN2DIR)/%.2: %.xml
date=`date +"%B %e %Y"`; \
xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $<
-
ifneq ($(wildcard $(SPECDIR)),)
$(MAN3DIR)/%.3: %.xml $(SPECDIR)/specs_%.xml
date=`date +"%B %e %Y"`; \
@@ -294,5 +315,5 @@ $(MAN9DIR)/%.9: %.xml
escript $(DOCGEN)/priv/bin/codeline_preprocessing.escript $< $@
.fo.pdf:
- $(FOP) -fo $< -pdf $@
+ $(FOP) -c $(FOP_CONFIG) -fo $< -pdf $@
diff --git a/make/otp_ded.mk.in b/make/otp_ded.mk.in
index e719312473..e2232acbb1 100644
--- a/make/otp_ded.mk.in
+++ b/make/otp_ded.mk.in
@@ -37,7 +37,7 @@ DED__NOWARN_CFLAGS = @DED_EMU_THR_DEFS@ @DED_CFLAGS@
DED_THR_DEFS = @DED_THR_DEFS@
DED_EMU_THR_DEFS = @DED_EMU_THR_DEFS@
DED_WARN_FLAGS = @WFLAGS@
-DED_CFLAGS = @WFLAGS@ @DED_EMU_THR_DEFS@ @DED_CFLAGS@
+DED_CFLAGS = @WERRORFLAGS@ @WFLAGS@ @DED_EMU_THR_DEFS@ @DED_CFLAGS@
DED_LIBS = @LIBS@
DED_EXT = @DED_EXT@
ERLANG_OSTYPE = @ERLANG_OSTYPE@
diff --git a/make/otp_release_targets.mk b/make/otp_release_targets.mk
index 67243b5ffd..65a2e62979 100644
--- a/make/otp_release_targets.mk
+++ b/make/otp_release_targets.mk
@@ -42,17 +42,34 @@ $(HTMLDIR)/index.html: $(XML_FILES) $(SPECS_FILES)
--stringparam gendate "$$date" \
--stringparam appname "$(APPLICATION)" \
--stringparam appver "$(VSN)" \
+ --stringparam stylesheet "$(CSS_FILE)" \
+ --stringparam winprefix "$(WINPREFIX)" \
+ --stringparam logo "$(HTMLLOGO_FILE)" \
+ --stringparam pdfname "$(PDFNAME)" \
-path $(DOCGEN)/priv/dtd \
-path $(DOCGEN)/priv/dtd_html_entities \
$(DOCGEN)/priv/xsl/db_html.xsl book.xml
+
endif
$(HTMLDIR)/users_guide.html: $(XML_FILES)
date=`date +"%B %e %Y"`; \
- $(XSLTPROC) --noout --stringparam outdir $(HTMLDIR) --stringparam docgen "$(DOCGEN)" --stringparam topdocdir "$(TOPDOCDIR)" \
+ $(XSLTPROC) --noout \
+ --stringparam outdir $(HTMLDIR) \
+ --stringparam docgen "$(DOCGEN)" \
+ --stringparam topdocdir "$(TOPDOCDIR)" \
--stringparam pdfdir "$(PDFDIR)" \
- --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude \
- -path $(DOCGEN)/priv/dtd -path $(DOCGEN)/priv/dtd_html_entities $(DOCGEN)/priv/xsl/db_html.xsl book.xml
+ --stringparam gendate "$$date" \
+ --stringparam appname "$(APPLICATION)" \
+ --stringparam appver "$(VSN)" \
+ --stringparam stylesheet "$(CSS_FILE)" \
+ --stringparam winprefix "$(WINPREFIX)" \
+ --stringparam logo "$(HTMLLOGO_FILE)" \
+ --stringparam pdfname "$(PDFNAME)" \
+ --xinclude \
+ -path $(DOCGEN)/priv/dtd \
+ -path $(DOCGEN)/priv/dtd_html_entities \
+ $(DOCGEN)/priv/xsl/db_html.xsl book.xml
%.fo: $(XML_FILES) $(SPECS_FILES)
date=`date +"%B %e %Y"`; \
@@ -61,6 +78,8 @@ $(HTMLDIR)/users_guide.html: $(XML_FILES)
--stringparam gendate "$$date" \
--stringparam appname "$(APPLICATION)" \
--stringparam appver "$(VSN)" \
+ --stringparam logo "$(PDFLOGO_FILE)" \
+ --stringparam pdfcolor "$(PDFCOLOR)" \
--xinclude $(TOP_SPECS_PARAM) \
-path $(DOCGEN)/priv/dtd \
-path $(DOCGEN)/priv/dtd_html_entities \
@@ -77,11 +96,19 @@ ifneq ($(XML_FILES),)
$(HTMLDIR)/$(APPLICATION).eix: $(XML_FILES) $(SPECS_FILES)
date=`date +"%B %e %Y"`; \
$(XSLTPROC) --stringparam docgen "$(DOCGEN)" \
- --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude $(TOP_SPECS_PARAM) \
- -path $(DOCGEN)/priv/dtd -path $(DOCGEN)/priv/dtd_html_entities $(DOCGEN)/priv/xsl/db_eix.xsl book.xml > $@
+ --stringparam gendate "$$date" \
+ --stringparam appname "$(APPLICATION)" \
+ --stringparam appver "$(VSN)" \
+ -xinclude $(TOP_SPECS_PARAM) \
+ -path $(DOCGEN)/priv/dtd \
+ -path $(DOCGEN)/priv/dtd_html_entities \
+ $(DOCGEN)/priv/xsl/db_eix.xsl book.xml > $@
docs: $(HTMLDIR)/$(APPLICATION).eix
+xmllint: $(XML_FILES)
+ $(XMLLINT) --noout --valid --nodefdtd --loaddtd --path $(DOCGEN)/priv/dtd:$(DOCGEN)/priv/dtd_html_entities $(XML_FILES)
+
# ----------------------------------------------------
# Local documentation target for testing
# ----------------------------------------------------
diff --git a/make/output.mk.in b/make/output.mk.in
new file mode 100644
index 0000000000..2f1a1d3a79
--- /dev/null
+++ b/make/output.mk.in
@@ -0,0 +1,112 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+# ----------------------------------------------------
+# Make include file for otp
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1997-2012. All Rights Reserved.
+#
+# The 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%
+#
+# Author: Anthony Ramine
+# ----------------------------------------------------
+
+ifeq ($(V),)
+V = @DEFAULT_VERBOSITY@
+endif
+
+ifeq ($(V),0)
+v_p = 0
+else
+v_p = 1
+endif
+
+V_at_0 = @
+V_at = $(V_at_$(V))
+
+V_colon_0 = @: ""
+V_colon = $(V_colon_$(V))
+
+ar_verbose_0 = @echo " AR "$@;
+ar_verbose = $(ar_verbose_$(V))
+V_AR = $(ar_verbose)$(AR)
+
+asn_verbose_0 = @echo " ASN "$@;
+asn_verbose = $(asn_verbose_$(V))
+
+cc_verbose_0 = @echo " CC "$@;
+cc_verbose = $(cc_verbose_$(V))
+V_CC = $(cc_verbose)$(CC)
+
+dia_verbose_0 = @echo " DIA "$@;
+dia_verbose = $(dia_verbose_$(V))
+
+dtrace_verbose_0 = @echo " DTRACE "$@;
+dtrace_verbose = $(dtrace_verbose_$(V))
+
+emacs_verbose_0 = @echo " EMACS "$@;
+emacs_verbose = $(emacs_verbose_$(V))
+
+emu_cc_verbose_0 = @echo " EMU_CC "$@;
+emu_cc_verbose = $(emu_cc_verbose_$(V))
+V_EMU_CC = $(emu_cc_verbose)$(EMU_CC)
+
+erlc_verbose_0 = @echo " ERLC "$@;
+erlc_verbose = $(erlc_verbose_$(V))
+V_ERLC = $(erlc_verbose)$(ERLC)
+
+gen_verbose_0 = @echo " GEN "$@;
+gen_verbose = $(gen_verbose_$(V))
+
+javac_verbose_0 = @echo " JAVAC "$@;
+javac_verbose = $(javac_verbose_$(V))
+V_JAVAC = $(javac_verbose)$(JAVAC)
+
+ld_verbose_0 = @echo " LD "$@;
+ld_verbose = $(ld_verbose_$(V))
+V_LD = $(ld_verbose)$(LD)
+
+leex_verbose_0 = @echo " LEEX "$@;
+leex_verbose = $(leex_verbose_$(V))
+
+lex_verbose_0 = @echo " LEX "$@;
+lex_verbose = $(lex_verbose_$(V))
+V_LEX = $(lex_verbose)$(LEX)
+
+m4_verbose_0 = @echo " M4 "$@;
+m4_verbose = $(m4_verbose_$(V))
+
+make_verbose_0 = @echo " MAKE "$@;
+make_verbose = $(make_verbose_$(V))
+
+mc_verbose_0 = @echo " MC "$@;
+mc_verbose = $(mc_verbose_$(V))
+V_MC = $(mc_verbose)$(MC)
+
+ranlib_verbose_0 = @echo " RANLIB "$@;
+ranlib_verbose = $(ranlib_verbose_$(V))
+V_RANLIB = $(ranlib_verbose)$(RANLIB)
+
+rc_verbose_0 = @echo " RC "$@;
+rc_verbose = $(rc_verbose_$(V))
+V_RC = $(rc_verbose)$(RC)
+
+snmp_verbose_0 = @echo " SNMP "$@;
+snmp_verbose = $(snmp_verbose_$(V))
+
+vsn_verbose_0 = @echo " VSN "$@;
+vsn_verbose = $(vsn_verbose_$(V))
+
+yecc_verbose_0 = @echo " YECC "$@;
+yecc_verbose = $(yecc_verbose_$(V))
diff --git a/make/run_make.mk b/make/run_make.mk
index b7a5a64847..1b4213107f 100644
--- a/make/run_make.mk
+++ b/make/run_make.mk
@@ -25,19 +25,20 @@
#
# ----------------------------------------------------
+include $(ERL_TOP)/make/output.mk
include $(ERL_TOP)/make/target.mk
.PHONY: valgrind
opt debug purify quantify purecov valgrind gcov gprof lcnt:
- $(MAKE) -f $(TARGET)/Makefile TYPE=$@
+ $(make_verbose)$(MAKE) -f $(TARGET)/Makefile TYPE=$@
plain smp frag smp_frag:
- $(MAKE) -f $(TARGET)/Makefile FLAVOR=$@
+ $(make_verbose)$(MAKE) -f $(TARGET)/Makefile FLAVOR=$@
clean generate depend docs release release_spec release_docs release_docs_spec \
tests release_tests release_tests_spec:
- $(MAKE) -f $(TARGET)/Makefile $@
+ $(make_verbose)$(MAKE) -f $(TARGET)/Makefile $@
diff --git a/otp_build b/otp_build
index 85be25a8a1..093fde8034 100755
--- a/otp_build
+++ b/otp_build
@@ -295,7 +295,7 @@ chk_eq()
check_config_helpers ()
{
- aclocals="./aclocal.m4 ./lib/erl_interface/aclocal.m4 ./lib/odbc/aclocal.m4 ./lib/wx/aclocal.m4"
+ aclocals="./aclocal.m4 ./lib/erl_interface/aclocal.m4 ./lib/odbc/aclocal.m4 ./lib/wx/aclocal.m4 ./lib/megaco/aclocal.m4"
install_shs="./lib/common_test/priv/auxdir/install-sh ./lib/erl_interface/src/auxdir/install-sh ./lib/test_server/src/install-sh"
config_guesses="./lib/common_test/priv/auxdir/config.guess ./lib/erl_interface/src/auxdir/config.guess ./lib/test_server/src/config.guess"
config_subs="./lib/common_test/priv/auxdir/config.sub ./lib/erl_interface/src/auxdir/config.sub ./lib/test_server/src/config.sub"
diff --git a/system/doc/efficiency_guide/advanced.xml b/system/doc/efficiency_guide/advanced.xml
index 821175bb09..ac35a37bc4 100644
--- a/system/doc/efficiency_guide/advanced.xml
+++ b/system/doc/efficiency_guide/advanced.xml
@@ -123,12 +123,11 @@ On 64-bit architectures: 4 words for a reference from the current local node, an
<tag><em>Processes</em></tag>
<item>
<p>The maximum number of simultaneously alive Erlang processes is
- by default 32768. This limit can be raised up to at most 268435456
- processes at startup (see documentation of the system flag
- <seealso marker="erts:erl#max_processes">+P</seealso> in the
- <seealso marker="erts:erl">erl(1)</seealso> documentation).
- The maximum limit of 268435456 processes will at least on a 32-bit
- architecture be impossible to reach due to memory shortage.</p>
+ by default 32768. This limit can be configured at startup,
+ for more information see the
+ <seealso marker="erts:erl#max_processes"><c>+P</c></seealso>
+ command line flag of
+ <seealso marker="erts:erl"><c>erl(1)</c></seealso>.</p>
</item>
<tag><em>Distributed nodes</em></tag>
<item>
@@ -184,13 +183,12 @@ On 64-bit architectures: 4 words for a reference from the current local node, an
<tag><em>Open ports</em></tag>
<item>
<marker id="ports"></marker>
- <p>The maximum number of simultaneously open Erlang ports is
- by default 1024. This limit can be raised up to at most 268435456
- at startup (see environment variable
- <seealso marker="erts:erlang#ERL_MAX_PORTS">ERL_MAX_PORTS</seealso>
- in <seealso marker="erts:erlang">erlang(3)</seealso>)
- The maximum limit of 268435456 open ports will at least on a 32-bit
- architecture be impossible to reach due to memory shortage.</p>
+ <p>The maximum number of simultaneously oper Erlang ports is
+ often by default 16384. This limit can be configured at startup,
+ for more information see the
+ <seealso marker="erts:erl#max_ports"><c>+Q</c></seealso>
+ command line flag of
+ <seealso marker="erts:erl"><c>erl(1)</c></seealso>.</p>
</item>
<tag><em>Open files, and sockets</em></tag>
<item> <marker id="files_sockets"></marker>
diff --git a/system/doc/efficiency_guide/drivers.xml b/system/doc/efficiency_guide/drivers.xml
index fec68ca059..b10595ea4d 100644
--- a/system/doc/efficiency_guide/drivers.xml
+++ b/system/doc/efficiency_guide/drivers.xml
@@ -105,9 +105,9 @@ client_port() ->
<p>If you know that the binaries you return are always small,
you should use driver API calls that do not require a pre-allocated
binary, for instance
- <seealso marker="erts:erl_driver#int driver_output-3">driver_output()</seealso>
+ <seealso marker="erts:erl_driver#driver_output">driver_output()</seealso>
or
- <seealso marker="erts:erl_driver#int driver_output_term-3">driver_output_term()</seealso>
+ <seealso marker="erts:erl_driver#erl_drv_output_term">erl_drv_output_term()</seealso>
using the <c>ERL_DRV_BUF2BINARY</c> format,
to allow the run-time to construct a heap binary.</p>
@@ -120,7 +120,7 @@ client_port() ->
the driver to an Erlang process, the driver must first allocate the
binary and then send it to an Erlang process in some way.</p>
- <p>Use <seealso marker="erts:erl_driver#ErlDrvBinary* driver_alloc_binary-1">driver_alloc_binary()</seealso> to allocate a binary.</p>
+ <p>Use <seealso marker="erts:erl_driver#driver_alloc_binary">driver_alloc_binary()</seealso> to allocate a binary.</p>
<p>There are several ways to send a binary created with
<c>driver_alloc_binary()</c>.</p>
@@ -128,17 +128,17 @@ client_port() ->
<list type="bulleted">
<item><p>From the <c>control</c> callback, a binary can be returned provided
that
- <seealso marker="erts:erl_driver#void set_port_control_flags-2">set_port_control()</seealso>
+ <seealso marker="erts:erl_driver#set_port_control_flags">set_port_control_flags()</seealso>
has been called with the flag value <c>PORT_CONTROL_FLAG_BINARY</c>.</p>
</item>
<item><p>A single binary can be sent with
- <seealso marker="erts:erl_driver#int driver_output_binary-6">driver_output_binary()</seealso>.</p></item>
+ <seealso marker="erts:erl_driver#driver_output_binary">driver_output_binary()</seealso>.</p></item>
<item><p>Using
- <seealso marker="erts:erl_driver#int driver_output_term-3">driver_output_term()</seealso>
+ <seealso marker="erts:erl_driver#erl_drv_output_term">erl_drv_output_term()</seealso>
or
- <seealso marker="erts:erl_driver#int driver_send_term-4">driver_send_term()</seealso>,
+ <seealso marker="erts:erl_driver#erl_drv_send_term">erl_drv_send_term()</seealso>,
a binary can be included in an Erlang term.</p>
</item>
</list>
diff --git a/system/doc/embedded/part.xml b/system/doc/embedded/part.xml
index abedce46d6..d96a94a1a0 100644
--- a/system/doc/embedded/part.xml
+++ b/system/doc/embedded/part.xml
@@ -45,6 +45,5 @@
</description>
<xi:include href="embedded_solaris.xml"/>
<xi:include href="embedded_nt.xml"/>
- <xi:include href="vxworks.xml"/>
</part>
diff --git a/system/doc/reference_manual/introduction.xml b/system/doc/reference_manual/introduction.xml
index 3dac5cfe13..7737c34469 100644
--- a/system/doc/reference_manual/introduction.xml
+++ b/system/doc/reference_manual/introduction.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2003</year><year>2009</year>
+ <year>2003</year><year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -150,6 +150,17 @@
</row>
<tcaption>Character Classes.</tcaption>
</table>
+ <p>In Erlang/OTP R16 the syntax of Erlang tokens was extended to
+ handle Unicode. To begin with the support is limited to strings,
+ but Erlang/OTP R18 is expected to handle Unicode atoms as well.
+ More about the usage of Unicode in Erlang source files can be
+ found in <seealso
+ marker="stdlib:unicode_usage#unicode_in_erlang">STDLIB's User'S
+ Guide</seealso>. The default encoding for Erlang source files
+ is still Latin-1, but in Erlang/OTP R17 the default encoding
+ will be UTF-8. The details on how to state the encoding of an
+ Erlang source file can be found in <seealso
+ marker="stdlib:epp#encoding">epp(3)</seealso>.</p>
</section>
</chapter>
diff --git a/system/doc/reference_manual/ports.xml b/system/doc/reference_manual/ports.xml
index 4847dd67cd..c4e4ef1d35 100644
--- a/system/doc/reference_manual/ports.xml
+++ b/system/doc/reference_manual/ports.xml
@@ -87,8 +87,14 @@
of bytes, the option <c>binary</c> must be included.</p>
<p>The port owner <c>Pid</c> can communicate with the port
<c>Port</c> by sending and receiving messages. (In fact, any
- process can send the messages to the port, but the messages from
- the port always go to the port owner).</p>
+ process can send the messages to the port, but the port owner must
+ be identified in the message).</p>
+ <p>As of OTP-R16 messages sent to ports are delivered truly
+ asynchronously. The underlying implementation previously
+ delivered messages to ports synchronously. Message passing has
+ however always been documented as an asynchronous operation, so
+ this should not be an issue for an Erlang program communicating
+ with ports, unless false assumptions about ports has been made.</p>
<p>Below, <c>Data</c> must be an I/O list. An I/O list is a binary
or a (possibly deep) list of binaries or integers in the range
0..255.</p>
@@ -127,8 +133,7 @@
<tcaption>Messages Received From a Port.</tcaption>
</table>
<p>Instead of sending and receiving messages, there are also a
- number of BIFs that can be used. These can be called by any
- process, not only the port owner.</p>
+ number of BIFs that can be used.</p>
<table>
<row>
<cell align="left" valign="middle"><c>port_command(Port,Data)</c></cell>
diff --git a/system/doc/top/Makefile b/system/doc/top/Makefile
index 9b305eb13b..673ba44c94 100644
--- a/system/doc/top/Makefile
+++ b/system/doc/top/Makefile
@@ -163,17 +163,34 @@ $(MAN_INDEX): $(MAN_INDEX_SCRIPT)
$(HTMLDIR)/highlights.html: highlights.xml
date=`date +"%B %e %Y"`; \
- $(XSLTPROC) --output $(@) --stringparam docgen "$(DOCGEN)" --stringparam topdocdir "$(TOPDOCDIR)" \
- --stringparam pdfdir "$(PDFREFDIR)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" \
- --stringparam appver "$(VSN)" -path $(DOCGEN)/priv/dtd -path $(DOCGEN)/priv/dtd_html_entities \
+ $(XSLTPROC) --output $(@) \
+ --stringparam docgen "$(DOCGEN)" \
+ --stringparam topdocdir "$(TOPDOCDIR)" \
+ --stringparam pdfdir "$(PDFREFDIR)" \
+ --stringparam gendate "$$date" \
+ --stringparam appname "$(APPLICATION)" \
+ --stringparam appver "$(VSN)" \
+ --stringparam stylesheet "$(CSS_FILE)" \
+ --stringparam winprefix "$(WINPREFIX)" \
+ --stringparam logo "$(HTMLLOGO_FILE)" \
+ -path $(DOCGEN)/priv/dtd \
+ -path $(DOCGEN)/priv/dtd_html_entities \
$(DOCGEN)/priv/xsl/db_html.xsl $<
$(HTMLDIR)/incompatible.html: incompatible.xml
date=`date +"%B %e %Y"`; \
- $(XSLTPROC) --output $(@) --stringparam docgen "$(DOCGEN)" --stringparam topdocdir "$(TOPDOCDIR)" \
- --stringparam pdfdir "$(PDFREFDIR)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" \
- --stringparam appver "$(VSN)" -path $(DOCGEN)/priv/dtd -path $(DOCGEN)/priv/dtd_html_entities \
+ $(XSLTPROC) --output $(@) --stringparam docgen "$(DOCGEN)" \
+ --stringparam topdocdir "$(TOPDOCDIR)" \
+ --stringparam pdfdir "$(PDFREFDIR)" \
+ --stringparam gendate "$$date" \
+ --stringparam appname "$(APPLICATION)" \
+ --stringparam appver "$(VSN)" \
+ --stringparam stylesheet "$(CSS_FILE)" \
+ --stringparam winprefix "$(WINPREFIX)" \
+ --stringparam logo "$(HTMLLOGO_FILE)" \
+ -path $(DOCGEN)/priv/dtd \
+ -path $(DOCGEN)/priv/dtd_html_entities \
$(DOCGEN)/priv/xsl/db_html.xsl $<
#--------------------------------------------------------------------------
diff --git a/system/doc/tutorial/port_driver.c b/system/doc/tutorial/port_driver.c
index d428d08ff3..37de67310f 100644
--- a/system/doc/tutorial/port_driver.c
+++ b/system/doc/tutorial/port_driver.c
@@ -19,7 +19,8 @@ static void example_drv_stop(ErlDrvData handle)
driver_free((char*)handle);
}
-static void example_drv_output(ErlDrvData handle, char *buff, int bufflen)
+static void example_drv_output(ErlDrvData handle, char *buff,
+ ErlDrvSizeT bufflen)
{
example_data* d = (example_data*)handle;
char fn = buff[0], arg = buff[1], res;
@@ -32,7 +33,7 @@ static void example_drv_output(ErlDrvData handle, char *buff, int bufflen)
}
ErlDrvEntry example_driver_entry = {
- NULL, /* F_PTR init, N/A */
+ NULL, /* F_PTR init, called when driver is loaded */
example_drv_start, /* L_PTR start, called when port is opened */
example_drv_stop, /* F_PTR stop, called when port is closed */
example_drv_output, /* F_PTR output, called when erlang has sent */
@@ -40,9 +41,30 @@ ErlDrvEntry example_driver_entry = {
NULL, /* F_PTR ready_output, called when output descriptor ready */
"example_drv", /* char *driver_name, the argument to open_port */
NULL, /* F_PTR finish, called when unloaded */
+ NULL, /* void *handle, Reserved by VM */
NULL, /* F_PTR control, port_command callback */
NULL, /* F_PTR timeout, reserved */
- NULL /* F_PTR outputv, reserved */
+ NULL, /* F_PTR outputv, reserved */
+ NULL, /* F_PTR ready_async, only for async drivers */
+ NULL, /* F_PTR flush, called when port is about
+ to be closed, but there is data in driver
+ queue */
+ NULL, /* F_PTR call, much like control, sync call
+ to driver */
+ NULL, /* F_PTR event, called when an event selected
+ by driver_event() occurs. */
+ ERL_DRV_EXTENDED_MARKER, /* int extended marker, Should always be
+ set to indicate driver versioning */
+ ERL_DRV_EXTENDED_MAJOR_VERSION, /* int major_version, should always be
+ set to this value */
+ ERL_DRV_EXTENDED_MINOR_VERSION, /* int minor_version, should always be
+ set to this value */
+ 0, /* int driver_flags, see documentation */
+ NULL, /* void *handle2, reserved for VM use */
+ NULL, /* F_PTR process_exit, called when a
+ monitored process dies */
+ NULL /* F_PTR stop_select, called to close an
+ event object */
};
DRIVER_INIT(example_drv) /* must match name in driver_entry */
diff --git a/xcomp/erl-xcomp-powerpc-dso-linux-gnu.conf b/xcomp/erl-xcomp-powerpc-dso-linux-gnu.conf
index 0e0c2f2337..c245b493a5 100644
--- a/xcomp/erl-xcomp-powerpc-dso-linux-gnu.conf
+++ b/xcomp/erl-xcomp-powerpc-dso-linux-gnu.conf
@@ -55,11 +55,11 @@ erl_xcomp_build=guess
# It does not have to be a full `CPU-VENDOR-OS' triplet, but can be. The
# full `CPU-VENDOR-OS' triplet will be created by
# `$ERL_TOP/erts/autoconf/config.sub $erl_xcomp_host'.
-erl_xcomp_host=powerpc-dso-linux-gnu
+erl_xcomp_host=powerpc-linux-gnu
# * `erl_xcomp_configure_flags' - Extra configure flags to pass to the
# `configure' script.
-erl_xcomp_configure_flags=--without-termcap
+erl_xcomp_configure_flags="--without-termcap"
## -- Cross Compiler and Other Tools -------------------------------------------
@@ -70,7 +70,7 @@ erl_xcomp_configure_flags=--without-termcap
## All variables in this section can also be used when native compiling.
# * `CC' - C compiler.
-CC=powerpc-dso-linux-gnu-gcc
+CC=powerpc-linux-gnu-gcc
# * `CFLAGS' - C compiler flags.
#CFLAGS=
@@ -90,13 +90,13 @@ CC=powerpc-dso-linux-gnu-gcc
#CPPFLAGS=
# * `CXX' - C++ compiler.
-CXX=powerpc-dso-linux-gnu-g++
+CXX=powerpc-linux-gnu-g++
# * `CXXFLAGS' - C++ compiler flags.
#CXXFLAGS=
# * `LD' - Linker.
-LD=powerpc-dso-linux-gnu-ld
+LD=powerpc-linux-gnu-ld
# * `LDFLAGS' - Linker flags.
#LDFLAGS=
@@ -134,10 +134,10 @@ LD=powerpc-dso-linux-gnu-ld
## -- Other Tools --
# * `RANLIB' - `ranlib' archive index tool.
-RANLIB=powerpc-dso-linux-gnu-ranlib
+RANLIB=powerpc-linux-gnu-ranlib
# * `AR' - `ar' archiving tool.
-AR=powerpc-dso-linux-gnu-ar
+AR=powerpc-linux-gnu-ar
# * `GETCONF' - `getconf' system configuration inspection tool. `getconf' is
# currently used for finding out large file support flags to use, and
@@ -178,7 +178,7 @@ erl_xcomp_sysroot="$DSO_SYSROOT_POWERPC"
# the target system must have a working `__after_morecore_hook' that can be
# used for tracking used `malloc()' implementations core memory usage.
# This is currently only used by unsupported features.
-erl_xcomp_after_morecore_hook=yes
+#erl_xcomp_after_morecore_hook=
# * `erl_xcomp_bigendian' - `yes|no'. No default. If `yes', the target system
# must be big endian. If `no', little endian. This can often be